cordova-sqlite-evmax-build-free 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGES.md +3 -1
- package/README.md +6 -2
- package/package.json +1 -1
- package/plugin.xml +4 -1
- package/spec/www/spec/db-tx-string-test.js +14 -0
- package/src/deps/android/sqlc-evmax-ndk-driver.jar +0 -0
- package/src/icu/icu.c +596 -0
- package/src/icu/sqliteicu.h +26 -0
- package/src/ios/SQLitePlugin.m +4 -0
package/CHANGES.md
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
# Changes
|
|
2
2
|
|
|
3
|
-
# cordova-sqlite-evmax-build-free 0.
|
|
3
|
+
# cordova-sqlite-evmax-build-free 0.2.0
|
|
4
|
+
|
|
5
|
+
- add ICU support for Android & iOS using built-in platform ICU on each platform (requires Android 12+)
|
|
4
6
|
|
|
5
7
|
## cordova-sqlite-evmax-feat-android-db-location 0.0.3-dev
|
|
6
8
|
|
package/README.md
CHANGED
|
@@ -54,7 +54,11 @@ under consideration:
|
|
|
54
54
|
|
|
55
55
|
## About this plugin version
|
|
56
56
|
|
|
57
|
-
Super-premium enterprise version with additional performance and stability improvements for Android, iOS, ~~and macOS,~~ including workarounds for super-large INSERT transactions and SELECT results on Android - with limited extra features (missing pre-populated database support)
|
|
57
|
+
Super-premium enterprise version with additional performance and stability improvements for Android, iOS, ~~and macOS,~~ including workarounds for super-large INSERT transactions and SELECT results on Android - with limited extra features (missing pre-populated database support)
|
|
58
|
+
|
|
59
|
+
with ICU support for Android & iOS using built-in platform ICU on each platform, using Android JAR built from: https://github.com/brody4hire/android-sqlite-evmax-ndk-driver-free/tree/evmax-icu-support-2026-01
|
|
60
|
+
|
|
61
|
+
NOTE that this should work for UPPER, LOWER, & LIKE functions. REGEXP & `icu_load_collation` cannot be supported consistently by built-in platform ICU on all platforms.
|
|
58
62
|
|
|
59
63
|
<!-- FUTURE TBD critical bug notices for this plugin version -->
|
|
60
64
|
|
|
@@ -252,7 +256,7 @@ See the [Sample section](#sample) for a sample with a more detailed explanation
|
|
|
252
256
|
- The **macOS** platform version (**"osx" platform**) is not tested in a release build and should be considered pre-alpha with known issues:
|
|
253
257
|
- `cordova prepare osx` is needed before building and running from Xcode
|
|
254
258
|
- known issue between `cordova-osx` and Cordova CLI `10.0.0`: <https://github.com/apache/cordova-osx/issues/106>
|
|
255
|
-
- Android versions supported: _minimum
|
|
259
|
+
- Android versions supported: _minimum 12, see also: <https://cordova.apache.org/docs/en/latest/guide/platforms/android/>_
|
|
256
260
|
- iOS versions supported: 8.x / 9.x / 10.x / 11.x / 12.x (see [deviations section](#deviations) below for differences in case of WKWebView)
|
|
257
261
|
- FTS3, FTS4, and R-Tree are fully tested and supported for all target platforms in this version branch.
|
|
258
262
|
- Default `PRAGMA journal_mode` setting (*tested*):
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cordova-sqlite-evmax-build-free",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Cordova/PhoneGap sqlite storage - free evmax enterprise version with premium stability and performance improvements including workaround for super-large INSERT transactions & SELECT results on Android (version with external sqlite3 dependencies)",
|
|
5
5
|
"cordova": {
|
|
6
6
|
"id": "cordova-sqlite-evmax-build-free",
|
package/plugin.xml
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
|
|
3
3
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
4
4
|
id="cordova-sqlite-evmax-build-free"
|
|
5
|
-
version="0.
|
|
5
|
+
version="0.2.0">
|
|
6
6
|
|
|
7
7
|
<name>Cordova sqlite storage - free evmax common version branch with premium stability performance improvements including workaround for super-large INSERT transactions and SELECT results on Android (with external sqlite3 dependencies)</name>
|
|
8
8
|
|
|
@@ -67,6 +67,9 @@
|
|
|
67
67
|
<header-file src="src/deps/common/sqlite3.h" />
|
|
68
68
|
<source-file src="src/deps/common/sqlite3.c"
|
|
69
69
|
compiler-flags="-w -DSQLITE_THREADSAFE=1 -DSQLITE_DEFAULT_SYNCHRONOUS=3 -DSQLITE_LOCKING_STYLE=1 -DHAVE_USLEEP=1 -DSQLITE_DEFAULT_MEMSTATUS=0 -DSQLITE_OMIT_DECLTYPE -DSQLITE_OMIT_DEPRECATED -DSQLITE_OMIT_PROGRESS_CALLBACK -DSQLITE_OMIT_SHARED_CACHE -DSQLITE_TEMP_STORE=2 -DSQLITE_OMIT_LOAD_EXTENSION -DSQLITE_ENABLE_FTS3 -DSQLITE_ENABLE_FTS3_PARENTHESIS -DSQLITE_ENABLE_FTS4 -DSQLITE_ENABLE_FTS5 -DSQLITE_ENABLE_RTREE -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MATH_FUNCTIONS -DSQLITE_DEFAULT_PAGE_SIZE=4096 -DSQLITE_DEFAULT_CACHE_SIZE=-2000" />
|
|
70
|
+
|
|
71
|
+
<header-file src="src/icu/sqliteicu.h" />
|
|
72
|
+
<source-file src="src/icu/icu.c" />
|
|
70
73
|
</platform>
|
|
71
74
|
|
|
72
75
|
<!-- macOS (osx) -->
|
|
@@ -1094,6 +1094,7 @@ var mytests = function() {
|
|
|
1094
1094
|
// - plugin with androidDatabaseImplementation: 2 on
|
|
1095
1095
|
// Android 4.4 & newer
|
|
1096
1096
|
if ((isWebSql && isChromeBrowser) ||
|
|
1097
|
+
!isWebSql || // PLUGIN WITH BUILT-IN ICU SUPPORT
|
|
1097
1098
|
(isAndroid && ((isWebSql && isAndroid && !(/Android 4.[1-3]/.test(navigator.userAgent))) || (isImpl2 && /Android [5-9]/.test(navigator.userAgent)))))
|
|
1098
1099
|
expect(resultRow1.myresult).toBe('AÉ');
|
|
1099
1100
|
else
|
|
@@ -1112,6 +1113,7 @@ var mytests = function() {
|
|
|
1112
1113
|
// - plugin with androidDatabaseImplementation: 2 on
|
|
1113
1114
|
// Android 4.4 & newer
|
|
1114
1115
|
if ((isWebSql && isChromeBrowser) ||
|
|
1116
|
+
!isWebSql || // PLUGIN WITH BUILT-IN ICU SUPPORT
|
|
1115
1117
|
(isAndroid && ((isWebSql && isAndroid && !(/Android 4.[1-3]/.test(navigator.userAgent))) || (isImpl2 && /Android [5-9]/.test(navigator.userAgent)))))
|
|
1116
1118
|
expect(resultRow2.myresult).toBe('BÉ');
|
|
1117
1119
|
else
|
|
@@ -1150,6 +1152,7 @@ var mytests = function() {
|
|
|
1150
1152
|
// - plugin with androidDatabaseImplementation: 2 on
|
|
1151
1153
|
// Android 4.4 & newer
|
|
1152
1154
|
if ((isWebSql && isChromeBrowser) ||
|
|
1155
|
+
!isWebSql || // PLUGIN WITH BUILT-IN ICU SUPPORT
|
|
1153
1156
|
(isAndroid && ((isWebSql && isAndroid && !(/Android 4.[1-3]/.test(navigator.userAgent))) || (isImpl2 && /Android [5-9]/.test(navigator.userAgent)))))
|
|
1154
1157
|
expect(resultRow1.myresult).toBe('aé');
|
|
1155
1158
|
else
|
|
@@ -1168,6 +1171,7 @@ var mytests = function() {
|
|
|
1168
1171
|
// - plugin with androidDatabaseImplementation: 2 on
|
|
1169
1172
|
// Android 4.4 & newer
|
|
1170
1173
|
if ((isWebSql && isChromeBrowser) ||
|
|
1174
|
+
!isWebSql || // PLUGIN WITH BUILT-IN ICU SUPPORT
|
|
1171
1175
|
(isAndroid && ((isWebSql && isAndroid && !(/Android 4.[1-3]/.test(navigator.userAgent))) || (isImpl2 && /Android [5-9]/.test(navigator.userAgent)))))
|
|
1172
1176
|
expect(resultRow2.myresult).toBe('bé');
|
|
1173
1177
|
else
|
|
@@ -1206,6 +1210,7 @@ var mytests = function() {
|
|
|
1206
1210
|
// - plugin with androidDatabaseImplementation: 2 on
|
|
1207
1211
|
// Android 4.4 & newer
|
|
1208
1212
|
if ((isWebSql && isChromeBrowser) ||
|
|
1213
|
+
!isWebSql || // PLUGIN WITH BUILT-IN ICU SUPPORT
|
|
1209
1214
|
(isAndroid && ((isWebSql && isAndroid && !(/Android 4.[1-3]/.test(navigator.userAgent))) || (isImpl2 && /Android [5-9]/.test(navigator.userAgent)))))
|
|
1210
1215
|
expect(resultRow1.myresult).toBe('STRASSE');
|
|
1211
1216
|
else
|
|
@@ -1224,6 +1229,7 @@ var mytests = function() {
|
|
|
1224
1229
|
// - plugin with androidDatabaseImplementation: 2 on
|
|
1225
1230
|
// Android 4.4 & newer
|
|
1226
1231
|
if ((isWebSql && isChromeBrowser) ||
|
|
1232
|
+
!isWebSql || // PLUGIN WITH BUILT-IN ICU SUPPORT
|
|
1227
1233
|
(isAndroid && ((isWebSql && isAndroid && !(/Android 4.[1-3]/.test(navigator.userAgent))) || (isImpl2 && /Android [5-9]/.test(navigator.userAgent)))))
|
|
1228
1234
|
expect(resultRow2.myresult).toBe('STRASSE');
|
|
1229
1235
|
else
|
|
@@ -1434,6 +1440,7 @@ var mytests = function() {
|
|
|
1434
1440
|
// - plugin with androidDatabaseImplementation: 2 on
|
|
1435
1441
|
// Android 4.4 & newer
|
|
1436
1442
|
if ((isWebSql && isChromeBrowser) ||
|
|
1443
|
+
!isWebSql || // PLUGIN WITH BUILT-IN ICU SUPPORT
|
|
1437
1444
|
(isAndroid && ((isWebSql && isAndroid && !(/Android 4.[1-3]/.test(navigator.userAgent))) || (isImpl2 && /Android [5-9]/.test(navigator.userAgent)))))
|
|
1438
1445
|
expect(resultRow1.myresult).toBe('straße');
|
|
1439
1446
|
else
|
|
@@ -1452,6 +1459,7 @@ var mytests = function() {
|
|
|
1452
1459
|
// - plugin with androidDatabaseImplementation: 2 on
|
|
1453
1460
|
// Android 4.4 & newer
|
|
1454
1461
|
if ((isWebSql && isChromeBrowser) ||
|
|
1462
|
+
!isWebSql || // PLUGIN WITH BUILT-IN ICU SUPPORT
|
|
1455
1463
|
(isAndroid && ((isWebSql && isAndroid && !(/Android 4.[1-3]/.test(navigator.userAgent))) || (isImpl2 && /Android [5-9]/.test(navigator.userAgent)))))
|
|
1456
1464
|
expect(resultRow2.myresult).toBe('straße');
|
|
1457
1465
|
else
|
|
@@ -1597,6 +1605,7 @@ var mytests = function() {
|
|
|
1597
1605
|
});
|
|
1598
1606
|
}, MYTIMEOUT);
|
|
1599
1607
|
|
|
1608
|
+
/* ** NOT SUPPORTING OR TESTING THIS CASE WITH BUILT-IN ICU LIB:
|
|
1600
1609
|
it(suiteName + "SELECT LOWER(X'41EDA080EDBCB1') - result column value is '\\uED41\u80A0\\uBCED' ('\uED41\u80A0\uBCED') on Android 4.1-4.3 (WebKit) Web SQL & Windows (UTF-16le), 'a\uD800\uDF31' (non-standard encoding) on Android with default Android NDK provider on all Android versions & androidDatabaseProvider: 'system' on Android 4.x, MISSING on iOS/macOS plugin, 'a\\uFFFD\\uFFFD' ('a\uFFFD\uFFFD') on Android with androidDatabaseProvider: 'system' on Android post-4.x & (WebKit) Web SQL (Android post-4.3/iOS/Browser)", function(done) {
|
|
1601
1610
|
// ref:
|
|
1602
1611
|
// - litehelpers/Cordova-sqlite-evcore-extbuild-free#44
|
|
@@ -1630,6 +1639,7 @@ var mytests = function() {
|
|
|
1630
1639
|
(isWebSql) ? done() : db.close(done, done);
|
|
1631
1640
|
});
|
|
1632
1641
|
}, MYTIMEOUT);
|
|
1642
|
+
** NOT SUPPORTING OR TESTING THIS CASE WITH BUILT-IN ICU LIB */
|
|
1633
1643
|
|
|
1634
1644
|
it(suiteName + 'Inline emoji string manipulation test: SELECT UPPER("a\\uD83D\\uDE03.") [\\u1F603 SMILING FACE (MOUTH OPEN)] - ENCODING ISSUE NOW FIXED on default Android SQLite3 NDK [evplus] implementation for Android post-5.x', function(done) {
|
|
1635
1645
|
// ref:
|
|
@@ -1777,6 +1787,7 @@ var mytests = function() {
|
|
|
1777
1787
|
});
|
|
1778
1788
|
}, MYTIMEOUT);
|
|
1779
1789
|
|
|
1790
|
+
/* ** NOT SUPPORTING OR TESTING THIS CASE WITH BUILT-IN ICU LIB:
|
|
1780
1791
|
it(suiteName + "SELECT LOWER(X'41EDA0BDEDB88321') - result column value is '\\uED41\\uBDA0\\uB8ED\\u2183' ('\uED41\uBDA0\uB8ED\u2183') on Android 4.1-4.3 (WebKit) Web SQL & Windows (UTF-16le), 'a\\uD83D\\uDE03!' ('a\uD83D\uDE03!') [non-standard encoding] on Android with default Android NDK provider on all Android versions & androidDatabaseProvider: 'system' on Android 4.x, MISSING on iOS/macOS plugin, '\\uED41\\uBDA0\\uB8ED\\u2183' ('\uED41\uBDA0\uB8ED\u2183') on Android with androidDatabaseProvider: 'system' on Android post-4.x & (WebKit) Web SQL (Android post-4.3/iOS/Browser)", function(done) {
|
|
1781
1792
|
// ref:
|
|
1782
1793
|
// - litehelpers/Cordova-sqlite-evcore-extbuild-free#44
|
|
@@ -1822,6 +1833,7 @@ var mytests = function() {
|
|
|
1822
1833
|
done.fail();
|
|
1823
1834
|
});
|
|
1824
1835
|
}, MYTIMEOUT);
|
|
1836
|
+
** NOT SUPPORTING OR TESTING THIS CASE WITH BUILT-IN ICU LIB */
|
|
1825
1837
|
|
|
1826
1838
|
// NOTE: the next 3 tests show that for iOS/macOS/Android:
|
|
1827
1839
|
// - UNICODE \u2028 line separator from JavaScript to native (Objective-C/Java) is working OK
|
|
@@ -2030,6 +2042,7 @@ var mytests = function() {
|
|
|
2030
2042
|
// - plugin with androidDatabaseImplementation: 2 on
|
|
2031
2043
|
// Android 4.4 & newer
|
|
2032
2044
|
if ((isWebSql && isChromeBrowser) ||
|
|
2045
|
+
!isWebSql || // PLUGIN WITH BUILT-IN ICU SUPPORT
|
|
2033
2046
|
(isAndroid && ((isWebSql && !(/Android 4.[1-3]/.test(navigator.userAgent))) || (isImpl2 && /Android [5-9]/.test(navigator.userAgent)))))
|
|
2034
2047
|
expect(rs.rows.item(0).upper_result).toBe('TEST ¢ É €');
|
|
2035
2048
|
else
|
|
@@ -2062,6 +2075,7 @@ var mytests = function() {
|
|
|
2062
2075
|
// - plugin with androidDatabaseImplementation: 2 on
|
|
2063
2076
|
// Android 4.4 & newer
|
|
2064
2077
|
if ((isWebSql && isChromeBrowser) ||
|
|
2078
|
+
!isWebSql || // PLUGIN WITH BUILT-IN ICU SUPPORT
|
|
2065
2079
|
(isAndroid && ((isWebSql && !(/Android 4.[1-3]/.test(navigator.userAgent))) || (isImpl2 && /Android [5-9]/.test(navigator.userAgent)))))
|
|
2066
2080
|
expect(rs.rows.item(0).upper_result).toBe('TEST ¢ É €');
|
|
2067
2081
|
else
|
|
Binary file
|
package/src/icu/icu.c
ADDED
|
@@ -0,0 +1,596 @@
|
|
|
1
|
+
/*
|
|
2
|
+
** 2007 May 6
|
|
3
|
+
**
|
|
4
|
+
** The author disclaims copyright to this source code. In place of
|
|
5
|
+
** a legal notice, here is a blessing:
|
|
6
|
+
**
|
|
7
|
+
** May you do good and not evil.
|
|
8
|
+
** May you find forgiveness for yourself and forgive others.
|
|
9
|
+
** May you share freely, never taking more than you give.
|
|
10
|
+
**
|
|
11
|
+
*************************************************************************
|
|
12
|
+
** $Id: icu.c,v 1.7 2007/12/13 21:54:11 drh Exp $
|
|
13
|
+
**
|
|
14
|
+
** This file implements an integration between the ICU library
|
|
15
|
+
** ("International Components for Unicode", an open-source library
|
|
16
|
+
** for handling unicode data) and SQLite. The integration uses
|
|
17
|
+
** ICU to provide the following to SQLite:
|
|
18
|
+
**
|
|
19
|
+
** * An implementation of the SQL regexp() function (and hence REGEXP
|
|
20
|
+
** operator) using the ICU uregex_XX() APIs.
|
|
21
|
+
**
|
|
22
|
+
** * Implementations of the SQL scalar upper() and lower() functions
|
|
23
|
+
** for case mapping.
|
|
24
|
+
**
|
|
25
|
+
** * Integration of ICU and SQLite collation sequences.
|
|
26
|
+
**
|
|
27
|
+
** * An implementation of the LIKE operator that uses ICU to
|
|
28
|
+
** provide case-independent matching.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
#if !defined(SQLITE_CORE) \
|
|
32
|
+
|| defined(SQLITE_ENABLE_ICU) \
|
|
33
|
+
|| defined(SQLITE_ENABLE_ICU_COLLATIONS)
|
|
34
|
+
|
|
35
|
+
/* Include ICU headers */
|
|
36
|
+
#include <unicode/utypes.h>
|
|
37
|
+
#include <unicode/uregex.h>
|
|
38
|
+
#include <unicode/ustring.h>
|
|
39
|
+
#if 0 // AVOID BUILD ISSUE WITH COLLATION
|
|
40
|
+
#include <unicode/ucol.h>
|
|
41
|
+
#endif // AVOID BUILD ISSUE WITH COLLATION
|
|
42
|
+
|
|
43
|
+
#include <assert.h>
|
|
44
|
+
|
|
45
|
+
#ifndef SQLITE_CORE
|
|
46
|
+
#include "sqlite3ext.h"
|
|
47
|
+
SQLITE_EXTENSION_INIT1
|
|
48
|
+
#else
|
|
49
|
+
#include "sqlite3.h"
|
|
50
|
+
#endif
|
|
51
|
+
|
|
52
|
+
/*
|
|
53
|
+
** This function is called when an ICU function called from within
|
|
54
|
+
** the implementation of an SQL scalar function returns an error.
|
|
55
|
+
**
|
|
56
|
+
** The scalar function context passed as the first argument is
|
|
57
|
+
** loaded with an error message based on the following two args.
|
|
58
|
+
*/
|
|
59
|
+
static void icuFunctionError(
|
|
60
|
+
sqlite3_context *pCtx, /* SQLite scalar function context */
|
|
61
|
+
const char *zName, /* Name of ICU function that failed */
|
|
62
|
+
UErrorCode e /* Error code returned by ICU function */
|
|
63
|
+
){
|
|
64
|
+
char zBuf[128];
|
|
65
|
+
sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e));
|
|
66
|
+
zBuf[127] = '\0';
|
|
67
|
+
sqlite3_result_error(pCtx, zBuf, -1);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
|
|
71
|
+
|
|
72
|
+
/*
|
|
73
|
+
** Maximum length (in bytes) of the pattern in a LIKE or GLOB
|
|
74
|
+
** operator.
|
|
75
|
+
*/
|
|
76
|
+
#ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH
|
|
77
|
+
# define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000
|
|
78
|
+
#endif
|
|
79
|
+
|
|
80
|
+
/*
|
|
81
|
+
** Version of sqlite3_free() that is always a function, never a macro.
|
|
82
|
+
*/
|
|
83
|
+
static void xFree(void *p){
|
|
84
|
+
sqlite3_free(p);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/*
|
|
88
|
+
** This lookup table is used to help decode the first byte of
|
|
89
|
+
** a multi-byte UTF8 character. It is copied here from SQLite source
|
|
90
|
+
** code file utf8.c.
|
|
91
|
+
*/
|
|
92
|
+
static const unsigned char icuUtf8Trans1[] = {
|
|
93
|
+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
94
|
+
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
|
95
|
+
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
|
96
|
+
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
|
97
|
+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
98
|
+
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
|
99
|
+
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
|
|
100
|
+
0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
#define SQLITE_ICU_READ_UTF8(zIn, c) \
|
|
104
|
+
c = *(zIn++); \
|
|
105
|
+
if( c>=0xc0 ){ \
|
|
106
|
+
c = icuUtf8Trans1[c-0xc0]; \
|
|
107
|
+
while( (*zIn & 0xc0)==0x80 ){ \
|
|
108
|
+
c = (c<<6) + (0x3f & *(zIn++)); \
|
|
109
|
+
} \
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
#define SQLITE_ICU_SKIP_UTF8(zIn) \
|
|
113
|
+
assert( *zIn ); \
|
|
114
|
+
if( *(zIn++)>=0xc0 ){ \
|
|
115
|
+
while( (*zIn & 0xc0)==0x80 ){zIn++;} \
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
/*
|
|
120
|
+
** Compare two UTF-8 strings for equality where the first string is
|
|
121
|
+
** a "LIKE" expression. Return true (1) if they are the same and
|
|
122
|
+
** false (0) if they are different.
|
|
123
|
+
*/
|
|
124
|
+
static int icuLikeCompare(
|
|
125
|
+
const uint8_t *zPattern, /* LIKE pattern */
|
|
126
|
+
const uint8_t *zString, /* The UTF-8 string to compare against */
|
|
127
|
+
const UChar32 uEsc /* The escape character */
|
|
128
|
+
){
|
|
129
|
+
static const uint32_t MATCH_ONE = (uint32_t)'_';
|
|
130
|
+
static const uint32_t MATCH_ALL = (uint32_t)'%';
|
|
131
|
+
|
|
132
|
+
int prevEscape = 0; /* True if the previous character was uEsc */
|
|
133
|
+
|
|
134
|
+
while( 1 ){
|
|
135
|
+
|
|
136
|
+
/* Read (and consume) the next character from the input pattern. */
|
|
137
|
+
uint32_t uPattern;
|
|
138
|
+
SQLITE_ICU_READ_UTF8(zPattern, uPattern);
|
|
139
|
+
if( uPattern==0 ) break;
|
|
140
|
+
|
|
141
|
+
/* There are now 4 possibilities:
|
|
142
|
+
**
|
|
143
|
+
** 1. uPattern is an unescaped match-all character "%",
|
|
144
|
+
** 2. uPattern is an unescaped match-one character "_",
|
|
145
|
+
** 3. uPattern is an unescaped escape character, or
|
|
146
|
+
** 4. uPattern is to be handled as an ordinary character
|
|
147
|
+
*/
|
|
148
|
+
if( uPattern==MATCH_ALL && !prevEscape && uPattern!=(uint32_t)uEsc ){
|
|
149
|
+
/* Case 1. */
|
|
150
|
+
uint8_t c;
|
|
151
|
+
|
|
152
|
+
/* Skip any MATCH_ALL or MATCH_ONE characters that follow a
|
|
153
|
+
** MATCH_ALL. For each MATCH_ONE, skip one character in the
|
|
154
|
+
** test string.
|
|
155
|
+
*/
|
|
156
|
+
while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){
|
|
157
|
+
if( c==MATCH_ONE ){
|
|
158
|
+
if( *zString==0 ) return 0;
|
|
159
|
+
SQLITE_ICU_SKIP_UTF8(zString);
|
|
160
|
+
}
|
|
161
|
+
zPattern++;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
if( *zPattern==0 ) return 1;
|
|
165
|
+
|
|
166
|
+
while( *zString ){
|
|
167
|
+
if( icuLikeCompare(zPattern, zString, uEsc) ){
|
|
168
|
+
return 1;
|
|
169
|
+
}
|
|
170
|
+
SQLITE_ICU_SKIP_UTF8(zString);
|
|
171
|
+
}
|
|
172
|
+
return 0;
|
|
173
|
+
|
|
174
|
+
}else if( uPattern==MATCH_ONE && !prevEscape && uPattern!=(uint32_t)uEsc ){
|
|
175
|
+
/* Case 2. */
|
|
176
|
+
if( *zString==0 ) return 0;
|
|
177
|
+
SQLITE_ICU_SKIP_UTF8(zString);
|
|
178
|
+
|
|
179
|
+
}else if( uPattern==(uint32_t)uEsc && !prevEscape ){
|
|
180
|
+
/* Case 3. */
|
|
181
|
+
prevEscape = 1;
|
|
182
|
+
|
|
183
|
+
}else{
|
|
184
|
+
/* Case 4. */
|
|
185
|
+
uint32_t uString;
|
|
186
|
+
SQLITE_ICU_READ_UTF8(zString, uString);
|
|
187
|
+
uString = (uint32_t)u_foldCase((UChar32)uString, U_FOLD_CASE_DEFAULT);
|
|
188
|
+
uPattern = (uint32_t)u_foldCase((UChar32)uPattern, U_FOLD_CASE_DEFAULT);
|
|
189
|
+
if( uString!=uPattern ){
|
|
190
|
+
return 0;
|
|
191
|
+
}
|
|
192
|
+
prevEscape = 0;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return *zString==0;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/*
|
|
200
|
+
** Implementation of the like() SQL function. This function implements
|
|
201
|
+
** the build-in LIKE operator. The first argument to the function is the
|
|
202
|
+
** pattern and the second argument is the string. So, the SQL statements:
|
|
203
|
+
**
|
|
204
|
+
** A LIKE B
|
|
205
|
+
**
|
|
206
|
+
** is implemented as like(B, A). If there is an escape character E,
|
|
207
|
+
**
|
|
208
|
+
** A LIKE B ESCAPE E
|
|
209
|
+
**
|
|
210
|
+
** is mapped to like(B, A, E).
|
|
211
|
+
*/
|
|
212
|
+
static void icuLikeFunc(
|
|
213
|
+
sqlite3_context *context,
|
|
214
|
+
int argc,
|
|
215
|
+
sqlite3_value **argv
|
|
216
|
+
){
|
|
217
|
+
const unsigned char *zA = sqlite3_value_text(argv[0]);
|
|
218
|
+
const unsigned char *zB = sqlite3_value_text(argv[1]);
|
|
219
|
+
UChar32 uEsc = 0;
|
|
220
|
+
|
|
221
|
+
/* Limit the length of the LIKE or GLOB pattern to avoid problems
|
|
222
|
+
** of deep recursion and N*N behavior in patternCompare().
|
|
223
|
+
*/
|
|
224
|
+
if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){
|
|
225
|
+
sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1);
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
if( argc==3 ){
|
|
231
|
+
/* The escape character string must consist of a single UTF-8 character.
|
|
232
|
+
** Otherwise, return an error.
|
|
233
|
+
*/
|
|
234
|
+
int nE= sqlite3_value_bytes(argv[2]);
|
|
235
|
+
const unsigned char *zE = sqlite3_value_text(argv[2]);
|
|
236
|
+
int i = 0;
|
|
237
|
+
if( zE==0 ) return;
|
|
238
|
+
U8_NEXT(zE, i, nE, uEsc);
|
|
239
|
+
if( i!=nE){
|
|
240
|
+
sqlite3_result_error(context,
|
|
241
|
+
"ESCAPE expression must be a single character", -1);
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
if( zA && zB ){
|
|
247
|
+
sqlite3_result_int(context, icuLikeCompare(zA, zB, uEsc));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
/*
|
|
252
|
+
** Function to delete compiled regexp objects. Registered as
|
|
253
|
+
** a destructor function with sqlite3_set_auxdata().
|
|
254
|
+
*/
|
|
255
|
+
static void icuRegexpDelete(void *p){
|
|
256
|
+
URegularExpression *pExpr = (URegularExpression *)p;
|
|
257
|
+
uregex_close(pExpr);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/*
|
|
261
|
+
** Implementation of SQLite REGEXP operator. This scalar function takes
|
|
262
|
+
** two arguments. The first is a regular expression pattern to compile
|
|
263
|
+
** the second is a string to match against that pattern. If either
|
|
264
|
+
** argument is an SQL NULL, then NULL Is returned. Otherwise, the result
|
|
265
|
+
** is 1 if the string matches the pattern, or 0 otherwise.
|
|
266
|
+
**
|
|
267
|
+
** SQLite maps the regexp() function to the regexp() operator such
|
|
268
|
+
** that the following two are equivalent:
|
|
269
|
+
**
|
|
270
|
+
** zString REGEXP zPattern
|
|
271
|
+
** regexp(zPattern, zString)
|
|
272
|
+
**
|
|
273
|
+
** Uses the following ICU regexp APIs:
|
|
274
|
+
**
|
|
275
|
+
** uregex_open()
|
|
276
|
+
** uregex_matches()
|
|
277
|
+
** uregex_close()
|
|
278
|
+
*/
|
|
279
|
+
static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
|
|
280
|
+
UErrorCode status = U_ZERO_ERROR;
|
|
281
|
+
URegularExpression *pExpr;
|
|
282
|
+
UBool res;
|
|
283
|
+
const UChar *zString = sqlite3_value_text16(apArg[1]);
|
|
284
|
+
|
|
285
|
+
(void)nArg; /* Unused parameter */
|
|
286
|
+
|
|
287
|
+
/* If the left hand side of the regexp operator is NULL,
|
|
288
|
+
** then the result is also NULL.
|
|
289
|
+
*/
|
|
290
|
+
if( !zString ){
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
pExpr = sqlite3_get_auxdata(p, 0);
|
|
295
|
+
if( !pExpr ){
|
|
296
|
+
const UChar *zPattern = sqlite3_value_text16(apArg[0]);
|
|
297
|
+
if( !zPattern ){
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
pExpr = uregex_open(zPattern, -1, 0, 0, &status);
|
|
301
|
+
|
|
302
|
+
if( U_SUCCESS(status) ){
|
|
303
|
+
sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete);
|
|
304
|
+
pExpr = sqlite3_get_auxdata(p, 0);
|
|
305
|
+
}
|
|
306
|
+
if( !pExpr ){
|
|
307
|
+
icuFunctionError(p, "uregex_open", status);
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/* Configure the text that the regular expression operates on. */
|
|
313
|
+
uregex_setText(pExpr, zString, -1, &status);
|
|
314
|
+
if( !U_SUCCESS(status) ){
|
|
315
|
+
icuFunctionError(p, "uregex_setText", status);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/* Attempt the match */
|
|
320
|
+
res = uregex_matches(pExpr, 0, &status);
|
|
321
|
+
if( !U_SUCCESS(status) ){
|
|
322
|
+
icuFunctionError(p, "uregex_matches", status);
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/* Set the text that the regular expression operates on to a NULL
|
|
327
|
+
** pointer. This is not really necessary, but it is tidier than
|
|
328
|
+
** leaving the regular expression object configured with an invalid
|
|
329
|
+
** pointer after this function returns.
|
|
330
|
+
*/
|
|
331
|
+
uregex_setText(pExpr, 0, 0, &status);
|
|
332
|
+
|
|
333
|
+
/* Return 1 or 0. */
|
|
334
|
+
sqlite3_result_int(p, res ? 1 : 0);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/*
|
|
338
|
+
** Implementations of scalar functions for case mapping - upper() and
|
|
339
|
+
** lower(). Function upper() converts its input to upper-case (ABC).
|
|
340
|
+
** Function lower() converts to lower-case (abc).
|
|
341
|
+
**
|
|
342
|
+
** ICU provides two types of case mapping, "general" case mapping and
|
|
343
|
+
** "language specific". Refer to ICU documentation for the differences
|
|
344
|
+
** between the two.
|
|
345
|
+
**
|
|
346
|
+
** To utilise "general" case mapping, the upper() or lower() scalar
|
|
347
|
+
** functions are invoked with one argument:
|
|
348
|
+
**
|
|
349
|
+
** upper('ABC') -> 'abc'
|
|
350
|
+
** lower('abc') -> 'ABC'
|
|
351
|
+
**
|
|
352
|
+
** To access ICU "language specific" case mapping, upper() or lower()
|
|
353
|
+
** should be invoked with two arguments. The second argument is the name
|
|
354
|
+
** of the locale to use. Passing an empty string ("") or SQL NULL value
|
|
355
|
+
** as the second argument is the same as invoking the 1 argument version
|
|
356
|
+
** of upper() or lower().
|
|
357
|
+
**
|
|
358
|
+
** lower('I', 'en_us') -> 'i'
|
|
359
|
+
** lower('I', 'tr_tr') -> '\u131' (small dotless i)
|
|
360
|
+
**
|
|
361
|
+
** http://www.icu-project.org/userguide/posix.html#case_mappings
|
|
362
|
+
*/
|
|
363
|
+
static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
|
|
364
|
+
const UChar *zInput; /* Pointer to input string */
|
|
365
|
+
UChar *zOutput = 0; /* Pointer to output buffer */
|
|
366
|
+
int nInput; /* Size of utf-16 input string in bytes */
|
|
367
|
+
int nOut; /* Size of output buffer in bytes */
|
|
368
|
+
int cnt;
|
|
369
|
+
int bToUpper; /* True for toupper(), false for tolower() */
|
|
370
|
+
UErrorCode status;
|
|
371
|
+
const char *zLocale = 0;
|
|
372
|
+
|
|
373
|
+
assert(nArg==1 || nArg==2);
|
|
374
|
+
bToUpper = (sqlite3_user_data(p)!=0);
|
|
375
|
+
if( nArg==2 ){
|
|
376
|
+
zLocale = (const char *)sqlite3_value_text(apArg[1]);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
zInput = sqlite3_value_text16(apArg[0]);
|
|
380
|
+
if( !zInput ){
|
|
381
|
+
return;
|
|
382
|
+
}
|
|
383
|
+
nOut = nInput = sqlite3_value_bytes16(apArg[0]);
|
|
384
|
+
if( nOut==0 ){
|
|
385
|
+
sqlite3_result_text16(p, "", 0, SQLITE_STATIC);
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
for(cnt=0; cnt<2; cnt++){
|
|
390
|
+
UChar *zNew = sqlite3_realloc(zOutput, nOut);
|
|
391
|
+
if( zNew==0 ){
|
|
392
|
+
sqlite3_free(zOutput);
|
|
393
|
+
sqlite3_result_error_nomem(p);
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
zOutput = zNew;
|
|
397
|
+
status = U_ZERO_ERROR;
|
|
398
|
+
if( bToUpper ){
|
|
399
|
+
nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
|
|
400
|
+
}else{
|
|
401
|
+
nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status);
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if( U_SUCCESS(status) ){
|
|
405
|
+
sqlite3_result_text16(p, zOutput, nOut, xFree);
|
|
406
|
+
}else if( status==U_BUFFER_OVERFLOW_ERROR ){
|
|
407
|
+
assert( cnt==0 );
|
|
408
|
+
continue;
|
|
409
|
+
}else{
|
|
410
|
+
icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status);
|
|
411
|
+
}
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
assert( 0 ); /* Unreachable */
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
|
|
418
|
+
|
|
419
|
+
#if 0 // AVOID BUILD ISSUE WITH COLLATION
|
|
420
|
+
/*
|
|
421
|
+
** Collation sequence destructor function. The pCtx argument points to
|
|
422
|
+
** a UCollator structure previously allocated using ucol_open().
|
|
423
|
+
*/
|
|
424
|
+
static void icuCollationDel(void *pCtx){
|
|
425
|
+
UCollator *p = (UCollator *)pCtx;
|
|
426
|
+
ucol_close(p);
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/*
|
|
430
|
+
** Collation sequence comparison function. The pCtx argument points to
|
|
431
|
+
** a UCollator structure previously allocated using ucol_open().
|
|
432
|
+
*/
|
|
433
|
+
static int icuCollationColl(
|
|
434
|
+
void *pCtx,
|
|
435
|
+
int nLeft,
|
|
436
|
+
const void *zLeft,
|
|
437
|
+
int nRight,
|
|
438
|
+
const void *zRight
|
|
439
|
+
){
|
|
440
|
+
UCollationResult res;
|
|
441
|
+
UCollator *p = (UCollator *)pCtx;
|
|
442
|
+
res = ucol_strcoll(p, (UChar *)zLeft, nLeft/2, (UChar *)zRight, nRight/2);
|
|
443
|
+
switch( res ){
|
|
444
|
+
case UCOL_LESS: return -1;
|
|
445
|
+
case UCOL_GREATER: return +1;
|
|
446
|
+
case UCOL_EQUAL: return 0;
|
|
447
|
+
}
|
|
448
|
+
assert(!"Unexpected return value from ucol_strcoll()");
|
|
449
|
+
return 0;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
/*
|
|
453
|
+
** Implementation of the scalar function icu_load_collation().
|
|
454
|
+
**
|
|
455
|
+
** This scalar function is used to add ICU collation based collation
|
|
456
|
+
** types to an SQLite database connection. It is intended to be called
|
|
457
|
+
** as follows:
|
|
458
|
+
**
|
|
459
|
+
** SELECT icu_load_collation(<locale>, <collation-name>);
|
|
460
|
+
**
|
|
461
|
+
** Where <locale> is a string containing an ICU locale identifier (i.e.
|
|
462
|
+
** "en_AU", "tr_TR" etc.) and <collation-name> is the name of the
|
|
463
|
+
** collation sequence to create.
|
|
464
|
+
*/
|
|
465
|
+
static void icuLoadCollation(
|
|
466
|
+
sqlite3_context *p,
|
|
467
|
+
int nArg,
|
|
468
|
+
sqlite3_value **apArg
|
|
469
|
+
){
|
|
470
|
+
sqlite3 *db = (sqlite3 *)sqlite3_user_data(p);
|
|
471
|
+
UErrorCode status = U_ZERO_ERROR;
|
|
472
|
+
const char *zLocale; /* Locale identifier - (eg. "jp_JP") */
|
|
473
|
+
const char *zName; /* SQL Collation sequence name (eg. "japanese") */
|
|
474
|
+
UCollator *pUCollator; /* ICU library collation object */
|
|
475
|
+
int rc; /* Return code from sqlite3_create_collation_x() */
|
|
476
|
+
|
|
477
|
+
assert(nArg==2 || nArg==3);
|
|
478
|
+
(void)nArg; /* Unused parameter */
|
|
479
|
+
zLocale = (const char *)sqlite3_value_text(apArg[0]);
|
|
480
|
+
zName = (const char *)sqlite3_value_text(apArg[1]);
|
|
481
|
+
|
|
482
|
+
if( !zLocale || !zName ){
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
pUCollator = ucol_open(zLocale, &status);
|
|
487
|
+
if( !U_SUCCESS(status) ){
|
|
488
|
+
icuFunctionError(p, "ucol_open", status);
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
491
|
+
assert(p);
|
|
492
|
+
if(nArg==3){
|
|
493
|
+
const char *zOption = (const char*)sqlite3_value_text(apArg[2]);
|
|
494
|
+
static const struct {
|
|
495
|
+
const char *zName;
|
|
496
|
+
UColAttributeValue val;
|
|
497
|
+
} aStrength[] = {
|
|
498
|
+
{ "PRIMARY", UCOL_PRIMARY },
|
|
499
|
+
{ "SECONDARY", UCOL_SECONDARY },
|
|
500
|
+
{ "TERTIARY", UCOL_TERTIARY },
|
|
501
|
+
{ "DEFAULT", UCOL_DEFAULT_STRENGTH },
|
|
502
|
+
{ "QUARTERNARY", UCOL_QUATERNARY },
|
|
503
|
+
{ "IDENTICAL", UCOL_IDENTICAL },
|
|
504
|
+
};
|
|
505
|
+
unsigned int i;
|
|
506
|
+
for(i=0; i<sizeof(aStrength)/sizeof(aStrength[0]); i++){
|
|
507
|
+
if( sqlite3_stricmp(zOption,aStrength[i].zName)==0 ){
|
|
508
|
+
ucol_setStrength(pUCollator, aStrength[i].val);
|
|
509
|
+
break;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
if( i>=sizeof(aStrength)/sizeof(aStrength[0]) ){
|
|
513
|
+
sqlite3_str *pStr = sqlite3_str_new(sqlite3_context_db_handle(p));
|
|
514
|
+
sqlite3_str_appendf(pStr,
|
|
515
|
+
"unknown collation strength \"%s\" - should be one of:",
|
|
516
|
+
zOption);
|
|
517
|
+
for(i=0; i<sizeof(aStrength)/sizeof(aStrength[0]); i++){
|
|
518
|
+
sqlite3_str_appendf(pStr, " %s", aStrength[i].zName);
|
|
519
|
+
}
|
|
520
|
+
sqlite3_result_error(p, sqlite3_str_value(pStr), -1);
|
|
521
|
+
sqlite3_free(sqlite3_str_finish(pStr));
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator,
|
|
526
|
+
icuCollationColl, icuCollationDel
|
|
527
|
+
);
|
|
528
|
+
if( rc!=SQLITE_OK ){
|
|
529
|
+
ucol_close(pUCollator);
|
|
530
|
+
sqlite3_result_error(p, "Error registering collation function", -1);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
#endif // AVOID BUILD ISSUE WITH COLLATION
|
|
534
|
+
|
|
535
|
+
/*
|
|
536
|
+
** Register the ICU extension functions with database db.
|
|
537
|
+
*/
|
|
538
|
+
int sqlite3IcuInit(sqlite3 *db){
|
|
539
|
+
# define SQLITEICU_EXTRAFLAGS (SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS)
|
|
540
|
+
static const struct IcuScalar {
|
|
541
|
+
const char *zName; /* Function name */
|
|
542
|
+
unsigned char nArg; /* Number of arguments */
|
|
543
|
+
unsigned int enc; /* Optimal text encoding */
|
|
544
|
+
unsigned char iContext; /* sqlite3_user_data() context */
|
|
545
|
+
void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
|
|
546
|
+
} scalars[] = {
|
|
547
|
+
#if 0 // AVOID BUILD ISSUE WITH COLLATION
|
|
548
|
+
{"icu_load_collation",2,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation},
|
|
549
|
+
{"icu_load_collation",3,SQLITE_UTF8|SQLITE_DIRECTONLY,1, icuLoadCollation},
|
|
550
|
+
#endif // AVOID BUILD ISSUE WITH COLLATION
|
|
551
|
+
#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
|
|
552
|
+
#if 0 // AVOID INCONSISTENCY WITH ANDROID PLATFORM - CLEANUP TODO REMOVE OTHER REGEXP FUNCTIONS FROM THIS BUILD
|
|
553
|
+
{"regexp", 2, SQLITE_ANY|SQLITEICU_EXTRAFLAGS, 0, icuRegexpFunc},
|
|
554
|
+
#endif
|
|
555
|
+
{"lower", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
|
|
556
|
+
{"lower", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
|
|
557
|
+
{"upper", 1, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
|
|
558
|
+
{"upper", 2, SQLITE_UTF16|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
|
|
559
|
+
{"lower", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
|
|
560
|
+
{"lower", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuCaseFunc16},
|
|
561
|
+
{"upper", 1, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
|
|
562
|
+
{"upper", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 1, icuCaseFunc16},
|
|
563
|
+
{"like", 2, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc},
|
|
564
|
+
{"like", 3, SQLITE_UTF8|SQLITEICU_EXTRAFLAGS, 0, icuLikeFunc},
|
|
565
|
+
#endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU) */
|
|
566
|
+
};
|
|
567
|
+
int rc = SQLITE_OK;
|
|
568
|
+
int i;
|
|
569
|
+
|
|
570
|
+
for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){
|
|
571
|
+
const struct IcuScalar *p = &scalars[i];
|
|
572
|
+
rc = sqlite3_create_function(
|
|
573
|
+
db, p->zName, p->nArg, p->enc,
|
|
574
|
+
p->iContext ? (void*)db : (void*)0,
|
|
575
|
+
p->xFunc, 0, 0
|
|
576
|
+
);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
return rc;
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
#ifndef SQLITE_CORE
|
|
583
|
+
#ifdef _WIN32
|
|
584
|
+
__declspec(dllexport)
|
|
585
|
+
#endif
|
|
586
|
+
int sqlite3_icu_init(
|
|
587
|
+
sqlite3 *db,
|
|
588
|
+
char **pzErrMsg,
|
|
589
|
+
const sqlite3_api_routines *pApi
|
|
590
|
+
){
|
|
591
|
+
SQLITE_EXTENSION_INIT2(pApi)
|
|
592
|
+
return sqlite3IcuInit(db);
|
|
593
|
+
}
|
|
594
|
+
#endif
|
|
595
|
+
|
|
596
|
+
#endif
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/*
|
|
2
|
+
** 2008 May 26
|
|
3
|
+
**
|
|
4
|
+
** The author disclaims copyright to this source code. In place of
|
|
5
|
+
** a legal notice, here is a blessing:
|
|
6
|
+
**
|
|
7
|
+
** May you do good and not evil.
|
|
8
|
+
** May you find forgiveness for yourself and forgive others.
|
|
9
|
+
** May you share freely, never taking more than you give.
|
|
10
|
+
**
|
|
11
|
+
******************************************************************************
|
|
12
|
+
**
|
|
13
|
+
** This header file is used by programs that want to link against the
|
|
14
|
+
** ICU extension. All it does is declare the sqlite3IcuInit() interface.
|
|
15
|
+
*/
|
|
16
|
+
#include "sqlite3.h"
|
|
17
|
+
|
|
18
|
+
#ifdef __cplusplus
|
|
19
|
+
extern "C" {
|
|
20
|
+
#endif /* __cplusplus */
|
|
21
|
+
|
|
22
|
+
int sqlite3IcuInit(sqlite3 *db);
|
|
23
|
+
|
|
24
|
+
#ifdef __cplusplus
|
|
25
|
+
} /* extern "C" */
|
|
26
|
+
#endif /* __cplusplus */
|
package/src/ios/SQLitePlugin.m
CHANGED
|
@@ -14,6 +14,8 @@
|
|
|
14
14
|
|
|
15
15
|
#import "sqlite3_base64.h"
|
|
16
16
|
|
|
17
|
+
#import "sqliteicu.h"
|
|
18
|
+
|
|
17
19
|
// Defines Macro to only log lines when in DEBUG mode
|
|
18
20
|
#ifdef DEBUG
|
|
19
21
|
# define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
|
|
@@ -191,6 +193,8 @@
|
|
|
191
193
|
|
|
192
194
|
sqlite3_base64_init(db);
|
|
193
195
|
|
|
196
|
+
sqlite3IcuInit(db);
|
|
197
|
+
|
|
194
198
|
// for SQLCipher version:
|
|
195
199
|
// NSString *dbkey = [options objectForKey:@"key"];
|
|
196
200
|
// const char *key = NULL;
|