database.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 <glib.h>#include <sqlite3.h>#include <database.h>#include <utils.h>#include "internal.h"/** * @brief Create a #RecordDB object, initialized with * the given information. * * @param db_fname database filename * @param db_table_prefix database tables prefix * @param db_template database template * * @return newly-created #RecordDB object or NULL if failed. */RecordDB * record_db_new (const gchar *db_fname){ RecordDB *db = NULL; g_return_val_if_fail(db_fname, NULL); db = g_new0(RecordDB, 1); if (db == NULL) { return NULL; } db->db_fname = g_strdup(db_fname); db->db_trans_status = TRANS_NONE; db->database = NULL; if (g_file_test(db->db_fname, G_FILE_TEST_IS_REGULAR) == FALSE) { g_print("%s(): db file NOT exists.[%s]\n", __FUNCTION__, db->db_fname); FILE *file = fopen(db->db_fname, "wb"); g_print("%s(): file_handle = %d\n", __FUNCTION__, db->db_fname); fclose(file); } db->elements = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); return db;}/** * @brief Frees the memory allocated for * the #RecordDB object. * * @param db the #RecordDB object */voidrecord_db_free (RecordDB *db){ g_return_if_fail(db); g_hash_table_destroy(db->elements); g_free(db->db_fname); g_free(db); return;}/** * @brief Open the database of #RecordDB object * * @param db the #RecordDB object */RecordDBErrorrecord_db_open (RecordDB *db){ g_return_val_if_fail(db, DB_ERROR_ARG_NULL); if (db->database != NULL) { g_print("%s(): database already opened.\n", __FUNCTION__); return DB_ERROR_FAILED; } if (!g_file_test(db->db_fname, G_FILE_TEST_IS_REGULAR)) { g_print("%s(): database file NOT exists: %s.\n", __FUNCTION__, db->db_fname); return DB_ERROR_NOT_EXIST; } if (sqlite3_open(db->db_fname, &db->database) != SQLITE_OK) { g_print("%s(): open database failed: %s.\n", __FUNCTION__, sqlite3_errmsg(db->database)); sqlite3_close(db->database); db->database = NULL; return DB_ERROR_FAILED; } /* * sets a busy timeout that sleeps for a while * when a database/table is locked. */ sqlite3_busy_timeout(db->database, 10000); return DB_ERROR_NONE;}/** * @brief Close the database of #RecordDB object * * @param db the #RecordDB object */RecordDBErrorrecord_db_close (RecordDB *db){ g_return_val_if_fail(db, DB_ERROR_ARG_NULL); if (db->database) { sqlite3_close(db->database); db->database = NULL; } return DB_ERROR_NONE;}static gbooleanrecord_db_trans_begin_real (RecordDB *db, RecordDBTransType type, TransactionStatus status){ gchar * errmsg = NULL; GString * sql_str = NULL; /* * Transactions can be deferred, immediate, or exclusive. * Deferred means that no locks are acquired on the database * until the database is first accessed. Thus with a deferred * transaction, the BEGIN statement itself does nothing. * Locks are not acquired until the first read or write * operation. The first read operation against a database * creates a SHARED lock and the first write operation creates * a RESERVED lock. Because the acquisition of locks is * deferred until they are needed, it is possible that another * thread or process could create a separate transaction and * write to the database after the BEGIN on the current thread * has executed. If the transaction is immediate, then RESERVED * locks are acquired on all databases as soon as the BEGIN * command is executed, without waiting for the database to be * used. After a BEGIN IMMEDIATE, you are guaranteed that no other * thread or process will be able to write to the database or * do a BEGIN IMMEDIATE or BEGIN EXCLUSIVE. Other processes can * ontinue to read from the database, however. An exclusive * transaction causes EXCLUSIVE locks to be acquired on all * databases. After a BEGIN EXCLUSIVE, you are guaranteed that * no other thread or process will be able to read or write the * database until the transaction is complete. */ sql_str = g_string_new("BEGIN "); switch (type) { case DB_TRANS_IMMEDIATE: g_string_append(sql_str, "IMMEDIATE"); break; case DB_TRANS_EXCLUSIVE: g_string_append(sql_str, "EXCLUSIVE"); break; default: g_string_append(sql_str, "DEFERRED"); break; } // g_return_val_if_fail(db, DB_ERROR_ARG_NULL); if (sqlite3_exec(db->database, sql_str->str, NULL, NULL, &errmsg) != SQLITE_OK) { g_print("%s(): %s error: %s.\n", __FUNCTION__, sql_str->str, errmsg); g_free(errmsg); return FALSE; } g_string_free(sql_str, TRUE); db->db_trans_status = status; return TRUE;}gbooleanrecord_db_inner_trans_begin (RecordDB *db, RecordDBTransType type){ g_return_val_if_fail(db, DB_ERROR_ARG_NULL); if (db->db_trans_status != TRANS_NONE) { return DB_ERROR_NONE; } if (record_db_trans_begin_real(db, type, TRANS_INNER) == FALSE) { return DB_ERROR_FAILED; } return DB_ERROR_NONE;}RecordDBErrorrecord_db_trans_begin (RecordDB *db){ g_return_val_if_fail(db, DB_ERROR_ARG_NULL); if (db->db_trans_status != TRANS_NONE) { return DB_ERROR_NONE; } if (record_db_trans_begin_real(db, DB_TRANS_DEFERRED, TRANS_OUTER) == FALSE) { return DB_ERROR_FAILED; } return DB_ERROR_NONE;}RecordDBErrorrecord_db_trans_begin_extend (RecordDB *db, RecordDBTransType type){ g_return_val_if_fail(db, DB_ERROR_ARG_NULL); if (db->db_trans_status != TRANS_NONE) { return DB_ERROR_NONE; } if (record_db_trans_begin_real(db, type, TRANS_OUTER) == FALSE) { return DB_ERROR_FAILED; } return DB_ERROR_NONE;}static gbooleanrecord_db_trans_commit_real (RecordDB *db){ gchar * errmsg = NULL; if (sqlite3_exec(db->database, "COMMIT", NULL, NULL, &errmsg) != SQLITE_OK) { g_print("%s(): COMMIT TRANS error: %s.\n", __FUNCTION__, errmsg); g_free(errmsg); return FALSE; } db->db_trans_status = TRANS_NONE; return TRUE;}gbooleanrecord_db_inner_trans_commit (RecordDB *db){ g_return_val_if_fail(db, DB_ERROR_ARG_NULL); if (db->db_trans_status != TRANS_INNER) { return DB_ERROR_NONE; } if (record_db_trans_commit_real(db) == FALSE) { return DB_ERROR_FAILED; } return DB_ERROR_NONE;}RecordDBErrorrecord_db_trans_commit (RecordDB *db){ g_return_val_if_fail(db, DB_ERROR_ARG_NULL); if (db->db_trans_status != TRANS_OUTER) { return DB_ERROR_NONE; } if (record_db_trans_commit_real(db) == FALSE) { return DB_ERROR_FAILED; } return DB_ERROR_NONE;}/*vi:ts=2:nowrap:ai:expandtab */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -