#include "config.h"
#include <errno.h>
#include <stdlib.h>
#include <time.h>
#include <glib/gstdio.h>
#include <sqlite.h>
#include <glib.h>
#include <libintl.h>
#include "qof.h"
#include "qofsql-p.h"
#include "qof-sqlite.h"
#include "kvputil-p.h"
Go to the source code of this file.
Defines | |
#define | _(String) dgettext (GETTEXT_PACKAGE, String) |
#define | ACCESS_METHOD "sqlite" |
#define | PRIORITY_HIGH 9 |
#define | PRIORITY_STANDARD 5 |
#define | PRIORITY_LOW 0 |
#define | QSQL_ERROR -1 |
#define | QSQL_KVP_TABLE "sqlite_kvp" |
#define | END_DB_VERSION " dbversion int );" |
Functions | |
static KvpValue * | string_to_kvp_value (const gchar *content, KvpValueType type) |
static G_GNUC_UNUSED void | kvpvalue_to_sql (const gchar *key, KvpValue *val, gpointer builder) |
static void | delete_event (QofEntity *ent, QofEventId event_type, gpointer handler_data, gpointer event_data) |
use the new-style event handlers for insert and update insert runs after QOF_EVENT_CREATE delete runs before QOF_EVENT_DESTROY | |
static void | create_event (QofEntity *ent, QofEventId event_type, gpointer handler_data, gpointer event_data) |
static void | qsql_modify (QofBackend *be, QofInstance *inst) |
static gint | record_foreach (gpointer builder, gint col_num, gchar **strings, gchar **columnNames) |
static void | update_dirty (gpointer value, gpointer builder) |
static gint | create_dirty_list (gpointer builder, gint col_num, gchar **strings, gchar **columnNames) |
static gint | mark_entity (gpointer builder, gint col_num, gchar **strings, gchar **columnNames) |
static void | qsql_create (QofBackend *be, QofInstance *inst) |
static void | check_state (QofEntity *ent, gpointer builder) |
static gint | build_kvp_table (gpointer builder, gint col_num, gchar **strings, gchar **columnNames) |
chekc kvp data once per record | |
static void | qsql_load_kvp (QSQLiteBackend *qsql_be) |
static void | qsql_class_foreach (QofObject *obj, gpointer data) |
static void | qsql_backend_createdb (QofBackend *be, QofSession *session) |
static void | qsql_backend_opendb (QofBackend *be, QofSession *session) |
static void | qsqlite_session_begin (QofBackend *be, QofSession *session, const gchar *book_path, gboolean ignore_lock, gboolean create_if_nonexistent) |
static void | qsqlite_db_load (QofBackend *be, QofBook *book) |
static void | qsqlite_write_db (QofBackend *be, QofBook *book) |
static gboolean | qsql_determine_file_type (const gchar *path) |
static void | qsqlite_session_end (QofBackend *be) |
static void | qsqlite_destroy_backend (QofBackend *be) |
static void | qsql_provider_free (QofBackendProvider *prov) |
static QofBackend * | qsql_backend_new (void) |
Starts the backend and creates the context. | |
void | qof_sqlite_provider_init (void) |
Initialises the SQLite backend. | |
Variables | |
static QofLogModule | log_module = QOF_MOD_SQLITE |
static gboolean | loading = FALSE |
Definition in file qof-sqlite.c.
#define PRIORITY_HIGH 9 |
Indicates an item with high priority.
Definition at line 46 of file qof-sqlite.c.
#define PRIORITY_LOW 0 |
Indicates a low priority item.
Definition at line 50 of file qof-sqlite.c.
#define PRIORITY_STANDARD 5 |
Indicates an item with default priority.
Definition at line 48 of file qof-sqlite.c.
#define QSQL_ERROR -1 |
Indicate an error to sqlite
Definition at line 52 of file qof-sqlite.c.
#define QSQL_KVP_TABLE "sqlite_kvp" |
One KVP table per file for all instances.
Definition at line 55 of file qof-sqlite.c.
static gint build_kvp_table | ( | gpointer | builder, | |
gint | col_num, | |||
gchar ** | strings, | |||
gchar ** | columnNames | |||
) | [static] |
chekc kvp data once per record
creates a new KvpFrame as data for a GHashTable with the guid as key
Definition at line 665 of file qof-sqlite.c.
00667 { 00668 QSQLiteBackend *qsql_be; 00669 struct QsqlBuilder *qb; 00670 KvpFrame *frame; 00671 KvpValueType type; 00672 KvpValue *value; 00673 gulong max; 00674 gchar *tail; 00675 00676 g_return_val_if_fail (builder, QSQL_ERROR); 00677 qb = (struct QsqlBuilder *) builder; 00678 max = 0; 00679 qsql_be = qb->qsql_be; 00680 g_return_val_if_fail ((col_num < 4), QSQL_ERROR); 00681 g_return_val_if_fail (strings[2], QSQL_ERROR); 00682 frame = kvp_frame_new (); 00683 /* columnNames = fields strings = values 00684 [0]=kvp_id, [1]=guid, [2]=path, [3]=type, [4]=value 00685 get type from type_string */ 00686 type = qof_id_to_kvp_value_type (strings[3]); 00687 if (type == 0) 00688 { 00689 PERR (" invalid type returned from kvp table"); 00690 return QSQL_ERROR; 00691 } 00692 /* use the type to make a KvpValue from value */ 00693 value = string_to_kvp_value (strings[4], type); 00694 if (!value) 00695 { 00696 PERR (" invalid KvpValue for type: %d", type); 00697 return QSQL_ERROR; 00698 } 00699 /* add the KvpValue to the frame at path */ 00700 kvp_frame_set_value (frame, strings[2], value); 00701 /* index the frame under the entity GUID */ 00702 g_hash_table_insert (qsql_be->kvp_table, strings[1], frame); 00703 /* index the guid under the kvp_id */ 00704 g_hash_table_insert (qsql_be->kvp_id, strings[0], strings[1]); 00705 errno = 0; 00706 max = strtol (strings[0], &tail, 0); 00707 if (errno == 0) 00708 { 00709 qsql_be->index = (max > qsql_be->index) ? max : qsql_be->index; 00710 } 00711 return SQLITE_OK; 00712 }
static void create_event | ( | QofEntity * | ent, | |
QofEventId | event_type, | |||
gpointer | handler_data, | |||
gpointer | event_data | |||
) | [static] |
receives QSQLiteBackend, passes on QsqlBuilder
Definition at line 295 of file qof-sqlite.c.
00297 { 00298 QofBackend *be; 00299 struct QsqlBuilder qb; 00300 QSQLiteBackend *qsql_be; 00301 gchar *gstr; 00302 KvpFrame *slots; 00303 00304 qsql_be = (QSQLiteBackend *) handler_data; 00305 be = (QofBackend *) qsql_be; 00306 if (!ent) 00307 return; 00308 if (0 == safe_strcmp (ent->e_type, QOF_ID_BOOK)) 00309 return; 00310 if (!qof_class_is_registered (ent->e_type)) 00311 return; 00312 switch (event_type) 00313 { 00314 case QOF_EVENT_CREATE: 00315 { 00316 ENTER (" insert:%s", ent->e_type); 00317 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' '); 00318 guid_to_string_buff (qof_instance_get_guid ((QofInstance *) 00319 ent), gstr); 00320 DEBUG (" guid=%s", gstr); 00321 qb.ent = ent; 00322 qb.sql_str = qof_sql_entity_insert (ent); 00324 DEBUG (" sql_str=%s", qb.sql_str); 00325 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str, 00326 NULL, &qb, &qsql_be->err) != SQLITE_OK) 00327 { 00328 qof_error_set_be (be, qsql_be->err_insert); 00329 qsql_be->error = TRUE; 00330 PERR (" error on create_event:%s", qsql_be->err); 00331 } 00332 else 00333 { 00334 ((QofInstance *) ent)->dirty = FALSE; 00335 qsql_be->error = FALSE; 00336 g_free (qb.sql_str); 00337 g_free (gstr); 00338 LEAVE (" "); 00339 break; 00340 } 00341 /* insert sqlite_kvp data */ 00342 slots = qof_instance_get_slots ((QofInstance *) ent); 00343 if (slots) 00344 { 00345 /* id, guid, path, type, value */ 00346 qb.sql_str = qof_sql_entity_insert (ent); 00347 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str, 00348 NULL, &qb, &qsql_be->err) != SQLITE_OK) 00349 { 00350 qof_error_set_be (be, qsql_be->err_insert); 00351 qsql_be->error = TRUE; 00352 PERR (" error on KVP create_event:%s", qsql_be->err); 00353 } 00354 else 00355 { 00356 ((QofInstance *) ent)->dirty = FALSE; 00357 qsql_be->error = FALSE; 00358 g_free (qb.sql_str); 00359 g_free (gstr); 00360 LEAVE (" "); 00361 break; 00362 } 00363 } 00364 g_free (qb.sql_str); 00365 g_free (gstr); 00366 LEAVE (" "); 00367 break; 00368 } 00369 default: 00370 break; 00371 } 00372 }
static G_GNUC_UNUSED void kvpvalue_to_sql | ( | const gchar * | key, | |
KvpValue * | val, | |||
gpointer | builder | |||
) | [static] |
returns the VALUES for INSERT in pre-defined order
Definition at line 195 of file qof-sqlite.c.
00196 { 00197 QSQLiteBackend *qsql_be; 00198 struct QsqlBuilder *qb; 00199 KvpValueType n; 00200 gchar *full_path; 00201 00202 full_path = NULL; 00203 ENTER (" "); 00204 qb = (struct QsqlBuilder *) builder; 00205 qsql_be = qb->qsql_be; 00206 g_return_if_fail (key && val && qsql_be); 00207 n = kvp_value_get_type (val); 00208 switch (n) 00209 { 00210 case KVP_TYPE_GINT64: 00211 case KVP_TYPE_DOUBLE: 00212 case KVP_TYPE_NUMERIC: 00213 case KVP_TYPE_STRING: 00214 case KVP_TYPE_GUID: 00215 case KVP_TYPE_TIME: 00216 case KVP_TYPE_BOOLEAN: 00217 { 00218 /* ("kvp_id int primary key not null", "guid char(32)", "path mediumtext", 00219 "type mediumtext", "value text", */ 00220 00221 qb->sql_str = 00222 g_strdup_printf (" kvp key=%s val=%s type=%s", key, 00223 kvp_value_to_bare_string (val), 00224 kvp_value_type_to_qof_id (n)); 00225 DEBUG (" %s", qb->sql_str); 00226 qb->has_slots = TRUE; 00227 break; 00228 } 00229 case KVP_TYPE_FRAME: 00230 { 00231 kvp_frame_for_each_slot (kvp_value_get_frame (val), 00232 kvpvalue_to_sql, qb); 00233 break; 00234 } 00235 default: 00236 { 00237 PERR (" unsupported value = %d", kvp_value_get_type (val)); 00238 break; 00239 } 00240 } 00241 LEAVE (" %s", qb->sql_str); 00242 }
static QofBackend* qsql_backend_new | ( | void | ) | [static] |
Starts the backend and creates the context.
Definition at line 1014 of file qof-sqlite.c.
01015 { 01016 QSQLiteBackend *qsql_be; 01017 QofBackend *be; 01018 01019 ENTER (" "); 01020 qsql_be = g_new0 (QSQLiteBackend, 1); 01021 be = (QofBackend *) qsql_be; 01022 qof_backend_init (be); 01023 qsql_be->kvp_table = g_hash_table_new (g_str_hash, g_str_equal); 01024 qsql_be->kvp_id = g_hash_table_new (g_str_hash, g_str_equal); 01025 qsql_be->dbversion = QOF_OBJECT_VERSION; 01026 qsql_be->stm_type = SQL_NONE; 01027 qsql_be->err_delete = 01028 qof_error_register (_("Unable to delete record."), FALSE); 01029 qsql_be->err_create = 01030 qof_error_register (_("Unable to create record."), FALSE); 01031 qsql_be->err_insert = 01032 qof_error_register (_("Unable to insert a new record."), FALSE); 01033 qsql_be->err_update = 01034 qof_error_register (_("Unable to update existing record."), FALSE); 01035 be->session_begin = qsqlite_session_begin; 01036 01037 be->session_end = qsqlite_session_end; 01038 be->destroy_backend = qsqlite_destroy_backend; 01039 be->load = qsqlite_db_load; 01040 be->save_may_clobber_data = NULL; 01041 /* begin: create an empty entity if none exists, 01042 even if events are suspended. */ 01043 be->begin = qsql_create; 01044 /* commit: write to sqlite, commit undo record. */ 01045 be->commit = qsql_modify; 01046 be->rollback = NULL; 01047 /* would need a QofQuery back to QofSqlQuery conversion. */ 01048 be->compile_query = NULL; 01049 /* unused */ 01050 be->free_query = NULL; 01051 be->run_query = NULL; 01052 be->counter = NULL; 01053 /* The QOF SQLite backend is not multi-user - all QOF users are the same. */ 01054 be->events_pending = NULL; 01055 be->process_events = NULL; 01056 01057 be->sync = qsqlite_write_db; 01058 be->load_config = NULL; 01059 be->get_config = NULL; 01060 LEAVE (" "); 01061 return be; 01062 }
static void qsql_class_foreach | ( | QofObject * | obj, | |
gpointer | data | |||
) | [static] |
receives QSQLiteBackend from QofBackend
Definition at line 757 of file qof-sqlite.c.
00758 { 00759 struct QsqlBuilder qb; 00760 QSQLiteBackend *qsql_be; 00761 QofBackend *be; 00762 00763 qsql_be = (QSQLiteBackend *) data; 00764 be = (QofBackend *) qsql_be; 00765 qb.qsql_be = qsql_be; 00766 qb.e_type = obj->e_type; 00767 ENTER (" obj_type=%s", qb.e_type); 00768 switch (qsql_be->stm_type) 00769 { 00770 case SQL_NONE: 00771 case SQL_INSERT: 00772 case SQL_DELETE: 00773 case SQL_UPDATE: 00774 { 00775 break; 00776 } 00777 case SQL_CREATE: 00778 { 00779 /* KVP is handled separately */ 00780 qb.sql_str = qof_sql_object_create_table (obj); 00781 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str, 00782 NULL, NULL, &qsql_be->err) != SQLITE_OK) 00783 { 00784 qof_error_set_be (be, qsql_be->err_create); 00785 qsql_be->error = TRUE; 00786 PERR (" error on SQL_CREATE:%s", qsql_be->err); 00787 } 00788 g_free (qb.sql_str); 00789 break; 00790 } 00791 case SQL_LOAD: 00792 { 00793 qb.sql_str = 00794 g_strdup_printf ("SELECT * FROM %s;", obj->e_type); 00795 PINFO (" sql=%s", qb.sql_str); 00796 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str, 00797 record_foreach, &qb, &qsql_be->err) != SQLITE_OK) 00798 { 00799 qsql_be->error = TRUE; 00800 PERR (" error on SQL_LOAD:%s", qsql_be->err); 00801 } 00802 break; 00803 } 00804 case SQL_WRITE: 00805 { 00806 if (!qof_book_not_saved (qsql_be->book)) 00807 break; 00808 qof_object_foreach (obj->e_type, qsql_be->book, check_state, 00809 &qb); 00810 break; 00811 } 00812 } 00813 LEAVE (" "); 00814 }
static void qsql_load_kvp | ( | QSQLiteBackend * | qsql_be | ) | [static] |
only call once per book
Definition at line 716 of file qof-sqlite.c.
00717 { 00718 struct QsqlBuilder qb; 00719 QofBackend *be; 00720 gint sq_code; 00721 00722 g_return_if_fail (qsql_be); 00723 sq_code = SQLITE_OK; 00724 be = (QofBackend *) qsql_be; 00725 qb.sql_str = 00726 g_strdup_printf ("SELECT kvp_id from %s;", QSQL_KVP_TABLE); 00727 sq_code = sqlite_exec (qsql_be->sqliteh, qb.sql_str, build_kvp_table, 00728 &qb, &qsql_be->err); 00729 /* catch older files without a sqlite_kvp table */ 00730 if (sq_code == SQLITE_ERROR) 00731 { 00732 g_free (qb.sql_str); 00733 qb.sql_str = 00734 g_strdup_printf ("CREATE TABLE %s (%s, %s, %s, %s, %s, %s", 00735 QSQL_KVP_TABLE, "kvp_id int primary key not null", 00736 "guid char(32)", "path mediumtext", "type mediumtext", 00737 "value text", END_DB_VERSION); 00738 PINFO (" creating kvp table. sql=%s", qb.sql_str); 00739 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str, 00740 record_foreach, &qb, &qsql_be->err) != SQLITE_OK) 00741 { 00742 qsql_be->error = TRUE; 00743 PERR (" unable to create kvp table:%s", qsql_be->err); 00744 } 00745 } 00746 else if (sq_code != SQLITE_OK) 00747 { 00748 qof_error_set_be (be, qsql_be->err_create); 00749 qsql_be->error = TRUE; 00750 PERR (" error on KVP select:%s:%s:%d", qb.sql_str, qsql_be->err, sq_code); 00751 } 00752 g_free (qb.sql_str); 00753 }
static gint record_foreach | ( | gpointer | builder, | |
gint | col_num, | |||
gchar ** | strings, | |||
gchar ** | columnNames | |||
) | [static] |
Definition at line 419 of file qof-sqlite.c.
00421 { 00422 QSQLiteBackend *qsql_be; 00423 struct QsqlBuilder *qb; 00424 const QofParam *param; 00425 QofInstance *inst; 00426 QofEntity *ent; 00427 gint i; 00428 00429 g_return_val_if_fail (builder, QSQL_ERROR); 00430 qb = (struct QsqlBuilder *) builder; 00431 qsql_be = qb->qsql_be; 00432 qof_event_suspend (); 00433 inst = (QofInstance *) qof_object_new_instance (qb->e_type, qsql_be->book); 00434 ent = &inst->entity; 00435 for (i = 0; i < col_num; i++) 00436 { 00437 /* get param and set as string */ 00438 param = qof_class_get_parameter (qb->e_type, columnNames[i]); 00439 if (!param) 00440 continue; 00441 /* set the inst->param entry */ 00442 inst->param = param; 00443 if (0 == safe_strcmp (columnNames[i], QOF_TYPE_GUID)) 00444 { 00445 GUID *guid; 00446 guid = guid_malloc (); 00447 if (!string_to_guid (strings[i], guid)) 00448 { 00449 DEBUG (" set guid failed:%s", strings[i]); 00450 return QSQL_ERROR; 00451 } 00452 qof_entity_set_guid (ent, guid); 00453 } 00454 if (strings[i]) 00455 qof_util_param_set_string (ent, param, strings[i]); 00456 } 00457 qof_event_resume (); 00458 return SQLITE_OK; 00459 }
static KvpValue* string_to_kvp_value | ( | const gchar * | content, | |
KvpValueType | type | |||
) | [static] |
Definition at line 117 of file qof-sqlite.c.
00118 { 00119 gchar *tail; 00120 gint64 cm_i64; 00121 gdouble cm_double; 00122 QofNumeric cm_numeric; 00123 GUID *cm_guid; 00124 00125 switch (type) 00126 { 00127 case KVP_TYPE_GINT64: 00128 { 00129 errno = 0; 00130 cm_i64 = strtoll (content, &tail, 0); 00131 if (errno == 0) 00132 { 00133 return kvp_value_new_gint64 (cm_i64); 00134 } 00135 break; 00136 } 00137 case KVP_TYPE_DOUBLE: 00138 { 00139 errno = 0; 00140 cm_double = strtod (content, &tail); 00141 if (errno == 0) 00142 return kvp_value_new_double (cm_double); 00143 break; 00144 } 00145 case KVP_TYPE_NUMERIC: 00146 { 00147 qof_numeric_from_string (content, &cm_numeric); 00148 return kvp_value_new_numeric (cm_numeric); 00149 break; 00150 } 00151 case KVP_TYPE_STRING: 00152 { 00153 return kvp_value_new_string (content); 00154 break; 00155 } 00156 case KVP_TYPE_GUID: 00157 { 00158 cm_guid = g_new0 (GUID, 1); 00159 if (TRUE == string_to_guid (content, cm_guid)) 00160 return kvp_value_new_guid (cm_guid); 00161 break; 00162 } 00163 case KVP_TYPE_TIME: 00164 { 00165 QofDate *qd; 00166 QofTime *qt; 00167 KvpValue *retval; 00168 00169 qd = qof_date_parse (content, QOF_DATE_FORMAT_UTC); 00170 if (qd) 00171 { 00172 qt = qof_date_to_qtime (qd); 00173 retval = kvp_value_new_time (qt); 00174 qof_date_free (qd); 00175 qof_time_free (qt); 00176 return retval; 00177 } 00178 else 00179 PERR (" failed to parse date"); 00180 } 00181 case KVP_TYPE_BOOLEAN: 00182 { 00183 gboolean val; 00184 val = qof_util_bool_to_int (content); 00185 return kvp_value_new_boolean (val); 00186 } 00187 default: 00188 break; 00189 } 00190 return NULL; 00191 }