Improve search API 47/9847/2
authorDonghee Ye <donghee.ye@samsung.com>
Sat, 7 Sep 2013 10:57:53 +0000 (19:57 +0900)
committerDonghee Ye <donghee.ye@samsung.com>
Tue, 17 Sep 2013 05:49:12 +0000 (14:49 +0900)
- Add contacts_db_search_records_with_range API (range: name, number, data)
- Fix search query for special character (sqlite keyword '_', '%', '\')
- Fix search contact (diacritical case)
- Change keyword : full-width -> half-width number

Change-Id: Iccb3b3f51b547683a320fa7fe4bd1abe1a330894

client/ctsvc_client_db.c
common/ctsvc_normalize.c
common/ctsvc_normalize.h
common/ipc/ctsvc_ipc_define.h
include/contacts_db.h
include/contacts_types.h
native/ctsvc_db_plugin_contact.c
native/ctsvc_db_query.c
server/ctsvc_ipc_server.c
server/ctsvc_ipc_server.h
server/ctsvc_server.c

index f7c8037..cc6b2a4 100644 (file)
@@ -1346,6 +1346,74 @@ API int contacts_db_search_records(const char* view_uri, const char *keyword,
        return ret;
 }
 
+API int contacts_db_search_records_with_range(const char* view_uri, const char *keyword,
+               int offset, int limit, int range, contacts_list_h* out_list)
+{
+       int ret = CONTACTS_ERROR_NONE;
+       pims_ipc_data_h indata = NULL;
+       pims_ipc_data_h outdata = NULL;
+
+       RETVM_IF(out_list == NULL, CONTACTS_ERROR_INVALID_PARAMETER, "list is NULL");
+       *out_list = NULL;
+       RETVM_IF(range == 0, CONTACTS_ERROR_INVALID_PARAMETER, "range is 0");
+       RETVM_IF(ctsvc_get_ipc_handle() == NULL, CONTACTS_ERROR_IPC, "contacts not connected");
+
+       indata = pims_ipc_data_create(0);
+       if (indata == NULL) {
+               CTS_ERR("ipc data created fail !");
+               return CONTACTS_ERROR_OUT_OF_MEMORY;
+       }
+
+       ret = ctsvc_ipc_marshal_string(view_uri, indata);
+       if (ret != CONTACTS_ERROR_NONE) {
+               CTS_ERR("marshal fail");
+               goto DATA_FREE;
+       }
+       ret = ctsvc_ipc_marshal_string(keyword, indata);
+       if (ret != CONTACTS_ERROR_NONE) {
+               CTS_ERR("marshal fail");
+               goto DATA_FREE;
+       }
+       ret = ctsvc_ipc_marshal_int(offset, indata);
+       if (ret != CONTACTS_ERROR_NONE) {
+               CTS_ERR("marshal fail");
+               goto DATA_FREE;
+       }
+       ret = ctsvc_ipc_marshal_int(limit, indata);
+       if (ret != CONTACTS_ERROR_NONE) {
+               CTS_ERR("marshal fail");
+               goto DATA_FREE;
+       }
+       ret = ctsvc_ipc_marshal_int(range, indata);
+       if (ret != CONTACTS_ERROR_NONE) {
+               CTS_ERR("marshal fail");
+               goto DATA_FREE;
+       }
+
+       if (ctsvc_ipc_call(CTSVC_IPC_DB_MODULE, CTSVC_IPC_SERVER_DB_SEARCH_RECORDS_WITH_RANGE, indata, &outdata) != 0) {
+               CTS_ERR("ctsvc_ipc_call failed");
+               pims_ipc_data_destroy(indata);
+               return CONTACTS_ERROR_IPC;
+       }
+
+       pims_ipc_data_destroy(indata);
+
+       if (outdata) {
+               unsigned int size = 0;
+               ret = *(int*) pims_ipc_data_get(outdata,&size);
+
+               if (ret == CONTACTS_ERROR_NONE)
+                       ret = ctsvc_ipc_unmarshal_list(outdata,out_list);
+               pims_ipc_data_destroy(outdata);
+       }
+
+       return ret;
+
+DATA_FREE:
+       free(indata);
+       return ret;
+}
+
 API int contacts_db_search_records_with_query(contacts_query_h query, const char *keyword,
                int offset, int limit, contacts_list_h* out_list)
 {
index a32f0d1..53aa893 100644 (file)
@@ -406,7 +406,7 @@ static inline int __ctsvc_collation_str(const char *src, char **dest)
 int ctsvc_collation_str(char *src, char **dest)
 {
        int ret;
-       char temp[strlen(src) + 1];
+       char temp[SAFE_STRLEN(src) + 1];
 
        ret = __ctsvc_remove_special_char(src, temp, sizeof(temp));
        WARN_IF(ret < CONTACTS_ERROR_NONE, "__ctsvc_remove_special_char() Failed(%d)", ret);
@@ -507,6 +507,164 @@ DATA_FREE:
        return ret;
 }
 
+
+
+////// contacts_normalized_strstr API should be separated from contacts-service /////////////////////////////////////////////////////////////
+#define CTSVC_COMPARE_BETWEEN(left_range, value, right_range) (((left_range) <= (value)) && ((value) <= (right_range)))
+
+static int __ctsvc_convert_halfwidth_ascii_and_symbol(const char *src, UChar *dest, int dest_size, int* str_size)
+{
+       int i;
+       int32_t size = dest_size;
+       UErrorCode status = 0;
+
+       u_strFromUTF8(dest, dest_size, &size, src, strlen(src), &status);
+       if (U_FAILURE(status)) {
+               CTS_ERR("u_strFromUTF8() Failed(%s)", u_errorName(status));
+               return CONTACTS_ERROR_SYSTEM;
+       }
+
+       *str_size = size;
+
+       // full width -> half width
+       for ( i=0; i < size; i++ ) {
+               // FF00 ~ FF60: Fullwidth ASCII variants
+               if (CTSVC_COMPARE_BETWEEN((UChar)0xFF00, dest[i], (UChar)0xFF60)) {
+                       int unicode_value1 = 0;
+                       int unicode_value2 = 0;
+                       unicode_value1 = 0x0;
+                       unicode_value2 = (0xFF & dest[i]) + 0x20;
+                       dest[i] = unicode_value1 << 8 | unicode_value2;
+               }
+               // FFE0~FFE6: Fullwidth symbol variants
+               else if (CTSVC_COMPARE_BETWEEN((UChar)0xFFE0, dest[i], (UChar)0xFFE6)) {
+                       if( dest[i] == (UChar)0xFFE0 )
+                       {
+                               dest[i] = (UChar)0x00A2;
+                       }
+                       else if( dest[i] == (UChar)0xFFE1 )
+                       {
+                               dest[i] = (UChar)0x00A3;
+                       }
+                       else if( dest[i] == (UChar)0xFFE2 )
+                       {
+                               dest[i] = (UChar)0x00AC;
+                       }
+                       else if( dest[i] == (UChar)0xFFE3 )
+                       {
+                               dest[i] = (UChar)0x00AF;
+                       }
+                       else if( dest[i] == (UChar)0xFFE4 )
+                       {
+                               dest[i] = (UChar)0x00A6;
+                       }
+                       else if( dest[i] == (UChar)0xFFE5 )
+                       {
+                               dest[i] = (UChar)0x00A5;
+                       }
+                       else if( dest[i] == (UChar)0xFFE6 )
+                       {
+                               dest[i] = (UChar)0x20A9;
+                       }
+                       else
+                       {
+
+                       }
+               }
+               else {
+
+               }
+
+       }
+
+       dest[size] = 0x00;
+       return CONTACTS_ERROR_NONE;
+}
+
+static bool __ctsvc_is_phonenumber_halfwidth(const char* keyword)
+{
+       int i;
+       int len = strlen(keyword);
+
+       // TODO: we should add predicate including '+'
+       // TODO: finally, we try to check the number with regular expression.
+       for(i=0; i<len; i++) {
+               if (keyword[i] < '0' || keyword[i] > '9') {
+                       CTS_ERR("keyword[%d]: %c is not number)", i, keyword[i]);
+                       return false;
+               }
+       }
+       return true;
+}
+
+#define LARGE_BUFFER_SIZE 100
+
+static bool __ctsvc_is_phonenumber_fullwidth(const char* keyword)
+{
+       UChar unicodes[LARGE_BUFFER_SIZE];
+
+       int size = 0;
+       if( __ctsvc_convert_halfwidth_ascii_and_symbol(keyword, unicodes, LARGE_BUFFER_SIZE, &size) != CONTACTS_ERROR_NONE )
+       {
+               CTS_ERR("convert failed! %s", keyword);
+
+               return false;
+       }
+
+       int i = 0;
+       for( i = 0; i < size; i++ )
+       {
+               if (unicodes[i] < (UChar)0xFF10 || unicodes[i] > (UChar)0xFF19 )
+               {
+                       CTS_ERR("keyword[%d]: 0x%0x is not number)", i, unicodes[i] );
+
+                       return false;
+               }
+       }
+
+       return true;
+}
+
+bool ctsvc_is_phonenumber(const char* src)
+{
+       return ( __ctsvc_is_phonenumber_halfwidth(src) || __ctsvc_is_phonenumber_fullwidth(src) );
+}
+
+int ctsvc_get_halfwidth_string(const char *src, char** dest, int* dest_size)
+{
+       UChar unicodes[LARGE_BUFFER_SIZE];
+       int ustr_size = 0;
+
+       if( __ctsvc_convert_halfwidth_ascii_and_symbol(src, unicodes, LARGE_BUFFER_SIZE, &ustr_size) != CONTACTS_ERROR_NONE )
+       {
+               CTS_ERR("convert to halfwidth failed! %s ", src);
+
+               return CONTACTS_ERROR_SYSTEM;
+       }
+
+       UErrorCode status = 0;
+
+       // pre-flighting
+       int size = 0;
+       u_strToUTF8(NULL, 0, &size, unicodes, -1, &status);
+       status = U_ZERO_ERROR;
+       *dest = calloc(1, sizeof(char) * (size+1));
+
+       u_strToUTF8(*dest, size+1, dest_size, unicodes, ustr_size, &status);
+       if (U_FAILURE(status)) {
+               CTS_ERR("u_strToUTF8() Failed(%s)", u_errorName(status));
+
+               free(*dest);
+               *dest = NULL;
+               *dest_size = 0;
+
+               return CONTACTS_ERROR_SYSTEM;
+       }
+
+       return CONTACTS_ERROR_NONE;
+}
+
+
 static int __ctsvc_normalize_str_to_unicode(const char *src, int src_size, UChar *dest, int dest_size)
 {
        int ret;
@@ -569,9 +727,7 @@ static void __ctsvc_convert_japanese_group_letter(char *dest)
        unicode_value1 = (0xFF00 & (tmp_result[0])) >> 8;
        unicode_value2 = (0xFF & (tmp_result[0]));
 
-
-       for(i=0; i < 13; i++)
-       {
+       for(i=0; i < 13; i++) {
                if (hiragana_group[i].start <= unicode_value2
                                && unicode_value2 <= hiragana_group[i].end)
                        result[0] = hiragana_group[i].letter;
index 765b295..d248c5e 100644 (file)
@@ -74,4 +74,7 @@ int ctsvc_normalize_str(const char *src, char **dest);
 int ctsvc_collation_str(char *src, char **dest);\r
 int ctsvc_normalize_index(const char *src, char **dest);\r
 \r
+bool ctsvc_is_phonenumber(const char* src);\r
+int ctsvc_get_halfwidth_string(const char *src, char** dest, int* dest_size);\r
+\r
 #endif /*  __TIZEN_SOCIAL_CTSVC_NORMALIZE_H__ */\r
index c2d28c3..226a3e8 100644 (file)
@@ -56,6 +56,7 @@
 #define CTSVC_IPC_SERVER_DB_CHANGES_BY_VERSION        "changes_by_version"
 #define CTSVC_IPC_SERVER_DB_GET_CURRENT_VERSION       "get_current_version"
 #define CTSVC_IPC_SERVER_DB_SEARCH_RECORDS            "search_records"
+#define CTSVC_IPC_SERVER_DB_SEARCH_RECORDS_WITH_RANGE          "search_records_with_range"
 #define CTSVC_IPC_SERVER_DB_SEARCH_RECORDS_WITH_QUERY    "search_records_with_query"
 
 #define CTSVC_IPC_SERVER_ACTIVITY_DELETE_BY_CONTACT_ID   "activity_delete_by_contact_id"
index b06c9e7..c8a1fa2 100755 (executable)
@@ -599,6 +599,32 @@ API int contacts_db_search_records(const char* view_uri, const char *keyword, in
 API int contacts_db_search_records_with_query(contacts_query_h query, const char *keyword, int offset, int limit, contacts_list_h* record_list);
 
 /**
+ * @brief       Retrieves records with a keyword in range
+ *
+ * @remarks     @a record_list must be released with contacts_list_destroy() by you. \n
+ * This API works only for \ref CAPI_SOCIAL_CONTACTS_SVC_VIEW_MODULE_contacts_person and \ref CAPI_SOCIAL_CONTACTS_SVC_VIEW_MODULE_contacts_person_grouprel.
+ *
+ * @param[in]   view_uri                       The view URI to get records
+ * @param[in]   keyword                        Thekeyword
+ * @param[in]   offset                 The index to get results from which index
+ * @param[in]   limit                  The number to limit results
+ * @param[in]   range                  The search range
+ * @param[out]  record_list            The record list
+ *
+ * @return  0 on success, otherwise a negative error value.
+ * @retval  #CONTACTS_ERROR_NONE                               Successful
+ * @retval  #CONTACTS_ERROR_OUT_OF_MEMORY              Out of memory
+ * @retval  #CONTACTS_ERROR_INVALID_PARAMETER  Invalid parameter
+ * @retval  #CONTACTS_ERROR_DB                                 Database operation failure
+ *
+ * @pre    This function requires an open connection to contacts service by contacts_connect2().
+ *
+ * @see contacts_connect2()
+ * @see contacts_list_destroy()
+ */
+API int contacts_db_search_records_with_range(const char* view_uri, const char *keyword, int offset, int limit, int range, contacts_list_h* record_list);
+
+/**
  * @brief       Gets records count of a specific view
  *
  * @param[in]   view_uri               The view URI to get records
index f491877..e87690f 100644 (file)
@@ -225,6 +225,12 @@ typedef enum {
        CONTACTS_RELATIONSHIP_TYPE_CUSTOM, /**< .*/
 }contacts_relationship_type_e;
 
+typedef enum {
+       CONTACTS_SEARCH_RANGE_NAME = 0x00000001,         /**< .*/
+       CONTACTS_SEARCH_RANGE_NUMBER  = 0x00000002,      /**< .*/
+       CONTACTS_SEARCH_RANGE_DATA  = 0x00000004,        /**< .*/
+}contacts_search_range_e;
+
 /**
  * @}
  */
index 887616f..7855e12 100644 (file)
@@ -473,16 +473,22 @@ static inline void __ctsvc_contact_get_initial(char *src, char *dest, int dest_s
        int i, j=0;
        bool bFirst = true;
        int len = strlen(src);
-       for(i = 0; i < len && j < (dest_size-1); i++)
+       for(i = 0; i < len && j < (dest_size-1);)
        {
                if (src[i] == ' ') {
                        bFirst=true;
+                       i++;
                } else if (bFirst) {
-                       dest[j++] = src[i];
+                       int char_len = ctsvc_check_utf8(src[i]);
+                       int k;
+                       for (k=0;k<char_len;k++)
+                               dest[j++] = src[i++];
                        if (!pinyin)
                                dest[j++] = ' ';
                        bFirst = false;
                }
+               else
+                       i++;
        }
        CTS_DBG("src(%s) dest(%s)", src, dest);
 }
index 72b2c45..b6acab2 100755 (executable)
@@ -222,12 +222,34 @@ static inline int __ctsvc_db_create_lli_condition(ctsvc_composite_filter_s *com_
        return CONTACTS_ERROR_NONE;
 }
 
+#define CTSVC_DB_ESCAPE_CHAR   '\\'
+
+static char * __ctsvc_db_get_str_with_escape(char *str, int len, bool with_escape)
+{
+       int i, j = 0;
+       char temp_str[len*2+1];
+
+       if (false == with_escape)
+               return strdup(str);
+
+       for(i=0;i<len;i++) {
+               if (str[i] == '\'' || str[i] == '_' || str[i] == '%' || str[i] == '\\') {
+                       temp_str[j++] = CTSVC_DB_ESCAPE_CHAR;
+               }
+               temp_str[j++] = str[i];
+       }
+       temp_str[j] = '\0';
+
+       return strdup(temp_str);
+}
+
 static inline int __ctsvc_db_create_str_condition(ctsvc_composite_filter_s *com_filter,
                ctsvc_attribute_filter_s *filter, char **condition, GSList **bind_text)
 {
        int ret;
        const char *field_name;
        char out_cond[CTS_SQL_MAX_LEN] = {0};
+       bool with_escape = true;
 
        *condition = NULL;
 
@@ -242,18 +264,19 @@ static inline int __ctsvc_db_create_str_condition(ctsvc_composite_filter_s *com_
        switch(filter->match) {
        case CONTACTS_MATCH_EXACTLY:
                snprintf(out_cond, sizeof(out_cond), "%s = ?", field_name);
+               with_escape = false;
                break;
        case CONTACTS_MATCH_FULLSTRING:
-               snprintf(out_cond, sizeof(out_cond), "%s LIKE ?", field_name);
+               snprintf(out_cond, sizeof(out_cond), "%s LIKE ? ESCAPE '%c'", field_name, CTSVC_DB_ESCAPE_CHAR);
                break;
        case CONTACTS_MATCH_CONTAINS:
-               snprintf(out_cond, sizeof(out_cond), "%s LIKE ('%%' || ? || '%%')", field_name);
+               snprintf(out_cond, sizeof(out_cond), "%s LIKE ('%%' || ? || '%%') ESCAPE '%c'", field_name, CTSVC_DB_ESCAPE_CHAR);
                break;
        case CONTACTS_MATCH_STARTSWITH:
-               snprintf(out_cond, sizeof(out_cond), "%s LIKE ( ? || '%%')", field_name);
+               snprintf(out_cond, sizeof(out_cond), "%s LIKE ( ? || '%%') ESCAPE '%c'", field_name, CTSVC_DB_ESCAPE_CHAR);
                break;
        case CONTACTS_MATCH_ENDSWITH:
-               snprintf(out_cond, sizeof(out_cond), "%s LIKE ('%%' || ?)", field_name);
+               snprintf(out_cond, sizeof(out_cond), "%s LIKE ('%%' || ?) ESCAPE '%c'", field_name, CTSVC_DB_ESCAPE_CHAR);
                break;
        case CONTACTS_MATCH_EXISTS:
                snprintf(out_cond, sizeof(out_cond), "%s IS NOT NULL", field_name);
@@ -268,12 +291,12 @@ static inline int __ctsvc_db_create_str_condition(ctsvc_composite_filter_s *com_
                        char dest[strlen(filter->value.s)+1];
                        ret = ctsvc_normalize_number(filter->value.s, dest, sizeof(dest), ctsvc_get_phonenumber_min_match_digit());
                        if (CONTACTS_ERROR_NONE == ret)
-                               *bind_text = g_slist_append(*bind_text, strdup(dest));
+                               *bind_text = g_slist_append(*bind_text, __ctsvc_db_get_str_with_escape(dest, strlen(dest), with_escape));
                        else
                                return CONTACTS_ERROR_INVALID_PARAMETER;
                }
                else
-                       *bind_text = g_slist_append(*bind_text, strdup(filter->value.s));
+                       *bind_text = g_slist_append(*bind_text, __ctsvc_db_get_str_with_escape(filter->value.s, strlen(filter->value.s), with_escape));
        }
        *condition = strdup(out_cond);
        return CONTACTS_ERROR_NONE;
@@ -613,7 +636,7 @@ int ctsvc_db_make_get_records_query_stmt(ctsvc_query_s *s_query, int offset, int
                        return ret;
                }
                if (condition && *condition)
-                       len += snprintf(query+len, sizeof(query)-len, " WHERE %s", condition);
+                       len += snprintf(query+len, sizeof(query)-len, " WHERE (%s)", condition);
        }
 
        if (__ctsvc_db_view_has_display_name(s_query->view_uri, s_query->properties, s_query->property_count))
@@ -738,7 +761,7 @@ static int __ctsvc_db_get_records_with_query_exec(ctsvc_query_s *query, int offs
        cts_stmt_finalize(stmt);
        ctsvc_list_reverse(list);
 
-       *out_list = (contacts_list_h)list;
+       *out_list = list;
        return CONTACTS_ERROR_NONE;
 }
 
@@ -871,40 +894,87 @@ static char* __ctsvc_db_make_search_keyword(const char *keyword)
        }
 }
 
-static int __ctsvc_db_append_search_query(const char *keyword, char *query, int size)
+static int __ctsvc_db_append_search_query_range(char *query, int size, int range, char *name, char *number, char *data)
 {
-       bool phonenumber = false;
+       bool first = true;
+       int ret = 0;
+       ret = snprintf(query, size, "'");
+       if (range & CONTACTS_SEARCH_RANGE_NAME) {
+               ret += snprintf(query+ret, size-ret, "name:%s", name);
+               first = false;
+       }
+
+       if (range & CONTACTS_SEARCH_RANGE_NUMBER) {
+               if (first == false)
+                       ret += snprintf(query+ret, size-ret, " OR ");
+               ret += snprintf(query+ret, size-ret, "number:%s", number);
+               first = false;
+       }
+
+       if (range & CONTACTS_SEARCH_RANGE_DATA) {
+               if (first == false)
+                       ret += snprintf(query+ret, size-ret, " OR ");
+               ret += snprintf(query+ret, size-ret, "data:%s", data);
+               first = false;
+       }
+
+       ret += snprintf(query+ret, size-ret, "' ");
+       return ret;
+}
+
+static int __ctsvc_db_append_search_query(const char *src, char *query, int size, int range)
+{
+       bool phonenumber = true;
        int ret;
-       int len = 0, i;
+       int i = 0;
+       int temp_len = 0;
 
-       len = strlen(keyword);
-       phonenumber = true;
-       for(i=0; i<len; i++) {
-               if (keyword[i] < '0' || keyword[i] > '9') {
-                       phonenumber = false;
-                       break;
-               }
+       if( ctsvc_is_phonenumber(src) == false)
+       {
+               CTS_DBG("src is not phone number %s", src);
+               phonenumber = false;
        }
 
-       if (phonenumber) {
-               char normalized_number[CTSVC_NUMBER_MAX_LEN];
-               ctsvc_normalize_number(keyword, normalized_number, CTSVC_NUMBER_MAX_LEN, CTSVC_NUMBER_MAX_LEN -1);
+       char* keyword = NULL;
+       int keyword_size = 0;
+       bool use_replaced_keyword = true;
+       // full width characters -> half width characters (apply to only FW ASCII & some symbols)
+       if( ctsvc_get_halfwidth_string(src, &keyword, &keyword_size) != CONTACTS_ERROR_NONE )
+       {
+               CTS_ERR("UChar converting error : ctsvc_get_halfwidth_string() Failed - %s", src );
+               keyword = (char*)src;
+               use_replaced_keyword = false;
+       }
+       CTS_DBG("UChar converting success : ctsvc_get_halfwidth_string(%s) -> %s[%d] ", src, keyword, keyword_size );
 
-               ret =snprintf(query, size,
-                               "(SELECT contact_id FROM %s WHERE %s MATCH 'name:%s OR number:%s OR data:%s' "
-                                       "UNION "
-                                       "SELECT contact_id FROM %s WHERE number LIKE '%%%s%%') ",
-                               CTS_TABLE_SEARCH_INDEX, CTS_TABLE_SEARCH_INDEX,
-                               keyword, keyword, keyword, CTS_TABLE_PHONE_LOOKUP, normalized_number );
+       char *search_keyword = NULL;
+       search_keyword = __ctsvc_db_make_search_keyword(keyword);
+
+       if (phonenumber) {
+               ret = snprintf(query, size,
+                               "(SELECT contact_id FROM %s WHERE %s MATCH ",
+                               CTS_TABLE_SEARCH_INDEX, CTS_TABLE_SEARCH_INDEX);
+               ret += __ctsvc_db_append_search_query_range(query+ret, size-ret,
+                                                       range, search_keyword, search_keyword, search_keyword);
+
+               if (range & CONTACTS_SEARCH_RANGE_NUMBER) {
+                       char normalized_number[CTSVC_NUMBER_MAX_LEN];
+                       int err = ctsvc_normalize_number(keyword, normalized_number, CTSVC_NUMBER_MAX_LEN, CTSVC_NUMBER_MAX_LEN -1);
+                       if (0 < err) {
+                               ret += snprintf(query+ret, size-ret,
+                                                       "UNION "
+                                                               "SELECT contact_id FROM %s WHERE number LIKE '%%%s%%' ",
+                                                       CTS_TABLE_PHONE_LOOKUP, normalized_number);
+                       }
+               }
+               ret += snprintf(query+ret, size-ret, ")");
        }
        else {
                char *normalized_name = NULL;
-               char *search_keyword = NULL;
-               char *saarch_normal_name = NULL;
-               ret = ctsvc_normalize_str(keyword, &normalized_name);
+               char *search_normal_name = NULL;
 
-               search_keyword = __ctsvc_db_make_search_keyword(keyword);
-               saarch_normal_name = __ctsvc_db_make_search_keyword(normalized_name);
+               ret = ctsvc_normalize_str(keyword, &normalized_name);
+               search_normal_name = __ctsvc_db_make_search_keyword(normalized_name);
 
                if (CTSVC_LANG_KOREAN == ret) {
                        char *chosung = calloc(1, strlen(keyword) * 5);
@@ -916,10 +986,18 @@ static int __ctsvc_db_append_search_query(const char *keyword, char *query, int
 
                        search_chosung = __ctsvc_db_make_search_keyword(chosung);
                        ret = snprintf(query, size,
-                                       "(SELECT contact_id FROM %s WHERE %s MATCH 'name:%s OR number:%s OR data:%s' "
+                                       "(SELECT contact_id FROM %s WHERE %s MATCH ",
+                               CTS_TABLE_SEARCH_INDEX, CTS_TABLE_SEARCH_INDEX);
+
+                       ret += __ctsvc_db_append_search_query_range(query+ret, size-ret,
+                                                               range, search_chosung, search_keyword, search_keyword);
+
+                       if (range & CONTACTS_SEARCH_RANGE_NAME) {
+                               ret += snprintf(query+ret, size-ret,
                                                "INTERSECT SELECT contact_id FROM %s WHERE name GLOB '*%s*' ",
-                                       CTS_TABLE_SEARCH_INDEX, CTS_TABLE_SEARCH_INDEX,
-                                       search_chosung, search_keyword, search_keyword, CTS_TABLE_NAME_LOOKUP, korean_pattern);
+                                               CTS_TABLE_NAME_LOOKUP, korean_pattern);
+                       }
+
                        free(chosung);
                        free(korean_pattern);
                        free(search_chosung);
@@ -932,26 +1010,48 @@ static int __ctsvc_db_append_search_query(const char *keyword, char *query, int
                        search_hiragana = __ctsvc_db_make_search_keyword(hiragana);
 
                        ret = snprintf(query, size,
-                                                               "(SELECT contact_id FROM %s WHERE %s MATCH 'name:%s OR number:%s OR data:%s' ",
-                                                               CTS_TABLE_SEARCH_INDEX, CTS_TABLE_SEARCH_INDEX,
+                                                               "(SELECT contact_id FROM %s WHERE %s MATCH ",
+                                                               CTS_TABLE_SEARCH_INDEX, CTS_TABLE_SEARCH_INDEX);
+                       ret += __ctsvc_db_append_search_query_range(query+ret, size-ret, range,
                                                                search_hiragana, search_hiragana, search_hiragana);
                        free(hiragana);
                        free(search_hiragana);
                }
                else if (CONTACTS_ERROR_NONE <= ret) {
                        ret = snprintf(query, size,
-                                       "(SELECT contact_id FROM %s WHERE %s MATCH 'name:%s OR number:%s OR data:%s' ",
-                                       CTS_TABLE_SEARCH_INDEX, CTS_TABLE_SEARCH_INDEX,
-                                       saarch_normal_name, search_keyword, search_keyword);
+                                       "(SELECT contact_id FROM %s WHERE %s MATCH ",
+                                       CTS_TABLE_SEARCH_INDEX, CTS_TABLE_SEARCH_INDEX);
+
+                       ret += __ctsvc_db_append_search_query_range(query+ret, size-ret, range,
+                                                               search_normal_name, search_keyword, search_keyword);
                }
                else {
                        ret = snprintf(query, size,
-                                       "(SELECT contact_id FROM %s WHERE %s MATCH 'name:%s OR number:%s OR data:%s' ",
-                                       CTS_TABLE_SEARCH_INDEX, CTS_TABLE_SEARCH_INDEX,
-                                       search_keyword, search_keyword, search_keyword);
+                                       "(SELECT contact_id FROM %s WHERE %s MATCH '",
+                                       CTS_TABLE_SEARCH_INDEX, CTS_TABLE_SEARCH_INDEX);
+                       ret += __ctsvc_db_append_search_query_range(query+ret, size-ret,
+                                                               range, search_keyword, search_keyword, search_keyword);
                }
 
-               if (strstr(keyword, "@") != NULL) {
+               if (range & CONTACTS_SEARCH_RANGE_NAME) {
+                       int j = 0;
+                       temp_len = strlen(keyword);
+                       char temp_str[temp_len*2+1];
+                       for(i=0;i<temp_len;i++) {
+                               if (keyword[i] == '\'' || keyword[i] == '_' || keyword[i] == '%' || keyword[i] == '\\') {
+                                       temp_str[j++] = CTSVC_DB_ESCAPE_CHAR;
+                               }
+                               temp_str[j++] = keyword[i];
+                       }
+                       temp_str[j] = '\0';
+                       ret += snprintf(query+ret, size-ret,
+                                                       "UNION SELECT contact_id FROM "CTS_TABLE_NAME_LOOKUP" "
+                                                       "WHERE name LIKE '%s%%' ESCAPE '%c'",
+                                                       temp_str, CTSVC_DB_ESCAPE_CHAR);
+               }
+
+               if ((range & CONTACTS_SEARCH_RANGE_DATA) &&
+                                (strstr(keyword, "@") != NULL)) {
                        ret += snprintf(query+ret, size-ret,
                                        " UNION "
                                                "SELECT contact_id FROM %s WHERE %s MATCH 'data:%s' ) ",
@@ -961,17 +1061,21 @@ static int __ctsvc_db_append_search_query(const char *keyword, char *query, int
                        ret += snprintf(query+ret, size-ret,") ");
 
                free(normalized_name);
-               free(search_keyword);
-               free(saarch_normal_name);
+               free(search_normal_name);
        }
 
+       free(search_keyword);
+
+       if( use_replaced_keyword )
+               free(keyword);
+
        return ret;
 }
 
 static int __ctsvc_db_search_records_exec(const char *view_uri, const property_info_s* properties,
-               int ids_count, const char *projection, const char *keyword, int offset, int limit, contacts_list_h* out_list )
+               int ids_count, const char *projection, const char *keyword, int offset, int limit, int range, contacts_list_h* out_list )
 {
-       char query[CTS_SQL_MAX_LEN*8] = {0}; // temporarily extend
+       char query[CTS_SQL_MAX_LEN + strlen(keyword)*20];
        const char *table;
        int len;
        int ret;
@@ -981,6 +1085,7 @@ static int __ctsvc_db_search_records_exec(const char *view_uri, const property_i
        contacts_list_h list = NULL;
        ctsvc_record_type_e r_type;
        const char *sortkey;
+       query[0] = '\0';
 
        ret = ctsvc_db_get_table_name(view_uri, &table);
        RETVM_IF (CONTACTS_ERROR_NONE != ret, ret, "Invalid parameter : view uri (%s)", view_uri);
@@ -990,7 +1095,7 @@ static int __ctsvc_db_search_records_exec(const char *view_uri, const property_i
                len = snprintf(query, sizeof(query), "SELECT %s FROM %s "
                                        "WHERE contact_id IN ",
                                        projection, table);
-               len += __ctsvc_db_append_search_query(keyword, query + len, sizeof(query) - len);
+               len += __ctsvc_db_append_search_query(keyword, query + len, sizeof(query) - len, range);
        }
        else {          // CTSVC_VIEW_URI_PERSON
                len = snprintf(query, sizeof(query), "SELECT %s FROM %s, "
@@ -998,7 +1103,7 @@ static int __ctsvc_db_search_records_exec(const char *view_uri, const property_i
                                                        "FROM "CTS_TABLE_CONTACTS " "
                                                        "WHERE deleted = 0 AND contact_id IN ",
                                                        projection, table);
-               len += __ctsvc_db_append_search_query(keyword, query + len, sizeof(query) - len);
+               len += __ctsvc_db_append_search_query(keyword, query + len, sizeof(query) - len, range);
                len += snprintf(query + len, sizeof(query) - len, " GROUP BY person_id_in_contact) temp_contacts "
                                                "ON %s.person_id = temp_contacts.person_id_in_contact", table);
        }
@@ -1040,7 +1145,6 @@ static int __ctsvc_db_search_records_exec(const char *view_uri, const property_i
                if( r_type == CTSVC_RECORD_PERSON )
                {
                        unsigned int *project = malloc(sizeof(unsigned int)*ids_count);
-                       int i;
                        for(i=0;i<ids_count;i++)
                        {
                                project[i] = properties[i].property_id;
@@ -1092,6 +1196,7 @@ static int __ctsvc_db_search_records(const char* view_uri, const char *keyword,
        char *projection;
        const property_info_s *p;
        bool can_keyword_search = false;
+       int range = CONTACTS_SEARCH_RANGE_NAME | CONTACTS_SEARCH_RANGE_NUMBER | CONTACTS_SEARCH_RANGE_DATA;
 
        RETVM_IF(NULL == keyword, CONTACTS_ERROR_INVALID_PARAMETER,
                        "Invalid parameter : keyword is NULL");
@@ -1104,16 +1209,42 @@ static int __ctsvc_db_search_records(const char* view_uri, const char *keyword,
        ret = __ctsvc_db_create_projection(p, count, NULL, 0, &projection);
        RETVM_IF (CONTACTS_ERROR_NONE != ret, ret, "__ctsvc_db_create_projection is failed(%s)", ret);
 
-       __ctsvc_db_search_records_exec(view_uri, p, count, projection, keyword, offset, limit, out_list);
+       ret = __ctsvc_db_search_records_exec(view_uri, p, count, projection, keyword, offset, limit, range, out_list);
        free(projection);
 
-       return CONTACTS_ERROR_NONE;
+       return ret;
+}
+
+static int __ctsvc_db_search_records_with_range(const char* view_uri, const char *keyword,
+               int offset, int limit, int range, contacts_list_h* out_list)
+{
+       int ret;
+       unsigned int count;
+       char *projection;
+       const property_info_s *p;
+       bool can_keyword_search = false;
+
+       RETVM_IF(NULL == keyword, CONTACTS_ERROR_INVALID_PARAMETER,
+                       "Invalid parameter : keyword is NULL");
+
+       can_keyword_search = __ctsvc_db_view_can_keyword_search(view_uri);
+       RETVM_IF(false == can_keyword_search, CONTACTS_ERROR_INVALID_PARAMETER,
+                       "Invalid parameter : can not keyword search");
+
+       p = ctsvc_view_get_all_property_infos(view_uri, &count);
+       ret = __ctsvc_db_create_projection(p, count, NULL, 0, &projection);
+       RETVM_IF (CONTACTS_ERROR_NONE != ret, ret, "__ctsvc_db_create_projection is failed(%s)", ret);
+
+       ret = __ctsvc_db_search_records_exec(view_uri, p, count, projection, keyword, offset, limit, range, out_list);
+       free(projection);
+
+       return ret;
 }
 
 static inline int __ctsvc_db_search_records_with_query_exec(ctsvc_query_s *s_query, const char *projection,
        const char *condition, GSList *bind, const char *keyword, int offset, int limit, contacts_list_h * out_list )
 {
-       char query[CTS_SQL_MAX_LEN*8] = {0}; // temporarily extend
+       char query[CTS_SQL_MAX_LEN + strlen(keyword) *20];
        int len;
        int ret;
        int i;
@@ -1123,6 +1254,8 @@ static inline int __ctsvc_db_search_records_with_query_exec(ctsvc_query_s *s_que
        contacts_list_h list = NULL;
        const char *table;
        const char *sortkey = NULL;
+       int range = CONTACTS_SEARCH_RANGE_NAME | CONTACTS_SEARCH_RANGE_NUMBER | CONTACTS_SEARCH_RANGE_DATA;
+       query[0] = '\0';
 
        RETV_IF(NULL == projection || '\0' == *projection, CONTACTS_ERROR_INVALID_PARAMETER);
 
@@ -1136,20 +1269,18 @@ static inline int __ctsvc_db_search_records_with_query_exec(ctsvc_query_s *s_que
 
        if (0 == strcmp(s_query->view_uri, CTSVC_VIEW_URI_READ_ONLY_PERSON_CONTACT)
                        || 0 == strcmp(s_query->view_uri, CTSVC_VIEW_URI_READ_ONLY_PERSON_GROUP)) {
-               len += snprintf(query+len, sizeof(query)-len, "FROM %s temp_contacts ", table);
+               len += snprintf(query+len, sizeof(query)-len, "FROM %s WHERE %s.contact_id IN ", table, table);
        }
        else {          // CTSVC_VIEW_URI_PERSON
                len += snprintf(query+len, sizeof(query)-len, "FROM %s, "
-                                               "(SELECT contact_id, person_id person_id_in_contact FROM %s WHERE deleted = 0) temp_contacts "
-                                               "ON %s.person_id = temp_contacts.person_id_in_contact "
+                                               "(SELECT contact_id, person_id person_id_in_contact, addressbook_id FROM %s WHERE deleted = 0) temp_contacts "
+                                               "ON %s.person_id = temp_contacts.person_id_in_contact WHERE temp_contacts.contact_id IN "
                                                , table, CTS_TABLE_CONTACTS, table);
        }
 /*     len += snprintf(query+len, sizeof(query)-len, "FROM %s, "CTS_TABLE_SEARCH_INDEX" "
                                        "ON %s.contact_id = "CTS_TABLE_SEARCH_INDEX".contact_id", table, table);*/
 
-       len += snprintf(query+len, sizeof(query)-len,
-                       " WHERE temp_contacts.contact_id IN ");
-       len += __ctsvc_db_append_search_query(keyword, query + len, sizeof(query) - len);
+       len += __ctsvc_db_append_search_query(keyword, query + len, sizeof(query) - len, range);
 
        if (condition && *condition)
                len += snprintf(query+len, sizeof(query)-len, " AND (%s)", condition);
@@ -2054,6 +2185,17 @@ API int contacts_db_search_records(const char* view_uri, const char *keyword,
        return __ctsvc_db_search_records(view_uri, keyword, offset, limit, out_list);
 }
 
+API int contacts_db_search_records_with_range(const char* view_uri, const char *keyword,
+               int offset, int limit, int range, contacts_list_h* out_list)
+{
+       RETV_IF(NULL == out_list, CONTACTS_ERROR_INVALID_PARAMETER);
+       *out_list = NULL;
+       RETVM_IF(range == 0, CONTACTS_ERROR_INVALID_PARAMETER, "range is 0");
+       RETVM_IF(NULL == view_uri, CONTACTS_ERROR_INVALID_PARAMETER, "Invalid parameter");
+
+       return __ctsvc_db_search_records_with_range(view_uri, keyword, offset, limit, range, out_list);
+}
+
 API int contacts_db_search_records_with_query( contacts_query_h query, const char *keyword,
                int offset, int limit, contacts_list_h* out_list)
 {
index 036bd36..5d6eec9 100644 (file)
@@ -144,7 +144,7 @@ void ctsvc_ipc_server_db_insert_record(pims_ipc_h ipc, pims_ipc_data_h indata, p
                CTS_ERR("outdata is NULL");
        }
        goto DATA_FREE;
-       // goto 주의..
+
 ERROR_RETURN:
        if (outdata)
        {
@@ -205,7 +205,6 @@ void ctsvc_ipc_server_db_get_record(pims_ipc_h ipc, pims_ipc_data_h indata, pims
 
        ret = contacts_db_get_record(view_uri,id,&record);
 
-       // goto 주의..
 ERROR_RETURN:
        if (outdata)
        {
@@ -576,7 +575,6 @@ void ctsvc_ipc_server_db_get_all_records(pims_ipc_h ipc, pims_ipc_data_h indata,
 
        goto DATA_FREE;
 
-       // goto 주의..
 ERROR_RETURN:
        if (outdata)
        {
@@ -682,7 +680,6 @@ void ctsvc_ipc_server_db_get_records_with_query(pims_ipc_h ipc, pims_ipc_data_h
        }
        goto DATA_FREE;
 
-       // goto 주의..
 ERROR_RETURN:
        if (outdata)
        {
@@ -778,7 +775,6 @@ void ctsvc_ipc_server_db_get_count(pims_ipc_h ipc, pims_ipc_data_h indata, pims_
        }
        goto DATA_FREE;
 
-       // goto 주의..
 ERROR_RETURN:
        if (outdata)
        {
@@ -865,7 +861,6 @@ void ctsvc_ipc_server_db_get_count_with_query(pims_ipc_h ipc, pims_ipc_data_h in
        }
        goto DATA_FREE;
 
-       // goto 주의..
 ERROR_RETURN:
        if (outdata)
        {
@@ -1065,7 +1060,6 @@ void ctsvc_ipc_server_db_update_records(pims_ipc_h ipc, pims_ipc_data_h indata,
        }
        goto DATA_FREE;
 
-       // goto 주의..
 ERROR_RETURN:
        if (outdata)
        {
@@ -1384,7 +1378,6 @@ void ctsvc_ipc_server_db_get_changes_by_version(pims_ipc_h ipc, pims_ipc_data_h
        }
        goto DATA_FREE;
 
-       // goto 주의..
 ERROR_RETURN:
        if (outdata)
        {
@@ -1540,7 +1533,6 @@ void ctsvc_ipc_server_db_search_records(pims_ipc_h ipc, pims_ipc_data_h indata,
        }
        goto DATA_FREE;
 
-       // goto 주의..
 ERROR_RETURN:
        if (outdata)
        {
@@ -1573,6 +1565,107 @@ DATA_FREE:
        return;
 }
 
+void ctsvc_ipc_server_db_search_records_with_range(pims_ipc_h ipc, pims_ipc_data_h indata, pims_ipc_data_h *outdata, void *userdata)
+{
+       int ret = CONTACTS_ERROR_NONE;
+       char* view_uri = NULL;
+       char* keyword = NULL;
+       int offset = 0;
+       int limit = 0;
+       int range = 0;
+       contacts_list_h list = NULL;
+
+       if (indata) {
+               ret = ctsvc_ipc_unmarshal_string(indata,&view_uri);
+               if (ret != CONTACTS_ERROR_NONE) {
+                       CTS_ERR("ctsvc_ipc_unmarshal_record fail");
+                       goto ERROR_RETURN;
+               }
+               ret = ctsvc_ipc_unmarshal_string(indata,&keyword);
+               if (ret != CONTACTS_ERROR_NONE) {
+                       CTS_ERR("ctsvc_ipc_unmarshal_record fail");
+                       goto ERROR_RETURN;
+               }
+               ret = ctsvc_ipc_unmarshal_int(indata,&offset);
+               if (ret != CONTACTS_ERROR_NONE) {
+                       CTS_ERR("ctsvc_ipc_unmarshal_int fail");
+                       goto ERROR_RETURN;
+               }
+               ret = ctsvc_ipc_unmarshal_int(indata,&limit);
+               if (ret != CONTACTS_ERROR_NONE) {
+                       CTS_ERR("ctsvc_ipc_unmarshal_int fail");
+                       goto ERROR_RETURN;
+               }
+               ret = ctsvc_ipc_unmarshal_int(indata,&range);
+               if (ret != CONTACTS_ERROR_NONE) {
+                       CTS_ERR("ctsvc_ipc_unmarshal_int fail");
+                       goto ERROR_RETURN;
+               }
+       }
+       else {
+               CTS_ERR("ctsvc_ipc_server_db_insert_record fail");
+               goto ERROR_RETURN;
+       }
+
+       ret = contacts_db_search_records_with_range(view_uri, keyword, offset,limit,range, &list);
+
+       if (outdata) {
+               *outdata = pims_ipc_data_create(0);
+               if (!*outdata) {
+                       CTS_ERR("pims_ipc_data_create fail");
+                       goto DATA_FREE;
+               }
+               if (pims_ipc_data_put(*outdata,(void*)&ret,sizeof(int)) != 0) {
+                       pims_ipc_data_destroy(*outdata);
+                       *outdata = NULL;
+                       CTS_ERR("pims_ipc_data_put fail");
+                       goto DATA_FREE;
+               }
+
+               if (CONTACTS_ERROR_NO_DATA == ret) {
+                       CTS_DBG("no data");
+               }
+               else if(CONTACTS_ERROR_NONE == ret) {
+                       ret = ctsvc_ipc_marshal_list(list,*outdata);
+
+                       if (ret != CONTACTS_ERROR_NONE) {
+                               CTS_ERR("ctsvc_ipc_unmarshal_int fail");
+                               goto DATA_FREE;
+                       }
+               }
+       }
+       else {
+               CTS_ERR("outdata is NULL");
+       }
+       goto DATA_FREE;
+
+ERROR_RETURN:
+       if (outdata) {
+               *outdata = pims_ipc_data_create(0);
+               if (!*outdata) {
+                       CTS_ERR("pims_ipc_data_create fail");
+                       goto DATA_FREE;
+               }
+               if (pims_ipc_data_put(*outdata,(void*)&ret,sizeof(int)) != 0) {
+                       pims_ipc_data_destroy(*outdata);
+                       *outdata = NULL;
+                       CTS_ERR("pims_ipc_data_put fail");
+                       goto DATA_FREE;
+               }
+       }
+       else {
+               CTS_ERR("outdata is NULL");
+       }
+
+DATA_FREE:
+
+       if (list)
+               contacts_list_destroy(list,true);
+       free(view_uri);
+       free(keyword);
+       return;
+}
+
 void ctsvc_ipc_server_db_search_records_with_query(pims_ipc_h ipc, pims_ipc_data_h indata, pims_ipc_data_h *outdata, void *userdata)
 {
        int ret = CONTACTS_ERROR_NONE;
@@ -1654,7 +1747,6 @@ void ctsvc_ipc_server_db_search_records_with_query(pims_ipc_h ipc, pims_ipc_data
        }
        goto DATA_FREE;
 
-       // goto 주의..
 ERROR_RETURN:
        if (outdata)
        {
index 370b5de..66c9c37 100644 (file)
@@ -46,6 +46,7 @@ void ctsvc_ipc_server_db_get_changes_by_version(pims_ipc_h ipc, pims_ipc_data_h
 void ctsvc_ipc_server_db_get_current_version(pims_ipc_h ipc, pims_ipc_data_h indata, pims_ipc_data_h *outdata, void *userdata);
 
 void ctsvc_ipc_server_db_search_records(pims_ipc_h ipc, pims_ipc_data_h indata, pims_ipc_data_h *outdata, void *userdata);
+void ctsvc_ipc_server_db_search_records_with_range(pims_ipc_h ipc, pims_ipc_data_h indata, pims_ipc_data_h *outdata, void *userdata);
 void ctsvc_ipc_server_db_search_records_with_query(pims_ipc_h ipc, pims_ipc_data_h indata, pims_ipc_data_h *outdata, void *userdata);
 
 
index c7b747f..fd0e7e4 100644 (file)
@@ -61,6 +61,7 @@ static int __server_main(void)
                if (pims_ipc_svc_register(CTSVC_IPC_DB_MODULE, CTSVC_IPC_SERVER_DB_CHANGES_BY_VERSION, ctsvc_ipc_server_db_get_changes_by_version, NULL) != 0) break;
                if (pims_ipc_svc_register(CTSVC_IPC_DB_MODULE, CTSVC_IPC_SERVER_DB_GET_CURRENT_VERSION, ctsvc_ipc_server_db_get_current_version, NULL) != 0) break;
                if (pims_ipc_svc_register(CTSVC_IPC_DB_MODULE, CTSVC_IPC_SERVER_DB_SEARCH_RECORDS, ctsvc_ipc_server_db_search_records, NULL) != 0) break;
+               if (pims_ipc_svc_register(CTSVC_IPC_DB_MODULE, CTSVC_IPC_SERVER_DB_SEARCH_RECORDS_WITH_RANGE, ctsvc_ipc_server_db_search_records_with_range, NULL) != 0) break;
                if (pims_ipc_svc_register(CTSVC_IPC_DB_MODULE, CTSVC_IPC_SERVER_DB_SEARCH_RECORDS_WITH_QUERY, ctsvc_ipc_server_db_search_records_with_query, NULL) != 0) break;
 
                if (pims_ipc_svc_register(CTSVC_IPC_ACTIVITY_MODULE, CTSVC_IPC_SERVER_ACTIVITY_DELETE_BY_CONTACT_ID, ctsvc_ipc_activity_delete_by_contact_id, NULL) != 0) break;