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