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