sqlite3_android.cpp revision 4b2aeb8073512909db336dd297563f6d07df7537
1/* 2 * Copyright (C) 2007 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#define LOG_TAG "sqlite3_android" 18 19#include <ctype.h> 20#include <stdlib.h> 21#include <string.h> 22#include <unistd.h> 23 24#include <unicode/ucol.h> 25#include <unicode/uiter.h> 26#include <unicode/ustring.h> 27#include <unicode/utypes.h> 28#include <cutils/log.h> 29 30#include "sqlite3_android.h" 31#include "PhoneNumberUtils.h" 32#include "PhonebookIndex.h" 33#include "PhoneticStringUtils.h" 34 35#define ENABLE_ANDROID_LOG 0 36#define SMALL_BUFFER_SIZE 10 37 38static int collate16(void *p, int n1, const void *v1, int n2, const void *v2) 39{ 40 UCollator *coll = (UCollator *) p; 41 UCollationResult result = ucol_strcoll(coll, (const UChar *) v1, n1, 42 (const UChar *) v2, n2); 43 44 if (result == UCOL_LESS) { 45 return -1; 46 } else if (result == UCOL_GREATER) { 47 return 1; 48 } else { 49 return 0; 50 } 51} 52 53static int collate8(void *p, int n1, const void *v1, int n2, const void *v2) 54{ 55 UCollator *coll = (UCollator *) p; 56 UCharIterator i1, i2; 57 UErrorCode status = U_ZERO_ERROR; 58 59 uiter_setUTF8(&i1, (const char *) v1, n1); 60 uiter_setUTF8(&i2, (const char *) v2, n2); 61 62 UCollationResult result = ucol_strcollIter(coll, &i1, &i2, &status); 63 64 if (U_FAILURE(status)) { 65// LOGE("Collation iterator error: %d\n", status); 66 } 67 68 if (result == UCOL_LESS) { 69 return -1; 70 } else if (result == UCOL_GREATER) { 71 return 1; 72 } else { 73 return 0; 74 } 75} 76 77/** 78 * Obtains the first UNICODE letter from the supplied string, normalizes and returns it. 79 */ 80static void get_phonebook_index( 81 sqlite3_context * context, int argc, sqlite3_value ** argv) 82{ 83 if (argc != 2) { 84 sqlite3_result_null(context); 85 return; 86 } 87 88 char const * src = (char const *)sqlite3_value_text(argv[0]); 89 char const * locale = (char const *)sqlite3_value_text(argv[1]); 90 if (src == NULL || src[0] == 0 || locale == NULL) { 91 sqlite3_result_null(context); 92 return; 93 } 94 95 UCharIterator iter; 96 uiter_setUTF8(&iter, src, -1); 97 98 UBool isError = FALSE; 99 UChar index[SMALL_BUFFER_SIZE]; 100 uint32_t len = android::GetPhonebookIndex(&iter, locale, index, sizeof(index), &isError); 101 if (isError) { 102 sqlite3_result_null(context); 103 return; 104 } 105 106 uint32_t outlen = 0; 107 uint8_t out[SMALL_BUFFER_SIZE]; 108 for (uint32_t i = 0; i < len; i++) { 109 U8_APPEND(out, outlen, sizeof(out), index[i], isError); 110 if (isError) { 111 sqlite3_result_null(context); 112 return; 113 } 114 } 115 116 if (outlen == 0) { 117 sqlite3_result_null(context); 118 return; 119 } 120 121 sqlite3_result_text(context, (const char*)out, outlen, SQLITE_TRANSIENT); 122} 123 124static void get_phonetically_sortable_string( 125 sqlite3_context * context, int argc, sqlite3_value ** argv) 126{ 127 if (argc != 1) { 128 sqlite3_result_null(context); 129 return; 130 } 131 char const * src = (char const *)sqlite3_value_text(argv[0]); 132 char * ret; 133 size_t len; 134 135 if (!android::GetPhoneticallySortableString(src, &ret, &len)) { 136 // Put this text at the end of a list. 137 sqlite3_result_text(context, "\xF0\x9F\xBF\xBD", -1, SQLITE_STATIC); 138 // sqlite3_result_null(context); 139 } else { 140 sqlite3_result_text(context, ret, len, free); 141 } 142} 143 144static void get_normalized_string( 145 sqlite3_context * context, int argc, sqlite3_value ** argv) 146{ 147 if (argc != 1) { 148 sqlite3_result_null(context); 149 return; 150 } 151 char const * src = (char const *)sqlite3_value_text(argv[0]); 152 char * ret; 153 size_t len; 154 155 if (!android::GetNormalizedString(src, &ret, &len)) { 156 // Probably broken string. Return 0 length string. 157 sqlite3_result_text(context, "", -1, SQLITE_STATIC); 158 } else { 159 sqlite3_result_text(context, ret, len, free); 160 } 161} 162 163static void phone_numbers_equal(sqlite3_context * context, int argc, sqlite3_value ** argv) 164{ 165 if (argc != 2 && argc != 3) { 166 sqlite3_result_int(context, 0); 167 return; 168 } 169 170 char const * num1 = (char const *)sqlite3_value_text(argv[0]); 171 char const * num2 = (char const *)sqlite3_value_text(argv[1]); 172 173 bool use_strict = false; 174 if (argc == 3) { 175 use_strict = (sqlite3_value_int(argv[2]) != 0); 176 } 177 178 if (num1 == NULL || num2 == NULL) { 179 sqlite3_result_null(context); 180 return; 181 } 182 183 bool equal = 184 (use_strict ? 185 android::phone_number_compare_strict(num1, num2) : 186 android::phone_number_compare_loose(num1, num2)); 187 188 if (equal) { 189 sqlite3_result_int(context, 1); 190 } else { 191 sqlite3_result_int(context, 0); 192 } 193} 194 195#if ENABLE_ANDROID_LOG 196static void android_log(sqlite3_context * context, int argc, sqlite3_value ** argv) 197{ 198 char const * tag = "sqlite_trigger"; 199 char const * msg = ""; 200 int msgIndex = 0; 201 202 switch (argc) { 203 case 2: 204 tag = (char const *)sqlite3_value_text(argv[0]); 205 if (tag == NULL) { 206 tag = "sqlite_trigger"; 207 } 208 msgIndex = 1; 209 case 1: 210 msg = (char const *)sqlite3_value_text(argv[msgIndex]); 211 if (msg == NULL) { 212 msg = ""; 213 } 214 LOG(LOG_INFO, tag, msg); 215 sqlite3_result_int(context, 1); 216 return; 217 218 default: 219 sqlite3_result_int(context, 0); 220 return; 221 } 222} 223#endif 224 225static void delete_file(sqlite3_context * context, int argc, sqlite3_value ** argv) 226{ 227 if (argc != 1) { 228 sqlite3_result_int(context, 0); 229 return; 230 } 231 232 char const * path = (char const *)sqlite3_value_text(argv[0]); 233 if (path == NULL) { 234 sqlite3_result_null(context); 235 return; 236 } 237 238 if (strncmp("/sdcard/", path, 8) != 0) { 239 sqlite3_result_null(context); 240 return; 241 } 242 if (strstr(path, "/../") != NULL) { 243 sqlite3_result_null(context); 244 return; 245 } 246 247 int err = unlink(path); 248 if (err != -1) { 249 // No error occured, return true 250 sqlite3_result_int(context, 1); 251 } else { 252 // An error occured, return false 253 sqlite3_result_int(context, 0); 254 } 255} 256 257static void tokenize_auxdata_delete(void * data) 258{ 259 sqlite3_stmt * statement = (sqlite3_stmt *)data; 260 sqlite3_finalize(statement); 261} 262 263static void base16Encode(char* dest, const char* src, uint32_t size) 264{ 265 static const char * BASE16_TABLE = "0123456789abcdef"; 266 for (uint32_t i = 0; i < size; i++) { 267 char ch = *src++; 268 *dest++ = BASE16_TABLE[ (ch & 0xf0) >> 4 ]; 269 *dest++ = BASE16_TABLE[ (ch & 0x0f) ]; 270 } 271} 272 273struct SqliteUserData { 274 sqlite3 * handle; 275 UCollator* collator; 276}; 277 278/** 279 * This function is invoked as: 280 * 281 * _TOKENIZE('<token_table>', <data_row_id>, <data>, <delimiter>, 282 * <use_token_index>, <data_tag>) 283 * 284 * If <use_token_index> is omitted, it is treated as 0. 285 * If <data_tag> is omitted, it is treated as NULL. 286 * 287 * It will split <data> on each instance of <delimiter> and insert each token 288 * into <token_table>. The following columns in <token_table> are used: 289 * token TEXT, source INTEGER, token_index INTEGER, tag (any type) 290 * The token_index column is not required if <use_token_index> is 0. 291 * The tag column is not required if <data_tag> is NULL. 292 * 293 * One row is inserted for each token in <data>. 294 * In each inserted row, 'source' is <data_row_id>. 295 * In the first inserted row, 'token' is the hex collation key of 296 * the entire <data> string, and 'token_index' is 0. 297 * In each row I (where 1 <= I < N, and N is the number of tokens in <data>) 298 * 'token' will be set to the hex collation key of the I:th token (0-based). 299 * If <use_token_index> != 0, 'token_index' is set to I. 300 * If <data_tag> is not NULL, 'tag' is set to <data_tag>. 301 * 302 * In other words, there will be one row for the entire string, 303 * and one row for each token except the first one. 304 * 305 * The function returns the number of tokens generated. 306 */ 307static void tokenize(sqlite3_context * context, int argc, sqlite3_value ** argv) 308{ 309 //LOGD("enter tokenize"); 310 int err; 311 int useTokenIndex = 0; 312 int useDataTag = 0; 313 314 if (!(argc >= 4 || argc <= 6)) { 315 LOGE("Tokenize requires 4 to 6 arguments"); 316 sqlite3_result_null(context); 317 return; 318 } 319 320 if (argc > 4) { 321 useTokenIndex = sqlite3_value_int(argv[4]); 322 } 323 324 if (argc > 5) { 325 useDataTag = (sqlite3_value_type(argv[5]) != SQLITE_NULL); 326 } 327 328 sqlite3 * handle = sqlite3_context_db_handle(context); 329 UCollator* collator = (UCollator*)sqlite3_user_data(context); 330 char const * tokenTable = (char const *)sqlite3_value_text(argv[0]); 331 if (tokenTable == NULL) { 332 LOGE("tokenTable null"); 333 sqlite3_result_null(context); 334 return; 335 } 336 337 // Get or create the prepared statement for the insertions 338 sqlite3_stmt * statement = (sqlite3_stmt *)sqlite3_get_auxdata(context, 0); 339 if (!statement) { 340 char const * tokenIndexCol = useTokenIndex ? ", token_index" : ""; 341 char const * tokenIndexParam = useTokenIndex ? ", ?" : ""; 342 char const * dataTagCol = useDataTag ? ", tag" : ""; 343 char const * dataTagParam = useDataTag ? ", ?" : ""; 344 char * sql = sqlite3_mprintf("INSERT INTO %s (token, source%s%s) VALUES (?, ?%s%s);", 345 tokenTable, tokenIndexCol, dataTagCol, tokenIndexParam, dataTagParam); 346 err = sqlite3_prepare_v2(handle, sql, -1, &statement, NULL); 347 sqlite3_free(sql); 348 if (err) { 349 LOGE("prepare failed"); 350 sqlite3_result_null(context); 351 return; 352 } 353 // This binds the statement to the table it was compiled against, which is argv[0]. 354 // If this function is ever called with a different table the finalizer will be called 355 // and sqlite3_get_auxdata() will return null above, forcing a recompile for the new table. 356 sqlite3_set_auxdata(context, 0, statement, tokenize_auxdata_delete); 357 } else { 358 // Reset the cached statement so that binding the row ID will work properly 359 sqlite3_reset(statement); 360 } 361 362 // Bind the row ID of the source row 363 int64_t rowID = sqlite3_value_int64(argv[1]); 364 err = sqlite3_bind_int64(statement, 2, rowID); 365 if (err != SQLITE_OK) { 366 LOGE("bind failed"); 367 sqlite3_result_null(context); 368 return; 369 } 370 371 // Bind <data_tag> to the tag column 372 if (useDataTag) { 373 int dataTagParamIndex = useTokenIndex ? 4 : 3; 374 err = sqlite3_bind_value(statement, dataTagParamIndex, argv[5]); 375 if (err != SQLITE_OK) { 376 LOGE("bind failed"); 377 sqlite3_result_null(context); 378 return; 379 } 380 } 381 382 // Get the raw bytes for the string to tokenize 383 // the string will be modified by following code 384 // however, sqlite did not reuse the string, so it is safe to not dup it 385 UChar * origData = (UChar *)sqlite3_value_text16(argv[2]); 386 if (origData == NULL) { 387 sqlite3_result_null(context); 388 return; 389 } 390 391 // Get the raw bytes for the delimiter 392 const UChar * delim = (const UChar *)sqlite3_value_text16(argv[3]); 393 if (delim == NULL) { 394 LOGE("can't get delimiter"); 395 sqlite3_result_null(context); 396 return; 397 } 398 399 UChar * token = NULL; 400 UChar *state; 401 int numTokens = 0; 402 403 do { 404 if (numTokens == 0) { 405 token = origData; 406 } 407 408 // Reset the program so we can use it to perform the insert 409 sqlite3_reset(statement); 410 UErrorCode status = U_ZERO_ERROR; 411 char keybuf[1024]; 412 uint32_t result = ucol_getSortKey(collator, token, -1, (uint8_t*)keybuf, sizeof(keybuf)-1); 413 if (result > sizeof(keybuf)) { 414 // TODO allocate memory for this super big string 415 LOGE("ucol_getSortKey needs bigger buffer %d", result); 416 break; 417 } 418 uint32_t keysize = result-1; 419 uint32_t base16Size = keysize*2; 420 char *base16buf = (char*)malloc(base16Size); 421 base16Encode(base16buf, keybuf, keysize); 422 err = sqlite3_bind_text(statement, 1, base16buf, base16Size, SQLITE_STATIC); 423 424 if (err != SQLITE_OK) { 425 LOGE(" sqlite3_bind_text16 error %d", err); 426 free(base16buf); 427 break; 428 } 429 430 if (useTokenIndex) { 431 err = sqlite3_bind_int(statement, 3, numTokens); 432 if (err != SQLITE_OK) { 433 LOGE(" sqlite3_bind_int error %d", err); 434 free(base16buf); 435 break; 436 } 437 } 438 439 err = sqlite3_step(statement); 440 free(base16buf); 441 442 if (err != SQLITE_DONE) { 443 LOGE(" sqlite3_step error %d", err); 444 break; 445 } 446 numTokens++; 447 if (numTokens == 1) { 448 // first call 449 u_strtok_r(origData, delim, &state); 450 } 451 } while ((token = u_strtok_r(NULL, delim, &state)) != NULL); 452 sqlite3_result_int(context, numTokens); 453} 454 455static void localized_collator_dtor(UCollator* collator) 456{ 457 ucol_close(collator); 458} 459 460#define LOCALIZED_COLLATOR_NAME "LOCALIZED" 461 462extern "C" int register_localized_collators(sqlite3* handle, const char* systemLocale, int utf16Storage) 463{ 464 int err; 465 UErrorCode status = U_ZERO_ERROR; 466 void* icudata; 467 468 UCollator* collator = ucol_open(systemLocale, &status); 469 if (U_FAILURE(status)) { 470 return -1; 471 } 472 473 ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_PRIMARY, &status); 474 if (U_FAILURE(status)) { 475 return -1; 476 } 477 478 status = U_ZERO_ERROR; 479 char buf[1024]; 480 int n = ucol_getShortDefinitionString(collator, NULL, buf, 1024, &status); 481 482 if (utf16Storage) { 483 err = sqlite3_create_collation_v2(handle, LOCALIZED_COLLATOR_NAME, SQLITE_UTF16, collator, 484 collate16, (void(*)(void*))localized_collator_dtor); 485 } else { 486 err = sqlite3_create_collation_v2(handle, LOCALIZED_COLLATOR_NAME, SQLITE_UTF8, collator, 487 collate8, (void(*)(void*))localized_collator_dtor); 488 } 489 if (err != SQLITE_OK) { 490 return err; 491 } 492 493 // Register the _TOKENIZE function 494 err = sqlite3_create_function(handle, "_TOKENIZE", 4, SQLITE_UTF16, collator, tokenize, NULL, NULL); 495 if (err != SQLITE_OK) { 496 return err; 497 } 498 err = sqlite3_create_function(handle, "_TOKENIZE", 5, SQLITE_UTF16, collator, tokenize, NULL, NULL); 499 if (err != SQLITE_OK) { 500 return err; 501 } 502 err = sqlite3_create_function(handle, "_TOKENIZE", 6, SQLITE_UTF16, collator, tokenize, NULL, NULL); 503 if (err != SQLITE_OK) { 504 return err; 505 } 506 507 return SQLITE_OK; 508} 509 510 511extern "C" int register_android_functions(sqlite3 * handle, int utf16Storage) 512{ 513 int err; 514 UErrorCode status = U_ZERO_ERROR; 515 516 UCollator * collator = ucol_open(NULL, &status); 517 if (U_FAILURE(status)) { 518 return -1; 519 } 520 521 if (utf16Storage) { 522 // Note that text should be stored as UTF-16 523 err = sqlite3_exec(handle, "PRAGMA encoding = 'UTF-16'", 0, 0, 0); 524 if (err != SQLITE_OK) { 525 return err; 526 } 527 528 // Register the UNICODE collation 529 err = sqlite3_create_collation_v2(handle, "UNICODE", SQLITE_UTF16, collator, collate16, 530 (void(*)(void*))localized_collator_dtor); 531 } else { 532 err = sqlite3_create_collation_v2(handle, "UNICODE", SQLITE_UTF8, collator, collate8, 533 (void(*)(void*))localized_collator_dtor); 534 } 535 536 if (err != SQLITE_OK) { 537 return err; 538 } 539 540 // Register the PHONE_NUM_EQUALS function 541 err = sqlite3_create_function( 542 handle, "PHONE_NUMBERS_EQUAL", 2, 543 SQLITE_UTF8, NULL, phone_numbers_equal, NULL, NULL); 544 if (err != SQLITE_OK) { 545 return err; 546 } 547 548 // Register the PHONE_NUM_EQUALS function with an additional argument "use_strict" 549 err = sqlite3_create_function( 550 handle, "PHONE_NUMBERS_EQUAL", 3, 551 SQLITE_UTF8, NULL, phone_numbers_equal, NULL, NULL); 552 if (err != SQLITE_OK) { 553 return err; 554 } 555 556 // Register the _DELETE_FILE function 557 err = sqlite3_create_function(handle, "_DELETE_FILE", 1, SQLITE_UTF8, NULL, delete_file, NULL, NULL); 558 if (err != SQLITE_OK) { 559 return err; 560 } 561 562#if ENABLE_ANDROID_LOG 563 // Register the _LOG function 564 err = sqlite3_create_function(handle, "_LOG", 1, SQLITE_UTF8, NULL, android_log, NULL, NULL); 565 if (err != SQLITE_OK) { 566 return err; 567 } 568#endif 569 570 // Register the GET_PHONETICALLY_SORTABLE_STRING function 571 err = sqlite3_create_function(handle, 572 "GET_PHONETICALLY_SORTABLE_STRING", 573 1, SQLITE_UTF8, NULL, 574 get_phonetically_sortable_string, 575 NULL, NULL); 576 if (err != SQLITE_OK) { 577 return err; 578 } 579 580 // Register the GET_NORMALIZED_STRING function 581 err = sqlite3_create_function(handle, 582 "GET_NORMALIZED_STRING", 583 1, SQLITE_UTF8, NULL, 584 get_normalized_string, 585 NULL, NULL); 586 if (err != SQLITE_OK) { 587 return err; 588 } 589 590 // Register the GET_PHONEBOOK_INDEX function 591 err = sqlite3_create_function(handle, 592 "GET_PHONEBOOK_INDEX", 593 2, SQLITE_UTF8, NULL, 594 get_phonebook_index, 595 NULL, NULL); 596 if (err != SQLITE_OK) { 597 return err; 598 } 599 600 return SQLITE_OK; 601} 602