4 * Copyright (c) 2010 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
20 #include <phone_number.h>
23 #include "contacts_internal.h"
25 #include "ctsvc_internal.h"
26 #include "ctsvc_db_sqlite.h"
27 #include "ctsvc_db_schema.h"
28 #include "ctsvc_list.h"
29 #include "ctsvc_record.h"
30 #include "ctsvc_db_utils.h"
31 #include "ctsvc_normalize.h"
32 #include "ctsvc_number_utils.h"
33 #include "ctsvc_db_init.h"
34 #include "ctsvc_view.h"
35 #include "ctsvc_inotify.h"
36 #include "ctsvc_localize.h"
37 #include "ctsvc_localize_utils.h"
38 #include "ctsvc_server_setting.h"
39 #include "ctsvc_notify.h"
40 #include "ctsvc_utils_string.h"
42 #include "ctsvc_db_access_control.h"
43 #include "ctsvc_db_plugin_person_helper.h"
44 #include "ctsvc_db_plugin_group_helper.h"
45 #include "ctsvc_db_plugin_company_helper.h"
46 #include "ctsvc_db_query.h"
48 #ifdef _CONTACTS_IPC_SERVER
49 #include "ctsvc_server_sim.h"
50 #include "ctsvc_server_change_subject.h"
51 #endif /* _CONTACTS_IPC_SERVER */
53 /* It is used to sort search results */
54 const char *hangul_syllable[19][3] = {
55 {"ㄱ", "가", "깋"}, /* AC00, AE3B */
56 {"ㄲ", "까", "낗"}, /* AE3C, B097 */
57 {"ㄴ", "나", "닣"}, /* B098, B2E3 */
58 {"ㄷ", "다", "딯"}, /* B2E4, B52F */
59 {"ㄸ", "따", "띻"}, /* B530, B77B */
60 {"ㄹ", "라", "맇"}, /* B77C, B9C7 */
61 {"ㅁ", "마", "밓"}, /* B9C8, BC13 */
62 {"ㅂ", "바", "빟"}, /* BC14, BE5F */
63 {"ㅃ", "빠", "삫"}, /* BE60, C0AB */
64 {"ㅅ", "사", "싷"}, /* C0AC, C2F7 */
65 {"ㅆ", "싸", "앃"}, /* C2F8, C543 */
66 {"ㅇ", "아", "잏"}, /* C544, C78F */
67 {"ㅈ", "자", "짛"}, /* C790, C9DB */
68 {"ㅉ", "짜", "찧"}, /* C9DC, CC27 */
69 {"ㅊ", "차", "칳"}, /* CC28, CE73 */
70 {"ㅋ", "카", "킿"}, /* CE74, D0AF */
71 {"ㅌ", "타", "팋"}, /* D0C0, D30B */
72 {"ㅍ", "파", "핗"}, /* D30C, D557 */
73 {"ㅎ", "하", "힣"}, /* D558, D7A3 */
76 /* When one more information is matched in snippet API,
77 * only one result is returned as below priority.
78 * Priority order is set for UI concept.
79 * To get name, with_range_for_snippet() API should be used with name range.
82 CTSVC_SNIPPET_PRIO_NICKNAME = 1,
83 CTSVC_SNIPPET_PRIO_COMPANY,
84 CTSVC_SNIPPET_PRIO_POSTAL,
85 CTSVC_SNIPPET_PRIO_EMAIL,
86 CTSVC_SNIPPET_PRIO_NOTE,
87 CTSVC_SNIPPET_PRIO_NUMBER,
88 CTSVC_SNIPPET_PRIO_NAME,
89 } ctsvc_snippet_prio_e;
96 } db_query_property_type_e;
98 static contacts_db_status_e __db_status = CONTACTS_DB_STATUS_NORMAL;
100 static const char * __ctsvc_db_get_property_field_name(const property_info_s *properties,
101 int count, db_query_property_type_e property_type, unsigned int property_id)
105 for (i = 0; i < count; i++) {
106 property_info_s *p = (property_info_s*)&(properties[i]);
107 if (property_id == p->property_id) {
109 if (property_type == QUERY_PROJECTION) {
110 if (p->property_type == CTSVC_SEARCH_PROPERTY_PROJECTION
111 || p->property_type == CTSVC_SEARCH_PROPERTY_ALL) {
114 } else if (property_type == QUERY_FILTER) {
115 if (p->property_type == CTSVC_SEARCH_PROPERTY_FILTER
116 || p->property_type == CTSVC_SEARCH_PROPERTY_ALL) {
119 } else if (property_type == QUERY_SORTKEY) {
125 } else if (property_id == CTSVC_PROPERTY_PERSON_DISPLAY_NAME_INDEX) {
126 if (property_type != QUERY_PROJECTION)
128 const char *temp = ctsvc_get_display_column();
129 /* snprintf(temp, sizeof(temp), "_NORMALIZE_INDEX_(%s)",
130 ctsvc_get_display_column()); */
131 return "_NORMALIZE_INDEX_"temp;
134 return ctsvc_get_display_column();
142 * return data type of the property
143 * bool / int / long long int / char string / double / child record
145 static inline int __ctsvc_db_get_property_type(const property_info_s *properties,
146 int count, unsigned int property_id)
149 for (i = 0; i < count; i++) {
150 property_info_s *p = (property_info_s*)&(properties[i]);
152 if (property_id == p->property_id)
153 return (property_id & CTSVC_VIEW_DATA_TYPE_MASK);
159 static inline int __ctsvc_db_create_int_condition(ctsvc_composite_filter_s *com_filter,
160 ctsvc_attribute_filter_s *filter, char **condition)
162 const char *field_name;
163 char out_cond[CTS_SQL_MAX_LEN] = {0};
165 field_name = __ctsvc_db_get_property_field_name(com_filter->properties,
166 com_filter->property_count, QUERY_FILTER, filter->property_id);
167 RETVM_IF(NULL == field_name, CONTACTS_ERROR_INVALID_PARAMETER,
168 "property id(%d)", filter->property_id);
170 #ifdef _CONTACTS_IPC_SERVER
171 if (CTSVC_PROPERTY_PHONELOG_SIM_SLOT_NO == filter->property_id ||
172 CTSVC_PROPERTY_PHONELOG_STAT_SIM_SLOT_NO == filter->property_id) {
173 /* get real sim info id by SIM slot number 0/1 */
174 int sim_info_id = ctsvc_server_sim_get_info_id_by_sim_slot_no(filter->value.i);
175 if (0 < sim_info_id) {
176 snprintf(out_cond, sizeof(out_cond), "%s = %d", field_name, sim_info_id);
177 *condition = strdup(out_cond);
178 return CONTACTS_ERROR_NONE;
180 return CONTACTS_ERROR_INVALID_PARAMETER;
182 #endif /* _CONTACTS_IPC_SERVER */
184 switch (filter->match) {
185 case CONTACTS_MATCH_EQUAL:
186 snprintf(out_cond, sizeof(out_cond), "%s = %d", field_name, filter->value.i);
188 case CONTACTS_MATCH_GREATER_THAN:
189 snprintf(out_cond, sizeof(out_cond), "%s > %d", field_name, filter->value.i);
191 case CONTACTS_MATCH_GREATER_THAN_OR_EQUAL:
192 snprintf(out_cond, sizeof(out_cond), "%s >= %d", field_name, filter->value.i);
194 case CONTACTS_MATCH_LESS_THAN:
195 snprintf(out_cond, sizeof(out_cond), "%s < %d", field_name, filter->value.i);
197 case CONTACTS_MATCH_LESS_THAN_OR_EQUAL:
198 snprintf(out_cond, sizeof(out_cond), "%s <= %d", field_name, filter->value.i);
200 case CONTACTS_MATCH_NOT_EQUAL:
201 snprintf(out_cond, sizeof(out_cond), "%s <> %d", field_name, filter->value.i);
203 case CONTACTS_MATCH_NONE:
204 snprintf(out_cond, sizeof(out_cond), "%s IS NULL", field_name);
207 /* LCOV_EXCL_START */
208 ERR("Invalid : match rule(%d) is not supported", filter->match);
209 return CONTACTS_ERROR_INVALID_PARAMETER;
213 *condition = strdup(out_cond);
214 return CONTACTS_ERROR_NONE;
217 static inline int __ctsvc_db_create_double_condition(
218 ctsvc_composite_filter_s *com_filter,
219 ctsvc_attribute_filter_s *filter,
222 const char *field_name;
223 char out_cond[CTS_SQL_MAX_LEN] = {0};
225 field_name = __ctsvc_db_get_property_field_name(com_filter->properties,
226 com_filter->property_count, QUERY_FILTER, filter->property_id);
227 RETVM_IF(NULL == field_name, CONTACTS_ERROR_INVALID_PARAMETER,
228 "property id(%d)", filter->property_id);
230 switch (filter->match) {
231 case CONTACTS_MATCH_EQUAL:
232 snprintf(out_cond, sizeof(out_cond), "%s = %lf", field_name, filter->value.d);
234 case CONTACTS_MATCH_GREATER_THAN:
235 snprintf(out_cond, sizeof(out_cond), "%s > %lf", field_name, filter->value.d);
237 case CONTACTS_MATCH_GREATER_THAN_OR_EQUAL:
238 snprintf(out_cond, sizeof(out_cond), "%s >= %lf", field_name, filter->value.d);
240 case CONTACTS_MATCH_LESS_THAN:
241 snprintf(out_cond, sizeof(out_cond), "%s < %lf", field_name, filter->value.d);
243 case CONTACTS_MATCH_LESS_THAN_OR_EQUAL:
244 snprintf(out_cond, sizeof(out_cond), "%s <= %lf", field_name, filter->value.d);
246 case CONTACTS_MATCH_NOT_EQUAL:
247 snprintf(out_cond, sizeof(out_cond), "%s <> %lf", field_name, filter->value.d);
249 case CONTACTS_MATCH_NONE:
250 snprintf(out_cond, sizeof(out_cond), "%s IS NULL", field_name);
253 /* LCOV_EXCL_START */
254 ERR("Invalid : match rule(%d) is not supported", filter->match);
255 return CONTACTS_ERROR_INVALID_PARAMETER;
259 *condition = strdup(out_cond);
260 return CONTACTS_ERROR_NONE;
263 static inline int __ctsvc_db_create_lli_condition(ctsvc_composite_filter_s *com_filter,
264 ctsvc_attribute_filter_s *filter, char **condition)
266 const char *field_name;
267 char out_cond[CTS_SQL_MAX_LEN] = {0};
269 field_name = __ctsvc_db_get_property_field_name(com_filter->properties,
270 com_filter->property_count, QUERY_FILTER, filter->property_id);
271 RETVM_IF(NULL == field_name, CONTACTS_ERROR_INVALID_PARAMETER,
272 "property id(%d)", filter->property_id);
274 switch (filter->match) {
275 case CONTACTS_MATCH_EQUAL:
276 snprintf(out_cond, sizeof(out_cond), "%s = %lld", field_name, filter->value.l);
278 case CONTACTS_MATCH_GREATER_THAN:
279 snprintf(out_cond, sizeof(out_cond), "%s > %lld", field_name, filter->value.l);
281 case CONTACTS_MATCH_GREATER_THAN_OR_EQUAL:
282 snprintf(out_cond, sizeof(out_cond), "%s >= %lld", field_name, filter->value.l);
284 case CONTACTS_MATCH_LESS_THAN:
285 snprintf(out_cond, sizeof(out_cond), "%s < %lld", field_name, filter->value.l);
287 case CONTACTS_MATCH_LESS_THAN_OR_EQUAL:
288 snprintf(out_cond, sizeof(out_cond), "%s <= %lld", field_name, filter->value.l);
290 case CONTACTS_MATCH_NOT_EQUAL:
291 snprintf(out_cond, sizeof(out_cond), "%s <> %lld", field_name, filter->value.l);
293 case CONTACTS_MATCH_NONE:
294 snprintf(out_cond, sizeof(out_cond), "%s IS NULL", field_name);
297 /* LCOV_EXCL_START */
298 ERR("Invalid : match rule(%d) is not supported", filter->match);
299 return CONTACTS_ERROR_INVALID_PARAMETER;
303 *condition = strdup(out_cond);
304 return CONTACTS_ERROR_NONE;
307 #define CTSVC_DB_ESCAPE_CHAR '\\'
309 static char* __db_get_str_with_escape(char *str, int len, bool with_escape)
312 char temp_str[len*2+1];
314 if (false == with_escape)
317 for (i = 0; i < len; i++) {
318 if (str[i] == '\'' || str[i] == '_' || str[i] == '%' || str[i] == '\\')
319 temp_str[j++] = CTSVC_DB_ESCAPE_CHAR;
321 temp_str[j++] = str[i];
325 return strdup(temp_str);
328 static int __db_add_str_matching_rule(const char *field_name, int match,
329 char **condition, bool *with_escape)
332 char cond[CTS_SQL_MAX_LEN] = {0};
336 case CONTACTS_MATCH_EXACTLY:
337 len = snprintf(cond, sizeof(cond), "%s = ?", field_name);
338 *with_escape = false;
340 case CONTACTS_MATCH_FULLSTRING:
341 len = snprintf(cond, sizeof(cond), "%s LIKE ? ESCAPE '%c'",
342 field_name, CTSVC_DB_ESCAPE_CHAR);
344 case CONTACTS_MATCH_CONTAINS:
345 len = snprintf(cond, sizeof(cond), "%s LIKE ('%%' || ? || '%%') ESCAPE '%c'",
346 field_name, CTSVC_DB_ESCAPE_CHAR);
348 case CONTACTS_MATCH_STARTSWITH:
349 len = snprintf(cond, sizeof(cond), "%s LIKE (? || '%%') ESCAPE '%c'",
350 field_name, CTSVC_DB_ESCAPE_CHAR);
352 case CONTACTS_MATCH_ENDSWITH:
353 len = snprintf(cond, sizeof(cond), "%s LIKE ('%%' || ?) ESCAPE '%c'",
354 field_name, CTSVC_DB_ESCAPE_CHAR);
356 case CONTACTS_MATCH_EXISTS:
357 len = snprintf(cond, sizeof(cond), "%s IS NOT NULL", field_name);
360 /* LCOV_EXCL_START */
361 ERR("Invalid : match rule (%d) is not supported", match);
362 return CONTACTS_ERROR_INVALID_PARAMETER;
367 *condition = strdup(cond);
372 static char* __ctsvc_db_make_search_keyword(const char *keyword)
378 size = strlen(keyword);
379 if (strstr(keyword, " ")) {
382 char search_keyword[size * 2+1];
383 for (i = 0; i < size; i++) {
384 if (0 < j && keyword[i] == ' ') {
385 if (search_keyword[j-1] != ' ')
386 search_keyword[j++] = '*';
388 search_keyword[j++] = keyword[i];
390 if (0 < j && search_keyword[j-1] != ' ')
391 search_keyword[j++] = '*';
392 search_keyword[j] = '\0';
393 return strdup(search_keyword);
395 char search_keyword[size+2];
396 snprintf(search_keyword, sizeof(search_keyword), "%s*", keyword);
397 return strdup(search_keyword);
401 static char *_get_search_query_for_name(const char *keyword)
404 char *half_keyword = NULL;
405 int keyword_size = 0;
406 bool use_replaced_keyword = true;
408 ret = ctsvc_get_halfwidth_string(keyword, &half_keyword, &keyword_size);
409 if (CONTACTS_ERROR_NONE != ret) {
410 /* LCOV_EXCL_START */
411 ERR("UChar converting error : ctsvc_get_halfwidth_string() Fail");
412 half_keyword = (char*)keyword;
413 use_replaced_keyword = false;
417 char *search_keyword = NULL;
418 search_keyword = __ctsvc_db_make_search_keyword(half_keyword);
420 char *normalized_name = NULL;
421 int lang = CTSVC_LANG_OTHERS;
422 lang = ctsvc_normalize_str(half_keyword, &normalized_name);
423 char *hiragana = NULL;
424 char *search_hiragana = NULL;
426 if (CTSVC_LANG_JAPANESE == lang) {
427 ctsvc_convert_japanese_to_hiragana(half_keyword, &hiragana);
428 search_hiragana = __ctsvc_db_make_search_keyword(hiragana);
431 int len_keyword = strlen(half_keyword);
433 char *chosung = NULL;
434 char *korean_pattern = NULL;
435 char *search_chosung = NULL;
436 char *search_normalized = NULL;
438 char *mod_keyword = NULL;
440 case CTSVC_LANG_KOREAN: /* search with chosung */
442 * If try to find '홍길동' by 'ㄱ동'
443 * search by 'ㄱㄷ' in search_index table
445 * search by '*ㄱ*동*' in name_lookup table
447 chosung = calloc(len_keyword * 5, sizeof(char));
448 len_chosung = ctsvc_get_chosung(half_keyword, chosung, len_keyword * 5);
449 mod_keyword = __ctsvc_db_make_search_keyword(0 < len_chosung ? chosung : half_keyword);
451 case CTSVC_LANG_JAPANESE:
452 mod_keyword = search_hiragana;
455 if (CONTACTS_ERROR_NONE <= lang) { /* normalized string search */
456 search_normalized = __ctsvc_db_make_search_keyword(normalized_name);
457 mod_keyword = search_normalized;
458 } else { /* original keyword search */
459 mod_keyword = search_keyword;
465 int query_size = CTS_SQL_MAX_LEN;
466 char *query = calloc(query_size, sizeof(char));
469 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " SELECT contact_id "
470 "FROM "CTS_TABLE_SEARCH_INDEX" WHERE "CTS_TABLE_SEARCH_INDEX" "
474 temp_len = SAFE_SNPRINTF(&query, &query_size, len, mod_keyword);
477 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " '");
483 case CTSVC_LANG_KOREAN:
485 korean_pattern = calloc(len_keyword *5, sizeof(char));
486 ctsvc_get_korean_search_pattern(half_keyword, korean_pattern, len_keyword * 5);
487 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " INTERSECT SELECT "
488 "contact_id FROM "CTS_TABLE_NAME_LOOKUP" WHERE type = 0 AND name GLOB '*");
492 temp_len = SAFE_SNPRINTF(&query, &query_size, len, korean_pattern);
496 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "*' ");
501 free(korean_pattern);
502 free(search_chosung);
504 case CTSVC_LANG_JAPANESE:
508 free(search_normalized);
513 char temp_str[len_keyword * 2 + 1];
514 for (i = 0; i < len_keyword; i++) {
515 if (half_keyword[i] == '\'' || half_keyword[i] == '_' ||
516 half_keyword[i] == '%' || half_keyword[i] == '\\') {
517 temp_str[j++] = CTSVC_DB_ESCAPE_CHAR;
519 temp_str[j++] = half_keyword[i];
522 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " UNION SELECT contact_id "
523 " FROM "CTS_TABLE_NAME_LOOKUP" WHERE type = 0 AND name LIKE '%%");
527 temp_len = SAFE_SNPRINTF(&query, &query_size, len, temp_str);
531 /* CTSVC_DB_ESCAPE_CHAR */
532 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "%%' ESCAPE '\\' ");
536 free(normalized_name);
538 free(search_hiragana);
539 free(search_keyword);
541 if (use_replaced_keyword)
544 return strdup(query);
547 static char *_get_search_query_for_number(const char *keyword)
550 char *half_keyword = NULL;
551 int keyword_size = 0;
552 bool use_replaced_keyword = true;
554 ret = ctsvc_get_halfwidth_string(keyword, &half_keyword, &keyword_size);
555 if (CONTACTS_ERROR_NONE != ret) {
556 /* LCOV_EXCL_START */
557 ERR("UChar converting error : ctsvc_get_halfwidth_string() Fail");
558 half_keyword = (char*)keyword;
559 use_replaced_keyword = false;
563 char *search_keyword = NULL;
564 search_keyword = __ctsvc_db_make_search_keyword(half_keyword);
566 char *normalized_name = NULL;
567 int lang = CTSVC_LANG_OTHERS;
568 lang = ctsvc_normalize_str(half_keyword, &normalized_name);
569 char *hiragana = NULL;
570 char *search_hiragana = NULL;
572 if (CTSVC_LANG_JAPANESE == lang) {
573 ctsvc_convert_japanese_to_hiragana(half_keyword, &hiragana);
574 search_hiragana = __ctsvc_db_make_search_keyword(hiragana);
577 char *mod_keyword = NULL;
579 case CTSVC_LANG_JAPANESE:
580 mod_keyword = search_hiragana;
583 mod_keyword = search_keyword;
588 int query_size = CTS_SQL_MAX_LEN;
589 char *query = calloc(query_size, sizeof(char));
592 mod_keyword = search_hiragana ? search_hiragana : search_keyword;
593 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "SELECT contact_id "
594 "FROM "CTS_TABLE_SEARCH_INDEX" WHERE "CTS_TABLE_SEARCH_INDEX" "
599 temp_len = SAFE_SNPRINTF(&query, &query_size, len, mod_keyword);
603 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " '");
608 free(search_hiragana);
609 free(search_keyword);
614 int len_keyword = strlen(half_keyword);
615 char *clean_number = calloc(len_keyword + 1, sizeof(char));
616 if (clean_number == NULL) {
617 ERR("Memory allocation failure : ctsvc_clean_number() fail ");
620 int err = ctsvc_clean_number(half_keyword, clean_number, len_keyword + 1, false);
622 /* LCOV_EXCL_START */
623 ERR("ctsvc_clean_number() Fail(%d)", err);
629 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " UNION SELECT contact_id "
630 "FROM "CTS_TABLE_PHONE_LOOKUP" WHERE number LIKE '%%");
634 temp_len = SAFE_SNPRINTF(&query, &query_size, len, clean_number);
638 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "%%' ");
642 const char *cc = ctsvc_get_network_cc(false);
643 if (cc && cc[0] == '7' && clean_number[0] == '8') { /* Russia */
644 char normal_num[strlen(clean_number)+1+5]; /* for cc */
646 ret = ctsvc_normalize_number(clean_number, normal_num, sizeof(normal_num), false);
651 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "OR number LIKE '%%");
655 temp_len = SAFE_SNPRINTF(&query, &query_size, len, normal_num);
659 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "%%' ");
666 if (use_replaced_keyword)
669 return strdup(query);
672 static char *_get_search_query_for_data(const char *keyword)
675 char *half_keyword = NULL;
676 int keyword_size = 0;
677 bool use_replaced_keyword = true;
679 ret = ctsvc_get_halfwidth_string(keyword, &half_keyword, &keyword_size);
680 if (CONTACTS_ERROR_NONE != ret) {
681 /* LCOV_EXCL_START */
682 ERR("UChar converting error : ctsvc_get_halfwidth_string() Fail");
683 half_keyword = (char*)keyword;
684 use_replaced_keyword = false;
688 char *search_keyword = NULL;
689 search_keyword = __ctsvc_db_make_search_keyword(half_keyword);
691 char *normalized_name = NULL;
692 int lang = CTSVC_LANG_OTHERS;
693 lang = ctsvc_normalize_str(half_keyword, &normalized_name);
694 char *hiragana = NULL;
695 char *search_hiragana = NULL;
697 if (CTSVC_LANG_JAPANESE == lang) {
698 ctsvc_convert_japanese_to_hiragana(half_keyword, &hiragana);
699 search_hiragana = __ctsvc_db_make_search_keyword(hiragana);
703 char *tmp_keyword = NULL;
706 char *mod_keyword = NULL;
708 case CTSVC_LANG_JAPANESE:
709 mod_keyword = search_hiragana;
712 /* replace '-' -> '_' because FTS does not support search '-' */
713 tmp_len = strlen(search_keyword);
714 tmp_keyword = calloc(tmp_len + 1, sizeof(char));
715 if (NULL == tmp_keyword) {
716 /* LCOV_EXCL_START */
717 ERR("calloc() Fail");
718 mod_keyword = search_keyword;
722 for (i = 0; i < tmp_len; i++)
723 tmp_keyword[i] = ('-' == search_keyword[i]) ? '_' : search_keyword[i];
724 tmp_keyword[i] = '\0';
725 mod_keyword = tmp_keyword;
731 int query_size = CTS_SQL_MAX_LEN;
732 char *query = calloc(query_size, sizeof(char));
735 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " SELECT contact_id "
736 "FROM "CTS_TABLE_SEARCH_INDEX" WHERE "CTS_TABLE_SEARCH_INDEX" "
741 temp_len = SAFE_SNPRINTF(&query, &query_size, len, mod_keyword);
745 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " '");
750 free(search_hiragana);
751 free(search_keyword);
754 if (use_replaced_keyword)
757 return strdup(query);
760 static inline void __db_create_str_condtion_number(
761 ctsvc_composite_filter_s *com_filter,
762 ctsvc_attribute_filter_s *filter,
770 * number filter is for matching number
771 * depends on internal rule _NUMBER_COMPARE_
774 char clean_num[strlen(filter->value.s)+1+5]; /* for cc */
775 char normal_num[strlen(filter->value.s)+1+5]; /* for cc */
776 bool add_condition = false;
778 ret = ctsvc_clean_number(filter->value.s, clean_num, sizeof(clean_num), false);
780 ret = ctsvc_normalize_number(clean_num, normal_num, sizeof(normal_num), false);
781 normal_num[sizeof(normal_num) -1] = '\0';
783 char min_match[sizeof(normal_num)+1]; /* for cc */
784 ret = ctsvc_get_minmatch_number(normal_num, min_match,
785 sizeof(min_match), ctsvc_get_phonenumber_min_match_digit());
786 if (CONTACTS_ERROR_NONE == ret) {
787 /* minmatch filter is to improve performance */
788 size_t min_match_sz = strlen(min_match);
789 *bind_text = g_slist_append(*bind_text,
790 __db_get_str_with_escape(min_match, min_match_sz, with_escape));
792 /* _NUMBER_COMPARE_(noraml_num, normalized keyword) */
793 if (STRING_EQUAL != strcmp(normal_num, "+")) {
794 const char *number_field = NULL;
795 int property_id = filter->property_id;
796 if (property_id == CTSVC_PROPERTY_NUMBER_NUMBER_FILTER) {
797 number_field = __ctsvc_db_get_property_field_name(
798 com_filter->properties,
799 com_filter->property_count,
801 CTSVC_PROPERTY_NUMBER_NORMALIZED_NUMBER);
802 } else if (property_id == CTSVC_PROPERTY_PHONELOG_ADDRESS_FILTER) {
803 number_field = __ctsvc_db_get_property_field_name(
804 com_filter->properties,
805 com_filter->property_count,
807 CTSVC_PROPERTY_PHONELOG_NORMALIZED_ADDRESS);
808 } else if (property_id == CTSVC_PROPERTY_SPEEDDIAL_NUMBER_FILTER) {
809 number_field = __ctsvc_db_get_property_field_name(
810 com_filter->properties,
811 com_filter->property_count,
813 CTSVC_PROPERTY_SPEEDDIAL_NORMALIZED_NUMBER);
817 cond_len += snprintf(out_cond+cond_len, out_cond_size - cond_len,
818 " AND _NUMBER_COMPARE_(%s, ?, NULL, NULL)", number_field);
819 *bind_text = g_slist_append(*bind_text, strdup(normal_num));
820 add_condition = true;
827 if (add_condition == false) {
828 /* If Failto get normalized number then compare with original number */
829 const char *number_field = NULL;
830 if (filter->property_id == CTSVC_PROPERTY_NUMBER_NUMBER_FILTER) {
831 number_field = __ctsvc_db_get_property_field_name(com_filter->properties,
832 com_filter->property_count,
834 CTSVC_PROPERTY_NUMBER_NUMBER);
835 } else if (filter->property_id == CTSVC_PROPERTY_PHONELOG_ADDRESS_FILTER) {
836 number_field = __ctsvc_db_get_property_field_name(com_filter->properties,
837 com_filter->property_count,
839 CTSVC_PROPERTY_PHONELOG_ADDRESS);
840 } else if (filter->property_id == CTSVC_PROPERTY_SPEEDDIAL_NUMBER_FILTER) {
841 number_field = __ctsvc_db_get_property_field_name(com_filter->properties,
842 com_filter->property_count,
844 CTSVC_PROPERTY_SPEEDDIAL_NUMBER);
848 snprintf(out_cond, out_cond_size, "%s = ?", number_field);
849 *bind_text = g_slist_append(*bind_text, strdup(filter->value.s));
854 static inline int __db_create_str_condtion_normalized_number(
855 ctsvc_composite_filter_s *com_filter,
856 ctsvc_attribute_filter_s *filter,
865 char clean_num[strlen(filter->value.s)+1+5]; /* for cc */
867 ret = ctsvc_clean_number(filter->value.s, clean_num, sizeof(clean_num), false);
869 bool add_condition = true;
870 const char *clean_field = NULL;
871 /* has clean number or normalized number */
872 const char *cc = ctsvc_get_network_cc(false);
873 if (cc && cc[0] == '7' && clean_num[0] == '8') { /* Russia */
874 char normal_num[strlen(clean_num)+1+5]; /* for cc */
875 int normal_num_sz = sizeof(normal_num);
877 ret = ctsvc_normalize_number(clean_num, normal_num, normal_num_sz, false);
879 *bind_text = g_slist_append(*bind_text,
880 __db_get_str_with_escape(normal_num, normal_num_sz, with_escape));
882 *bind_text = g_slist_append(*bind_text,
883 __db_get_str_with_escape(clean_num, normal_num_sz, with_escape));
885 } else if (STRING_EQUAL != strcmp(clean_num, "+")) {
886 *bind_text = g_slist_append(*bind_text,
887 __db_get_str_with_escape(clean_num, strlen(clean_num), with_escape));
889 add_condition = false;
892 if (filter->property_id == CTSVC_PROPERTY_NUMBER_NORMALIZED_NUMBER) {
893 clean_field = __ctsvc_db_get_property_field_name(com_filter->properties,
894 com_filter->property_count,
896 CTSVC_PROPERTY_NUMBER_CLEANED_NUMBER);
897 } else if (filter->property_id == CTSVC_PROPERTY_PHONELOG_NORMALIZED_ADDRESS) {
898 clean_field = __ctsvc_db_get_property_field_name(com_filter->properties,
899 com_filter->property_count,
901 CTSVC_PROPERTY_PHONELOG_CLEANED_ADDRESS);
902 } else if (filter->property_id == CTSVC_PROPERTY_SPEEDDIAL_NORMALIZED_NUMBER) {
903 clean_field = __ctsvc_db_get_property_field_name(com_filter->properties,
904 com_filter->property_count,
906 CTSVC_PROPERTY_SPEEDDIAL_CLEANED_NUMBER);
911 cond_len += snprintf(out_cond+cond_len, out_cond_sz - cond_len, " OR ");
912 ret = __db_add_str_matching_rule(clean_field, filter->match, &tmp,
915 /* LCOV_EXCL_START */
916 ERR("__db_add_str_matching_rule() Fail");
917 return CONTACTS_ERROR_INVALID_PARAMETER;
920 cond_len += snprintf(out_cond + cond_len, out_cond_sz - cond_len, "%s", tmp);
923 *bind_text = g_slist_append(*bind_text,
924 __db_get_str_with_escape(clean_num, strlen(clean_num), with_escape));
926 } else if (ret == 0) {
927 /* If Failto get cleaned number then compare with original number */
928 const char *number_field = NULL;
929 if (filter->property_id == CTSVC_PROPERTY_NUMBER_NORMALIZED_NUMBER) {
930 number_field = __ctsvc_db_get_property_field_name(com_filter->properties,
931 com_filter->property_count,
933 CTSVC_PROPERTY_NUMBER_NUMBER);
934 } else if (filter->property_id == CTSVC_PROPERTY_PHONELOG_NORMALIZED_ADDRESS) {
935 number_field = __ctsvc_db_get_property_field_name(com_filter->properties,
936 com_filter->property_count,
938 CTSVC_PROPERTY_PHONELOG_ADDRESS);
939 } else if (filter->property_id == CTSVC_PROPERTY_SPEEDDIAL_NORMALIZED_NUMBER) {
940 number_field = __ctsvc_db_get_property_field_name(com_filter->properties,
941 com_filter->property_count,
943 CTSVC_PROPERTY_SPEEDDIAL_NUMBER);
947 ret = __db_add_str_matching_rule(number_field, filter->match, &tmp,
950 /* LCOV_EXCL_START */
951 ERR("__db_add_str_matching_rule() Fail");
952 return CONTACTS_ERROR_INVALID_PARAMETER;
956 cond_len = snprintf(out_cond, out_cond_sz, "%s", tmp);
959 *bind_text = g_slist_append(*bind_text,
960 __db_get_str_with_escape(filter->value.s, strlen(filter->value.s),
965 return CONTACTS_ERROR_INVALID_PARAMETER;
968 return CONTACTS_ERROR_NONE;
971 static inline int __ctsvc_db_create_str_condition(ctsvc_composite_filter_s *com_filter,
972 ctsvc_attribute_filter_s *filter, char **condition, GSList **bind_text)
975 const char *field_name;
976 char out_cond[CTS_SQL_MAX_LEN] = {0};
979 bool with_escape = true;
983 field_name = __ctsvc_db_get_property_field_name(com_filter->properties,
984 com_filter->property_count, QUERY_FILTER, filter->property_id);
985 RETVM_IF(NULL == field_name, CONTACTS_ERROR_INVALID_PARAMETER,
986 "property id(%d)", filter->property_id);
989 * number_filter condition is only used to find exactly matched number
990 * based on internal logic : _NUMBER_COMPARE_
992 if (filter->property_id == CTSVC_PROPERTY_NUMBER_NUMBER_FILTER
993 || filter->property_id == CTSVC_PROPERTY_PHONELOG_ADDRESS_FILTER
994 || filter->property_id == CTSVC_PROPERTY_SPEEDDIAL_NUMBER_FILTER)
995 filter->match = CONTACTS_MATCH_EXACTLY;
997 ret = __db_add_str_matching_rule(field_name, filter->match, &tmp, &with_escape);
999 /* LCOV_EXCL_START */
1000 ERR("__db_add_str_matching_rule() Fail(%d)", ret);
1002 return CONTACTS_ERROR_INVALID_PARAMETER;
1003 /* LCOV_EXCL_STOP */
1005 cond_len = snprintf(out_cond, sizeof(out_cond), "%s", tmp);
1009 if (filter->value.s) {
1010 if (filter->property_id == CTSVC_PROPERTY_NUMBER_NUMBER_FILTER
1011 || filter->property_id == CTSVC_PROPERTY_PHONELOG_ADDRESS_FILTER
1012 || filter->property_id == CTSVC_PROPERTY_SPEEDDIAL_NUMBER_FILTER) {
1014 __db_create_str_condtion_number(com_filter, filter, with_escape, bind_text,
1015 cond_len, out_cond, sizeof(out_cond));
1016 } else if (filter->property_id == CTSVC_PROPERTY_NUMBER_NORMALIZED_NUMBER
1017 || filter->property_id == CTSVC_PROPERTY_PHONELOG_NORMALIZED_ADDRESS
1018 || filter->property_id == CTSVC_PROPERTY_SPEEDDIAL_NORMALIZED_NUMBER) {
1019 /* normalized number */
1020 ret = __db_create_str_condtion_normalized_number(com_filter, filter,
1021 with_escape, bind_text, cond_len, out_cond, sizeof(out_cond));
1022 if (CONTACTS_ERROR_NONE != ret) {
1023 /* LCOV_EXCL_START */
1024 ERR("__db_create_str_condtion_normalized_number() Fail(%d)", ret);
1026 /* LCOV_EXCL_STOP */
1028 } else if (filter->property_id == CTSVC_PROPERTY_NUMBER_CLEANED_NUMBER
1029 || filter->property_id == CTSVC_PROPERTY_PHONELOG_CLEANED_ADDRESS
1030 || filter->property_id == CTSVC_PROPERTY_SPEEDDIAL_CLEANED_NUMBER) {
1031 /* cleaned number */
1032 char clean_num[strlen(filter->value.s)+1+5]; /* for cc */
1034 ret = ctsvc_clean_number(filter->value.s, clean_num, sizeof(clean_num),
1037 *bind_text = g_slist_append(*bind_text,
1038 __db_get_str_with_escape(clean_num, strlen(clean_num),
1040 } else if (ret == 0) {
1041 /* If Failto get cleaned number then compare with original number */
1042 const char *number_field = NULL;
1043 if (filter->property_id == CTSVC_PROPERTY_NUMBER_CLEANED_NUMBER) {
1044 number_field = __ctsvc_db_get_property_field_name(
1045 com_filter->properties,
1046 com_filter->property_count,
1048 CTSVC_PROPERTY_NUMBER_NUMBER);
1049 } else if (filter->property_id == CTSVC_PROPERTY_PHONELOG_CLEANED_ADDRESS) {
1050 number_field = __ctsvc_db_get_property_field_name(
1051 com_filter->properties,
1052 com_filter->property_count,
1054 CTSVC_PROPERTY_PHONELOG_ADDRESS);
1055 } else if (filter->property_id == CTSVC_PROPERTY_SPEEDDIAL_CLEANED_NUMBER) {
1056 number_field = __ctsvc_db_get_property_field_name(
1057 com_filter->properties,
1058 com_filter->property_count,
1060 CTSVC_PROPERTY_SPEEDDIAL_NUMBER);
1064 ret = __db_add_str_matching_rule(number_field, filter->match, &tmp,
1066 RETVM_IF(ret <= 0, CONTACTS_ERROR_INVALID_PARAMETER,
1067 "__db_add_str_matching_rule Fail");
1068 cond_len = snprintf(out_cond, sizeof(out_cond), "%s", tmp);
1071 *bind_text = g_slist_append(*bind_text,
1072 __db_get_str_with_escape(filter->value.s,
1073 strlen(filter->value.s), with_escape));
1076 return CONTACTS_ERROR_INVALID_PARAMETER;
1078 } else if (filter->property_id == CTSVC_PROPERTY_CONTACT_IMAGE_THUMBNAIL
1079 || filter->property_id == CTSVC_PROPERTY_PERSON_IMAGE_THUMBNAIL
1080 || filter->property_id == CTSVC_PROPERTY_MY_PROFILE_IMAGE_THUMBNAIL
1081 || filter->property_id == CTSVC_PROPERTY_IMAGE_PATH) {
1082 if (STRING_EQUAL == strncmp(filter->value.s, CTSVC_CONTACT_IMG_FULL_LOCATION,
1083 strlen(CTSVC_CONTACT_IMG_FULL_LOCATION))) {
1084 *bind_text = g_slist_append(*bind_text,
1085 __db_get_str_with_escape(
1086 filter->value.s + strlen(CTSVC_CONTACT_IMG_FULL_LOCATION) + 1,
1087 strlen(filter->value.s) - strlen(CTSVC_CONTACT_IMG_FULL_LOCATION) - 1,
1090 *bind_text = g_slist_append(*bind_text,
1091 __db_get_str_with_escape(filter->value.s, strlen(filter->value.s),
1094 } else if (filter->property_id == CTSVC_PROPERTY_GROUP_IMAGE) {
1095 if (STRING_EQUAL == strncmp(filter->value.s, CTS_GROUP_IMAGE_LOCATION,
1096 strlen(CTS_GROUP_IMAGE_LOCATION))) {
1097 *bind_text = g_slist_append(*bind_text,
1098 __db_get_str_with_escape(
1099 filter->value.s + strlen(CTS_GROUP_IMAGE_LOCATION) + 1,
1100 strlen(filter->value.s) - strlen(CTS_GROUP_IMAGE_LOCATION)-1,
1103 *bind_text = g_slist_append(*bind_text,
1104 __db_get_str_with_escape(filter->value.s, strlen(filter->value.s),
1107 } else if (filter->property_id == CTSVC_PROPERTY_COMPANY_LOGO) {
1108 if (STRING_EQUAL == strncmp(filter->value.s, CTS_LOGO_IMAGE_LOCATION,
1109 strlen(CTS_LOGO_IMAGE_LOCATION))) {
1110 *bind_text = g_slist_append(*bind_text,
1111 __db_get_str_with_escape(
1112 filter->value.s + strlen(CTS_LOGO_IMAGE_LOCATION) + 1,
1113 strlen(filter->value.s) - strlen(CTS_LOGO_IMAGE_LOCATION) - 1,
1116 *bind_text = g_slist_append(*bind_text,
1117 __db_get_str_with_escape(filter->value.s, strlen(filter->value.s),
1122 *bind_text = g_slist_append(*bind_text,
1123 __db_get_str_with_escape(filter->value.s, strlen(filter->value.s),
1128 *condition = strdup(out_cond);
1130 return CONTACTS_ERROR_NONE;
1133 static inline int __ctsvc_db_create_bool_condition(ctsvc_composite_filter_s *com_filter,
1134 ctsvc_attribute_filter_s *filter, char **condition)
1136 const char *field_name;
1137 char out_cond[CTS_SQL_MAX_LEN] = {0};
1139 field_name = __ctsvc_db_get_property_field_name(com_filter->properties,
1140 com_filter->property_count, QUERY_FILTER, filter->property_id);
1141 RETVM_IF(NULL == field_name, CONTACTS_ERROR_INVALID_PARAMETER,
1142 "property id(%d)", filter->property_id);
1144 snprintf(out_cond, sizeof(out_cond), "%s = %d", field_name, filter->value.b ? 1 : 0);
1145 *condition = strdup(out_cond);
1146 return CONTACTS_ERROR_NONE;
1149 static int __ctsvc_db_create_attribute_condition(ctsvc_composite_filter_s *com_filter,
1150 ctsvc_attribute_filter_s *filter, char **condition, GSList **bind_text)
1155 RETV_IF(NULL == filter, CONTACTS_ERROR_INVALID_PARAMETER);
1157 switch (filter->filter_type) {
1158 case CTSVC_FILTER_INT:
1159 ret = __ctsvc_db_create_int_condition(com_filter, filter, &cond);
1161 case CTSVC_FILTER_BOOL:
1162 ret = __ctsvc_db_create_bool_condition(com_filter, filter, &cond);
1164 case CTSVC_FILTER_STR:
1165 ret = __ctsvc_db_create_str_condition(com_filter, filter, &cond, bind_text);
1167 case CTSVC_FILTER_LLI:
1168 ret = __ctsvc_db_create_lli_condition(com_filter, filter, &cond);
1170 case CTSVC_FILTER_DOUBLE:
1171 ret = __ctsvc_db_create_double_condition(com_filter, filter, &cond);
1174 /* LCOV_EXCL_START */
1175 ERR("The filter type is not supported (%d)", filter->filter_type);
1176 return CONTACTS_ERROR_INVALID_PARAMETER;
1177 /* LCOV_EXCL_STOP */
1180 if (CONTACTS_ERROR_NONE == ret)
1186 #define CTSVC_FILTER_LENGTH 100
1189 * If there are too many condition, sqlite return FailSQLITE_ERROR(1).
1190 * Expression tree is too large (maximum depth 1000).
1191 * It is related to SQLITE_LIMIT_EXPR_DEPTH.
1193 static inline int __db_create_composite_condition(
1194 ctsvc_composite_filter_s *com_filter, char **condition, GSList **bind_text)
1196 RETV_IF(NULL == com_filter, CONTACTS_ERROR_INVALID_PARAMETER);
1202 char *out_cond = NULL;
1203 GSList *cursor_filter;
1205 ctsvc_filter_s *filter;
1206 contacts_filter_operator_e op;
1208 GSList *filters = com_filter->filters;
1209 GSList *ops = com_filter->filter_ops;
1212 /* the case : did not set filter condition after calling contacts_filter_create() */
1214 RETV_IF(NULL == filters, CONTACTS_ERROR_NONE);
1219 filter = (ctsvc_filter_s*)filters->data;
1220 if (filter->filter_type == CTSVC_FILTER_COMPOSITE) {
1221 __db_create_composite_condition((ctsvc_composite_filter_s*)filter, &cond,
1224 __ctsvc_db_create_attribute_condition(com_filter,
1225 (ctsvc_attribute_filter_s*)filter, &cond, bind_text);
1228 buf_size = CTSVC_FILTER_LENGTH;
1229 out_cond = calloc(1, buf_size);
1230 if (NULL == out_cond) {
1231 /* LCOV_EXCL_START */
1232 ERR("calloc() Fail");
1234 return CONTACTS_ERROR_OUT_OF_MEMORY;
1235 /* LCOV_EXCL_STOP */
1240 temp_len = SAFE_SNPRINTF(&out_cond, &buf_size, len, "(");
1244 temp_len = SAFE_SNPRINTF(&out_cond, &buf_size, len, cond);
1248 temp_len = SAFE_SNPRINTF(&out_cond, &buf_size, len, ")");
1254 cursor_filter = filters->next;
1255 for (cursor_ops = ops; cursor_ops && cursor_filter;
1256 cursor_filter = cursor_filter->next, cursor_ops = cursor_ops->next) {
1260 filter = cursor_filter->data;
1261 if (filter->filter_type == CTSVC_FILTER_COMPOSITE) {
1262 __db_create_composite_condition((ctsvc_composite_filter_s*)filter,
1265 __ctsvc_db_create_attribute_condition(com_filter,
1266 (ctsvc_attribute_filter_s*)filter, &cond, &bind);
1270 op = (contacts_filter_operator_e)cursor_ops->data;
1271 if (op == CONTACTS_FILTER_OPERATOR_AND)
1272 temp_len = SAFE_SNPRINTF(&out_cond, &buf_size, len, " AND (");
1274 temp_len = SAFE_SNPRINTF(&out_cond, &buf_size, len, " OR (");
1278 temp_len = SAFE_SNPRINTF(&out_cond, &buf_size, len, cond);
1281 temp_len = SAFE_SNPRINTF(&out_cond, &buf_size, len, ")");
1286 *bind_text = g_slist_concat(*bind_text, bind);
1291 *condition = out_cond;
1293 return CONTACTS_ERROR_NONE;
1296 /* Make and execute 'UPDATE' sqlite statement to update record */
1297 int ctsvc_db_update_record_with_set_query(const char *set, GSList *bind_text,
1298 const char *table, int id)
1300 int ret = CONTACTS_ERROR_NONE;
1301 char query[CTS_SQL_MAX_LEN] = {0};
1302 sqlite3_stmt *stmt = NULL;
1303 GSList *cursor = NULL;
1305 snprintf(query, sizeof(query), "UPDATE %s SET %s WHERE id = %d", table, set, id);
1307 ret = ctsvc_query_prepare(query, &stmt);
1308 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
1312 for (cursor = bind_text, i = 1; cursor; cursor = cursor->next, i++) {
1313 const char *text = cursor->data;
1315 ctsvc_stmt_bind_text(stmt, i, text);
1318 ret = ctsvc_stmt_step(stmt);
1319 if (CONTACTS_ERROR_NONE != ret) {
1320 /* LCOV_EXCL_START */
1321 ERR("ctsvc_stmt_step() Fail(%d)", ret);
1322 ctsvc_stmt_finalize(stmt);
1324 /* LCOV_EXCL_STOP */
1326 ctsvc_stmt_finalize(stmt);
1330 /* make 'SET' sqlite statement to update record */
1331 int ctsvc_db_create_set_query(contacts_record_h record, char **set, GSList **bind_text)
1333 ctsvc_record_s *s_record;
1335 const property_info_s *property_info = NULL;
1336 unsigned int property_info_count = 0;
1337 char out_set[CTS_SQL_MAX_LEN] = {0};
1339 const char *field_name;
1340 int ret = CONTACTS_ERROR_NONE;
1342 RETV_IF(record == NULL, CONTACTS_ERROR_INVALID_PARAMETER);
1344 s_record = (ctsvc_record_s*)record;
1345 if (0 == s_record->property_max_count || NULL == s_record->properties_flags) {
1346 /* LCOV_EXCL_START */
1347 ERR("record don't have properties");
1348 return CONTACTS_ERROR_INVALID_PARAMETER;
1349 /* LCOV_EXCL_STOP */
1352 property_info = ctsvc_view_get_all_property_infos(s_record->view_uri,
1353 &property_info_count);
1355 for (i = 0; i < property_info_count; i++) {
1356 if (ctsvc_record_check_property_flag(s_record, property_info[i].property_id,
1357 CTSVC_PROPERTY_FLAG_DIRTY)) {
1358 field_name = property_info[i].fields;
1359 if (NULL == field_name)
1362 if (CTSVC_VIEW_CHECK_DATA_TYPE(property_info[i].property_id, CTSVC_VIEW_DATA_TYPE_BOOL)) {
1364 ret = contacts_record_get_bool(record, property_info[i].property_id, &tmp);
1365 if (ret != CONTACTS_ERROR_NONE)
1368 len += snprintf(out_set+len, sizeof(out_set)-len, ", ");
1369 len += snprintf(out_set+len, sizeof(out_set)-len, "%s=%d", field_name, tmp);
1370 } else if (CTSVC_VIEW_CHECK_DATA_TYPE(property_info[i].property_id, CTSVC_VIEW_DATA_TYPE_INT)) {
1372 ret = contacts_record_get_int(record, property_info[i].property_id, &tmp);
1373 if (ret != CONTACTS_ERROR_NONE)
1376 len += snprintf(out_set+len, sizeof(out_set)-len, ", ");
1377 len += snprintf(out_set+len, sizeof(out_set)-len, "%s=%d", field_name, tmp);
1378 } else if (CTSVC_VIEW_CHECK_DATA_TYPE(property_info[i].property_id, CTSVC_VIEW_DATA_TYPE_LLI)) {
1379 long long int tmp = 0;
1380 ret = contacts_record_get_lli(record, property_info[i].property_id, &tmp);
1381 if (ret != CONTACTS_ERROR_NONE)
1384 len += snprintf(out_set+len, sizeof(out_set)-len, ", ");
1385 len += snprintf(out_set+len, sizeof(out_set)-len, "%s=%lld", field_name, tmp);
1386 } else if (CTSVC_VIEW_CHECK_DATA_TYPE(property_info[i].property_id, CTSVC_VIEW_DATA_TYPE_STR)) {
1388 ret = contacts_record_get_str_p(record, property_info[i].property_id, &tmp);
1389 if (ret != CONTACTS_ERROR_NONE)
1392 len += snprintf(out_set+len, sizeof(out_set)-len, ", ");
1393 len += snprintf(out_set+len, sizeof(out_set)-len, "%s=?", field_name);
1394 *bind_text = g_slist_append(*bind_text, strdup(SAFE_STR(tmp)));
1395 } else if (CTSVC_VIEW_CHECK_DATA_TYPE(property_info[i].property_id, CTSVC_VIEW_DATA_TYPE_DOUBLE)) {
1397 ret = contacts_record_get_double(record, property_info[i].property_id, &tmp);
1398 if (ret != CONTACTS_ERROR_NONE)
1401 len += snprintf(out_set+len, sizeof(out_set)-len, ", ");
1402 len += snprintf(out_set+len, sizeof(out_set)-len, "%s=%lf", field_name,
1407 *set = strdup(out_set);
1409 return CONTACTS_ERROR_NONE;
1412 static int __db_create_projection(const char *view_uri,
1413 const property_info_s *properties, int ids_count,
1414 unsigned int *projections,
1422 const char *field_name = NULL;
1423 char out_projection[CTS_SQL_MAX_LEN] = {0};
1424 char temp[CTS_SQL_MAX_LEN] = {0};
1425 bool is_data1 = false;
1426 bool is_data2 = false;
1430 if (0 < pro_count) {
1431 for (i = 0; i < pro_count; i++) {
1432 if (projections[i] == CTSVC_PROPERTY_PERSON_DISPLAY_NAME_INDEX) {
1433 snprintf(temp, sizeof(temp), "_NORMALIZE_INDEX_(%s)",
1434 ctsvc_get_sort_name_column());
1436 } else if (true == is_snippet &&
1437 projections[i] == CTSVC_PROPERTY_PERSON_SNIPPET_TYPE) {
1438 snprintf(temp, sizeof(temp), "temp_data.datatype");
1441 } else if (true == is_snippet &&
1442 projections[i] == CTSVC_PROPERTY_PERSON_SNIPPET_STRING) {
1443 snprintf(temp, sizeof(temp), "(CASE "
1444 "WHEN datatype=1 THEN (datatype || '@' || display_name) "
1445 "ELSE (datatype || '@' || temp_data._data) END)");
1449 field_name = __ctsvc_db_get_property_field_name(properties, ids_count,
1450 QUERY_PROJECTION, projections[i]);
1455 len += snprintf(out_projection+len, sizeof(out_projection)-len,
1459 len += snprintf(out_projection+len, sizeof(out_projection)-len,
1460 ", %s", field_name);
1465 /* add all properties */
1466 for (i = 0; i < ids_count; i++) {
1467 if (CTSVC_VIEW_DATA_TYPE_REC == (properties[i].property_id & CTSVC_VIEW_DATA_TYPE_MASK))
1470 if (properties[i].fields) {
1471 field_name = properties[i].fields;
1472 } else if (properties[i].property_id == CTSVC_PROPERTY_PERSON_DISPLAY_NAME_INDEX) {
1473 snprintf(temp, sizeof(temp), "_NORMALIZE_INDEX_(%s)",
1474 ctsvc_get_sort_name_column());
1476 } else if (true == is_snippet &&
1477 properties[i].property_id == CTSVC_PROPERTY_PERSON_SNIPPET_TYPE) {
1478 snprintf(temp, sizeof(temp), "temp_data.datatype");
1481 } else if (true == is_snippet &&
1482 properties[i].property_id == CTSVC_PROPERTY_PERSON_SNIPPET_STRING) {
1483 snprintf(temp, sizeof(temp), "(CASE "
1484 "WHEN datatype=1 THEN (datatype || '@' || display_name) "
1485 "ELSE (datatype || '@' || temp_data._data) END)");
1489 field_name = ctsvc_get_display_column();
1493 len += snprintf(out_projection+len, sizeof(out_projection)-len, "%s",
1497 len += snprintf(out_projection+len, sizeof(out_projection)-len, ", %s",
1503 /* check extra data */
1504 if (true == is_data1 || true == is_data2) {
1505 snprintf(temp, sizeof(temp), "MIN(temp_data._priority) ");
1508 len += snprintf(out_projection+len, sizeof(out_projection)-len, "%s",
1512 len += snprintf(out_projection+len, sizeof(out_projection)-len, ", %s",
1517 *projection = strdup(out_projection);
1518 return CONTACTS_ERROR_NONE;
1521 static inline bool __ctsvc_db_view_has_display_name(const char *view_uri,
1522 const property_info_s *properties, int count)
1525 #ifdef ENABLE_LOG_FEATURE
1526 if (STRING_EQUAL == strcmp(view_uri, _contacts_person_phone_log._uri))
1528 #endif /* ENABLE_LOG_FEATURE */
1530 for (i = 0; i < count; i++) {
1531 property_info_s *p = (property_info_s*)&(properties[i]);
1532 switch (p->property_id) {
1533 case CTSVC_PROPERTY_PERSON_DISPLAY_NAME:
1534 case CTSVC_PROPERTY_CONTACT_DISPLAY_NAME:
1543 #define SORT_CHECK_LEN 7
1545 int ctsvc_db_make_get_records_query_stmt(ctsvc_query_s *s_query, int offset, int limit,
1549 char temp_str[100] = {0};
1556 const char *sortkey = NULL;
1557 char *condition = NULL;
1558 char *projection = NULL;
1559 GSList *bind_text = NULL;
1562 ret = ctsvc_db_get_table_name(s_query->view_uri, &table);
1563 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "Invalid view uri(%s)", s_query->view_uri);
1565 ret = __db_create_projection(s_query->view_uri, s_query->properties,
1566 s_query->property_count, s_query->projection, s_query->projection_count,
1567 &projection, false);
1568 if (CONTACTS_ERROR_NONE != ret) {
1569 /* LCOV_EXCL_START */
1570 ERR("__db_create_projection() Fail(%d)", ret);
1572 /* LCOV_EXCL_STOP */
1575 query_size = CTS_SQL_MAX_LEN;
1576 query = calloc(1, query_size);
1577 if (NULL == query) {
1578 /* LCOV_EXCL_START */
1579 ERR("calloc() Fail");
1581 return CONTACTS_ERROR_OUT_OF_MEMORY;
1582 /* LCOV_EXCL_STOP */
1586 if (s_query->distinct)
1587 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "SELECT DISTINCT ");
1589 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "SELECT ");
1590 if (0 <= temp_len) len += temp_len;
1591 temp_len = SAFE_SNPRINTF(&query, &query_size, len, projection);
1592 if (0 <= temp_len) len += temp_len;
1593 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " FROM ");
1594 if (0 <= temp_len) len += temp_len;
1596 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " (");
1597 if (0 <= temp_len) len += temp_len;
1598 temp_len = SAFE_SNPRINTF(&query, &query_size, len, table);
1599 if (0 <= temp_len) len += temp_len;
1600 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ")");
1601 if (0 <= temp_len) len += temp_len;
1603 if (s_query->filter) {
1604 ret = __db_create_composite_condition(s_query->filter, &condition,
1606 if (CONTACTS_ERROR_NONE != ret) {
1607 /* LCOV_EXCL_START */
1608 ERR("__db_create_composite_condition Fail(%d)", ret);
1611 /* LCOV_EXCL_STOP */
1613 if (condition && *condition) {
1614 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " WHERE (");
1615 if (0 <= temp_len) len += temp_len;
1616 temp_len = SAFE_SNPRINTF(&query, &query_size, len, condition);
1617 if (0 <= temp_len) len += temp_len;
1618 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ")");
1619 if (0 <= temp_len) len += temp_len;
1623 /* If the view_uri has display_name, default sortkey is display_name */
1624 if (__ctsvc_db_view_has_display_name(s_query->view_uri, s_query->properties, s_query->property_count))
1625 sortkey = ctsvc_get_sort_column();
1627 if (s_query->sort_property_id) {
1628 const char *field_name;
1630 switch (s_query->sort_property_id) {
1631 case CTSVC_PROPERTY_PERSON_DISPLAY_NAME:
1632 case CTSVC_PROPERTY_CONTACT_DISPLAY_NAME:
1634 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " ORDER BY ");
1635 if (0 <= temp_len) len += temp_len;
1636 temp_len = SAFE_SNPRINTF(&query, &query_size, len, sortkey);
1637 if (0 <= temp_len) len += temp_len;
1638 if (false == s_query->sort_asc) {
1639 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " DESC ");
1640 if (0 <= temp_len) len += temp_len;
1645 field_name = __ctsvc_db_get_property_field_name(s_query->properties,
1646 s_query->property_count, QUERY_SORTKEY, s_query->sort_property_id);
1648 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " ORDER BY ");
1649 if (0 <= temp_len) len += temp_len;
1650 temp_len = SAFE_SNPRINTF(&query, &query_size, len, field_name);
1651 if (0 <= temp_len) len += temp_len;
1653 if (CTSVC_PROPERTY_GROUP_NAME == s_query->sort_property_id) {
1654 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " COLLATE _NAME_SORT_ ");
1655 if (0 <= temp_len) len += temp_len;
1658 if (false == s_query->sort_asc) {
1659 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " DESC ");
1660 if (0 <= temp_len) len += temp_len;
1662 } else if (sortkey) {
1663 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " ORDER BY ");
1664 if (0 <= temp_len) len += temp_len;
1665 temp_len = SAFE_SNPRINTF(&query, &query_size, len, sortkey);
1666 if (0 <= temp_len) len += temp_len;
1670 } else if (sortkey) {
1671 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " ORDER BY ");
1675 temp_len = SAFE_SNPRINTF(&query, &query_size, len, sortkey);
1678 } else if (STRING_EQUAL == strcmp(s_query->view_uri, CTSVC_VIEW_URI_GROUP)) {
1679 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " ORDER BY group_prio");
1680 if (0 <= temp_len) len += temp_len;
1684 snprintf(temp_str, sizeof(temp_str), " LIMIT %d", limit);
1685 temp_len = SAFE_SNPRINTF(&query, &query_size, len, temp_str);
1686 if (0 <= temp_len) len += temp_len;
1688 snprintf(temp_str, sizeof(temp_str), " OFFSET %d", offset);
1689 temp_len = SAFE_SNPRINTF(&query, &query_size, len, temp_str);
1690 if (0 <= temp_len) len += temp_len;
1697 ret = ctsvc_query_prepare(query, stmt);
1699 if (NULL == *stmt) {
1700 /* LCOV_EXCL_START */
1701 ERR("ctsvc_query_prepare() Fail(%d)", ret);
1702 for (cursor = bind_text; cursor; cursor = cursor->next)
1704 g_slist_free(bind_text);
1706 /* LCOV_EXCL_STOP */
1709 for (cursor = bind_text, i = 1; cursor; cursor = cursor->next, i++)
1710 ctsvc_stmt_bind_copy_text(*stmt, i, cursor->data, strlen(cursor->data));
1712 for (cursor = bind_text; cursor; cursor = cursor->next)
1714 g_slist_free(bind_text);
1716 return CONTACTS_ERROR_NONE;
1719 static int __ctsvc_db_get_records_with_query_exec(ctsvc_query_s *query, int offset,
1720 int limit, contacts_list_h *out_list)
1725 cts_stmt stmt = NULL;
1726 contacts_list_h list = NULL;
1728 ret = ctsvc_db_make_get_records_query_stmt(query, offset, limit, &stmt);
1729 if (CONTACTS_ERROR_NONE != ret) {
1730 /* LCOV_EXCL_START */
1731 ERR("ctsvc_db_make_get_records_query_stmt() Fail(%d)", ret);
1733 /* LCOV_EXCL_STOP */
1736 contacts_list_create(&list);
1737 while ((ret = ctsvc_stmt_step(stmt))) {
1738 contacts_record_h record;
1741 /* LCOV_EXCL_START */
1742 ERR("ctsvc_stmt_step() Fail(%d)", ret);
1743 ctsvc_stmt_finalize(stmt);
1744 contacts_list_destroy(list, true);
1746 /* LCOV_EXCL_STOP */
1749 contacts_record_create(query->view_uri, (contacts_record_h*)&record);
1751 if (0 == query->projection_count) {
1752 field_count = query->property_count;
1754 field_count = query->projection_count;
1756 ret = ctsvc_record_set_projection_flags(record, query->projection,
1757 query->projection_count, query->property_count);
1758 if (CONTACTS_ERROR_NONE != ret)
1759 ASSERT_NOT_REACHED("To set projection is Fail.\n");
1762 for (i = 0; i < field_count; i++) {
1765 if (0 == query->projection_count)
1766 property_id = query->properties[i].property_id;
1768 property_id = query->projection[i];
1770 type = __ctsvc_db_get_property_type(query->properties, query->property_count,
1772 if (type == CTSVC_VIEW_DATA_TYPE_INT)
1773 ctsvc_record_set_int(record, property_id, ctsvc_stmt_get_int(stmt, i));
1774 else if (type == CTSVC_VIEW_DATA_TYPE_STR)
1775 ctsvc_record_set_str(record, property_id, ctsvc_stmt_get_text(stmt, i));
1776 else if (type == CTSVC_VIEW_DATA_TYPE_BOOL)
1777 ctsvc_record_set_bool(record, property_id, (ctsvc_stmt_get_int(stmt, i) ? true : false));
1778 else if (type == CTSVC_VIEW_DATA_TYPE_LLI)
1779 ctsvc_record_set_lli(record, property_id, ctsvc_stmt_get_int64(stmt, i));
1780 else if (type == CTSVC_VIEW_DATA_TYPE_DOUBLE)
1781 ctsvc_record_set_double(record, property_id, ctsvc_stmt_get_dbl(stmt, i));
1783 /* LCOV_EXCL_START */
1784 ERR("unknown type(%d)", type);
1785 /* LCOV_EXCL_STOP */
1787 ctsvc_list_prepend(list, record);
1789 ctsvc_stmt_finalize(stmt);
1790 ctsvc_list_reverse(list);
1793 return CONTACTS_ERROR_NONE;
1796 static int __ctsvc_db_get_all_records_exec(const char *view_uri,
1797 const property_info_s *properties,
1799 const char *projection,
1802 contacts_list_h *out_list)
1804 char query[CTS_SQL_MAX_LEN] = {0};
1810 cts_stmt stmt = NULL;
1811 contacts_list_h list = NULL;
1812 const char *sortkey;
1814 ret = ctsvc_db_get_table_name(view_uri, &table);
1815 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "Invalid view uri (%s)", view_uri);
1817 len = snprintf(query, sizeof(query), "SELECT %s FROM ", projection);
1819 len += snprintf(query+len, sizeof(query)-len, " (%s)", table);
1821 if (__ctsvc_db_view_has_display_name(view_uri, properties, ids_count)) {
1822 sortkey = ctsvc_get_sort_column();
1823 len += snprintf(query+len, sizeof(query)-len, " ORDER BY %s", sortkey);
1824 } else if (STRING_EQUAL == strcmp(view_uri, CTSVC_VIEW_URI_GROUP))
1825 len += snprintf(query+len, sizeof(query)-len, " ORDER BY group_prio");
1828 len += snprintf(query+len, sizeof(query)-len, " LIMIT %d", limit);
1830 len += snprintf(query+len, sizeof(query)-len, " OFFSET %d", offset);
1833 ret = ctsvc_query_prepare(query, &stmt);
1834 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
1836 contacts_list_create(&list);
1837 while ((ret = ctsvc_stmt_step(stmt))) {
1838 contacts_record_h record;
1840 /* LCOV_EXCL_START */
1841 ERR("ctsvc_stmt_step() Fail(%d)", ret);
1842 ctsvc_stmt_finalize(stmt);
1843 contacts_list_destroy(list, true);
1845 /* LCOV_EXCL_STOP */
1848 contacts_record_create(view_uri, &record);
1849 for (i = 0; i < ids_count; i++) {
1850 type = (properties[i].property_id & CTSVC_VIEW_DATA_TYPE_MASK);
1851 if (type == CTSVC_VIEW_DATA_TYPE_INT)
1852 ctsvc_record_set_int(record, properties[i].property_id, ctsvc_stmt_get_int(stmt, i));
1853 else if (type == CTSVC_VIEW_DATA_TYPE_STR)
1854 ctsvc_record_set_str(record, properties[i].property_id, ctsvc_stmt_get_text(stmt, i));
1855 else if (type == CTSVC_VIEW_DATA_TYPE_BOOL)
1856 ctsvc_record_set_bool(record, properties[i].property_id, (ctsvc_stmt_get_int(stmt, i) ? true : false));
1857 else if (type == CTSVC_VIEW_DATA_TYPE_LLI)
1858 ctsvc_record_set_lli(record, properties[i].property_id, ctsvc_stmt_get_int64(stmt, i));
1859 else if (type == CTSVC_VIEW_DATA_TYPE_DOUBLE)
1860 ctsvc_record_set_double(record, properties[i].property_id, ctsvc_stmt_get_dbl(stmt, i));
1862 /* LCOV_EXCL_START */
1863 ERR("unknown type (%d)", type);
1864 /* LCOV_EXCL_STOP */
1866 ctsvc_list_prepend(list, record);
1868 ctsvc_stmt_finalize(stmt);
1869 ctsvc_list_reverse(list);
1871 *out_list = (contacts_list_h)list;
1872 return CONTACTS_ERROR_NONE;
1875 static int __ctsvc_db_get_all_records(const char *view_uri, int offset, int limit,
1876 contacts_list_h *out_list)
1882 const property_info_s *p = ctsvc_view_get_all_property_infos(view_uri, &count);
1883 ret = __db_create_projection(view_uri, p, count, NULL, 0, &projection, false);
1884 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "__db_create_projection Fail(%d)", ret);
1886 ret = __ctsvc_db_get_all_records_exec(view_uri, p, count, projection, offset, limit, out_list);
1892 static bool __ctsvc_db_view_can_keyword_search(const char *view_uri, int *out_enum_uri)
1894 RETV_IF(NULL == view_uri, false);
1895 RETV_IF(NULL == out_enum_uri, false);
1899 if (STRING_EQUAL == strcmp(view_uri, CTSVC_VIEW_URI_PERSON))
1900 enum_uri = CTSVC_ENUM_URI_PERSON;
1901 else if (STRING_EQUAL == strcmp(view_uri, CTSVC_VIEW_URI_READ_ONLY_PERSON_CONTACT))
1902 enum_uri = CTSVC_ENUM_URI_READ_ONLY_PERSON_CONTACT;
1903 else if (STRING_EQUAL == strcmp(view_uri, CTSVC_VIEW_URI_READ_ONLY_PERSON_NUMBER))
1904 enum_uri = CTSVC_ENUM_URI_READ_ONLY_PERSON_NUMBER;
1905 else if (STRING_EQUAL == strcmp(view_uri, CTSVC_VIEW_URI_READ_ONLY_PERSON_EMAIL))
1906 enum_uri = CTSVC_ENUM_URI_READ_ONLY_PERSON_EMAIL;
1907 else if (STRING_EQUAL == strcmp(view_uri, CTSVC_VIEW_URI_READ_ONLY_PERSON_GROUP))
1908 enum_uri = CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP;
1909 else if (STRING_EQUAL == strcmp(view_uri, CTSVC_VIEW_URI_READ_ONLY_PERSON_GROUP_ASSIGNED))
1910 enum_uri = CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP_ASSIGNED;
1911 else if (STRING_EQUAL == strcmp(view_uri, CTSVC_VIEW_URI_READ_ONLY_PERSON_GROUP_NOT_ASSIGNED))
1912 enum_uri = CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP_NOT_ASSIGNED;
1914 /* LCOV_EXCL_START */
1915 ERR("Invalid uri[%s]", view_uri);
1916 /* LCOV_EXCL_STOP */
1918 *out_enum_uri = enum_uri;
1920 return (-1 == enum_uri) ? false : true;
1924 * to find contact which has number including keyword
1925 * FTS can only startwiths search
1927 static int __db_append_search_query(const char *keyword, char **query, int *query_size,
1930 bool phonenumber = true;
1935 if (ctsvc_is_phonenumber(keyword) == false || STRING_EQUAL == strcmp(keyword, "+"))
1936 phonenumber = false;
1939 * If the search key is email address format,
1940 * DO NOT search it from NAME
1942 if (strstr(keyword, "@"))
1943 range &= ~CONTACTS_SEARCH_RANGE_NAME;
1945 if (STRING_EQUAL == strcmp(keyword, "+"))
1946 range &= ~CONTACTS_SEARCH_RANGE_NUMBER;
1948 char *half_keyword = NULL;
1949 int keyword_size = 0;
1950 bool use_replaced_keyword = true;
1952 * full width characters -> half width characters
1953 * (apply to only FW ASCII & some symbols)
1955 ret = ctsvc_get_halfwidth_string(keyword, &half_keyword, &keyword_size);
1956 if (CONTACTS_ERROR_NONE != ret) {
1957 /* LCOV_EXCL_START */
1958 ERR("UChar converting error : ctsvc_get_halfwidth_string() Fail");
1959 half_keyword = (char*)keyword;
1960 use_replaced_keyword = false;
1961 /* LCOV_EXCL_STOP */
1964 char *search_keyword = NULL;
1965 search_keyword = __ctsvc_db_make_search_keyword(half_keyword);
1966 if (NULL == search_keyword) {
1967 /* LCOV_EXCL_START */
1968 ERR("__ctsvc_db_make_search_keyword() Fail");
1969 if (use_replaced_keyword)
1971 return CONTACTS_ERROR_OUT_OF_MEMORY;
1972 /* LCOV_EXCL_STOP */
1975 temp_len = SAFE_SNPRINTF(query, query_size, len, "(");
1980 bool need_or = false;
1982 temp_len = SAFE_SNPRINTF(query, query_size, len, "SELECT contact_id "
1983 "FROM "CTS_TABLE_SEARCH_INDEX" WHERE "CTS_TABLE_SEARCH_INDEX" MATCH ");
1987 temp_len = SAFE_SNPRINTF(query, query_size, len, "'");
1991 if (range & CONTACTS_SEARCH_RANGE_NAME) {
1992 temp_len = SAFE_SNPRINTF(query, query_size, len, "name:");
1995 temp_len = SAFE_SNPRINTF(query, query_size, len, search_keyword);
2001 if (range & CONTACTS_SEARCH_RANGE_NUMBER) {
2003 temp_len = SAFE_SNPRINTF(query, query_size, len, " OR ");
2007 temp_len = SAFE_SNPRINTF(query, query_size, len, "number:");
2010 temp_len = SAFE_SNPRINTF(query, query_size, len, search_keyword);
2016 if (range & CONTACTS_SEARCH_RANGE_DATA) {
2018 temp_len = SAFE_SNPRINTF(query, query_size, len, " OR ");
2022 temp_len = SAFE_SNPRINTF(query, query_size, len, "data:");
2025 temp_len = SAFE_SNPRINTF(query, query_size, len, search_keyword);
2030 temp_len = SAFE_SNPRINTF(query, query_size, len, "' ");
2035 if (!(range & CONTACTS_SEARCH_RANGE_NUMBER))
2037 int len_keyword = strlen(half_keyword);
2038 char *clean_number = calloc(len_keyword + 1, sizeof(char));
2039 if(clean_number == NULL) {
2040 ERR("Memory allocation failure ");
2043 int err = ctsvc_clean_number(half_keyword, clean_number, len_keyword + 1, false);
2045 /* LCOV_EXCL_START */
2046 ERR("ctsvc_clean_number() Fail(%d)", err);
2049 /* LCOV_EXCL_STOP */
2052 const char *cc = ctsvc_get_network_cc(false);
2053 temp_len = SAFE_SNPRINTF(query, query_size, len, " UNION SELECT contact_id "
2054 "FROM "CTS_TABLE_PHONE_LOOKUP" WHERE number LIKE '%%");
2058 temp_len = SAFE_SNPRINTF(query, query_size, len, clean_number);
2062 temp_len = SAFE_SNPRINTF(query, query_size, len, "%%' ");
2067 if (cc && cc[0] == '7' && clean_number[0] == '8') { /* Russia */
2068 char normal_num[strlen(clean_number)+1+5]; /* for cc */
2070 ret = ctsvc_normalize_number(clean_number, normal_num, sizeof(normal_num), false);
2075 temp_len = SAFE_SNPRINTF(query, query_size, len, "OR number LIKE '%%");
2079 temp_len = SAFE_SNPRINTF(query, query_size, len, normal_num);
2083 temp_len = SAFE_SNPRINTF(query, query_size, len, "%%' ");
2091 char *normalized_name = NULL;
2092 int lang = CTSVC_LANG_OTHERS;
2093 char *hiragana = NULL;
2094 char *search_hiragana = NULL;
2095 bool need_union = false;
2097 lang = ctsvc_normalize_str(half_keyword, &normalized_name);
2099 char *mod_keyword = NULL;
2100 if (range & CONTACTS_SEARCH_RANGE_NUMBER) {
2102 case CTSVC_LANG_JAPANESE:
2103 ctsvc_convert_japanese_to_hiragana(half_keyword, &hiragana);
2104 search_hiragana = __ctsvc_db_make_search_keyword(hiragana);
2105 mod_keyword = search_hiragana;
2108 mod_keyword = search_keyword;
2112 temp_len = SAFE_SNPRINTF(query, query_size, len, "SELECT contact_id "
2113 "FROM "CTS_TABLE_SEARCH_INDEX" WHERE "CTS_TABLE_SEARCH_INDEX" "
2118 temp_len = SAFE_SNPRINTF(query, query_size, len, mod_keyword);
2122 temp_len = SAFE_SNPRINTF(query, query_size, len, "' ");
2129 if (range & CONTACTS_SEARCH_RANGE_DATA) {
2131 char *tmp_keyword = NULL;
2133 case CTSVC_LANG_JAPANESE:
2134 mod_keyword = search_hiragana;
2137 /* replace '-' -> '_' because FTS does not support search '-' */
2138 tmp_len = strlen(search_keyword);
2139 tmp_keyword = calloc(tmp_len + 1, sizeof(char));
2140 if (NULL == tmp_keyword) {
2141 /* LCOV_EXCL_START */
2142 ERR("calloc() Fail");
2143 mod_keyword = search_keyword;
2145 /* LCOV_EXCL_STOP */
2147 for (i = 0; i < tmp_len; i++)
2148 tmp_keyword[i] = ('-' == search_keyword[i]) ? '_' : search_keyword[i];
2149 tmp_keyword[i] = '\0';
2150 mod_keyword = tmp_keyword;
2154 temp_len = SAFE_SNPRINTF(query, query_size, len, " UNION ");
2158 temp_len = SAFE_SNPRINTF(query, query_size, len, "SELECT contact_id "
2159 "FROM "CTS_TABLE_SEARCH_INDEX" WHERE "CTS_TABLE_SEARCH_INDEX" "
2164 temp_len = SAFE_SNPRINTF(query, query_size, len, mod_keyword);
2168 temp_len = SAFE_SNPRINTF(query, query_size, len, "' ");
2176 if (range & CONTACTS_SEARCH_RANGE_NAME) {
2177 int len_keyword = strlen(half_keyword);
2178 int len_chosung = 0;
2179 char *chosung = NULL;
2180 char *korean_pattern = NULL;
2181 char *search_chosung = NULL;
2182 char *search_normalized = NULL;
2184 case CTSVC_LANG_KOREAN: /* search with chosung */
2186 * If try to find '홍길동' by 'ㄱ동'
2187 * search by 'ㄱㄷ' in search_index table
2189 * search by '*ㄱ*동*' in name_lookup table
2191 chosung = calloc(len_keyword * 5, sizeof(char));
2192 len_chosung = ctsvc_get_chosung(half_keyword, chosung, len_keyword * 5);
2193 mod_keyword = __ctsvc_db_make_search_keyword(0 < len_chosung ? chosung : half_keyword);
2195 case CTSVC_LANG_JAPANESE:
2196 mod_keyword = search_hiragana;
2199 if (CONTACTS_ERROR_NONE <= lang) { /* normalized string search */
2200 search_normalized = __ctsvc_db_make_search_keyword(normalized_name);
2201 mod_keyword = search_normalized;
2202 } else { /* original keyword search */
2203 mod_keyword = search_keyword;
2208 temp_len = SAFE_SNPRINTF(query, query_size, len, " UNION ");
2212 temp_len = SAFE_SNPRINTF(query, query_size, len, "SELECT contact_id "
2213 "FROM "CTS_TABLE_SEARCH_INDEX" WHERE "CTS_TABLE_SEARCH_INDEX" "
2218 temp_len = SAFE_SNPRINTF(query, query_size, len, mod_keyword);
2222 temp_len = SAFE_SNPRINTF(query, query_size, len, "' ");
2227 case CTSVC_LANG_KOREAN:
2228 korean_pattern = calloc(len_keyword *5, sizeof(char));
2229 ctsvc_get_korean_search_pattern(half_keyword, korean_pattern, len_keyword * 5);
2230 temp_len = SAFE_SNPRINTF(query, query_size, len, " INTERSECT SELECT "
2231 "contact_id FROM "CTS_TABLE_NAME_LOOKUP" WHERE name GLOB '*");
2235 temp_len = SAFE_SNPRINTF(query, query_size, len, korean_pattern);
2239 temp_len = SAFE_SNPRINTF(query, query_size, len, "*' ");
2244 free(korean_pattern);
2245 free(search_chosung);
2247 case CTSVC_LANG_JAPANESE:
2250 free(search_normalized);
2255 char temp_str[len_keyword * 2 + 1];
2256 for (i = 0; i < len_keyword; i++) {
2257 if (half_keyword[i] == '\'' || half_keyword[i] == '_' ||
2258 half_keyword[i] == '%' || half_keyword[i] == '\\') {
2259 temp_str[j++] = CTSVC_DB_ESCAPE_CHAR;
2261 temp_str[j++] = half_keyword[i];
2264 temp_len = SAFE_SNPRINTF(query, query_size, len, " UNION SELECT contact_id "
2265 "FROM "CTS_TABLE_NAME_LOOKUP" WHERE name LIKE '");
2269 temp_len = SAFE_SNPRINTF(query, query_size, len, temp_str);
2273 /* CTSVC_DB_ESCAPE_CHAR */
2274 temp_len = SAFE_SNPRINTF(query, query_size, len, "%%' ESCAPE '\\' ");
2279 free(normalized_name);
2281 free(search_hiragana);
2284 temp_len = SAFE_SNPRINTF(query, query_size, len, ") ");
2288 free(search_keyword);
2290 if (use_replaced_keyword)
2296 static int __ctsvc_db_search_records_character_count(const char *keyword)
2299 int str_len = strlen(keyword);
2302 bool after_space = true;
2304 for (i = 0; i < str_len; i += char_len) {
2305 char_len = ctsvc_check_utf8(keyword[i]);
2306 if (char_len == 1 && keyword[i] == ' ') {
2310 if (after_space == true) {
2312 after_space = false;
2318 static int __ctsvc_db_search_records_append_sort(const char *view_uri,
2319 const char *sortkey, const char *keyword, int len, char **query, int *query_size)
2324 if (ctsvc_get_primary_sort() == CTSVC_SORT_KOREAN) {
2325 contacts_name_sorting_order_e order;
2326 const char *field = NULL;
2327 char *tmp_keyword = NULL;
2328 ctsvc_setting_get_name_sorting_order(&order);
2330 if (CONTACTS_NAME_SORTING_ORDER_FIRSTLAST == order)
2331 field = "display_name";
2333 field = "reverse_display_name";
2335 if (ctsvc_has_chosung(keyword)) {
2336 if (__ctsvc_db_search_records_character_count(keyword) == 1) {
2340 int keyword_len = strlen(keyword);
2342 char temp_str[((250*keyword_len) + 30) * SORT_CHECK_LEN + 50];
2343 int temp_str_len = 0;
2345 temp_str_len = snprintf(temp_str + temp_str_len,
2346 sizeof(temp_str) - temp_str_len, " ORDER BY CASE ");
2348 for (j = 1; j <= SORT_CHECK_LEN; j++) {
2349 temp_str_len += snprintf(temp_str + temp_str_len,
2350 sizeof(temp_str) - temp_str_len, " WHEN ");
2351 for (i = 0, m = 0; i < keyword_len; i += char_len, m++) {
2352 char temp[10] = {0};
2354 char_len = ctsvc_check_utf8(keyword[i]);
2355 if (char_len <= 0) {
2359 memcpy(temp, &keyword[i], char_len);
2360 temp[char_len] = '\0';
2362 if (char_len == 1 && temp[0] == ' ')
2364 if (first == false && i != 0) {
2365 temp_str_len += snprintf(temp_str + temp_str_len,
2366 sizeof(temp_str)-temp_str_len, " AND ");
2368 if (ctsvc_is_chosung(temp)) {
2369 for (k = 0; k < 19; k++) {
2370 if (STRING_EQUAL == strcmp(hangul_syllable[k][0], temp))
2375 if (0 <= k && k <= 18) {
2376 temp_str_len += snprintf(temp_str+temp_str_len,
2377 sizeof(temp_str)-temp_str_len,
2378 " ((substr(%s, %d, 1) BETWEEN '%s' AND '%s') OR (substr(%s, %d, 1) = '%s')) ",
2381 hangul_syllable[k][1],
2382 hangul_syllable[k][2],
2387 temp_str_len += snprintf(temp_str+temp_str_len,
2388 sizeof(temp_str)-temp_str_len,
2389 " (substr(%s, %d, 1) = '%s') ",
2397 temp_str_len += snprintf(temp_str + temp_str_len,
2398 sizeof(temp_str) - temp_str_len, " THEN %d ", j);
2400 temp_str_len = snprintf(temp_str + temp_str_len,
2401 sizeof(temp_str) - temp_str_len, " ELSE %d END ", j);
2403 temp_len = SAFE_SNPRINTF(query, query_size, len, temp_str);
2407 temp_len = SAFE_SNPRINTF(query, query_size, len, " ORDER BY ");
2408 if (0 <= temp_len) len += temp_len;
2409 temp_len = SAFE_SNPRINTF(query, query_size, len, sortkey);
2410 if (0 <= temp_len) len += temp_len;
2413 tmp_keyword = __db_get_str_with_escape((char*)keyword, strlen(keyword), true);
2414 if (NULL == tmp_keyword) {
2415 /* LCOV_EXCL_START */
2416 ERR("__db_get_str_with_escape() Fail");
2417 /* LCOV_EXCL_STOP */
2418 return CONTACTS_ERROR_OUT_OF_MEMORY;
2421 char temp_str[CTS_SQL_MIN_LEN + (strlen(field) + strlen(tmp_keyword)) * SORT_CHECK_LEN];
2422 snprintf(temp_str, sizeof(temp_str),
2425 " WHEN %s LIKE '%s%%' THEN 1 "
2426 " WHEN %s LIKE '_%s%%' THEN 2 "
2427 " WHEN %s LIKE '__%s%%' THEN 3 "
2428 " WHEN %s LIKE '___%s%%' THEN 4 "
2429 " WHEN %s LIKE '____%s%%' THEN 5 "
2430 " WHEN %s LIKE '_____%s%%' THEN 6 "
2431 " WHEN %s LIKE '______%s%%' THEN 7 "
2434 field, tmp_keyword, field, tmp_keyword,
2435 field, tmp_keyword, field, tmp_keyword,
2436 field, tmp_keyword, field, tmp_keyword,
2437 field, tmp_keyword);
2438 temp_len = SAFE_SNPRINTF(query, query_size, len, temp_str);
2439 if (0 <= temp_len) len += temp_len;
2442 temp_len = SAFE_SNPRINTF(query, query_size, len, ", ");
2443 if (0 <= temp_len) len += temp_len;
2444 temp_len = SAFE_SNPRINTF(query, query_size, len, sortkey);
2445 if (0 <= temp_len) len += temp_len;
2447 temp_len = SAFE_SNPRINTF(query, query_size, len, " ORDER BY ");
2448 if (0 <= temp_len) len += temp_len;
2449 temp_len = SAFE_SNPRINTF(query, query_size, len, sortkey);
2450 if (0 <= temp_len) len += temp_len;
2455 static int __ctsvc_db_search_records_exec(const char *view_uri,
2457 const property_info_s *properties,
2459 const char *projection,
2460 const char *keyword,
2465 const char *start_match,
2466 const char *end_match,
2468 contacts_list_h *out_list)
2471 char temp_query[CTS_SQL_MAX_LEN];
2479 cts_stmt stmt = NULL;
2480 contacts_list_h list = NULL;
2481 ctsvc_record_type_e r_type;
2482 const char *sortkey = NULL;
2484 ret = ctsvc_db_get_table_name(view_uri, &table);
2485 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "Invalid view uri (%s)", view_uri);
2487 query_size = CTS_SQL_MAX_LEN;
2488 query = calloc(1, query_size);
2489 if (NULL == query) {
2490 /* LCOV_EXCL_START */
2491 ERR("calloc() Fail");
2492 return CONTACTS_ERROR_OUT_OF_MEMORY;
2493 /* LCOV_EXCL_STOP */
2498 if (STRING_EQUAL == strcmp(keyword, "+"))
2499 range &= ~CONTACTS_SEARCH_RANGE_NUMBER;
2502 /* LCOV_EXCL_START */
2504 contacts_list_create(&list);
2507 return CONTACTS_ERROR_NONE;
2508 /* LCOV_EXCL_STOP */
2512 case CTSVC_ENUM_URI_READ_ONLY_PERSON_CONTACT:
2513 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP:
2514 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP_ASSIGNED:
2515 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP_NOT_ASSIGNED:
2517 if (range & CONTACTS_SEARCH_RANGE_EMAIL) {
2519 return CONTACTS_ERROR_INVALID_PARAMETER;
2522 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "SELECT ");
2525 temp_len = SAFE_SNPRINTF(&query, &query_size, len, projection);
2528 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " FROM ");
2531 temp_len = SAFE_SNPRINTF(&query, &query_size, len, table);
2534 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " as temp_contacts");
2539 case CTSVC_ENUM_URI_READ_ONLY_PERSON_NUMBER:
2541 bool need_or = false;
2542 if (range & CONTACTS_SEARCH_RANGE_DATA || range & CONTACTS_SEARCH_RANGE_EMAIL) {
2543 /* LCOV_EXCL_START */
2544 ERR("Invalid range");
2546 return CONTACTS_ERROR_INVALID_PARAMETER;
2547 /* LCOV_EXCL_STOP */
2549 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "SELECT ");
2550 if (0 <= temp_len) len += temp_len;
2551 temp_len = SAFE_SNPRINTF(&query, &query_size, len, projection);
2552 if (0 <= temp_len) len += temp_len;
2553 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " FROM (SELECT * FROM ");
2554 if (0 <= temp_len) len += temp_len;
2555 temp_len = SAFE_SNPRINTF(&query, &query_size, len, table);
2556 if (0 <= temp_len) len += temp_len;
2558 if ((range & CONTACTS_SEARCH_RANGE_NUMBER) && ctsvc_is_phonenumber(keyword)) {
2559 char clean_num[strlen(keyword)+1+5]; /* for cc */
2562 * Original number can include '-' or special character. So search by cleaned_number
2563 * If contact has 010 1234 5678 (normalized number is +cc 10 1234 5678),
2564 * then the contact should be searched by keyword +cc 10 1234 5678
2566 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " WHERE ");
2570 ret = ctsvc_clean_number(keyword, clean_num, sizeof(clean_num), false);
2572 const char *cc = ctsvc_get_network_cc(false);
2574 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "(normalized_number LIKE '%%");
2578 if (cc && cc[0] == '7' && clean_num[0] == '8') { /* Russia */
2579 char normal_num[strlen(clean_num)+1+5]; /* for cc */
2580 ret = ctsvc_normalize_number(clean_num, normal_num,
2581 sizeof(normal_num), false);
2583 temp_len = SAFE_SNPRINTF(&query, &query_size, len, normal_num);
2585 temp_len = SAFE_SNPRINTF(&query, &query_size, len, clean_num);
2587 temp_len = SAFE_SNPRINTF(&query, &query_size, len, clean_num);
2592 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "%%' OR cleaned_number LIKE '%%");
2596 temp_len = SAFE_SNPRINTF(&query, &query_size, len, clean_num);
2600 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "%%')");
2604 char *temp_keyword = __db_get_str_with_escape((char*)keyword,
2605 strlen(keyword), true);
2606 if (NULL == temp_keyword) {
2607 /* LCOV_EXCL_START */
2608 ERR("__db_get_str_with_escape() Fail");
2610 return CONTACTS_ERROR_OUT_OF_MEMORY;
2611 /* LCOV_EXCL_STOP */
2614 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "(SELECT * FROM ");
2618 temp_len = SAFE_SNPRINTF(&query, &query_size, len, table);
2622 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " WHERE number LIKE '%%");
2626 temp_len = SAFE_SNPRINTF(&query, &query_size, len, temp_keyword);
2630 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "%%' ESCAPE '\\')");
2638 if (range & CONTACTS_SEARCH_RANGE_NAME) {
2640 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " OR ");
2642 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " WHERE ");
2647 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "person_id IN (SELECT "
2648 "person_id FROM "CTS_TABLE_CONTACTS" WHERE deleted = 0 AND contact_id IN");
2653 * search contact from search_index table by name and join the results
2654 * FTS can support to serach with multiple words
2655 * If contact display_name is 'abc def', then the contact should be searched by 'def'
2657 temp_len = __db_append_search_query(keyword, &query, &query_size, len,
2658 CONTACTS_SEARCH_RANGE_NAME);
2662 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ") ");
2667 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ") as temp_contacts");
2673 case CTSVC_ENUM_URI_READ_ONLY_PERSON_EMAIL:
2675 bool need_or = false;
2676 if (range & CONTACTS_SEARCH_RANGE_NUMBER || range & CONTACTS_SEARCH_RANGE_DATA) {
2678 return CONTACTS_ERROR_INVALID_PARAMETER;
2681 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "SELECT ");
2685 temp_len = SAFE_SNPRINTF(&query, &query_size, len, projection);
2689 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " FROM (");
2693 if (range & CONTACTS_SEARCH_RANGE_EMAIL) {
2694 /* search contact which has email address started with keyword */
2695 char *temp_keyword = __db_get_str_with_escape((char*)keyword,
2696 strlen(keyword), true);
2697 if (NULL == temp_keyword) {
2698 /* LCOV_EXCL_START */
2699 ERR("__db_get_str_with_escape() Fail");
2701 return CONTACTS_ERROR_OUT_OF_MEMORY;
2702 /* LCOV_EXCL_STOP */
2704 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "SELECT * FROM ");
2708 temp_len = SAFE_SNPRINTF(&query, &query_size, len, table);
2712 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " WHERE (email LIKE '");
2716 temp_len = SAFE_SNPRINTF(&query, &query_size, len, temp_keyword);
2720 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "%%' ESCAPE '\\')");
2727 if (range & CONTACTS_SEARCH_RANGE_NAME) {
2729 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " OR ");
2734 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "SELECT * FROM ");
2737 temp_len = SAFE_SNPRINTF(&query, &query_size, len, table);
2740 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " WHERE ");
2745 snprintf(temp_query, sizeof(temp_query), "person_id IN (SELECT person_id "
2746 "FROM "CTS_TABLE_CONTACTS" WHERE deleted = 0 AND contact_id ");
2747 temp_len = SAFE_SNPRINTF(&query, &query_size, len, temp_query);
2750 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " IN ");
2753 temp_len = __db_append_search_query(keyword, &query, &query_size, len,
2754 CONTACTS_SEARCH_RANGE_NAME);
2757 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ") ");
2762 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ") ");
2768 case CTSVC_ENUM_URI_PERSON:
2769 if (range & CONTACTS_SEARCH_RANGE_EMAIL) {
2771 return CONTACTS_ERROR_INVALID_PARAMETER;
2773 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "SELECT ");
2777 temp_len = SAFE_SNPRINTF(&query, &query_size, len, projection);
2781 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " FROM ");
2785 temp_len = SAFE_SNPRINTF(&query, &query_size, len, table);
2790 if (true == is_snippet) {
2791 bool need_union = false;
2792 char cond_data[CTS_SQL_MAX_LEN] = {0};
2793 char clean_number[SAFE_STRLEN(keyword) + 1];
2794 ctsvc_clean_number(keyword, clean_number, sizeof(clean_number), false);
2795 temp_len = SAFE_SNPRINTF(&query, &query_size, len,
2796 ", (SELECT contact_id temp_contact_id, "
2797 "datatype, _priority, _data FROM (");
2801 if (range & CONTACTS_SEARCH_RANGE_NAME) {
2802 snprintf(cond_data, sizeof(cond_data), "SELECT contact_id, "
2803 "datatype, %d as _priority, 'a' as _data FROM "CTS_TABLE_DATA" "
2804 "WHERE contact_id IN (", CTSVC_SNIPPET_PRIO_NAME);
2805 temp_len = SAFE_SNPRINTF(&query, &query_size, len, cond_data);
2809 char *query_name = _get_search_query_for_name(keyword);
2810 temp_len = SAFE_SNPRINTF(&query, &query_size, len, query_name);
2815 /* datatype=1 NAME */
2816 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ") AND datatype=1 AND is_my_profile=0 ");
2822 if (range & CONTACTS_SEARCH_RANGE_NUMBER) {
2823 if (true == need_union) {
2824 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " UNION ");
2828 snprintf(cond_data, sizeof(cond_data), "SELECT contact_id, "
2829 "datatype, %d as _priority, data3 as _data FROM "CTS_TABLE_DATA" "
2830 "WHERE contact_id IN (", CTSVC_SNIPPET_PRIO_NUMBER);
2831 temp_len = SAFE_SNPRINTF(&query, &query_size, len, cond_data);
2835 char *query_number = _get_search_query_for_number(keyword);
2836 temp_len = SAFE_SNPRINTF(&query, &query_size, len, query_number);
2841 /* datatype=8 NUMBER */
2842 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ") AND datatype=8 AND is_my_profile=0 ");
2848 if (range & CONTACTS_SEARCH_RANGE_DATA) {
2849 if (true == need_union) {
2850 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " UNION ");
2854 snprintf(cond_data, sizeof(cond_data), "SELECT contact_id, datatype, "
2856 "WHEN datatype=%d THEN %d " /* POSTAL */
2857 "WHEN datatype=%d THEN %d " /* COMPANY */
2858 "WHEN datatype=%d THEN %d " /* NICKNAME */
2859 "WHEN datatype=%d THEN %d " /* EMAIL */
2860 "WHEN datatype=%d THEN %d " /* NOTE */
2861 "END) as _priority, "
2863 "WHEN datatype=%d THEN (COALESCE(data5||' ','')||"
2864 "COALESCE(data6||' ','')||COALESCE(data7||' ','')||"
2865 "COALESCE(data8||' ','')||COALESCE(data9,'')) " /* POSTAL */
2866 "WHEN datatype=%d THEN (COALESCE(data3||' ','')||"
2867 "COALESCE(data4||' ','')||COALESCE(data5||' ','')||"
2868 "COALESCE(data6||' ','')||COALESCE(data7||' ','')||"
2869 "COALESCE(data8||' ','')||COALESCE(data9||' ','')||"
2870 "COALESCE(data10||' ','')||COALESCE(data11||' ','')) " /* COMPANY */
2871 "WHEN datatype=%d THEN data3 " /* NICKNAME */
2872 "WHEN datatype=%d THEN data3 " /* EMAIL */
2873 "WHEN datatype=%d THEN data3 " /* NOTE */
2874 "END) as _data FROM "CTS_TABLE_DATA" WHERE is_my_profile=0 AND contact_id IN (",
2875 CONTACTS_DATA_TYPE_POSTAL, CTSVC_SNIPPET_PRIO_POSTAL,
2876 CONTACTS_DATA_TYPE_COMPANY, CTSVC_SNIPPET_PRIO_COMPANY,
2877 CONTACTS_DATA_TYPE_NICKNAME, CTSVC_SNIPPET_PRIO_NICKNAME,
2878 CONTACTS_DATA_TYPE_EMAIL, CTSVC_SNIPPET_PRIO_EMAIL,
2879 CONTACTS_DATA_TYPE_NOTE, CTSVC_SNIPPET_PRIO_NOTE,
2880 CONTACTS_DATA_TYPE_POSTAL,
2881 CONTACTS_DATA_TYPE_COMPANY,
2882 CONTACTS_DATA_TYPE_NICKNAME,
2883 CONTACTS_DATA_TYPE_EMAIL,
2884 CONTACTS_DATA_TYPE_NOTE);
2885 temp_len = SAFE_SNPRINTF(&query, &query_size, len, cond_data);
2889 char *query_data = _get_search_query_for_data(keyword);
2890 temp_len = SAFE_SNPRINTF(&query, &query_size, len, query_data);
2895 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ") AND _data IS NOT NULL "
2896 "AND _data LIKE ('%%' || '");
2899 temp_len = SAFE_SNPRINTF(&query, &query_size, len, keyword);
2902 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "' || '%%') ");
2906 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ")) as temp_data ON "
2907 "temp_data.temp_contact_id = temp_contacts.contact_id ");
2913 case CTSVC_ENUM_URI_READ_ONLY_PERSON_CONTACT:
2914 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP:
2915 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP_ASSIGNED:
2916 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP_NOT_ASSIGNED:
2917 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " WHERE temp_contacts.contact_id IN ");
2920 temp_len = __db_append_search_query(keyword, &query, &query_size, len, range);
2925 case CTSVC_ENUM_URI_READ_ONLY_PERSON_NUMBER:
2927 case CTSVC_ENUM_URI_READ_ONLY_PERSON_EMAIL:
2929 case CTSVC_ENUM_URI_PERSON:
2930 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ", (SELECT contact_id, person_id "
2931 "person_id_in_contact, addressbook_id FROM "CTS_TABLE_CONTACTS" "
2932 "WHERE deleted = 0 AND contact_id IN ");
2936 temp_len = __db_append_search_query(keyword, &query, &query_size, len, range);
2940 temp_len = SAFE_SNPRINTF(&query, &query_size, len,
2941 "GROUP BY person_id_in_contact) temp_contacts ON ");
2945 temp_len = SAFE_SNPRINTF(&query, &query_size, len, table);
2949 temp_len = SAFE_SNPRINTF(&query, &query_size, len,
2950 ".person_id = temp_contacts.person_id_in_contact");
2956 if (__ctsvc_db_view_has_display_name(view_uri, properties, ids_count))
2957 sortkey = ctsvc_get_sort_column();
2959 if (true == is_snippet) {
2961 case CTSVC_ENUM_URI_READ_ONLY_PERSON_CONTACT:
2962 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP:
2963 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP_ASSIGNED:
2964 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP_NOT_ASSIGNED:
2965 case CTSVC_ENUM_URI_READ_ONLY_PERSON_NUMBER:
2966 case CTSVC_ENUM_URI_READ_ONLY_PERSON_EMAIL:
2967 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " GROUP BY temp_data.temp_contact_id");
2969 case CTSVC_ENUM_URI_PERSON:
2970 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " GROUP BY person_id");
2978 len = __ctsvc_db_search_records_append_sort(view_uri, sortkey, keyword, len,
2979 &query, &query_size);
2980 } else if (STRING_EQUAL == strcmp(view_uri, CTSVC_VIEW_URI_GROUP)) {
2981 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " ORDER BY group_prio");
2982 if (0 <= temp_len) len += temp_len;
2989 snprintf(temp_query, sizeof(temp_query), " LIMIT %d", limit);
2990 temp_len = SAFE_SNPRINTF(&query, &query_size, len, temp_query);
2997 snprintf(temp_query, sizeof(temp_query), " OFFSET %d", offset);
2998 temp_len = SAFE_SNPRINTF(&query, &query_size, len, temp_query);
3003 ret = ctsvc_query_prepare(query, &stmt);
3005 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
3007 r_type = ctsvc_view_get_record_type(view_uri);
3009 contacts_list_create(&list);
3010 while ((ret = ctsvc_stmt_step(stmt))) {
3011 contacts_record_h record;
3013 /* LCOV_EXCL_START */
3014 ERR("ctsvc_stmt_step() Fail(%d)", ret);
3015 ctsvc_stmt_finalize(stmt);
3016 contacts_list_destroy(list, true);
3018 /* LCOV_EXCL_STOP */
3021 if (r_type == CTSVC_RECORD_PERSON) {
3022 unsigned int *project = malloc(sizeof(unsigned int)*ids_count);
3023 for (i = 0; i < ids_count; i++)
3024 project[i] = properties[i].property_id;
3026 int ret = ctsvc_db_person_create_record_from_stmt_with_projection(stmt, project,
3027 ids_count, is_snippet, keyword, start_match, end_match, token_number, &record);
3031 if (CONTACTS_ERROR_NONE != ret)
3032 /* LCOV_EXCL_START */
3033 ERR("make record Fail(%d)", ret);
3034 /* LCOV_EXCL_STOP */
3036 contacts_record_create(view_uri, &record);
3038 for (i = 0; i < ids_count; i++) {
3039 type = (properties[i].property_id & CTSVC_VIEW_DATA_TYPE_MASK);
3042 case CTSVC_VIEW_DATA_TYPE_INT:
3043 ctsvc_record_set_int(record, properties[i].property_id,
3044 ctsvc_stmt_get_int(stmt, i));
3046 case CTSVC_VIEW_DATA_TYPE_STR:
3047 temp = ctsvc_stmt_get_text(stmt, i);
3048 if (CTSVC_PROPERTY_PERSON_SNIPPET_STRING == properties[i].property_id) {
3049 temp = ctsvc_utils_get_modified_str(temp, is_snippet, keyword,
3050 start_match, end_match, token_number);
3052 ctsvc_record_set_str(record, properties[i].property_id, temp);
3054 case CTSVC_VIEW_DATA_TYPE_BOOL:
3055 ctsvc_record_set_bool(record, properties[i].property_id,
3056 (ctsvc_stmt_get_int(stmt, i) ? true : false));
3058 case CTSVC_VIEW_DATA_TYPE_LLI:
3059 ctsvc_record_set_lli(record, properties[i].property_id,
3060 ctsvc_stmt_get_int64(stmt, i));
3062 case CTSVC_VIEW_DATA_TYPE_DOUBLE:
3063 ctsvc_record_set_double(record, properties[i].property_id,
3064 ctsvc_stmt_get_dbl(stmt, i));
3067 /* LCOV_EXCL_START */
3068 ERR("unknown type (%d)", type);
3070 /* LCOV_EXCL_STOP */
3075 ctsvc_list_prepend(list, record);
3078 ctsvc_stmt_finalize(stmt);
3079 ctsvc_list_reverse(list);
3081 return CONTACTS_ERROR_NONE;
3084 static int __ctsvc_db_search_records(const char *view_uri,
3085 const char *keyword,
3089 const char *start_match,
3090 const char *end_match,
3092 contacts_list_h *out_list)
3097 const property_info_s *p;
3098 bool can_keyword_search = false;
3100 int range = CONTACTS_SEARCH_RANGE_NAME | CONTACTS_SEARCH_RANGE_NUMBER | CONTACTS_SEARCH_RANGE_DATA;
3102 RETV_IF(NULL == keyword, CONTACTS_ERROR_INVALID_PARAMETER);
3104 can_keyword_search = __ctsvc_db_view_can_keyword_search(view_uri, &enum_uri);
3105 RETVM_IF(false == can_keyword_search, CONTACTS_ERROR_INVALID_PARAMETER,
3106 "can not keyword search");
3108 p = ctsvc_view_get_all_property_infos(view_uri, &count);
3109 ret = __db_create_projection(view_uri, p, count, NULL, 0, &projection, is_snippet);
3110 if (CONTACTS_ERROR_NONE != ret) {
3111 /* LCOV_EXCL_START */
3112 ERR("__db_create_projection() Fail(%d)", ret);
3114 /* LCOV_EXCL_STOP */
3117 ret = __ctsvc_db_search_records_exec(view_uri, enum_uri, p, count, projection,
3118 keyword, offset, limit, range, is_snippet, start_match, end_match, token_number, out_list);
3124 static int __ctsvc_db_search_records_with_range(const char *view_uri,
3125 const char *keyword,
3130 const char *start_match,
3131 const char *end_match,
3133 contacts_list_h *out_list)
3138 const property_info_s *p;
3139 bool can_keyword_search = false;
3142 RETV_IF(NULL == keyword, CONTACTS_ERROR_INVALID_PARAMETER);
3144 can_keyword_search = __ctsvc_db_view_can_keyword_search(view_uri, &eunm_uri);
3145 RETV_IF(false == can_keyword_search, CONTACTS_ERROR_INVALID_PARAMETER);
3147 p = ctsvc_view_get_all_property_infos(view_uri, &count);
3148 ret = __db_create_projection(view_uri, p, count, NULL, 0, &projection, is_snippet);
3149 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "__db_create_projection() Fail(%d)", ret);
3151 ret = __ctsvc_db_search_records_exec(view_uri, eunm_uri, p, count, projection,
3152 keyword, offset, limit, range, is_snippet, start_match, end_match, token_number, out_list);
3158 static inline int __ctsvc_db_search_records_with_query_exec(ctsvc_query_s *s_query,
3160 const char *projection,
3161 const char *condition,
3163 const char *keyword,
3167 const char *start_match,
3168 const char *end_match,
3170 contacts_list_h *out_list)
3179 bool person_contact_query = false;
3181 cts_stmt stmt = NULL;
3182 contacts_list_h list = NULL;
3184 const char *sortkey = NULL;
3185 int range = CONTACTS_SEARCH_RANGE_NAME | CONTACTS_SEARCH_RANGE_NUMBER | CONTACTS_SEARCH_RANGE_DATA;
3187 RETV_IF(NULL == projection || '\0' == *projection, CONTACTS_ERROR_INVALID_PARAMETER);
3189 ret = ctsvc_db_get_table_name(s_query->view_uri, &table);
3190 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "Invalid view uri(%s)", s_query->view_uri);
3192 query_size = CTS_SQL_MAX_LEN;
3193 query = calloc(1, query_size);
3194 if (NULL == query) {
3195 /* LCOV_EXCL_START */
3196 ERR("calloc() Fail");
3197 return CONTACTS_ERROR_OUT_OF_MEMORY;
3198 /* LCOV_EXCL_STOP */
3203 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "SELECT ");
3207 if (s_query->distinct) {
3208 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "DISTINCT ");
3212 temp_len = SAFE_SNPRINTF(&query, &query_size, len, projection);
3215 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " FROM ");
3218 temp_len = SAFE_SNPRINTF(&query, &query_size, len, table);
3223 case CTSVC_ENUM_URI_READ_ONLY_PERSON_CONTACT:
3224 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP:
3225 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP_ASSIGNED:
3226 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP_NOT_ASSIGNED:
3227 case CTSVC_ENUM_URI_PERSON:
3230 case CTSVC_ENUM_URI_READ_ONLY_PERSON_NUMBER:
3231 case CTSVC_ENUM_URI_READ_ONLY_PERSON_EMAIL:
3234 return CONTACTS_ERROR_INVALID_PARAMETER;
3237 if (true == is_snippet) {
3238 bool need_union = false;
3239 char cond_data[CTS_SQL_MAX_LEN] = {0};
3240 char clean_number[SAFE_STRLEN(keyword) + 1];
3241 ctsvc_clean_number(keyword, clean_number, sizeof(clean_number), false);
3242 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ", (SELECT contact_id temp_contact_id, "
3243 "datatype, _priority, _data FROM (");
3247 if (range & CONTACTS_SEARCH_RANGE_NAME) {
3248 snprintf(cond_data, sizeof(cond_data), "SELECT contact_id, "
3249 "datatype, %d as _priority, 'a' as _data FROM "CTS_TABLE_DATA" "
3250 "WHERE contact_id IN (", CTSVC_SNIPPET_PRIO_NAME);
3251 temp_len = SAFE_SNPRINTF(&query, &query_size, len, cond_data);
3255 char *query_name = _get_search_query_for_name(keyword);
3256 temp_len = SAFE_SNPRINTF(&query, &query_size, len, query_name);
3261 /* datatype=1 NAME */
3262 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ") AND datatype=1 ");
3268 if (range & CONTACTS_SEARCH_RANGE_NUMBER) {
3269 if (true == need_union) {
3270 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " UNION ");
3274 snprintf(cond_data, sizeof(cond_data), "SELECT contact_id, "
3275 "datatype, %d as _priority, data3 as _data FROM "CTS_TABLE_DATA" "
3276 "WHERE contact_id IN (", CTSVC_SNIPPET_PRIO_NUMBER);
3277 temp_len = SAFE_SNPRINTF(&query, &query_size, len, cond_data);
3281 char *query_number = _get_search_query_for_number(keyword);
3282 temp_len = SAFE_SNPRINTF(&query, &query_size, len, query_number);
3287 /* datatype=8 NUMBER */
3288 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ") AND datatype=8 ");
3294 if (range & CONTACTS_SEARCH_RANGE_DATA) {
3295 if (true == need_union) {
3296 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " UNION ");
3300 snprintf(cond_data, sizeof(cond_data), "SELECT contact_id, datatype, "
3302 "WHEN datatype=%d THEN %d " /* POSTAL */
3303 "WHEN datatype=%d THEN %d " /* COMPANY */
3304 "WHEN datatype=%d THEN %d " /* NICKNAME */
3305 "WHEN datatype=%d THEN %d " /* EMAIL */
3306 "WHEN datatype=%d THEN %d " /* NOTE */
3307 "END) as _priority, "
3309 "WHEN datatype=%d THEN (COALESCE(data5||' ','')||"
3310 "COALESCE(data6||' ','')||COALESCE(data7||' ','')||"
3311 "COALESCE(data8||' ','')||COALESCE(data9,'')) " /* POSTAL */
3312 "WHEN datatype=%d THEN (COALESCE(data3||' ','')||"
3313 "COALESCE(data4||' ','')||COALESCE(data5||' ','')||"
3314 "COALESCE(data6||' ','')||COALESCE(data7||' ','')||"
3315 "COALESCE(data8||' ','')||COALESCE(data9||' ','')||"
3316 "COALESCE(data10||' ','')||COALESCE(data11||' ','')) " /* COMPANY */
3317 "WHEN datatype=%d THEN data3 " /* NICKNAME */
3318 "WHEN datatype=%d THEN data3 " /* EMAIL */
3319 "WHEN datatype=%d THEN data3 " /* NOTE */
3320 "END) as _data FROM "CTS_TABLE_DATA" WHERE contact_id IN (",
3321 CONTACTS_DATA_TYPE_POSTAL, CTSVC_SNIPPET_PRIO_POSTAL,
3322 CONTACTS_DATA_TYPE_COMPANY, CTSVC_SNIPPET_PRIO_COMPANY,
3323 CONTACTS_DATA_TYPE_NICKNAME, CTSVC_SNIPPET_PRIO_NICKNAME,
3324 CONTACTS_DATA_TYPE_EMAIL, CTSVC_SNIPPET_PRIO_EMAIL,
3325 CONTACTS_DATA_TYPE_NOTE, CTSVC_SNIPPET_PRIO_NOTE,
3326 CONTACTS_DATA_TYPE_POSTAL,
3327 CONTACTS_DATA_TYPE_COMPANY,
3328 CONTACTS_DATA_TYPE_NICKNAME,
3329 CONTACTS_DATA_TYPE_EMAIL,
3330 CONTACTS_DATA_TYPE_NOTE);
3331 temp_len = SAFE_SNPRINTF(&query, &query_size, len, cond_data);
3335 char *query_data = _get_search_query_for_data(keyword);
3336 temp_len = SAFE_SNPRINTF(&query, &query_size, len, query_data);
3341 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ") AND _data IS NOT NULL "
3342 "AND _data LIKE ('%%' || '");
3345 temp_len = SAFE_SNPRINTF(&query, &query_size, len, keyword);
3348 temp_len = SAFE_SNPRINTF(&query, &query_size, len, "' || '%%') ");
3352 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ")) as temp_data ON "
3353 "temp_data.temp_contact_id = contact_id ");
3359 case CTSVC_ENUM_URI_READ_ONLY_PERSON_CONTACT:
3360 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP:
3361 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP_ASSIGNED:
3362 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP_NOT_ASSIGNED:
3363 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " WHERE person_id IN (SELECT "
3364 "person_id FROM "CTS_TABLE_CONTACTS" WHERE deleted = 0 AND contact_id IN ");
3368 person_contact_query = true;
3371 case CTSVC_ENUM_URI_PERSON:
3372 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ", (SELECT contact_id, "
3373 "person_id person_id_in_contact, addressbook_id FROM "CTS_TABLE_CONTACTS" "
3374 "WHERE deleted = 0) temp_contacts ON ");
3378 temp_len = SAFE_SNPRINTF(&query, &query_size, len, table);
3382 temp_len = SAFE_SNPRINTF(&query, &query_size, len,
3383 ".person_id = temp_contacts.person_id_in_contact WHERE temp_contacts.contact_id IN ");
3388 case CTSVC_ENUM_URI_READ_ONLY_PERSON_NUMBER:
3389 case CTSVC_ENUM_URI_READ_ONLY_PERSON_EMAIL:
3391 return CONTACTS_ERROR_INVALID_PARAMETER;
3394 temp_len = __db_append_search_query(keyword, &query, &query_size, len, range);
3398 if (person_contact_query) {
3399 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ") ");
3404 if (condition && *condition) {
3405 if (person_contact_query) {
3406 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " AND contact_id IN "
3407 "(SELECT contact_id FROM ");
3410 temp_len = SAFE_SNPRINTF(&query, &query_size, len, table);
3413 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " WHERE ");
3417 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " AND (");
3421 temp_len = SAFE_SNPRINTF(&query, &query_size, len, condition);
3424 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ")");
3429 if (true == is_snippet) {
3431 case CTSVC_ENUM_URI_READ_ONLY_PERSON_CONTACT:
3432 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP:
3433 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP_ASSIGNED:
3434 case CTSVC_ENUM_URI_READ_ONLY_PERSON_GROUP_NOT_ASSIGNED:
3435 case CTSVC_ENUM_URI_READ_ONLY_PERSON_NUMBER:
3436 case CTSVC_ENUM_URI_READ_ONLY_PERSON_EMAIL:
3437 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " GROUP BY temp_data.temp_contact_id");
3439 case CTSVC_ENUM_URI_PERSON:
3440 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " GROUP BY person_id");
3447 if (__ctsvc_db_view_has_display_name(s_query->view_uri, s_query->properties, s_query->property_count))
3448 sortkey = ctsvc_get_sort_column();
3450 if (s_query->sort_property_id) {
3451 const char *field_name;
3453 switch (s_query->sort_property_id) {
3454 case CTSVC_PROPERTY_PERSON_DISPLAY_NAME:
3455 case CTSVC_PROPERTY_CONTACT_DISPLAY_NAME:
3457 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " ORDER BY ");
3460 temp_len = SAFE_SNPRINTF(&query, &query_size, len, sortkey);
3463 if (false == s_query->sort_asc) {
3464 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " DESC ");
3471 field_name = __ctsvc_db_get_property_field_name(s_query->properties,
3472 s_query->property_count, QUERY_SORTKEY, s_query->sort_property_id);
3474 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " ORDER BY ");
3477 temp_len = SAFE_SNPRINTF(&query, &query_size, len, field_name);
3480 if (false == s_query->sort_asc) {
3481 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " DESC ");
3485 } else if (sortkey) {
3486 len += snprintf(query+len, sizeof(query)-len, " ORDER BY %s", sortkey);
3487 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " ORDER BY ");
3490 temp_len = SAFE_SNPRINTF(&query, &query_size, len, sortkey);
3496 } else if (sortkey) {
3497 len = __ctsvc_db_search_records_append_sort(s_query->view_uri, sortkey, keyword,
3498 len, &query, &query_size);
3499 } else if (STRING_EQUAL == strcmp(s_query->view_uri, CTSVC_VIEW_URI_GROUP)) {
3500 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " ORDER BY group_prio");
3509 char temp_str[20] = {0};
3510 snprintf(temp_str, sizeof(temp_str), " LIMIT %d", limit);
3511 temp_len = SAFE_SNPRINTF(&query, &query_size, len, temp_str);
3518 snprintf(temp_str, sizeof(temp_str), " OFFSET %d", offset);
3519 temp_len = SAFE_SNPRINTF(&query, &query_size, len, temp_str);
3524 ret = ctsvc_query_prepare(query, &stmt);
3526 /* LCOV_EXCL_START */
3527 ERR("ctsvc_query_prepare() Fail(%d)[%s]", ret, query);
3530 /* LCOV_EXCL_STOP */
3535 len = g_slist_length(bind);
3536 for (cursor = bind; cursor; cursor = cursor->next, i++)
3537 ctsvc_stmt_bind_text(stmt, i, cursor->data);
3539 contacts_list_create(&list);
3540 while ((ret = ctsvc_stmt_step(stmt))) {
3541 contacts_record_h record;
3543 /* LCOV_EXCL_START */
3544 ERR("ctsvc_stmt_step() Fail(%d)", ret);
3545 ctsvc_stmt_finalize(stmt);
3546 contacts_list_destroy(list, true);
3548 /* LCOV_EXCL_STOP */
3551 if (ctsvc_view_get_record_type(s_query->view_uri) == CTSVC_RECORD_PERSON) {
3552 unsigned int ids_count;
3553 unsigned int *project;
3554 if (0 == s_query->projection_count)
3555 ids_count = s_query->property_count;
3557 ids_count = s_query->projection_count;
3559 project = malloc(sizeof(unsigned int)*ids_count);
3561 for (i = 0; i < ids_count; i++) {
3562 if (0 == s_query->projection_count)
3563 project[i] = s_query->properties[i].property_id;
3565 project[i] = s_query->projection[i];
3568 ret = ctsvc_db_person_create_record_from_stmt_with_projection(stmt, project,
3569 ids_count, is_snippet, keyword, start_match, end_match, token_number, &record);
3570 if (CONTACTS_ERROR_NONE != ret)
3571 /* LCOV_EXCL_START */
3572 ERR("ctsvc_db_person_create_record_from_stmt_with_projection() Fail(%d)", ret);
3573 /* LCOV_EXCL_STOP */
3577 contacts_record_create(s_query->view_uri, (contacts_record_h*)&record);
3579 if (0 == s_query->projection_count) {
3580 field_count = s_query->property_count;
3582 field_count = s_query->projection_count;
3584 int err = ctsvc_record_set_projection_flags(record, s_query->projection,
3585 s_query->projection_count, s_query->property_count);
3586 if (CONTACTS_ERROR_NONE != err)
3587 ASSERT_NOT_REACHED("To set projection is Fail");
3590 for (i = 0; i < field_count; i++) {
3593 if (0 == s_query->projection_count)
3594 property_id = s_query->properties[i].property_id;
3596 property_id = s_query->projection[i];
3598 type = __ctsvc_db_get_property_type(s_query->properties,
3599 s_query->property_count, property_id);
3603 case CTSVC_VIEW_DATA_TYPE_INT:
3604 ctsvc_record_set_int(record, property_id, ctsvc_stmt_get_int(stmt, i));
3606 case CTSVC_VIEW_DATA_TYPE_STR:
3607 temp = ctsvc_stmt_get_text(stmt, i);
3608 if (CTSVC_PROPERTY_PERSON_SNIPPET_STRING == property_id) {
3609 temp = ctsvc_utils_get_modified_str(temp, is_snippet, keyword,
3610 start_match, end_match, token_number);
3612 ctsvc_record_set_str(record, property_id, temp);
3614 case CTSVC_VIEW_DATA_TYPE_BOOL:
3615 ctsvc_record_set_bool(record, property_id, (ctsvc_stmt_get_int(stmt, i) ? true : false));
3617 case CTSVC_VIEW_DATA_TYPE_LLI:
3618 ctsvc_record_set_lli(record, property_id, ctsvc_stmt_get_int64(stmt, i));
3620 case CTSVC_VIEW_DATA_TYPE_DOUBLE:
3621 ctsvc_record_set_double(record, property_id, ctsvc_stmt_get_dbl(stmt, i));
3624 /* LCOV_EXCL_START */
3625 ERR("unknown type (%d)", type);
3627 /* LCOV_EXCL_STOP */
3631 ctsvc_list_prepend(list, record);
3633 ctsvc_stmt_finalize(stmt);
3634 ctsvc_list_reverse(list);
3637 return CONTACTS_ERROR_NONE;
3640 static int __ctsvc_db_search_records_with_query(contacts_query_h query,
3641 const char *keyword,
3645 const char *start_match,
3646 const char *end_match,
3648 contacts_list_h *out_list)
3651 char *condition = NULL;
3653 ctsvc_query_s *s_query = (ctsvc_query_s*)query;
3654 GSList *bind_text = NULL;
3655 GSList *cursor = NULL;
3656 bool can_keyword_search;
3659 RETV_IF(NULL == query, CONTACTS_ERROR_INVALID_PARAMETER);
3660 RETV_IF(NULL == keyword, CONTACTS_ERROR_INVALID_PARAMETER);
3662 can_keyword_search = __ctsvc_db_view_can_keyword_search(s_query->view_uri, &enum_uri);
3663 RETV_IF(false == can_keyword_search, CONTACTS_ERROR_INVALID_PARAMETER);
3665 ret = __db_create_projection(s_query->view_uri, s_query->properties,
3666 s_query->property_count, s_query->projection, s_query->projection_count,
3667 &projection, is_snippet);
3668 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "__db_create_projection Fail(%d)", ret);
3670 if (s_query->filter) {
3671 ret = __db_create_composite_condition(s_query->filter, &condition,
3673 if (CONTACTS_ERROR_NONE != ret) {
3674 /* LCOV_EXCL_START */
3675 ERR("__db_create_composite_condition Fail(%d)", ret);
3678 /* LCOV_EXCL_STOP */
3682 ret = __ctsvc_db_search_records_with_query_exec(s_query, enum_uri, projection, condition,
3683 bind_text, keyword, offset, limit, is_snippet, start_match, end_match, token_number, out_list);
3684 if (CONTACTS_ERROR_NONE != ret) {
3685 /* LCOV_EXCL_START */
3686 ERR("__ctsvc_db_search_records_with_query_exec Fail(%d)", ret);
3687 for (cursor = bind_text; cursor; cursor = cursor->next)
3689 g_slist_free(bind_text);
3694 /* LCOV_EXCL_STOP */
3697 for (cursor = bind_text; cursor; cursor = cursor->next)
3699 g_slist_free(bind_text);
3704 return CONTACTS_ERROR_NONE;
3708 contacts_list_h list;
3712 const char *view_uri;
3715 } ctsvc_bulk_info_s;
3717 static int __ctsvc_db_insert_records(contacts_list_h list, int **ids)
3723 contacts_record_h record = NULL;
3725 ret = contacts_list_get_count(list, &count);
3726 if (CONTACTS_ERROR_NONE != ret) {
3727 /* LCOV_EXCL_START */
3728 ERR("contacts_list_get_count() Fail(%d)", ret);
3730 /* LCOV_EXCL_STOP */
3733 ret = ctsvc_begin_trans();
3734 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "ctsvc_begin_trans Fail(%d)", ret);
3736 id = calloc(count, sizeof(int));
3738 contacts_list_first(list);
3740 /* for performance. phone_number_get_normalized_number() can be called repeatedly below */
3741 phone_number_connect();
3743 ret = contacts_list_get_current_record_p(list, &record);
3744 if (CONTACTS_ERROR_NONE != ret) {
3745 /* LCOV_EXCL_START */
3746 ERR("contacts_list_get_current_record_p() Fail(%d)", ret);
3747 ctsvc_end_trans(false);
3749 phone_number_disconnect();
3751 /* LCOV_EXCL_STOP */
3754 ret = ctsvc_db_insert_record(record, &id[index++]);
3755 if (ret != CONTACTS_ERROR_NONE) {
3756 /* LCOV_EXCL_START */
3757 ERR("contacts_db_insert_record() Fail(%d)", ret);
3758 ctsvc_end_trans(false);
3760 phone_number_disconnect();
3762 /* LCOV_EXCL_STOP */
3764 } while (CONTACTS_ERROR_NONE == contacts_list_next(list));
3765 phone_number_disconnect();
3766 ret = ctsvc_end_trans(true);
3767 if (ret < CONTACTS_ERROR_NONE) {
3768 /* LCOV_EXCL_START */
3769 ERR("ctsvc_end_trans() Fail(%d)", ret);
3772 /* LCOV_EXCL_STOP */
3779 return CONTACTS_ERROR_NONE;
3782 static int __ctsvc_db_delete_records(const char *view_uri, int ids[], int count)
3784 int ret = CONTACTS_ERROR_NONE;
3787 ret = ctsvc_begin_trans();
3788 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "ctsvc_begin_trans Fail(%d)", ret);
3792 ret = ctsvc_db_delete_record(view_uri, ids[index++]);
3793 if (CONTACTS_ERROR_NO_DATA == ret) {
3794 DBG("the record is not exist : %d", ret);
3796 } else if (ret != CONTACTS_ERROR_NONE) {
3797 /* LCOV_EXCL_START */
3798 ERR("contacts_db_delete_record() Fail(%d)", ret);
3799 ctsvc_end_trans(false);
3801 /* LCOV_EXCL_STOP */
3803 } while (index < count);
3805 ret = ctsvc_end_trans(true);
3806 if (ret < CONTACTS_ERROR_NONE) {
3807 /* LCOV_EXCL_START */
3808 ERR("ctsvc_end_trans() Fail(%d)", ret);
3810 /* LCOV_EXCL_STOP */
3813 return CONTACTS_ERROR_NONE;
3816 static int __ctsvc_db_update_records(contacts_list_h list)
3818 int ret = CONTACTS_ERROR_NONE;
3820 contacts_record_h record;
3822 ret = contacts_list_get_count(list, &count);
3823 RETVM_IF(ret != CONTACTS_ERROR_NONE, ret, "contacts_list_get_count() Fail(%d)", ret);
3824 RETVM_IF(count <= 0, CONTACTS_ERROR_INVALID_PARAMETER, "Invalid count(%d)", count);
3826 ret = ctsvc_begin_trans();
3827 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "ctsvc_begin_trans() Fail(%d)", ret);
3829 contacts_list_first(list);
3830 /* for performance. phone_number_get_normalized_number() can be called repeatedly below */
3831 phone_number_connect();
3833 ret = contacts_list_get_current_record_p(list, &record);
3834 if (CONTACTS_ERROR_NONE != ret) {
3835 /* LCOV_EXCL_START */
3836 ERR("contacts_list_get_current_record_p() Fail(%d)", ret);
3837 ctsvc_end_trans(false);
3838 phone_number_disconnect();
3840 /* LCOV_EXCL_STOP */
3843 ret = ctsvc_db_update_record(record);
3844 if (ret != CONTACTS_ERROR_NONE) {
3845 /* LCOV_EXCL_START */
3846 ERR("contacts_db_update_record() Fail(%d)", ret);
3847 ctsvc_end_trans(false);
3848 phone_number_disconnect();
3850 /* LCOV_EXCL_STOP */
3852 } while (CONTACTS_ERROR_NONE == contacts_list_next(list));
3853 phone_number_disconnect();
3854 ret = ctsvc_end_trans(true);
3855 if (ret < CONTACTS_ERROR_NONE) {
3856 /* LCOV_EXCL_START */
3857 ERR("ctsvc_end_trans() Fail(%d)", ret);
3859 /* LCOV_EXCL_STOP */
3862 return CONTACTS_ERROR_NONE;
3865 static int __ctsvc_db_get_count_exec(const char *view_uri, const property_info_s *properties, int ids_count,
3866 const char *projection, int *out_count)
3868 char query[CTS_SQL_MAX_LEN] = {0};
3873 ret = ctsvc_db_get_table_name(view_uri, &table);
3874 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "Invalid view uri(%s)", view_uri);
3876 len = snprintf(query, sizeof(query), "SELECT COUNT(*) FROM (SELECT %s FROM ", projection);
3878 len += snprintf(query+len, sizeof(query)-len, " (%s)", table);
3880 len += snprintf(query+len, sizeof(query)-len, ") ");
3882 ret = ctsvc_query_get_first_int_result(query, out_count);
3883 if (CONTACTS_ERROR_NONE != ret) {
3884 /* LCOV_EXCL_START */
3885 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
3887 /* LCOV_EXCL_STOP */
3893 static int __ctsvc_db_get_count(const char *view_uri, int *out_count)
3899 const property_info_s *p = ctsvc_view_get_all_property_infos(view_uri, &count);
3900 ret = __db_create_projection(view_uri, p, count, NULL, 0, &projection, false);
3901 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "__db_create_projection Fail(%d)", ret);
3903 __ctsvc_db_get_count_exec(view_uri, p, count, projection, out_count);
3906 return CONTACTS_ERROR_NONE;
3909 static int __db_get_count_with_query_exec(ctsvc_query_s *s_query, const char *projection,
3910 const char *condition, GSList *bind_text, int *out_count)
3919 RETV_IF(NULL == projection || '\0' == *projection, CONTACTS_ERROR_INVALID_PARAMETER);
3921 ret = ctsvc_db_get_table_name(s_query->view_uri, &table);
3922 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "Invalid view uri(%s)", s_query->view_uri);
3924 query_size = CTS_SQL_MAX_LEN;
3925 query = calloc(1, query_size);
3926 if (NULL == query) {
3927 /* LCOV_EXCL_START */
3928 ERR("calloc() Fail");
3929 return CONTACTS_ERROR_OUT_OF_MEMORY;
3930 /* LCOV_EXCL_STOP */
3934 if (s_query->distinct) {
3935 temp_len = SAFE_SNPRINTF(&query, &query_size, len,
3936 "SELECT COUNT(*) FROM (SELECT DISTINCT ");
3938 temp_len = SAFE_SNPRINTF(&query, &query_size, len,
3939 "SELECT COUNT(*) FROM (SELECT ");
3944 temp_len = SAFE_SNPRINTF(&query, &query_size, len, projection);
3948 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " FROM ");
3952 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " (");
3956 temp_len = SAFE_SNPRINTF(&query, &query_size, len, table);
3960 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ") ");
3964 if (condition && *condition) {
3965 temp_len = SAFE_SNPRINTF(&query, &query_size, len, " WHERE (");
3969 temp_len = SAFE_SNPRINTF(&query, &query_size, len, condition);
3973 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ") ");
3978 temp_len = SAFE_SNPRINTF(&query, &query_size, len, ") ");
3979 if (0 <= temp_len) len += temp_len;
3985 ret = ctsvc_query_prepare(query, &stmt);
3987 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
3989 for (cursor = bind_text, i = 1; cursor; cursor = cursor->next, i++)
3990 ctsvc_stmt_bind_copy_text(stmt, i, cursor->data, strlen(cursor->data));
3991 ret = ctsvc_stmt_get_first_int_result(stmt, out_count);
3992 if (CONTACTS_ERROR_NONE != ret) {
3993 /* LCOV_EXCL_START */
3994 ERR("ctsvc_stmt_get_first_int_result() Fail(%d)", ret);
3996 /* LCOV_EXCL_STOP */
3999 ret = ctsvc_query_get_first_int_result(query, out_count);
4001 if (CONTACTS_ERROR_NONE != ret) {
4002 /* LCOV_EXCL_START */
4003 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
4005 /* LCOV_EXCL_STOP */
4011 static int __ctsvc_db_get_count_with_query(contacts_query_h query, int *out_count)
4014 char *condition = NULL;
4015 char *projection = NULL;
4016 ctsvc_query_s *s_query;
4017 GSList *bind_text = NULL;
4020 RETV_IF(NULL == query, CONTACTS_ERROR_INVALID_PARAMETER);
4021 s_query = (ctsvc_query_s*)query;
4023 if (s_query->filter) {
4024 ret = __db_create_composite_condition(s_query->filter, &condition, &bind_text);
4025 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret,
4026 "__db_create_composite_condition() Fail(%d)", ret);
4029 ret = __db_create_projection(s_query->view_uri, s_query->properties,
4030 s_query->property_count, s_query->projection, s_query->projection_count,
4031 &projection, false);
4032 if (CONTACTS_ERROR_NONE != ret) {
4033 /* LCOV_EXCL_START */
4034 ERR("__db_create_projection() Fail(%d)", ret);
4035 for (cursor = bind_text; cursor; cursor = cursor->next)
4037 g_slist_free(bind_text);
4040 /* LCOV_EXCL_STOP */
4043 ret = __db_get_count_with_query_exec(s_query, projection, condition, bind_text,
4045 for (cursor = bind_text; cursor; cursor = cursor->next)
4047 g_slist_free(bind_text);
4055 int ctsvc_db_get_records_with_query(contacts_query_h query, int offset, int limit,
4056 contacts_list_h *out_list)
4058 int ret = CONTACTS_ERROR_NONE;
4059 ctsvc_query_s *s_query = (ctsvc_query_s*)query;
4060 ctsvc_db_plugin_info_s *plugin_info = NULL;
4062 RETV_IF(NULL == out_list, CONTACTS_ERROR_INVALID_PARAMETER);
4065 RETV_IF(NULL == query, CONTACTS_ERROR_INVALID_PARAMETER);
4067 plugin_info = ctsvc_db_get_plugin_info(ctsvc_view_get_record_type(s_query->view_uri));
4069 if (plugin_info->get_records_with_query) {
4070 ret = plugin_info->get_records_with_query(query, offset, limit, out_list);
4075 return __ctsvc_db_get_records_with_query_exec(s_query, offset, limit, out_list);
4078 static int __ctsvc_db_get_contact_changes(const char *view_uri, int addressbook_id,
4079 int version, contacts_list_h *out_list, int *out_current_version)
4082 char query[CTS_SQL_MAX_LEN] = {0};
4083 contacts_list_h list;
4086 if (0 <= addressbook_id) {
4087 snprintf(query, sizeof(query),
4088 "SELECT %d, contact_id, changed_ver, created_ver, addressbook_id, image_changed_ver "
4089 "FROM "CTS_TABLE_CONTACTS" "
4090 "WHERE changed_ver > %d AND addressbook_id = %d AND deleted = 0 "
4092 "SELECT %d, contact_id, deleted_ver, -1, addressbook_id, 0 "
4093 "FROM "CTS_TABLE_DELETEDS" "
4094 "WHERE deleted_ver > %d AND created_ver <= %d AND addressbook_id = %d "
4096 "SELECT %d, contact_id, changed_ver, -1, addressbook_id, 0 "
4097 "FROM "CTS_TABLE_CONTACTS" "
4098 "WHERE changed_ver > %d AND created_ver <= %d AND addressbook_id = %d AND deleted = 1 "
4099 "AND addressbook_id = (SELECT addressbook_id FROM "CTS_TABLE_ADDRESSBOOKS" WHERE addressbook_id = %d)",
4100 CONTACTS_CHANGE_UPDATED, version, addressbook_id,
4101 CONTACTS_CHANGE_DELETED, version, version, addressbook_id,
4102 CONTACTS_CHANGE_DELETED, version, version, addressbook_id, addressbook_id);
4104 snprintf(query, sizeof(query),
4105 "SELECT %d, contact_id, changed_ver, created_ver, addressbook_id, image_changed_ver "
4106 "FROM "CTS_TABLE_CONTACTS" "
4107 "WHERE changed_ver > %d AND deleted = 0 "
4109 "SELECT %d, contact_id, deleted_ver, -1, addressbook_id, 0 "
4110 "FROM "CTS_TABLE_DELETEDS" "
4111 "WHERE deleted_ver > %d AND created_ver <= %d "
4113 "SELECT %d, contact_id, changed_ver, -1, "CTS_TABLE_CONTACTS".addressbook_id, 0 "
4114 "FROM "CTS_TABLE_CONTACTS", "CTS_TABLE_ADDRESSBOOKS" "
4115 "WHERE changed_ver > %d AND created_ver <= %d AND deleted = 1 "
4116 "AND "CTS_TABLE_CONTACTS".addressbook_id = "CTS_TABLE_ADDRESSBOOKS".addressbook_id",
4117 CONTACTS_CHANGE_UPDATED, version,
4118 CONTACTS_CHANGE_DELETED, version, version,
4119 CONTACTS_CHANGE_DELETED, version, version);
4122 ret = ctsvc_query_prepare(query, &stmt);
4123 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
4125 contacts_list_create(&list);
4126 while ((ret = ctsvc_stmt_step(stmt))) {
4127 contacts_record_h record;
4128 ctsvc_updated_info_s *update_info;
4131 /* LCOV_EXCL_START */
4132 ERR("ctsvc_stmt_step() Fail(%d)", ret);
4133 ctsvc_stmt_finalize(stmt);
4134 contacts_list_destroy(list, true);
4136 /* LCOV_EXCL_STOP */
4139 ret = contacts_record_create(_contacts_contact_updated_info._uri, &record);
4140 update_info = (ctsvc_updated_info_s*)record;
4141 update_info->changed_type = ctsvc_stmt_get_int(stmt, 0);
4142 update_info->id = ctsvc_stmt_get_int(stmt, 1);
4143 update_info->changed_ver = ctsvc_stmt_get_int(stmt, 2);
4145 if (ctsvc_stmt_get_int(stmt, 3) == update_info->changed_ver
4146 || version < ctsvc_stmt_get_int(stmt, 3)) {
4147 update_info->changed_type = CONTACTS_CHANGE_INSERTED;
4150 update_info->addressbook_id = ctsvc_stmt_get_int(stmt, 4);
4152 if (version < ctsvc_stmt_get_int(stmt, 5))
4153 update_info->image_changed = true;
4155 ctsvc_list_prepend(list, record);
4157 ctsvc_stmt_finalize(stmt);
4158 ctsvc_list_reverse(list);
4160 snprintf(query, sizeof(query), "SELECT ver FROM "CTS_TABLE_VERSION);
4161 ret = ctsvc_query_get_first_int_result(query, out_current_version);
4162 if (CONTACTS_ERROR_NONE != ret) {
4163 /* LCOV_EXCL_START */
4164 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
4165 contacts_list_destroy(list, true);
4167 /* LCOV_EXCL_STOP */
4171 return CONTACTS_ERROR_NONE;
4174 static int __ctsvc_db_get_group_changes(const char *view_uri, int addressbook_id,
4175 int version, contacts_list_h *out_list, int *out_current_version)
4178 char query[CTS_SQL_MAX_LEN] = {0};
4179 contacts_list_h list;
4182 if (0 <= addressbook_id) {
4183 snprintf(query, sizeof(query),
4184 "SELECT %d, group_id, changed_ver, created_ver, addressbook_id FROM %s "
4185 "WHERE changed_ver > %d AND addressbook_id = %d "
4187 "SELECT %d, group_id, deleted_ver, -1, addressbook_id FROM %s "
4188 "WHERE deleted_ver > %d AND created_ver <= %d AND addressbook_id = %d",
4189 CONTACTS_CHANGE_UPDATED, CTS_TABLE_GROUPS, version, addressbook_id,
4190 CONTACTS_CHANGE_DELETED, CTS_TABLE_GROUP_DELETEDS, version, version, addressbook_id);
4192 snprintf(query, sizeof(query),
4193 "SELECT %d, group_id, changed_ver, created_ver, addressbook_id FROM %s "
4194 "WHERE changed_ver > %d "
4196 "SELECT %d, group_id, deleted_ver, -1, addressbook_id FROM %s "
4197 "WHERE deleted_ver > %d AND created_ver <= %d",
4198 CONTACTS_CHANGE_UPDATED, CTS_TABLE_GROUPS, version,
4199 CONTACTS_CHANGE_DELETED, CTS_TABLE_GROUP_DELETEDS, version, version);
4202 ret = ctsvc_query_prepare(query, &stmt);
4203 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
4205 contacts_list_create(&list);
4206 while ((ret = ctsvc_stmt_step(stmt))) {
4207 contacts_record_h record;
4208 ctsvc_updated_info_s *update_info;
4211 /* LCOV_EXCL_START */
4212 ERR("ctsvc_stmt_step() Fail(%d)", ret);
4213 ctsvc_stmt_finalize(stmt);
4214 contacts_list_destroy(list, true);
4216 /* LCOV_EXCL_STOP */
4219 ret = contacts_record_create(_contacts_group_updated_info._uri, &record);
4220 update_info = (ctsvc_updated_info_s*)record;
4221 update_info->changed_type = ctsvc_stmt_get_int(stmt, 0);
4222 update_info->id = ctsvc_stmt_get_int(stmt, 1);
4223 update_info->changed_ver = ctsvc_stmt_get_int(stmt, 2);
4225 if (ctsvc_stmt_get_int(stmt, 3) == update_info->changed_ver
4226 || version < ctsvc_stmt_get_int(stmt, 3)) {
4227 update_info->changed_type = CONTACTS_CHANGE_INSERTED;
4230 update_info->addressbook_id = ctsvc_stmt_get_int(stmt, 4);
4232 ctsvc_list_prepend(list, record);
4234 ctsvc_stmt_finalize(stmt);
4235 ctsvc_list_reverse(list);
4237 snprintf(query, sizeof(query), "SELECT ver FROM "CTS_TABLE_VERSION);
4238 ret = ctsvc_query_get_first_int_result(query, out_current_version);
4239 if (CONTACTS_ERROR_NONE != ret) {
4240 /* LCOV_EXCL_START */
4241 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
4242 contacts_list_destroy(list, true);
4244 /* LCOV_EXCL_STOP */
4248 return CONTACTS_ERROR_NONE;
4251 static int __ctsvc_db_get_group_relations_changes(const char *view_uri,
4254 contacts_list_h *out_list,
4255 int *out_current_version)
4259 char query[CTS_SQL_MAX_LEN] = {0};
4260 char temp_query[CTS_SQL_MAX_LEN] = {0};
4261 contacts_list_h list;
4264 len = snprintf(temp_query, sizeof(temp_query),
4265 "SELECT %d, group_id, contact_id, addressbook_id, ver "
4266 "FROM "CTS_TABLE_GROUP_RELATIONS", "CTS_TABLE_GROUPS" USING (group_id) "
4267 "WHERE ver > %d AND deleted = 0 "
4268 "UNION SELECT %d, group_id, contact_id, addressbook_id, ver "
4269 "FROM "CTS_TABLE_GROUP_RELATIONS", "CTS_TABLE_GROUPS" USING (group_id) "
4270 "WHERE ver > %d AND deleted = 1 ",
4271 CONTACTS_CHANGE_INSERTED, version,
4272 CONTACTS_CHANGE_DELETED, version);
4274 if (0 <= addressbook_id) {
4275 len += snprintf(query, sizeof(query),
4276 "SELECT * FROM (%s) WHERE addressbook_id = %d ", temp_query, addressbook_id);
4279 ret = ctsvc_query_prepare(query, &stmt);
4280 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
4282 contacts_list_create(&list);
4283 while ((ret = ctsvc_stmt_step(stmt))) {
4284 contacts_record_h record;
4286 /* LCOV_EXCL_START */
4287 ERR("ctsvc_stmt_step() Fail(%d)", ret);
4288 ctsvc_stmt_finalize(stmt);
4289 contacts_list_destroy(list, true);
4291 /* LCOV_EXCL_STOP */
4294 ret = contacts_record_create(view_uri, &record);
4295 ctsvc_record_set_int(record, _contacts_grouprel_updated_info.type,
4296 ctsvc_stmt_get_int(stmt, 0));
4297 ctsvc_record_set_int(record, _contacts_grouprel_updated_info.group_id,
4298 ctsvc_stmt_get_int(stmt, 1));
4299 ctsvc_record_set_int(record, _contacts_grouprel_updated_info.contact_id,
4300 ctsvc_stmt_get_int(stmt, 2));
4301 ctsvc_record_set_int(record, _contacts_grouprel_updated_info.address_book_id,
4302 ctsvc_stmt_get_int(stmt, 3));
4303 ctsvc_record_set_int(record, _contacts_grouprel_updated_info.version,
4304 ctsvc_stmt_get_int(stmt, 4));
4306 ctsvc_list_prepend(list, record);
4308 ctsvc_stmt_finalize(stmt);
4309 ctsvc_list_reverse(list);
4311 snprintf(query, sizeof(query), "SELECT ver FROM "CTS_TABLE_VERSION);
4312 ret = ctsvc_query_get_first_int_result(query, out_current_version);
4313 if (CONTACTS_ERROR_NONE != ret) {
4314 /* LCOV_EXCL_START */
4315 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
4316 contacts_list_destroy(list, true);
4318 /* LCOV_EXCL_STOP */
4323 return CONTACTS_ERROR_NONE;
4326 static int __ctsvc_db_get_group_member_changes(const char *view_uri, int addressbook_id,
4327 int version, contacts_list_h *out_list, int *out_current_version)
4331 char query[CTS_SQL_MAX_LEN] = {0};
4332 contacts_list_h list;
4335 len = snprintf(query, sizeof(query),
4336 "SELECT group_id, member_changed_ver, addressbook_id "
4337 "FROM "CTS_TABLE_GROUPS" WHERE member_changed_ver > %d", version);
4339 if (0 <= addressbook_id) {
4340 len += snprintf(query+len, sizeof(query)-len, " AND addressbook_id = %d ",
4344 ret = ctsvc_query_prepare(query, &stmt);
4345 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
4347 contacts_list_create(&list);
4348 while ((ret = ctsvc_stmt_step(stmt))) {
4349 contacts_record_h record;
4351 /* LCOV_EXCL_START */
4352 ERR("ctsvc_stmt_step() Fail(%d)", ret);
4353 ctsvc_stmt_finalize(stmt);
4354 contacts_list_destroy(list, true);
4356 /* LCOV_EXCL_STOP */
4359 ret = contacts_record_create(view_uri, &record);
4360 ctsvc_record_set_int(record, _contacts_group_member_updated_info.group_id,
4361 ctsvc_stmt_get_int(stmt, 0));
4362 ctsvc_record_set_int(record, _contacts_group_member_updated_info.version,
4363 ctsvc_stmt_get_int(stmt, 1));
4364 ctsvc_record_set_int(record, _contacts_group_member_updated_info.address_book_id,
4365 ctsvc_stmt_get_int(stmt, 2));
4367 ctsvc_list_prepend(list, record);
4369 ctsvc_stmt_finalize(stmt);
4370 ctsvc_list_reverse(list);
4372 snprintf(query, sizeof(query), "SELECT ver FROM "CTS_TABLE_VERSION);
4373 ret = ctsvc_query_get_first_int_result(query, out_current_version);
4374 if (CONTACTS_ERROR_NONE != ret) {
4375 /* LCOV_EXCL_START */
4376 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
4377 contacts_list_destroy(list, true);
4379 /* LCOV_EXCL_STOP */
4384 return CONTACTS_ERROR_NONE;
4387 static int __ctsvc_db_get_my_profile_changes(const char *view_uri, int addressbook_id,
4388 int version, contacts_list_h *out_list, int *out_current_version)
4391 char query[CTS_SQL_MAX_LEN] = {0};
4392 contacts_list_h list;
4395 if (0 <= addressbook_id) {
4396 snprintf(query, sizeof(query),
4397 "SELECT changed_ver, addressbook_id, %d FROM %s "
4398 "WHERE changed_ver > %d AND changed_ver == created_ver AND deleted = 0 AND addressbook_id = %d "
4400 "SELECT changed_ver, addressbook_id, %d FROM %s "
4401 "WHERE changed_ver > %d AND changed_ver != created_ver AND deleted = 0 AND addressbook_id = %d "
4403 "SELECT changed_ver, addressbook_id, %d FROM %s "
4404 "WHERE changed_ver > %d AND deleted = 1 AND addressbook_id = %d",
4405 CONTACTS_CHANGE_INSERTED, CTS_TABLE_MY_PROFILES, version, addressbook_id,
4406 CONTACTS_CHANGE_UPDATED, CTS_TABLE_MY_PROFILES, version, addressbook_id,
4407 CONTACTS_CHANGE_DELETED, CTS_TABLE_MY_PROFILES, version, addressbook_id);
4409 snprintf(query, sizeof(query),
4410 "SELECT changed_ver, addressbook_id, %d FROM %s "
4411 "WHERE changed_ver > %d AND changed_ver == created_ver AND deleted = 0 "
4413 "SELECT changed_ver, addressbook_id, %d FROM %s "
4414 "WHERE changed_ver > %d AND changed_ver != created_ver AND deleted = 0 "
4416 "SELECT changed_ver, addressbook_id, %d FROM %s "
4417 "WHERE changed_ver > %d AND deleted = 1",
4418 CONTACTS_CHANGE_INSERTED, CTS_TABLE_MY_PROFILES, version,
4419 CONTACTS_CHANGE_UPDATED, CTS_TABLE_MY_PROFILES, version,
4420 CONTACTS_CHANGE_DELETED, CTS_TABLE_MY_PROFILES, version);
4423 ret = ctsvc_query_prepare(query, &stmt);
4424 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
4426 contacts_list_create(&list);
4427 while ((ret = ctsvc_stmt_step(stmt))) {
4428 contacts_record_h record;
4430 /* LCOV_EXCL_START */
4431 ERR("ctsvc_stmt_step() Fail(%d)", ret);
4432 ctsvc_stmt_finalize(stmt);
4433 contacts_list_destroy(list, true);
4435 /* LCOV_EXCL_STOP */
4438 ret = contacts_record_create(view_uri, &record);
4439 ctsvc_record_set_int(record, _contacts_my_profile_updated_info.version,
4440 ctsvc_stmt_get_int(stmt, 0));
4441 ctsvc_record_set_int(record, _contacts_my_profile_updated_info.address_book_id,
4442 ctsvc_stmt_get_int(stmt, 1));
4443 ctsvc_record_set_int(record, _contacts_my_profile_updated_info.last_changed_type,
4444 ctsvc_stmt_get_int(stmt, 2));
4445 ctsvc_list_prepend(list, record);
4447 ctsvc_stmt_finalize(stmt);
4448 ctsvc_list_reverse(list);
4450 snprintf(query, sizeof(query), "SELECT ver FROM "CTS_TABLE_VERSION);
4451 ret = ctsvc_query_get_first_int_result(query, out_current_version);
4452 if (CONTACTS_ERROR_NONE != ret) {
4453 /* LCOV_EXCL_START */
4454 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
4455 contacts_list_destroy(list, true);
4457 /* LCOV_EXCL_STOP */
4462 return CONTACTS_ERROR_NONE;
4465 int ctsvc_db_get_changes_by_version(const char *view_uri, int addressbook_id,
4466 int version, contacts_list_h *out_list, int *out_current_version)
4469 RETV_IF(version < 0, CONTACTS_ERROR_INVALID_PARAMETER);
4470 RETV_IF(NULL == out_list, CONTACTS_ERROR_INVALID_PARAMETER);
4472 RETV_IF(NULL == out_current_version, CONTACTS_ERROR_INVALID_PARAMETER);
4473 *out_current_version = 0;
4475 if (STRING_EQUAL == strcmp(view_uri, _contacts_contact_updated_info._uri)) {
4476 ret = __ctsvc_db_get_contact_changes(view_uri, addressbook_id,
4477 version, out_list, out_current_version);
4479 } else if (STRING_EQUAL == strcmp(view_uri, _contacts_group_updated_info._uri)) {
4480 ret = __ctsvc_db_get_group_changes(view_uri, addressbook_id,
4481 version, out_list, out_current_version);
4483 } else if (STRING_EQUAL == strcmp(view_uri, _contacts_group_member_updated_info._uri)) {
4484 ret = __ctsvc_db_get_group_member_changes(view_uri, addressbook_id,
4485 version, out_list, out_current_version);
4487 } else if (STRING_EQUAL == strcmp(view_uri, _contacts_grouprel_updated_info._uri)) {
4488 ret = __ctsvc_db_get_group_relations_changes(view_uri, addressbook_id,
4489 version, out_list, out_current_version);
4491 } else if (STRING_EQUAL == strcmp(view_uri, _contacts_my_profile_updated_info._uri)) {
4492 ret = __ctsvc_db_get_my_profile_changes(view_uri, addressbook_id,
4493 version, out_list, out_current_version);
4497 /* LCOV_EXCL_START */
4498 ERR("this API does not support uri(%s)", view_uri);
4499 return CONTACTS_ERROR_INVALID_PARAMETER;
4500 /* LCOV_EXCL_STOP */
4503 int ctsvc_db_get_current_version(int *out_current_version)
4505 RETV_IF(NULL == out_current_version, CONTACTS_ERROR_INVALID_PARAMETER);
4507 return ctsvc_get_current_version(out_current_version);
4510 int ctsvc_db_search_records(const char *view_uri, const char *keyword,
4511 int offset, int limit, contacts_list_h *out_list)
4513 RETV_IF(NULL == out_list, CONTACTS_ERROR_INVALID_PARAMETER);
4515 RETV_IF(NULL == view_uri, CONTACTS_ERROR_INVALID_PARAMETER);
4517 return __ctsvc_db_search_records(view_uri, keyword, offset, limit, false, NULL,
4518 NULL, -1, out_list);
4521 int ctsvc_db_search_records_with_range(const char *view_uri, const char *keyword,
4522 int offset, int limit, int range, contacts_list_h *out_list)
4524 RETV_IF(NULL == out_list, CONTACTS_ERROR_INVALID_PARAMETER);
4526 RETV_IF(range == 0, CONTACTS_ERROR_INVALID_PARAMETER);
4527 RETV_IF(NULL == view_uri, CONTACTS_ERROR_INVALID_PARAMETER);
4529 return __ctsvc_db_search_records_with_range(view_uri, keyword, offset, limit, range,
4530 false, NULL, NULL, -1, out_list);
4533 int ctsvc_db_search_records_with_query(contacts_query_h query, const char *keyword,
4534 int offset, int limit, contacts_list_h *out_list)
4536 RETV_IF(NULL == out_list, CONTACTS_ERROR_INVALID_PARAMETER);
4538 RETV_IF(NULL == query, CONTACTS_ERROR_INVALID_PARAMETER);
4540 return __ctsvc_db_search_records_with_query(query, keyword, offset, limit, false,
4541 NULL, NULL, -1, out_list);
4544 int ctsvc_db_search_records_for_snippet(const char *view_uri, const char *keyword,
4547 const char *start_match,
4548 const char *end_match,
4550 contacts_list_h *out_list)
4552 RETV_IF(NULL == out_list, CONTACTS_ERROR_INVALID_PARAMETER);
4554 RETV_IF(NULL == view_uri, CONTACTS_ERROR_INVALID_PARAMETER);
4556 return __ctsvc_db_search_records(view_uri, keyword, offset, limit, true, start_match,
4557 end_match, token_number, out_list);
4560 int ctsvc_db_search_records_with_range_for_snippet(const char *view_uri,
4561 const char *keyword,
4565 const char *start_match,
4566 const char *end_match,
4568 contacts_list_h *out_list)
4570 RETV_IF(NULL == out_list, CONTACTS_ERROR_INVALID_PARAMETER);
4572 RETV_IF(range == 0, CONTACTS_ERROR_INVALID_PARAMETER);
4573 RETV_IF(NULL == view_uri, CONTACTS_ERROR_INVALID_PARAMETER);
4575 return __ctsvc_db_search_records_with_range(view_uri, keyword, offset, limit, range,
4576 true, start_match, end_match, token_number, out_list);
4579 int ctsvc_db_search_records_with_query_for_snippet(contacts_query_h query,
4580 const char *keyword,
4583 const char *start_match,
4584 const char *end_match,
4586 contacts_list_h *out_list)
4588 RETV_IF(NULL == out_list, CONTACTS_ERROR_INVALID_PARAMETER);
4590 RETV_IF(NULL == query, CONTACTS_ERROR_INVALID_PARAMETER);
4592 return __ctsvc_db_search_records_with_query(query, keyword, offset, limit, true,
4593 start_match, end_match, token_number, out_list);
4596 int ctsvc_db_get_count(const char *view_uri, int *out_count)
4599 ctsvc_db_plugin_info_s *plugin_info = NULL;
4601 RETV_IF(NULL == out_count, CONTACTS_ERROR_INVALID_PARAMETER);
4603 RETV_IF(NULL == view_uri, CONTACTS_ERROR_INVALID_PARAMETER);
4605 if ((plugin_info = ctsvc_db_get_plugin_info(ctsvc_view_get_record_type(view_uri)))) {
4606 if (plugin_info->get_count) {
4607 ret = plugin_info->get_count(out_count);
4612 return __ctsvc_db_get_count(view_uri, out_count);
4615 int ctsvc_db_get_count_with_query(contacts_query_h query, int *out_count)
4617 int ret = CONTACTS_ERROR_NONE;
4618 ctsvc_record_type_e type = CTSVC_RECORD_INVALID;
4619 ctsvc_db_plugin_info_s *plugin_info = NULL;
4620 ctsvc_query_s *s_query = (ctsvc_query_s*)query;
4622 RETV_IF(NULL == out_count, CONTACTS_ERROR_INVALID_PARAMETER);
4624 RETV_IF(NULL == query, CONTACTS_ERROR_INVALID_PARAMETER);
4626 type = ctsvc_view_get_record_type(s_query->view_uri);
4627 plugin_info = ctsvc_db_get_plugin_info(type);
4630 if (plugin_info->get_count_with_query) {
4631 ret = plugin_info->get_count_with_query(query, out_count);
4636 return __ctsvc_db_get_count_with_query(query, out_count);
4639 int ctsvc_db_insert_record(contacts_record_h record, int *id)
4641 ctsvc_db_plugin_info_s *plugin_info = NULL;
4646 RETV_IF(NULL == record, CONTACTS_ERROR_INVALID_PARAMETER);
4648 plugin_info = ctsvc_db_get_plugin_info(((ctsvc_record_s*)record)->r_type);
4649 RETV_IF(NULL == plugin_info, CONTACTS_ERROR_INVALID_PARAMETER);
4650 RETV_IF(NULL == plugin_info->insert_record, CONTACTS_ERROR_INVALID_PARAMETER);
4652 return plugin_info->insert_record(record, id);
4655 int ctsvc_db_update_record(contacts_record_h record)
4657 ctsvc_db_plugin_info_s *plugin_info = NULL;
4659 RETV_IF(NULL == record, CONTACTS_ERROR_INVALID_PARAMETER);
4661 plugin_info = ctsvc_db_get_plugin_info(((ctsvc_record_s*)record)->r_type);
4662 RETV_IF(NULL == plugin_info, CONTACTS_ERROR_INVALID_PARAMETER);
4663 RETV_IF(NULL == plugin_info->update_record, CONTACTS_ERROR_INVALID_PARAMETER);
4665 return plugin_info->update_record(record);
4668 int ctsvc_db_delete_record(const char *view_uri, int id)
4670 ctsvc_record_type_e type = CTSVC_RECORD_INVALID;
4671 ctsvc_db_plugin_info_s *plugin_info = NULL;
4673 RETV_IF(NULL == view_uri, CONTACTS_ERROR_INVALID_PARAMETER);
4675 type = ctsvc_view_get_record_type(view_uri);
4676 plugin_info = ctsvc_db_get_plugin_info(type);
4677 RETV_IF(NULL == plugin_info, CONTACTS_ERROR_INVALID_PARAMETER);
4678 RETV_IF(NULL == plugin_info->delete_record, CONTACTS_ERROR_INVALID_PARAMETER);
4680 return plugin_info->delete_record(id);
4683 int ctsvc_db_get_record(const char *view_uri, int id, contacts_record_h *out_record)
4685 ctsvc_record_type_e type = CTSVC_RECORD_INVALID;
4686 ctsvc_db_plugin_info_s *plugin_info = NULL;
4688 RETV_IF(NULL == out_record, CONTACTS_ERROR_INVALID_PARAMETER);
4690 RETV_IF(NULL == view_uri, CONTACTS_ERROR_INVALID_PARAMETER);
4692 type = ctsvc_view_get_record_type(view_uri);
4693 plugin_info = ctsvc_db_get_plugin_info(type);
4695 RETV_IF(NULL == plugin_info, CONTACTS_ERROR_INVALID_PARAMETER);
4696 RETV_IF(NULL == plugin_info->get_record, CONTACTS_ERROR_INVALID_PARAMETER);
4698 return plugin_info->get_record(id, out_record);
4701 int ctsvc_db_replace_record(contacts_record_h record, int id)
4703 ctsvc_db_plugin_info_s *plugin_info = NULL;
4705 RETV_IF(NULL == record, CONTACTS_ERROR_INVALID_PARAMETER);
4707 plugin_info = ctsvc_db_get_plugin_info(((ctsvc_record_s*)record)->r_type);
4708 RETV_IF(NULL == plugin_info, CONTACTS_ERROR_INVALID_PARAMETER);
4709 RETV_IF(NULL == plugin_info->replace_record, CONTACTS_ERROR_INVALID_PARAMETER);
4711 return plugin_info->replace_record(record, id);
4714 int ctsvc_db_get_all_records(const char *view_uri, int offset, int limit,
4715 contacts_list_h *out_list)
4717 int ret = CONTACTS_ERROR_NONE;
4718 ctsvc_record_type_e type = CTSVC_RECORD_INVALID;
4719 ctsvc_db_plugin_info_s *plugin_info = NULL;
4721 RETV_IF(NULL == out_list, CONTACTS_ERROR_INVALID_PARAMETER);
4723 RETV_IF(NULL == view_uri, CONTACTS_ERROR_INVALID_PARAMETER);
4725 type = ctsvc_view_get_record_type(view_uri);
4726 plugin_info = ctsvc_db_get_plugin_info(type);
4729 if (plugin_info->get_all_records) {
4730 ret = plugin_info->get_all_records(offset, limit, out_list);
4735 return __ctsvc_db_get_all_records(view_uri, offset, limit, out_list);
4738 int ctsvc_db_insert_records(contacts_list_h list, int **ids, int *count)
4740 int ret = CONTACTS_ERROR_NONE;
4741 ctsvc_db_plugin_info_s *plugin_info = NULL;
4743 RETV_IF(NULL == list, CONTACTS_ERROR_INVALID_PARAMETER);
4746 contacts_list_get_count(list, count);
4747 if ((plugin_info = ctsvc_db_get_plugin_info(((ctsvc_list_s*)list)->l_type))) {
4748 if (plugin_info->insert_records) {
4749 ret = plugin_info->insert_records(list, ids);
4754 return __ctsvc_db_insert_records(list, ids);
4757 int ctsvc_db_update_records(contacts_list_h list)
4759 int ret = CONTACTS_ERROR_NONE;
4760 ctsvc_db_plugin_info_s *plugin_info = NULL;
4762 RETV_IF(NULL == list, CONTACTS_ERROR_INVALID_PARAMETER);
4764 if ((plugin_info = ctsvc_db_get_plugin_info(((ctsvc_list_s*)list)->l_type))) {
4765 if (plugin_info->update_records) {
4766 ret = plugin_info->update_records(list);
4771 return __ctsvc_db_update_records(list);
4774 int ctsvc_db_delete_records(const char *view_uri, int *ids, int count)
4776 int ret = CONTACTS_ERROR_NONE;
4777 ctsvc_db_plugin_info_s *plugin_info = NULL;
4779 RETV_IF(NULL == ids, CONTACTS_ERROR_INVALID_PARAMETER);
4781 if ((plugin_info = ctsvc_db_get_plugin_info(ctsvc_view_get_record_type(view_uri)))) {
4782 if (plugin_info->delete_records) {
4783 ret = plugin_info->delete_records(ids, count);
4788 return __ctsvc_db_delete_records(view_uri, ids, count);
4791 static int __ctsvc_db_replace_records(contacts_list_h list, int ids[], int count)
4793 int ret = CONTACTS_ERROR_NONE;
4795 contacts_record_h record;
4798 ret = contacts_list_get_count(list, &record_count);
4799 RETVM_IF(ret != CONTACTS_ERROR_NONE, ret, "contacts_list_get_count() Fail(%d)", ret);
4800 RETVM_IF(record_count <= 0, CONTACTS_ERROR_INVALID_PARAMETER, "Invalid count(%d)",
4802 RETVM_IF(record_count != count, CONTACTS_ERROR_INVALID_PARAMETER,
4803 "record_count(%d) and count(%d) are not matched", record_count, count);
4805 ret = ctsvc_begin_trans();
4806 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "ctsvc_begin_trans Fail(%d)", ret);
4808 contacts_list_first(list);
4810 /* for performance. phone_number_get_normalized_number() can be called repeatedly below */
4811 phone_number_connect();
4813 ret = contacts_list_get_current_record_p(list, &record);
4814 if (CONTACTS_ERROR_NONE != ret) {
4815 /* LCOV_EXCL_START */
4816 ERR("contacts_list_get_current_record_p() Fail(%d)", ret);
4817 ctsvc_end_trans(false);
4818 phone_number_disconnect();
4820 /* LCOV_EXCL_STOP */
4823 ret = ctsvc_db_replace_record(record, ids[i++]);
4824 if (ret != CONTACTS_ERROR_NONE) {
4825 /* LCOV_EXCL_START */
4826 ERR("contacts_db_replace_record() Fail(%d)", ret);
4827 ctsvc_end_trans(false);
4828 phone_number_disconnect();
4830 /* LCOV_EXCL_STOP */
4832 } while (CONTACTS_ERROR_NONE == contacts_list_next(list));
4833 phone_number_disconnect();
4834 ret = ctsvc_end_trans(true);
4840 int ctsvc_db_replace_records(contacts_list_h list, int ids[], int count)
4842 int ret = CONTACTS_ERROR_NONE;
4843 ctsvc_db_plugin_info_s *plugin_info = NULL;
4845 RETV_IF(NULL == list, CONTACTS_ERROR_INVALID_PARAMETER);
4846 RETV_IF(NULL == ids, CONTACTS_ERROR_INVALID_PARAMETER);
4848 if ((plugin_info = ctsvc_db_get_plugin_info(((ctsvc_list_s*)list)->l_type))) {
4849 if (plugin_info->replace_records) {
4850 ret = plugin_info->replace_records(list, ids, count);
4855 return __ctsvc_db_replace_records(list, ids, count);
4858 int ctsvc_db_get_status(contacts_db_status_e *status)
4860 *status = __db_status;
4861 return CONTACTS_ERROR_NONE;
4864 void ctsvc_db_set_status(contacts_db_status_e status)
4866 __db_status = status;
4868 ctsvc_change_subject_publish_status(status);