Annotation of embedaddon/sqlite3/ext/icu/icu.c, revision 1.1
1.1 ! misho 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 seqences.
! 26: **
! 27: ** * An implementation of the LIKE operator that uses ICU to
! 28: ** provide case-independent matching.
! 29: */
! 30:
! 31: #if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_ICU)
! 32:
! 33: /* Include ICU headers */
! 34: #include <unicode/utypes.h>
! 35: #include <unicode/uregex.h>
! 36: #include <unicode/ustring.h>
! 37: #include <unicode/ucol.h>
! 38:
! 39: #include <assert.h>
! 40:
! 41: #ifndef SQLITE_CORE
! 42: #include "sqlite3ext.h"
! 43: SQLITE_EXTENSION_INIT1
! 44: #else
! 45: #include "sqlite3.h"
! 46: #endif
! 47:
! 48: /*
! 49: ** Maximum length (in bytes) of the pattern in a LIKE or GLOB
! 50: ** operator.
! 51: */
! 52: #ifndef SQLITE_MAX_LIKE_PATTERN_LENGTH
! 53: # define SQLITE_MAX_LIKE_PATTERN_LENGTH 50000
! 54: #endif
! 55:
! 56: /*
! 57: ** Version of sqlite3_free() that is always a function, never a macro.
! 58: */
! 59: static void xFree(void *p){
! 60: sqlite3_free(p);
! 61: }
! 62:
! 63: /*
! 64: ** Compare two UTF-8 strings for equality where the first string is
! 65: ** a "LIKE" expression. Return true (1) if they are the same and
! 66: ** false (0) if they are different.
! 67: */
! 68: static int icuLikeCompare(
! 69: const uint8_t *zPattern, /* LIKE pattern */
! 70: const uint8_t *zString, /* The UTF-8 string to compare against */
! 71: const UChar32 uEsc /* The escape character */
! 72: ){
! 73: static const int MATCH_ONE = (UChar32)'_';
! 74: static const int MATCH_ALL = (UChar32)'%';
! 75:
! 76: int iPattern = 0; /* Current byte index in zPattern */
! 77: int iString = 0; /* Current byte index in zString */
! 78:
! 79: int prevEscape = 0; /* True if the previous character was uEsc */
! 80:
! 81: while( zPattern[iPattern]!=0 ){
! 82:
! 83: /* Read (and consume) the next character from the input pattern. */
! 84: UChar32 uPattern;
! 85: U8_NEXT_UNSAFE(zPattern, iPattern, uPattern);
! 86: assert(uPattern!=0);
! 87:
! 88: /* There are now 4 possibilities:
! 89: **
! 90: ** 1. uPattern is an unescaped match-all character "%",
! 91: ** 2. uPattern is an unescaped match-one character "_",
! 92: ** 3. uPattern is an unescaped escape character, or
! 93: ** 4. uPattern is to be handled as an ordinary character
! 94: */
! 95: if( !prevEscape && uPattern==MATCH_ALL ){
! 96: /* Case 1. */
! 97: uint8_t c;
! 98:
! 99: /* Skip any MATCH_ALL or MATCH_ONE characters that follow a
! 100: ** MATCH_ALL. For each MATCH_ONE, skip one character in the
! 101: ** test string.
! 102: */
! 103: while( (c=zPattern[iPattern]) == MATCH_ALL || c == MATCH_ONE ){
! 104: if( c==MATCH_ONE ){
! 105: if( zString[iString]==0 ) return 0;
! 106: U8_FWD_1_UNSAFE(zString, iString);
! 107: }
! 108: iPattern++;
! 109: }
! 110:
! 111: if( zPattern[iPattern]==0 ) return 1;
! 112:
! 113: while( zString[iString] ){
! 114: if( icuLikeCompare(&zPattern[iPattern], &zString[iString], uEsc) ){
! 115: return 1;
! 116: }
! 117: U8_FWD_1_UNSAFE(zString, iString);
! 118: }
! 119: return 0;
! 120:
! 121: }else if( !prevEscape && uPattern==MATCH_ONE ){
! 122: /* Case 2. */
! 123: if( zString[iString]==0 ) return 0;
! 124: U8_FWD_1_UNSAFE(zString, iString);
! 125:
! 126: }else if( !prevEscape && uPattern==uEsc){
! 127: /* Case 3. */
! 128: prevEscape = 1;
! 129:
! 130: }else{
! 131: /* Case 4. */
! 132: UChar32 uString;
! 133: U8_NEXT_UNSAFE(zString, iString, uString);
! 134: uString = u_foldCase(uString, U_FOLD_CASE_DEFAULT);
! 135: uPattern = u_foldCase(uPattern, U_FOLD_CASE_DEFAULT);
! 136: if( uString!=uPattern ){
! 137: return 0;
! 138: }
! 139: prevEscape = 0;
! 140: }
! 141: }
! 142:
! 143: return zString[iString]==0;
! 144: }
! 145:
! 146: /*
! 147: ** Implementation of the like() SQL function. This function implements
! 148: ** the build-in LIKE operator. The first argument to the function is the
! 149: ** pattern and the second argument is the string. So, the SQL statements:
! 150: **
! 151: ** A LIKE B
! 152: **
! 153: ** is implemented as like(B, A). If there is an escape character E,
! 154: **
! 155: ** A LIKE B ESCAPE E
! 156: **
! 157: ** is mapped to like(B, A, E).
! 158: */
! 159: static void icuLikeFunc(
! 160: sqlite3_context *context,
! 161: int argc,
! 162: sqlite3_value **argv
! 163: ){
! 164: const unsigned char *zA = sqlite3_value_text(argv[0]);
! 165: const unsigned char *zB = sqlite3_value_text(argv[1]);
! 166: UChar32 uEsc = 0;
! 167:
! 168: /* Limit the length of the LIKE or GLOB pattern to avoid problems
! 169: ** of deep recursion and N*N behavior in patternCompare().
! 170: */
! 171: if( sqlite3_value_bytes(argv[0])>SQLITE_MAX_LIKE_PATTERN_LENGTH ){
! 172: sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1);
! 173: return;
! 174: }
! 175:
! 176:
! 177: if( argc==3 ){
! 178: /* The escape character string must consist of a single UTF-8 character.
! 179: ** Otherwise, return an error.
! 180: */
! 181: int nE= sqlite3_value_bytes(argv[2]);
! 182: const unsigned char *zE = sqlite3_value_text(argv[2]);
! 183: int i = 0;
! 184: if( zE==0 ) return;
! 185: U8_NEXT(zE, i, nE, uEsc);
! 186: if( i!=nE){
! 187: sqlite3_result_error(context,
! 188: "ESCAPE expression must be a single character", -1);
! 189: return;
! 190: }
! 191: }
! 192:
! 193: if( zA && zB ){
! 194: sqlite3_result_int(context, icuLikeCompare(zA, zB, uEsc));
! 195: }
! 196: }
! 197:
! 198: /*
! 199: ** This function is called when an ICU function called from within
! 200: ** the implementation of an SQL scalar function returns an error.
! 201: **
! 202: ** The scalar function context passed as the first argument is
! 203: ** loaded with an error message based on the following two args.
! 204: */
! 205: static void icuFunctionError(
! 206: sqlite3_context *pCtx, /* SQLite scalar function context */
! 207: const char *zName, /* Name of ICU function that failed */
! 208: UErrorCode e /* Error code returned by ICU function */
! 209: ){
! 210: char zBuf[128];
! 211: sqlite3_snprintf(128, zBuf, "ICU error: %s(): %s", zName, u_errorName(e));
! 212: zBuf[127] = '\0';
! 213: sqlite3_result_error(pCtx, zBuf, -1);
! 214: }
! 215:
! 216: /*
! 217: ** Function to delete compiled regexp objects. Registered as
! 218: ** a destructor function with sqlite3_set_auxdata().
! 219: */
! 220: static void icuRegexpDelete(void *p){
! 221: URegularExpression *pExpr = (URegularExpression *)p;
! 222: uregex_close(pExpr);
! 223: }
! 224:
! 225: /*
! 226: ** Implementation of SQLite REGEXP operator. This scalar function takes
! 227: ** two arguments. The first is a regular expression pattern to compile
! 228: ** the second is a string to match against that pattern. If either
! 229: ** argument is an SQL NULL, then NULL Is returned. Otherwise, the result
! 230: ** is 1 if the string matches the pattern, or 0 otherwise.
! 231: **
! 232: ** SQLite maps the regexp() function to the regexp() operator such
! 233: ** that the following two are equivalent:
! 234: **
! 235: ** zString REGEXP zPattern
! 236: ** regexp(zPattern, zString)
! 237: **
! 238: ** Uses the following ICU regexp APIs:
! 239: **
! 240: ** uregex_open()
! 241: ** uregex_matches()
! 242: ** uregex_close()
! 243: */
! 244: static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){
! 245: UErrorCode status = U_ZERO_ERROR;
! 246: URegularExpression *pExpr;
! 247: UBool res;
! 248: const UChar *zString = sqlite3_value_text16(apArg[1]);
! 249:
! 250: (void)nArg; /* Unused parameter */
! 251:
! 252: /* If the left hand side of the regexp operator is NULL,
! 253: ** then the result is also NULL.
! 254: */
! 255: if( !zString ){
! 256: return;
! 257: }
! 258:
! 259: pExpr = sqlite3_get_auxdata(p, 0);
! 260: if( !pExpr ){
! 261: const UChar *zPattern = sqlite3_value_text16(apArg[0]);
! 262: if( !zPattern ){
! 263: return;
! 264: }
! 265: pExpr = uregex_open(zPattern, -1, 0, 0, &status);
! 266:
! 267: if( U_SUCCESS(status) ){
! 268: sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete);
! 269: }else{
! 270: assert(!pExpr);
! 271: icuFunctionError(p, "uregex_open", status);
! 272: return;
! 273: }
! 274: }
! 275:
! 276: /* Configure the text that the regular expression operates on. */
! 277: uregex_setText(pExpr, zString, -1, &status);
! 278: if( !U_SUCCESS(status) ){
! 279: icuFunctionError(p, "uregex_setText", status);
! 280: return;
! 281: }
! 282:
! 283: /* Attempt the match */
! 284: res = uregex_matches(pExpr, 0, &status);
! 285: if( !U_SUCCESS(status) ){
! 286: icuFunctionError(p, "uregex_matches", status);
! 287: return;
! 288: }
! 289:
! 290: /* Set the text that the regular expression operates on to a NULL
! 291: ** pointer. This is not really necessary, but it is tidier than
! 292: ** leaving the regular expression object configured with an invalid
! 293: ** pointer after this function returns.
! 294: */
! 295: uregex_setText(pExpr, 0, 0, &status);
! 296:
! 297: /* Return 1 or 0. */
! 298: sqlite3_result_int(p, res ? 1 : 0);
! 299: }
! 300:
! 301: /*
! 302: ** Implementations of scalar functions for case mapping - upper() and
! 303: ** lower(). Function upper() converts its input to upper-case (ABC).
! 304: ** Function lower() converts to lower-case (abc).
! 305: **
! 306: ** ICU provides two types of case mapping, "general" case mapping and
! 307: ** "language specific". Refer to ICU documentation for the differences
! 308: ** between the two.
! 309: **
! 310: ** To utilise "general" case mapping, the upper() or lower() scalar
! 311: ** functions are invoked with one argument:
! 312: **
! 313: ** upper('ABC') -> 'abc'
! 314: ** lower('abc') -> 'ABC'
! 315: **
! 316: ** To access ICU "language specific" case mapping, upper() or lower()
! 317: ** should be invoked with two arguments. The second argument is the name
! 318: ** of the locale to use. Passing an empty string ("") or SQL NULL value
! 319: ** as the second argument is the same as invoking the 1 argument version
! 320: ** of upper() or lower().
! 321: **
! 322: ** lower('I', 'en_us') -> 'i'
! 323: ** lower('I', 'tr_tr') -> 'ı' (small dotless i)
! 324: **
! 325: ** http://www.icu-project.org/userguide/posix.html#case_mappings
! 326: */
! 327: static void icuCaseFunc16(sqlite3_context *p, int nArg, sqlite3_value **apArg){
! 328: const UChar *zInput;
! 329: UChar *zOutput;
! 330: int nInput;
! 331: int nOutput;
! 332:
! 333: UErrorCode status = U_ZERO_ERROR;
! 334: const char *zLocale = 0;
! 335:
! 336: assert(nArg==1 || nArg==2);
! 337: if( nArg==2 ){
! 338: zLocale = (const char *)sqlite3_value_text(apArg[1]);
! 339: }
! 340:
! 341: zInput = sqlite3_value_text16(apArg[0]);
! 342: if( !zInput ){
! 343: return;
! 344: }
! 345: nInput = sqlite3_value_bytes16(apArg[0]);
! 346:
! 347: nOutput = nInput * 2 + 2;
! 348: zOutput = sqlite3_malloc(nOutput);
! 349: if( !zOutput ){
! 350: return;
! 351: }
! 352:
! 353: if( sqlite3_user_data(p) ){
! 354: u_strToUpper(zOutput, nOutput/2, zInput, nInput/2, zLocale, &status);
! 355: }else{
! 356: u_strToLower(zOutput, nOutput/2, zInput, nInput/2, zLocale, &status);
! 357: }
! 358:
! 359: if( !U_SUCCESS(status) ){
! 360: icuFunctionError(p, "u_strToLower()/u_strToUpper", status);
! 361: return;
! 362: }
! 363:
! 364: sqlite3_result_text16(p, zOutput, -1, xFree);
! 365: }
! 366:
! 367: /*
! 368: ** Collation sequence destructor function. The pCtx argument points to
! 369: ** a UCollator structure previously allocated using ucol_open().
! 370: */
! 371: static void icuCollationDel(void *pCtx){
! 372: UCollator *p = (UCollator *)pCtx;
! 373: ucol_close(p);
! 374: }
! 375:
! 376: /*
! 377: ** Collation sequence comparison function. The pCtx argument points to
! 378: ** a UCollator structure previously allocated using ucol_open().
! 379: */
! 380: static int icuCollationColl(
! 381: void *pCtx,
! 382: int nLeft,
! 383: const void *zLeft,
! 384: int nRight,
! 385: const void *zRight
! 386: ){
! 387: UCollationResult res;
! 388: UCollator *p = (UCollator *)pCtx;
! 389: res = ucol_strcoll(p, (UChar *)zLeft, nLeft/2, (UChar *)zRight, nRight/2);
! 390: switch( res ){
! 391: case UCOL_LESS: return -1;
! 392: case UCOL_GREATER: return +1;
! 393: case UCOL_EQUAL: return 0;
! 394: }
! 395: assert(!"Unexpected return value from ucol_strcoll()");
! 396: return 0;
! 397: }
! 398:
! 399: /*
! 400: ** Implementation of the scalar function icu_load_collation().
! 401: **
! 402: ** This scalar function is used to add ICU collation based collation
! 403: ** types to an SQLite database connection. It is intended to be called
! 404: ** as follows:
! 405: **
! 406: ** SELECT icu_load_collation(<locale>, <collation-name>);
! 407: **
! 408: ** Where <locale> is a string containing an ICU locale identifier (i.e.
! 409: ** "en_AU", "tr_TR" etc.) and <collation-name> is the name of the
! 410: ** collation sequence to create.
! 411: */
! 412: static void icuLoadCollation(
! 413: sqlite3_context *p,
! 414: int nArg,
! 415: sqlite3_value **apArg
! 416: ){
! 417: sqlite3 *db = (sqlite3 *)sqlite3_user_data(p);
! 418: UErrorCode status = U_ZERO_ERROR;
! 419: const char *zLocale; /* Locale identifier - (eg. "jp_JP") */
! 420: const char *zName; /* SQL Collation sequence name (eg. "japanese") */
! 421: UCollator *pUCollator; /* ICU library collation object */
! 422: int rc; /* Return code from sqlite3_create_collation_x() */
! 423:
! 424: assert(nArg==2);
! 425: zLocale = (const char *)sqlite3_value_text(apArg[0]);
! 426: zName = (const char *)sqlite3_value_text(apArg[1]);
! 427:
! 428: if( !zLocale || !zName ){
! 429: return;
! 430: }
! 431:
! 432: pUCollator = ucol_open(zLocale, &status);
! 433: if( !U_SUCCESS(status) ){
! 434: icuFunctionError(p, "ucol_open", status);
! 435: return;
! 436: }
! 437: assert(p);
! 438:
! 439: rc = sqlite3_create_collation_v2(db, zName, SQLITE_UTF16, (void *)pUCollator,
! 440: icuCollationColl, icuCollationDel
! 441: );
! 442: if( rc!=SQLITE_OK ){
! 443: ucol_close(pUCollator);
! 444: sqlite3_result_error(p, "Error registering collation function", -1);
! 445: }
! 446: }
! 447:
! 448: /*
! 449: ** Register the ICU extension functions with database db.
! 450: */
! 451: int sqlite3IcuInit(sqlite3 *db){
! 452: struct IcuScalar {
! 453: const char *zName; /* Function name */
! 454: int nArg; /* Number of arguments */
! 455: int enc; /* Optimal text encoding */
! 456: void *pContext; /* sqlite3_user_data() context */
! 457: void (*xFunc)(sqlite3_context*,int,sqlite3_value**);
! 458: } scalars[] = {
! 459: {"regexp", 2, SQLITE_ANY, 0, icuRegexpFunc},
! 460:
! 461: {"lower", 1, SQLITE_UTF16, 0, icuCaseFunc16},
! 462: {"lower", 2, SQLITE_UTF16, 0, icuCaseFunc16},
! 463: {"upper", 1, SQLITE_UTF16, (void*)1, icuCaseFunc16},
! 464: {"upper", 2, SQLITE_UTF16, (void*)1, icuCaseFunc16},
! 465:
! 466: {"lower", 1, SQLITE_UTF8, 0, icuCaseFunc16},
! 467: {"lower", 2, SQLITE_UTF8, 0, icuCaseFunc16},
! 468: {"upper", 1, SQLITE_UTF8, (void*)1, icuCaseFunc16},
! 469: {"upper", 2, SQLITE_UTF8, (void*)1, icuCaseFunc16},
! 470:
! 471: {"like", 2, SQLITE_UTF8, 0, icuLikeFunc},
! 472: {"like", 3, SQLITE_UTF8, 0, icuLikeFunc},
! 473:
! 474: {"icu_load_collation", 2, SQLITE_UTF8, (void*)db, icuLoadCollation},
! 475: };
! 476:
! 477: int rc = SQLITE_OK;
! 478: int i;
! 479:
! 480: for(i=0; rc==SQLITE_OK && i<(int)(sizeof(scalars)/sizeof(scalars[0])); i++){
! 481: struct IcuScalar *p = &scalars[i];
! 482: rc = sqlite3_create_function(
! 483: db, p->zName, p->nArg, p->enc, p->pContext, p->xFunc, 0, 0
! 484: );
! 485: }
! 486:
! 487: return rc;
! 488: }
! 489:
! 490: #if !SQLITE_CORE
! 491: int sqlite3_extension_init(
! 492: sqlite3 *db,
! 493: char **pzErrMsg,
! 494: const sqlite3_api_routines *pApi
! 495: ){
! 496: SQLITE_EXTENSION_INIT2(pApi)
! 497: return sqlite3IcuInit(db);
! 498: }
! 499: #endif
! 500:
! 501: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>