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
collate16(void * p,int n1,const void * v1,int n2,const void * v2)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
collate8(void * p,int n1,const void * v1,int n2,const void * v2)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 // LOGE("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 /**
77 * Obtains the first UNICODE letter from the supplied string, normalizes and returns it.
78 */
get_phonebook_index(sqlite3_context * context,int argc,sqlite3_value ** argv)79 static void get_phonebook_index(
80 sqlite3_context * context, int argc, sqlite3_value ** argv)
81 {
82 if (argc != 2) {
83 sqlite3_result_null(context);
84 return;
85 }
86
87 char const * src = (char const *)sqlite3_value_text(argv[0]);
88 char const * locale = (char const *)sqlite3_value_text(argv[1]);
89 if (src == NULL || src[0] == 0 || locale == NULL) {
90 sqlite3_result_null(context);
91 return;
92 }
93
94 UCharIterator iter;
95 uiter_setUTF8(&iter, src, -1);
96
97 UBool isError = FALSE;
98 UChar index[SMALL_BUFFER_SIZE];
99 uint32_t len = android::GetPhonebookIndex(&iter, locale, index, sizeof(index), &isError);
100 if (isError) {
101 sqlite3_result_null(context);
102 return;
103 }
104
105 uint32_t outlen = 0;
106 uint8_t out[SMALL_BUFFER_SIZE];
107 for (uint32_t i = 0; i < len; i++) {
108 U8_APPEND(out, outlen, sizeof(out), index[i], isError);
109 if (isError) {
110 sqlite3_result_null(context);
111 return;
112 }
113 }
114
115 if (outlen == 0) {
116 sqlite3_result_null(context);
117 return;
118 }
119
120 sqlite3_result_text(context, (const char*)out, outlen, SQLITE_TRANSIENT);
121 }
122
phone_numbers_equal(sqlite3_context * context,int argc,sqlite3_value ** argv)123 static void phone_numbers_equal(sqlite3_context * context, int argc, sqlite3_value ** argv)
124 {
125 if (argc != 2 && argc != 3) {
126 sqlite3_result_int(context, 0);
127 return;
128 }
129
130 char const * num1 = (char const *)sqlite3_value_text(argv[0]);
131 char const * num2 = (char const *)sqlite3_value_text(argv[1]);
132
133 bool use_strict = false;
134 if (argc == 3) {
135 use_strict = (sqlite3_value_int(argv[2]) != 0);
136 }
137
138 if (num1 == NULL || num2 == NULL) {
139 sqlite3_result_null(context);
140 return;
141 }
142
143 bool equal =
144 (use_strict ?
145 android::phone_number_compare_strict(num1, num2) :
146 android::phone_number_compare_loose(num1, num2));
147
148 if (equal) {
149 sqlite3_result_int(context, 1);
150 } else {
151 sqlite3_result_int(context, 0);
152 }
153 }
154
155 #if ENABLE_ANDROID_LOG
android_log(sqlite3_context * context,int argc,sqlite3_value ** argv)156 static void android_log(sqlite3_context * context, int argc, sqlite3_value ** argv)
157 {
158 char const * tag = "sqlite_trigger";
159 char const * msg = "";
160 int msgIndex = 0;
161
162 switch (argc) {
163 case 2:
164 tag = (char const *)sqlite3_value_text(argv[0]);
165 if (tag == NULL) {
166 tag = "sqlite_trigger";
167 }
168 msgIndex = 1;
169 case 1:
170 msg = (char const *)sqlite3_value_text(argv[msgIndex]);
171 if (msg == NULL) {
172 msg = "";
173 }
174 LOG(LOG_INFO, tag, msg);
175 sqlite3_result_int(context, 1);
176 return;
177
178 default:
179 sqlite3_result_int(context, 0);
180 return;
181 }
182 }
183 #endif
184
delete_file(sqlite3_context * context,int argc,sqlite3_value ** argv)185 static void delete_file(sqlite3_context * context, int argc, sqlite3_value ** argv)
186 {
187 if (argc != 1) {
188 sqlite3_result_int(context, 0);
189 return;
190 }
191
192 char const * path = (char const *)sqlite3_value_text(argv[0]);
193 char const * external_storage = getenv("EXTERNAL_STORAGE");
194 if (path == NULL || external_storage == NULL) {
195 sqlite3_result_null(context);
196 return;
197 }
198
199 if (strncmp(external_storage, path, strlen(external_storage)) != 0) {
200 sqlite3_result_null(context);
201 return;
202 }
203 if (strstr(path, "/../") != NULL) {
204 sqlite3_result_null(context);
205 return;
206 }
207
208 int err = unlink(path);
209 if (err != -1) {
210 // No error occured, return true
211 sqlite3_result_int(context, 1);
212 } else {
213 // An error occured, return false
214 sqlite3_result_int(context, 0);
215 }
216 }
217
tokenize_auxdata_delete(void * data)218 static void tokenize_auxdata_delete(void * data)
219 {
220 sqlite3_stmt * statement = (sqlite3_stmt *)data;
221 sqlite3_finalize(statement);
222 }
223
base16Encode(char * dest,const char * src,uint32_t size)224 static void base16Encode(char* dest, const char* src, uint32_t size)
225 {
226 static const char * BASE16_TABLE = "0123456789abcdef";
227 for (uint32_t i = 0; i < size; i++) {
228 char ch = *src++;
229 *dest++ = BASE16_TABLE[ (ch & 0xf0) >> 4 ];
230 *dest++ = BASE16_TABLE[ (ch & 0x0f) ];
231 }
232 }
233
234 struct SqliteUserData {
235 sqlite3 * handle;
236 UCollator* collator;
237 };
238
239 /**
240 * This function is invoked as:
241 *
242 * _TOKENIZE('<token_table>', <data_row_id>, <data>, <delimiter>,
243 * <use_token_index>, <data_tag>)
244 *
245 * If <use_token_index> is omitted, it is treated as 0.
246 * If <data_tag> is omitted, it is treated as NULL.
247 *
248 * It will split <data> on each instance of <delimiter> and insert each token
249 * into <token_table>. The following columns in <token_table> are used:
250 * token TEXT, source INTEGER, token_index INTEGER, tag (any type)
251 * The token_index column is not required if <use_token_index> is 0.
252 * The tag column is not required if <data_tag> is NULL.
253 *
254 * One row is inserted for each token in <data>.
255 * In each inserted row, 'source' is <data_row_id>.
256 * In the first inserted row, 'token' is the hex collation key of
257 * the entire <data> string, and 'token_index' is 0.
258 * In each row I (where 1 <= I < N, and N is the number of tokens in <data>)
259 * 'token' will be set to the hex collation key of the I:th token (0-based).
260 * If <use_token_index> != 0, 'token_index' is set to I.
261 * If <data_tag> is not NULL, 'tag' is set to <data_tag>.
262 *
263 * In other words, there will be one row for the entire string,
264 * and one row for each token except the first one.
265 *
266 * The function returns the number of tokens generated.
267 */
tokenize(sqlite3_context * context,int argc,sqlite3_value ** argv)268 static void tokenize(sqlite3_context * context, int argc, sqlite3_value ** argv)
269 {
270 //LOGD("enter tokenize");
271 int err;
272 int useTokenIndex = 0;
273 int useDataTag = 0;
274
275 if (!(argc >= 4 || argc <= 6)) {
276 LOGE("Tokenize requires 4 to 6 arguments");
277 sqlite3_result_null(context);
278 return;
279 }
280
281 if (argc > 4) {
282 useTokenIndex = sqlite3_value_int(argv[4]);
283 }
284
285 if (argc > 5) {
286 useDataTag = (sqlite3_value_type(argv[5]) != SQLITE_NULL);
287 }
288
289 sqlite3 * handle = sqlite3_context_db_handle(context);
290 UCollator* collator = (UCollator*)sqlite3_user_data(context);
291 char const * tokenTable = (char const *)sqlite3_value_text(argv[0]);
292 if (tokenTable == NULL) {
293 LOGE("tokenTable null");
294 sqlite3_result_null(context);
295 return;
296 }
297
298 // Get or create the prepared statement for the insertions
299 sqlite3_stmt * statement = (sqlite3_stmt *)sqlite3_get_auxdata(context, 0);
300 if (!statement) {
301 char const * tokenIndexCol = useTokenIndex ? ", token_index" : "";
302 char const * tokenIndexParam = useTokenIndex ? ", ?" : "";
303 char const * dataTagCol = useDataTag ? ", tag" : "";
304 char const * dataTagParam = useDataTag ? ", ?" : "";
305 char * sql = sqlite3_mprintf("INSERT INTO %s (token, source%s%s) VALUES (?, ?%s%s);",
306 tokenTable, tokenIndexCol, dataTagCol, tokenIndexParam, dataTagParam);
307 err = sqlite3_prepare_v2(handle, sql, -1, &statement, NULL);
308 sqlite3_free(sql);
309 if (err) {
310 LOGE("prepare failed");
311 sqlite3_result_null(context);
312 return;
313 }
314 // This binds the statement to the table it was compiled against, which is argv[0].
315 // If this function is ever called with a different table the finalizer will be called
316 // and sqlite3_get_auxdata() will return null above, forcing a recompile for the new table.
317 sqlite3_set_auxdata(context, 0, statement, tokenize_auxdata_delete);
318 } else {
319 // Reset the cached statement so that binding the row ID will work properly
320 sqlite3_reset(statement);
321 }
322
323 // Bind the row ID of the source row
324 int64_t rowID = sqlite3_value_int64(argv[1]);
325 err = sqlite3_bind_int64(statement, 2, rowID);
326 if (err != SQLITE_OK) {
327 LOGE("bind failed");
328 sqlite3_result_null(context);
329 return;
330 }
331
332 // Bind <data_tag> to the tag column
333 if (useDataTag) {
334 int dataTagParamIndex = useTokenIndex ? 4 : 3;
335 err = sqlite3_bind_value(statement, dataTagParamIndex, argv[5]);
336 if (err != SQLITE_OK) {
337 LOGE("bind failed");
338 sqlite3_result_null(context);
339 return;
340 }
341 }
342
343 // Get the raw bytes for the string to tokenize
344 // the string will be modified by following code
345 // however, sqlite did not reuse the string, so it is safe to not dup it
346 UChar * origData = (UChar *)sqlite3_value_text16(argv[2]);
347 if (origData == NULL) {
348 sqlite3_result_null(context);
349 return;
350 }
351
352 // Get the raw bytes for the delimiter
353 const UChar * delim = (const UChar *)sqlite3_value_text16(argv[3]);
354 if (delim == NULL) {
355 LOGE("can't get delimiter");
356 sqlite3_result_null(context);
357 return;
358 }
359
360 UChar * token = NULL;
361 UChar *state;
362 int numTokens = 0;
363
364 do {
365 if (numTokens == 0) {
366 token = origData;
367 }
368
369 // Reset the program so we can use it to perform the insert
370 sqlite3_reset(statement);
371 UErrorCode status = U_ZERO_ERROR;
372 char keybuf[1024];
373 uint32_t result = ucol_getSortKey(collator, token, -1, (uint8_t*)keybuf, sizeof(keybuf)-1);
374 if (result > sizeof(keybuf)) {
375 // TODO allocate memory for this super big string
376 LOGE("ucol_getSortKey needs bigger buffer %d", result);
377 break;
378 }
379 uint32_t keysize = result-1;
380 uint32_t base16Size = keysize*2;
381 char *base16buf = (char*)malloc(base16Size);
382 base16Encode(base16buf, keybuf, keysize);
383 err = sqlite3_bind_text(statement, 1, base16buf, base16Size, SQLITE_STATIC);
384
385 if (err != SQLITE_OK) {
386 LOGE(" sqlite3_bind_text16 error %d", err);
387 free(base16buf);
388 break;
389 }
390
391 if (useTokenIndex) {
392 err = sqlite3_bind_int(statement, 3, numTokens);
393 if (err != SQLITE_OK) {
394 LOGE(" sqlite3_bind_int error %d", err);
395 free(base16buf);
396 break;
397 }
398 }
399
400 err = sqlite3_step(statement);
401 free(base16buf);
402
403 if (err != SQLITE_DONE) {
404 LOGE(" sqlite3_step error %d", err);
405 break;
406 }
407 numTokens++;
408 if (numTokens == 1) {
409 // first call
410 u_strtok_r(origData, delim, &state);
411 }
412 } while ((token = u_strtok_r(NULL, delim, &state)) != NULL);
413 sqlite3_result_int(context, numTokens);
414 }
415
localized_collator_dtor(UCollator * collator)416 static void localized_collator_dtor(UCollator* collator)
417 {
418 ucol_close(collator);
419 }
420
421 #define LOCALIZED_COLLATOR_NAME "LOCALIZED"
422
423 // This collator may be removed in the near future, so you MUST not use now.
424 #define PHONEBOOK_COLLATOR_NAME "PHONEBOOK"
425
register_localized_collators(sqlite3 * handle,const char * systemLocale,int utf16Storage)426 extern "C" int register_localized_collators(sqlite3* handle, const char* systemLocale, int utf16Storage)
427 {
428 int err;
429 UErrorCode status = U_ZERO_ERROR;
430 void* icudata;
431
432 UCollator* collator = ucol_open(systemLocale, &status);
433 if (U_FAILURE(status)) {
434 return -1;
435 }
436
437 ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_PRIMARY, &status);
438 if (U_FAILURE(status)) {
439 return -1;
440 }
441
442 status = U_ZERO_ERROR;
443 char buf[1024];
444 ucol_getShortDefinitionString(collator, NULL, buf, 1024, &status);
445
446 if (utf16Storage) {
447 err = sqlite3_create_collation_v2(handle, LOCALIZED_COLLATOR_NAME, SQLITE_UTF16, collator,
448 collate16, (void(*)(void*))localized_collator_dtor);
449 } else {
450 err = sqlite3_create_collation_v2(handle, LOCALIZED_COLLATOR_NAME, SQLITE_UTF8, collator,
451 collate8, (void(*)(void*))localized_collator_dtor);
452 }
453
454 if (err != SQLITE_OK) {
455 return err;
456 }
457
458 // Register the _TOKENIZE function
459 err = sqlite3_create_function(handle, "_TOKENIZE", 4, SQLITE_UTF16, collator, tokenize, NULL, NULL);
460 if (err != SQLITE_OK) {
461 return err;
462 }
463 err = sqlite3_create_function(handle, "_TOKENIZE", 5, SQLITE_UTF16, collator, tokenize, NULL, NULL);
464 if (err != SQLITE_OK) {
465 return err;
466 }
467 err = sqlite3_create_function(handle, "_TOKENIZE", 6, SQLITE_UTF16, collator, tokenize, NULL, NULL);
468 if (err != SQLITE_OK) {
469 return err;
470 }
471
472
473 //// PHONEBOOK_COLLATOR
474 // The collator may be removed in the near future. Do not depend on it.
475 // TODO: it might be better to have another function for registering phonebook collator.
476 status = U_ZERO_ERROR;
477 if (strcmp(systemLocale, "ja") == 0 || strcmp(systemLocale, "ja_JP") == 0) {
478 collator = ucol_open("ja@collation=phonebook", &status);
479 } else {
480 collator = ucol_open(systemLocale, &status);
481 }
482 if (U_FAILURE(status)) {
483 return -1;
484 }
485
486 status = U_ZERO_ERROR;
487 ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_PRIMARY, &status);
488 if (U_FAILURE(status)) {
489 return -1;
490 }
491
492 status = U_ZERO_ERROR;
493 // ucol_getShortDefinitionString(collator, NULL, buf, 1024, &status);
494 if (utf16Storage) {
495 err = sqlite3_create_collation_v2(handle, PHONEBOOK_COLLATOR_NAME, SQLITE_UTF16, collator,
496 collate16, (void(*)(void*))localized_collator_dtor);
497 } else {
498 err = sqlite3_create_collation_v2(handle, PHONEBOOK_COLLATOR_NAME, SQLITE_UTF8, collator,
499 collate8, (void(*)(void*))localized_collator_dtor);
500 }
501
502 if (err != SQLITE_OK) {
503 return err;
504 }
505 //// PHONEBOOK_COLLATOR
506
507 return SQLITE_OK;
508 }
509
510
register_android_functions(sqlite3 * handle,int utf16Storage)511 extern "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_PHONEBOOK_INDEX function
571 err = sqlite3_create_function(handle,
572 "GET_PHONEBOOK_INDEX",
573 2, SQLITE_UTF8, NULL,
574 get_phonebook_index,
575 NULL, NULL);
576 if (err != SQLITE_OK) {
577 return err;
578 }
579
580 return SQLITE_OK;
581 }
582