Index: third_party/sqlite/src/ext/icu/icu.c |
diff --git a/third_party/sqlite/src/ext/icu/icu.c b/third_party/sqlite/src/ext/icu/icu.c |
index da34f3b11a90b6ab8dd4bea509e30d36bb0353f3..7c37812d86aed44e6b975546b2b7f1a8e2a27e59 100644 |
--- a/third_party/sqlite/src/ext/icu/icu.c |
+++ b/third_party/sqlite/src/ext/icu/icu.c |
@@ -61,6 +61,38 @@ static void xFree(void *p){ |
} |
/* |
+** This lookup table is used to help decode the first byte of |
+** a multi-byte UTF8 character. It is copied here from SQLite source |
+** code file utf8.c. |
+*/ |
+static const unsigned char icuUtf8Trans1[] = { |
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, |
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, |
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, |
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, |
+ 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, |
+}; |
+ |
+#define SQLITE_ICU_READ_UTF8(zIn, c) \ |
+ c = *(zIn++); \ |
+ if( c>=0xc0 ){ \ |
+ c = icuUtf8Trans1[c-0xc0]; \ |
+ while( (*zIn & 0xc0)==0x80 ){ \ |
+ c = (c<<6) + (0x3f & *(zIn++)); \ |
+ } \ |
+ } |
+ |
+#define SQLITE_ICU_SKIP_UTF8(zIn) \ |
+ assert( *zIn ); \ |
+ if( *(zIn++)>=0xc0 ){ \ |
+ while( (*zIn & 0xc0)==0x80 ){zIn++;} \ |
+ } |
+ |
+ |
+/* |
** Compare two UTF-8 strings for equality where the first string is |
** a "LIKE" expression. Return true (1) if they are the same and |
** false (0) if they are different. |
@@ -73,16 +105,14 @@ static int icuLikeCompare( |
static const int MATCH_ONE = (UChar32)'_'; |
static const int MATCH_ALL = (UChar32)'%'; |
- int iPattern = 0; /* Current byte index in zPattern */ |
- int iString = 0; /* Current byte index in zString */ |
- |
int prevEscape = 0; /* True if the previous character was uEsc */ |
- while( zPattern[iPattern]!=0 ){ |
+ while( 1 ){ |
/* Read (and consume) the next character from the input pattern. */ |
UChar32 uPattern; |
- U8_NEXT_OR_FFFD(zPattern, iPattern, -1, uPattern); |
+ SQLITE_ICU_READ_UTF8(zPattern, uPattern); |
+ if( uPattern==0 ) break; |
/* There are now 4 possibilities: |
** |
@@ -99,28 +129,28 @@ static int icuLikeCompare( |
** MATCH_ALL. For each MATCH_ONE, skip one character in the |
** test string. |
*/ |
- while( (c=zPattern[iPattern]) == MATCH_ALL || c == MATCH_ONE ){ |
+ while( (c=*zPattern) == MATCH_ALL || c == MATCH_ONE ){ |
if( c==MATCH_ONE ){ |
- if( zString[iString]==0 ) return 0; |
- U8_FWD_1(zString, iString, -1); |
+ if( *zString==0 ) return 0; |
+ SQLITE_ICU_SKIP_UTF8(zString); |
} |
- iPattern++; |
+ zPattern++; |
} |
- if( zPattern[iPattern]==0 ) return 1; |
+ if( *zPattern==0 ) return 1; |
- while( zString[iString] ){ |
- if( icuLikeCompare(&zPattern[iPattern], &zString[iString], uEsc) ){ |
+ while( *zString ){ |
+ if( icuLikeCompare(zPattern, zString, uEsc) ){ |
return 1; |
} |
- U8_FWD_1(zString, iString, -1); |
+ SQLITE_ICU_SKIP_UTF8(zString); |
} |
return 0; |
}else if( !prevEscape && uPattern==MATCH_ONE ){ |
/* Case 2. */ |
- if( zString[iString]==0 ) return 0; |
- U8_FWD_1(zString, iString, -1); |
+ if( *zString==0 ) return 0; |
+ SQLITE_ICU_SKIP_UTF8(zString); |
}else if( !prevEscape && uPattern==uEsc){ |
/* Case 3. */ |
@@ -129,7 +159,7 @@ static int icuLikeCompare( |
}else{ |
/* Case 4. */ |
UChar32 uString; |
- U8_NEXT_OR_FFFD(zString, iString, -1, uString); |
+ SQLITE_ICU_READ_UTF8(zString, uString); |
uString = u_foldCase(uString, U_FOLD_CASE_DEFAULT); |
uPattern = u_foldCase(uPattern, U_FOLD_CASE_DEFAULT); |
if( uString!=uPattern ){ |
@@ -139,7 +169,7 @@ static int icuLikeCompare( |
} |
} |
- return zString[iString]==0; |
+ return *zString==0; |
} |
/* |
@@ -319,20 +349,22 @@ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ |
** of upper() or lower(). |
** |
** lower('I', 'en_us') -> 'i' |
-** lower('I', 'tr_tr') -> 'ı' (small dotless i) |
+** lower('I', 'tr_tr') -> '\u131' (small dotless i) |
** |
** http://www.icu-project.org/userguide/posix.html#case_mappings |
*/ |
static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ |
- const UChar *zInput; |
- UChar *zOutput = 0; |
- int nInput; |
- int nOut; |
+ const UChar *zInput; /* Pointer to input string */ |
+ UChar *zOutput = 0; /* Pointer to output buffer */ |
+ int nInput; /* Size of utf-16 input string in bytes */ |
+ int nOut; /* Size of output buffer in bytes */ |
int cnt; |
+ int bToUpper; /* True for toupper(), false for tolower() */ |
UErrorCode status; |
const char *zLocale = 0; |
assert(nArg==1 || nArg==2); |
+ bToUpper = (sqlite3_user_data(p)!=0); |
if( nArg==2 ){ |
zLocale = (const char *)sqlite3_value_text(apArg[1]); |
} |
@@ -356,19 +388,23 @@ static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){ |
} |
zOutput = zNew; |
status = U_ZERO_ERROR; |
- if( sqlite3_user_data(p) ){ |
+ if( bToUpper ){ |
nOut = 2*u_strToUpper(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); |
}else{ |
nOut = 2*u_strToLower(zOutput,nOut/2,zInput,nInput/2,zLocale,&status); |
} |
- if( !U_SUCCESS(status) ){ |
- if( status==U_BUFFER_OVERFLOW_ERROR ) continue; |
- icuFunctionError(p, |
- sqlite3_user_data(p) ? "u_strToUpper()" : "u_strToLower", status); |
- return; |
+ |
+ if( U_SUCCESS(status) ){ |
+ sqlite3_result_text16(p, zOutput, nOut, xFree); |
+ }else if( status==U_BUFFER_OVERFLOW_ERROR ){ |
+ assert( cnt==0 ); |
+ continue; |
+ }else{ |
+ icuFunctionError(p, bToUpper ? "u_strToUpper" : "u_strToLower", status); |
} |
+ return; |
} |
- sqlite3_result_text16(p, zOutput, nOut, xFree); |
+ assert( 0 ); /* Unreachable */ |
} |
/* |
@@ -457,38 +493,36 @@ static void icuLoadCollation( |
** Register the ICU extension functions with database db. |
*/ |
int sqlite3IcuInit(sqlite3 *db){ |
- struct IcuScalar { |
+ static const struct IcuScalar { |
const char *zName; /* Function name */ |
- int nArg; /* Number of arguments */ |
- int enc; /* Optimal text encoding */ |
- void *pContext; /* sqlite3_user_data() context */ |
+ unsigned char nArg; /* Number of arguments */ |
+ unsigned short enc; /* Optimal text encoding */ |
+ unsigned char iContext; /* sqlite3_user_data() context */ |
void (*xFunc)(sqlite3_context*,int,sqlite3_value**); |
} scalars[] = { |
- {"regexp", 2, SQLITE_ANY, 0, icuRegexpFunc}, |
- |
- {"lower", 1, SQLITE_UTF16, 0, icuCaseFunc16}, |
- {"lower", 2, SQLITE_UTF16, 0, icuCaseFunc16}, |
- {"upper", 1, SQLITE_UTF16, (void*)1, icuCaseFunc16}, |
- {"upper", 2, SQLITE_UTF16, (void*)1, icuCaseFunc16}, |
- |
- {"lower", 1, SQLITE_UTF8, 0, icuCaseFunc16}, |
- {"lower", 2, SQLITE_UTF8, 0, icuCaseFunc16}, |
- {"upper", 1, SQLITE_UTF8, (void*)1, icuCaseFunc16}, |
- {"upper", 2, SQLITE_UTF8, (void*)1, icuCaseFunc16}, |
- |
- {"like", 2, SQLITE_UTF8, 0, icuLikeFunc}, |
- {"like", 3, SQLITE_UTF8, 0, icuLikeFunc}, |
- |
- {"icu_load_collation", 2, SQLITE_UTF8, (void*)db, icuLoadCollation}, |
+ {"icu_load_collation", 2, SQLITE_UTF8, 1, icuLoadCollation}, |
+ {"regexp", 2, SQLITE_ANY|SQLITE_DETERMINISTIC, 0, icuRegexpFunc}, |
+ {"lower", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, |
+ {"lower", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, |
+ {"upper", 1, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, |
+ {"upper", 2, SQLITE_UTF16|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, |
+ {"lower", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, |
+ {"lower", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuCaseFunc16}, |
+ {"upper", 1, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, |
+ {"upper", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 1, icuCaseFunc16}, |
+ {"like", 2, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc}, |
+ {"like", 3, SQLITE_UTF8|SQLITE_DETERMINISTIC, 0, icuLikeFunc}, |
}; |
- |
int rc = SQLITE_OK; |
int i; |
+ |
for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){ |
- struct IcuScalar *p = &scalars[i]; |
+ const struct IcuScalar *p = &scalars[i]; |
rc = sqlite3_create_function( |
- db, p->zName, p->nArg, p->enc, p->pContext, p->xFunc, 0, 0 |
+ db, p->zName, p->nArg, p->enc, |
+ p->iContext ? (void*)db : (void*)0, |
+ p->xFunc, 0, 0 |
); |
} |