sqlite3_android.cpp revision 165c687ec0f21b4ca003384a7528305e38d2f4c6
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 34#define ENABLE_ANDROID_LOG 0 35#define SMALL_BUFFER_SIZE 10 36#define PHONE_NUMBER_BUFFER_SIZE 40 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// ALOGE("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 phone_numbers_equal(sqlite3_context * context, int argc, sqlite3_value ** argv) 125{ 126 if (argc != 2 && argc != 3) { 127 sqlite3_result_int(context, 0); 128 return; 129 } 130 131 char const * num1 = (char const *)sqlite3_value_text(argv[0]); 132 char const * num2 = (char const *)sqlite3_value_text(argv[1]); 133 134 bool use_strict = false; 135 if (argc == 3) { 136 use_strict = (sqlite3_value_int(argv[2]) != 0); 137 } 138 139 if (num1 == NULL || num2 == NULL) { 140 sqlite3_result_null(context); 141 return; 142 } 143 144 bool equal = 145 (use_strict ? 146 android::phone_number_compare_strict(num1, num2) : 147 android::phone_number_compare_loose(num1, num2)); 148 149 if (equal) { 150 sqlite3_result_int(context, 1); 151 } else { 152 sqlite3_result_int(context, 0); 153 } 154} 155 156static void phone_number_stripped_reversed(sqlite3_context * context, int argc, 157 sqlite3_value ** argv) 158{ 159 if (argc != 1) { 160 sqlite3_result_int(context, 0); 161 return; 162 } 163 164 char const * number = (char const *)sqlite3_value_text(argv[0]); 165 if (number == NULL) { 166 sqlite3_result_null(context); 167 return; 168 } 169 170 char out[PHONE_NUMBER_BUFFER_SIZE]; 171 int outlen = 0; 172 android::phone_number_stripped_reversed_inter(number, out, PHONE_NUMBER_BUFFER_SIZE, &outlen); 173 sqlite3_result_text(context, (const char*)out, outlen, SQLITE_TRANSIENT); 174} 175 176 177#if ENABLE_ANDROID_LOG 178static void android_log(sqlite3_context * context, int argc, sqlite3_value ** argv) 179{ 180 char const * tag = "sqlite_trigger"; 181 char const * msg = ""; 182 int msgIndex = 0; 183 184 switch (argc) { 185 case 2: 186 tag = (char const *)sqlite3_value_text(argv[0]); 187 if (tag == NULL) { 188 tag = "sqlite_trigger"; 189 } 190 msgIndex = 1; 191 case 1: 192 msg = (char const *)sqlite3_value_text(argv[msgIndex]); 193 if (msg == NULL) { 194 msg = ""; 195 } 196 ALOG(LOG_INFO, tag, "%s", msg); 197 sqlite3_result_int(context, 1); 198 return; 199 200 default: 201 sqlite3_result_int(context, 0); 202 return; 203 } 204} 205#endif 206 207static void delete_file(sqlite3_context * context, int argc, sqlite3_value ** argv) 208{ 209 if (argc != 1) { 210 sqlite3_result_int(context, 0); 211 return; 212 } 213 214 char const * path = (char const *)sqlite3_value_text(argv[0]); 215 // Don't allow ".." in paths 216 if (path == NULL || strstr(path, "/../") != NULL) { 217 sqlite3_result_null(context); 218 return; 219 } 220 221 // We only allow deleting files in the EXTERNAL_STORAGE path, or one of the 222 // SECONDARY_STORAGE paths 223 bool good_path = false; 224 char const * external_storage = getenv("EXTERNAL_STORAGE"); 225 if (external_storage && strncmp(external_storage, path, strlen(external_storage)) == 0) { 226 good_path = true; 227 } else { 228 // check SECONDARY_STORAGE, which should be a colon separated list of paths 229 char const * secondary_paths = getenv("SECONDARY_STORAGE"); 230 while (secondary_paths && secondary_paths[0]) { 231 const char* colon = strchr(secondary_paths, ':'); 232 int length = (colon ? colon - secondary_paths : strlen(secondary_paths)); 233 if (strncmp(secondary_paths, path, length) == 0) { 234 good_path = true; 235 } 236 secondary_paths += length; 237 while (*secondary_paths == ':') secondary_paths++; 238 } 239 } 240 241 if (!good_path) { 242 sqlite3_result_null(context); 243 return; 244 } 245 246 int err = unlink(path); 247 if (err != -1) { 248 // No error occured, return true 249 sqlite3_result_int(context, 1); 250 } else { 251 // An error occured, return false 252 sqlite3_result_int(context, 0); 253 } 254} 255 256static void tokenize_auxdata_delete(void * data) 257{ 258 sqlite3_stmt * statement = (sqlite3_stmt *)data; 259 sqlite3_finalize(statement); 260} 261 262static void base16Encode(char* dest, const char* src, uint32_t size) 263{ 264 static const char * BASE16_TABLE = "0123456789abcdef"; 265 for (uint32_t i = 0; i < size; i++) { 266 char ch = *src++; 267 *dest++ = BASE16_TABLE[ (ch & 0xf0) >> 4 ]; 268 *dest++ = BASE16_TABLE[ (ch & 0x0f) ]; 269 } 270} 271 272struct SqliteUserData { 273 sqlite3 * handle; 274 UCollator* collator; 275}; 276 277/** 278 * This function is invoked as: 279 * 280 * _TOKENIZE('<token_table>', <data_row_id>, <data>, <delimiter>, 281 * <use_token_index>, <data_tag>) 282 * 283 * If <use_token_index> is omitted, it is treated as 0. 284 * If <data_tag> is omitted, it is treated as NULL. 285 * 286 * It will split <data> on each instance of <delimiter> and insert each token 287 * into <token_table>. The following columns in <token_table> are used: 288 * token TEXT, source INTEGER, token_index INTEGER, tag (any type) 289 * The token_index column is not required if <use_token_index> is 0. 290 * The tag column is not required if <data_tag> is NULL. 291 * 292 * One row is inserted for each token in <data>. 293 * In each inserted row, 'source' is <data_row_id>. 294 * In the first inserted row, 'token' is the hex collation key of 295 * the entire <data> string, and 'token_index' is 0. 296 * In each row I (where 1 <= I < N, and N is the number of tokens in <data>) 297 * 'token' will be set to the hex collation key of the I:th token (0-based). 298 * If <use_token_index> != 0, 'token_index' is set to I. 299 * If <data_tag> is not NULL, 'tag' is set to <data_tag>. 300 * 301 * In other words, there will be one row for the entire string, 302 * and one row for each token except the first one. 303 * 304 * The function returns the number of tokens generated. 305 */ 306static void tokenize(sqlite3_context * context, int argc, sqlite3_value ** argv) 307{ 308 //ALOGD("enter tokenize"); 309 int err; 310 int useTokenIndex = 0; 311 int useDataTag = 0; 312 313 if (!(argc >= 4 || argc <= 6)) { 314 ALOGE("Tokenize requires 4 to 6 arguments"); 315 sqlite3_result_null(context); 316 return; 317 } 318 319 if (argc > 4) { 320 useTokenIndex = sqlite3_value_int(argv[4]); 321 } 322 323 if (argc > 5) { 324 useDataTag = (sqlite3_value_type(argv[5]) != SQLITE_NULL); 325 } 326 327 sqlite3 * handle = sqlite3_context_db_handle(context); 328 UCollator* collator = (UCollator*)sqlite3_user_data(context); 329 char const * tokenTable = (char const *)sqlite3_value_text(argv[0]); 330 if (tokenTable == NULL) { 331 ALOGE("tokenTable null"); 332 sqlite3_result_null(context); 333 return; 334 } 335 336 // Get or create the prepared statement for the insertions 337 sqlite3_stmt * statement = (sqlite3_stmt *)sqlite3_get_auxdata(context, 0); 338 if (!statement) { 339 char const * tokenIndexCol = useTokenIndex ? ", token_index" : ""; 340 char const * tokenIndexParam = useTokenIndex ? ", ?" : ""; 341 char const * dataTagCol = useDataTag ? ", tag" : ""; 342 char const * dataTagParam = useDataTag ? ", ?" : ""; 343 char * sql = sqlite3_mprintf("INSERT INTO %s (token, source%s%s) VALUES (?, ?%s%s);", 344 tokenTable, tokenIndexCol, dataTagCol, tokenIndexParam, dataTagParam); 345 err = sqlite3_prepare_v2(handle, sql, -1, &statement, NULL); 346 sqlite3_free(sql); 347 if (err) { 348 ALOGE("prepare failed"); 349 sqlite3_result_null(context); 350 return; 351 } 352 // This binds the statement to the table it was compiled against, which is argv[0]. 353 // If this function is ever called with a different table the finalizer will be called 354 // and sqlite3_get_auxdata() will return null above, forcing a recompile for the new table. 355 sqlite3_set_auxdata(context, 0, statement, tokenize_auxdata_delete); 356 } else { 357 // Reset the cached statement so that binding the row ID will work properly 358 sqlite3_reset(statement); 359 } 360 361 // Bind the row ID of the source row 362 int64_t rowID = sqlite3_value_int64(argv[1]); 363 err = sqlite3_bind_int64(statement, 2, rowID); 364 if (err != SQLITE_OK) { 365 ALOGE("bind failed"); 366 sqlite3_result_null(context); 367 return; 368 } 369 370 // Bind <data_tag> to the tag column 371 if (useDataTag) { 372 int dataTagParamIndex = useTokenIndex ? 4 : 3; 373 err = sqlite3_bind_value(statement, dataTagParamIndex, argv[5]); 374 if (err != SQLITE_OK) { 375 ALOGE("bind failed"); 376 sqlite3_result_null(context); 377 return; 378 } 379 } 380 381 // Get the raw bytes for the string to tokenize 382 // the string will be modified by following code 383 // however, sqlite did not reuse the string, so it is safe to not dup it 384 UChar * origData = (UChar *)sqlite3_value_text16(argv[2]); 385 if (origData == NULL) { 386 sqlite3_result_null(context); 387 return; 388 } 389 390 // Get the raw bytes for the delimiter 391 const UChar * delim = (const UChar *)sqlite3_value_text16(argv[3]); 392 if (delim == NULL) { 393 ALOGE("can't get delimiter"); 394 sqlite3_result_null(context); 395 return; 396 } 397 398 UChar * token = NULL; 399 UChar *state; 400 int numTokens = 0; 401 402 do { 403 if (numTokens == 0) { 404 token = origData; 405 } 406 407 // Reset the program so we can use it to perform the insert 408 sqlite3_reset(statement); 409 UErrorCode status = U_ZERO_ERROR; 410 char keybuf[1024]; 411 uint32_t result = ucol_getSortKey(collator, token, -1, (uint8_t*)keybuf, sizeof(keybuf)-1); 412 if (result > sizeof(keybuf)) { 413 // TODO allocate memory for this super big string 414 ALOGE("ucol_getSortKey needs bigger buffer %d", result); 415 break; 416 } 417 uint32_t keysize = result-1; 418 uint32_t base16Size = keysize*2; 419 char *base16buf = (char*)malloc(base16Size); 420 base16Encode(base16buf, keybuf, keysize); 421 err = sqlite3_bind_text(statement, 1, base16buf, base16Size, SQLITE_STATIC); 422 423 if (err != SQLITE_OK) { 424 ALOGE(" sqlite3_bind_text16 error %d", err); 425 free(base16buf); 426 break; 427 } 428 429 if (useTokenIndex) { 430 err = sqlite3_bind_int(statement, 3, numTokens); 431 if (err != SQLITE_OK) { 432 ALOGE(" sqlite3_bind_int error %d", err); 433 free(base16buf); 434 break; 435 } 436 } 437 438 err = sqlite3_step(statement); 439 free(base16buf); 440 441 if (err != SQLITE_DONE) { 442 ALOGE(" sqlite3_step error %d", err); 443 break; 444 } 445 numTokens++; 446 if (numTokens == 1) { 447 // first call 448 u_strtok_r(origData, delim, &state); 449 } 450 } while ((token = u_strtok_r(NULL, delim, &state)) != NULL); 451 sqlite3_result_int(context, numTokens); 452} 453 454static void localized_collator_dtor(UCollator* collator) 455{ 456 ucol_close(collator); 457} 458 459#define LOCALIZED_COLLATOR_NAME "LOCALIZED" 460 461// This collator may be removed in the near future, so you MUST not use now. 462#define PHONEBOOK_COLLATOR_NAME "PHONEBOOK" 463 464extern "C" int register_localized_collators(sqlite3* handle, const char* systemLocale, int utf16Storage) 465{ 466 int err; 467 UErrorCode status = U_ZERO_ERROR; 468 void* icudata; 469 470 UCollator* collator = ucol_open(systemLocale, &status); 471 if (U_FAILURE(status)) { 472 return -1; 473 } 474 475 ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_PRIMARY, &status); 476 if (U_FAILURE(status)) { 477 return -1; 478 } 479 480 status = U_ZERO_ERROR; 481 char buf[1024]; 482 ucol_getShortDefinitionString(collator, NULL, buf, 1024, &status); 483 484 if (utf16Storage) { 485 err = sqlite3_create_collation_v2(handle, LOCALIZED_COLLATOR_NAME, SQLITE_UTF16, collator, 486 collate16, (void(*)(void*))localized_collator_dtor); 487 } else { 488 err = sqlite3_create_collation_v2(handle, LOCALIZED_COLLATOR_NAME, SQLITE_UTF8, collator, 489 collate8, (void(*)(void*))localized_collator_dtor); 490 } 491 492 if (err != SQLITE_OK) { 493 return err; 494 } 495 496 // Register the _TOKENIZE function 497 err = sqlite3_create_function(handle, "_TOKENIZE", 4, SQLITE_UTF16, collator, tokenize, NULL, NULL); 498 if (err != SQLITE_OK) { 499 return err; 500 } 501 err = sqlite3_create_function(handle, "_TOKENIZE", 5, SQLITE_UTF16, collator, tokenize, NULL, NULL); 502 if (err != SQLITE_OK) { 503 return err; 504 } 505 err = sqlite3_create_function(handle, "_TOKENIZE", 6, SQLITE_UTF16, collator, tokenize, NULL, NULL); 506 if (err != SQLITE_OK) { 507 return err; 508 } 509 510 511 //// PHONEBOOK_COLLATOR 512 // The collator may be removed in the near future. Do not depend on it. 513 // TODO: it might be better to have another function for registering phonebook collator. 514 status = U_ZERO_ERROR; 515 if (strcmp(systemLocale, "ja") == 0 || strcmp(systemLocale, "ja_JP") == 0) { 516 collator = ucol_open("ja@collation=phonebook", &status); 517 } else { 518 collator = ucol_open(systemLocale, &status); 519 } 520 if (U_FAILURE(status)) { 521 return -1; 522 } 523 524 status = U_ZERO_ERROR; 525 ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_PRIMARY, &status); 526 if (U_FAILURE(status)) { 527 return -1; 528 } 529 530 status = U_ZERO_ERROR; 531 // ucol_getShortDefinitionString(collator, NULL, buf, 1024, &status); 532 if (utf16Storage) { 533 err = sqlite3_create_collation_v2(handle, PHONEBOOK_COLLATOR_NAME, SQLITE_UTF16, collator, 534 collate16, (void(*)(void*))localized_collator_dtor); 535 } else { 536 err = sqlite3_create_collation_v2(handle, PHONEBOOK_COLLATOR_NAME, SQLITE_UTF8, collator, 537 collate8, (void(*)(void*))localized_collator_dtor); 538 } 539 540 if (err != SQLITE_OK) { 541 return err; 542 } 543 //// PHONEBOOK_COLLATOR 544 545 return SQLITE_OK; 546} 547 548 549extern "C" int register_android_functions(sqlite3 * handle, int utf16Storage) 550{ 551 int err; 552 UErrorCode status = U_ZERO_ERROR; 553 554 UCollator * collator = ucol_open(NULL, &status); 555 if (U_FAILURE(status)) { 556 return -1; 557 } 558 559 if (utf16Storage) { 560 // Note that text should be stored as UTF-16 561 err = sqlite3_exec(handle, "PRAGMA encoding = 'UTF-16'", 0, 0, 0); 562 if (err != SQLITE_OK) { 563 return err; 564 } 565 566 // Register the UNICODE collation 567 err = sqlite3_create_collation_v2(handle, "UNICODE", SQLITE_UTF16, collator, collate16, 568 (void(*)(void*))localized_collator_dtor); 569 } else { 570 err = sqlite3_create_collation_v2(handle, "UNICODE", SQLITE_UTF8, collator, collate8, 571 (void(*)(void*))localized_collator_dtor); 572 } 573 574 if (err != SQLITE_OK) { 575 return err; 576 } 577 578 // Register the PHONE_NUM_EQUALS function 579 err = sqlite3_create_function( 580 handle, "PHONE_NUMBERS_EQUAL", 2, 581 SQLITE_UTF8, NULL, phone_numbers_equal, NULL, NULL); 582 if (err != SQLITE_OK) { 583 return err; 584 } 585 586 // Register the PHONE_NUM_EQUALS function with an additional argument "use_strict" 587 err = sqlite3_create_function( 588 handle, "PHONE_NUMBERS_EQUAL", 3, 589 SQLITE_UTF8, NULL, phone_numbers_equal, NULL, NULL); 590 if (err != SQLITE_OK) { 591 return err; 592 } 593 594 // Register the _DELETE_FILE function 595 err = sqlite3_create_function(handle, "_DELETE_FILE", 1, SQLITE_UTF8, NULL, delete_file, NULL, NULL); 596 if (err != SQLITE_OK) { 597 return err; 598 } 599 600#if ENABLE_ANDROID_LOG 601 // Register the _LOG function 602 err = sqlite3_create_function(handle, "_LOG", 1, SQLITE_UTF8, NULL, android_log, NULL, NULL); 603 if (err != SQLITE_OK) { 604 return err; 605 } 606#endif 607 608 // Register the GET_PHONEBOOK_INDEX function 609 err = sqlite3_create_function(handle, 610 "GET_PHONEBOOK_INDEX", 611 2, SQLITE_UTF8, NULL, 612 get_phonebook_index, 613 NULL, NULL); 614 if (err != SQLITE_OK) { 615 return err; 616 } 617 618 // Register the _PHONE_NUMBER_STRIPPED_REVERSED function, which imitates 619 // PhoneNumberUtils.getStrippedReversed. This function is not public API, 620 // it is only used for compatibility with Android 1.6 and earlier. 621 err = sqlite3_create_function(handle, 622 "_PHONE_NUMBER_STRIPPED_REVERSED", 623 1, SQLITE_UTF8, NULL, 624 phone_number_stripped_reversed, 625 NULL, NULL); 626 if (err != SQLITE_OK) { 627 return err; 628 } 629 630 return SQLITE_OK; 631} 632