00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "config.h"
00025 #include <errno.h>
00026 #include <stdlib.h>
00027 #include <time.h>
00028 #include <glib/gstdio.h>
00029 #include <sqlite.h>
00030 #include <glib.h>
00031 #include <libintl.h>
00032 #include "qof.h"
00033 #include "qofsql-p.h"
00034 #include "qof-sqlite.h"
00035 #include "kvputil-p.h"
00036
00037 #define _(String) dgettext (GETTEXT_PACKAGE, String)
00038 #define ACCESS_METHOD "sqlite"
00039
00046 #define PRIORITY_HIGH 9
00047
00048 #define PRIORITY_STANDARD 5
00049
00050 #define PRIORITY_LOW 0
00051
00052 #define QSQL_ERROR -1
00053
00054 #undef QSQL_KVP_TABLE
00055 #define QSQL_KVP_TABLE "sqlite_kvp"
00056
00057 #define END_DB_VERSION " dbversion int );"
00058
00059 static QofLogModule log_module = QOF_MOD_SQLITE;
00060 static gboolean loading = FALSE;
00061
00068 typedef struct
00069 {
00070 QofBackend be;
00071 sqlite *sqliteh;
00072 QsqlStatementType stm_type;
00073 gint dbversion;
00074 gint create_handler;
00075 gint delete_handler;
00076 const gchar *fullpath;
00077 gchar *err;
00078 gboolean error;
00079
00080 GHashTable *kvp_table;
00081
00082 GHashTable *kvp_id;
00083
00084 gulong index;
00085 QofBook *book;
00086 QofErrorId err_delete, err_insert, err_update, err_create;
00087 } QSQLiteBackend;
00088
00095 struct QsqlBuilder
00096 {
00098 QSQLiteBackend *qsql_be;
00100 QofEntity *ent;
00102 QofIdType e_type;
00104 gchar *sql_str;
00106 GList *dirty_list;
00108 gboolean exists;
00110 gboolean has_slots;
00112 const QofParam *dirty;
00113 };
00114
00116 static KvpValue *
00117 string_to_kvp_value (const gchar * content, KvpValueType type)
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 }
00192
00194 static G_GNUC_UNUSED void
00195 kvpvalue_to_sql (const gchar * key, KvpValue * val, gpointer builder)
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
00219
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 }
00243
00248 static void
00249 delete_event (QofEntity * ent, QofEventId event_type,
00250 gpointer handler_data, gpointer event_data)
00251 {
00252 QofBackend *be;
00253 QSQLiteBackend *qsql_be;
00254 gchar *gstr, *sql_str;
00255
00256 qsql_be = (QSQLiteBackend *) handler_data;
00257 be = (QofBackend *) qsql_be;
00258 if (!ent)
00259 return;
00260 if (0 == safe_strcmp (ent->e_type, QOF_ID_BOOK))
00261 return;
00262
00263 if (!qof_class_is_registered (ent->e_type))
00264 return;
00265 switch (event_type)
00266 {
00267 case QOF_EVENT_DESTROY:
00268 {
00269 ENTER (" %s do_free=%d", ent->e_type,
00270 ((QofInstance *) ent)->do_free);
00271 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
00272 guid_to_string_buff (qof_entity_get_guid (ent), gstr);
00273 sql_str = qof_sql_entity_delete (ent);
00274 DEBUG (" sql_str=%s", sql_str);
00275 if (sqlite_exec (qsql_be->sqliteh, sql_str,
00276 NULL, qsql_be, &qsql_be->err) != SQLITE_OK)
00277 {
00278 qof_error_set_be (be, qsql_be->err_delete);
00279 qsql_be->error = TRUE;
00280 LEAVE (" error on delete:%s", qsql_be->err);
00281 break;
00282 }
00283 LEAVE (" %d", event_type);
00284 qsql_be->error = FALSE;
00285 g_free (gstr);
00286 break;
00287 }
00288 default:
00289 break;
00290 }
00291 }
00292
00294 static void
00295 create_event (QofEntity * ent, QofEventId event_type,
00296 gpointer handler_data, gpointer event_data)
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
00342 slots = qof_instance_get_slots ((QofInstance *) ent);
00343 if (slots)
00344 {
00345
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 }
00373
00374 static void
00375 qsql_modify (QofBackend * be, QofInstance * inst)
00376 {
00377 struct QsqlBuilder qb;
00378 QSQLiteBackend *qsql_be;
00379
00380 qsql_be = (QSQLiteBackend *) be;
00381 qb.qsql_be = qsql_be;
00382 if (!inst)
00383 return;
00384 if (!inst->param)
00385 return;
00386 if (loading)
00387 return;
00388 if (!inst->param->param_setfcn)
00389 return;
00390 ENTER (" modified %s param:%s", ((QofEntity *) inst)->e_type,
00391 inst->param->param_name);
00392 qb.sql_str = qof_sql_entity_update ((QofEntity*)inst);
00393 if (!qb.sql_str)
00394 {
00395 LEAVE (" null string");
00396 return;
00397 }
00398 DEBUG (" sql_str=%s", qb.sql_str);
00399 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
00400 NULL, &qb, &qsql_be->err) != SQLITE_OK)
00401 {
00402 qof_error_set_be (be, qsql_be->err_update);
00403 qsql_be->error = TRUE;
00404 PERR (" error on modify:%s", qsql_be->err);
00405 }
00406 else
00407 {
00408 inst->dirty = FALSE;
00409 g_free (qb.sql_str);
00410 qsql_be->error = FALSE;
00411 LEAVE (" ");
00412 return;
00413 }
00414 LEAVE (" ");
00415 }
00416
00418 static gint
00419 record_foreach (gpointer builder, gint col_num, gchar ** strings,
00420 gchar ** columnNames)
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
00438 param = qof_class_get_parameter (qb->e_type, columnNames[i]);
00439 if (!param)
00440 continue;
00441
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 }
00460
00461 static void
00462 update_dirty (gpointer value, gpointer builder)
00463 {
00464 QofInstance *inst;
00465 QofEntity *ent;
00466 struct QsqlBuilder *qb;
00467 QSQLiteBackend *qsql_be;
00468 QofBackend *be;
00469 gchar *gstr;
00470
00471 qb = (struct QsqlBuilder *) builder;
00472 qsql_be = qb->qsql_be;
00473 be = (QofBackend *) qsql_be;
00474 ent = (QofEntity *) value;
00475 inst = (QofInstance *) ent;
00476 if (!inst->dirty)
00477 return;
00478 ENTER (" ");
00479 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
00480 guid_to_string_buff (qof_entity_get_guid (ent), gstr);
00481
00482 qb->sql_str = qof_sql_entity_update (ent);
00483 if (!qb->sql_str)
00484 {
00485 LEAVE (" null string");
00486 return;
00487 }
00488 DEBUG (" update=%s", qb->sql_str);
00489 if (sqlite_exec (qsql_be->sqliteh, qb->sql_str,
00490 NULL, qb, &qsql_be->err) != SQLITE_OK)
00491 {
00492 qof_error_set_be (be, qsql_be->err_update);
00493 qsql_be->error = TRUE;
00494 PERR (" error on update_dirty:%s", qsql_be->err);
00495 }
00496 else
00497 {
00498 qof_error_get_message_be (be);
00499 qsql_be->error = FALSE;
00500 inst->dirty = FALSE;
00501 }
00502 LEAVE (" ");
00503 g_free (gstr);
00504 return;
00505 }
00506
00507 static gint
00508 create_dirty_list (gpointer builder, gint col_num, gchar ** strings,
00509 gchar ** columnNames)
00510 {
00511 struct QsqlBuilder *qb;
00512 QofInstance *inst;
00513 const QofParam *param;
00514 gchar *value, *columnName, *tmp;
00515
00516 param = NULL;
00517 qb = (struct QsqlBuilder *) builder;
00518
00519 inst = (QofInstance *) qb->ent;
00520 qb->exists = TRUE;
00521 if (!inst->dirty)
00522 return SQLITE_OK;
00523 columnName = columnNames[col_num];
00524 tmp = strings[col_num];
00525 param = qof_class_get_parameter (qb->ent->e_type, columnName);
00526 if (!param)
00527 return SQLITE_OK;
00528 value = qof_util_param_to_string (qb->ent, param);
00529 qb->dirty = param;
00530 qb->dirty_list = g_list_prepend (qb->dirty_list, qb->ent);
00531 DEBUG (" dirty_list=%d", g_list_length (qb->dirty_list));
00532 return SQLITE_OK;
00533 }
00534
00535 static gint
00536 mark_entity (gpointer builder, gint col_num, gchar ** strings,
00537 gchar ** columnNames)
00538 {
00539 struct QsqlBuilder *qb;
00540
00541 qb = (struct QsqlBuilder *) builder;
00542 qb->exists = TRUE;
00543 return SQLITE_OK;
00544 }
00545
00546 static void
00547 qsql_create (QofBackend * be, QofInstance * inst)
00548 {
00549 gchar *gstr;
00550 QSQLiteBackend *qsql_be;
00551 struct QsqlBuilder qb;
00552 QofEntity *ent;
00553
00554 qsql_be = (QSQLiteBackend *) be;
00555 if (!inst)
00556 return;
00557 if (loading)
00558 return;
00559 ent = (QofEntity *) inst;
00560 qof_event_suspend ();
00561 qb.has_slots = FALSE;
00562 ENTER (" %s", ent->e_type);
00563 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
00564 guid_to_string_buff (qof_entity_get_guid (ent), gstr);
00565 qb.sql_str =
00566 g_strdup_printf ("SELECT * FROM %s where guid = \"%s\";",
00567 ent->e_type, gstr);
00568 PINFO (" check exists: %s", qb.sql_str);
00569 qb.ent = ent;
00570 qb.dirty_list = NULL;
00571 qb.exists = FALSE;
00572 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
00573 mark_entity, &qb, &qsql_be->err) != SQLITE_OK)
00574 {
00575 qof_error_set_be (be, qsql_be->err_update);
00576 qsql_be->error = TRUE;
00577 PERR (" error on select :%s", qsql_be->err);
00578 }
00579 if (!qb.exists)
00580 {
00581
00582 qb.sql_str = qof_sql_entity_insert (ent);
00583 DEBUG (" sql_str= %s", qb.sql_str);
00584 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
00585 NULL, qsql_be, &qsql_be->err) != SQLITE_OK)
00586 {
00587 qof_error_set_be (be, qsql_be->err_insert);
00588 qsql_be->error = TRUE;
00589 PERR (" error creating new entity:%s", qsql_be->err);
00590 }
00591 }
00592 g_free (qb.sql_str);
00593 g_free (gstr);
00594 qof_event_resume ();
00595 LEAVE (" ");
00596 }
00597
00598 static void
00599 check_state (QofEntity * ent, gpointer builder)
00600 {
00601 gchar *gstr;
00602 QSQLiteBackend *qsql_be;
00603 struct QsqlBuilder *qb;
00604 QofBackend *be;
00605 QofInstance *inst;
00606
00607 qb = (struct QsqlBuilder *) builder;
00608 qsql_be = qb->qsql_be;
00609 be = (QofBackend *) qsql_be;
00610 inst = (QofInstance *) ent;
00611 if (!inst->dirty)
00612 return;
00613
00614 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
00615 guid_to_string_buff (qof_entity_get_guid (ent), gstr);
00616 qb->sql_str =
00617 g_strdup_printf ("SELECT * FROM %s where guid = \"%s\";",
00618 ent->e_type, gstr);
00619 qb->ent = ent;
00620 qb->dirty_list = NULL;
00621
00622
00623 qb->exists = FALSE;
00624 qb->qsql_be = qsql_be;
00625
00626
00627
00628
00629 if (sqlite_exec (qsql_be->sqliteh, qb->sql_str,
00630 create_dirty_list, qb, &qsql_be->err) != SQLITE_OK)
00631 {
00632 qof_error_set_be (be, qsql_be->err_update);
00633 qsql_be->error = TRUE;
00634 PERR (" error on check_state:%s", qsql_be->err);
00635 }
00636 if (!qb->exists)
00637 {
00638
00639 qb->sql_str = qof_sql_entity_insert (ent);
00640 DEBUG (" sql_str= %s", qb->sql_str);
00641 if (sqlite_exec (qsql_be->sqliteh, qb->sql_str,
00642 NULL, qb, &qsql_be->err) != SQLITE_OK)
00643 {
00644 qof_error_set_be (be, qsql_be->err_insert);
00645 qsql_be->error = TRUE;
00646 PERR (" error on check_state create_new:%s", qsql_be->err);
00647 }
00648 g_free (qb->sql_str);
00649 }
00650
00651 g_list_foreach (qb->dirty_list, update_dirty, &qb);
00652 g_free (qb->sql_str);
00653 g_free (gstr);
00654 }
00655
00664 static gint
00665 build_kvp_table (gpointer builder, gint col_num, gchar ** strings,
00666 gchar ** columnNames)
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
00684
00685
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
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
00700 kvp_frame_set_value (frame, strings[2], value);
00701
00702 g_hash_table_insert (qsql_be->kvp_table, strings[1], frame);
00703
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 }
00713
00715 static void
00716 qsql_load_kvp (QSQLiteBackend * qsql_be)
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
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 }
00754
00756 static void
00757 qsql_class_foreach (QofObject * obj, gpointer data)
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
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 }
00815
00816 static void
00817 qsql_backend_createdb (QofBackend * be, QofSession * session)
00818 {
00819 FILE *f;
00820 QSQLiteBackend *qsql_be;
00821 struct QsqlBuilder qb;
00822
00823 g_return_if_fail (be || session);
00824 ENTER (" ");
00825 qsql_be = (QSQLiteBackend *) be;
00826 qsql_be->stm_type = SQL_CREATE;
00827 qb.qsql_be = qsql_be;
00828 qsql_be->book = qof_session_get_book (session);
00829 DEBUG (" create_file %s", qsql_be->fullpath);
00830 f = fopen (qsql_be->fullpath, "a+");
00831 if (f)
00832 fclose (f);
00833 else
00834 {
00835 qof_error_set (session, qof_error_register
00836 (_("Unable to open the output file '%s' - do you have "
00837 "permission to create this file?"), TRUE));
00838 qsql_be->error = TRUE;
00839 LEAVE (" unable to create new file '%s'", qsql_be->fullpath);
00840 return;
00841 }
00842 qsql_be->sqliteh =
00843 sqlite_open (qsql_be->fullpath, 0644, &qsql_be->err);
00844 if (!qsql_be->sqliteh)
00845 {
00846 qof_error_set_be (be, qsql_be->err_create);
00847 qsql_be->error = TRUE;
00848 LEAVE (" unable to open sqlite:%s", qsql_be->err);
00849 return;
00850 }
00851 qof_object_foreach_type (qsql_class_foreach, qsql_be);
00852 LEAVE (" ");
00853 }
00854
00855 static void
00856 qsql_backend_opendb (QofBackend * be, QofSession * session)
00857 {
00858 QSQLiteBackend *qsql_be;
00859
00860 g_return_if_fail (be || session);
00861 ENTER (" ");
00862 qsql_be = (QSQLiteBackend *) be;
00863 qsql_be->sqliteh =
00864 sqlite_open (qsql_be->fullpath, 0666, &qsql_be->err);
00865 if (!qsql_be->sqliteh)
00866 {
00867 qof_error_set_be (be, qof_error_register
00868 (_("Unable to open the sqlite database '%s'."), TRUE));
00869 qsql_be->error = TRUE;
00870 PERR (" %s", qsql_be->err);
00871 }
00872 LEAVE (" %s", qsql_be->fullpath);
00873 }
00874
00875 static void
00876 qsqlite_session_begin (QofBackend * be, QofSession * session,
00877 const gchar * book_path, gboolean ignore_lock,
00878 gboolean create_if_nonexistent)
00879 {
00880 QSQLiteBackend *qsql_be;
00881 gchar **pp;
00882 struct stat statinfo;
00883 gint stat_val;
00884
00885 g_return_if_fail (be);
00886 ENTER (" book_path=%s", book_path);
00887 qsql_be = (QSQLiteBackend *) be;
00888 qsql_be->fullpath = NULL;
00889 if (book_path == NULL)
00890 {
00891 qof_error_set_be (be, qof_error_register
00892 (_("Please provide a filename for sqlite."), FALSE));
00893 qsql_be->error = TRUE;
00894 LEAVE (" bad URL");
00895 return;
00896 }
00897
00898 pp = g_strsplit (book_path, ":", 2);
00899 if (0 == safe_strcmp (pp[0], ACCESS_METHOD))
00900 {
00901 qsql_be->fullpath = g_strdup (pp[1]);
00902 g_strfreev (pp);
00903 }
00904 else
00905 qsql_be->fullpath = g_strdup (book_path);
00906 be->fullpath = g_strdup (qsql_be->fullpath);
00907 PINFO (" final path = %s", qsql_be->fullpath);
00908 stat_val = g_stat (qsql_be->fullpath, &statinfo);
00909 if (!S_ISREG (statinfo.st_mode) || statinfo.st_size == 0)
00910 qsql_backend_createdb (be, session);
00911 if (!qsql_be->error)
00912 qsql_backend_opendb (be, session);
00913 if (qof_error_check_be (be) || qsql_be->error)
00914 {
00915 LEAVE (" open failed");
00916 return;
00917 }
00918 qsql_be->create_handler =
00919 qof_event_register_handler (create_event, qsql_be);
00920 qsql_be->delete_handler =
00921 qof_event_register_handler (delete_event, qsql_be);
00922 LEAVE (" db=%s", qsql_be->fullpath);
00923 }
00924
00925 static void
00926 qsqlite_db_load (QofBackend * be, QofBook * book)
00927 {
00928 QSQLiteBackend *qsql_be;
00929
00930 g_return_if_fail (be);
00931 ENTER (" ");
00932 loading = TRUE;
00933 qsql_be = (QSQLiteBackend *) be;
00934 qsql_be->stm_type = SQL_LOAD;
00935 qsql_be->book = book;
00936
00937 qof_object_foreach_type (qsql_class_foreach, qsql_be);
00938 qsql_load_kvp (qsql_be);
00939 loading = FALSE;
00940 LEAVE (" ");
00941 }
00942
00943 static void
00944 qsqlite_write_db (QofBackend * be, QofBook * book)
00945 {
00946 QSQLiteBackend *qsql_be;
00947
00948 g_return_if_fail (be);
00949 qsql_be = (QSQLiteBackend *) be;
00950 qsql_be->stm_type = SQL_WRITE;
00951 qsql_be->book = book;
00952
00953 qof_object_foreach_type (qsql_class_foreach, qsql_be);
00954 }
00955
00956 static gboolean
00957 qsql_determine_file_type (const gchar * path)
00958 {
00959 if (!path)
00960 return FALSE;
00961 return TRUE;
00962 }
00963
00964 static void
00965 qsqlite_session_end (QofBackend * be)
00966 {
00967 QSQLiteBackend *qsql_be;
00968
00969 g_return_if_fail (be);
00970 qsql_be = (QSQLiteBackend *) be;
00971 if (qsql_be->sqliteh)
00972 sqlite_close (qsql_be->sqliteh);
00973 }
00974
00975 static void
00976 qsqlite_destroy_backend (QofBackend * be)
00977 {
00978 QSQLiteBackend *qsql_be;
00979
00980 g_return_if_fail (be);
00981 qsql_be = (QSQLiteBackend *) be;
00982 g_hash_table_destroy (qsql_be->kvp_table);
00983 g_hash_table_destroy (qsql_be->kvp_id);
00984 qof_event_unregister_handler (qsql_be->create_handler);
00985 qof_event_unregister_handler (qsql_be->delete_handler);
00986 g_free (be);
00987 g_free (qsql_be);
00988 }
00989
00990 static void
00991 qsql_provider_free (QofBackendProvider * prov)
00992 {
00993 prov->provider_name = NULL;
00994 prov->access_method = NULL;
00995 g_free (prov);
00996 }
00997
01013 static QofBackend *
01014 qsql_backend_new (void)
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
01042
01043 be->begin = qsql_create;
01044
01045 be->commit = qsql_modify;
01046 be->rollback = NULL;
01047
01048 be->compile_query = NULL;
01049
01050 be->free_query = NULL;
01051 be->run_query = NULL;
01052 be->counter = NULL;
01053
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 }
01063
01064 void
01065 qof_sqlite_provider_init (void)
01066 {
01067 QofBackendProvider *prov;
01068
01069 ENTER (" ");
01070 bindtextdomain (PACKAGE, LOCALE_DIR);
01071 qof_sql_entity_set_kvp_tablename (QSQL_KVP_TABLE);
01072 prov = g_new0 (QofBackendProvider, 1);
01073 prov->provider_name = "QOF SQLite Backend Version 0.4";
01074 prov->access_method = ACCESS_METHOD;
01075 prov->partial_book_supported = TRUE;
01076 prov->backend_new = qsql_backend_new;
01077 prov->check_data_type = qsql_determine_file_type;
01078 prov->provider_free = qsql_provider_free;
01079 qof_backend_register_provider (prov);
01080 LEAVE (" ");
01081 }
01082
01083