📄 dbelement.c
字号:
/* librecord2 - Record Object manipulation and storage library 2 * * Authors: YE Nan <nan.ye@orange-ftgroup.com> * * This software and associated documentation files (the "Software") * are copyright (C) 2005 LiPS Linux Phone Standards Forum [FranceTelecom] * All Rights Reserved. * * A copyright license is hereby granted for redistribution and use of * the Software in source and binary forms, with or without modification, * provided that the following conditions are met: * - Redistributions of source code must retain the above copyright notice, * this copyright license and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright * notice, this copyright license and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - Neither the name of LiPS nor the names of its Members may be used * to endorse or promote products derived from the Software without * specific prior written permission. * * A patent license for any Necessary Claims owned by Members of LiPS Forum * to make, have made, use, import, offer to sell, lease and sell or otherwise * distribute any implementation compliant with the any specification adopted * by the LiPS Forumcan be obtained from the respective Members on reasonable * and non-discriminatory terms and conditions and under reciprocity, as * regulated in more detail in the Internal Policy of the LiPS Forum. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER, ITS MEMBERS AND CONTRIBUTORS * "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE * AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER, * ITS MEMBERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */#include <stdio.h>#include <string.h>#include <glib.h>#include <sqlite3.h>#include <database.h>#include <utils.h>#include "internal.h"#define FIDSMAP_TABLE_CREATE_TEMPLATE "CREATE TABLE IF NOT EXISTS %s_fidsmap ( ftid%d %s, ftid INTEGER, def INTEGER, PRIMARY KEY ( ftid%d, ftid ));"#define FIDSMAP_TABLE_INSERT_TEMPLATE "INSERT INTO %s_fidsmap ( ftid%d, ftid, def) VALUES ( :001, :002, :003 );"#define FIDSMAP_TABLE_UPDATE_TEMPLATE "UPDATE %s_fidsmap SET def = :001 WHERE ( ftid%d = :002 ) & ( ftid = :003);"#define EXTEND_TABLE_CREATE_TEMPLATE "CREATE TABLE IF NOT EXISTS %s_ext_%s ( ftid%d %s, fid INTEGER, label TEXT, desc TEXT, value %s, PRIMARY KEY ( ftid%d, fid ));"#define EXTEND_TABLE_INSERT_TEMPLATE "INSERT INTO %s_ext_%s ( ftid%d, fid, label, desc, value ) VALUES ( :001, :002, :003, :004, :005 );"#define EXTEND_TABLE_UPDATE_TEMPLATE "UPDATE %s_ext_%s SET label = :001, desc = :002, value = :003 WHERE ( fid = :004 ) & ( ftid%d = :005 );"static char * ftstrs [DB_FIELDS_NTYPES] = { "INTEGER", "REAL", "TEXT", "BLOB",};static gbooleanrecord_db_element_check_template_validity (RecordDBElement *element){ Iterator * iter = NULL; gint count; g_return_val_if_fail(element, FALSE); g_return_val_if_fail(element->db_elm_template, FALSE); iter = field_template_get_ftids(element->db_elm_template); count = 0; element->db_elm_id_ftid = FIELD_TEMPLATE_ID_INVALID; for(iterator_to_first(iter); !iterator_at_last(iter); iterator_next(iter)) { guint32 ftid = *(guint32 *)iterator_current(iter); const FieldDescriptor *fdesc = NULL; fdesc = field_template_get(element->db_elm_template, ftid); if (fdesc) { /* * Check validity of a datebase template, and * find out element "ID" field identifier: * * Validity: * 1. One and only one "ID" field(FIELD_ATTR_PRIMARY). * 2. "ID" field SHOULD NOT has FIELD_ATTR_MULTI attribute. * 3. "ID" field SHOULD be INTEGER (currently). */ if (fdesc->attribute & FIELD_ATTR_PRIMARY) { if (element->db_elm_id_ftid != FIELD_TEMPLATE_ID_INVALID) { g_print("%s(): more than one primary field %d, previous %d.\n", __FUNCTION__, ftid, element->db_elm_id_ftid); goto failure; } if (fdesc->attribute & FIELD_ATTR_MULTIPLE) { g_print("%s(): primary field %d CANNOT set MULTI.\n", __FUNCTION__, ftid); goto failure; } element->db_elm_id_ftid = fdesc->identifier; switch (fdesc->type) { case FIELD_TYPE_INTEGER: element->db_elm_id_type = DB_FIELDS_INTEGER; break; case FIELD_TYPE_STRING: case FIELD_TYPE_DATE: case FIELD_TYPE_BOOLEAN: case FIELD_TYPE_FLOAT: default: g_print("%s(): primary field type SHOULD be INTEGER.\n", __FUNCTION__); element->db_elm_id_type = DB_FIELDS_INVALID; goto failure; break; } } count++; } switch (fdesc->type) { case FIELD_TYPE_DATE: case FIELD_TYPE_BOOLEAN: case FIELD_TYPE_INTEGER: DB_FIELDS_TYPES_SET(element->db_elm_field_types, DB_FIELDS_INTEGER); break; case FIELD_TYPE_FLOAT: DB_FIELDS_TYPES_SET(element->db_elm_field_types, DB_FIELDS_REAL); break; case FIELD_TYPE_STRING: DB_FIELDS_TYPES_SET(element->db_elm_field_types, DB_FIELDS_TEXT); break; case FIELD_TYPE_BINARY: default: DB_FIELDS_TYPES_SET(element->db_elm_field_types, DB_FIELDS_BLOB); break; } } iterator_free(iter, TRUE); g_print("%s(): PRIMARY FTID: %d[%s], types = 0x%08x\n", __FUNCTION__, element->db_elm_id_ftid, ftstrs[element->db_elm_id_type], element->db_elm_field_types); return TRUE;failure: iterator_free(iter, TRUE); return FALSE;}static gbooleanrecord_db_element_create_tables (RecordDBElement *element){ Iterator * iter = NULL; GString * main_sqlstr = NULL; GString * ext_sqlstr = NULL; GString * fidsmap_sqlstr = NULL; GString * columns_str = NULL; gchar * errmsg = NULL; gint i; g_return_val_if_fail(element, FALSE); columns_str = g_string_new("( "); /* * Create main table of database element. * Each field in template exists as a single column(ftid%d) * in main table and stores its default value. */ iter = field_template_get_ftids(element->db_elm_template); for (iterator_to_first(iter); !iterator_at_last(iter); iterator_next(iter)) { guint32 ftid = *(guint32 *)iterator_current(iter); const FieldDescriptor *fdesc = NULL; fdesc = field_template_get(element->db_elm_template, ftid); g_string_append_printf(columns_str, "ftid%d ", fdesc->identifier); switch (fdesc->type) { case FIELD_TYPE_BINARY: g_string_append(columns_str, ftstrs[DB_FIELDS_BLOB]); break; case FIELD_TYPE_INTEGER: case FIELD_TYPE_DATE: case FIELD_TYPE_BOOLEAN: g_string_append(columns_str, ftstrs[DB_FIELDS_INTEGER]); break; case FIELD_TYPE_FLOAT: g_string_append(columns_str, ftstrs[DB_FIELDS_REAL]); break; default: g_string_append(columns_str, ftstrs[DB_FIELDS_TEXT]); break; } if (fdesc->attribute & FIELD_ATTR_REQUIRED) { g_string_append(columns_str, " NOT NULL"); } g_string_append(columns_str, ", "); } iterator_free(iter, TRUE); main_sqlstr = g_string_new(""); g_string_append_printf(main_sqlstr, "CREATE TABLE IF NOT EXISTS %s_main ", element->db_elm_name); g_string_append(main_sqlstr, columns_str->str); g_string_append(main_sqlstr, "extflag INTEGER, "); g_string_append_printf(main_sqlstr, "PRIMARY KEY ( ftid%d ) );", element->db_elm_id_ftid); g_string_free(columns_str, TRUE);/* g_print("CREATE MAIN TABLE sql:\n%s\n", main_sqlstr->str);*/ if (record_db_open(element->db) != DB_ERROR_NONE) { goto failure; } while (record_db_inner_trans_begin(element->db, DB_TRANS_DEFERRED) != DB_ERROR_NONE); if (sqlite3_exec(element->db->database, main_sqlstr->str, NULL, NULL, &errmsg) != SQLITE_OK) { g_print("%s(): create main table failed: %s.\n", __FUNCTION__, errmsg); goto failure; } /* * Create extend tables for database element. * The extended fields is categoried with its * field type. The field with the same field * type will be stored in the same extend table. * So the number of extend tables depends on the * number of field type in field templte of current * database element. */ ext_sqlstr = g_string_new(""); for (i = 0; i < DB_FIELDS_NTYPES; i++) {/* g_print("%s(): i = %d, set = %s\n", __FUNCTION__, i, (element->db_elm_field_types & (1 << i) ? "TRUE" : "FALSE"));*/ if (!(element->db_elm_field_types & (1 << i))) { continue; } g_string_append_printf(ext_sqlstr, EXTEND_TABLE_CREATE_TEMPLATE, element->db_elm_name, ftstrs[i], element->db_elm_id_ftid, ftstrs[element->db_elm_id_type], ftstrs[i], element->db_elm_id_ftid); /* g_print("CREATE EXTEND TABLE sql:\n%s\n", ext_sqlstr->str);*/ if (sqlite3_exec(element->db->database, ext_sqlstr->str, NULL, NULL, &errmsg) != SQLITE_OK) { g_print("%s(): create extend table failed: %s.\n", __FUNCTION__, errmsg); goto failure; } g_string_assign(ext_sqlstr, ""); } /* * Create default fid map for echo field template. * If deafult field of the field template is changed, * there will be one row newly created to describe this. */ fidsmap_sqlstr = g_string_new(""); g_string_append_printf(fidsmap_sqlstr, FIDSMAP_TABLE_CREATE_TEMPLATE, element->db_elm_name, element->db_elm_id_ftid, ftstrs[element->db_elm_id_type], element->db_elm_id_ftid); /* g_print("CREATE FIDSMAP sql:\n%s\n", fidsmap_sqlstr->str);*/ if (sqlite3_exec(element->db->database, fidsmap_sqlstr->str, NULL, NULL, &errmsg) != SQLITE_OK) { g_print("%s(): create fidsmap table failed: %s.\n", __FUNCTION__, errmsg); goto failure; } record_db_inner_trans_commit(element->db); record_db_close(element->db); g_string_free(main_sqlstr, TRUE); g_string_free(ext_sqlstr, TRUE); g_string_free(fidsmap_sqlstr, TRUE); return TRUE;failure: record_db_close(element->db); g_string_free(main_sqlstr, TRUE); g_string_free(ext_sqlstr, TRUE); g_string_free(fidsmap_sqlstr, TRUE); g_free(errmsg); return FALSE;}void record_db_element_print (const RecordDBElement *element){ g_return_if_fail(element); g_print("RecordDBElement: [0x%08x]\n", (guint32)element); g_print("|- Name : %s\n", (guint32)element->db_elm_name); g_print("|- RecordDB : 0x%08x\n", (guint32)element->db); g_print("|- Template : 0x%08x\n", (guint32)element->db_elm_template); g_print("|- Field Types : 0x%08x\n", element->db_elm_field_types); g_print("|- Primary FTID : %d\n", element->db_elm_id_ftid); g_print("`- Primary Type : 0x%08x\n", element->db_elm_id_type); return;}/** * @brief Create a #RecordDBElement object, initialized with * the given information. * * @param db database object handler * @param name element name * @param template field template used for element * * @return newly-created #RecordDBElement object or NULL if failed. */RecordDBElement *record_db_element_new (RecordDB *db, const gchar *name, const FieldTemplate *template){ RecordDBElement *element = NULL; g_return_val_if_fail(db, NULL); g_return_val_if_fail(name, NULL); g_return_val_if_fail(template, NULL); element = g_new0(RecordDBElement, 1); if (element == NULL) { return NULL; } element->db = db; element->db_elm_name = g_strdup(name); element->db_elm_template = template; element->db_elm_field_types = 0x0; element->db_elm_id_ftid = FIELD_TEMPLATE_ID_INVALID; element->db_elm_id_type = DB_FIELDS_TEXT; if (g_hash_table_lookup(db->elements, (gpointer)name) == NULL) { gchar * key = NULL; key = g_strdup(name); g_hash_table_replace(db->elements, (gpointer)key, (gpointer)element); } else { g_print("%s(): %s element already exists.\n", __FUNCTION__, element); record_db_element_free(element); return NULL; } if (record_db_element_check_template_validity(element) == FALSE) { g_print("%s(): check validity failed.\n", __FUNCTION__); record_db_element_free(element); return NULL; } if (record_db_element_create_tables(element) == FALSE) { g_print("%s(): create table failed.\n", __FUNCTION__); record_db_element_free(element); return NULL; } return element;}/** * @brief Frees the memory allocated for the #RecordDBElement object. * * @param element the #RecordDBElement object */voidrecord_db_element_free (RecordDBElement *element){ g_return_if_fail(element); g_hash_table_remove(element->db->elements, (gpointer)element->db_elm_name); g_free(element->db_elm_name); g_free(element); return;}static voidbind_value_by_fid (sqlite3_stmt *pStmt, guint32 fid, gconstpointer value, gint type, gint size){ gchar * name = NULL; gint index = 0; /* * use fid to fill pattern ":%03d" to location the * colum binding in a SQLite statement binary codes. */ name = sqlite3_mprintf(":%03d", fid); index = sqlite3_bind_parameter_index(pStmt, name); sqlite3_free(name);// g_print("%s(): fid = %d, type = %d, size = %d\n", __FUNCTION__, fid, type, size); switch (type) { case FIELD_TYPE_STRING:// g_print("%s(): value = %s\n", __FUNCTION__, value); sqlite3_bind_text(pStmt, index, (gchar *)value, strlen((gchar *)value), SQLITE_TRANSIENT); break; /* * INTEGER field SHOULD NOT treated as * binary or it will lead a logical error * when database manipulations. */ case FIELD_TYPE_INTEGER: sqlite3_bind_int(pStmt, index, *(gint *)value); break;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -