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 "ctsvc_internal.h"
21 #include "ctsvc_db_schema.h"
22 #include "ctsvc_db_sqlite.h"
23 #include "ctsvc_db_plugin_person_helper.h"
24 #include "ctsvc_db_init.h"
25 #include "ctsvc_db_access_control.h"
26 #include "ctsvc_db_utils.h"
27 #include "ctsvc_list.h"
28 #include "ctsvc_db_query.h"
29 #include "ctsvc_record.h"
30 #include "ctsvc_normalize.h"
31 #include "ctsvc_notification.h"
32 #include "ctsvc_notify.h"
34 #ifdef _CONTACTS_IPC_SERVER
35 #include "ctsvc_server_change_subject.h"
39 static int __ctsvc_db_person_insert_record(contacts_record_h record, int *id)
42 ERR("Can not insert person record directly");
43 return CONTACTS_ERROR_INVALID_PARAMETER;
47 static int __ctsvc_db_person_get_record(int id, contacts_record_h *out_record)
51 char query[CTS_SQL_MAX_LEN] = {0};
52 contacts_record_h record;
56 snprintf(query, sizeof(query),
57 "SELECT persons.person_id, "
59 "_NORMALIZE_INDEX_(%s), "
61 "persons.image_thumbnail_path, "
62 "persons.ringtone_path, "
64 "persons.message_alert, "
68 "persons.has_phonenumber, "
70 "EXISTS(SELECT person_id FROM "CTS_TABLE_FAVORITES" WHERE person_id=persons.person_id) is_favorite, "
71 "(SELECT favorite_prio FROM "CTS_TABLE_FAVORITES" WHERE person_id=persons.person_id) favorite_prio "
72 "FROM "CTS_TABLE_PERSONS" "
73 "LEFT JOIN "CTS_TABLE_CONTACTS" "
74 "ON (name_contact_id = contacts.contact_id AND contacts.deleted = 0) "
75 "WHERE persons.person_id = %d",
76 ctsvc_get_display_column(), ctsvc_get_sort_name_column(), id);
78 ret = ctsvc_query_prepare(query, &stmt);
79 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
81 ret = ctsvc_stmt_step(stmt);
82 if (1 /*CTS_TRUE*/ != ret) {
84 ERR("ctsvc_stmt_step() Fail(%d)", ret);
85 ctsvc_stmt_finalize(stmt);
86 if (CONTACTS_ERROR_NONE == ret)
87 return CONTACTS_ERROR_NO_DATA;
92 ret = ctsvc_db_person_create_record_from_stmt(stmt, &record);
93 ctsvc_stmt_finalize(stmt);
95 if (CONTACTS_ERROR_NONE != ret) {
97 ERR("ctsvc_db_person_create_record_from_stmt() Fail(%d)", ret);
102 *out_record = record;
103 return CONTACTS_ERROR_NONE;
106 static int __ctsvc_db_person_update_record(contacts_record_h record)
110 cts_stmt stmt = NULL;
112 GSList *bind_text = NULL;
113 GSList *cursor = NULL;
114 char contact_query[CTS_SQL_MIN_LEN] = {0};
115 char query[CTS_SQL_MIN_LEN] = {0};
116 ctsvc_person_s *person = (ctsvc_person_s*)record;
117 const char *display_name = NULL;
118 int index_favorite = 0;
120 RETV_IF(NULL == person, CONTACTS_ERROR_INVALID_PARAMETER);
121 RETV_IF(person->person_id <= 0, CONTACTS_ERROR_INVALID_PARAMETER);
123 ret = ctsvc_begin_trans();
124 RETVM_IF(ret, ret, "ctsvc_begin_trans() Fail(%d)", ret);
126 snprintf(query, sizeof(query),
127 "SELECT person_id FROM "CTS_TABLE_PERSONS" WHERE person_id = %d", person->person_id);
128 ret = ctsvc_query_get_first_int_result(query, &person_id);
129 if (ret != CONTACTS_ERROR_NONE) {
130 /* LCOV_EXCL_START */
131 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
132 ctsvc_end_trans(false);
137 if (ctsvc_record_check_property_flag((ctsvc_record_s*)person, _contacts_person.display_contact_id, CTSVC_PROPERTY_FLAG_DIRTY)) {
138 /* check name_contact_id validation */
140 char check_query[CTS_SQL_MIN_LEN] = {0};
141 snprintf(check_query, sizeof(check_query), "SELECT contact_id, %s FROM "CTS_TABLE_CONTACTS
142 " WHERE person_id = %d AND contact_id = %d AND deleted = 0",
143 ctsvc_get_display_column(), person->person_id, person->name_contact_id);
144 ret = ctsvc_query_prepare(check_query, &stmt);
146 /* LCOV_EXCL_START */
147 ERR("ctsvc_query_prepare() Fail(%d)", ret);
148 ctsvc_end_trans(false);
153 ret = ctsvc_stmt_step(stmt);
155 if (CONTACTS_ERROR_NONE == ret) {
156 /* LCOV_EXCL_START */
157 ERR("the name_contact_id(%d) is not linked with person_id(%d)",
158 person->name_contact_id, person->person_id);
159 ctsvc_stmt_finalize(stmt);
160 ctsvc_end_trans(false);
161 return CONTACTS_ERROR_INVALID_PARAMETER;
164 /* LCOV_EXCL_START */
165 ERR("ctsvc_stmt_step() Fail(%d)", ret);
166 ctsvc_stmt_finalize(stmt);
167 ctsvc_end_trans(false);
172 temp = ctsvc_stmt_get_text(stmt, 0);
173 display_name = SAFE_STRDUP(temp);
175 ctsvc_stmt_finalize(stmt);
178 /* update favorite */
179 index_favorite = CTSVC_PROPERTY_PERSON_IS_FAVORITE & 0x000000FF;
180 if (person->base.properties_flags &&
181 ctsvc_record_check_property_flag((ctsvc_record_s*)person, index_favorite, CTSVC_PROPERTY_FLAG_DIRTY)) {
182 ret = ctsvc_db_person_set_favorite(person->person_id, person->is_favorite, true);
183 if (CONTACTS_ERROR_NONE != ret) {
184 /* LCOV_EXCL_START */
185 ERR("ctsvc_db_person_set_favorite() Fail(%d)", ret);
186 ctsvc_end_trans(false);
190 person->base.properties_flags[index_favorite] &= 0xFFFFFFFD; /* remove dirty bit */
191 ctsvc_set_contact_noti();
195 int ret = CONTACTS_ERROR_NONE;
196 char query[CTS_SQL_MAX_LEN] = {0};
197 char query_set[CTS_SQL_MIN_LEN] = {0, };
198 GSList *cursor = NULL;
200 if (CONTACTS_ERROR_NONE != (ret = ctsvc_db_create_set_query(record, &set, &bind_text))) break;
201 if (NULL == set || '\0' == *set)
203 len = snprintf(query_set, sizeof(query_set), "%s, changed_ver=%d", set, ctsvc_get_next_ver());
205 snprintf(query, sizeof(query), "UPDATE %s SET %s WHERE person_id = %d", CTS_TABLE_PERSONS, query_set, person->person_id);
207 ret = ctsvc_query_prepare(query, &stmt);
209 /* LCOV_EXCL_START */
210 ERR("ctsvc_query_prepare() Fail(%d)", ret);
217 for (cursor = bind_text, i = 1; cursor; cursor = cursor->next, i++) {
218 const char *text = cursor->data;
220 ctsvc_stmt_bind_text(stmt, i, text);
223 ret = ctsvc_stmt_step(stmt);
224 if (CONTACTS_ERROR_NONE != ret) {
225 /* LCOV_EXCL_START */
226 ERR("ctsvc_stmt_step() Fail(%d)", ret);
227 ctsvc_stmt_finalize(stmt);
231 ctsvc_stmt_finalize(stmt);
234 if (CONTACTS_ERROR_NONE != ret) {
235 ctsvc_end_trans(false);
236 CTSVC_RECORD_RESET_PROPERTY_FLAGS((ctsvc_record_s*)record);
240 for (cursor = bind_text; cursor; cursor = cursor->next) {
244 g_slist_free(bind_text);
249 len = snprintf(contact_query, sizeof(contact_query), "UPDATE "CTS_TABLE_CONTACTS" SET changed_ver=%d ", ctsvc_get_next_ver());
250 if (ctsvc_record_check_property_flag((ctsvc_record_s*)person, _contacts_person.ringtone_path, CTSVC_PROPERTY_FLAG_DIRTY))
251 len += snprintf(contact_query + len, sizeof(contact_query) - len, ", ringtone_path=? ");
252 if (ctsvc_record_check_property_flag((ctsvc_record_s*)person, _contacts_person.vibration, CTSVC_PROPERTY_FLAG_DIRTY))
253 len += snprintf(contact_query + len, sizeof(contact_query) - len, ", vibration=? ");
254 if (ctsvc_record_check_property_flag((ctsvc_record_s*)person, _contacts_person.message_alert, CTSVC_PROPERTY_FLAG_DIRTY))
255 len += snprintf(contact_query + len, sizeof(contact_query) - len, ", message_alert=? ");
256 snprintf(contact_query+len, sizeof(contact_query)-len, " WHERE person_id=%d AND deleted = 0", person->person_id);
258 ret = ctsvc_query_prepare(contact_query, &stmt);
260 /* LCOV_EXCL_START */
261 ERR("ctsvc_query_prepare() Fail(%d)", ret);
262 ctsvc_end_trans(false);
263 CTSVC_RECORD_RESET_PROPERTY_FLAGS((ctsvc_record_s*)record);
267 for (cursor = bind_text; cursor; cursor = cursor->next) {
271 g_slist_free(bind_text);
278 if (ctsvc_record_check_property_flag((ctsvc_record_s*)person, _contacts_person.ringtone_path, CTSVC_PROPERTY_FLAG_DIRTY)) {
279 if (person->ringtone_path)
280 ctsvc_stmt_bind_text(stmt, i, person->ringtone_path);
283 if (ctsvc_record_check_property_flag((ctsvc_record_s*)person, _contacts_person.vibration, CTSVC_PROPERTY_FLAG_DIRTY)) {
284 if (person->vibration)
285 ctsvc_stmt_bind_text(stmt, i, person->vibration);
288 if (ctsvc_record_check_property_flag((ctsvc_record_s*)person, _contacts_person.message_alert, CTSVC_PROPERTY_FLAG_DIRTY)) {
289 if (person->message_alert)
290 ctsvc_stmt_bind_text(stmt, i, person->message_alert);
294 ret = ctsvc_stmt_step(stmt);
295 if (CONTACTS_ERROR_NONE != ret) {
296 /* LCOV_EXCL_START */
297 ERR("ctsvc_stmt_step() Fail(%d)", ret);
298 ctsvc_stmt_finalize(stmt);
299 ctsvc_end_trans(false);
300 CTSVC_RECORD_RESET_PROPERTY_FLAGS((ctsvc_record_s*)record);
304 for (cursor = bind_text; cursor; cursor = cursor->next) {
308 g_slist_free(bind_text);
313 ctsvc_stmt_finalize(stmt);
315 CTSVC_RECORD_RESET_PROPERTY_FLAGS((ctsvc_record_s*)record);
319 for (cursor = bind_text; cursor; cursor = cursor->next) {
323 g_slist_free(bind_text);
326 /* update person display_name */
329 person->display_name = SAFE_STRDUP(display_name);
330 ret = ctsvc_normalize_index(person->display_name, &temp);
332 person->display_name_index = strdup(temp);
335 /* TODO : update name primary_default?? */
337 ctsvc_set_person_noti();
338 #ifdef _CONTACTS_IPC_SERVER
339 ctsvc_change_subject_add_changed_person_id(CONTACTS_CHANGE_UPDATED, person->person_id);
342 ret = ctsvc_end_trans(true);
343 RETVM_IF(ret < CONTACTS_ERROR_NONE, ret, "ctsvc_end_trans() Fail(%d)", ret);
345 return CONTACTS_ERROR_NONE;
348 static int __ctsvc_db_person_delete_record(int id)
350 int ret, rel_changed;
352 char query[CTS_SQL_MAX_LEN] = {0};
354 int *addressbook_ids = NULL;
357 ret = ctsvc_begin_trans();
358 RETVM_IF(ret, ret, "ctsvc_begin_trans() Fail(%d)", ret);
360 snprintf(query, sizeof(query),
361 "SELECT person_id FROM "CTS_TABLE_PERSONS" WHERE person_id = %d", id);
362 ret = ctsvc_query_get_first_int_result(query, &person_id);
363 if (ret != CONTACTS_ERROR_NONE) {
364 /* LCOV_EXCL_START */
365 ERR("ctsvc_query_get_first_int_result() Fail(%d)", ret);
366 ctsvc_end_trans(false);
371 version = ctsvc_get_next_ver();
372 snprintf(query, sizeof(query),
373 "UPDATE "CTS_TABLE_GROUPS" SET member_changed_ver=%d "
374 "WHERE group_id IN (SELECT distinct group_id "
375 "FROM "CTS_TABLE_CONTACTS" C, "CTS_TABLE_GROUP_RELATIONS" R "
376 "ON C.contact_id=R.contact_id AND R.deleted = 0 AND C.deleted = 0 "
377 "WHERE person_id = %d)",
379 ret = ctsvc_query_exec(query);
380 if (CONTACTS_ERROR_NONE != ret) {
381 /* LCOV_EXCL_START */
382 ERR("ctsvc_query_exec() Fail(%d)", ret);
383 ctsvc_end_trans(false);
388 rel_changed = ctsvc_db_change();
390 ret = ctsvc_get_write_permitted_addressbook_ids(&addressbook_ids, &count);
391 if (CONTACTS_ERROR_INTERNAL == ret) {
392 /* LCOV_EXCL_START */
393 ERR("ctsvc_get_write_permitted_addressbook_ids() Fail(%d)", ret);
394 ctsvc_end_trans(false);
399 if (addressbook_ids && 0 < count) {
401 int len = snprintf(query, sizeof(query),
402 "UPDATE "CTS_TABLE_CONTACTS" SET deleted = 1, person_id = 0, changed_ver = %d "
403 "WHERE person_id = %d AND (",
406 for (i = 0; i < count; i++) {
408 len += snprintf(query+len, sizeof(query) + len, "addressbook_id = %d ", addressbook_ids[i]);
410 len += snprintf(query+len, sizeof(query) + len, "OR addressbook_id = %d ", addressbook_ids[i]);
412 len += snprintf(query+len, sizeof(query)-len, ") ");
414 ret = ctsvc_query_exec(query);
415 if (CONTACTS_ERROR_NONE != ret) {
416 /* LCOV_EXCL_START */
417 ERR("ctsvc_query_exec() Fail(%d)", ret);
418 ctsvc_end_trans(false);
419 free(addressbook_ids);
424 free(addressbook_ids);
426 /* access control logic should be enabled */
427 snprintf(query, sizeof(query),
428 "UPDATE "CTS_TABLE_CONTACTS" SET person_id = 0, changed_ver = %d WHERE person_id = %d",
430 ret = ctsvc_query_exec(query);
431 if (CONTACTS_ERROR_NONE != ret) {
432 /* LCOV_EXCL_START */
433 ERR("ctsvc_query_exec() Fail(%d)", ret);
434 ctsvc_end_trans(false);
440 * images are deleted by db trigger callback function
441 * in ctsvc_db_image_delete_callback
443 snprintf(query, sizeof(query), "DELETE FROM "CTS_TABLE_PERSONS" WHERE person_id = %d", id);
444 ret = ctsvc_query_exec(query);
445 if (CONTACTS_ERROR_NONE != ret) {
446 /* LCOV_EXCL_START */
447 ERR("ctsvc_query_exec() Fail(%d)", ret);
448 ctsvc_end_trans(false);
453 ctsvc_set_contact_noti();
454 ctsvc_set_person_noti();
456 ctsvc_set_group_rel_noti();
458 ret = ctsvc_end_trans(true);
459 if (ret < CONTACTS_ERROR_NONE) {
460 /* LCOV_EXCL_START */
461 ERR("ctsvc_end_trans() Fail(%d)", ret);
465 return CONTACTS_ERROR_NONE;
469 static int __ctsvc_db_person_get_all_records(int offset, int limit, contacts_list_h *out_list)
474 char query[CTS_SQL_MAX_LEN] = {0};
475 contacts_list_h list;
477 len = snprintf(query, sizeof(query),
480 "_NORMALIZE_INDEX_(%s), "
482 "image_thumbnail_path, "
493 "FROM "CTSVC_DB_VIEW_PERSON,
494 ctsvc_get_display_column(), ctsvc_get_sort_name_column());
496 len += snprintf(query+len, sizeof(query)-len, " ORDER BY %s", ctsvc_get_sort_column());
499 len += snprintf(query+len, sizeof(query)-len, " LIMIT %d", limit);
501 len += snprintf(query+len, sizeof(query)-len, " OFFSET %d", offset);
504 ret = ctsvc_query_prepare(query, &stmt);
505 RETVM_IF(NULL == stmt, ret, "ctsvc_query_prepare() Fail(%d)", ret);
507 contacts_list_create(&list);
508 while ((ret = ctsvc_stmt_step(stmt))) {
509 contacts_record_h record;
511 /* LCOV_EXCL_START */
512 ERR("ctsvc_stmt_step() Fail(%d)", ret);
513 ctsvc_stmt_finalize(stmt);
514 contacts_list_destroy(list, true);
518 ret = ctsvc_db_person_create_record_from_stmt(stmt, &record);
519 if (CONTACTS_ERROR_NONE != ret) {
520 /* LCOV_EXCL_START */
521 ERR("ctsvc_db_person_create_record_from_stmt() Fail(%d)", ret);
522 ctsvc_stmt_finalize(stmt);
523 contacts_list_destroy(list, true);
528 ctsvc_list_prepend(list, record);
530 ctsvc_stmt_finalize(stmt);
531 ctsvc_list_reverse(list);
534 return CONTACTS_ERROR_NONE;
537 static int __ctsvc_db_person_get_records_with_query(contacts_query_h query, int offset, int limit, contacts_list_h *out_list)
542 ctsvc_query_s *s_query;
544 contacts_list_h list;
545 ctsvc_person_s *person;
546 char full_path[CTSVC_IMG_FULL_PATH_SIZE_MAX] = {0};
548 RETV_IF(NULL == query, CONTACTS_ERROR_INVALID_PARAMETER);
549 s_query = (ctsvc_query_s*)query;
551 ret = ctsvc_db_make_get_records_query_stmt(s_query, offset, limit, &stmt);
552 RETVM_IF(CONTACTS_ERROR_NONE != ret, ret, "ctsvc_db_make_get_records_query_stmt fail(%d)", ret);
554 contacts_list_create(&list);
555 while ((ret = ctsvc_stmt_step(stmt))) {
556 contacts_record_h record;
558 /* LCOV_EXCL_START */
559 ERR("ctsvc_stmt_step() Fail(%d)", ret);
560 ctsvc_stmt_finalize(stmt);
561 contacts_list_destroy(list, true);
566 contacts_record_create(_contacts_person._uri, &record);
567 person = (ctsvc_person_s*)record;
568 if (0 == s_query->projection_count) {
569 field_count = s_query->property_count;
571 field_count = s_query->projection_count;
573 int err = ctsvc_record_set_projection_flags(record, s_query->projection,
574 s_query->projection_count, s_query->property_count);
575 if (CONTACTS_ERROR_NONE != err)
576 ASSERT_NOT_REACHED("To set projection is Fail.\n");
579 for (i = 0; i < field_count; i++) {
582 if (0 == s_query->projection_count)
583 property_id = s_query->properties[i].property_id;
585 property_id = s_query->projection[i];
587 switch (property_id) {
588 case CTSVC_PROPERTY_PERSON_ID:
589 person->person_id = ctsvc_stmt_get_int(stmt, i);
591 case CTSVC_PROPERTY_PERSON_DISPLAY_NAME:
592 temp = ctsvc_stmt_get_text(stmt, i);
593 free(person->display_name);
594 person->display_name = SAFE_STRDUP(temp);
596 case CTSVC_PROPERTY_PERSON_DISPLAY_NAME_INDEX:
597 temp = ctsvc_stmt_get_text(stmt, i);
598 free(person->display_name_index);
599 person->display_name_index = SAFE_STRDUP(temp);
601 case CTSVC_PROPERTY_PERSON_DISPLAY_CONTACT_ID:
602 person->name_contact_id = ctsvc_stmt_get_int(stmt, i);
604 case CTSVC_PROPERTY_PERSON_RINGTONE:
605 temp = ctsvc_stmt_get_text(stmt, i);
606 free(person->ringtone_path);
607 person->ringtone_path = SAFE_STRDUP(temp);
609 case CTSVC_PROPERTY_PERSON_IMAGE_THUMBNAIL:
610 temp = ctsvc_stmt_get_text(stmt, i);
612 snprintf(full_path, sizeof(full_path), "%s/%s", CTSVC_CONTACT_IMG_FULL_LOCATION, temp);
613 free(person->image_thumbnail_path);
614 person->image_thumbnail_path = strdup(full_path);
617 case CTSVC_PROPERTY_PERSON_IS_FAVORITE:
618 person->is_favorite = ctsvc_stmt_get_int(stmt, i);
620 case CTSVC_PROPERTY_PERSON_HAS_PHONENUMBER:
621 person->has_phonenumber = ctsvc_stmt_get_int(stmt, i);
623 case CTSVC_PROPERTY_PERSON_HAS_EMAIL:
624 person->has_email = ctsvc_stmt_get_int(stmt, i);
626 case CTSVC_PROPERTY_PERSON_LINK_COUNT:
627 person->link_count = ctsvc_stmt_get_int(stmt, i);
629 case CTSVC_PROPERTY_PERSON_ADDRESSBOOK_IDS:
630 temp = ctsvc_stmt_get_text(stmt, i);
631 free(person->addressbook_ids);
632 person->addressbook_ids = SAFE_STRDUP(temp);
634 case CTSVC_PROPERTY_PERSON_VIBRATION:
635 temp = ctsvc_stmt_get_text(stmt, i);
636 free(person->vibration);
637 person->vibration = SAFE_STRDUP(temp);
639 case CTSVC_PROPERTY_PERSON_STATUS:
640 temp = ctsvc_stmt_get_text(stmt, i);
641 free(person->status);
642 person->status = SAFE_STRDUP(temp);
644 case CTSVC_PROPERTY_PERSON_MESSAGE_ALERT:
645 temp = ctsvc_stmt_get_text(stmt, i);
646 free(person->message_alert);
647 person->message_alert = SAFE_STRDUP(temp);
649 case CTSVC_PROPERTY_PERSON_FAVORITE_PRIORITY:
650 person->favorite_prio = ctsvc_stmt_get_dbl(stmt, i);
656 ctsvc_list_prepend(list, record);
658 ctsvc_stmt_finalize(stmt);
659 ctsvc_list_reverse(list);
663 return CONTACTS_ERROR_NONE;
666 ctsvc_db_plugin_info_s ctsvc_db_plugin_person = {
667 .is_query_only = false,
668 .insert_record = __ctsvc_db_person_insert_record,
669 .get_record = __ctsvc_db_person_get_record,
670 .update_record = __ctsvc_db_person_update_record,
671 .delete_record = __ctsvc_db_person_delete_record,
672 .get_all_records = __ctsvc_db_person_get_all_records,
673 .get_records_with_query = __ctsvc_db_person_get_records_with_query,
674 .insert_records = NULL,
675 .update_records = NULL,
676 .delete_records = NULL,
678 .get_count_with_query = NULL,
679 .replace_record = NULL,
680 .replace_records = NULL,