QOF  0.8.7
qof-sqlite.c
Go to the documentation of this file.
1 /****************************************************************
2  * qof-sqlite.c
3  *
4  * Sun Jan 15 12:52:46 2006
5  * Copyright 2006-2008 Neil Williams
6  * linux@codehelp.co.uk
7  ****************************************************************/
8 /*
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22  */
23 
24 #include "config.h"
25 #include <errno.h>
26 #include <stdlib.h>
27 #include <time.h>
28 #include <glib/gstdio.h>
29 #include <sqlite.h>
30 #include <glib.h>
31 #include <libintl.h>
32 #include "qof.h"
33 #include "qofsql-p.h"
34 #include "qof-sqlite.h"
35 #include "kvputil-p.h"
36 
37 #define _(String) dgettext (GETTEXT_PACKAGE, String)
38 #define ACCESS_METHOD "sqlite"
39 
46 #define PRIORITY_HIGH 9
47 
48 #define PRIORITY_STANDARD 5
49 
50 #define PRIORITY_LOW 0
51 
52 #define QSQL_ERROR -1
53 
54 #undef QSQL_KVP_TABLE
55 #define QSQL_KVP_TABLE "sqlite_kvp"
56 
57 #define END_DB_VERSION " dbversion int );"
58 
59 static QofLogModule log_module = QOF_MOD_SQLITE;
60 static gboolean loading = FALSE;
61 
68 typedef struct
69 {
70  QofBackend be;
71  sqlite *sqliteh;
72  QsqlStatementType stm_type;
73  gint dbversion;
74  gint create_handler;
75  gint delete_handler;
76  const gchar *fullpath;
77  gchar *err;
78  gboolean error;
79  /* full hashtable of kvp records */
80  GHashTable *kvp_table;
81  /* hashtable relating the GUID to the kvp_id */
82  GHashTable *kvp_id;
83  /* highest kvp_id in the table */
84  gulong index;
85  QofBook *book;
86  QofErrorId err_delete, err_insert, err_update, err_create;
87 } QSQLiteBackend;
88 
95 struct QsqlBuilder
96 {
98  QSQLiteBackend *qsql_be;
100  QofEntity *ent;
102  QofIdType e_type;
104  gchar *sql_str;
106  GList *dirty_list;
108  gboolean exists;
110  gboolean has_slots;
112  const QofParam *dirty;
113 };
114 
116 static KvpValue *
117 string_to_kvp_value (const gchar * content, KvpValueType type)
118 {
119  gchar *tail;
120  gint64 cm_i64;
121  gdouble cm_double;
122  QofNumeric cm_numeric;
123  GUID *cm_guid;
124 
125  switch (type)
126  {
127  case KVP_TYPE_GINT64:
128  {
129  errno = 0;
130  cm_i64 = strtoll (content, &tail, 0);
131  if (errno == 0)
132  {
133  return kvp_value_new_gint64 (cm_i64);
134  }
135  break;
136  }
137  case KVP_TYPE_DOUBLE:
138  {
139  errno = 0;
140  cm_double = strtod (content, &tail);
141  if (errno == 0)
142  return kvp_value_new_double (cm_double);
143  break;
144  }
145  case KVP_TYPE_NUMERIC:
146  {
147  qof_numeric_from_string (content, &cm_numeric);
148  return kvp_value_new_numeric (cm_numeric);
149  break;
150  }
151  case KVP_TYPE_STRING:
152  {
153  return kvp_value_new_string (content);
154  break;
155  }
156  case KVP_TYPE_GUID:
157  {
158  cm_guid = g_new0 (GUID, 1);
159  if (TRUE == string_to_guid (content, cm_guid))
160  return kvp_value_new_guid (cm_guid);
161  break;
162  }
163  case KVP_TYPE_TIME:
164  {
165  QofDate *qd;
166  QofTime *qt;
167  KvpValue *retval;
168 
169  qd = qof_date_parse (content, QOF_DATE_FORMAT_UTC);
170  if (qd)
171  {
172  qt = qof_date_to_qtime (qd);
173  retval = kvp_value_new_time (qt);
174  qof_date_free (qd);
175  qof_time_free (qt);
176  return retval;
177  }
178  else
179  PERR (" failed to parse date");
180  }
181  case KVP_TYPE_BOOLEAN:
182  {
183  gboolean val;
184  val = qof_util_bool_to_int (content);
185  return kvp_value_new_boolean (val);
186  }
187  default:
188  break;
189  }
190  return NULL;
191 }
192 
194 static G_GNUC_UNUSED void
195 kvpvalue_to_sql (const gchar * key, KvpValue * val, gpointer builder)
196 {
197  QSQLiteBackend *qsql_be;
198  struct QsqlBuilder *qb;
199  KvpValueType n;
200 
201  ENTER (" ");
202  qb = (struct QsqlBuilder *) builder;
203  qsql_be = qb->qsql_be;
204  g_return_if_fail (key && val && qsql_be);
205  n = kvp_value_get_type (val);
206  switch (n)
207  {
208  case KVP_TYPE_GINT64:
209  case KVP_TYPE_DOUBLE:
210  case KVP_TYPE_NUMERIC:
211  case KVP_TYPE_STRING:
212  case KVP_TYPE_GUID:
213  case KVP_TYPE_TIME:
214  case KVP_TYPE_BOOLEAN:
215  {
216  /* ("kvp_id int primary key not null", "guid char(32)", "path mediumtext",
217  "type mediumtext", "value text", */
218 
219  qb->sql_str =
220  g_strdup_printf (" kvp key=%s val=%s type=%s", key,
223  DEBUG (" %s", qb->sql_str);
224  qb->has_slots = TRUE;
225  break;
226  }
227  case KVP_TYPE_FRAME:
228  {
230  kvpvalue_to_sql, qb);
231  break;
232  }
233  default:
234  {
235  PERR (" unsupported value = %d", kvp_value_get_type (val));
236  break;
237  }
238  }
239  LEAVE (" %s", qb->sql_str);
240 }
241 
246 static void
247 delete_event (QofEntity * ent, QofEventId event_type,
248  gpointer handler_data, gpointer event_data)
249 {
250  QofBackend *be;
251  QSQLiteBackend *qsql_be;
252  gchar *gstr, *sql_str;
253 
254  qsql_be = (QSQLiteBackend *) handler_data;
255  be = (QofBackend *) qsql_be;
256  if (!ent)
257  return;
258  if (0 == safe_strcmp (ent->e_type, QOF_ID_BOOK))
259  return;
260  /* do not try to delete if only a QofObject has been loaded. */
261  if (!qof_class_is_registered (ent->e_type))
262  return;
263  switch (event_type)
264  {
265  case QOF_EVENT_DESTROY:
266  {
267  ENTER (" %s do_free=%d", ent->e_type,
268  ((QofInstance *) ent)->do_free);
269  gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
271  sql_str = qof_sql_entity_delete (ent);
272  DEBUG (" sql_str=%s", sql_str);
273  if (sqlite_exec (qsql_be->sqliteh, sql_str,
274  NULL, qsql_be, &qsql_be->err) != SQLITE_OK)
275  {
276  qof_error_set_be (be, qsql_be->err_delete);
277  qsql_be->error = TRUE;
278  LEAVE (" error on delete:%s", qsql_be->err);
279  break;
280  }
281  LEAVE (" %d", event_type);
282  qsql_be->error = FALSE;
283  g_free (gstr);
284  break;
285  }
286  default:
287  break;
288  }
289 }
290 
292 static void
293 create_event (QofEntity * ent, QofEventId event_type,
294  gpointer handler_data, gpointer event_data)
295 {
296  QofBackend *be;
297  struct QsqlBuilder qb;
298  QSQLiteBackend *qsql_be;
299  gchar *gstr;
300  KvpFrame *slots;
301 
302  qsql_be = (QSQLiteBackend *) handler_data;
303  be = (QofBackend *) qsql_be;
304  if (!ent)
305  return;
306  if (0 == safe_strcmp (ent->e_type, QOF_ID_BOOK))
307  return;
308  if (!qof_class_is_registered (ent->e_type))
309  return;
310  switch (event_type)
311  {
312  case QOF_EVENT_CREATE:
313  {
314  ENTER (" insert:%s", ent->e_type);
315  gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
317  ent), gstr);
318  DEBUG (" guid=%s", gstr);
319  qb.ent = ent;
320  qb.sql_str = qof_sql_entity_insert (ent);
322  DEBUG (" sql_str=%s", qb.sql_str);
323  if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
324  NULL, &qb, &qsql_be->err) != SQLITE_OK)
325  {
326  qof_error_set_be (be, qsql_be->err_insert);
327  qsql_be->error = TRUE;
328  PERR (" error on create_event:%s", qsql_be->err);
329  }
330  else
331  {
332  ((QofInstance *) ent)->dirty = FALSE;
333  qsql_be->error = FALSE;
334  g_free (qb.sql_str);
335  g_free (gstr);
336  LEAVE (" ");
337  break;
338  }
339  /* insert sqlite_kvp data */
340  slots = qof_instance_get_slots ((QofInstance *) ent);
341  if (slots)
342  {
343  /* id, guid, path, type, value */
344  qb.sql_str = qof_sql_entity_insert (ent);
345  if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
346  NULL, &qb, &qsql_be->err) != SQLITE_OK)
347  {
348  qof_error_set_be (be, qsql_be->err_insert);
349  qsql_be->error = TRUE;
350  PERR (" error on KVP create_event:%s", qsql_be->err);
351  }
352  else
353  {
354  ((QofInstance *) ent)->dirty = FALSE;
355  qsql_be->error = FALSE;
356  g_free (qb.sql_str);
357  g_free (gstr);
358  LEAVE (" ");
359  break;
360  }
361  }
362  g_free (qb.sql_str);
363  g_free (gstr);
364  LEAVE (" ");
365  break;
366  }
367  default:
368  break;
369  }
370 }
371 
372 static void
373 qsql_modify (QofBackend * be, QofInstance * inst)
374 {
375  struct QsqlBuilder qb;
376  QSQLiteBackend *qsql_be;
377 
378  qsql_be = (QSQLiteBackend *) be;
379  qb.qsql_be = qsql_be;
380  if (!inst)
381  return;
382  if (!inst->param)
383  return;
384  if (loading)
385  return;
386  if (!inst->param->param_setfcn)
387  return;
388  ENTER (" modified %s param:%s", ((QofEntity *) inst)->e_type,
389  inst->param->param_name);
390  qb.sql_str = qof_sql_entity_update ((QofEntity*)inst);
391  if (!qb.sql_str)
392  {
393  LEAVE (" null string");
394  return;
395  }
396  DEBUG (" sql_str=%s", qb.sql_str);
397  if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
398  NULL, &qb, &qsql_be->err) != SQLITE_OK)
399  {
400  qof_error_set_be (be, qsql_be->err_update);
401  qsql_be->error = TRUE;
402  PERR (" error on modify:%s", qsql_be->err);
403  }
404  else
405  {
406  inst->dirty = FALSE;
407  g_free (qb.sql_str);
408  qsql_be->error = FALSE;
409  LEAVE (" ");
410  return;
411  }
412  LEAVE (" ");
413 }
414 
416 static gint
417 record_foreach (gpointer builder, gint col_num, gchar ** strings,
418  gchar ** columnNames)
419 {
420  QSQLiteBackend *qsql_be;
421  struct QsqlBuilder *qb;
422  const QofParam *param;
423  QofInstance *inst;
424  QofEntity *ent;
425  gint i;
426 
427  g_return_val_if_fail (builder, QSQL_ERROR);
428  qb = (struct QsqlBuilder *) builder;
429  qsql_be = qb->qsql_be;
431  inst = (QofInstance *) qof_object_new_instance (qb->e_type, qsql_be->book);
432  ent = &inst->entity;
433  for (i = 0; i < col_num; i++)
434  {
435  /* get param and set as string */
436  param = qof_class_get_parameter (qb->e_type, columnNames[i]);
437  if (!param)
438  continue;
439  /* set the inst->param entry */
440  inst->param = param;
441  if (0 == safe_strcmp (columnNames[i], QOF_TYPE_GUID))
442  {
443  GUID *guid;
444  guid = guid_malloc ();
445  if (!string_to_guid (strings[i], guid))
446  {
447  DEBUG (" set guid failed:%s", strings[i]);
448  return QSQL_ERROR;
449  }
450  qof_entity_set_guid (ent, guid);
451  }
452  if (strings[i])
453  qof_util_param_set_string (ent, param, strings[i]);
454  }
455  qof_event_resume ();
456  return SQLITE_OK;
457 }
458 
459 static void
460 update_dirty (gpointer value, gpointer builder)
461 {
462  QofInstance *inst;
463  QofEntity *ent;
464  struct QsqlBuilder *qb;
465  QSQLiteBackend *qsql_be;
466  QofBackend *be;
467  gchar *gstr;
468 
469  qb = (struct QsqlBuilder *) builder;
470  qsql_be = qb->qsql_be;
471  be = (QofBackend *) qsql_be;
472  ent = (QofEntity *) value;
473  inst = (QofInstance *) ent;
474  if (!inst->dirty)
475  return;
476  ENTER (" ");
477  gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
479  /* qof_class_param_foreach */
480  qb->sql_str = qof_sql_entity_update (ent);
481  if (!qb->sql_str)
482  {
483  LEAVE (" null string");
484  return;
485  }
486  DEBUG (" update=%s", qb->sql_str);
487  if (sqlite_exec (qsql_be->sqliteh, qb->sql_str,
488  NULL, qb, &qsql_be->err) != SQLITE_OK)
489  {
490  qof_error_set_be (be, qsql_be->err_update);
491  qsql_be->error = TRUE;
492  PERR (" error on update_dirty:%s", qsql_be->err);
493  }
494  else
495  {
497  qsql_be->error = FALSE;
498  inst->dirty = FALSE;
499  }
500  LEAVE (" ");
501  g_free (gstr);
502  return;
503 }
504 
505 static gint
506 create_dirty_list (gpointer builder, gint col_num, gchar ** strings,
507  gchar ** columnNames)
508 {
509  struct QsqlBuilder *qb;
510  QofInstance *inst;
511  const QofParam *param;
512  gchar * G_GNUC_UNUSED value, *columnName, * G_GNUC_UNUSED tmp;
513 
514  param = NULL;
515  qb = (struct QsqlBuilder *) builder;
516  /* qb->ent is the live data, strings is the sqlite data */
517  inst = (QofInstance *) qb->ent;
518  qb->exists = TRUE;
519  if (!inst->dirty)
520  return SQLITE_OK;
521  columnName = columnNames[col_num];
522  tmp = strings[col_num];
523  param = qof_class_get_parameter (qb->ent->e_type, columnName);
524  if (!param)
525  return SQLITE_OK;
526  value = qof_util_param_to_string (qb->ent, param);
527  qb->dirty = param;
528  qb->dirty_list = g_list_prepend (qb->dirty_list, qb->ent);
529  DEBUG (" dirty_list=%d", g_list_length (qb->dirty_list));
530  return SQLITE_OK;
531 }
532 
533 static gint
534 mark_entity (gpointer builder, gint col_num, gchar ** strings,
535  gchar ** columnNames)
536 {
537  struct QsqlBuilder *qb;
538 
539  qb = (struct QsqlBuilder *) builder;
540  qb->exists = TRUE;
541  return SQLITE_OK;
542 }
543 
544 static void
545 qsql_create (QofBackend * be, QofInstance * inst)
546 {
547  gchar *gstr;
548  QSQLiteBackend *qsql_be;
549  struct QsqlBuilder qb;
550  QofEntity *ent;
551 
552  qsql_be = (QSQLiteBackend *) be;
553  if (!inst)
554  return;
555  if (loading)
556  return;
557  ent = (QofEntity *) inst;
559  qb.has_slots = FALSE;
560  ENTER (" %s", ent->e_type);
561  gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
563  qb.sql_str =
564  g_strdup_printf ("SELECT * FROM %s where guid = \"%s\";",
565  ent->e_type, gstr);
566  PINFO (" check exists: %s", qb.sql_str);
567  qb.ent = ent;
568  qb.dirty_list = NULL;
569  qb.exists = FALSE;
570  if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
571  mark_entity, &qb, &qsql_be->err) != SQLITE_OK)
572  {
573  qof_error_set_be (be, qsql_be->err_update);
574  qsql_be->error = TRUE;
575  PERR (" error on select :%s", qsql_be->err);
576  }
577  if (!qb.exists)
578  {
579  /* create new entity */
580  qb.sql_str = qof_sql_entity_insert (ent);
581  DEBUG (" sql_str= %s", qb.sql_str);
582  if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
583  NULL, qsql_be, &qsql_be->err) != SQLITE_OK)
584  {
585  qof_error_set_be (be, qsql_be->err_insert);
586  qsql_be->error = TRUE;
587  PERR (" error creating new entity:%s", qsql_be->err);
588  }
589  }
590  g_free (qb.sql_str);
591  g_free (gstr);
592  qof_event_resume ();
593  LEAVE (" ");
594 }
595 
596 static void
597 check_state (QofEntity * ent, gpointer builder)
598 {
599  gchar *gstr;
600  QSQLiteBackend *qsql_be;
601  struct QsqlBuilder *qb;
602  QofBackend *be;
603  QofInstance *inst;
604 
605  qb = (struct QsqlBuilder *) builder;
606  qsql_be = qb->qsql_be;
607  be = (QofBackend *) qsql_be;
608  inst = (QofInstance *) ent;
609  if (!inst->dirty)
610  return;
611  /* check if this entity already exists */
612  gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
614  qb->sql_str =
615  g_strdup_printf ("SELECT * FROM %s where guid = \"%s\";",
616  ent->e_type, gstr);
617  qb->ent = ent;
618  qb->dirty_list = NULL;
619  /* assume entity does not yet exist in backend,
620  e.g. being copied from another session. */
621  qb->exists = FALSE;
622  qb->qsql_be = qsql_be;
623  /* update each dirty instance */
624  /* Make a GList of dirty instances
625  Don't update during a SELECT,
626  UPDATE will fail with DB_LOCKED */
627  if (sqlite_exec (qsql_be->sqliteh, qb->sql_str,
628  create_dirty_list, qb, &qsql_be->err) != SQLITE_OK)
629  {
630  qof_error_set_be (be, qsql_be->err_update);
631  qsql_be->error = TRUE;
632  PERR (" error on check_state:%s", qsql_be->err);
633  }
634  if (!qb->exists)
635  {
636  /* create new entity */
637  qb->sql_str = qof_sql_entity_insert (ent);
638  DEBUG (" sql_str= %s", qb->sql_str);
639  if (sqlite_exec (qsql_be->sqliteh, qb->sql_str,
640  NULL, qb, &qsql_be->err) != SQLITE_OK)
641  {
642  qof_error_set_be (be, qsql_be->err_insert);
643  qsql_be->error = TRUE;
644  PERR (" error on check_state create_new:%s", qsql_be->err);
645  }
646  g_free (qb->sql_str);
647  }
648  /* update instead */
649  g_list_foreach (qb->dirty_list, update_dirty, &qb);
650  g_free (qb->sql_str);
651  g_free (gstr);
652 }
653 
662 static gint
663 build_kvp_table (gpointer builder, gint col_num, gchar ** strings,
664  gchar ** columnNames)
665 {
666  QSQLiteBackend *qsql_be;
667  struct QsqlBuilder *qb;
668  KvpFrame *frame;
669  KvpValueType type;
670  KvpValue *value;
671  gulong max;
672  gchar *tail;
673 
674  g_return_val_if_fail (builder, QSQL_ERROR);
675  qb = (struct QsqlBuilder *) builder;
676  max = 0;
677  qsql_be = qb->qsql_be;
678  g_return_val_if_fail ((col_num < 4), QSQL_ERROR);
679  g_return_val_if_fail (strings[2], QSQL_ERROR);
680  frame = kvp_frame_new ();
681  /* columnNames = fields strings = values
682  [0]=kvp_id, [1]=guid, [2]=path, [3]=type, [4]=value
683  get type from type_string */
684  type = qof_id_to_kvp_value_type (strings[3]);
685  if (type == 0)
686  {
687  PERR (" invalid type returned from kvp table");
688  return QSQL_ERROR;
689  }
690  /* use the type to make a KvpValue from value */
691  value = string_to_kvp_value (strings[4], type);
692  if (!value)
693  {
694  PERR (" invalid KvpValue for type: %d", type);
695  return QSQL_ERROR;
696  }
697  /* add the KvpValue to the frame at path */
698  kvp_frame_set_value (frame, strings[2], value);
699  /* index the frame under the entity GUID */
700  g_hash_table_insert (qsql_be->kvp_table, strings[1], frame);
701  /* index the guid under the kvp_id */
702  g_hash_table_insert (qsql_be->kvp_id, strings[0], strings[1]);
703  errno = 0;
704  max = strtol (strings[0], &tail, 0);
705  if (errno == 0)
706  {
707  qsql_be->index = (max > qsql_be->index) ? max : qsql_be->index;
708  }
709  return SQLITE_OK;
710 }
711 
713 static void
714 qsql_load_kvp (QSQLiteBackend * qsql_be)
715 {
716  struct QsqlBuilder qb;
717  QofBackend *be;
718  gint sq_code;
719 
720  g_return_if_fail (qsql_be);
721  sq_code = SQLITE_OK;
722  be = (QofBackend *) qsql_be;
723  qb.sql_str =
724  g_strdup_printf ("SELECT kvp_id from %s;", QSQL_KVP_TABLE);
725  sq_code = sqlite_exec (qsql_be->sqliteh, qb.sql_str, build_kvp_table,
726  &qb, &qsql_be->err);
727  /* catch older files without a sqlite_kvp table */
728  if (sq_code == SQLITE_ERROR)
729  {
730  g_free (qb.sql_str);
731  qb.sql_str =
732  g_strdup_printf ("CREATE TABLE %s (%s, %s, %s, %s, %s, %s",
733  QSQL_KVP_TABLE, "kvp_id int primary key not null",
734  "guid char(32)", "path mediumtext", "type mediumtext",
735  "value text", END_DB_VERSION);
736  PINFO (" creating kvp table. sql=%s", qb.sql_str);
737  if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
738  record_foreach, &qb, &qsql_be->err) != SQLITE_OK)
739  {
740  qsql_be->error = TRUE;
741  PERR (" unable to create kvp table:%s", qsql_be->err);
742  }
743  }
744  else if (sq_code != SQLITE_OK)
745  {
746  qof_error_set_be (be, qsql_be->err_create);
747  qsql_be->error = TRUE;
748  PERR (" error on KVP select:%s:%s:%d", qb.sql_str, qsql_be->err, sq_code);
749  }
750  g_free (qb.sql_str);
751 }
752 
754 static void
755 qsql_class_foreach (QofObject * obj, gpointer data)
756 {
757  struct QsqlBuilder qb;
758  QSQLiteBackend *qsql_be;
759  QofBackend *be;
760 
761  qsql_be = (QSQLiteBackend *) data;
762  be = (QofBackend *) qsql_be;
763  qb.qsql_be = qsql_be;
764  qb.e_type = obj->e_type;
765  ENTER (" obj_type=%s", qb.e_type);
766  switch (qsql_be->stm_type)
767  {
768  case SQL_NONE:
769  case SQL_INSERT:
770  case SQL_DELETE:
771  case SQL_UPDATE:
772  {
773  break;
774  }
775  case SQL_CREATE:
776  {
777  /* KVP is handled separately */
778  qb.sql_str = qof_sql_object_create_table (obj);
779  if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
780  NULL, NULL, &qsql_be->err) != SQLITE_OK)
781  {
782  qof_error_set_be (be, qsql_be->err_create);
783  qsql_be->error = TRUE;
784  PERR (" error on SQL_CREATE:%s", qsql_be->err);
785  }
786  g_free (qb.sql_str);
787  break;
788  }
789  case SQL_LOAD:
790  {
791  qb.sql_str =
792  g_strdup_printf ("SELECT * FROM %s;", obj->e_type);
793  PINFO (" sql=%s", qb.sql_str);
794  if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
795  record_foreach, &qb, &qsql_be->err) != SQLITE_OK)
796  {
797  qsql_be->error = TRUE;
798  PERR (" error on SQL_LOAD:%s", qsql_be->err);
799  }
800  break;
801  }
802  case SQL_WRITE:
803  {
804  if (!qof_book_not_saved (qsql_be->book))
805  break;
806  qof_object_foreach (obj->e_type, qsql_be->book, check_state,
807  &qb);
808  break;
809  }
810  }
811  LEAVE (" ");
812 }
813 
814 static void
815 qsql_backend_createdb (QofBackend * be, QofSession * session)
816 {
817  FILE *f;
818  QSQLiteBackend *qsql_be;
819  struct QsqlBuilder G_GNUC_UNUSED qb;
820 
821  g_return_if_fail (be || session);
822  ENTER (" ");
823  qsql_be = (QSQLiteBackend *) be;
824  qsql_be->stm_type = SQL_CREATE;
825  qb.qsql_be = qsql_be;
826  qsql_be->book = qof_session_get_book (session);
827  DEBUG (" create_file %s", qsql_be->fullpath);
828  f = fopen (qsql_be->fullpath, "a+");
829  if (f)
830  fclose (f);
831  else
832  {
834  (_("Unable to open the output file '%s' - do you have "
835  "permission to create this file?"), TRUE));
836  qsql_be->error = TRUE;
837  LEAVE (" unable to create new file '%s'", qsql_be->fullpath);
838  return;
839  }
840  qsql_be->sqliteh =
841  sqlite_open (qsql_be->fullpath, 0644, &qsql_be->err);
842  if (!qsql_be->sqliteh)
843  {
844  qof_error_set_be (be, qsql_be->err_create);
845  qsql_be->error = TRUE;
846  LEAVE (" unable to open sqlite:%s", qsql_be->err);
847  return;
848  }
850  LEAVE (" ");
851 }
852 
853 static void
854 qsql_backend_opendb (QofBackend * be, QofSession * session)
855 {
856  QSQLiteBackend *qsql_be;
857 
858  g_return_if_fail (be || session);
859  ENTER (" ");
860  qsql_be = (QSQLiteBackend *) be;
861  qsql_be->sqliteh =
862  sqlite_open (qsql_be->fullpath, 0666, &qsql_be->err);
863  if (!qsql_be->sqliteh)
864  {
865  qof_error_set_be (be, qof_error_register
866  (_("Unable to open the sqlite database '%s'."), TRUE));
867  qsql_be->error = TRUE;
868  PERR (" %s", qsql_be->err);
869  }
870  LEAVE (" %s", qsql_be->fullpath);
871 }
872 
873 static void
874 qsqlite_session_begin (QofBackend * be, QofSession * session,
875  const gchar * book_path, gboolean ignore_lock,
876  gboolean create_if_nonexistent)
877 {
878  QSQLiteBackend *qsql_be;
879  gchar **pp;
880  struct stat statinfo;
881  gint G_GNUC_UNUSED stat_val;
882 
883  g_return_if_fail (be);
884  ENTER (" book_path=%s", book_path);
885  qsql_be = (QSQLiteBackend *) be;
886  qsql_be->fullpath = NULL;
887  if (book_path == NULL)
888  {
889  qof_error_set_be (be, qof_error_register
890  (_("Please provide a filename for sqlite."), FALSE));
891  qsql_be->error = TRUE;
892  LEAVE (" bad URL");
893  return;
894  }
895  /* book_path => sqlite_file_name */
896  pp = g_strsplit (book_path, ":", 2);
897  if (0 == safe_strcmp (pp[0], ACCESS_METHOD))
898  {
899  qsql_be->fullpath = g_strdup (pp[1]);
900  g_strfreev (pp);
901  }
902  else
903  qsql_be->fullpath = g_strdup (book_path);
904  be->fullpath = g_strdup (qsql_be->fullpath);
905  PINFO (" final path = %s", qsql_be->fullpath);
906  stat_val = g_stat (qsql_be->fullpath, &statinfo);
907  if (!S_ISREG (statinfo.st_mode) || statinfo.st_size == 0)
908  qsql_backend_createdb (be, session);
909  if (!qsql_be->error)
910  qsql_backend_opendb (be, session);
911  if (qof_error_check_be (be) || qsql_be->error)
912  {
913  LEAVE (" open failed");
914  return;
915  }
916  qsql_be->create_handler =
918  qsql_be->delete_handler =
920  LEAVE (" db=%s", qsql_be->fullpath);
921 }
922 
923 static void
924 qsqlite_db_load (QofBackend * be, QofBook * book)
925 {
926  QSQLiteBackend *qsql_be;
927 
928  g_return_if_fail (be);
929  ENTER (" ");
930  loading = TRUE;
931  qsql_be = (QSQLiteBackend *) be;
932  qsql_be->stm_type = SQL_LOAD;
933  qsql_be->book = book;
934  /* iterate over registered objects */
936  qsql_load_kvp (qsql_be);
937  loading = FALSE;
938  LEAVE (" ");
939 }
940 
941 static void
942 qsqlite_write_db (QofBackend * be, QofBook * book)
943 {
944  QSQLiteBackend *qsql_be;
945 
946  g_return_if_fail (be);
947  qsql_be = (QSQLiteBackend *) be;
948  qsql_be->stm_type = SQL_WRITE;
949  qsql_be->book = book;
950  /* update each record with current state */
952 }
953 
954 static gboolean
955 qsql_determine_file_type (const gchar * path)
956 {
957  if (!path)
958  return FALSE;
959  return TRUE;
960 }
961 
962 static void
963 qsqlite_session_end (QofBackend * be)
964 {
965  QSQLiteBackend *qsql_be;
966 
967  g_return_if_fail (be);
968  qsql_be = (QSQLiteBackend *) be;
969  if (qsql_be->sqliteh)
970  sqlite_close (qsql_be->sqliteh);
971 }
972 
973 static void
974 qsqlite_destroy_backend (QofBackend * be)
975 {
976  QSQLiteBackend *qsql_be;
977 
978  g_return_if_fail (be);
979  qsql_be = (QSQLiteBackend *) be;
980  g_hash_table_destroy (qsql_be->kvp_table);
981  g_hash_table_destroy (qsql_be->kvp_id);
982  qof_event_unregister_handler (qsql_be->create_handler);
983  qof_event_unregister_handler (qsql_be->delete_handler);
984  g_free (be);
985  g_free (qsql_be);
986 }
987 
988 static void
989 qsql_provider_free (QofBackendProvider * prov)
990 {
991  prov->provider_name = NULL;
992  prov->access_method = NULL;
993  g_free (prov);
994 }
995 
1011 static QofBackend *
1013 {
1014  QSQLiteBackend *qsql_be;
1015  QofBackend *be;
1016 
1017  ENTER (" ");
1018  qsql_be = g_new0 (QSQLiteBackend, 1);
1019  be = (QofBackend *) qsql_be;
1020  qof_backend_init (be);
1021  qsql_be->kvp_table = g_hash_table_new (g_str_hash, g_str_equal);
1022  qsql_be->kvp_id = g_hash_table_new (g_str_hash, g_str_equal);
1023  qsql_be->dbversion = QOF_OBJECT_VERSION;
1024  qsql_be->stm_type = SQL_NONE;
1025  qsql_be->err_delete =
1026  qof_error_register (_("Unable to delete record."), FALSE);
1027  qsql_be->err_create =
1028  qof_error_register (_("Unable to create record."), FALSE);
1029  qsql_be->err_insert =
1030  qof_error_register (_("Unable to insert a new record."), FALSE);
1031  qsql_be->err_update =
1032  qof_error_register (_("Unable to update existing record."), FALSE);
1033  be->session_begin = qsqlite_session_begin;
1034 
1035  be->session_end = qsqlite_session_end;
1036  be->destroy_backend = qsqlite_destroy_backend;
1037  be->load = qsqlite_db_load;
1038  be->save_may_clobber_data = NULL;
1039  /* begin: create an empty entity if none exists,
1040  even if events are suspended. */
1041  be->begin = qsql_create;
1042  /* commit: write to sqlite, commit undo record. */
1043  be->commit = qsql_modify;
1044  be->rollback = NULL;
1045  /* would need a QofQuery back to QofSqlQuery conversion. */
1046  be->compile_query = NULL;
1047  /* unused */
1048  be->free_query = NULL;
1049  be->run_query = NULL;
1050  be->counter = NULL;
1051  /* The QOF SQLite backend is not multi-user - all QOF users are the same. */
1052  be->events_pending = NULL;
1053  be->process_events = NULL;
1054 
1055  be->sync = qsqlite_write_db;
1056  be->load_config = NULL;
1057  be->get_config = NULL;
1058  LEAVE (" ");
1059  return be;
1060 }
1061 
1062 void
1064 {
1065  QofBackendProvider *prov;
1066 
1067  ENTER (" ");
1068  bindtextdomain (PACKAGE, LOCALE_DIR);
1070  prov = g_new0 (QofBackendProvider, 1);
1071  prov->provider_name = "QOF SQLite Backend Version 0.4";
1072  prov->access_method = ACCESS_METHOD;
1073  prov->partial_book_supported = TRUE;
1074  prov->backend_new = qsql_backend_new;
1075  prov->check_data_type = qsql_determine_file_type;
1076  prov->provider_free = qsql_provider_free;
1078  LEAVE (" ");
1079 }
1080 
1081 /* ================= END OF FILE =================== */
Private KVP utilities for backends etc.
void qof_sqlite_provider_init(void)
Initialises the SQLite backend.
Definition: qof-sqlite.c:1063
#define QOF_DATE_FORMAT_UTC
QOF UTC format, xsd:date compatible. QOF_UTC_DATE_FORMAT "%Y-%m-%dT%H:%M:%SZ".
Definition: qofdate.h:277
QofErrorId qof_error_register(const gchar *err_message, gboolean use_file)
Generate and register a new error.
Definition: qoferror.c:73
gchar * fullpath
Definition: qofbackend-p.h:332
gboolean(* save_may_clobber_data)(QofBackend *)
Definition: qofbackend-p.h:320
#define PERR(format, args...)
Definition: qoflog.h:183
gpointer qof_object_new_instance(QofIdTypeConst type_name, QofBook *book)
Definition: qofobject.c:42
const gchar * QofIdType
Definition: qofid.h:81
#define QSQL_KVP_TABLE
Definition: qof-sqlite.c:55
#define PINFO(format, args...)
Definition: qoflog.h:199
static KvpValue * string_to_kvp_value(const gchar *content, KvpValueType type)
Definition: qof-sqlite.c:117
gboolean qof_class_is_registered(QofIdTypeConst obj_name)
Definition: qofclass.c:133
void qof_date_free(QofDate *date)
Definition: qofdate.c:642
void qof_backend_register_provider(QofBackendProvider *)
Definition: qofsession.c:59
#define QOF_OBJECT_VERSION
Definition: qofobject.h:57
gchar * qof_sql_entity_insert(QofEntity *ent)
Build a SQL &#39;INSERT&#39; statement for this entity.
Definition: qofsql.c:1389
static gint build_kvp_table(gpointer builder, gint col_num, gchar **strings, gchar **columnNames)
chekc kvp data once per record
Definition: qof-sqlite.c:663
QofIdTypeConst kvp_value_type_to_qof_id(KvpValueType n)
Convert a KvpValueType to a QofIdType.
Definition: kvputil.c:246
GUID * guid_malloc(void)
Definition: guid.c:64
KvpValueType
possible types in the union KvpValue
Definition: kvpframe.h:87
void qof_object_foreach(QofIdTypeConst type_name, QofBook *book, QofEntityForeachCB cb, gpointer user_data)
Definition: qofobject.c:174
#define QOF_EVENT_DESTROY
Definition: qofevent.h:81
gboolean string_to_guid(const gchar *string, GUID *guid)
Unique identifier.
Definition: kvpframe.h:118
static void qsql_class_foreach(QofObject *obj, gpointer data)
Definition: qof-sqlite.c:755
gboolean partial_book_supported
Partial QofBook handler.
Definition: qofbackend-p.h:254
gint32 QofErrorId
The ID of this error.
Definition: qofbackend.h:54
gchar * qof_sql_object_create_table(QofObject *obj)
Build a SQL &#39;CREATE&#39; statement for this object.
Definition: qofsql.c:1346
struct _KvpFrame KvpFrame
Definition: kvpframe.h:74
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...
Definition: qof-sqlite.c:247
KvpValue * kvp_value_new_boolean(gboolean value)
Definition: kvpframe.c:1223
QofErrorId qof_error_check_be(QofBackend *be)
Check for errors.
Definition: qoferror.c:204
gint qof_util_bool_to_int(const gchar *val)
Definition: qofutil.c:252
#define LEAVE(format, args...)
Definition: qoflog.h:227
#define GUID_ENCODING_LENGTH
Definition: guid.h:64
static void qsql_load_kvp(QSQLiteBackend *qsql_be)
Definition: qof-sqlite.c:714
QofTime * qof_date_to_qtime(const QofDate *qd)
Definition: qofdate.c:926
Full range replacement for struct tm.
Definition: qofdate.h:138
KvpFrame * kvp_frame_set_value(KvpFrame *frame, const gchar *key_path, const KvpValue *value)
Copy the KvpValue into the frame.
Definition: kvpframe.c:496
128bit denominator/numerator maths.
Definition: kvpframe.h:106
gchar * qof_sql_entity_update(QofEntity *ent)
Build a SQL &#39;UPDATE&#39; statement for the current entity parameter.
Definition: qofsql.c:1460
const QofParam * qof_class_get_parameter(QofIdTypeConst obj_name, const gchar *parameter)
Definition: qofclass.c:147
#define QOF_EVENT_CREATE
Definition: qofevent.h:71
gint qof_event_register_handler(QofEventHandler handler, gpointer user_data)
Register a handler for events.
Definition: qofevent.c:72
const GUID * qof_instance_get_guid(QofInstance *inst)
Definition: qofinstance.c:79
QofDate * qof_date_parse(const gchar *str, QofDateFormat df)
Convert a timestamp to a QofTime.
Definition: qofdate.c:557
struct _KvpValue KvpValue
Definition: kvpframe.h:78
static void create_event(QofEntity *ent, QofEventId event_type, gpointer handler_data, gpointer event_data)
Definition: qof-sqlite.c:293
KvpFrame * qof_instance_get_slots(QofInstance *inst)
Definition: qofinstance.c:95
void qof_error_set(QofSession *session, QofErrorId error)
Add an error to the stack for this session.
Definition: qoferror.c:112
gint QofEventId
Definition: qofevent.h:40
gboolean qof_numeric_from_string(const gchar *str, QofNumeric *n)
Definition: qofnumeric.c:1116
gboolean qof_book_not_saved(QofBook *book)
Definition: qofbook.c:135
KvpValueType qof_id_to_kvp_value_type(QofIdTypeConst type_string)
Convert a QofIdType to a KvpValueType.
Definition: kvputil.c:228
static gint record_foreach(gpointer builder, gint col_num, gchar **strings, gchar **columnNames)
Definition: qof-sqlite.c:417
void qof_time_free(QofTime *qt)
Free a QofTime when no longer required.
Definition: qoftime.c:56
64bit integer
Definition: kvpframe.h:94
void(* provider_free)(QofBackendProvider *)
Definition: qofbackend-p.h:280
#define DEBUG(format, args...)
Definition: qoflog.h:208
QofBackend *(* backend_new)(void)
Definition: qofbackend-p.h:260
gchar * qof_util_param_to_string(QofEntity *ent, const QofParam *param)
Converts a parameter to a string for storage or display.
Definition: qofutil.c:464
void qof_event_unregister_handler(gint handler_id)
Unregister an event handler.
Definition: qofevent.c:103
gchar * guid_to_string_buff(const GUID *guid, gchar *buff)
gchar * kvp_value_to_bare_string(const KvpValue *val)
General purpose function to convert any KvpValue to a string.
Definition: kvpframe.c:1834
gboolean qof_util_param_set_string(QofEntity *ent, const QofParam *param, const gchar *value_string)
Set a parameter from a value string.
Definition: qofutil.c:647
Private QOF SQL generation routines.
QofEntity entity
Definition: qofinstance-p.h:39
const gchar * access_method
Definition: qofbackend-p.h:247
void kvp_frame_for_each_slot(KvpFrame *f, KvpValueForeachCB proc, gpointer data)
Definition: kvpframe.c:1642
Definition: guid.h:53
gboolean(* check_data_type)(const gchar *)
Distinguish two providers with same access method.
Definition: qofbackend-p.h:277
void qof_sql_entity_set_kvp_tablename(const gchar *name)
Set a default KVP table name for each backend.
Definition: qofsql.c:1558
struct QofTime64 QofTime
Use a 64-bit signed int QofTime.
Definition: qoftime.h:112
void qof_event_suspend(void)
Suspend all engine events.
Definition: qofevent.c:145
Simple boolean type.
Definition: kvpframe.h:136
const GUID * qof_entity_get_guid(QofEntity *ent)
Definition: qofid.c:105
void qof_event_resume(void)
Definition: qofevent.c:156
Public interface of qof-backend-sqlite.
standard C string
Definition: kvpframe.h:112
static G_GNUC_UNUSED void kvpvalue_to_sql(const gchar *key, KvpValue *val, gpointer builder)
Definition: qof-sqlite.c:195
void qof_entity_set_guid(QofEntity *ent, const GUID *guid)
Definition: qofid.c:92
static QofBackend * qsql_backend_new(void)
Starts the backend and creates the context.
Definition: qof-sqlite.c:1012
KvpFrame * kvp_frame_new(void)
Definition: kvpframe.c:97
gint safe_strcmp(const gchar *da, const gchar *db)
Definition: qofutil.c:75
KvpFrame * kvp_value_get_frame(const KvpValue *value)
Definition: kvpframe.c:1546
const QofParam * param
Definition: qofinstance-p.h:53
standard C double type
Definition: kvpframe.h:100
const gchar * provider_name
Definition: qofbackend-p.h:241
QsqlStatementType
Definition: qofsql-p.h:54
const gchar * qof_error_get_message_be(QofBackend *be)
Pop the most recent error and get the message.
Definition: qoferror.c:298
#define ENTER(format, args...)
Definition: qoflog.h:217
gchar * qof_sql_entity_delete(QofEntity *ent)
Build a SQL &#39;DELETE&#39; statement for this entity.
Definition: qofsql.c:1535
void qof_object_foreach_type(QofForeachTypeCB cb, gpointer user_data)
Definition: qofobject.c:140
const gchar * QofLogModule
Definition: qofid.h:85
64bit time/date handling.
Definition: kvpframe.h:124
#define QSQL_ERROR
Definition: qof-sqlite.c:52