Add compile time switch SQLITE_ENABLE_ICU_COLLATIONS. For enabling ICU

collations without also enabling the tokenizer, the LIKE operator, the
REGEXP operator, or the unicode aware upper()/lower() scalar functions.

FossilOrigin-Name: a079f914522d7bc4b3d27d70114eb09adedfac936a64883e6ed8d382c428dd0e
This commit is contained in:
dan 2017-12-08 16:23:38 +00:00
parent ee15962dd0
commit 21540ae479
6 changed files with 108 additions and 91 deletions

View File

@ -28,7 +28,9 @@
** provide case-independent matching.
*/
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
#if !defined(SQLITE_CORE) \
|| defined(SQLITE_ENABLE_ICU) \
|| defined(SQLITE_ENABLE_ICU_COLLATIONS)
/* Include ICU headers */
#include <unicode/utypes.h>
@ -45,6 +47,26 @@
#include "sqlite3.h"
#endif
/*
** This function is called when an ICU function called from within
** the implementation of an SQL scalar function returns an error.
**
** The scalar function context passed as the first argument is
** loaded with an error message based on the following two args.
*/
static void icuFunctionError(
sqlite3_context *pCtx, /* SQLite scalar function context */
const char *zName, /* Name of ICU function that failed */
UErrorCode e /* Error code returned by ICU function */
){
char zBuf[128];
sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e));
zBuf[127] = '\0';
sqlite3_result_error(pCtx, zBuf, -1);
}
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
/*
** Maximum length (in bytes) of the pattern in a LIKE or GLOB
** operator.
@ -224,24 +246,6 @@ static void icuLikeFunc(
}
}
/*
** This function is called when an ICU function called from within
** the implementation of an SQL scalar function returns an error.
**
** The scalar function context passed as the first argument is
** loaded with an error message based on the following two args.
*/
static void icuFunctionError(
sqlite3_context *pCtx, /* SQLite scalar function context */
const char *zName, /* Name of ICU function that failed */
UErrorCode e /* Error code returned by ICU function */
){
char zBuf[128];
sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e));
zBuf[127] = '\0';
sqlite3_result_error(pCtx, zBuf, -1);
}
/*
** Function to delete compiled regexp objects. Registered as
** a destructor function with sqlite3_set_auxdata().
@ -407,6 +411,8 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
assert( 0 ); /* Unreachable */
}
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
/*
** Collation sequence destructor function. The pCtx argument points to
** a UCollator structure previously allocated using ucol_open().
@ -501,6 +507,7 @@ int sqlite3IcuInit(sqlite3 *db){
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
} scalars[] = {
{"icu_load_collation", 2, SQLITE_UTF8, 1, icuLoadCollation},
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
{"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC, 0, icuRegexpFunc},
{"lower", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
{"lower", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16},
@ -512,10 +519,10 @@ int sqlite3IcuInit(sqlite3 *db){
{"upper", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16},
{"like", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
{"like", 3, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc},
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
};
int rc = SQLITE_OK;
int i;
for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){
const struct IcuScalar *p = &scalars[i];

View File

@ -1,5 +1,5 @@
C Make\ssure\sthe\sbComplex\svariable\sin\ssqlite3DeleteFrom()\sis\sinitialized\swhen\ncompiling\swith\s-DSQLITE_OMIT_TRIGGER.
D 2017-12-08T14:07:14.466
C Add\scompile\stime\sswitch\sSQLITE_ENABLE_ICU_COLLATIONS.\sFor\senabling\sICU\ncollations\swithout\salso\senabling\sthe\stokenizer,\sthe\sLIKE\soperator,\sthe\nREGEXP\soperator,\sor\sthe\sunicode\saware\supper()/lower()\sscalar\sfunctions.
D 2017-12-08T16:23:38.347
F Makefile.in 6a879cbf01e37f9eac131414955f71774b566502d9a57ded1b8585b507503cb8
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc e5d7606238f55816da99f719969598df5b091aa2e9a6935c9412fcae8f53fc44
@ -210,7 +210,7 @@ F ext/fts5/tool/loadfts5.tcl 95b03429ee6b138645703c6ca192c3ac96eaf093
F ext/fts5/tool/mkfts5c.tcl d1c2a9ab8e0ec690a52316f33dd9b1d379942f45
F ext/fts5/tool/showfts5.tcl d54da0e067306663e2d5d523965ca487698e722c
F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43
F ext/icu/icu.c 635775226d07c743c770888a9dd5175afc6e67d3e28a4032b7fedc3bcaa92e65
F ext/icu/icu.c c2c7592574c08cd1270d909b8fb8797f6ea1f49e931e71dbcc25506b9b224580
F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37
F ext/lsm1/Makefile 98b0a24b45e248283d6bea4b6cb3e58d7b394edd8e96a0ac28c5fa5104813bad
F ext/lsm1/Makefile.msc f8c878b467232226de288da320e1ac71c131f5ec91e08b21f502303347260013
@ -436,7 +436,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71
F src/insert.c cb67cc56ef2ddd13e6944b2c0dd08a920bcd9503230adef8b9928d338097c722
F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e
F src/loadext.c 20865b183bb8a3723d59cf1efffc3c50217eb452c1021d077b908c94da26b0b2
F src/main.c 6a0cc1c7b8ab92374effecdd7b92792b3273a255c70575b7d67bd9a4315e6d3a
F src/main.c 4f94536a61dc77477e1cee7ecfae2896778c1a3d3de4f978db28f8b9220f6e52
F src/malloc.c a02c9e69bc76bee0f639416b947a946412890b606301454727feadcb313536d6
F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645
F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de
@ -496,7 +496,7 @@ F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0
F src/test_bestindex.c 78809f11026f18a93fcfd798d9479cba37e1201c830260bf1edc674b2fa9b857
F src/test_blob.c ae4a0620b478548afb67963095a7417cd06a4ec0a56adb453542203bfdcb31ce
F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274
F src/test_config.c 2dad654eb81e90160f764f485bf7248e87b6d251e484c959de1aa04935acae8e
F src/test_config.c 3904a8682aac58b77d20ca236face2b11e50781be4116004ba1ba79f69896ec9
F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f
F src/test_demovfs.c a0c3bdd45ed044115c2c9f7779e56eafff18741e
F src/test_devsym.c 1960abbb234b97e9b920f07e99503fc04b443f62bbc3c6ff2c2cea2133e3b8a2
@ -932,7 +932,7 @@ F test/hexlit.test 4a6a5f46e3c65c4bf1fa06f5dd5a9507a5627751
F test/hidden.test 23c1393a79e846d68fd902d72c85d5e5dcf98711
F test/hook.test dbc0b87756e1e20e7497b56889c9e9cd2f8cc2b5
F test/hook2.test b9ff3b8c6519fb67f33192f1afe86e7782ee4ac8
F test/icu.test 73956798bace8982909c00476b216714a6d0559a
F test/icu.test 7fb00edc09e05d51e36be12b33e0af04e3394e3b02dbdcb2eefcb901203e28c4
F test/ieee754.test 806fc0ce7f305f57e3331eaceeddcfec9339e607
F test/imposter1.test c3f1db2d3db2c24611a6596a3fc0ffc14f1466c8
F test/in.test 2fa2dfba1afe30eb830f327e7131dfadaa7a701d677de0eb65f9303d99e18fe0
@ -1679,7 +1679,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P bbd69fa6fa7f3c86fb5cd1b69e1abbe1bbad61aa281e6c073a402d1b202e42ec
R ca151348414bf89661535a75ec0c12be
U drh
Z 7fa850481121f6987d8c1258ea8eefc5
P e526d0c40b971d970367a52a57d3920cb64e6a98920114bfac46ba009f0b1eb5
R e5fd041d6b7727f71627ca57ebea4f83
U dan
Z b6d953d578629eaa29d8e731d0cdeaa8

View File

@ -1 +1 @@
e526d0c40b971d970367a52a57d3920cb64e6a98920114bfac46ba009f0b1eb5
a079f914522d7bc4b3d27d70114eb09adedfac936a64883e6ed8d382c428dd0e

View File

@ -22,7 +22,7 @@
#ifdef SQLITE_ENABLE_RTREE
# include "rtree.h"
#endif
#ifdef SQLITE_ENABLE_ICU
#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
# include "sqliteicu.h"
#endif
#ifdef SQLITE_ENABLE_JSON1
@ -3050,7 +3050,7 @@ static int openDatabase(
}
#endif
#ifdef SQLITE_ENABLE_ICU
#if defined(SQLITE_ENABLE_ICU) || defined(SQLITE_ENABLE_ICU_COLLATIONS)
if( !db->mallocFailed && rc==SQLITE_OK ){
rc = sqlite3IcuInit(db);
}

View File

@ -429,6 +429,12 @@ static void set_options(Tcl_Interp *interp){
Tcl_SetVar2(interp, "sqlite_options", "icu", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_ENABLE_ICU_COLLATIONS
Tcl_SetVar2(interp, "sqlite_options", "icu_collations", "1", TCL_GLOBAL_ONLY);
#else
Tcl_SetVar2(interp, "sqlite_options", "icu_collations", "0", TCL_GLOBAL_ONLY);
#endif
#ifdef SQLITE_OMIT_INCRBLOB
Tcl_SetVar2(interp, "sqlite_options", "incrblob", "0", TCL_GLOBAL_ONLY);
#else

View File

@ -15,7 +15,7 @@
set testdir [file dirname $argv0]
source $testdir/tester.tcl
ifcapable !icu {
ifcapable !icu&&!icu_collations {
finish_test
return
}
@ -35,54 +35,57 @@ proc test_expr {name settings expr result} {
} $settings $expr] $result
}
# Tests of the REGEXP operator.
#
test_expr icu-1.1 {i1='hello'} {i1 REGEXP 'hello'} 1
test_expr icu-1.2 {i1='hello'} {i1 REGEXP '.ello'} 1
test_expr icu-1.3 {i1='hello'} {i1 REGEXP '.ell'} 0
test_expr icu-1.4 {i1='hello'} {i1 REGEXP '.ell.*'} 1
test_expr icu-1.5 {i1=NULL} {i1 REGEXP '.ell.*'} {}
ifcapable icu {
# Some non-ascii characters with defined case mappings
#
set ::EGRAVE "\xC8"
set ::egrave "\xE8"
# Tests of the REGEXP operator.
#
test_expr icu-1.1 {i1='hello'} {i1 REGEXP 'hello'} 1
test_expr icu-1.2 {i1='hello'} {i1 REGEXP '.ello'} 1
test_expr icu-1.3 {i1='hello'} {i1 REGEXP '.ell'} 0
test_expr icu-1.4 {i1='hello'} {i1 REGEXP '.ell.*'} 1
test_expr icu-1.5 {i1=NULL} {i1 REGEXP '.ell.*'} {}
set ::OGRAVE "\xD2"
set ::ograve "\xF2"
# Some non-ascii characters with defined case mappings
#
set ::EGRAVE "\xC8"
set ::egrave "\xE8"
# That German letter that looks a bit like a B. The
# upper-case version of which is "SS" (two characters).
#
set ::szlig "\xDF"
set ::OGRAVE "\xD2"
set ::ograve "\xF2"
# Tests of the upper()/lower() functions.
#
test_expr icu-2.1 {i1='HellO WorlD'} {upper(i1)} {HELLO WORLD}
test_expr icu-2.2 {i1='HellO WorlD'} {lower(i1)} {hello world}
test_expr icu-2.3 {i1=$::egrave} {lower(i1)} $::egrave
test_expr icu-2.4 {i1=$::egrave} {upper(i1)} $::EGRAVE
test_expr icu-2.5 {i1=$::ograve} {lower(i1)} $::ograve
test_expr icu-2.6 {i1=$::ograve} {upper(i1)} $::OGRAVE
test_expr icu-2.3 {i1=$::EGRAVE} {lower(i1)} $::egrave
test_expr icu-2.4 {i1=$::EGRAVE} {upper(i1)} $::EGRAVE
test_expr icu-2.5 {i1=$::OGRAVE} {lower(i1)} $::ograve
test_expr icu-2.6 {i1=$::OGRAVE} {upper(i1)} $::OGRAVE
# That German letter that looks a bit like a B. The
# upper-case version of which is "SS" (two characters).
#
set ::szlig "\xDF"
test_expr icu-2.7 {i1=$::szlig} {upper(i1)} "SS"
test_expr icu-2.8 {i1='SS'} {lower(i1)} "ss"
# Tests of the upper()/lower() functions.
#
test_expr icu-2.1 {i1='HellO WorlD'} {upper(i1)} {HELLO WORLD}
test_expr icu-2.2 {i1='HellO WorlD'} {lower(i1)} {hello world}
test_expr icu-2.3 {i1=$::egrave} {lower(i1)} $::egrave
test_expr icu-2.4 {i1=$::egrave} {upper(i1)} $::EGRAVE
test_expr icu-2.5 {i1=$::ograve} {lower(i1)} $::ograve
test_expr icu-2.6 {i1=$::ograve} {upper(i1)} $::OGRAVE
test_expr icu-2.3 {i1=$::EGRAVE} {lower(i1)} $::egrave
test_expr icu-2.4 {i1=$::EGRAVE} {upper(i1)} $::EGRAVE
test_expr icu-2.5 {i1=$::OGRAVE} {lower(i1)} $::ograve
test_expr icu-2.6 {i1=$::OGRAVE} {upper(i1)} $::OGRAVE
do_execsql_test icu-2.9 {
SELECT upper(char(0xfb04,0xfb04,0xfb04,0xfb04));
} {FFLFFLFFLFFL}
test_expr icu-2.7 {i1=$::szlig} {upper(i1)} "SS"
test_expr icu-2.8 {i1='SS'} {lower(i1)} "ss"
# In turkish (locale="tr_TR"), the lower case version of I
# is "small dotless i" (code point 0x131 (decimal 305)).
#
set ::small_dotless_i "\u0131"
test_expr icu-3.1 {i1='I'} {lower(i1)} "i"
test_expr icu-3.2 {i1='I'} {lower(i1, 'tr_tr')} $::small_dotless_i
test_expr icu-3.3 {i1='I'} {lower(i1, 'en_AU')} "i"
do_execsql_test icu-2.9 {
SELECT upper(char(0xfb04,0xfb04,0xfb04,0xfb04));
} {FFLFFLFFLFFL}
# In turkish (locale="tr_TR"), the lower case version of I
# is "small dotless i" (code point 0x131 (decimal 305)).
#
set ::small_dotless_i "\u0131"
test_expr icu-3.1 {i1='I'} {lower(i1)} "i"
test_expr icu-3.2 {i1='I'} {lower(i1, 'tr_tr')} $::small_dotless_i
test_expr icu-3.3 {i1='I'} {lower(i1, 'en_AU')} "i"
}
#--------------------------------------------------------------------
# Test the collation sequence function.
@ -124,22 +127,23 @@ do_test icu-4.3 {
#
# http://src.chromium.org/viewvc/chrome/trunk/src/third_party/sqlite/icu-regexp.patch?revision=34807&view=markup
#
do_catchsql_test icu-5.1 { SELECT regexp('a[abc]c.*', 'abc') } {0 1}
do_catchsql_test icu-5.2 {
SELECT regexp('a[abc]c.*')
} {1 {wrong number of arguments to function regexp()}}
do_catchsql_test icu-5.3 {
SELECT regexp('a[abc]c.*', 'abc', 'c')
} {1 {wrong number of arguments to function regexp()}}
do_catchsql_test icu-5.4 {
SELECT 'abc' REGEXP 'a[abc]c.*'
} {0 1}
do_catchsql_test icu-5.4 { SELECT 'abc' REGEXP } {1 {near " ": syntax error}}
do_catchsql_test icu-5.5 { SELECT 'abc' REGEXP, 1 } {1 {near ",": syntax error}}
do_malloc_test icu-6.10 -sqlbody {
SELECT upper(char(0xfb04,0xdf,0xfb04,0xe8,0xfb04));
ifcapable icu {
do_catchsql_test icu-5.1 { SELECT regexp('a[abc]c.*', 'abc') } {0 1}
do_catchsql_test icu-5.2 {
SELECT regexp('a[abc]c.*')
} {1 {wrong number of arguments to function regexp()}}
do_catchsql_test icu-5.3 {
SELECT regexp('a[abc]c.*', 'abc', 'c')
} {1 {wrong number of arguments to function regexp()}}
do_catchsql_test icu-5.4 {
SELECT 'abc' REGEXP 'a[abc]c.*'
} {0 1}
do_catchsql_test icu-5.4 {SELECT 'abc' REGEXP } {1 {near " ": syntax error}}
do_catchsql_test icu-5.5 {SELECT 'abc' REGEXP, 1} {1 {near ",": syntax error}}
do_malloc_test icu-6.10 -sqlbody {
SELECT upper(char(0xfb04,0xdf,0xfb04,0xe8,0xfb04));
}
}
finish_test