blob: 5cc39d8881c19fa7c9b77d9f7f0c8cdfe02d44c0 [file] [log] [blame]
The Android Open Source Project7790ef52009-03-03 19:30:40 -08001/*
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>
Dmitri Plotnikov3a749622010-03-03 11:29:46 -080025#include <unicode/uiter.h>
The Android Open Source Project7790ef52009-03-03 19:30:40 -080026#include <unicode/ustring.h>
Dmitri Plotnikov3a749622010-03-03 11:29:46 -080027#include <unicode/utypes.h>
The Android Open Source Project7790ef52009-03-03 19:30:40 -080028#include <cutils/log.h>
Mike Lockwood439e88e2010-10-05 13:35:27 -040029#include <cutils/properties.h>
The Android Open Source Project7790ef52009-03-03 19:30:40 -080030
31#include "sqlite3_android.h"
32#include "PhoneNumberUtils.h"
Dmitri Plotnikov3a749622010-03-03 11:29:46 -080033#include "PhonebookIndex.h"
The Android Open Source Project7790ef52009-03-03 19:30:40 -080034
35#define ENABLE_ANDROID_LOG 0
Dmitri Plotnikov3a749622010-03-03 11:29:46 -080036#define SMALL_BUFFER_SIZE 10
Dmitri Plotnikov46bdb5c2011-01-06 13:48:50 -080037#define PHONE_NUMBER_BUFFER_SIZE 40
The Android Open Source Project7790ef52009-03-03 19:30:40 -080038
39static int collate16(void *p, int n1, const void *v1, int n2, const void *v2)
40{
41 UCollator *coll = (UCollator *) p;
42 UCollationResult result = ucol_strcoll(coll, (const UChar *) v1, n1,
43 (const UChar *) v2, n2);
44
45 if (result == UCOL_LESS) {
46 return -1;
47 } else if (result == UCOL_GREATER) {
48 return 1;
49 } else {
50 return 0;
51 }
52}
53
54static int collate8(void *p, int n1, const void *v1, int n2, const void *v2)
55{
56 UCollator *coll = (UCollator *) p;
57 UCharIterator i1, i2;
58 UErrorCode status = U_ZERO_ERROR;
59
60 uiter_setUTF8(&i1, (const char *) v1, n1);
61 uiter_setUTF8(&i2, (const char *) v2, n2);
62
63 UCollationResult result = ucol_strcollIter(coll, &i1, &i2, &status);
64
65 if (U_FAILURE(status)) {
66// LOGE("Collation iterator error: %d\n", status);
67 }
68
69 if (result == UCOL_LESS) {
70 return -1;
71 } else if (result == UCOL_GREATER) {
72 return 1;
73 } else {
74 return 0;
75 }
76}
77
Dmitri Plotnikov3a749622010-03-03 11:29:46 -080078/**
79 * Obtains the first UNICODE letter from the supplied string, normalizes and returns it.
80 */
81static void get_phonebook_index(
82 sqlite3_context * context, int argc, sqlite3_value ** argv)
83{
84 if (argc != 2) {
85 sqlite3_result_null(context);
86 return;
87 }
88
89 char const * src = (char const *)sqlite3_value_text(argv[0]);
90 char const * locale = (char const *)sqlite3_value_text(argv[1]);
91 if (src == NULL || src[0] == 0 || locale == NULL) {
92 sqlite3_result_null(context);
93 return;
94 }
95
96 UCharIterator iter;
97 uiter_setUTF8(&iter, src, -1);
98
Dmitri Plotnikov4b2aeb82010-03-03 14:48:34 -080099 UBool isError = FALSE;
100 UChar index[SMALL_BUFFER_SIZE];
101 uint32_t len = android::GetPhonebookIndex(&iter, locale, index, sizeof(index), &isError);
102 if (isError) {
Dmitri Plotnikov3a749622010-03-03 11:29:46 -0800103 sqlite3_result_null(context);
104 return;
105 }
106
107 uint32_t outlen = 0;
108 uint8_t out[SMALL_BUFFER_SIZE];
Dmitri Plotnikov4b2aeb82010-03-03 14:48:34 -0800109 for (uint32_t i = 0; i < len; i++) {
110 U8_APPEND(out, outlen, sizeof(out), index[i], isError);
111 if (isError) {
112 sqlite3_result_null(context);
113 return;
114 }
115 }
116
117 if (outlen == 0) {
Dmitri Plotnikov3a749622010-03-03 11:29:46 -0800118 sqlite3_result_null(context);
119 return;
120 }
121
122 sqlite3_result_text(context, (const char*)out, outlen, SQLITE_TRANSIENT);
123}
124
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800125static void phone_numbers_equal(sqlite3_context * context, int argc, sqlite3_value ** argv)
126{
Daisuke Miyakawa948a1192009-09-19 19:19:53 -0700127 if (argc != 2 && argc != 3) {
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800128 sqlite3_result_int(context, 0);
129 return;
130 }
131
132 char const * num1 = (char const *)sqlite3_value_text(argv[0]);
133 char const * num2 = (char const *)sqlite3_value_text(argv[1]);
134
Daisuke Miyakawa948a1192009-09-19 19:19:53 -0700135 bool use_strict = false;
136 if (argc == 3) {
137 use_strict = (sqlite3_value_int(argv[2]) != 0);
138 }
139
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800140 if (num1 == NULL || num2 == NULL) {
141 sqlite3_result_null(context);
142 return;
143 }
144
Daisuke Miyakawa948a1192009-09-19 19:19:53 -0700145 bool equal =
146 (use_strict ?
147 android::phone_number_compare_strict(num1, num2) :
148 android::phone_number_compare_loose(num1, num2));
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800149
150 if (equal) {
151 sqlite3_result_int(context, 1);
152 } else {
153 sqlite3_result_int(context, 0);
154 }
155}
156
Dmitri Plotnikov46bdb5c2011-01-06 13:48:50 -0800157static void phone_number_stripped_reversed(sqlite3_context * context, int argc,
158 sqlite3_value ** argv)
159{
160 if (argc != 1) {
161 sqlite3_result_int(context, 0);
162 return;
163 }
164
165 char const * number = (char const *)sqlite3_value_text(argv[0]);
166 if (number == NULL) {
167 sqlite3_result_null(context);
168 return;
169 }
170
171 char out[PHONE_NUMBER_BUFFER_SIZE];
172 int outlen = 0;
173 android::phone_number_stripped_reversed_inter(number, out, PHONE_NUMBER_BUFFER_SIZE, &outlen);
174 sqlite3_result_text(context, (const char*)out, outlen, SQLITE_TRANSIENT);
175}
176
177
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800178#if ENABLE_ANDROID_LOG
179static void android_log(sqlite3_context * context, int argc, sqlite3_value ** argv)
180{
181 char const * tag = "sqlite_trigger";
182 char const * msg = "";
183 int msgIndex = 0;
184
185 switch (argc) {
186 case 2:
187 tag = (char const *)sqlite3_value_text(argv[0]);
188 if (tag == NULL) {
189 tag = "sqlite_trigger";
190 }
191 msgIndex = 1;
192 case 1:
193 msg = (char const *)sqlite3_value_text(argv[msgIndex]);
194 if (msg == NULL) {
195 msg = "";
196 }
197 LOG(LOG_INFO, tag, msg);
198 sqlite3_result_int(context, 1);
199 return;
200
201 default:
202 sqlite3_result_int(context, 0);
203 return;
204 }
205}
206#endif
207
208static void delete_file(sqlite3_context * context, int argc, sqlite3_value ** argv)
209{
210 if (argc != 1) {
211 sqlite3_result_int(context, 0);
212 return;
213 }
214
215 char const * path = (char const *)sqlite3_value_text(argv[0]);
Mike Lockwood439e88e2010-10-05 13:35:27 -0400216 char media_storage[PROPERTY_VALUE_MAX];
Ray Chen76b3da42010-03-12 11:30:27 -0800217 char const * external_storage = getenv("EXTERNAL_STORAGE");
Mike Lockwood439e88e2010-10-05 13:35:27 -0400218 if (path == NULL) {
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800219 sqlite3_result_null(context);
220 return;
221 }
Dmitri Plotnikov3a749622010-03-03 11:29:46 -0800222
Mike Lockwood439e88e2010-10-05 13:35:27 -0400223 property_get("ro.media.storage", media_storage, "");
224 // path must match either ro.media.storage or EXTERNAL_STORAGE directory
225 if ( !(media_storage[0] && strncmp(media_storage, path, strlen(media_storage)) == 0) &&
226 !(external_storage && strncmp(external_storage, path, strlen(external_storage)) == 0)) {
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800227 sqlite3_result_null(context);
Dmitri Plotnikov3a749622010-03-03 11:29:46 -0800228 return;
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800229 }
Marco Nelissen2da78c02009-05-06 11:08:08 -0700230 if (strstr(path, "/../") != NULL) {
231 sqlite3_result_null(context);
232 return;
233 }
234
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800235 int err = unlink(path);
236 if (err != -1) {
237 // No error occured, return true
238 sqlite3_result_int(context, 1);
239 } else {
240 // An error occured, return false
241 sqlite3_result_int(context, 0);
242 }
243}
244
245static void tokenize_auxdata_delete(void * data)
246{
247 sqlite3_stmt * statement = (sqlite3_stmt *)data;
248 sqlite3_finalize(statement);
249}
250
251static void base16Encode(char* dest, const char* src, uint32_t size)
252{
253 static const char * BASE16_TABLE = "0123456789abcdef";
254 for (uint32_t i = 0; i < size; i++) {
255 char ch = *src++;
256 *dest++ = BASE16_TABLE[ (ch & 0xf0) >> 4 ];
257 *dest++ = BASE16_TABLE[ (ch & 0x0f) ];
258 }
259}
260
261struct SqliteUserData {
262 sqlite3 * handle;
263 UCollator* collator;
264};
265
266/**
267 * This function is invoked as:
268 *
Bjorn Bringert754d83d2009-05-18 11:21:50 +0100269 * _TOKENIZE('<token_table>', <data_row_id>, <data>, <delimiter>,
270 * <use_token_index>, <data_tag>)
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800271 *
Bjorn Bringert754d83d2009-05-18 11:21:50 +0100272 * If <use_token_index> is omitted, it is treated as 0.
273 * If <data_tag> is omitted, it is treated as NULL.
Bjorn Bringert687f1162009-05-13 22:13:09 +0100274 *
275 * It will split <data> on each instance of <delimiter> and insert each token
Bjorn Bringert754d83d2009-05-18 11:21:50 +0100276 * into <token_table>. The following columns in <token_table> are used:
277 * token TEXT, source INTEGER, token_index INTEGER, tag (any type)
278 * The token_index column is not required if <use_token_index> is 0.
279 * The tag column is not required if <data_tag> is NULL.
Bjorn Bringert687f1162009-05-13 22:13:09 +0100280 *
281 * One row is inserted for each token in <data>.
282 * In each inserted row, 'source' is <data_row_id>.
283 * In the first inserted row, 'token' is the hex collation key of
284 * the entire <data> string, and 'token_index' is 0.
285 * In each row I (where 1 <= I < N, and N is the number of tokens in <data>)
286 * 'token' will be set to the hex collation key of the I:th token (0-based).
Bjorn Bringert754d83d2009-05-18 11:21:50 +0100287 * If <use_token_index> != 0, 'token_index' is set to I.
288 * If <data_tag> is not NULL, 'tag' is set to <data_tag>.
Bjorn Bringert687f1162009-05-13 22:13:09 +0100289 *
290 * In other words, there will be one row for the entire string,
291 * and one row for each token except the first one.
292 *
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800293 * The function returns the number of tokens generated.
294 */
295static void tokenize(sqlite3_context * context, int argc, sqlite3_value ** argv)
296{
297 //LOGD("enter tokenize");
298 int err;
Bjorn Bringert687f1162009-05-13 22:13:09 +0100299 int useTokenIndex = 0;
Bjorn Bringert754d83d2009-05-18 11:21:50 +0100300 int useDataTag = 0;
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800301
Bjorn Bringert754d83d2009-05-18 11:21:50 +0100302 if (!(argc >= 4 || argc <= 6)) {
303 LOGE("Tokenize requires 4 to 6 arguments");
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800304 sqlite3_result_null(context);
305 return;
306 }
307
Bjorn Bringert687f1162009-05-13 22:13:09 +0100308 if (argc > 4) {
309 useTokenIndex = sqlite3_value_int(argv[4]);
310 }
311
Bjorn Bringert754d83d2009-05-18 11:21:50 +0100312 if (argc > 5) {
313 useDataTag = (sqlite3_value_type(argv[5]) != SQLITE_NULL);
314 }
315
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800316 sqlite3 * handle = sqlite3_context_db_handle(context);
317 UCollator* collator = (UCollator*)sqlite3_user_data(context);
318 char const * tokenTable = (char const *)sqlite3_value_text(argv[0]);
319 if (tokenTable == NULL) {
320 LOGE("tokenTable null");
321 sqlite3_result_null(context);
322 return;
323 }
324
325 // Get or create the prepared statement for the insertions
326 sqlite3_stmt * statement = (sqlite3_stmt *)sqlite3_get_auxdata(context, 0);
327 if (!statement) {
Bjorn Bringert754d83d2009-05-18 11:21:50 +0100328 char const * tokenIndexCol = useTokenIndex ? ", token_index" : "";
329 char const * tokenIndexParam = useTokenIndex ? ", ?" : "";
330 char const * dataTagCol = useDataTag ? ", tag" : "";
331 char const * dataTagParam = useDataTag ? ", ?" : "";
332 char * sql = sqlite3_mprintf("INSERT INTO %s (token, source%s%s) VALUES (?, ?%s%s);",
333 tokenTable, tokenIndexCol, dataTagCol, tokenIndexParam, dataTagParam);
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800334 err = sqlite3_prepare_v2(handle, sql, -1, &statement, NULL);
335 sqlite3_free(sql);
336 if (err) {
337 LOGE("prepare failed");
338 sqlite3_result_null(context);
339 return;
340 }
341 // This binds the statement to the table it was compiled against, which is argv[0].
342 // If this function is ever called with a different table the finalizer will be called
343 // and sqlite3_get_auxdata() will return null above, forcing a recompile for the new table.
344 sqlite3_set_auxdata(context, 0, statement, tokenize_auxdata_delete);
345 } else {
346 // Reset the cached statement so that binding the row ID will work properly
347 sqlite3_reset(statement);
348 }
349
350 // Bind the row ID of the source row
351 int64_t rowID = sqlite3_value_int64(argv[1]);
352 err = sqlite3_bind_int64(statement, 2, rowID);
353 if (err != SQLITE_OK) {
354 LOGE("bind failed");
355 sqlite3_result_null(context);
356 return;
357 }
358
Bjorn Bringert754d83d2009-05-18 11:21:50 +0100359 // Bind <data_tag> to the tag column
360 if (useDataTag) {
361 int dataTagParamIndex = useTokenIndex ? 4 : 3;
362 err = sqlite3_bind_value(statement, dataTagParamIndex, argv[5]);
363 if (err != SQLITE_OK) {
364 LOGE("bind failed");
365 sqlite3_result_null(context);
366 return;
367 }
368 }
369
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800370 // Get the raw bytes for the string to tokenize
371 // the string will be modified by following code
372 // however, sqlite did not reuse the string, so it is safe to not dup it
373 UChar * origData = (UChar *)sqlite3_value_text16(argv[2]);
374 if (origData == NULL) {
375 sqlite3_result_null(context);
376 return;
Dmitri Plotnikov3a749622010-03-03 11:29:46 -0800377 }
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800378
379 // Get the raw bytes for the delimiter
380 const UChar * delim = (const UChar *)sqlite3_value_text16(argv[3]);
381 if (delim == NULL) {
382 LOGE("can't get delimiter");
383 sqlite3_result_null(context);
384 return;
385 }
Dmitri Plotnikov3a749622010-03-03 11:29:46 -0800386
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800387 UChar * token = NULL;
388 UChar *state;
Dmitri Plotnikov3a749622010-03-03 11:29:46 -0800389 int numTokens = 0;
390
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800391 do {
392 if (numTokens == 0) {
393 token = origData;
Dmitri Plotnikov3a749622010-03-03 11:29:46 -0800394 }
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800395
396 // Reset the program so we can use it to perform the insert
397 sqlite3_reset(statement);
398 UErrorCode status = U_ZERO_ERROR;
399 char keybuf[1024];
400 uint32_t result = ucol_getSortKey(collator, token, -1, (uint8_t*)keybuf, sizeof(keybuf)-1);
401 if (result > sizeof(keybuf)) {
402 // TODO allocate memory for this super big string
403 LOGE("ucol_getSortKey needs bigger buffer %d", result);
404 break;
405 }
406 uint32_t keysize = result-1;
407 uint32_t base16Size = keysize*2;
408 char *base16buf = (char*)malloc(base16Size);
Dmitri Plotnikov3a749622010-03-03 11:29:46 -0800409 base16Encode(base16buf, keybuf, keysize);
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800410 err = sqlite3_bind_text(statement, 1, base16buf, base16Size, SQLITE_STATIC);
Dmitri Plotnikov3a749622010-03-03 11:29:46 -0800411
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800412 if (err != SQLITE_OK) {
413 LOGE(" sqlite3_bind_text16 error %d", err);
414 free(base16buf);
415 break;
416 }
417
Bjorn Bringert687f1162009-05-13 22:13:09 +0100418 if (useTokenIndex) {
419 err = sqlite3_bind_int(statement, 3, numTokens);
420 if (err != SQLITE_OK) {
421 LOGE(" sqlite3_bind_int error %d", err);
422 free(base16buf);
423 break;
424 }
425 }
426
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800427 err = sqlite3_step(statement);
428 free(base16buf);
429
430 if (err != SQLITE_DONE) {
431 LOGE(" sqlite3_step error %d", err);
432 break;
433 }
434 numTokens++;
435 if (numTokens == 1) {
436 // first call
437 u_strtok_r(origData, delim, &state);
438 }
439 } while ((token = u_strtok_r(NULL, delim, &state)) != NULL);
440 sqlite3_result_int(context, numTokens);
441}
442
443static void localized_collator_dtor(UCollator* collator)
444{
445 ucol_close(collator);
446}
447
448#define LOCALIZED_COLLATOR_NAME "LOCALIZED"
449
Daisuke Miyakawa31089e02010-02-24 19:03:33 +0900450// This collator may be removed in the near future, so you MUST not use now.
451#define PHONEBOOK_COLLATOR_NAME "PHONEBOOK"
452
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800453extern "C" int register_localized_collators(sqlite3* handle, const char* systemLocale, int utf16Storage)
454{
455 int err;
456 UErrorCode status = U_ZERO_ERROR;
457 void* icudata;
458
459 UCollator* collator = ucol_open(systemLocale, &status);
460 if (U_FAILURE(status)) {
461 return -1;
462 }
Dmitri Plotnikov3a749622010-03-03 11:29:46 -0800463
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800464 ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_PRIMARY, &status);
465 if (U_FAILURE(status)) {
466 return -1;
467 }
468
469 status = U_ZERO_ERROR;
470 char buf[1024];
Daisuke Miyakawa31089e02010-02-24 19:03:33 +0900471 ucol_getShortDefinitionString(collator, NULL, buf, 1024, &status);
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800472
473 if (utf16Storage) {
474 err = sqlite3_create_collation_v2(handle, LOCALIZED_COLLATOR_NAME, SQLITE_UTF16, collator,
475 collate16, (void(*)(void*))localized_collator_dtor);
476 } else {
477 err = sqlite3_create_collation_v2(handle, LOCALIZED_COLLATOR_NAME, SQLITE_UTF8, collator,
478 collate8, (void(*)(void*))localized_collator_dtor);
479 }
Daisuke Miyakawa31089e02010-02-24 19:03:33 +0900480
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800481 if (err != SQLITE_OK) {
482 return err;
483 }
Dmitri Plotnikov3a749622010-03-03 11:29:46 -0800484
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800485 // Register the _TOKENIZE function
486 err = sqlite3_create_function(handle, "_TOKENIZE", 4, SQLITE_UTF16, collator, tokenize, NULL, NULL);
487 if (err != SQLITE_OK) {
488 return err;
Bjorn Bringert687f1162009-05-13 22:13:09 +0100489 }
490 err = sqlite3_create_function(handle, "_TOKENIZE", 5, SQLITE_UTF16, collator, tokenize, NULL, NULL);
491 if (err != SQLITE_OK) {
492 return err;
493 }
Bjorn Bringert754d83d2009-05-18 11:21:50 +0100494 err = sqlite3_create_function(handle, "_TOKENIZE", 6, SQLITE_UTF16, collator, tokenize, NULL, NULL);
495 if (err != SQLITE_OK) {
496 return err;
497 }
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800498
Daisuke Miyakawa31089e02010-02-24 19:03:33 +0900499
500 //// PHONEBOOK_COLLATOR
501 // The collator may be removed in the near future. Do not depend on it.
502 // TODO: it might be better to have another function for registering phonebook collator.
503 status = U_ZERO_ERROR;
504 if (strcmp(systemLocale, "ja") == 0 || strcmp(systemLocale, "ja_JP") == 0) {
505 collator = ucol_open("ja@collation=phonebook", &status);
506 } else {
507 collator = ucol_open(systemLocale, &status);
508 }
509 if (U_FAILURE(status)) {
510 return -1;
511 }
512
513 status = U_ZERO_ERROR;
514 ucol_setAttribute(collator, UCOL_STRENGTH, UCOL_PRIMARY, &status);
515 if (U_FAILURE(status)) {
516 return -1;
517 }
518
519 status = U_ZERO_ERROR;
520 // ucol_getShortDefinitionString(collator, NULL, buf, 1024, &status);
521 if (utf16Storage) {
522 err = sqlite3_create_collation_v2(handle, PHONEBOOK_COLLATOR_NAME, SQLITE_UTF16, collator,
523 collate16, (void(*)(void*))localized_collator_dtor);
524 } else {
525 err = sqlite3_create_collation_v2(handle, PHONEBOOK_COLLATOR_NAME, SQLITE_UTF8, collator,
526 collate8, (void(*)(void*))localized_collator_dtor);
527 }
528
529 if (err != SQLITE_OK) {
530 return err;
531 }
532 //// PHONEBOOK_COLLATOR
533
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800534 return SQLITE_OK;
535}
536
537
538extern "C" int register_android_functions(sqlite3 * handle, int utf16Storage)
539{
540 int err;
541 UErrorCode status = U_ZERO_ERROR;
542
543 UCollator * collator = ucol_open(NULL, &status);
544 if (U_FAILURE(status)) {
545 return -1;
Dmitri Plotnikov3a749622010-03-03 11:29:46 -0800546 }
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800547
548 if (utf16Storage) {
549 // Note that text should be stored as UTF-16
550 err = sqlite3_exec(handle, "PRAGMA encoding = 'UTF-16'", 0, 0, 0);
551 if (err != SQLITE_OK) {
552 return err;
553 }
554
555 // Register the UNICODE collation
556 err = sqlite3_create_collation_v2(handle, "UNICODE", SQLITE_UTF16, collator, collate16,
557 (void(*)(void*))localized_collator_dtor);
558 } else {
559 err = sqlite3_create_collation_v2(handle, "UNICODE", SQLITE_UTF8, collator, collate8,
560 (void(*)(void*))localized_collator_dtor);
561 }
562
563 if (err != SQLITE_OK) {
564 return err;
565 }
566
567 // Register the PHONE_NUM_EQUALS function
Daisuke Miyakawa948a1192009-09-19 19:19:53 -0700568 err = sqlite3_create_function(
569 handle, "PHONE_NUMBERS_EQUAL", 2,
570 SQLITE_UTF8, NULL, phone_numbers_equal, NULL, NULL);
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800571 if (err != SQLITE_OK) {
572 return err;
573 }
Daisuke Miyakawa948a1192009-09-19 19:19:53 -0700574
575 // Register the PHONE_NUM_EQUALS function with an additional argument "use_strict"
576 err = sqlite3_create_function(
577 handle, "PHONE_NUMBERS_EQUAL", 3,
578 SQLITE_UTF8, NULL, phone_numbers_equal, NULL, NULL);
579 if (err != SQLITE_OK) {
580 return err;
581 }
582
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800583 // Register the _DELETE_FILE function
584 err = sqlite3_create_function(handle, "_DELETE_FILE", 1, SQLITE_UTF8, NULL, delete_file, NULL, NULL);
585 if (err != SQLITE_OK) {
586 return err;
587 }
588
589#if ENABLE_ANDROID_LOG
590 // Register the _LOG function
591 err = sqlite3_create_function(handle, "_LOG", 1, SQLITE_UTF8, NULL, android_log, NULL, NULL);
592 if (err != SQLITE_OK) {
593 return err;
594 }
595#endif
596
Dmitri Plotnikov3a749622010-03-03 11:29:46 -0800597 // Register the GET_PHONEBOOK_INDEX function
598 err = sqlite3_create_function(handle,
599 "GET_PHONEBOOK_INDEX",
600 2, SQLITE_UTF8, NULL,
601 get_phonebook_index,
602 NULL, NULL);
603 if (err != SQLITE_OK) {
604 return err;
605 }
606
Dmitri Plotnikov46bdb5c2011-01-06 13:48:50 -0800607 // Register the _PHONE_NUMBER_STRIPPED_REVERSED function, which imitates
608 // PhoneNumberUtils.getStrippedReversed. This function is not public API,
609 // it is only used for compatibility with Android 1.6 and earlier.
610 err = sqlite3_create_function(handle,
611 "_PHONE_NUMBER_STRIPPED_REVERSED",
612 1, SQLITE_UTF8, NULL,
613 phone_number_stripped_reversed,
614 NULL, NULL);
615 if (err != SQLITE_OK) {
616 return err;
617 }
618
The Android Open Source Project7790ef52009-03-03 19:30:40 -0800619 return SQLITE_OK;
620}