mirror of https://github.com/postgres/postgres
Add a column collprovider to pg_collation that determines which library provides the collation data. The existing choices are default and libc, and this adds an icu choice, which uses the ICU4C library. The pg_locale_t type is changed to a union that contains the provider-specific locale handles. Users of locale information are changed to look into that struct for the appropriate handle to use. Also add a collversion column that records the version of the collation when it is created, and check at run time whether it is still the same. This detects potentially incompatible library upgrades that can corrupt indexes and other structures. This is currently only supported by ICU-provided collations. initdb initializes the default collation set as before from the `locale -a` output but also adds all available ICU locales with a "-x-icu" appended. Currently, ICU-provided collations can only be explicitly named collations. The global database locales are still always libc-provided. ICU support is enabled by configure --with-icu. Reviewed-by: Thomas Munro <thomas.munro@enterprisedb.com> Reviewed-by: Andreas Karlsson <andreas@proxel.se>pull/3/merge
parent
ea42cc18c3
commit
eccfef81e1
@ -0,0 +1,275 @@ |
||||
# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*- |
||||
# serial 12 (pkg-config-0.29.2) |
||||
|
||||
dnl Copyright © 2004 Scott James Remnant <scott@netsplit.com>. |
||||
dnl Copyright © 2012-2015 Dan Nicholson <dbn.lists@gmail.com> |
||||
dnl |
||||
dnl This program is free software; you can redistribute it and/or modify |
||||
dnl it under the terms of the GNU General Public License as published by |
||||
dnl the Free Software Foundation; either version 2 of the License, or |
||||
dnl (at your option) any later version. |
||||
dnl |
||||
dnl This program is distributed in the hope that it will be useful, but |
||||
dnl WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
dnl General Public License for more details. |
||||
dnl |
||||
dnl You should have received a copy of the GNU General Public License |
||||
dnl along with this program; if not, write to the Free Software |
||||
dnl Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA |
||||
dnl 02111-1307, USA. |
||||
dnl |
||||
dnl As a special exception to the GNU General Public License, if you |
||||
dnl distribute this file as part of a program that contains a |
||||
dnl configuration script generated by Autoconf, you may include it under |
||||
dnl the same distribution terms that you use for the rest of that |
||||
dnl program. |
||||
|
||||
dnl PKG_PREREQ(MIN-VERSION) |
||||
dnl ----------------------- |
||||
dnl Since: 0.29 |
||||
dnl |
||||
dnl Verify that the version of the pkg-config macros are at least |
||||
dnl MIN-VERSION. Unlike PKG_PROG_PKG_CONFIG, which checks the user's |
||||
dnl installed version of pkg-config, this checks the developer's version |
||||
dnl of pkg.m4 when generating configure. |
||||
dnl |
||||
dnl To ensure that this macro is defined, also add: |
||||
dnl m4_ifndef([PKG_PREREQ], |
||||
dnl [m4_fatal([must install pkg-config 0.29 or later before running autoconf/autogen])]) |
||||
dnl |
||||
dnl See the "Since" comment for each macro you use to see what version |
||||
dnl of the macros you require. |
||||
m4_defun([PKG_PREREQ], |
||||
[m4_define([PKG_MACROS_VERSION], [0.29.2]) |
||||
m4_if(m4_version_compare(PKG_MACROS_VERSION, [$1]), -1, |
||||
[m4_fatal([pkg.m4 version $1 or higher is required but ]PKG_MACROS_VERSION[ found])]) |
||||
])dnl PKG_PREREQ |
||||
|
||||
dnl PKG_PROG_PKG_CONFIG([MIN-VERSION]) |
||||
dnl ---------------------------------- |
||||
dnl Since: 0.16 |
||||
dnl |
||||
dnl Search for the pkg-config tool and set the PKG_CONFIG variable to |
||||
dnl first found in the path. Checks that the version of pkg-config found |
||||
dnl is at least MIN-VERSION. If MIN-VERSION is not specified, 0.9.0 is |
||||
dnl used since that's the first version where most current features of |
||||
dnl pkg-config existed. |
||||
AC_DEFUN([PKG_PROG_PKG_CONFIG], |
||||
[m4_pattern_forbid([^_?PKG_[A-Z_]+$]) |
||||
m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$]) |
||||
m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$]) |
||||
AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility]) |
||||
AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path]) |
||||
AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path]) |
||||
|
||||
if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then |
||||
AC_PATH_TOOL([PKG_CONFIG], [pkg-config]) |
||||
fi |
||||
if test -n "$PKG_CONFIG"; then |
||||
_pkg_min_version=m4_default([$1], [0.9.0]) |
||||
AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version]) |
||||
if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then |
||||
AC_MSG_RESULT([yes]) |
||||
else |
||||
AC_MSG_RESULT([no]) |
||||
PKG_CONFIG="" |
||||
fi |
||||
fi[]dnl |
||||
])dnl PKG_PROG_PKG_CONFIG |
||||
|
||||
dnl PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) |
||||
dnl ------------------------------------------------------------------- |
||||
dnl Since: 0.18 |
||||
dnl |
||||
dnl Check to see whether a particular set of modules exists. Similar to |
||||
dnl PKG_CHECK_MODULES(), but does not set variables or print errors. |
||||
dnl |
||||
dnl Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG]) |
||||
dnl only at the first occurence in configure.ac, so if the first place |
||||
dnl it's called might be skipped (such as if it is within an "if", you |
||||
dnl have to call PKG_CHECK_EXISTS manually |
||||
AC_DEFUN([PKG_CHECK_EXISTS], |
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl |
||||
if test -n "$PKG_CONFIG" && \ |
||||
AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then |
||||
m4_default([$2], [:]) |
||||
m4_ifvaln([$3], [else |
||||
$3])dnl |
||||
fi]) |
||||
|
||||
dnl _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES]) |
||||
dnl --------------------------------------------- |
||||
dnl Internal wrapper calling pkg-config via PKG_CONFIG and setting |
||||
dnl pkg_failed based on the result. |
||||
m4_define([_PKG_CONFIG], |
||||
[if test -n "$$1"; then |
||||
pkg_cv_[]$1="$$1" |
||||
elif test -n "$PKG_CONFIG"; then |
||||
PKG_CHECK_EXISTS([$3], |
||||
[pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null` |
||||
test "x$?" != "x0" && pkg_failed=yes ], |
||||
[pkg_failed=yes]) |
||||
else |
||||
pkg_failed=untried |
||||
fi[]dnl |
||||
])dnl _PKG_CONFIG |
||||
|
||||
dnl _PKG_SHORT_ERRORS_SUPPORTED |
||||
dnl --------------------------- |
||||
dnl Internal check to see if pkg-config supports short errors. |
||||
AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED], |
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG]) |
||||
if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then |
||||
_pkg_short_errors_supported=yes |
||||
else |
||||
_pkg_short_errors_supported=no |
||||
fi[]dnl |
||||
])dnl _PKG_SHORT_ERRORS_SUPPORTED |
||||
|
||||
|
||||
dnl PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], |
||||
dnl [ACTION-IF-NOT-FOUND]) |
||||
dnl -------------------------------------------------------------- |
||||
dnl Since: 0.4.0 |
||||
dnl |
||||
dnl Note that if there is a possibility the first call to |
||||
dnl PKG_CHECK_MODULES might not happen, you should be sure to include an |
||||
dnl explicit call to PKG_PROG_PKG_CONFIG in your configure.ac |
||||
AC_DEFUN([PKG_CHECK_MODULES], |
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl |
||||
AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl |
||||
AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl |
||||
|
||||
pkg_failed=no |
||||
AC_MSG_CHECKING([for $2]) |
||||
|
||||
_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2]) |
||||
_PKG_CONFIG([$1][_LIBS], [libs], [$2]) |
||||
|
||||
m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS |
||||
and $1[]_LIBS to avoid the need to call pkg-config. |
||||
See the pkg-config man page for more details.]) |
||||
|
||||
if test $pkg_failed = yes; then |
||||
AC_MSG_RESULT([no]) |
||||
_PKG_SHORT_ERRORS_SUPPORTED |
||||
if test $_pkg_short_errors_supported = yes; then |
||||
$1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1` |
||||
else |
||||
$1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1` |
||||
fi |
||||
# Put the nasty error message in config.log where it belongs |
||||
echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD |
||||
|
||||
m4_default([$4], [AC_MSG_ERROR( |
||||
[Package requirements ($2) were not met: |
||||
|
||||
$$1_PKG_ERRORS |
||||
|
||||
Consider adjusting the PKG_CONFIG_PATH environment variable if you |
||||
installed software in a non-standard prefix. |
||||
|
||||
_PKG_TEXT])[]dnl |
||||
]) |
||||
elif test $pkg_failed = untried; then |
||||
AC_MSG_RESULT([no]) |
||||
m4_default([$4], [AC_MSG_FAILURE( |
||||
[The pkg-config script could not be found or is too old. Make sure it |
||||
is in your PATH or set the PKG_CONFIG environment variable to the full |
||||
path to pkg-config. |
||||
|
||||
_PKG_TEXT |
||||
|
||||
To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl |
||||
]) |
||||
else |
||||
$1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS |
||||
$1[]_LIBS=$pkg_cv_[]$1[]_LIBS |
||||
AC_MSG_RESULT([yes]) |
||||
$3 |
||||
fi[]dnl |
||||
])dnl PKG_CHECK_MODULES |
||||
|
||||
|
||||
dnl PKG_CHECK_MODULES_STATIC(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND], |
||||
dnl [ACTION-IF-NOT-FOUND]) |
||||
dnl --------------------------------------------------------------------- |
||||
dnl Since: 0.29 |
||||
dnl |
||||
dnl Checks for existence of MODULES and gathers its build flags with |
||||
dnl static libraries enabled. Sets VARIABLE-PREFIX_CFLAGS from --cflags |
||||
dnl and VARIABLE-PREFIX_LIBS from --libs. |
||||
dnl |
||||
dnl Note that if there is a possibility the first call to |
||||
dnl PKG_CHECK_MODULES_STATIC might not happen, you should be sure to |
||||
dnl include an explicit call to PKG_PROG_PKG_CONFIG in your |
||||
dnl configure.ac. |
||||
AC_DEFUN([PKG_CHECK_MODULES_STATIC], |
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl |
||||
_save_PKG_CONFIG=$PKG_CONFIG |
||||
PKG_CONFIG="$PKG_CONFIG --static" |
||||
PKG_CHECK_MODULES($@) |
||||
PKG_CONFIG=$_save_PKG_CONFIG[]dnl |
||||
])dnl PKG_CHECK_MODULES_STATIC |
||||
|
||||
|
||||
dnl PKG_INSTALLDIR([DIRECTORY]) |
||||
dnl ------------------------- |
||||
dnl Since: 0.27 |
||||
dnl |
||||
dnl Substitutes the variable pkgconfigdir as the location where a module |
||||
dnl should install pkg-config .pc files. By default the directory is |
||||
dnl $libdir/pkgconfig, but the default can be changed by passing |
||||
dnl DIRECTORY. The user can override through the --with-pkgconfigdir |
||||
dnl parameter. |
||||
AC_DEFUN([PKG_INSTALLDIR], |
||||
[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])]) |
||||
m4_pushdef([pkg_description], |
||||
[pkg-config installation directory @<:@]pkg_default[@:>@]) |
||||
AC_ARG_WITH([pkgconfigdir], |
||||
[AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],, |
||||
[with_pkgconfigdir=]pkg_default) |
||||
AC_SUBST([pkgconfigdir], [$with_pkgconfigdir]) |
||||
m4_popdef([pkg_default]) |
||||
m4_popdef([pkg_description]) |
||||
])dnl PKG_INSTALLDIR |
||||
|
||||
|
||||
dnl PKG_NOARCH_INSTALLDIR([DIRECTORY]) |
||||
dnl -------------------------------- |
||||
dnl Since: 0.27 |
||||
dnl |
||||
dnl Substitutes the variable noarch_pkgconfigdir as the location where a |
||||
dnl module should install arch-independent pkg-config .pc files. By |
||||
dnl default the directory is $datadir/pkgconfig, but the default can be |
||||
dnl changed by passing DIRECTORY. The user can override through the |
||||
dnl --with-noarch-pkgconfigdir parameter. |
||||
AC_DEFUN([PKG_NOARCH_INSTALLDIR], |
||||
[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])]) |
||||
m4_pushdef([pkg_description], |
||||
[pkg-config arch-independent installation directory @<:@]pkg_default[@:>@]) |
||||
AC_ARG_WITH([noarch-pkgconfigdir], |
||||
[AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],, |
||||
[with_noarch_pkgconfigdir=]pkg_default) |
||||
AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir]) |
||||
m4_popdef([pkg_default]) |
||||
m4_popdef([pkg_description]) |
||||
])dnl PKG_NOARCH_INSTALLDIR |
||||
|
||||
|
||||
dnl PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, |
||||
dnl [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) |
||||
dnl ------------------------------------------- |
||||
dnl Since: 0.28 |
||||
dnl |
||||
dnl Retrieves the value of the pkg-config variable for the given module. |
||||
AC_DEFUN([PKG_CHECK_VAR], |
||||
[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl |
||||
AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl |
||||
|
||||
_PKG_CONFIG([$1], [variable="][$3]["], [$2]) |
||||
AS_VAR_COPY([$1], [pkg_cv_][$1]) |
||||
|
||||
AS_VAR_IF([$1], [""], [$5], [$4])dnl |
||||
])dnl PKG_CHECK_VAR |
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,433 @@ |
||||
/* |
||||
* This test is for ICU collations. |
||||
*/ |
||||
|
||||
SET client_encoding TO UTF8; |
||||
|
||||
CREATE SCHEMA collate_tests; |
||||
SET search_path = collate_tests; |
||||
|
||||
|
||||
CREATE TABLE collate_test1 ( |
||||
a int, |
||||
b text COLLATE "en-x-icu" NOT NULL |
||||
); |
||||
|
||||
\d collate_test1 |
||||
|
||||
CREATE TABLE collate_test_fail ( |
||||
a int, |
||||
b text COLLATE "ja_JP.eucjp-x-icu" |
||||
); |
||||
|
||||
CREATE TABLE collate_test_fail ( |
||||
a int, |
||||
b text COLLATE "foo-x-icu" |
||||
); |
||||
|
||||
CREATE TABLE collate_test_fail ( |
||||
a int COLLATE "en-x-icu", |
||||
b text |
||||
); |
||||
|
||||
CREATE TABLE collate_test_like ( |
||||
LIKE collate_test1 |
||||
); |
||||
|
||||
\d collate_test_like |
||||
|
||||
CREATE TABLE collate_test2 ( |
||||
a int, |
||||
b text COLLATE "sv-x-icu" |
||||
); |
||||
|
||||
CREATE TABLE collate_test3 ( |
||||
a int, |
||||
b text COLLATE "C" |
||||
); |
||||
|
||||
INSERT INTO collate_test1 VALUES (1, 'abc'), (2, 'äbc'), (3, 'bbc'), (4, 'ABC'); |
||||
INSERT INTO collate_test2 SELECT * FROM collate_test1; |
||||
INSERT INTO collate_test3 SELECT * FROM collate_test1; |
||||
|
||||
SELECT * FROM collate_test1 WHERE b >= 'bbc'; |
||||
SELECT * FROM collate_test2 WHERE b >= 'bbc'; |
||||
SELECT * FROM collate_test3 WHERE b >= 'bbc'; |
||||
SELECT * FROM collate_test3 WHERE b >= 'BBC'; |
||||
|
||||
SELECT * FROM collate_test1 WHERE b COLLATE "C" >= 'bbc'; |
||||
SELECT * FROM collate_test1 WHERE b >= 'bbc' COLLATE "C"; |
||||
SELECT * FROM collate_test1 WHERE b COLLATE "C" >= 'bbc' COLLATE "C"; |
||||
SELECT * FROM collate_test1 WHERE b COLLATE "C" >= 'bbc' COLLATE "en-x-icu"; |
||||
|
||||
|
||||
CREATE DOMAIN testdomain_sv AS text COLLATE "sv-x-icu"; |
||||
CREATE DOMAIN testdomain_i AS int COLLATE "sv-x-icu"; -- fails |
||||
CREATE TABLE collate_test4 ( |
||||
a int, |
||||
b testdomain_sv |
||||
); |
||||
INSERT INTO collate_test4 SELECT * FROM collate_test1; |
||||
SELECT a, b FROM collate_test4 ORDER BY b; |
||||
|
||||
CREATE TABLE collate_test5 ( |
||||
a int, |
||||
b testdomain_sv COLLATE "en-x-icu" |
||||
); |
||||
INSERT INTO collate_test5 SELECT * FROM collate_test1; |
||||
SELECT a, b FROM collate_test5 ORDER BY b; |
||||
|
||||
|
||||
SELECT a, b FROM collate_test1 ORDER BY b; |
||||
SELECT a, b FROM collate_test2 ORDER BY b; |
||||
SELECT a, b FROM collate_test3 ORDER BY b; |
||||
|
||||
SELECT a, b FROM collate_test1 ORDER BY b COLLATE "C"; |
||||
|
||||
-- star expansion |
||||
SELECT * FROM collate_test1 ORDER BY b; |
||||
SELECT * FROM collate_test2 ORDER BY b; |
||||
SELECT * FROM collate_test3 ORDER BY b; |
||||
|
||||
-- constant expression folding |
||||
SELECT 'bbc' COLLATE "en-x-icu" > 'äbc' COLLATE "en-x-icu" AS "true"; |
||||
SELECT 'bbc' COLLATE "sv-x-icu" > 'äbc' COLLATE "sv-x-icu" AS "false"; |
||||
|
||||
-- upper/lower |
||||
|
||||
CREATE TABLE collate_test10 ( |
||||
a int, |
||||
x text COLLATE "en-x-icu", |
||||
y text COLLATE "tr-x-icu" |
||||
); |
||||
|
||||
INSERT INTO collate_test10 VALUES (1, 'hij', 'hij'), (2, 'HIJ', 'HIJ'); |
||||
|
||||
SELECT a, lower(x), lower(y), upper(x), upper(y), initcap(x), initcap(y) FROM collate_test10; |
||||
SELECT a, lower(x COLLATE "C"), lower(y COLLATE "C") FROM collate_test10; |
||||
|
||||
SELECT a, x, y FROM collate_test10 ORDER BY lower(y), a; |
||||
|
||||
-- LIKE/ILIKE |
||||
|
||||
SELECT * FROM collate_test1 WHERE b LIKE 'abc'; |
||||
SELECT * FROM collate_test1 WHERE b LIKE 'abc%'; |
||||
SELECT * FROM collate_test1 WHERE b LIKE '%bc%'; |
||||
SELECT * FROM collate_test1 WHERE b ILIKE 'abc'; |
||||
SELECT * FROM collate_test1 WHERE b ILIKE 'abc%'; |
||||
SELECT * FROM collate_test1 WHERE b ILIKE '%bc%'; |
||||
|
||||
SELECT 'Türkiye' COLLATE "en-x-icu" ILIKE '%KI%' AS "true"; |
||||
SELECT 'Türkiye' COLLATE "tr-x-icu" ILIKE '%KI%' AS "false"; |
||||
|
||||
SELECT 'bıt' ILIKE 'BIT' COLLATE "en-x-icu" AS "false"; |
||||
SELECT 'bıt' ILIKE 'BIT' COLLATE "tr-x-icu" AS "true"; |
||||
|
||||
-- The following actually exercises the selectivity estimation for ILIKE. |
||||
SELECT relname FROM pg_class WHERE relname ILIKE 'abc%'; |
||||
|
||||
-- regular expressions |
||||
|
||||
SELECT * FROM collate_test1 WHERE b ~ '^abc$'; |
||||
SELECT * FROM collate_test1 WHERE b ~ '^abc'; |
||||
SELECT * FROM collate_test1 WHERE b ~ 'bc'; |
||||
SELECT * FROM collate_test1 WHERE b ~* '^abc$'; |
||||
SELECT * FROM collate_test1 WHERE b ~* '^abc'; |
||||
SELECT * FROM collate_test1 WHERE b ~* 'bc'; |
||||
|
||||
CREATE TABLE collate_test6 ( |
||||
a int, |
||||
b text COLLATE "en-x-icu" |
||||
); |
||||
INSERT INTO collate_test6 VALUES (1, 'abc'), (2, 'ABC'), (3, '123'), (4, 'ab1'), |
||||
(5, 'a1!'), (6, 'a c'), (7, '!.;'), (8, ' '), |
||||
(9, 'äbç'), (10, 'ÄBÇ'); |
||||
SELECT b, |
||||
b ~ '^[[:alpha:]]+$' AS is_alpha, |
||||
b ~ '^[[:upper:]]+$' AS is_upper, |
||||
b ~ '^[[:lower:]]+$' AS is_lower, |
||||
b ~ '^[[:digit:]]+$' AS is_digit, |
||||
b ~ '^[[:alnum:]]+$' AS is_alnum, |
||||
b ~ '^[[:graph:]]+$' AS is_graph, |
||||
b ~ '^[[:print:]]+$' AS is_print, |
||||
b ~ '^[[:punct:]]+$' AS is_punct, |
||||
b ~ '^[[:space:]]+$' AS is_space |
||||
FROM collate_test6; |
||||
|
||||
SELECT 'Türkiye' COLLATE "en-x-icu" ~* 'KI' AS "true"; |
||||
SELECT 'Türkiye' COLLATE "tr-x-icu" ~* 'KI' AS "true"; -- true with ICU |
||||
|
||||
SELECT 'bıt' ~* 'BIT' COLLATE "en-x-icu" AS "false"; |
||||
SELECT 'bıt' ~* 'BIT' COLLATE "tr-x-icu" AS "false"; -- false with ICU |
||||
|
||||
-- The following actually exercises the selectivity estimation for ~*. |
||||
SELECT relname FROM pg_class WHERE relname ~* '^abc'; |
||||
|
||||
|
||||
/* not run by default because it requires tr_TR system locale |
||||
-- to_char |
||||
|
||||
SET lc_time TO 'tr_TR'; |
||||
SELECT to_char(date '2010-04-01', 'DD TMMON YYYY'); |
||||
SELECT to_char(date '2010-04-01', 'DD TMMON YYYY' COLLATE "tr-x-icu"); |
||||
*/ |
||||
|
||||
|
||||
-- backwards parsing |
||||
|
||||
CREATE VIEW collview1 AS SELECT * FROM collate_test1 WHERE b COLLATE "C" >= 'bbc'; |
||||
CREATE VIEW collview2 AS SELECT a, b FROM collate_test1 ORDER BY b COLLATE "C"; |
||||
CREATE VIEW collview3 AS SELECT a, lower((x || x) COLLATE "C") FROM collate_test10; |
||||
|
||||
SELECT table_name, view_definition FROM information_schema.views |
||||
WHERE table_name LIKE 'collview%' ORDER BY 1; |
||||
|
||||
|
||||
-- collation propagation in various expression types |
||||
|
||||
SELECT a, coalesce(b, 'foo') FROM collate_test1 ORDER BY 2; |
||||
SELECT a, coalesce(b, 'foo') FROM collate_test2 ORDER BY 2; |
||||
SELECT a, coalesce(b, 'foo') FROM collate_test3 ORDER BY 2; |
||||
SELECT a, lower(coalesce(x, 'foo')), lower(coalesce(y, 'foo')) FROM collate_test10; |
||||
|
||||
SELECT a, b, greatest(b, 'CCC') FROM collate_test1 ORDER BY 3; |
||||
SELECT a, b, greatest(b, 'CCC') FROM collate_test2 ORDER BY 3; |
||||
SELECT a, b, greatest(b, 'CCC') FROM collate_test3 ORDER BY 3; |
||||
SELECT a, x, y, lower(greatest(x, 'foo')), lower(greatest(y, 'foo')) FROM collate_test10; |
||||
|
||||
SELECT a, nullif(b, 'abc') FROM collate_test1 ORDER BY 2; |
||||
SELECT a, nullif(b, 'abc') FROM collate_test2 ORDER BY 2; |
||||
SELECT a, nullif(b, 'abc') FROM collate_test3 ORDER BY 2; |
||||
SELECT a, lower(nullif(x, 'foo')), lower(nullif(y, 'foo')) FROM collate_test10; |
||||
|
||||
SELECT a, CASE b WHEN 'abc' THEN 'abcd' ELSE b END FROM collate_test1 ORDER BY 2; |
||||
SELECT a, CASE b WHEN 'abc' THEN 'abcd' ELSE b END FROM collate_test2 ORDER BY 2; |
||||
SELECT a, CASE b WHEN 'abc' THEN 'abcd' ELSE b END FROM collate_test3 ORDER BY 2; |
||||
|
||||
CREATE DOMAIN testdomain AS text; |
||||
SELECT a, b::testdomain FROM collate_test1 ORDER BY 2; |
||||
SELECT a, b::testdomain FROM collate_test2 ORDER BY 2; |
||||
SELECT a, b::testdomain FROM collate_test3 ORDER BY 2; |
||||
SELECT a, b::testdomain_sv FROM collate_test3 ORDER BY 2; |
||||
SELECT a, lower(x::testdomain), lower(y::testdomain) FROM collate_test10; |
||||
|
||||
SELECT min(b), max(b) FROM collate_test1; |
||||
SELECT min(b), max(b) FROM collate_test2; |
||||
SELECT min(b), max(b) FROM collate_test3; |
||||
|
||||
SELECT array_agg(b ORDER BY b) FROM collate_test1; |
||||
SELECT array_agg(b ORDER BY b) FROM collate_test2; |
||||
SELECT array_agg(b ORDER BY b) FROM collate_test3; |
||||
|
||||
SELECT a, b FROM collate_test1 UNION ALL SELECT a, b FROM collate_test1 ORDER BY 2; |
||||
SELECT a, b FROM collate_test2 UNION SELECT a, b FROM collate_test2 ORDER BY 2; |
||||
SELECT a, b FROM collate_test3 WHERE a < 4 INTERSECT SELECT a, b FROM collate_test3 WHERE a > 1 ORDER BY 2; |
||||
SELECT a, b FROM collate_test3 EXCEPT SELECT a, b FROM collate_test3 WHERE a < 2 ORDER BY 2; |
||||
|
||||
SELECT a, b FROM collate_test1 UNION ALL SELECT a, b FROM collate_test3 ORDER BY 2; -- fail |
||||
SELECT a, b FROM collate_test1 UNION ALL SELECT a, b FROM collate_test3; -- ok |
||||
SELECT a, b FROM collate_test1 UNION SELECT a, b FROM collate_test3 ORDER BY 2; -- fail |
||||
SELECT a, b COLLATE "C" FROM collate_test1 UNION SELECT a, b FROM collate_test3 ORDER BY 2; -- ok |
||||
SELECT a, b FROM collate_test1 INTERSECT SELECT a, b FROM collate_test3 ORDER BY 2; -- fail |
||||
SELECT a, b FROM collate_test1 EXCEPT SELECT a, b FROM collate_test3 ORDER BY 2; -- fail |
||||
|
||||
CREATE TABLE test_u AS SELECT a, b FROM collate_test1 UNION ALL SELECT a, b FROM collate_test3; -- fail |
||||
|
||||
-- ideally this would be a parse-time error, but for now it must be run-time: |
||||
select x < y from collate_test10; -- fail |
||||
select x || y from collate_test10; -- ok, because || is not collation aware |
||||
select x, y from collate_test10 order by x || y; -- not so ok |
||||
|
||||
-- collation mismatch between recursive and non-recursive term |
||||
WITH RECURSIVE foo(x) AS |
||||
(SELECT x FROM (VALUES('a' COLLATE "en-x-icu"),('b')) t(x) |
||||
UNION ALL |
||||
SELECT (x || 'c') COLLATE "de-x-icu" FROM foo WHERE length(x) < 10) |
||||
SELECT * FROM foo; |
||||
|
||||
|
||||
-- casting |
||||
|
||||
SELECT CAST('42' AS text COLLATE "C"); |
||||
|
||||
SELECT a, CAST(b AS varchar) FROM collate_test1 ORDER BY 2; |
||||
SELECT a, CAST(b AS varchar) FROM collate_test2 ORDER BY 2; |
||||
SELECT a, CAST(b AS varchar) FROM collate_test3 ORDER BY 2; |
||||
|
||||
|
||||
-- propagation of collation in SQL functions (inlined and non-inlined cases) |
||||
-- and plpgsql functions too |
||||
|
||||
CREATE FUNCTION mylt (text, text) RETURNS boolean LANGUAGE sql |
||||
AS $$ select $1 < $2 $$; |
||||
|
||||
CREATE FUNCTION mylt_noninline (text, text) RETURNS boolean LANGUAGE sql |
||||
AS $$ select $1 < $2 limit 1 $$; |
||||
|
||||
CREATE FUNCTION mylt_plpgsql (text, text) RETURNS boolean LANGUAGE plpgsql |
||||
AS $$ begin return $1 < $2; end $$; |
||||
|
||||
SELECT a.b AS a, b.b AS b, a.b < b.b AS lt, |
||||
mylt(a.b, b.b), mylt_noninline(a.b, b.b), mylt_plpgsql(a.b, b.b) |
||||
FROM collate_test1 a, collate_test1 b |
||||
ORDER BY a.b, b.b; |
||||
|
||||
SELECT a.b AS a, b.b AS b, a.b < b.b COLLATE "C" AS lt, |
||||
mylt(a.b, b.b COLLATE "C"), mylt_noninline(a.b, b.b COLLATE "C"), |
||||
mylt_plpgsql(a.b, b.b COLLATE "C") |
||||
FROM collate_test1 a, collate_test1 b |
||||
ORDER BY a.b, b.b; |
||||
|
||||
|
||||
-- collation override in plpgsql |
||||
|
||||
CREATE FUNCTION mylt2 (x text, y text) RETURNS boolean LANGUAGE plpgsql AS $$ |
||||
declare |
||||
xx text := x; |
||||
yy text := y; |
||||
begin |
||||
return xx < yy; |
||||
end |
||||
$$; |
||||
|
||||
SELECT mylt2('a', 'B' collate "en-x-icu") as t, mylt2('a', 'B' collate "C") as f; |
||||
|
||||
CREATE OR REPLACE FUNCTION |
||||
mylt2 (x text, y text) RETURNS boolean LANGUAGE plpgsql AS $$ |
||||
declare |
||||
xx text COLLATE "POSIX" := x; |
||||
yy text := y; |
||||
begin |
||||
return xx < yy; |
||||
end |
||||
$$; |
||||
|
||||
SELECT mylt2('a', 'B') as f; |
||||
SELECT mylt2('a', 'B' collate "C") as fail; -- conflicting collations |
||||
SELECT mylt2('a', 'B' collate "POSIX") as f; |
||||
|
||||
|
||||
-- polymorphism |
||||
|
||||
SELECT * FROM unnest((SELECT array_agg(b ORDER BY b) FROM collate_test1)) ORDER BY 1; |
||||
SELECT * FROM unnest((SELECT array_agg(b ORDER BY b) FROM collate_test2)) ORDER BY 1; |
||||
SELECT * FROM unnest((SELECT array_agg(b ORDER BY b) FROM collate_test3)) ORDER BY 1; |
||||
|
||||
CREATE FUNCTION dup (anyelement) RETURNS anyelement |
||||
AS 'select $1' LANGUAGE sql; |
||||
|
||||
SELECT a, dup(b) FROM collate_test1 ORDER BY 2; |
||||
SELECT a, dup(b) FROM collate_test2 ORDER BY 2; |
||||
SELECT a, dup(b) FROM collate_test3 ORDER BY 2; |
||||
|
||||
|
||||
-- indexes |
||||
|
||||
CREATE INDEX collate_test1_idx1 ON collate_test1 (b); |
||||
CREATE INDEX collate_test1_idx2 ON collate_test1 (b COLLATE "C"); |
||||
CREATE INDEX collate_test1_idx3 ON collate_test1 ((b COLLATE "C")); -- this is different grammatically |
||||
CREATE INDEX collate_test1_idx4 ON collate_test1 (((b||'foo') COLLATE "POSIX")); |
||||
|
||||
CREATE INDEX collate_test1_idx5 ON collate_test1 (a COLLATE "C"); -- fail |
||||
CREATE INDEX collate_test1_idx6 ON collate_test1 ((a COLLATE "C")); -- fail |
||||
|
||||
SELECT relname, pg_get_indexdef(oid) FROM pg_class WHERE relname LIKE 'collate_test%_idx%' ORDER BY 1; |
||||
|
||||
|
||||
-- schema manipulation commands |
||||
|
||||
CREATE ROLE regress_test_role; |
||||
CREATE SCHEMA test_schema; |
||||
|
||||
-- We need to do this this way to cope with varying names for encodings: |
||||
do $$ |
||||
BEGIN |
||||
EXECUTE 'CREATE COLLATION test0 (provider = icu, locale = ' || |
||||
quote_literal(current_setting('lc_collate')) || ');'; |
||||
END |
||||
$$; |
||||
CREATE COLLATION test0 FROM "C"; -- fail, duplicate name |
||||
do $$ |
||||
BEGIN |
||||
EXECUTE 'CREATE COLLATION test1 (provider = icu, lc_collate = ' || |
||||
quote_literal(current_setting('lc_collate')) || |
||||
', lc_ctype = ' || |
||||
quote_literal(current_setting('lc_ctype')) || ');'; |
||||
END |
||||
$$; |
||||
CREATE COLLATION test3 (provider = icu, lc_collate = 'en_US.utf8'); -- fail, need lc_ctype |
||||
CREATE COLLATION testx (provider = icu, locale = 'nonsense'); /* never fails with ICU */ DROP COLLATION testx; |
||||
|
||||
CREATE COLLATION test4 FROM nonsense; |
||||
CREATE COLLATION test5 FROM test0; |
||||
|
||||
SELECT collname FROM pg_collation WHERE collname LIKE 'test%' ORDER BY 1; |
||||
|
||||
ALTER COLLATION test1 RENAME TO test11; |
||||
ALTER COLLATION test0 RENAME TO test11; -- fail |
||||
ALTER COLLATION test1 RENAME TO test22; -- fail |
||||
|
||||
ALTER COLLATION test11 OWNER TO regress_test_role; |
||||
ALTER COLLATION test11 OWNER TO nonsense; |
||||
ALTER COLLATION test11 SET SCHEMA test_schema; |
||||
|
||||
COMMENT ON COLLATION test0 IS 'US English'; |
||||
|
||||
SELECT collname, nspname, obj_description(pg_collation.oid, 'pg_collation') |
||||
FROM pg_collation JOIN pg_namespace ON (collnamespace = pg_namespace.oid) |
||||
WHERE collname LIKE 'test%' |
||||
ORDER BY 1; |
||||
|
||||
DROP COLLATION test0, test_schema.test11, test5; |
||||
DROP COLLATION test0; -- fail |
||||
DROP COLLATION IF EXISTS test0; |
||||
|
||||
SELECT collname FROM pg_collation WHERE collname LIKE 'test%'; |
||||
|
||||
DROP SCHEMA test_schema; |
||||
DROP ROLE regress_test_role; |
||||
|
||||
|
||||
-- ALTER |
||||
|
||||
ALTER COLLATION "en-x-icu" REFRESH VERSION; |
||||
|
||||
|
||||
-- dependencies |
||||
|
||||
CREATE COLLATION test0 FROM "C"; |
||||
|
||||
CREATE TABLE collate_dep_test1 (a int, b text COLLATE test0); |
||||
CREATE DOMAIN collate_dep_dom1 AS text COLLATE test0; |
||||
CREATE TYPE collate_dep_test2 AS (x int, y text COLLATE test0); |
||||
CREATE VIEW collate_dep_test3 AS SELECT text 'foo' COLLATE test0 AS foo; |
||||
CREATE TABLE collate_dep_test4t (a int, b text); |
||||
CREATE INDEX collate_dep_test4i ON collate_dep_test4t (b COLLATE test0); |
||||
|
||||
DROP COLLATION test0 RESTRICT; -- fail |
||||
DROP COLLATION test0 CASCADE; |
||||
|
||||
\d collate_dep_test1 |
||||
\d collate_dep_test2 |
||||
|
||||
DROP TABLE collate_dep_test1, collate_dep_test4t; |
||||
DROP TYPE collate_dep_test2; |
||||
|
||||
-- test range types and collations |
||||
|
||||
create type textrange_c as range(subtype=text, collation="C"); |
||||
create type textrange_en_us as range(subtype=text, collation="en-x-icu"); |
||||
|
||||
select textrange_c('A','Z') @> 'b'::text; |
||||
select textrange_en_us('A','Z') @> 'b'::text; |
||||
|
||||
drop type textrange_c; |
||||
drop type textrange_en_us; |
||||
|
||||
|
||||
-- cleanup |
||||
DROP SCHEMA collate_tests CASCADE; |
||||
RESET search_path; |
||||
|
||||
-- leave a collation for pg_upgrade test |
||||
CREATE COLLATION coll_icu_upgrade FROM "und-x-icu"; |
||||
Loading…
Reference in new issue