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
00034 #define _(String) dgettext (GETTEXT_PACKAGE, String)
00035 #define ACCESS_METHOD "sqlite"
00036
00043 #define PRIORITY_HIGH 9
00044
00045 #define PRIORITY_STANDARD 5
00046
00047 #define PRIORITY_LOW 0
00048
00049 #define QSQL_ERROR -1
00050
00051 #define QSQL_KVP_TABLE "sqlite_kvp"
00052
00053 #define END_DB_VERSION " dbversion int );"
00054
00055 static QofLogModule log_module = QOF_MOD_SQLITE;
00056 static gboolean loading = FALSE;
00057
00058 typedef enum
00059 {
00061 SQL_NONE = 0,
00063 SQL_CREATE,
00065 SQL_LOAD,
00067 SQL_WRITE,
00069 SQL_INSERT,
00071 SQL_DELETE,
00073 SQL_UPDATE
00074 } QsqlStatementType;
00075
00082 typedef struct
00083 {
00084 QofBackend be;
00085 sqlite *sqliteh;
00086 QsqlStatementType stm_type;
00087 gint dbversion;
00088 gint create_handler;
00089 gint delete_handler;
00090 const gchar *fullpath;
00091 gchar *err;
00092 gboolean error;
00093
00094 GHashTable *kvp_table;
00095
00096 GHashTable *kvp_id;
00097
00098 glong index;
00099 QofBook *book;
00100 QofErrorId err_delete, err_insert, err_update, err_create;
00101 } QSQLiteBackend;
00102
00109 struct QsqlBuilder
00110 {
00112 QSQLiteBackend *qsql_be;
00114 QofEntity *ent;
00116 QofIdType e_type;
00118 gchar *sql_str;
00120 GList *dirty_list;
00122 gboolean exists;
00124 gboolean has_slots;
00126 const QofParam *dirty;
00127 };
00128
00129 static inline gchar *
00130 add_to_sql (gchar * sql_str, const gchar * add)
00131 {
00132 gchar *old;
00133 old = g_strdup (sql_str);
00134 g_free (sql_str);
00135 sql_str = g_strconcat (old, add, NULL);
00136 g_free (old);
00137 return sql_str;
00138 }
00139
00144 static QofIdTypeConst
00145 kvp_value_to_qof_type_helper (KvpValueType n)
00146 {
00147 switch (n)
00148 {
00149 case KVP_TYPE_GINT64:
00150 {
00151 return QOF_TYPE_INT64;
00152 break;
00153 }
00154 case KVP_TYPE_DOUBLE:
00155 {
00156 return QOF_TYPE_DOUBLE;
00157 break;
00158 }
00159 case KVP_TYPE_NUMERIC:
00160 {
00161 return QOF_TYPE_NUMERIC;
00162 break;
00163 }
00164 case KVP_TYPE_STRING:
00165 {
00166 return QOF_TYPE_STRING;
00167 break;
00168 }
00169 case KVP_TYPE_GUID:
00170 {
00171 return QOF_TYPE_GUID;
00172 break;
00173 }
00174 #ifndef QOF_DISABLE_DEPRECATED
00175 case KVP_TYPE_TIMESPEC:
00176 {
00177 return QOF_TYPE_DATE;
00178 break;
00179 }
00180 #endif
00181 case KVP_TYPE_BOOLEAN:
00182 {
00183 return QOF_TYPE_BOOLEAN;
00184 break;
00185 }
00186 case KVP_TYPE_TIME:
00187 {
00188 return QOF_TYPE_TIME;
00189 break;
00190 }
00191 default:
00192 {
00193 return NULL;
00194 }
00195 }
00196 }
00197
00199 static KvpValueType
00200 sql_to_kvp_helper (const gchar * type_string)
00201 {
00202 if (0 == safe_strcmp (QOF_TYPE_INT64, type_string))
00203 return KVP_TYPE_GINT64;
00204 if (0 == safe_strcmp (QOF_TYPE_DOUBLE, type_string))
00205 return KVP_TYPE_DOUBLE;
00206 if (0 == safe_strcmp (QOF_TYPE_NUMERIC, type_string))
00207 return KVP_TYPE_NUMERIC;
00208 if (0 == safe_strcmp (QOF_TYPE_STRING, type_string))
00209 return KVP_TYPE_STRING;
00210 if (0 == safe_strcmp (QOF_TYPE_GUID, type_string))
00211 return KVP_TYPE_GUID;
00212 #ifndef QOF_DISABLE_DEPRECATED
00213 if (0 == safe_strcmp (QOF_TYPE_DATE, type_string))
00214 return KVP_TYPE_TIMESPEC;
00215 #endif
00216 if (0 == safe_strcmp (QOF_TYPE_TIME, type_string))
00217 return KVP_TYPE_TIME;
00218 return 0;
00219 }
00220
00222 KvpValue *
00223 string_to_kvp_value (const gchar * content, KvpValueType type)
00224 {
00225 gchar *tail;
00226 gint64 cm_i64;
00227 gdouble cm_double;
00228 QofNumeric cm_numeric;
00229 GUID *cm_guid;
00230 #ifndef QOF_DISABLE_DEPRECATED
00231 struct tm kvp_time;
00232 time_t kvp_time_t;
00233 Timespec cm_date;
00234 #endif
00235
00236 switch (type)
00237 {
00238 case KVP_TYPE_GINT64:
00239 {
00240 errno = 0;
00241 cm_i64 = strtoll (content, &tail, 0);
00242 if (errno == 0)
00243 {
00244 return kvp_value_new_gint64 (cm_i64);
00245 }
00246 break;
00247 }
00248 case KVP_TYPE_DOUBLE:
00249 {
00250 errno = 0;
00251 cm_double = strtod (content, &tail);
00252 if (errno == 0)
00253 return kvp_value_new_double (cm_double);
00254 break;
00255 }
00256 case KVP_TYPE_NUMERIC:
00257 {
00258 qof_numeric_from_string (content, &cm_numeric);
00259 return kvp_value_new_numeric (cm_numeric);
00260 break;
00261 }
00262 case KVP_TYPE_STRING:
00263 {
00264 return kvp_value_new_string (content);
00265 break;
00266 }
00267 case KVP_TYPE_GUID:
00268 {
00269 cm_guid = g_new0 (GUID, 1);
00270 if (TRUE == string_to_guid (content, cm_guid))
00271 return kvp_value_new_guid (cm_guid);
00272 break;
00273 }
00274 case KVP_TYPE_TIME:
00275 {
00276 QofDate *qd;
00277 QofTime *qt;
00278 KvpValue *retval;
00279
00280 qd = qof_date_parse (content, QOF_DATE_FORMAT_UTC);
00281 if (qd)
00282 {
00283 qt = qof_date_to_qtime (qd);
00284 retval = kvp_value_new_time (qt);
00285 qof_date_free (qd);
00286 qof_time_free (qt);
00287 return retval;
00288 }
00289 else
00290 PERR (" failed to parse date");
00291 }
00292 #ifndef QOF_DISABLE_DEPRECATED
00293 case KVP_TYPE_TIMESPEC:
00294 {
00295 strptime (content, QOF_UTC_DATE_FORMAT, &kvp_time);
00296 kvp_time_t = mktime (&kvp_time);
00297 timespecFromTime_t (&cm_date, kvp_time_t);
00298 return kvp_value_new_timespec (cm_date);
00299 break;
00300 }
00301 #endif
00302 case KVP_TYPE_BOOLEAN:
00303 {
00304 gboolean val;
00305 val = qof_util_bool_to_int (content);
00306 return kvp_value_new_boolean (val);
00307 }
00308 default:
00309 break;
00310 }
00311 return NULL;
00312 }
00313
00315 static void
00316 kvpvalue_to_sql (const gchar * key, KvpValue * val, gpointer builder)
00317 {
00318 QSQLiteBackend *qsql_be;
00319 struct QsqlBuilder *qb;
00320 KvpValueType n;
00321 gchar *full_path;
00322
00323 full_path = NULL;
00324 ENTER (" ");
00325 qb = (struct QsqlBuilder *) builder;
00326 qsql_be = qb->qsql_be;
00327 g_return_if_fail (key && val && qsql_be);
00328 n = kvp_value_get_type (val);
00329 switch (n)
00330 {
00331 case KVP_TYPE_GINT64:
00332 case KVP_TYPE_DOUBLE:
00333 case KVP_TYPE_NUMERIC:
00334 case KVP_TYPE_STRING:
00335 case KVP_TYPE_GUID:
00336 case KVP_TYPE_TIME:
00337 case KVP_TYPE_BOOLEAN:
00338 #ifndef QOF_DISABLE_DEPRECATED
00339 case KVP_TYPE_TIMESPEC:
00340 #endif
00341 {
00342
00343
00344
00345 qb->sql_str =
00346 g_strdup_printf (" kvp key=%s val=%s type=%s", key,
00347 kvp_value_to_bare_string (val),
00348 kvp_value_to_qof_type_helper (n));
00349 DEBUG (" %s", qb->sql_str);
00350 qb->has_slots = TRUE;
00351 break;
00352 }
00353 case KVP_TYPE_FRAME:
00354 {
00355 kvp_frame_for_each_slot (kvp_value_get_frame (val),
00356 kvpvalue_to_sql, qb);
00357 break;
00358 }
00359 default:
00360 {
00361 PERR (" unsupported value = %d", kvp_value_get_type (val));
00362 break;
00363 }
00364 }
00365 LEAVE (" %s", qb->sql_str);
00366 }
00367
00368 static gchar *
00369 string_param_to_sql (QofParam * param)
00370 {
00371
00372
00373 if ((0 == safe_strcmp (param->param_type, QOF_TYPE_GUID)) &&
00374 (0 == safe_strcmp (param->param_name, QOF_PARAM_GUID)))
00375 return g_strdup_printf (" %s char(32) primary key not null",
00376 param->param_name);
00377 if (0 == safe_strcmp (param->param_type, QOF_TYPE_GUID))
00378 return g_strdup_printf (" %s char(32)", param->param_name);
00379
00380 if (!param->param_setfcn)
00381 return NULL;
00382 if (0 == safe_strcmp (param->param_type, QOF_TYPE_STRING))
00383 return g_strdup_printf (" %s mediumtext", param->param_name);
00384 if (0 == safe_strcmp (param->param_type, QOF_TYPE_BOOLEAN))
00385 return g_strdup_printf (" %s int", param->param_name);
00386 if ((0 == safe_strcmp (param->param_type, QOF_TYPE_NUMERIC))
00387 || (0 == safe_strcmp (param->param_type, QOF_TYPE_DOUBLE))
00388 || (0 == safe_strcmp (param->param_type, QOF_TYPE_DEBCRED)))
00389 {
00390 return g_strdup_printf (" %s text", param->param_name);
00391 }
00392 if (0 == safe_strcmp (param->param_type, QOF_TYPE_INT32))
00393 return g_strdup_printf (" %s int", param->param_name);
00394 #ifndef QOF_DISABLE_DEPRECATED
00395 if ((0 == safe_strcmp (param->param_type, QOF_TYPE_DATE)) ||
00396 (0 == safe_strcmp (param->param_type, QOF_TYPE_TIME)))
00397 #else
00398 if (0 == safe_strcmp (param->param_type, QOF_TYPE_TIME))
00399 #endif
00400 return g_strdup_printf (" %s datetime", param->param_name);
00401 if (0 == safe_strcmp (param->param_type, QOF_TYPE_CHAR))
00402 return g_strdup_printf (" %s char(1)", param->param_name);
00403
00404
00405 if (0 == safe_strcmp (param->param_type, QOF_TYPE_KVP))
00406 return g_strdup ("");
00407 if (0 == safe_strcmp (param->param_type, QOF_TYPE_COLLECT))
00408 return g_strdup_printf (" %s char(32)", param->param_name);
00409
00410 return g_strdup_printf (" %s char(32)", param->param_name);
00411 }
00412
00418 static void
00419 create_param_list (QofParam * param, gpointer builder)
00420 {
00421 struct QsqlBuilder *qb;
00422 qb = (struct QsqlBuilder *) builder;
00423
00424
00425 if (!param->param_setfcn)
00426 return;
00427
00428
00429 if (0 == safe_strcmp (param->param_type, QOF_TYPE_KVP))
00430 {
00431 PINFO (" kvp support tag");
00432 return;
00433 }
00434 if (!g_str_has_suffix (qb->sql_str, "("))
00435 {
00436 gchar *add;
00437 add = g_strconcat (", ", param->param_name, NULL);
00438 qb->sql_str = add_to_sql (qb->sql_str, add);
00439 g_free (add);
00440 }
00441 else
00442 qb->sql_str = add_to_sql (qb->sql_str, param->param_name);
00443 }
00444
00446 static void
00447 create_each_param (QofParam * param, gpointer builder)
00448 {
00449 gchar *value;
00450 struct QsqlBuilder *qb;
00451 qb = (struct QsqlBuilder *) builder;
00452 GList *references;
00453
00454
00455 if (!param->param_setfcn)
00456 return;
00457
00458
00459 if (0 == safe_strcmp (param->param_type, QOF_TYPE_KVP))
00460 return;
00461 references = qof_class_get_referenceList (qb->ent->e_type);
00462 if (g_list_find (references, param))
00463 {
00466 QofEntity *e;
00467 e = param->param_getfcn (qb->ent, param);
00468 value = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
00469 guid_to_string_buff (qof_entity_get_guid (e), value);
00470 PINFO (" ref=%p GUID=%s", e, value);
00471 }
00472 else
00473 value = qof_util_param_to_string (qb->ent, param);
00474 if (value)
00475 g_strescape (value, NULL);
00476 if (!value)
00477 value = g_strdup ("");
00478 if (!g_str_has_suffix (qb->sql_str, "("))
00479 {
00480 gchar *val;
00481 val = g_strconcat (", \"", value, "\"", NULL);
00482 qb->sql_str = add_to_sql (qb->sql_str, val);
00483 g_free (val);
00484 }
00485 else
00486 {
00487 gchar *val;
00488 val = g_strconcat ("\"", value, "\"", NULL);
00489 qb->sql_str = add_to_sql (qb->sql_str, val);
00490 g_free (val);
00491 }
00492 }
00493
00498 static void
00499 delete_event (QofEntity * ent, QofEventId event_type,
00500 gpointer handler_data, gpointer event_data)
00501 {
00502 QofBackend *be;
00503 QSQLiteBackend *qsql_be;
00504 gchar *gstr, *sql_str;
00505
00506 qsql_be = (QSQLiteBackend *) handler_data;
00507 be = (QofBackend *) qsql_be;
00508 if (!ent)
00509 return;
00510 if (0 == safe_strcmp (ent->e_type, QOF_ID_BOOK))
00511 return;
00512
00513 if (!qof_class_is_registered (ent->e_type))
00514 return;
00515 switch (event_type)
00516 {
00517 case QOF_EVENT_DESTROY:
00518 {
00519 ENTER (" %s do_free=%d", ent->e_type,
00520 ((QofInstance *) ent)->do_free);
00521 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
00522 guid_to_string_buff (qof_entity_get_guid (ent), gstr);
00523 sql_str = g_strconcat ("DELETE from ", ent->e_type, " WHERE ",
00524 QOF_TYPE_GUID, "='", gstr, "';", NULL);
00525 DEBUG (" sql_str=%s", sql_str);
00526 if (sqlite_exec (qsql_be->sqliteh, sql_str,
00527 NULL, qsql_be, &qsql_be->err) != SQLITE_OK)
00528 {
00529 qof_error_set_be (be, qsql_be->err_delete);
00530 qsql_be->error = TRUE;
00531 LEAVE (" error on delete:%s", qsql_be->err);
00532 break;
00533 }
00535
00536 LEAVE (" %d", event_type);
00537 qsql_be->error = FALSE;
00538 g_free (gstr);
00539 break;
00540 }
00541 default:
00542 break;
00543 }
00544 }
00545
00547 static void
00548 create_event (QofEntity * ent, QofEventId event_type,
00549 gpointer handler_data, gpointer event_data)
00550 {
00551 QofBackend *be;
00552 struct QsqlBuilder qb;
00553 QSQLiteBackend *qsql_be;
00554 gchar *gstr;
00555 KvpFrame *slots;
00556
00557 qsql_be = (QSQLiteBackend *) handler_data;
00558 be = (QofBackend *) qsql_be;
00559 if (!ent)
00560 return;
00561 if (0 == safe_strcmp (ent->e_type, QOF_ID_BOOK))
00562 return;
00563 if (!qof_class_is_registered (ent->e_type))
00564 return;
00565 switch (event_type)
00566 {
00567 case QOF_EVENT_CREATE:
00568 {
00569 gchar *tmp;
00570 ENTER (" create:%s", ent->e_type);
00571 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
00572 guid_to_string_buff (qof_instance_get_guid ((QofInstance *)
00573 ent), gstr);
00574 DEBUG (" guid=%s", gstr);
00575 qb.ent = ent;
00576 qb.sql_str =
00577 g_strdup_printf ("INSERT into %s (guid ", ent->e_type);
00578 qof_class_param_foreach (ent->e_type, create_param_list, &qb);
00579 tmp = g_strconcat (") VALUES (\"", gstr, "\" ", NULL);
00580 qb.sql_str = add_to_sql (qb.sql_str, tmp);
00581 g_free (tmp);
00582 qof_class_param_foreach (ent->e_type, create_each_param, &qb);
00583 qb.sql_str = add_to_sql (qb.sql_str, ");");
00584 DEBUG (" sql_str=%s", qb.sql_str);
00585 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
00586 NULL, &qb, &qsql_be->err) != SQLITE_OK)
00587 {
00588 qof_error_set_be (be, qsql_be->err_insert);
00589 qsql_be->error = TRUE;
00590 PERR (" error on create_event:%s", qsql_be->err);
00591 }
00592 else
00593 {
00594 ((QofInstance *) ent)->dirty = FALSE;
00595 qsql_be->error = FALSE;
00596 g_free (qb.sql_str);
00597 g_free (gstr);
00598 LEAVE (" ");
00599 break;
00600 }
00601
00602 slots = qof_instance_get_slots ((QofInstance *) ent);
00603 if (slots)
00604 {
00605
00606 qb.sql_str = g_strconcat ("INSERT into ", QSQL_KVP_TABLE,
00607 " (kvp_id \"", gstr, "\", ", NULL);
00608 kvp_frame_for_each_slot (slots, kvpvalue_to_sql, &qb);
00609 qb.sql_str = add_to_sql (qb.sql_str, END_DB_VERSION);
00610 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
00611 NULL, &qb, &qsql_be->err) != SQLITE_OK)
00612 {
00613 qof_error_set_be (be, qsql_be->err_insert);
00614 qsql_be->error = TRUE;
00615 PERR (" error on KVP create_event:%s", qsql_be->err);
00616 }
00617 else
00618 {
00619 ((QofInstance *) ent)->dirty = FALSE;
00620 qsql_be->error = FALSE;
00621 g_free (qb.sql_str);
00622 g_free (gstr);
00623 LEAVE (" ");
00624 break;
00625 }
00626 }
00627 g_free (qb.sql_str);
00628 g_free (gstr);
00629 LEAVE (" ");
00630 break;
00631 }
00632 default:
00633 break;
00634 }
00635 }
00636
00637 static void
00638 qsql_modify (QofBackend * be, QofInstance * inst)
00639 {
00640 struct QsqlBuilder qb;
00641 QSQLiteBackend *qsql_be;
00642 gchar *gstr, *param_str;
00643 KvpFrame *slots;
00644
00645 qsql_be = (QSQLiteBackend *) be;
00646 qb.qsql_be = qsql_be;
00647 if (!inst)
00648 return;
00649 if (!inst->param)
00650 return;
00651 if (loading)
00652 return;
00653 if (!inst->param->param_setfcn)
00654 return;
00655 ENTER (" modified %s param:%s", ((QofEntity *) inst)->e_type,
00656 inst->param->param_name);
00657 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
00658 guid_to_string_buff (qof_instance_get_guid (inst), gstr);
00659 qb.ent = (QofEntity *) inst;
00660 param_str = qof_util_param_to_string (qb.ent, inst->param);
00661 if (param_str)
00662 g_strescape (param_str, NULL);
00663 qb.sql_str = g_strconcat ("UPDATE ", qb.ent->e_type, " SET ",
00664 inst->param->param_name, " = \"", param_str,
00665 "\" WHERE ", QOF_TYPE_GUID, "='", gstr, "';", NULL);
00666 DEBUG (" sql_str=%s param_Str=%s", qb.sql_str, param_str);
00667 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
00668 NULL, &qb, &qsql_be->err) != SQLITE_OK)
00669 {
00670 qof_error_set_be (be, qsql_be->err_update);
00671 qsql_be->error = TRUE;
00672 PERR (" error on modify:%s", qsql_be->err);
00673 }
00674 else
00675 {
00676 inst->dirty = FALSE;
00677 g_free (qb.sql_str);
00678 g_free (gstr);
00679 qsql_be->error = FALSE;
00680 LEAVE (" ");
00681 return;
00682 }
00683
00684 slots = qof_instance_get_slots (inst);
00685 if (slots)
00686 {
00687
00688
00689 qb.sql_str = g_strconcat ("UPDATE ", QSQL_KVP_TABLE,
00690 " SET (kvp_id \"", gstr, "\", ", NULL);
00691 kvp_frame_for_each_slot (slots, kvpvalue_to_sql, &qb);
00692 qb.sql_str = add_to_sql (qb.sql_str, END_DB_VERSION);
00693 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
00694 NULL, &qb, &qsql_be->err) != SQLITE_OK)
00695 {
00696 qof_error_set_be (be, qsql_be->err_insert);
00697 qsql_be->error = TRUE;
00698 PERR (" error on KVP create_event:%s", qsql_be->err);
00699 }
00700 else
00701 {
00702 ((QofInstance *) qb.ent)->dirty = FALSE;
00703 qsql_be->error = FALSE;
00704 g_free (qb.sql_str);
00705 }
00706 }
00707 g_free (gstr);
00708 LEAVE (" ");
00709 }
00710
00712 static gint
00713 record_foreach (gpointer builder, gint col_num, gchar ** strings,
00714 gchar ** columnNames)
00715 {
00716 QSQLiteBackend *qsql_be;
00717 struct QsqlBuilder *qb;
00718 const QofParam *param;
00719 QofInstance *inst;
00720 QofEntity *ent;
00721 gint i;
00722
00723 g_return_val_if_fail (builder, QSQL_ERROR);
00724 qb = (struct QsqlBuilder *) builder;
00725 qsql_be = qb->qsql_be;
00726 qof_event_suspend ();
00727 inst = (QofInstance *) qof_object_new_instance (qb->e_type, qsql_be->book);
00728 ent = &inst->entity;
00729 for (i = 0; i < col_num; i++)
00730 {
00731
00732 param = qof_class_get_parameter (qb->e_type, columnNames[i]);
00733 if (!param)
00734 continue;
00735
00736 inst->param = param;
00737 if (0 == safe_strcmp (columnNames[i], QOF_TYPE_GUID))
00738 {
00739 GUID *guid;
00740 guid = guid_malloc ();
00741 if (!string_to_guid (strings[i], guid))
00742 {
00743 DEBUG (" set guid failed:%s", strings[i]);
00744 return QSQL_ERROR;
00745 }
00746 qof_entity_set_guid (ent, guid);
00747 }
00748 if (strings[i])
00749 qof_util_param_set_string (ent, param, strings[i]);
00750 }
00751 qof_event_resume ();
00752 return SQLITE_OK;
00753 }
00754
00755
00756 static void
00757 string_param_foreach (QofParam * param, gpointer builder)
00758 {
00759 struct QsqlBuilder *qb;
00760 QSQLiteBackend *qsql_be;
00761 gchar *p_str, *old;
00762
00763 qb = (struct QsqlBuilder *) builder;
00764 qsql_be = qb->qsql_be;
00765 if (0 == safe_strcmp (param->param_type, QOF_TYPE_KVP))
00766 return;
00767 p_str = string_param_to_sql (param);
00768
00769 if (!p_str)
00770 return;
00771 old = g_strconcat (p_str, ",", NULL);
00772 qb->sql_str = add_to_sql (qb->sql_str, old);
00773 g_free (old);
00774 g_free (p_str);
00775 }
00776
00777 static void
00778 update_param_foreach (QofParam * param, gpointer builder)
00779 {
00780 struct QsqlBuilder *qb;
00781 gchar *value, *add;
00782
00783 qb = (struct QsqlBuilder *) builder;
00784 if (param != qb->dirty)
00785 return;
00786
00787 value = qof_util_param_to_string (qb->ent, param);
00788 if (value)
00789 g_strescape (value, NULL);
00790 if (!value)
00791 value = g_strdup ("");
00792 if (g_str_has_suffix (qb->sql_str, " "))
00793 {
00794 add = g_strconcat (param->param_name, "=\"", value, "\"", NULL);
00795 qb->sql_str = add_to_sql (qb->sql_str, add);
00796 g_free (add);
00797 }
00798 else
00799 {
00800 add =
00801 g_strconcat (",", param->param_name, "=\"", value, "\"", NULL);
00802 qb->sql_str = add_to_sql (qb->sql_str, add);
00803 g_free (add);
00804 }
00805 }
00806
00807 static void
00808 update_dirty (gpointer value, gpointer builder)
00809 {
00810 QofInstance *inst;
00811 QofEntity *ent;
00812 struct QsqlBuilder *qb;
00813 QSQLiteBackend *qsql_be;
00814 QofBackend *be;
00815 gchar *gstr, *param_str;
00816
00817 qb = (struct QsqlBuilder *) builder;
00818 qsql_be = qb->qsql_be;
00819 be = (QofBackend *) qsql_be;
00820 ent = (QofEntity *) value;
00821 inst = (QofInstance *) ent;
00822 if (!inst->dirty)
00823 return;
00824 ENTER (" ");
00825 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
00826 guid_to_string_buff (qof_entity_get_guid (ent), gstr);
00827
00828 qb->sql_str = g_strdup_printf ("UPDATE %s SET ", ent->e_type);
00829 qof_class_param_foreach (ent->e_type, update_param_foreach, qb);
00830 param_str = g_strdup_printf ("WHERE %s=\"%s\";", QOF_TYPE_GUID, gstr);
00831 qb->sql_str = add_to_sql (qb->sql_str, param_str);
00832 g_free (param_str);
00833 DEBUG (" update=%s", qb->sql_str);
00834 if (sqlite_exec (qsql_be->sqliteh, qb->sql_str,
00835 NULL, qb, &qsql_be->err) != SQLITE_OK)
00836 {
00837 qof_error_set_be (be, qsql_be->err_update);
00838 qsql_be->error = TRUE;
00839 PERR (" error on update_dirty:%s", qsql_be->err);
00840 }
00841 else
00842 {
00843 qof_error_get_message_be (be);
00844 qsql_be->error = FALSE;
00845 inst->dirty = FALSE;
00846 }
00847 LEAVE (" ");
00848 g_free (gstr);
00849 return;
00850 }
00851
00852 static gint
00853 create_dirty_list (gpointer builder, gint col_num, gchar ** strings,
00854 gchar ** columnNames)
00855 {
00856 struct QsqlBuilder *qb;
00857 QofInstance *inst;
00858 const QofParam *param;
00859 gchar *value, *columnName, *tmp;
00860
00861 param = NULL;
00862 qb = (struct QsqlBuilder *) builder;
00863
00864 inst = (QofInstance *) qb->ent;
00865 qb->exists = TRUE;
00866 if (!inst->dirty)
00867 return SQLITE_OK;
00868 columnName = columnNames[col_num];
00869 tmp = strings[col_num];
00870 param = qof_class_get_parameter (qb->ent->e_type, columnName);
00871 if (!param)
00872 return SQLITE_OK;
00873 value = qof_util_param_to_string (qb->ent, param);
00874 qb->dirty = param;
00875 qb->dirty_list = g_list_prepend (qb->dirty_list, qb->ent);
00876 DEBUG (" dirty_list=%d", g_list_length (qb->dirty_list));
00877 return SQLITE_OK;
00878 }
00879
00880 static gint
00881 mark_entity (gpointer builder, gint col_num, gchar ** strings,
00882 gchar ** columnNames)
00883 {
00884 struct QsqlBuilder *qb;
00885
00886 qb = (struct QsqlBuilder *) builder;
00887 qb->exists = TRUE;
00888 return SQLITE_OK;
00889 }
00890
00891 static void
00892 qsql_create (QofBackend * be, QofInstance * inst)
00893 {
00894 gchar *gstr;
00895 QSQLiteBackend *qsql_be;
00896 struct QsqlBuilder qb;
00897 QofEntity *ent;
00898 KvpFrame *slots;
00899
00900 qsql_be = (QSQLiteBackend *) be;
00901 if (!inst)
00902 return;
00903 if (loading)
00904 return;
00905 ent = (QofEntity *) inst;
00906 qof_event_suspend ();
00907 qb.has_slots = FALSE;
00908 ENTER (" %s", ent->e_type);
00909 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
00910 guid_to_string_buff (qof_entity_get_guid (ent), gstr);
00911 qb.sql_str =
00912 g_strdup_printf ("SELECT * FROM %s where guid = \"%s\";",
00913 ent->e_type, gstr);
00914 PINFO (" check exists: %s", qb.sql_str);
00915 qb.ent = ent;
00916 qb.dirty_list = NULL;
00917 qb.exists = FALSE;
00918 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
00919 mark_entity, &qb, &qsql_be->err) != SQLITE_OK)
00920 {
00921 qof_error_set_be (be, qsql_be->err_update);
00922 qsql_be->error = TRUE;
00923 PERR (" error on select :%s", qsql_be->err);
00924 }
00925 if (!qb.exists)
00926 {
00927 gchar *add;
00928
00929 qb.sql_str =
00930 g_strdup_printf ("INSERT into %s (guid ", ent->e_type);
00931 qof_class_param_foreach (ent->e_type, create_param_list, &qb);
00932 add = g_strconcat (") VALUES (\"", gstr, "\"", NULL);
00933 qb.sql_str = add_to_sql (qb.sql_str, add);
00934 g_free (add);
00935 qof_class_param_foreach (ent->e_type, create_each_param, &qb);
00936 qb.sql_str = add_to_sql (qb.sql_str, ");");
00937 DEBUG (" sql_str= %s", qb.sql_str);
00938 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
00939 NULL, qsql_be, &qsql_be->err) != SQLITE_OK)
00940 {
00941 qof_error_set_be (be, qsql_be->err_insert);
00942 qsql_be->error = TRUE;
00943 PERR (" error creating new entity:%s", qsql_be->err);
00944 }
00945
00946 slots = qof_instance_get_slots ((QofInstance *) ent);
00947 if (slots)
00948 {
00949
00950 qb.sql_str = g_strconcat ("INSERT into ", QSQL_KVP_TABLE,
00951 " (kvp_id, \"", gstr, "\", ", NULL);
00952 kvp_frame_for_each_slot (slots, kvpvalue_to_sql, &qb);
00953 qb.sql_str = add_to_sql (qb.sql_str, ");");
00954 }
00955 if (qb.has_slots)
00956 {
00957 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
00958 NULL, &qb, &qsql_be->err) != SQLITE_OK)
00959 {
00960 qof_error_set_be (be, qsql_be->err_insert);
00961 qsql_be->error = TRUE;
00962 PERR (" error on KVP create_event:%s:%s", qsql_be->err,
00963 qb.sql_str);
00964 }
00965 else
00966 {
00967 ((QofInstance *) ent)->dirty = FALSE;
00968 qsql_be->error = FALSE;
00969 }
00970 }
00971 }
00972 g_free (qb.sql_str);
00973 g_free (gstr);
00974 qof_event_resume ();
00975 LEAVE (" ");
00976 }
00977
00978 static void
00979 check_state (QofEntity * ent, gpointer builder)
00980 {
00981 gchar *gstr;
00982 QSQLiteBackend *qsql_be;
00983 struct QsqlBuilder *qb;
00984 QofBackend *be;
00985 QofInstance *inst;
00986 KvpFrame *slots;
00987
00988 qb = (struct QsqlBuilder *) builder;
00989 qsql_be = qb->qsql_be;
00990 be = (QofBackend *) qsql_be;
00991 inst = (QofInstance *) ent;
00992 if (!inst->dirty)
00993 return;
00994
00995 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
00996 guid_to_string_buff (qof_entity_get_guid (ent), gstr);
00997 qb->sql_str =
00998 g_strdup_printf ("SELECT * FROM %s where guid = \"%s\";",
00999 ent->e_type, gstr);
01000 qb->ent = ent;
01001 qb->dirty_list = NULL;
01002
01003
01004 qb->exists = FALSE;
01005 qb->qsql_be = qsql_be;
01006
01007
01008
01009
01010 if (sqlite_exec (qsql_be->sqliteh, qb->sql_str,
01011 create_dirty_list, qb, &qsql_be->err) != SQLITE_OK)
01012 {
01013 qof_error_set_be (be, qsql_be->err_update);
01014 qsql_be->error = TRUE;
01015 PERR (" error on check_state:%s", qsql_be->err);
01016 }
01017 if (!qb->exists)
01018 {
01019 gchar *add;
01020
01021 qb->sql_str =
01022 g_strdup_printf ("INSERT into %s (guid ", ent->e_type);
01023 qof_class_param_foreach (ent->e_type, create_param_list, &qb);
01024 add = g_strconcat (") VALUES (\"", gstr, "\" ", NULL);
01025 qb->sql_str = add_to_sql (qb->sql_str, add);
01026 g_free (add);
01027 qof_class_param_foreach (ent->e_type, create_each_param, &qb);
01028 qb->sql_str = add_to_sql (qb->sql_str, ");");
01029 DEBUG (" sql_str= %s", qb->sql_str);
01030 if (sqlite_exec (qsql_be->sqliteh, qb->sql_str,
01031 NULL, qb, &qsql_be->err) != SQLITE_OK)
01032 {
01033 qof_error_set_be (be, qsql_be->err_insert);
01034 qsql_be->error = TRUE;
01035 PERR (" error on check_state create_new:%s", qsql_be->err);
01036 }
01037 g_free (qb->sql_str);
01038
01039 slots = qof_instance_get_slots ((QofInstance *) ent);
01040 if (slots)
01041 {
01042
01043 qb->sql_str = g_strconcat ("INSERT into ", QSQL_KVP_TABLE,
01044 " (kvp_id \"", gstr, "\", ", NULL);
01045 kvp_frame_for_each_slot (slots, kvpvalue_to_sql, &qb);
01046 qb->sql_str = add_to_sql (qb->sql_str, END_DB_VERSION);
01047 if (sqlite_exec (qsql_be->sqliteh, qb->sql_str,
01048 NULL, &qb, &qsql_be->err) != SQLITE_OK)
01049 {
01050 qof_error_set_be (be, qsql_be->err_insert);
01051 qsql_be->error = TRUE;
01052 PERR (" error on KVP create_event:%s", qsql_be->err);
01053 }
01054 else
01055 {
01056 ((QofInstance *) ent)->dirty = FALSE;
01057 qsql_be->error = FALSE;
01058 }
01059 }
01060 }
01061
01062 g_list_foreach (qb->dirty_list, update_dirty, &qb);
01063 g_free (qb->sql_str);
01064 g_free (gstr);
01065 }
01066
01075 static gint
01076 build_kvp_table (gpointer builder, gint col_num, gchar ** strings,
01077 gchar ** columnNames)
01078 {
01079 QSQLiteBackend *qsql_be;
01080 struct QsqlBuilder *qb;
01081 KvpFrame *frame;
01082 KvpValueType type;
01083 KvpValue *value;
01084 glong max;
01085 gchar *tail;
01086
01087 g_return_val_if_fail (builder, QSQL_ERROR);
01088 qb = (struct QsqlBuilder *) builder;
01089 max = 0;
01090 qsql_be = qb->qsql_be;
01091 g_return_val_if_fail ((col_num < 4), QSQL_ERROR);
01092 g_return_val_if_fail (strings[2], QSQL_ERROR);
01093 frame = kvp_frame_new ();
01094
01095
01096
01097 type = sql_to_kvp_helper (strings[3]);
01098 if (type == 0)
01099 {
01100 PERR (" invalid type returned from kvp table");
01101 return QSQL_ERROR;
01102 }
01103
01104 value = string_to_kvp_value (strings[4], type);
01105 if (!value)
01106 {
01107 PERR (" invalid KvpValue for type: %d", type);
01108 return QSQL_ERROR;
01109 }
01110
01111 kvp_frame_set_value (frame, strings[2], value);
01112
01113 g_hash_table_insert (qsql_be->kvp_table, strings[1], frame);
01114
01115 g_hash_table_insert (qsql_be->kvp_id, strings[0], strings[1]);
01116 errno = 0;
01117 max = strtol (strings[0], &tail, 0);
01118 if (errno == 0)
01119 {
01120 qsql_be->index = (max > qsql_be->index) ? max : qsql_be->index;
01121 }
01122 return SQLITE_OK;
01123 }
01124
01126 static void
01127 qsql_load_kvp (QSQLiteBackend * qsql_be)
01128 {
01129 struct QsqlBuilder qb;
01130 QofBackend *be;
01131 gint sq_code;
01132
01133 g_return_if_fail (qsql_be);
01134 sq_code = SQLITE_OK;
01135 be = (QofBackend *) qsql_be;
01136 qb.sql_str =
01137 g_strdup_printf ("SELECT kvp_id from %s;", QSQL_KVP_TABLE);
01138 sq_code = sqlite_exec (qsql_be->sqliteh, qb.sql_str, build_kvp_table,
01139 &qb, &qsql_be->err);
01140
01141 if (sq_code == SQLITE_ERROR)
01142 {
01143 g_free (qb.sql_str);
01144 qb.sql_str =
01145 g_strdup_printf ("CREATE TABLE %s (%s, %s, %s, %s, %s, %s",
01146 QSQL_KVP_TABLE, "kvp_id int primary key not null",
01147 "guid char(32)", "path mediumtext", "type mediumtext",
01148 "value text", END_DB_VERSION);
01149 PINFO (" creating kvp table. sql=%s", qb.sql_str);
01150 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
01151 record_foreach, &qb, &qsql_be->err) != SQLITE_OK)
01152 {
01153 qsql_be->error = TRUE;
01154 PERR (" unable to create kvp table:%s", qsql_be->err);
01155 }
01156 }
01157 else if (sq_code != SQLITE_OK)
01158 {
01159 qof_error_set_be (be, qsql_be->err_create);
01160 qsql_be->error = TRUE;
01161 PERR (" error on KVP select:%s:%s:%d", qb.sql_str, qsql_be->err, sq_code);
01162 }
01163 g_free (qb.sql_str);
01164 }
01165
01167 static void
01168 qsql_class_foreach (QofObject * obj, gpointer data)
01169 {
01170 struct QsqlBuilder qb;
01171 QSQLiteBackend *qsql_be;
01172 QofBackend *be;
01173
01174 qsql_be = (QSQLiteBackend *) data;
01175 be = (QofBackend *) qsql_be;
01176 qb.qsql_be = qsql_be;
01177 qb.e_type = obj->e_type;
01178 ENTER (" obj_type=%s", qb.e_type);
01179 switch (qsql_be->stm_type)
01180 {
01181 case SQL_NONE:
01182 case SQL_INSERT:
01183 case SQL_DELETE:
01184 case SQL_UPDATE:
01185 {
01186 break;
01187 }
01188 case SQL_CREATE:
01189 {
01190
01191 qb.sql_str =
01192 g_strdup_printf ("CREATE TABLE %s (", obj->e_type);
01193 qof_class_param_foreach (obj->e_type, string_param_foreach,
01194 &qb);
01195 qb.sql_str = add_to_sql (qb.sql_str, END_DB_VERSION);
01196 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
01197 NULL, NULL, &qsql_be->err) != SQLITE_OK)
01198 {
01199 qof_error_set_be (be, qsql_be->err_create);
01200 qsql_be->error = TRUE;
01201 PERR (" error on SQL_CREATE:%s", qsql_be->err);
01202 }
01203 g_free (qb.sql_str);
01204 break;
01205 }
01206 case SQL_LOAD:
01207 {
01208 qb.sql_str =
01209 g_strdup_printf ("SELECT * FROM %s;", obj->e_type);
01210 PINFO (" sql=%s", qb.sql_str);
01211 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
01212 record_foreach, &qb, &qsql_be->err) != SQLITE_OK)
01213 {
01214 qsql_be->error = TRUE;
01215 PERR (" error on SQL_LOAD:%s", qsql_be->err);
01216 }
01217 break;
01218 }
01219 case SQL_WRITE:
01220 {
01221 if (!qof_book_not_saved (qsql_be->book))
01222 break;
01223 qof_object_foreach (obj->e_type, qsql_be->book, check_state,
01224 &qb);
01225 break;
01226 }
01227 }
01228 LEAVE (" ");
01229 }
01230
01231 static void
01232 qsql_backend_createdb (QofBackend * be, QofSession * session)
01233 {
01234 FILE *f;
01235 QSQLiteBackend *qsql_be;
01236 struct QsqlBuilder qb;
01237
01238 g_return_if_fail (be || session);
01239 ENTER (" ");
01240 qsql_be = (QSQLiteBackend *) be;
01241 qsql_be->stm_type = SQL_CREATE;
01242 qb.qsql_be = qsql_be;
01243 qsql_be->book = qof_session_get_book (session);
01244 DEBUG (" create_file %s", qsql_be->fullpath);
01245 f = fopen (qsql_be->fullpath, "a+");
01246 if (f)
01247 fclose (f);
01248 else
01249 {
01250 qof_error_set (session, qof_error_register
01251 (_("Unable to open the output file '%s' - do you have "
01252 "permission to create this file?"), TRUE));
01253 qsql_be->error = TRUE;
01254 LEAVE (" unable to create new file '%s'", qsql_be->fullpath);
01255 return;
01256 }
01257 qsql_be->sqliteh =
01258 sqlite_open (qsql_be->fullpath, 0644, &qsql_be->err);
01259 if (!qsql_be->sqliteh)
01260 {
01261 qof_error_set_be (be, qsql_be->err_create);
01262 qsql_be->error = TRUE;
01263 LEAVE (" unable to open sqlite:%s", qsql_be->err);
01264 return;
01265 }
01266 qof_object_foreach_type (qsql_class_foreach, qsql_be);
01267
01268
01269
01270 qb.sql_str =
01271 g_strdup_printf ("CREATE TABLE %s (%s, %s, %s, %s, %s, %s",
01272 QSQL_KVP_TABLE, "kvp_id int primary key not null",
01273 "guid char(32)", "path mediumtext", "type mediumtext",
01274 "value text", END_DB_VERSION);
01275 PINFO (" sql=%s", qb.sql_str);
01276 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
01277 record_foreach, &qb, &qsql_be->err) != SQLITE_OK)
01278 {
01279 qsql_be->error = TRUE;
01280 PERR (" unable to create kvp table:%s", qsql_be->err);
01281 }
01282 g_free (qb.sql_str);
01283 LEAVE (" ");
01284 }
01285
01286 static void
01287 qsql_backend_opendb (QofBackend * be, QofSession * session)
01288 {
01289 QSQLiteBackend *qsql_be;
01290
01291 g_return_if_fail (be || session);
01292 ENTER (" ");
01293 qsql_be = (QSQLiteBackend *) be;
01294 qsql_be->sqliteh =
01295 sqlite_open (qsql_be->fullpath, 0666, &qsql_be->err);
01296 if (!qsql_be->sqliteh)
01297 {
01298 qof_error_set_be (be, qof_error_register
01299 (_("Unable to open the sqlite database '%s'."), TRUE));
01300 qsql_be->error = TRUE;
01301 PERR (" %s", qsql_be->err);
01302 }
01303 LEAVE (" %s", qsql_be->fullpath);
01304 }
01305
01306 static void
01307 qsqlite_session_begin (QofBackend * be, QofSession * session,
01308 const gchar * book_path, gboolean ignore_lock,
01309 gboolean create_if_nonexistent)
01310 {
01311 QSQLiteBackend *qsql_be;
01312 gchar **pp;
01313 struct stat statinfo;
01314 gint stat_val;
01315
01316 g_return_if_fail (be);
01317 ENTER (" book_path=%s", book_path);
01318 qsql_be = (QSQLiteBackend *) be;
01319 qsql_be->fullpath = NULL;
01320 if (book_path == NULL)
01321 {
01322 qof_error_set_be (be, qof_error_register
01323 (_("Please provide a filename for sqlite."), FALSE));
01324 qsql_be->error = TRUE;
01325 LEAVE (" bad URL");
01326 return;
01327 }
01328
01329 pp = g_strsplit (book_path, ":", 2);
01330 if (0 == safe_strcmp (pp[0], ACCESS_METHOD))
01331 {
01332 qsql_be->fullpath = g_strdup (pp[1]);
01333 g_strfreev (pp);
01334 }
01335 else
01336 qsql_be->fullpath = g_strdup (book_path);
01337 be->fullpath = g_strdup (qsql_be->fullpath);
01338 PINFO (" final path = %s", qsql_be->fullpath);
01339 stat_val = g_stat (qsql_be->fullpath, &statinfo);
01340 if (!S_ISREG (statinfo.st_mode) || statinfo.st_size == 0)
01341 qsql_backend_createdb (be, session);
01342 if (!qsql_be->error)
01343 qsql_backend_opendb (be, session);
01344 if (qof_error_check_be (be) || qsql_be->error)
01345 {
01346 LEAVE (" open failed");
01347 return;
01348 }
01349 qsql_be->create_handler =
01350 qof_event_register_handler (create_event, qsql_be);
01351 qsql_be->delete_handler =
01352 qof_event_register_handler (delete_event, qsql_be);
01353 LEAVE (" db=%s", qsql_be->fullpath);
01354 }
01355
01356 static void
01357 qsqlite_db_load (QofBackend * be, QofBook * book)
01358 {
01359 QSQLiteBackend *qsql_be;
01360
01361 g_return_if_fail (be);
01362 ENTER (" ");
01363 loading = TRUE;
01364 qsql_be = (QSQLiteBackend *) be;
01365 qsql_be->stm_type = SQL_LOAD;
01366 qsql_be->book = book;
01367
01368 qof_object_foreach_type (qsql_class_foreach, qsql_be);
01369 qsql_load_kvp (qsql_be);
01370 loading = FALSE;
01371 LEAVE (" ");
01372 }
01373
01374 static void
01375 qsqlite_write_db (QofBackend * be, QofBook * book)
01376 {
01377 QSQLiteBackend *qsql_be;
01378
01379 g_return_if_fail (be);
01380 qsql_be = (QSQLiteBackend *) be;
01381 qsql_be->stm_type = SQL_WRITE;
01382 qsql_be->book = book;
01383
01384 qof_object_foreach_type (qsql_class_foreach, qsql_be);
01385
01386 }
01387
01388 static gboolean
01389 qsql_determine_file_type (const gchar * path)
01390 {
01391 if (!path)
01392 return FALSE;
01393 return TRUE;
01394 }
01395
01396 static void
01397 qsqlite_session_end (QofBackend * be)
01398 {
01399 QSQLiteBackend *qsql_be;
01400
01401 g_return_if_fail (be);
01402 qsql_be = (QSQLiteBackend *) be;
01403 if (qsql_be->sqliteh)
01404 sqlite_close (qsql_be->sqliteh);
01405 }
01406
01407 static void
01408 qsqlite_destroy_backend (QofBackend * be)
01409 {
01410 QSQLiteBackend *qsql_be;
01411
01412 g_return_if_fail (be);
01413 qsql_be = (QSQLiteBackend *) be;
01414 g_hash_table_destroy (qsql_be->kvp_table);
01415 g_hash_table_destroy (qsql_be->kvp_id);
01416 qof_event_unregister_handler (qsql_be->create_handler);
01417 qof_event_unregister_handler (qsql_be->delete_handler);
01418 g_free (be);
01419 g_free (qsql_be);
01420 }
01421
01422 static void
01423 qsql_provider_free (QofBackendProvider * prov)
01424 {
01425 prov->provider_name = NULL;
01426 prov->access_method = NULL;
01427 g_free (prov);
01428 }
01429
01445 static QofBackend *
01446 qsql_backend_new (void)
01447 {
01448 QSQLiteBackend *qsql_be;
01449 QofBackend *be;
01450
01451 ENTER (" ");
01452 qsql_be = g_new0 (QSQLiteBackend, 1);
01453 be = (QofBackend *) qsql_be;
01454 qof_backend_init (be);
01455 qsql_be->kvp_table = g_hash_table_new (g_str_hash, g_str_equal);
01456 qsql_be->kvp_id = g_hash_table_new (g_str_hash, g_str_equal);
01457 qsql_be->dbversion = QOF_OBJECT_VERSION;
01458 qsql_be->stm_type = SQL_NONE;
01459 qsql_be->err_delete =
01460 qof_error_register (_("Unable to delete record."), FALSE);
01461 qsql_be->err_create =
01462 qof_error_register (_("Unable to create record."), FALSE);
01463 qsql_be->err_insert =
01464 qof_error_register (_("Unable to insert a new record."), FALSE);
01465 qsql_be->err_update =
01466 qof_error_register (_("Unable to update existing record."), FALSE);
01467 be->session_begin = qsqlite_session_begin;
01468
01469 be->session_end = qsqlite_session_end;
01470 be->destroy_backend = qsqlite_destroy_backend;
01471 be->load = qsqlite_db_load;
01472 be->save_may_clobber_data = NULL;
01473
01474
01475 be->begin = qsql_create;
01476
01477 be->commit = qsql_modify;
01478 be->rollback = NULL;
01479
01480 be->compile_query = NULL;
01481
01482 be->free_query = NULL;
01483 be->run_query = NULL;
01484 be->counter = NULL;
01485
01486 be->events_pending = NULL;
01487 be->process_events = NULL;
01488
01489 be->sync = qsqlite_write_db;
01490 be->load_config = NULL;
01491 be->get_config = NULL;
01492 LEAVE (" ");
01493 return be;
01494 }
01495
01496 void
01497 qof_sqlite_provider_init (void)
01498 {
01499 QofBackendProvider *prov;
01500
01501 ENTER (" ");
01502 bindtextdomain (PACKAGE, LOCALE_DIR);
01503 prov = g_new0 (QofBackendProvider, 1);
01504 prov->provider_name = "QOF SQLite Backend Version 0.3";
01505 prov->access_method = ACCESS_METHOD;
01506 prov->partial_book_supported = TRUE;
01507 prov->backend_new = qsql_backend_new;
01508 prov->check_data_type = qsql_determine_file_type;
01509 prov->provider_free = qsql_provider_free;
01510 qof_backend_register_provider (prov);
01511 LEAVE (" ");
01512 }
01513
01514