2 #include "stuffkeeper-data-schema.h"
3 #include "stuffkeeper-data-item.h"
4 #include "stuffkeeper-data-tag.h"
5 #include "stuffkeeper-data-item-search.h"
9 #include <glib/gstdio.h>
16 #define DB_VERSION 0.06
20 class Stuffkeeper:Data:Backend from G:Object
25 /* A hash list used to store the items, the item id is the hash key */
26 private GHashTable *schemas = {g_hash_table_new_full(g_int_hash, g_int_equal,g_free, g_object_unref)} ;
28 /* A hash list used to store the tags, the tags id is the hash key */
29 private GHashTable *tags = {g_hash_table_new_full(g_int_hash, g_int_equal,g_free, g_object_unref)} ;
31 /* A hash list used to store the items, the item id is the hash key */
32 private GHashTable *items = {g_hash_table_new_full(g_int_hash, g_int_equal,g_free, g_object_unref)} ;
34 /* A hash list used to store the searches, the item id is the hash key */
35 private GHashTable *searches = {g_hash_table_new_full(g_int_hash, g_int_equal,g_free, g_object_unref)} ;
37 /* The path this "db" resides */
38 private gchar *path = {NULL} destroywith g_free;
41 private sqlite3 *sqlHandle = {NULL};
42 private gint transaction = {0};
45 private gboolean locked = {FALSE};
46 property BOOLEAN locked
48 blurb = "Lock the database, all clients need to check this.",
49 default_value = FALSE,
60 signal last NONE (STRING,POINTER)
62 search_changed(self,const SearchField *field, StuffkeeperDataItemSearch *search)
68 signal last NONE (POINTER)
70 search_added(self, StuffkeeperDataItemSearch *search)
72 g_signal_connect_swapped(G_OBJECT(search), "search-changed", G_CALLBACK(self_search_changed), self);
76 signal last NONE (INT)
78 search_removed(self, gint id)
87 signal last NONE (STRING,POINTER)
89 item_changed(self, const gchar *field,StuffkeeperDataItem *item)
94 signal last NONE (POINTER)
96 item_added(self, StuffkeeperDataItem *item)
98 g_signal_connect_swapped(G_OBJECT(item), "item-changed", G_CALLBACK(self_item_changed), self);
103 signal last NONE (INT)
105 item_removed(self, gint id)
111 signal last NONE (POINTER)
113 schema_changed(self, StuffkeeperDataSchema *schema)
118 signal last NONE (POINTER)
120 schema_added(self, StuffkeeperDataSchema *schema)
122 g_signal_connect_swapped(G_OBJECT(schema), "schema-changed", G_CALLBACK(self_schema_changed), self);
125 signal last NONE (INT)
127 schema_removed(self, gint id)
134 StuffkeeperDataItemSearch *
138 StuffkeeperDataItemSearch *search = stuffkeeper_data_item_search_new(G_OBJECT(self));
139 /* We have a valid id now, so add it */
140 /* Add to the list */
141 ide = g_malloc0(sizeof(gint));
142 *ide = stuffkeeper_data_item_search_get_id(search);
143 g_hash_table_insert(self->_priv->searches,ide, search);
144 self_search_added(self, search);
149 remove_search(self, gint id)
151 StuffkeeperDataItemSearch *search = self_get_search(self, id);
154 self_search_removed(self,id);
157 stuffkeeper_data_item_search_delete_yourself(search);
160 if(g_hash_table_remove(self->_priv->searches, &id) == FALSE)
171 return g_hash_table_get_values(self->_priv->searches);
176 get_num_searches(self)
178 return g_hash_table_size(self->_priv->searches);
183 StuffkeeperDataItemSearch *
184 get_search(self, gint id)
186 StuffkeeperDataItemSearch *item;
187 item = g_hash_table_lookup(self->_priv->searches, &id);
198 return g_hash_table_get_values(self->_priv->items);
205 return g_hash_table_size(self->_priv->items);
210 StuffkeeperDataItem *
211 get_item(self, gint id)
213 StuffkeeperDataItem *item;
214 item = g_hash_table_lookup(self->_priv->items, &id);
219 StuffkeeperDataItem *
220 new_item(self,StuffkeeperDataSchema *schema)
223 StuffkeeperDataItem *item;
224 gchar *path = g_build_path(G_DIR_SEPARATOR_S, self->_priv->path, "items", NULL);
225 /* create a new item */
226 item = stuffkeeper_data_item_new(self,schema);
228 /* want to copy the key, even if it is an integer */
229 id = g_malloc0(sizeof(gint));
230 *id = stuffkeeper_data_item_get_id(item);
231 /* insert it into my hash-list */
232 g_hash_table_insert(self->_priv->items,id, item);
233 self_item_added(self, item);
237 public StuffkeeperDataItem *clone_item(self,
238 Stuffkeeper:Data:Item *orig_item (check null type))
241 StuffkeeperDataItem *item;
242 /* create a new item */
243 /* TODO: Could be a bug here: if we have multipile backends at some
244 * point, the item we clone might not even belong to this backend,
245 * the right way to fix this would be to have the new items signal the
246 * backend when they are created */
247 item = stuffkeeper_data_item_new_clone(orig_item);
248 /* want to copy the key, even if it is an integer */
249 id = g_malloc0(sizeof(gint));
250 *id = stuffkeeper_data_item_get_id(item);
251 /* insert it into my hash-list */
252 g_hash_table_insert(self->_priv->items,id, item);
253 self_item_added(self, item);
259 remove_item(self, gint id)
261 StuffkeeperDataItem *item = g_hash_table_lookup(self->_priv->items, &id);
262 self_item_removed(self, id);
265 stuffkeeper_data_item_delete_yourself(item);
267 if(g_hash_table_remove(self->_priv->items, &id) == FALSE)
278 if(self->_priv->items)
280 g_hash_table_foreach(self->_priv->items, (GHFunc)self_iterate_remove_item, self);
281 g_hash_table_remove_all(self->_priv->items);
283 if(self->_priv->tags)
285 g_hash_table_foreach(self->_priv->tags, (GHFunc)self_iterate_remove_tag, self);
286 g_hash_table_remove_all(self->_priv->tags);
288 if(self->_priv->schemas)
290 g_hash_table_foreach(self->_priv->schemas, (GHFunc)self_iterate_remove_schema, self);
291 g_hash_table_remove_all(self->_priv->schemas);
293 if(self->_priv->searches)
295 g_hash_table_foreach(self->_priv->searches, (GHFunc)self_iterate_remove_search, self);
296 g_hash_table_remove_all(self->_priv->searches);
303 /* close the open db */
304 if(self->_priv->sqlHandle)
306 int retv = sqlite3_close(self->_priv->sqlHandle);
307 if(retv != SQLITE_OK)
309 printf("The following error occured while trying to close the db: %s\n",
310 sqlite3_errmsg(self->_priv->sqlHandle));
313 self->_priv->sqlHandle = NULL;
314 g_free(self->_priv->path);
315 self->_priv->path = NULL;
322 load(self, const gchar *db_path)
334 /* check if there is allready data active */
335 if(self->_priv->path)
337 self_close_yourself(self);
341 * Store the path in the backend.
343 self->_priv->path = g_strdup(db_path);
348 path = g_build_path(G_DIR_SEPARATOR_S, self->_priv->path,"database.sqlite3",NULL);
350 retv = sqlite3_open(path, &(self->_priv->sqlHandle));
351 if(retv != SQLITE_OK)
353 g_error("Failed to open the db: %s because of '%s'", path, sqlite3_errmsg(self->_priv->sqlHandle));
358 * Do integrety check, if failed, bail out
360 r = sqlite3_prepare_v2(self->_priv->sqlHandle, "PRAGMA integrety_check;", -1, &stmt, &tail);
363 g_error("Failed: %s\n", sqlite3_errmsg(self->_priv->sqlHandle));
367 r = sqlite3_step(stmt);
368 while(r == SQLITE_ROW || r == SQLITE_BUSY)
370 if(r == SQLITE_ROW) {
371 const gchar *value = (const gchar *)sqlite3_column_text(stmt, 0);
372 if(strcmp(value, "ok") != 0){
373 g_error("%s: Sqlite database integrety check failed: %s\n",
380 sqlite3_finalize(stmt);
381 g_debug("Database integrety_check: ok");
384 r = sqlite3_prepare_v2(self->_priv->sqlHandle, "PRAGMA synchronous = 0;", -1, &stmt, &tail);
386 r = sqlite3_step(stmt);
387 }while(r == SQLITE_BUSY);
388 if(r != SQLITE_DONE) {
389 g_error("%s: sqlite3_step() failed: %s",__FUNCTION__,
390 sqlite3_errmsg(self->_priv->sqlHandle));
392 sqlite3_finalize(stmt);
393 g_debug("Database synchronious transactions: ok");
395 self_check_sqlite_db(self);
399 path = g_build_path(G_DIR_SEPARATOR_S, self->_priv->path,"images",NULL);
400 if(!g_file_test(path, G_FILE_TEST_IS_DIR))
410 TOC("time elapsed open & check db");
418 query = sqlite3_mprintf("SELECT SchemaId FROM Schemas WHERE type=%i",DB_SCHEMAS_TYPE_ID);
419 r = sqlite3_prepare_v2(self->_priv->sqlHandle, query, -1, &stmt, &tail);
423 printf("Failed: %s\n", sqlite3_errmsg(self->_priv->sqlHandle));
427 while((r = sqlite3_step(stmt)) == SQLITE_ROW)
429 gint oid = sqlite3_column_int(stmt, 0);
430 StuffkeeperDataSchema *schema;
432 /* create a new item */
433 schema = stuffkeeper_data_schema_open_from_id(self, oid);
434 /* want to copy the key, even if it is an integer */
435 id = g_malloc0(sizeof(gint));
437 /* insert it into my hash-list */
438 g_hash_table_insert(self->_priv->schemas,id,schema);
439 self_schema_added(self,schema);
442 sqlite3_finalize(stmt);
443 TOC("time elapsed open schemas");
448 query = "SELECT SearchID FROM SearchFields GROUP by SearchID";
449 r = sqlite3_prepare_v2(self->_priv->sqlHandle, query, -1, &stmt, &tail);
452 printf("Failed: %s\n", sqlite3_errmsg(self->_priv->sqlHandle));
456 while((r = sqlite3_step(stmt)) == SQLITE_ROW)
458 gint oid = sqlite3_column_int(stmt, 0);
459 StuffkeeperDataItemSearch *search;
461 /* create a new item */
462 search = (StuffkeeperDataItemSearch *) stuffkeeper_data_item_search_open_from_id(G_OBJECT(self), oid);
463 /* want to copy the key, even if it is an integer */
464 id = g_malloc0(sizeof(gint));
466 /* insert it into my hash-list */
467 g_hash_table_insert(self->_priv->searches,id, search);
468 self_search_added(self, search);
471 sqlite3_finalize(stmt);
473 TOC("time elapsed open searches");
478 query = "SELECT id FROM Tags";
479 r = sqlite3_prepare_v2(self->_priv->sqlHandle, query, -1, &stmt, &tail);
482 printf("Failed: %s\n", sqlite3_errmsg(self->_priv->sqlHandle));
486 while((r = sqlite3_step(stmt)) == SQLITE_ROW)
488 gint oid = sqlite3_column_int(stmt, 0);
489 StuffkeeperDataTag *tag;
491 /* create a new item */
492 tag = stuffkeeper_data_tag_open_from_id(self, oid);
493 /* want to copy the key, even if it is an integer */
494 id = g_malloc0(sizeof(gint));
496 /* insert it into my hash-list */
497 g_hash_table_insert(self->_priv->tags,id, tag);
498 self_tag_added(self, tag);
501 sqlite3_finalize(stmt);
503 TOC("time elapsed open tags");
508 /* also get schemaid, saves an extra N extra queries */
509 query = sqlite3_mprintf("SELECT ItemId,value FROM Items WHERE type=%i",DB_ITEMS_TYPE_SCHEMA);
510 r = sqlite3_prepare_v2(self->_priv->sqlHandle, query, -1, &stmt, &tail);
514 printf("Failed: %s\n", sqlite3_errmsg(self->_priv->sqlHandle));
518 while((r = sqlite3_step(stmt)) == SQLITE_ROW)
520 gint oid = sqlite3_column_int(stmt, 0);
521 int schemaid = sqlite3_column_int(stmt, 1);
522 StuffkeeperDataItem *item;
524 /* create a new item */
525 item = stuffkeeper_data_item_open_from_id(self,oid,schemaid);
526 /* want to copy the key, even if it is an integer */
527 id = g_malloc0(sizeof(gint));
529 /* insert it into my hash-list */
530 g_hash_table_insert(self->_priv->items,id,item);
531 self_item_added(self,item);
534 sqlite3_finalize(stmt);
536 TOC("time elapsed open items");
540 * Handle destroying of the object
544 iterate_remove_schema(gint *key, StuffkeeperDataSchema *schema, Self *self)
546 self_schema_removed(self, *key);
550 iterate_remove_item(gint *key, StuffkeeperDataItem *item, Self *self )
552 self_item_removed(self, *key);
556 iterate_remove_tag(gint *key, StuffkeeperDataTag *tag, Self *self)
558 self_tag_removed(self, *key);
562 iterate_remove_search(gint *key, StuffkeeperDataItemSearch *search, Self *self)
564 self_search_removed(self, *key);
571 finalize (G:Object *obj)
573 Self *self = SELF(obj);
575 if(self->_priv->items)
577 g_hash_table_destroy(self->_priv->items);
578 self->_priv->items = NULL;
580 if(self->_priv->tags)
582 g_hash_table_destroy(self->_priv->tags);
583 self->_priv->tags = NULL;
585 if(self->_priv->schemas)
587 g_hash_table_destroy(self->_priv->schemas);
588 self->_priv->schemas = NULL;
590 if(self->_priv->searches)
592 g_hash_table_destroy(self->_priv->searches);
593 self->_priv->searches = NULL;
603 if(self->_priv->sqlHandle)
606 printf("%i Rows modified.\n", sqlite3_total_changes(self->_priv->sqlHandle));
607 retv = sqlite3_close(self->_priv->sqlHandle);
608 if(retv != SQLITE_OK)
610 g_debug("The following error occured while trying to close the db: %s\n",
611 sqlite3_errmsg(self->_priv->sqlHandle));
613 /* set pointer to NULL */
614 self->_priv->sqlHandle = NULL;
621 * Create new StuffkeeperDataBackend
622 * destroy with g_object_unref();
625 StuffkeeperDataBackend *
628 Self *self = GET_NEW;
638 signal last NONE (POINTER)
640 tag_changed(self, StuffkeeperDataTag *tag)
645 signal last NONE (POINTER)
647 tag_added(self, StuffkeeperDataTag *tag)
650 g_signal_connect_swapped(G_OBJECT(tag), "tag-changed", G_CALLBACK(self_tag_changed), self);
654 signal last NONE (INT)
656 tag_removed(self,const int id)
664 StuffkeeperDataSchema*
665 get_schema(self, const int id)
668 StuffkeeperDataSchema *schema;
669 /* Look for existing tag */
670 schema = g_hash_table_lookup(self->_priv->schemas, &id);
675 /* No tag, lets make one. */
676 schema = stuffkeeper_data_schema_new_with_id(self,id);
678 /* Add to the list */
679 ide = g_malloc0(sizeof(gint));
681 g_hash_table_insert(self->_priv->schemas,ide, schema);
683 self_schema_added(self, schema);
690 return g_hash_table_get_values(self->_priv->schemas);
693 StuffkeeperDataSchema *
694 load_from_xml(self, const char *path)
699 StuffkeeperDataSchema *schema = stuffkeeper_data_schema_load_from_xml(self, path);
704 id = stuffkeeper_data_schema_get_id(schema);
705 /* Add to the list */
706 ide = g_malloc0(sizeof(gint));
708 g_hash_table_insert(self->_priv->schemas,ide, schema);
710 self_schema_added(self, schema);
714 StuffkeeperDataSchema *
719 StuffkeeperDataSchema *schema;
722 /* No schema, lets make one. */
723 schema = stuffkeeper_data_schema_new(self);
724 id = stuffkeeper_data_schema_get_id(schema);
725 /* Add to the list */
726 ide = g_malloc0(sizeof(gint));
728 g_hash_table_insert(self->_priv->schemas,ide, schema);
730 self_schema_added(self, schema);
735 remove_schema(self, gint id)
737 StuffkeeperDataSchema *schema = self_get_schema(self, id);
739 if(stuffkeeper_data_schema_num_items(schema) >0)
743 self_schema_removed(self,id);
746 stuffkeeper_data_schema_delete_yourself(schema);
749 if(g_hash_table_remove(self->_priv->schemas, &id) == FALSE)
761 * Call this from the item when adding a tag, it will return the tag.
762 * Existing tag if it allready exists
766 add_tag(self, const int id)
769 StuffkeeperDataTag *tag;
770 /* Look for existing tag */
771 tag = g_hash_table_lookup(self->_priv->tags, &id);
776 g_debug("Tag not found, this aint good\n");
777 /* No tag, lets make one, with this id. */
778 tag = stuffkeeper_data_tag_new_with_id(self,id);
780 /* Add to the list */
781 ide = g_malloc0(sizeof(gint));
782 *ide = stuffkeeper_data_tag_get_id(tag);
783 g_hash_table_insert(self->_priv->tags,ide, tag);
785 self_tag_added(self, tag);
792 find_tag(self, const char *tag_name)
796 g_hash_table_iter_init (&iter, self->_priv->tags);
797 while (g_hash_table_iter_next (&iter, &key, &value))
799 /* do something with key and value */
800 StuffkeeperDataTag *tag = (StuffkeeperDataTag *)value;
801 gchar *title = stuffkeeper_data_tag_get_title(tag);
802 if(title && g_utf8_collate(title, tag_name) == 0) {
806 if(title)g_free(title);
813 get_tag(self, const int id)
815 StuffkeeperDataTag *tag;
816 /* Look for existing tag */
817 tag = g_hash_table_lookup(self->_priv->tags, &id);
825 StuffkeeperDataTag *tag = stuffkeeper_data_tag_new(self);
826 /* We have a valid id now, so add it */
827 /* Add to the list */
828 ide = g_malloc0(sizeof(gint));
829 *ide = stuffkeeper_data_tag_get_id(tag);
830 g_hash_table_insert(self->_priv->tags,ide, tag);
831 self_tag_added(self, tag);
839 return g_hash_table_get_values(self->_priv->tags);
844 remove_tag(self, gint id)
846 StuffkeeperDataTag *tag = self_get_tag(self, id);
848 if(stuffkeeper_data_tag_num_items(tag) >0)
852 /* Add extra reference so it does not get destroyed when removed from hash table */
854 g_hash_table_remove(self->_priv->tags, &id);
855 self_tag_removed(self,id);
859 stuffkeeper_data_tag_delete_yourself(tag);
860 /* This should be the last ref and it should be destroyed */
869 return self->_priv->path;
875 /* function checks if all the tables exist */
878 check_sqlite_db(self)
885 /* available tables */
886 gboolean has_general = FALSE;
887 gboolean has_tags = FALSE;
888 gboolean has_schemas = FALSE;
889 gboolean has_schemas_field = FALSE;
890 gboolean has_items = FALSE;
891 gboolean has_items_field = FALSE;
892 gboolean has_search = FALSE;
897 char **resultp = NULL;
899 double version = 0.0;
901 /* Check what tables exists */
902 query = sqlite3_mprintf("select tbl_name from sqlite_master where type='table'");
904 result = sqlite3_get_table(self->_priv->sqlHandle, query, &resultp, &rows, &columns,&error);
905 for (i = 1; i < (rows + 1); i++) {
906 /** Check for availible tables */
907 if (!strcmp(resultp[i], "General")) {
910 else if (!strcmp(resultp[i], "Tags")) {
913 else if (!strcmp(resultp[i], "Schemas")) {
916 else if (!strcmp(resultp[i], "SchemasFields")) {
917 has_schemas_field = TRUE;
919 else if (!strcmp(resultp[i], "Items")) {
922 else if (!strcmp(resultp[i], "ItemsFields")) {
923 has_items_field = TRUE;
925 else if (!strcmp(resultp[i], "SearchFields")) {
930 sqlite3_free_table(resultp);
933 /* if not exists, create the general table */
934 if(G_UNLIKELY(!has_general)) {
935 g_debug("Create general table\n");
937 query = sqlite3_mprintf("CREATE TABLE 'General' ("
938 "'id' INTEGER PRIMARY KEY AUTOINCREMENT," /* not useful, but you want a row id anyway. */
939 "'key' TEXT," /* the key stored in value */
940 "'value' TEXT" /* the value */
943 result = sqlite3_exec(self->_priv->sqlHandle, query, NULL, NULL, &error);
944 if (result != SQLITE_OK) {
945 g_debug("failed: %s\n", error);
948 /* store db version */
949 query = sqlite3_mprintf("INSERT INTO 'General' ('key', 'value') VALUES('%q','%f')","Version", DB_VERSION);
950 result = sqlite3_exec(self->_priv->sqlHandle, query, NULL, NULL, &error);
951 if (result != SQLITE_OK) {
952 g_debug("failed: %s\n", error);
961 if(G_UNLIKELY(!has_tags)) {
962 g_debug("Create Tags table\n");
964 query = sqlite3_mprintf("CREATE TABLE 'Tags' ("
965 "'id' INTEGER PRIMARY KEY AUTOINCREMENT," /* not useful, but you want a row id anyway. */
966 "'mtime' INTEGER," /* the key stored in value */
967 "'name' TEXT" /* the value */
970 result = sqlite3_exec(self->_priv->sqlHandle, query, NULL, NULL, &error);
971 if (result != SQLITE_OK) {
972 g_debug("failed: %s\n", error);
977 if(G_UNLIKELY(!has_schemas)) {
978 g_debug("Create Schemas table\n");
980 query = sqlite3_mprintf("CREATE TABLE 'Schemas' ("
981 "'id' INTEGER PRIMARY KEY AUTOINCREMENT," /* not useful, but you want a row id anyway. */
982 "'SchemaId' INTEGER," /* id of the schema, taken from type=ID */
983 "'type' INTEGER," /* the key stored in value */
984 "'value' TEXT" /* the value */
987 result = sqlite3_exec(self->_priv->sqlHandle, query, NULL, NULL, &error);
988 if (result != SQLITE_OK) {
989 g_debug("failed: %s\n", error);
993 sqlite3_exec(self->_priv->sqlHandle, "CREATE INDEX SchemaId ON Schemas(SchemaId);", NULL, NULL, NULL);
995 if(G_UNLIKELY(!has_schemas_field)) {
996 g_debug("Create SchemasFields table\n");
998 query = sqlite3_mprintf("CREATE TABLE 'SchemasFields' ("
999 "'id' INTEGER PRIMARY KEY AUTOINCREMENT," /* not useful, but you want a row id anyway. */
1000 "'FieldId' INTEGER," /* id of the field, this is taken from the id of type=ID */
1001 "'SchemaId' INTEGER," /* Id of the schema this field belongs too */
1002 "'type' INTEGER," /* the key stored in value */
1003 "'value' TEXT" /* the value */
1006 result = sqlite3_exec(self->_priv->sqlHandle, query, NULL, NULL, &error);
1007 if (result != SQLITE_OK) {
1008 g_debug("failed: %s\n", error);
1010 sqlite3_free(query);
1011 result = sqlite3_exec(self->_priv->sqlHandle, "CREATE INDEX SchemaId2 ON SchemasFields(SchemaId);", NULL, NULL, NULL);
1012 if (result != SQLITE_OK) {
1013 g_debug("failed: %s\n", error);
1018 if(G_UNLIKELY(!has_items)) {
1019 g_debug("Create Items table\n");
1021 query = sqlite3_mprintf("CREATE TABLE 'Items' ("
1022 "'id' INTEGER PRIMARY KEY AUTOINCREMENT," /* not useful, but you want a row id anyway. */
1023 "'ItemId' INTEGER," /* id of the item, taken from type=ID */
1024 "'type' INTEGER," /* the key stored in value */
1025 "'value' TEXT" /* the value */
1028 result = sqlite3_exec(self->_priv->sqlHandle, query, NULL, NULL, &error);
1029 if (result != SQLITE_OK) {
1030 g_debug("failed: %s\n", error);
1032 sqlite3_free(query);
1034 sqlite3_exec(self->_priv->sqlHandle, "CREATE INDEX ItemId ON Items(ItemId);", NULL, NULL, NULL);
1036 if(G_UNLIKELY(!has_items_field)) {
1037 g_debug("Create ItemsFields table\n");
1039 query = sqlite3_mprintf("CREATE TABLE 'ItemsFields' ("
1040 "'id' INTEGER PRIMARY KEY AUTOINCREMENT," /* not useful, but you want a row id anyway. */
1041 "'ItemId' INTEGER," /* id of the field, this is taken from the id of type=ID */
1042 "'FieldId' INTEGER," /* Id of the schema this field belongs too */
1043 "'value' TEXT" /* the value */
1046 result = sqlite3_exec(self->_priv->sqlHandle, query, NULL, NULL, &error);
1047 if (result != SQLITE_OK) {
1048 g_debug("failed: %s\n", error);
1050 sqlite3_free(query);
1051 result = sqlite3_exec(self->_priv->sqlHandle, "CREATE INDEX ItemId2 ON ItemsFields(ItemId);", NULL, NULL, NULL);
1052 if (result != SQLITE_OK) {
1053 g_debug("failed: %s\n", error);
1058 if(G_UNLIKELY(!has_search)) {
1059 g_debug("Create SearchFields table\n");
1061 query = sqlite3_mprintf("CREATE TABLE 'SearchFields' ("
1062 "'id' INTEGER PRIMARY KEY AUTOINCREMENT," /* not useful, but you want a row id anyway. */
1063 "'SearchId' INTEGER," /* id of the field, this is taken from the id of type=ID */
1064 "'SearchType' INTEGER," /* id of the field, this is taken from the id of type=ID */
1065 "'FieldType' INTEGER," /* Id of the schema this field belongs too */
1066 "'value' TEXT" /* the value */
1069 result = sqlite3_exec(self->_priv->sqlHandle, query, NULL, NULL, &error);
1070 if (result != SQLITE_OK) {
1071 g_debug("failed: %s\n", error);
1073 sqlite3_free(query);
1074 result = sqlite3_exec(self->_priv->sqlHandle, "CREATE INDEX SearchId ON SearchFields(SearchId);", NULL, NULL, NULL);
1075 if (result != SQLITE_OK) {
1076 g_debug("failed: %s\n", error);
1084 query = sqlite3_mprintf("SELECT value FROM 'General' WHERE key='Version'");
1085 r = sqlite3_prepare_v2(self->_priv->sqlHandle, query, -1, &stmt, &tail);
1086 sqlite3_free(query);
1089 g_debug("Failed: %s\n", sqlite3_errmsg(self->_priv->sqlHandle));
1093 g_debug("stepping through rows\n");
1094 if((r = sqlite3_step(stmt)) == SQLITE_ROW)
1096 version = sqlite3_column_double(stmt, 0);
1099 sqlite3_finalize(stmt);
1102 printf("Current db version is: %lf\n",version);
1103 if(version != DB_VERSION )
1105 printf("New DB version: %f->%f\n", version, DB_VERSION);
1108 printf("Adding indexes\n");
1109 sqlite3_exec(self->_priv->sqlHandle, "CREATE INDEX SchemaId ON SchemasFields(SchemaId);", NULL, NULL, NULL);
1110 sqlite3_exec(self->_priv->sqlHandle, "CREATE INDEX ItemId ON ItemsFields(ItemId);", NULL, NULL, NULL);
1111 sqlite3_exec(self->_priv->sqlHandle, "CREATE INDEX SearchId ON SearchFields(SearchId);", NULL, NULL, NULL);
1115 sqlite3_exec(self->_priv->sqlHandle, "CREATE INDEX ItemId ON Items(ItemId);", NULL, NULL, NULL);
1116 sqlite3_exec(self->_priv->sqlHandle, "CREATE INDEX SchemaId ON Schemas(SchemaId);", NULL, NULL, NULL);
1119 else if (version <= 0.04)
1121 /* Add the indexes again, sqlite seems to overwrite the values */
1122 sqlite3_exec(self->_priv->sqlHandle, "CREATE INDEX ItemId ON Items(ItemId);", NULL, NULL, NULL);
1123 sqlite3_exec(self->_priv->sqlHandle, "CREATE INDEX ItemId2 ON ItemsFields(ItemId);", NULL, NULL, NULL);
1124 sqlite3_exec(self->_priv->sqlHandle, "CREATE INDEX SchemaId ON Schemas(SchemaId);", NULL, NULL, NULL);
1125 sqlite3_exec(self->_priv->sqlHandle, "CREATE INDEX SchemaId2 ON SchemasFields(SchemaId);", NULL, NULL, NULL);
1126 sqlite3_exec(self->_priv->sqlHandle, "CREATE INDEX SearchId ON SearchFields(SearchId);", NULL, NULL, NULL);
1128 else if (version <= 0.05)
1130 /* Need to update all rich text entries */
1131 self_update_005_db(self);
1134 query = sqlite3_mprintf( "UPDATE 'General' SET value=%f WHERE key='Version'",DB_VERSION);
1135 sqlite3_exec(self->_priv->sqlHandle,query, NULL, NULL, NULL);
1136 sqlite3_free(query);
1145 begin_transaction(self)
1147 if(self->_priv->transaction)
1149 self->_priv->transaction++;
1152 g_debug("begin transaction\n");
1153 sqlite3_exec(self->_priv->sqlHandle, "BEGIN TRANSACTION", NULL, NULL, NULL);
1154 self->_priv->transaction++;
1159 end_transaction(self)
1161 self->_priv->transaction--;
1162 if(self->_priv->transaction)
1164 g_debug("end transaction\n");
1165 sqlite3_exec(self->_priv->sqlHandle, "END TRANSACTION", NULL, NULL, NULL);
1168 /* Return the sqlite3 handle */
1173 return self->_priv->sqlHandle;
1177 private void update_005_db_field(self, int rowid)
1179 GtkTextBuffer *buffer = gtk_text_buffer_new(NULL);
1180 GdkAtom atom = gtk_text_buffer_register_deserialize_tagset (buffer, NULL);
1181 gtk_text_buffer_deserialize_set_can_create_tags (buffer, atom, FALSE);
1185 char *query = sqlite3_mprintf(
1186 "SELECT value FROM ItemsFields "
1190 r = sqlite3_prepare_v2(self->_priv->sqlHandle, query, -1, &stmt, &tail);
1191 sqlite3_free(query);
1192 if((r = sqlite3_step(stmt)) == SQLITE_ROW)
1194 const gchar *value = (const gchar *)sqlite3_column_text(stmt, 0);
1196 if(value != NULL && value[0] != '\0')
1198 guchar *base64 = g_base64_decode(value, &out);
1199 if(base64 && out > 0)
1202 GtkTextIter end,start;
1203 gtk_text_buffer_get_start_iter(buffer, &start);
1205 gboolean result = gtk_text_buffer_deserialize(buffer, buffer, atom,&start,
1210 gtk_text_buffer_get_start_iter(buffer, &start);
1211 gtk_text_buffer_get_end_iter(buffer, &end);
1212 gchar *re = gtk_text_buffer_get_text(buffer,&start,&end, FALSE);
1215 query = sqlite3_mprintf(
1216 "UPDATE ItemsFields "
1217 "SET value=%Q WHERE id=%i",
1221 sqlite3_exec(self->_priv->sqlHandle, query, NULL, NULL, &tail);
1222 printf("%i: Converted from rich to normal\n",rowid);
1224 sqlite3_free(query);
1229 if(base64)g_free(base64);
1232 g_object_unref(buffer);
1233 sqlite3_finalize(stmt);
1242 printf("Start 005 db update\n");
1243 //select itemsfields from itemsfields JOIN schemasfields on Schemasfields.FieldId == Itemsfields.fieldid where schemasfields.type=3 and schemasfields.value=5;
1244 self_begin_transaction(self);
1245 query = sqlite3_mprintf(
1246 "SELECT ItemsFields.ItemId,ItemsFields.id FROM ItemsFields JOIN SchemasFields on SchemasFields.FieldId == ItemsFields.FieldId "
1247 "WHERE SchemasFields.type=%i and SchemasFields.value=%i",
1248 DB_ITEMS_FIELD_TYPE_TYPE, FIELD_TYPE_TEXT
1251 r = sqlite3_prepare_v2(self->_priv->sqlHandle, query, -1, &stmt, &tail);
1252 sqlite3_free(query);
1253 while((r = sqlite3_step(stmt)) == SQLITE_ROW){
1254 int rowid = sqlite3_column_int(stmt, 1);
1255 self_update_005_db_field(self, rowid);
1257 sqlite3_finalize(stmt);
1258 self_end_transaction(self);