QOF: qof-sqlite.c Source File

QOF 0.7.5

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

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-2007 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
34 #define _(String) dgettext (GETTEXT_PACKAGE, String)
35 #define ACCESS_METHOD "sqlite"
36
43 #define PRIORITY_HIGH 9
44
45 #define PRIORITY_STANDARD 5
46
47 #define PRIORITY_LOW 0
48
49 #define QSQL_ERROR -1
50
51 #define QSQL_KVP_TABLE "sqlite_kvp"
52
53 #define END_DB_VERSION " dbversion int );"
54
55 static QofLogModule log_module = QOF_MOD_SQLITE;
56 static gboolean loading = FALSE;
57
58 typedef enum
59 {
61 SQL_NONE = 0,
63 SQL_CREATE,
65 SQL_LOAD,
67 SQL_WRITE,
69 SQL_INSERT,
71 SQL_DELETE,
73 SQL_UPDATE
74 } QsqlStatementType;
75
82 typedef struct
83 {
84 QofBackend be;
85 sqlite *sqliteh;
86 QsqlStatementType stm_type;
87 gint dbversion;
88 gint create_handler;
89 gint delete_handler;
90 const gchar *fullpath;
91 gchar *err;
92 gboolean error;
93 /* full hashtable of kvp records */
94 GHashTable *kvp_table;
95 /* hashtable relating the GUID to the kvp_id */
96 GHashTable *kvp_id;
97 /* highest kvp_id in the table */
98 glong index;
99 QofBook *book;
100 QofErrorId err_delete, err_insert, err_update, err_create;
101 } QSQLiteBackend;
102
109 struct QsqlBuilder
110 {
112 QSQLiteBackend *qsql_be;
114 QofEntity *ent;
116 QofIdType e_type;
118 gchar *sql_str;
120 GList *dirty_list;
122 gboolean exists;
124 gboolean has_slots;
126 const QofParam *dirty;
127 };
128
129 static inline gchar *
130 add_to_sql (gchar * sql_str, const gchar * add)
131 {
132 gchar *old;
133 old = g_strdup (sql_str);
134 g_free (sql_str);
135 sql_str = g_strconcat (old, add, NULL);
136 g_free (old);
137 return sql_str;
138 }
139
144 static QofIdTypeConst
145 kvp_value_to_qof_type_helper (KvpValueType n)
146 {
147 switch (n)
148 {
149 case KVP_TYPE_GINT64:
150 {
151 return QOF_TYPE_INT64;
152 break;
153 }
154 case KVP_TYPE_DOUBLE:
155 {
156 return QOF_TYPE_DOUBLE;
157 break;
158 }
159 case KVP_TYPE_NUMERIC:
160 {
161 return QOF_TYPE_NUMERIC;
162 break;
163 }
164 case KVP_TYPE_STRING:
165 {
166 return QOF_TYPE_STRING;
167 break;
168 }
169 case KVP_TYPE_GUID:
170 {
171 return QOF_TYPE_GUID;
172 break;
173 }
174 #ifndef QOF_DISABLE_DEPRECATED
175 case KVP_TYPE_TIMESPEC:
176 {
177 return QOF_TYPE_DATE;
178 break;
179 }
180 #endif
181 case KVP_TYPE_BOOLEAN:
182 {
183 return QOF_TYPE_BOOLEAN;
184 break;
185 }
186 case KVP_TYPE_TIME:
187 {
188 return QOF_TYPE_TIME;
189 break;
190 }
191 default:
192 {
193 return NULL;
194 }
195 }
196 }
197
199 static KvpValueType
200 sql_to_kvp_helper (const gchar * type_string)
201 {
202 if (0 == safe_strcmp (QOF_TYPE_INT64, type_string))
203 return KVP_TYPE_GINT64;
204 if (0 == safe_strcmp (QOF_TYPE_DOUBLE, type_string))
205 return KVP_TYPE_DOUBLE;
206 if (0 == safe_strcmp (QOF_TYPE_NUMERIC, type_string))
207 return KVP_TYPE_NUMERIC;
208 if (0 == safe_strcmp (QOF_TYPE_STRING, type_string))
209 return KVP_TYPE_STRING;
210 if (0 == safe_strcmp (QOF_TYPE_GUID, type_string))
211 return KVP_TYPE_GUID;
212 #ifndef QOF_DISABLE_DEPRECATED
213 if (0 == safe_strcmp (QOF_TYPE_DATE, type_string))
214 return KVP_TYPE_TIMESPEC;
215 #endif
216 if (0 == safe_strcmp (QOF_TYPE_TIME, type_string))
217 return KVP_TYPE_TIME;
218 return 0;
219 }
220
222 KvpValue *
223 string_to_kvp_value (const gchar * content, KvpValueType type)
224 {
225 gchar *tail;
226 gint64 cm_i64;
227 gdouble cm_double;
228 QofNumeric cm_numeric;
229 GUID *cm_guid;
230 #ifndef QOF_DISABLE_DEPRECATED
231 struct tm kvp_time;
232 time_t kvp_time_t;
233 Timespec cm_date;
234 #endif
235
236 switch (type)
237 {
238 case KVP_TYPE_GINT64:
239 {
240 errno = 0;
241 cm_i64 = strtoll (content, &tail, 0);
242 if (errno == 0)
243 {
244 return kvp_value_new_gint64 (cm_i64);
245 }
246 break;
247 }
248 case KVP_TYPE_DOUBLE:
249 {
250 errno = 0;
251 cm_double = strtod (content, &tail);
252 if (errno == 0)
253 return kvp_value_new_double (cm_double);
254 break;
255 }
256 case KVP_TYPE_NUMERIC:
257 {
258 qof_numeric_from_string (content, &cm_numeric);
259 return kvp_value_new_numeric (cm_numeric);
260 break;
261 }
262 case KVP_TYPE_STRING:
263 {
264 return kvp_value_new_string (content);
265 break;
266 }
267 case KVP_TYPE_GUID:
268 {
269 cm_guid = g_new0 (GUID, 1);
270 if (TRUE == string_to_guid (content, cm_guid))
271 return kvp_value_new_guid (cm_guid);
272 break;
273 }
274 case KVP_TYPE_TIME:
275 {
276 QofDate *qd;
277 QofTime *qt;
278 KvpValue *retval;
279
280 qd = qof_date_parse (content, QOF_DATE_FORMAT_UTC);
281 if (qd)
282 {
283 qt = qof_date_to_qtime (qd);
284 retval = kvp_value_new_time (qt);
285 qof_date_free (qd);
286 qof_time_free (qt);
287 return retval;
288 }
289 else
290 PERR (" failed to parse date");
291 }
292 #ifndef QOF_DISABLE_DEPRECATED
293 case KVP_TYPE_TIMESPEC:
294 {
295 strptime (content, QOF_UTC_DATE_FORMAT, &kvp_time);
296 kvp_time_t = mktime (&kvp_time);
297 timespecFromTime_t (&cm_date, kvp_time_t);
298 return kvp_value_new_timespec (cm_date);
299 break;
300 }
301 #endif
302 case KVP_TYPE_BOOLEAN:
303 {
304 gboolean val;
305 val = qof_util_bool_to_int (content);
306 return kvp_value_new_boolean (val);
307 }
308 default:
309 break;
310 }
311 return NULL;
312 }
313
315 static void
316 kvpvalue_to_sql (const gchar * key, KvpValue * val, gpointer builder)
317 {
318 QSQLiteBackend *qsql_be;
319 struct QsqlBuilder *qb;
320 KvpValueType n;
321 gchar *full_path;
322
323 full_path = NULL;
324 ENTER (" ");
325 qb = (struct QsqlBuilder *) builder;
326 qsql_be = qb->qsql_be;
327 g_return_if_fail (key && val && qsql_be);
328 n = kvp_value_get_type (val);
329 switch (n)
330 {
331 case KVP_TYPE_GINT64:
332 case KVP_TYPE_DOUBLE:
333 case KVP_TYPE_NUMERIC:
334 case KVP_TYPE_STRING:
335 case KVP_TYPE_GUID:
336 case KVP_TYPE_TIME:
337 case KVP_TYPE_BOOLEAN:
338 #ifndef QOF_DISABLE_DEPRECATED
339 case KVP_TYPE_TIMESPEC:
340 #endif
341 {
342 /* ("kvp_id int primary key not null", "guid char(32)", "path mediumtext",
343 "type mediumtext", "value text", */
344
345 qb->sql_str =
346 g_strdup_printf (" kvp key=%s val=%s type=%s", key,
347 kvp_value_to_bare_string (val),
348 kvp_value_to_qof_type_helper (n));
349 DEBUG (" %s", qb->sql_str);
350 qb->has_slots = TRUE;
351 break;
352 }
353 case KVP_TYPE_FRAME:
354 {
355 kvp_frame_for_each_slot (kvp_value_get_frame (val),
356 kvpvalue_to_sql, qb);
357 break;
358 }
359 default:
360 {
361 PERR (" unsupported value = %d", kvp_value_get_type (val));
362 break;
363 }
364 }
365 LEAVE (" %s", qb->sql_str);
366 }
367
368 static gchar *
369 string_param_to_sql (QofParam * param)
370 {
371 /* Handle the entity GUID. Ensure that reference GUIDs
372 must not also try to be primary keys and can be NULL. */
373 if ((0 == safe_strcmp (param->param_type, QOF_TYPE_GUID)) &&
374 (0 == safe_strcmp (param->param_name, QOF_PARAM_GUID)))
375 return g_strdup_printf (" %s char(32) primary key not null",
376 param->param_name);
377 if (0 == safe_strcmp (param->param_type, QOF_TYPE_GUID))
378 return g_strdup_printf (" %s char(32)", param->param_name);
379 /* avoid creating database fields for calculated values */
380 if (!param->param_setfcn)
381 return NULL;
382 if (0 == safe_strcmp (param->param_type, QOF_TYPE_STRING))
383 return g_strdup_printf (" %s mediumtext", param->param_name);
384 if (0 == safe_strcmp (param->param_type, QOF_TYPE_BOOLEAN))
385 return g_strdup_printf (" %s int", param->param_name);
386 if ((0 == safe_strcmp (param->param_type, QOF_TYPE_NUMERIC))
387 || (0 == safe_strcmp (param->param_type, QOF_TYPE_DOUBLE))
388 || (0 == safe_strcmp (param->param_type, QOF_TYPE_DEBCRED)))
389 {
390 return g_strdup_printf (" %s text", param->param_name);
391 }
392 if (0 == safe_strcmp (param->param_type, QOF_TYPE_INT32))
393 return g_strdup_printf (" %s int", param->param_name);
394 #ifndef QOF_DISABLE_DEPRECATED
395 if ((0 == safe_strcmp (param->param_type, QOF_TYPE_DATE)) ||
396 (0 == safe_strcmp (param->param_type, QOF_TYPE_TIME)))
397 #else
398 if (0 == safe_strcmp (param->param_type, QOF_TYPE_TIME))
399 #endif
400 return g_strdup_printf (" %s datetime", param->param_name);
401 if (0 == safe_strcmp (param->param_type, QOF_TYPE_CHAR))
402 return g_strdup_printf (" %s char(1)", param->param_name);
403 /* kvp data is stored separately - actually this is really
404 a no-op because entities do not need a param_setfcn for kvp data. */
405 if (0 == safe_strcmp (param->param_type, QOF_TYPE_KVP))
406 return g_strdup ("");
407 if (0 == safe_strcmp (param->param_type, QOF_TYPE_COLLECT))
408 return g_strdup_printf (" %s char(32)", param->param_name);
409 /* catch references */
410 return g_strdup_printf (" %s char(32)", param->param_name);
411 }
412
418 static void
419 create_param_list (QofParam * param, gpointer builder)
420 {
421 struct QsqlBuilder *qb;
422 qb = (struct QsqlBuilder *) builder;
423
424 /* avoid creating database fields for calculated values */
425 if (!param->param_setfcn)
426 return;
427 /* avoid setting KVP even if a param_setfcn has been set
428 because a QofSetterFunc for KVP is quite pointless. */
429 if (0 == safe_strcmp (param->param_type, QOF_TYPE_KVP))
430 {
431 PINFO (" kvp support tag");
432 return;
433 }
434 if (!g_str_has_suffix (qb->sql_str, "("))
435 {
436 gchar *add;
437 add = g_strconcat (", ", param->param_name, NULL);
438 qb->sql_str = add_to_sql (qb->sql_str, add);
439 g_free (add);
440 }
441 else
442 qb->sql_str = add_to_sql (qb->sql_str, param->param_name);
443 }
444
446 static void
447 create_each_param (QofParam * param, gpointer builder)
448 {
449 gchar *value;
450 struct QsqlBuilder *qb;
451 qb = (struct QsqlBuilder *) builder;
452 GList *references;
453
454 /* avoid creating database fields for calculated values */
455 if (!param->param_setfcn)
456 return;
457 /* avoid setting KVP even if a param_setfcn has been set
458 because a QofSetterFunc for KVP is quite pointless. */
459 if (0 == safe_strcmp (param->param_type, QOF_TYPE_KVP))
460 return;
461 references = qof_class_get_referenceList (qb->ent->e_type);
462 if (g_list_find (references, param))
463 {
466 QofEntity *e;
467 e = param->param_getfcn (qb->ent, param);
468 value = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
469 guid_to_string_buff (qof_entity_get_guid (e), value);
470 PINFO (" ref=%p GUID=%s", e, value);
471 }
472 else
473 value = qof_util_param_to_string (qb->ent, param);
474 if (value)
475 g_strescape (value, NULL);
476 if (!value)
477 value = g_strdup ("");
478 if (!g_str_has_suffix (qb->sql_str, "("))
479 {
480 gchar *val;
481 val = g_strconcat (", \"", value, "\"", NULL);
482 qb->sql_str = add_to_sql (qb->sql_str, val);
483 g_free (val);
484 }
485 else
486 {
487 gchar *val;
488 val = g_strconcat ("\"", value, "\"", NULL);
489 qb->sql_str = add_to_sql (qb->sql_str, val);
490 g_free (val);
491 }
492 }
493
498 static void
499 delete_event (QofEntity * ent, QofEventId event_type,
500 gpointer handler_data, gpointer event_data)
501 {
502 QofBackend *be;
503 QSQLiteBackend *qsql_be;
504 gchar *gstr, *sql_str;
505
506 qsql_be = (QSQLiteBackend *) handler_data;
507 be = (QofBackend *) qsql_be;
508 if (!ent)
509 return;
510 if (0 == safe_strcmp (ent->e_type, QOF_ID_BOOK))
511 return;
512 /* do not try to delete if only a QofObject has been loaded. */
513 if (!qof_class_is_registered (ent->e_type))
514 return;
515 switch (event_type)
516 {
517 case QOF_EVENT_DESTROY:
518 {
519 ENTER (" %s do_free=%d", ent->e_type,
520 ((QofInstance *) ent)->do_free);
521 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
522 guid_to_string_buff (qof_entity_get_guid (ent), gstr);
523 sql_str = g_strconcat ("DELETE from ", ent->e_type, " WHERE ",
524 QOF_TYPE_GUID, "='", gstr, "';", NULL);
525 DEBUG (" sql_str=%s", sql_str);
526 if (sqlite_exec (qsql_be->sqliteh, sql_str,
527 NULL, qsql_be, &qsql_be->err) != SQLITE_OK)
528 {
529 qof_error_set_be (be, qsql_be->err_delete);
530 qsql_be->error = TRUE;
531 LEAVE (" error on delete:%s", qsql_be->err);
532 break;
533 }
535 /* SELECT kvp_id from QSQL_KVP_TABLE where guid = gstr */
536 LEAVE (" %d", event_type);
537 qsql_be->error = FALSE;
538 g_free (gstr);
539 break;
540 }
541 default:
542 break;
543 }
544 }
545
547 static void
548 create_event (QofEntity * ent, QofEventId event_type,
549 gpointer handler_data, gpointer event_data)
550 {
551 QofBackend *be;
552 struct QsqlBuilder qb;
553 QSQLiteBackend *qsql_be;
554 gchar *gstr;
555 KvpFrame *slots;
556
557 qsql_be = (QSQLiteBackend *) handler_data;
558 be = (QofBackend *) qsql_be;
559 if (!ent)
560 return;
561 if (0 == safe_strcmp (ent->e_type, QOF_ID_BOOK))
562 return;
563 if (!qof_class_is_registered (ent->e_type))
564 return;
565 switch (event_type)
566 {
567 case QOF_EVENT_CREATE:
568 {
569 gchar *tmp;
570 ENTER (" create:%s", ent->e_type);
571 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
572 guid_to_string_buff (qof_instance_get_guid ((QofInstance *)
573 ent), gstr);
574 DEBUG (" guid=%s", gstr);
575 qb.ent = ent;
576 qb.sql_str =
577 g_strdup_printf ("INSERT into %s (guid ", ent->e_type);
578 qof_class_param_foreach (ent->e_type, create_param_list, &qb);
579 tmp = g_strconcat (") VALUES (\"", gstr, "\" ", NULL);
580 qb.sql_str = add_to_sql (qb.sql_str, tmp);
581 g_free (tmp);
582 qof_class_param_foreach (ent->e_type, create_each_param, &qb);
583 qb.sql_str = add_to_sql (qb.sql_str, ");");
584 DEBUG (" sql_str=%s", qb.sql_str);
585 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
586 NULL, &qb, &qsql_be->err) != SQLITE_OK)
587 {
588 qof_error_set_be (be, qsql_be->err_insert);
589 qsql_be->error = TRUE;
590 PERR (" error on create_event:%s", qsql_be->err);
591 }
592 else
593 {
594 ((QofInstance *) ent)->dirty = FALSE;
595 qsql_be->error = FALSE;
596 g_free (qb.sql_str);
597 g_free (gstr);
598 LEAVE (" ");
599 break;
600 }
601 /* insert sqlite_kvp data */
602 slots = qof_instance_get_slots ((QofInstance *) ent);
603 if (slots)
604 {
605 /* id, guid, path, type, value */
606 qb.sql_str = g_strconcat ("INSERT into ", QSQL_KVP_TABLE,
607 " (kvp_id \"", gstr, "\", ", NULL);
608 kvp_frame_for_each_slot (slots, kvpvalue_to_sql, &qb);
609 qb.sql_str = add_to_sql (qb.sql_str, END_DB_VERSION);
610 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
611 NULL, &qb, &qsql_be->err) != SQLITE_OK)
612 {
613 qof_error_set_be (be, qsql_be->err_insert);
614 qsql_be->error = TRUE;
615 PERR (" error on KVP create_event:%s", qsql_be->err);
616 }
617 else
618 {
619 ((QofInstance *) ent)->dirty = FALSE;
620 qsql_be->error = FALSE;
621 g_free (qb.sql_str);
622 g_free (gstr);
623 LEAVE (" ");
624 break;
625 }
626 }
627 g_free (qb.sql_str);
628 g_free (gstr);
629 LEAVE (" ");
630 break;
631 }
632 default:
633 break;
634 }
635 }
636
637 static void
638 qsql_modify (QofBackend * be, QofInstance * inst)
639 {
640 struct QsqlBuilder qb;
641 QSQLiteBackend *qsql_be;
642 gchar *gstr, *param_str;
643 KvpFrame *slots;
644
645 qsql_be = (QSQLiteBackend *) be;
646 qb.qsql_be = qsql_be;
647 if (!inst)
648 return;
649 if (!inst->param)
650 return;
651 if (loading)
652 return;
653 if (!inst->param->param_setfcn)
654 return;
655 ENTER (" modified %s param:%s", ((QofEntity *) inst)->e_type,
656 inst->param->param_name);
657 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
658 guid_to_string_buff (qof_instance_get_guid (inst), gstr);
659 qb.ent = (QofEntity *) inst;
660 param_str = qof_util_param_to_string (qb.ent, inst->param);
661 if (param_str)
662 g_strescape (param_str, NULL);
663 qb.sql_str = g_strconcat ("UPDATE ", qb.ent->e_type, " SET ",
664 inst->param->param_name, " = \"", param_str,
665 "\" WHERE ", QOF_TYPE_GUID, "='", gstr, "';", NULL);
666 DEBUG (" sql_str=%s param_Str=%s", qb.sql_str, param_str);
667 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
668 NULL, &qb, &qsql_be->err) != SQLITE_OK)
669 {
670 qof_error_set_be (be, qsql_be->err_update);
671 qsql_be->error = TRUE;
672 PERR (" error on modify:%s", qsql_be->err);
673 }
674 else
675 {
676 inst->dirty = FALSE;
677 g_free (qb.sql_str);
678 g_free (gstr);
679 qsql_be->error = FALSE;
680 LEAVE (" ");
681 return;
682 }
683 /* modify slot data */
684 slots = qof_instance_get_slots (inst);
685 if (slots)
686 {
687 /* update and delete KVP data */
688 /* id, guid, path, type, value */
689 qb.sql_str = g_strconcat ("UPDATE ", QSQL_KVP_TABLE,
690 " SET (kvp_id \"", gstr, "\", ", NULL);
691 kvp_frame_for_each_slot (slots, kvpvalue_to_sql, &qb);
692 qb.sql_str = add_to_sql (qb.sql_str, END_DB_VERSION);
693 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
694 NULL, &qb, &qsql_be->err) != SQLITE_OK)
695 {
696 qof_error_set_be (be, qsql_be->err_insert);
697 qsql_be->error = TRUE;
698 PERR (" error on KVP create_event:%s", qsql_be->err);
699 }
700 else
701 {
702 ((QofInstance *) qb.ent)->dirty = FALSE;
703 qsql_be->error = FALSE;
704 g_free (qb.sql_str);
705 }
706 }
707 g_free (gstr);
708 LEAVE (" ");
709 }
710
712 static gint
713 record_foreach (gpointer builder, gint col_num, gchar ** strings,
714 gchar ** columnNames)
715 {
716 QSQLiteBackend *qsql_be;
717 struct QsqlBuilder *qb;
718 const QofParam *param;
719 QofInstance *inst;
720 QofEntity *ent;
721 gint i;
722
723 g_return_val_if_fail (builder, QSQL_ERROR);
724 qb = (struct QsqlBuilder *) builder;
725 qsql_be = qb->qsql_be;
726 qof_event_suspend ();
727 inst = (QofInstance *) qof_object_new_instance (qb->e_type, qsql_be->book);
728 ent = &inst->entity;
729 for (i = 0; i < col_num; i++)
730 {
731 /* get param and set as string */
732 param = qof_class_get_parameter (qb->e_type, columnNames[i]);
733 if (!param)
734 continue;
735 /* set the inst->param entry */
736 inst->param = param;
737 if (0 == safe_strcmp (columnNames[i], QOF_TYPE_GUID))
738 {
739 GUID *guid;
740 guid = guid_malloc ();
741 if (!string_to_guid (strings[i], guid))
742 {
743 DEBUG (" set guid failed:%s", strings[i]);
744 return QSQL_ERROR;
745 }
746 qof_entity_set_guid (ent, guid);
747 }
748 if (strings[i])
749 qof_util_param_set_string (ent, param, strings[i]);
750 }
751 qof_event_resume ();
752 return SQLITE_OK;
753 }
754
755 /* used by create/insert */
756 static void
757 string_param_foreach (QofParam * param, gpointer builder)
758 {
759 struct QsqlBuilder *qb;
760 QSQLiteBackend *qsql_be;
761 gchar *p_str, *old;
762
763 qb = (struct QsqlBuilder *) builder;
764 qsql_be = qb->qsql_be;
765 if (0 == safe_strcmp (param->param_type, QOF_TYPE_KVP))
766 return;
767 p_str = string_param_to_sql (param);
768 /* skip empty values (no param_setfcn) */
769 if (!p_str)
770 return;
771 old = g_strconcat (p_str, ",", NULL);
772 qb->sql_str = add_to_sql (qb->sql_str, old);
773 g_free (old);
774 g_free (p_str);
775 }
776
777 static void
778 update_param_foreach (QofParam * param, gpointer builder)
779 {
780 struct QsqlBuilder *qb;
781 gchar *value, *add;
782
783 qb = (struct QsqlBuilder *) builder;
784 if (param != qb->dirty)
785 return;
786 /* update table set name=val,name=val where guid=gstr; */
787 value = qof_util_param_to_string (qb->ent, param);
788 if (value)
789 g_strescape (value, NULL);
790 if (!value)
791 value = g_strdup ("");
792 if (g_str_has_suffix (qb->sql_str, " "))
793 {
794 add = g_strconcat (param->param_name, "=\"", value, "\"", NULL);
795 qb->sql_str = add_to_sql (qb->sql_str, add);
796 g_free (add);
797 }
798 else
799 {
800 add =
801 g_strconcat (",", param->param_name, "=\"", value, "\"", NULL);
802 qb->sql_str = add_to_sql (qb->sql_str, add);
803 g_free (add);
804 }
805 }
806
807 static void
808 update_dirty (gpointer value, gpointer builder)
809 {
810 QofInstance *inst;
811 QofEntity *ent;
812 struct QsqlBuilder *qb;
813 QSQLiteBackend *qsql_be;
814 QofBackend *be;
815 gchar *gstr, *param_str;
816
817 qb = (struct QsqlBuilder *) builder;
818 qsql_be = qb->qsql_be;
819 be = (QofBackend *) qsql_be;
820 ent = (QofEntity *) value;
821 inst = (QofInstance *) ent;
822 if (!inst->dirty)
823 return;
824 ENTER (" ");
825 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
826 guid_to_string_buff (qof_entity_get_guid (ent), gstr);
827 /* qof_class_param_foreach */
828 qb->sql_str = g_strdup_printf ("UPDATE %s SET ", ent->e_type);
829 qof_class_param_foreach (ent->e_type, update_param_foreach, qb);
830 param_str = g_strdup_printf ("WHERE %s=\"%s\";", QOF_TYPE_GUID, gstr);
831 qb->sql_str = add_to_sql (qb->sql_str, param_str);
832 g_free (param_str);
833 DEBUG (" update=%s", qb->sql_str);
834 if (sqlite_exec (qsql_be->sqliteh, qb->sql_str,
835 NULL, qb, &qsql_be->err) != SQLITE_OK)
836 {
837 qof_error_set_be (be, qsql_be->err_update);
838 qsql_be->error = TRUE;
839 PERR (" error on update_dirty:%s", qsql_be->err);
840 }
841 else
842 {
843 qof_error_get_message_be (be);
844 qsql_be->error = FALSE;
845 inst->dirty = FALSE;
846 }
847 LEAVE (" ");
848 g_free (gstr);
849 return;
850 }
851
852 static gint
853 create_dirty_list (gpointer builder, gint col_num, gchar ** strings,
854 gchar ** columnNames)
855 {
856 struct QsqlBuilder *qb;
857 QofInstance *inst;
858 const QofParam *param;
859 gchar *value, *columnName, *tmp;
860
861 param = NULL;
862 qb = (struct QsqlBuilder *) builder;
863 /* qb->ent is the live data, strings is the sqlite data */
864 inst = (QofInstance *) qb->ent;
865 qb->exists = TRUE;
866 if (!inst->dirty)
867 return SQLITE_OK;
868 columnName = columnNames[col_num];
869 tmp = strings[col_num];
870 param = qof_class_get_parameter (qb->ent->e_type, columnName);
871 if (!param)
872 return SQLITE_OK;
873 value = qof_util_param_to_string (qb->ent, param);
874 qb->dirty = param;
875 qb->dirty_list = g_list_prepend (qb->dirty_list, qb->ent);
876 DEBUG (" dirty_list=%d", g_list_length (qb->dirty_list));
877 return SQLITE_OK;
878 }
879
880 static gint
881 mark_entity (gpointer builder, gint col_num, gchar ** strings,
882 gchar ** columnNames)
883 {
884 struct QsqlBuilder *qb;
885
886 qb = (struct QsqlBuilder *) builder;
887 qb->exists = TRUE;
888 return SQLITE_OK;
889 }
890
891 static void
892 qsql_create (QofBackend * be, QofInstance * inst)
893 {
894 gchar *gstr;
895 QSQLiteBackend *qsql_be;
896 struct QsqlBuilder qb;
897 QofEntity *ent;
898 KvpFrame *slots;
899
900 qsql_be = (QSQLiteBackend *) be;
901 if (!inst)
902 return;
903 if (loading)
904 return;
905 ent = (QofEntity *) inst;
906 qof_event_suspend ();
907 qb.has_slots = FALSE;
908 ENTER (" %s", ent->e_type);
909 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
910 guid_to_string_buff (qof_entity_get_guid (ent), gstr);
911 qb.sql_str =
912 g_strdup_printf ("SELECT * FROM %s where guid = \"%s\";",
913 ent->e_type, gstr);
914 PINFO (" check exists: %s", qb.sql_str);
915 qb.ent = ent;
916 qb.dirty_list = NULL;
917 qb.exists = FALSE;
918 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
919 mark_entity, &qb, &qsql_be->err) != SQLITE_OK)
920 {
921 qof_error_set_be (be, qsql_be->err_update);
922 qsql_be->error = TRUE;
923 PERR (" error on select :%s", qsql_be->err);
924 }
925 if (!qb.exists)
926 {
927 gchar *add;
928 /* create new entity */
929 qb.sql_str =
930 g_strdup_printf ("INSERT into %s (guid ", ent->e_type);
931 qof_class_param_foreach (ent->e_type, create_param_list, &qb);
932 add = g_strconcat (") VALUES (\"", gstr, "\"", NULL);
933 qb.sql_str = add_to_sql (qb.sql_str, add);
934 g_free (add);
935 qof_class_param_foreach (ent->e_type, create_each_param, &qb);
936 qb.sql_str = add_to_sql (qb.sql_str, ");");
937 DEBUG (" sql_str= %s", qb.sql_str);
938 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
939 NULL, qsql_be, &qsql_be->err) != SQLITE_OK)
940 {
941 qof_error_set_be (be, qsql_be->err_insert);
942 qsql_be->error = TRUE;
943 PERR (" error creating new entity:%s", qsql_be->err);
944 }
945 /* KVP here */
946 slots = qof_instance_get_slots ((QofInstance *) ent);
947 if (slots)
948 {
949 /* id, guid, path, type, value */
950 qb.sql_str = g_strconcat ("INSERT into ", QSQL_KVP_TABLE,
951 " (kvp_id, \"", gstr, "\", ", NULL);
952 kvp_frame_for_each_slot (slots, kvpvalue_to_sql, &qb);
953 qb.sql_str = add_to_sql (qb.sql_str, ");");
954 }
955 if (qb.has_slots)
956 {
957 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
958 NULL, &qb, &qsql_be->err) != SQLITE_OK)
959 {
960 qof_error_set_be (be, qsql_be->err_insert);
961 qsql_be->error = TRUE;
962 PERR (" error on KVP create_event:%s:%s", qsql_be->err,
963 qb.sql_str);
964 }
965 else
966 {
967 ((QofInstance *) ent)->dirty = FALSE;
968 qsql_be->error = FALSE;
969 }
970 }
971 }
972 g_free (qb.sql_str);
973 g_free (gstr);
974 qof_event_resume ();
975 LEAVE (" ");
976 }
977
978 static void
979 check_state (QofEntity * ent, gpointer builder)
980 {
981 gchar *gstr;
982 QSQLiteBackend *qsql_be;
983 struct QsqlBuilder *qb;
984 QofBackend *be;
985 QofInstance *inst;
986 KvpFrame *slots;
987
988 qb = (struct QsqlBuilder *) builder;
989 qsql_be = qb->qsql_be;
990 be = (QofBackend *) qsql_be;
991 inst = (QofInstance *) ent;
992 if (!inst->dirty)
993 return;
994 /* check if this entity already exists */
995 gstr = g_strnfill (GUID_ENCODING_LENGTH + 1, ' ');
996 guid_to_string_buff (qof_entity_get_guid (ent), gstr);
997 qb->sql_str =
998 g_strdup_printf ("SELECT * FROM %s where guid = \"%s\";",
999 ent->e_type, gstr);
1000 qb->ent = ent;
1001 qb->dirty_list = NULL;
1002 /* assume entity does not yet exist in backend,
1003 e.g. being copied from another session. */
1004 qb->exists = FALSE;
1005 qb->qsql_be = qsql_be;
1006 /* update each dirty instance */
1007 /* Make a GList of dirty instances
1008 Don't update during a SELECT,
1009 UPDATE will fail with DB_LOCKED */
1010 if (sqlite_exec (qsql_be->sqliteh, qb->sql_str,
1011 create_dirty_list, qb, &qsql_be->err) != SQLITE_OK)
1012 {
1013 qof_error_set_be (be, qsql_be->err_update);
1014 qsql_be->error = TRUE;
1015 PERR (" error on check_state:%s", qsql_be->err);
1016 }
1017 if (!qb->exists)
1018 {
1019 gchar *add;
1020 /* create new entity */
1021 qb->sql_str =
1022 g_strdup_printf ("INSERT into %s (guid ", ent->e_type);
1023 qof_class_param_foreach (ent->e_type, create_param_list, &qb);
1024 add = g_strconcat (") VALUES (\"", gstr, "\" ", NULL);
1025 qb->sql_str = add_to_sql (qb->sql_str, add);
1026 g_free (add);
1027 qof_class_param_foreach (ent->e_type, create_each_param, &qb);
1028 qb->sql_str = add_to_sql (qb->sql_str, ");");
1029 DEBUG (" sql_str= %s", qb->sql_str);
1030 if (sqlite_exec (qsql_be->sqliteh, qb->sql_str,
1031 NULL, qb, &qsql_be->err) != SQLITE_OK)
1032 {
1033 qof_error_set_be (be, qsql_be->err_insert);
1034 qsql_be->error = TRUE;
1035 PERR (" error on check_state create_new:%s", qsql_be->err);
1036 }
1037 g_free (qb->sql_str);
1038 /* create KVP data too */
1039 slots = qof_instance_get_slots ((QofInstance *) ent);
1040 if (slots)
1041 {
1042 /* id, guid, path, type, value */
1043 qb->sql_str = g_strconcat ("INSERT into ", QSQL_KVP_TABLE,
1044 " (kvp_id \"", gstr, "\", ", NULL);
1045 kvp_frame_for_each_slot (slots, kvpvalue_to_sql, &qb);
1046 qb->sql_str = add_to_sql (qb->sql_str, END_DB_VERSION);
1047 if (sqlite_exec (qsql_be->sqliteh, qb->sql_str,
1048 NULL, &qb, &qsql_be->err) != SQLITE_OK)
1049 {
1050 qof_error_set_be (be, qsql_be->err_insert);
1051 qsql_be->error = TRUE;
1052 PERR (" error on KVP create_event:%s", qsql_be->err);
1053 }
1054 else
1055 {
1056 ((QofInstance *) ent)->dirty = FALSE;
1057 qsql_be->error = FALSE;
1058 }
1059 }
1060 }
1061 /* update instead */
1062 g_list_foreach (qb->dirty_list, update_dirty, &qb);
1063 g_free (qb->sql_str);
1064 g_free (gstr);
1065 }
1066
1075 static gint
1076 build_kvp_table (gpointer builder, gint col_num, gchar ** strings,
1077 gchar ** columnNames)
1078 {
1079 QSQLiteBackend *qsql_be;
1080 struct QsqlBuilder *qb;
1081 KvpFrame *frame;
1082 KvpValueType type;
1083 KvpValue *value;
1084 glong max;
1085 gchar *tail;
1086
1087 g_return_val_if_fail (builder, QSQL_ERROR);
1088 qb = (struct QsqlBuilder *) builder;
1089 max = 0;
1090 qsql_be = qb->qsql_be;
1091 g_return_val_if_fail ((col_num < 4), QSQL_ERROR);
1092 g_return_val_if_fail (strings[2], QSQL_ERROR);
1093 frame = kvp_frame_new ();
1094 /* columnNames = fields strings = values
1095 [0]=kvp_id, [1]=guid, [2]=path, [3]=type, [4]=value
1096 get type from type_string */
1097 type = sql_to_kvp_helper (strings[3]);
1098 if (type == 0)
1099 {
1100 PERR (" invalid type returned from kvp table");
1101 return QSQL_ERROR;
1102 }
1103 /* use the type to make a KvpValue from value */
1104 value = string_to_kvp_value (strings[4], type);
1105 if (!value)
1106 {
1107 PERR (" invalid KvpValue for type: %d", type);
1108 return QSQL_ERROR;
1109 }
1110 /* add the KvpValue to the frame at path */
1111 kvp_frame_set_value (frame, strings[2], value);
1112 /* index the frame under the entity GUID */
1113 g_hash_table_insert (qsql_be->kvp_table, strings[1], frame);
1114 /* index the guid under the kvp_id */
1115 g_hash_table_insert (qsql_be->kvp_id, strings[0], strings[1]);
1116 errno = 0;
1117 max = strtol (strings[0], &tail, 0);
1118 if (errno == 0)
1119 {
1120 qsql_be->index = (max > qsql_be->index) ? max : qsql_be->index;
1121 }
1122 return SQLITE_OK;
1123 }
1124
1126 static void
1127 qsql_load_kvp (QSQLiteBackend * qsql_be)
1128 {
1129 struct QsqlBuilder qb;
1130 QofBackend *be;
1131 gint sq_code;
1132
1133 g_return_if_fail (qsql_be);
1134 sq_code = SQLITE_OK;
1135 be = (QofBackend *) qsql_be;
1136 qb.sql_str =
1137 g_strdup_printf ("SELECT kvp_id from %s;", QSQL_KVP_TABLE);
1138 sq_code = sqlite_exec (qsql_be->sqliteh, qb.sql_str, build_kvp_table,
1139 &qb, &qsql_be->err);
1140 /* catch older files without a sqlite_kvp table */
1141 if (sq_code == SQLITE_ERROR)
1142 {
1143 g_free (qb.sql_str);
1144 qb.sql_str =
1145 g_strdup_printf ("CREATE TABLE %s (%s, %s, %s, %s, %s, %s",
1146 QSQL_KVP_TABLE, "kvp_id int primary key not null",
1147 "guid char(32)", "path mediumtext", "type mediumtext",
1148 "value text", END_DB_VERSION);
1149 PINFO (" creating kvp table. sql=%s", qb.sql_str);
1150 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
1151 record_foreach, &qb, &qsql_be->err) != SQLITE_OK)
1152 {
1153 qsql_be->error = TRUE;
1154 PERR (" unable to create kvp table:%s", qsql_be->err);
1155 }
1156 }
1157 else if (sq_code != SQLITE_OK)
1158 {
1159 qof_error_set_be (be, qsql_be->err_create);
1160 qsql_be->error = TRUE;
1161 PERR (" error on KVP select:%s:%s:%d", qb.sql_str, qsql_be->err, sq_code);
1162 }
1163 g_free (qb.sql_str);
1164 }
1165
1167 static void
1168 qsql_class_foreach (QofObject * obj, gpointer data)
1169 {
1170 struct QsqlBuilder qb;
1171 QSQLiteBackend *qsql_be;
1172 QofBackend *be;
1173
1174 qsql_be = (QSQLiteBackend *) data;
1175 be = (QofBackend *) qsql_be;
1176 qb.qsql_be = qsql_be;
1177 qb.e_type = obj->e_type;
1178 ENTER (" obj_type=%s", qb.e_type);
1179 switch (qsql_be->stm_type)
1180 {
1181 case SQL_NONE:
1182 case SQL_INSERT:
1183 case SQL_DELETE:
1184 case SQL_UPDATE:
1185 {
1186 break;
1187 }
1188 case SQL_CREATE:
1189 {
1190 /* KVP is handled separately */
1191 qb.sql_str =
1192 g_strdup_printf ("CREATE TABLE %s (", obj->e_type);
1193 qof_class_param_foreach (obj->e_type, string_param_foreach,
1194 &qb);
1195 qb.sql_str = add_to_sql (qb.sql_str, END_DB_VERSION);
1196 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
1197 NULL, NULL, &qsql_be->err) != SQLITE_OK)
1198 {
1199 qof_error_set_be (be, qsql_be->err_create);
1200 qsql_be->error = TRUE;
1201 PERR (" error on SQL_CREATE:%s", qsql_be->err);
1202 }
1203 g_free (qb.sql_str);
1204 break;
1205 }
1206 case SQL_LOAD:
1207 {
1208 qb.sql_str =
1209 g_strdup_printf ("SELECT * FROM %s;", obj->e_type);
1210 PINFO (" sql=%s", qb.sql_str);
1211 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
1212 record_foreach, &qb, &qsql_be->err) != SQLITE_OK)
1213 {
1214 qsql_be->error = TRUE;
1215 PERR (" error on SQL_LOAD:%s", qsql_be->err);
1216 }
1217 break;
1218 }
1219 case SQL_WRITE:
1220 {
1221 if (!qof_book_not_saved (qsql_be->book))
1222 break;
1223 qof_object_foreach (obj->e_type, qsql_be->book, check_state,
1224 &qb);
1225 break;
1226 }
1227 }
1228 LEAVE (" ");
1229 }
1230
1231 static void
1232 qsql_backend_createdb (QofBackend * be, QofSession * session)
1233 {
1234 FILE *f;
1235 QSQLiteBackend *qsql_be;
1236 struct QsqlBuilder qb;
1237
1238 g_return_if_fail (be || session);
1239 ENTER (" ");
1240 qsql_be = (QSQLiteBackend *) be;
1241 qsql_be->stm_type = SQL_CREATE;
1242 qb.qsql_be = qsql_be;
1243 qsql_be->book = qof_session_get_book (session);
1244 DEBUG (" create_file %s", qsql_be->fullpath);
1245 f = fopen (qsql_be->fullpath, "a+");
1246 if (f)
1247 fclose (f);
1248 else
1249 {
1250 qof_error_set (session, qof_error_register
1251 (_("Unable to open the output file '%s' - do you have "
1252 "permission to create this file?"), TRUE));
1253 qsql_be->error = TRUE;
1254 LEAVE (" unable to create new file '%s'", qsql_be->fullpath);
1255 return;
1256 }
1257 qsql_be->sqliteh =
1258 sqlite_open (qsql_be->fullpath, 0644, &qsql_be->err);
1259 if (!qsql_be->sqliteh)
1260 {
1261 qof_error_set_be (be, qsql_be->err_create);
1262 qsql_be->error = TRUE;
1263 LEAVE (" unable to open sqlite:%s", qsql_be->err);
1264 return;
1265 }
1266 qof_object_foreach_type (qsql_class_foreach, qsql_be);
1267 /* create the KVP table here
1268 preset table name, internal_id, guid_as_string, path, type, value
1269 */
1270 qb.sql_str =
1271 g_strdup_printf ("CREATE TABLE %s (%s, %s, %s, %s, %s, %s",
1272 QSQL_KVP_TABLE, "kvp_id int primary key not null",
1273 "guid char(32)", "path mediumtext", "type mediumtext",
1274 "value text", END_DB_VERSION);
1275 PINFO (" sql=%s", qb.sql_str);
1276 if (sqlite_exec (qsql_be->sqliteh, qb.sql_str,
1277 record_foreach, &qb, &qsql_be->err) != SQLITE_OK)
1278 {
1279 qsql_be->error = TRUE;
1280 PERR (" unable to create kvp table:%s", qsql_be->err);
1281 }
1282 g_free (qb.sql_str);
1283 LEAVE (" ");
1284 }
1285
1286 static void
1287 qsql_backend_opendb (QofBackend * be, QofSession * session)
1288 {
1289 QSQLiteBackend *qsql_be;
1290
1291 g_return_if_fail (be || session);
1292 ENTER (" ");
1293 qsql_be = (QSQLiteBackend *) be;
1294 qsql_be->sqliteh =
1295 sqlite_open (qsql_be->fullpath, 0666, &qsql_be->err);
1296 if (!qsql_be->sqliteh)
1297 {
1298 qof_error_set_be (be, qof_error_register
1299 (_("Unable to open the sqlite database '%s'."), TRUE));
1300 qsql_be->error = TRUE;
1301 PERR (" %s", qsql_be->err);
1302 }
1303 LEAVE (" %s", qsql_be->fullpath);
1304 }
1305
1306 static void
1307 qsqlite_session_begin (QofBackend * be, QofSession * session,
1308 const gchar * book_path, gboolean ignore_lock,
1309 gboolean create_if_nonexistent)
1310 {
1311 QSQLiteBackend *qsql_be;
1312 gchar **pp;
1313 struct stat statinfo;
1314 gint stat_val;
1315
1316 g_return_if_fail (be);
1317 ENTER (" book_path=%s", book_path);
1318 qsql_be = (QSQLiteBackend *) be;
1319 qsql_be->fullpath = NULL;
1320 if (book_path == NULL)
1321 {
1322 qof_error_set_be (be, qof_error_register
1323 (_("Please provide a filename for sqlite."), FALSE));
1324 qsql_be->error = TRUE;
1325 LEAVE (" bad URL");
1326 return;
1327 }
1328 /* book_path => sqlite_file_name */
1329 pp = g_strsplit (book_path, ":", 2);
1330 if (0 == safe_strcmp (pp[0], ACCESS_METHOD))
1331 {
1332 qsql_be->fullpath = g_strdup (pp[1]);
1333 g_strfreev (pp);
1334 }
1335 else
1336 qsql_be->fullpath = g_strdup (book_path);
1337 be->fullpath = g_strdup (qsql_be->fullpath);
1338 PINFO (" final path = %s", qsql_be->fullpath);
1339 stat_val = g_stat (qsql_be->fullpath, &statinfo);
1340 if (!S_ISREG (statinfo.st_mode) || statinfo.st_size == 0)
1341 qsql_backend_createdb (be, session);
1342 if (!qsql_be->error)
1343 qsql_backend_opendb (be, session);
1344 if (qof_error_check_be (be) || qsql_be->error)
1345 {
1346 LEAVE (" open failed");
1347 return;
1348 }
1349 qsql_be->create_handler =
1350 qof_event_register_handler (create_event, qsql_be);
1351 qsql_be->delete_handler =
1352 qof_event_register_handler (delete_event, qsql_be);
1353 LEAVE (" db=%s", qsql_be->fullpath);
1354 }
1355
1356 static void
1357 qsqlite_db_load (QofBackend * be, QofBook * book)
1358 {
1359 QSQLiteBackend *qsql_be;
1360
1361 g_return_if_fail (be);
1362 ENTER (" ");
1363 loading = TRUE;
1364 qsql_be = (QSQLiteBackend *) be;
1365 qsql_be->stm_type = SQL_LOAD;
1366 qsql_be->book = book;
1367 /* iterate over registered objects */
1368 qof_object_foreach_type (qsql_class_foreach, qsql_be);
1369 qsql_load_kvp (qsql_be);
1370 loading = FALSE;
1371 LEAVE (" ");
1372 }
1373
1374 static void
1375 qsqlite_write_db (QofBackend * be, QofBook * book)
1376 {
1377 QSQLiteBackend *qsql_be;
1378
1379 g_return_if_fail (be);
1380 qsql_be = (QSQLiteBackend *) be;
1381 qsql_be->stm_type = SQL_WRITE;
1382 qsql_be->book = book;
1383 /* update each record with current state */
1384 qof_object_foreach_type (qsql_class_foreach, qsql_be);
1385 /* update KVP */
1386 }
1387
1388 static gboolean
1389 qsql_determine_file_type (const gchar * path)
1390 {
1391 if (!path)
1392 return FALSE;
1393 return TRUE;
1394 }
1395
1396 static void
1397 qsqlite_session_end (QofBackend * be)
1398 {
1399 QSQLiteBackend *qsql_be;
1400
1401 g_return_if_fail (be);
1402 qsql_be = (QSQLiteBackend *) be;
1403 if (qsql_be->sqliteh)
1404 sqlite_close (qsql_be->sqliteh);
1405 }
1406
1407 static void
1408 qsqlite_destroy_backend (QofBackend * be)
1409 {
1410 QSQLiteBackend *qsql_be;
1411
1412 g_return_if_fail (be);
1413 qsql_be = (QSQLiteBackend *) be;
1414 g_hash_table_destroy (qsql_be->kvp_table);
1415 g_hash_table_destroy (qsql_be->kvp_id);
1416 qof_event_unregister_handler (qsql_be->create_handler);
1417 qof_event_unregister_handler (qsql_be->delete_handler);
1418 g_free (be);
1419 g_free (qsql_be);
1420 }
1421
1422 static void
1423 qsql_provider_free (QofBackendProvider * prov)
1424 {
1425 prov->provider_name = NULL;
1426 prov->access_method = NULL;
1427 g_free (prov);
1428 }
1429
1445 static QofBackend *
1446 qsql_backend_new (void)
1447 {
1448 QSQLiteBackend *qsql_be;
1449 QofBackend *be;
1450
1451 ENTER (" ");
1452 qsql_be = g_new0 (QSQLiteBackend, 1);
1453 be = (QofBackend *) qsql_be;
1454 qof_backend_init (be);
1455 qsql_be->kvp_table = g_hash_table_new (g_str_hash, g_str_equal);
1456 qsql_be->kvp_id = g_hash_table_new (g_str_hash, g_str_equal);
1457 qsql_be->dbversion = QOF_OBJECT_VERSION;
1458 qsql_be->stm_type = SQL_NONE;
1459 qsql_be->err_delete =
1460 qof_error_register (_("Unable to delete record."), FALSE);
1461 qsql_be->err_create =
1462 qof_error_register (_("Unable to create record."), FALSE);
1463 qsql_be->err_insert =
1464 qof_error_register (_("Unable to insert a new record."), FALSE);
1465 qsql_be->err_update =
1466 qof_error_register (_("Unable to update existing record."), FALSE);
1467 be->session_begin = qsqlite_session_begin;
1468
1469 be->session_end = qsqlite_session_end;
1470 be->destroy_backend = qsqlite_destroy_backend;
1471 be->load = qsqlite_db_load;
1472 be->save_may_clobber_data = NULL;
1473 /* begin: create an empty entity if none exists,
1474 even if events are suspended. */
1475 be->begin = qsql_create;
1476 /* commit: write to sqlite, commit undo record. */
1477 be->commit = qsql_modify;
1478 be->rollback = NULL;
1479 /* would need a QofQuery back to QofSqlQuery conversion. */
1480 be->compile_query = NULL;
1481 /* unused */
1482 be->free_query = NULL;
1483 be->run_query = NULL;
1484 be->counter = NULL;
1485 /* The QOF SQLite backend is not multi-user - all QOF users are the same. */
1486 be->events_pending = NULL;
1487 be->process_events = NULL;
1488
1489 be->sync = qsqlite_write_db;
1490 be->load_config = NULL;
1491 be->get_config = NULL;
1492 LEAVE (" ");
1493 return be;
1494 }
1495
1496 void
1497 qof_sqlite_provider_init (void)
1498 {
1499 QofBackendProvider *prov;
1500
1501 ENTER (" ");
1502 bindtextdomain (PACKAGE, LOCALE_DIR);
1503 prov = g_new0 (QofBackendProvider, 1);
1504 prov->provider_name = "QOF SQLite Backend Version 0.3";
1505 prov->access_method = ACCESS_METHOD;
1506 prov->partial_book_supported = TRUE;
1507 prov->backend_new = qsql_backend_new;
1508 prov->check_data_type = qsql_determine_file_type;
1509 prov->provider_free = qsql_provider_free;
1510 qof_backend_register_provider (prov);
1511 LEAVE (" ");
1512 }
1513
1514 /* ================= END OF FILE =================== */
KVP_TYPE_TIMESPEC
Definition: kvpframe.h:121
QOF_TYPE_DATE
#define QOF_TYPE_DATE
Definition: deprecated.h:336
qof_sqlite_provider_init
void qof_sqlite_provider_init(void)
Initialises the SQLite backend.
Definition: qof-sqlite.c:1497
SQL_UPDATE
Definition: qof-sqlite.c:73
QOF_DATE_FORMAT_UTC
#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
qof_error_register
QofErrorId qof_error_register(const gchar *err_message, gboolean use_file)
Generate and register a new error.
Definition: qoferror.c:91
QofBackend_s::fullpath
gchar * fullpath
Definition: qofbackend-p.h:338
QofBackend_s::save_may_clobber_data
gboolean(* save_may_clobber_data)(QofBackend *)
Definition: qofbackend-p.h:320
PERR
#define PERR(format, args...)
Definition: qoflog.h:183
qof_object_new_instance
gpointer qof_object_new_instance(QofIdTypeConst type_name, QofBook *book)
Definition: qofobject.c:42
QOF_TYPE_COLLECT
#define QOF_TYPE_COLLECT
Definition: qofclass.h:93
string_to_kvp_value
KvpValue * string_to_kvp_value(const gchar *content, KvpValueType type)
Convert a string value into KvpValue.
Definition: qof-sqlite.c:223
QofIdType
const gchar * QofIdType
Definition: qofid.h:81
QSQL_KVP_TABLE
#define QSQL_KVP_TABLE
Definition: qof-sqlite.c:51
PINFO
#define PINFO(format, args...)
Definition: qoflog.h:199
QofInstance_s
Definition: qofinstance-p.h:35
qof_class_is_registered
gboolean qof_class_is_registered(QofIdTypeConst obj_name)
Definition: qofclass.c:132
qof_date_free
void qof_date_free(QofDate *date)
Definition: qofdate.c:608
qof_class_param_foreach
void qof_class_param_foreach(QofIdTypeConst obj_name, QofParamForeachCB cb, gpointer user_data)
Definition: qofclass.c:267
qof_backend_register_provider
void qof_backend_register_provider(QofBackendProvider *)
Definition: qofsession.c:59
SQL_NONE
Definition: qof-sqlite.c:61
_QofParam
Definition: qofclass.h:195
QOF_UTC_DATE_FORMAT
#define QOF_UTC_DATE_FORMAT
UTC date format string.
Definition: qofdate.h:244
QOF_OBJECT_VERSION
#define QOF_OBJECT_VERSION
Definition: qofobject.h:57
build_kvp_table
static gint build_kvp_table(gpointer builder, gint col_num, gchar **strings, gchar **columnNames)
chekc kvp data once per record
Definition: qof-sqlite.c:1076
_QofSession
Definition: qofsession-p.h:35
QofBackendProvider_s
Definition: qofbackend-p.h:238
guid_malloc
GUID * guid_malloc(void)
Definition: guid.c:100
KvpValueType
KvpValueType
possible types in the union KvpValue
Definition: kvpframe.h:87
QofEntity_s
Definition: qofid.h:147
qof_object_foreach
void qof_object_foreach(QofIdTypeConst type_name, QofBook *book, QofEntityForeachCB cb, gpointer user_data)
Definition: qofobject.c:174
kvpvalue_to_sql
static void kvpvalue_to_sql(const gchar *key, KvpValue *val, gpointer builder)
Definition: qof-sqlite.c:316
QOF_EVENT_DESTROY
#define QOF_EVENT_DESTROY
Definition: qofevent.h:81
string_to_guid
gboolean string_to_guid(const gchar *string, GUID *guid)
KVP_TYPE_GUID
Unique identifier.
Definition: kvpframe.h:118
qsql_class_foreach
static void qsql_class_foreach(QofObject *obj, gpointer data)
Definition: qof-sqlite.c:1168
QofBackendProvider_s::partial_book_supported
gboolean partial_book_supported
Partial QofBook handler.
Definition: qofbackend-p.h:254
QofErrorId
gint32 QofErrorId
The ID of this error.
Definition: qofbackend.h:54
KvpFrame
struct _KvpFrame KvpFrame
Definition: kvpframe.h:74
delete_event
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:499
timespec64
Definition: qoftime.h:97
kvp_value_new_boolean
KvpValue * kvp_value_new_boolean(gboolean value)
Definition: kvpframe.c:1226
kvp_value_to_qof_type_helper
static QofIdTypeConst kvp_value_to_qof_type_helper(KvpValueType n)
Map a KvpValue to a QofIdType.
Definition: qof-sqlite.c:145
qof_error_check_be
QofErrorId qof_error_check_be(QofBackend *be)
Check for errors.
Definition: qoferror.c:234
KVP_TYPE_FRAME
Definition: kvpframe.h:134
qof_util_bool_to_int
gint qof_util_bool_to_int(const gchar *val)
Definition: qofutil.c:249
create_param_list
static void create_param_list(QofParam *param, gpointer builder)
list just the parameter names
Definition: qof-sqlite.c:419
LEAVE
#define LEAVE(format, args...)
Definition: qoflog.h:227
GUID_ENCODING_LENGTH
#define GUID_ENCODING_LENGTH
Definition: guid.h:64
qsql_load_kvp
static void qsql_load_kvp(QSQLiteBackend *qsql_be)
Definition: qof-sqlite.c:1127
qof_date_to_qtime
QofTime * qof_date_to_qtime(const QofDate *qd)
Definition: qofdate.c:892
QofDate_s
Full range replacement for struct tm.
Definition: qofdate.h:138
kvp_frame_set_value
KvpFrame * kvp_frame_set_value(KvpFrame *frame, const gchar *key_path, const KvpValue *value)
Copy the KvpValue into the frame.
Definition: kvpframe.c:499
KVP_TYPE_NUMERIC
128bit denominator/numerator maths.
Definition: kvpframe.h:106
create_each_param
static void create_each_param(QofParam *param, gpointer builder)
Definition: qof-sqlite.c:447
qof_class_get_parameter
const QofParam * qof_class_get_parameter(QofIdTypeConst obj_name, const gchar *parameter)
Definition: qofclass.c:146
QOF_EVENT_CREATE
#define QOF_EVENT_CREATE
Definition: qofevent.h:71
qof_event_register_handler
gint qof_event_register_handler(QofEventHandler handler, gpointer user_data)
Register a handler for events.
Definition: qofevent.c:108
qof_instance_get_guid
const GUID * qof_instance_get_guid(QofInstance *inst)
Definition: qofinstance.c:79
qof_date_parse
QofDate * qof_date_parse(const gchar *str, QofDateFormat df)
Convert a timestamp to a QofTime.
Definition: qofdate.c:525
KvpValue
struct _KvpValue KvpValue
Definition: kvpframe.h:78
SQL_CREATE
Definition: qof-sqlite.c:63
create_event
static void create_event(QofEntity *ent, QofEventId event_type, gpointer handler_data, gpointer event_data)
Definition: qof-sqlite.c:548
kvp_value_new_timespec
KvpValue * kvp_value_new_timespec(Timespec timespec)
Definition: deprecated.c:1482
sql_to_kvp_helper
static KvpValueType sql_to_kvp_helper(const gchar *type_string)
Definition: qof-sqlite.c:200
qof_instance_get_slots
KvpFrame * qof_instance_get_slots(QofInstance *inst)
Definition: qofinstance.c:95
qof_error_set
void qof_error_set(QofSession *session, QofErrorId error)
Add an error to the stack for this session.
Definition: qoferror.c:133
QofEventId
gint QofEventId
Definition: qofevent.h:40
qof_backend_init
void qof_backend_init(QofBackend *be)
Definition: qofbackend.c:37
timespecFromTime_t
void timespecFromTime_t(Timespec *ts, time_t t)
Definition: deprecated.c:304
qof_numeric_from_string
gboolean qof_numeric_from_string(const gchar *str, QofNumeric *n)
Definition: qofnumeric.c:1121
qof_book_not_saved
gboolean qof_book_not_saved(QofBook *book)
Definition: qofbook.c:135
record_foreach
static gint record_foreach(gpointer builder, gint col_num, gchar **strings, gchar **columnNames)
Definition: qof-sqlite.c:713
qof_time_free
void qof_time_free(QofTime *qt)
Free a QofTime when no longer required.
Definition: qoftime.c:56
KVP_TYPE_GINT64
64bit integer
Definition: kvpframe.h:94
_QofObject
Definition: qofobject.h:70
QofBackendProvider_s::provider_free
void(* provider_free)(QofBackendProvider *)
Definition: qofbackend-p.h:280
_QofNumeric
Definition: qofnumeric.h:52
DEBUG
#define DEBUG(format, args...)
Definition: qoflog.h:208
SQL_INSERT
Definition: qof-sqlite.c:69
QofBackendProvider_s::backend_new
QofBackend *(* backend_new)(void)
Definition: qofbackend-p.h:260
qof_util_param_to_string
gchar * qof_util_param_to_string(QofEntity *ent, const QofParam *param)
Converts a parameter to a string for storage or display.
Definition: qofutil.c:447
qof_event_unregister_handler
void qof_event_unregister_handler(gint handler_id)
Unregister an event handler.
Definition: qofevent.c:139
guid_to_string_buff
gchar * guid_to_string_buff(const GUID *guid, gchar *buff)
kvp_value_to_bare_string
gchar * kvp_value_to_bare_string(const KvpValue *val)
General purpose function to convert any KvpValue to a string.
Definition: kvpframe.c:1848
qof_util_param_set_string
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:644
QofInstance_s::entity
QofEntity entity
Definition: qofinstance-p.h:38
qof_class_get_referenceList
GList * qof_class_get_referenceList(QofIdTypeConst type)
List of the parameters that could be references.
Definition: qofclass.c:332
QofBackendProvider_s::access_method
const gchar * access_method
Definition: qofbackend-p.h:247
kvp_frame_for_each_slot
void kvp_frame_for_each_slot(KvpFrame *f, KvpValueForeachCB proc, gpointer data)
Definition: kvpframe.c:1650
SQL_DELETE
Definition: qof-sqlite.c:71
_GUID
Definition: guid.h:53
QsqlStatementType
QsqlStatementType
Definition: qof-sqlite.c:58
QofBackendProvider_s::check_data_type
gboolean(* check_data_type)(const gchar *)
Distinguish two providers with same access method.
Definition: qofbackend-p.h:277
QofIdTypeConst
const gchar * QofIdTypeConst
Definition: qofid.h:83
SQL_LOAD
Definition: qof-sqlite.c:65
QofTime
struct QofTime64 QofTime
Use a 64-bit signed int QofTime.
Definition: qoftime.h:120
qof_event_suspend
void qof_event_suspend(void)
Suspend all engine events.
Definition: qofevent.c:189
KVP_TYPE_BOOLEAN
Simple boolean type.
Definition: kvpframe.h:140
qof_entity_get_guid
const GUID * qof_entity_get_guid(QofEntity *ent)
Definition: qofid.c:105
qof_event_resume
void qof_event_resume(void)
Definition: qofevent.c:200
KVP_TYPE_STRING
standard C string
Definition: kvpframe.h:112
qof_entity_set_guid
void qof_entity_set_guid(QofEntity *ent, const GUID *guid)
Definition: qofid.c:92
qsql_backend_new
static QofBackend * qsql_backend_new(void)
Starts the backend and creates the context.
Definition: qof-sqlite.c:1446
_QofBook
Definition: qofbook-p.h:48
kvp_frame_new
KvpFrame * kvp_frame_new(void)
Definition: kvpframe.c:100
safe_strcmp
gint safe_strcmp(const gchar *da, const gchar *db)
Definition: qofutil.c:72
kvp_value_get_frame
KvpFrame * kvp_value_get_frame(const KvpValue *value)
Definition: kvpframe.c:1549
QofInstance_s::param
const QofParam * param
Definition: qofinstance-p.h:52
KVP_TYPE_DOUBLE
standard C double type
Definition: kvpframe.h:100
QofBackendProvider_s::provider_name
const gchar * provider_name
Definition: qofbackend-p.h:241
SQL_WRITE
Definition: qof-sqlite.c:67
qof_error_get_message_be
const gchar * qof_error_get_message_be(QofBackend *be)
Pop the most recent error and get the message.
Definition: qoferror.c:364
ENTER
#define ENTER(format, args...)
Definition: qoflog.h:217
qof_object_foreach_type
void qof_object_foreach_type(QofForeachTypeCB cb, gpointer user_data)
Definition: qofobject.c:140
QofBackend_s
Definition: qofbackend-p.h:283
QofLogModule
const gchar * QofLogModule
Definition: qofid.h:85
KVP_TYPE_TIME
64bit time/date handling.
Definition: kvpframe.h:128
QSQL_ERROR
#define QSQL_ERROR
Definition: qof-sqlite.c:49