diff --git a/src/engine/gnc-pricedb-p.h b/src/engine/gnc-pricedb-p.h index 4db40d29c51..45b6be2e4ef 100644 --- a/src/engine/gnc-pricedb-p.h +++ b/src/engine/gnc-pricedb-p.h @@ -29,6 +29,26 @@ #include "BackendP.h" #include "gnc-pricedb.h" +struct _GNCPrice { + /* 'public' data fields */ + GUID guid; /* globally unique price id */ + GNCPriceDB *db; + gnc_commodity *commodity; + gnc_commodity *currency; + Timespec time; + char *source; + char *type; + gnc_numeric value; + + /* 'private' object management fields */ + guint32 refcount; /* garbage collection reference count */ + gint32 editlevel; /* nesting level of begin/end edit calls */ + gboolean not_saved; /* price edit saved flag */ + gboolean do_free; /* price is going to be destroyed soon */ +}; + + + struct _GNCPriceDB { GHashTable *commodity_hash; Backend *backend; diff --git a/src/engine/gnc-pricedb.c b/src/engine/gnc-pricedb.c index 75dad8eea4a..e59466a4a11 100644 --- a/src/engine/gnc-pricedb.c +++ b/src/engine/gnc-pricedb.c @@ -40,23 +40,6 @@ /* This static indicates the debugging module that this .o belongs to. */ static short module = MOD_ENGINE; -struct _GNCPrice { - /* 'public' data fields */ - GUID guid; /* globally unique price id */ - GNCPriceDB *db; - gnc_commodity *commodity; - gnc_commodity *currency; - Timespec time; - char *source; - char *type; - gnc_numeric value; - - /* 'private' object management fields */ - guint32 refcount; /* garbage collection reference count */ - gint32 editlevel; /* nesting level of begin/end edit calls */ - gboolean not_saved; /* price edit saved flag */ -}; - /* ==================================================================== */ /* GNCPrice functions */ @@ -69,12 +52,26 @@ gnc_price_create() p->refcount = 1; p->editlevel = 0; p->not_saved = FALSE; + p->do_free = FALSE; xaccGUIDNew (&p->guid); xaccStoreEntity(p, &p->guid, GNC_ID_PRICE); gnc_engine_generate_event (&p->guid, GNC_EVENT_CREATE); return p; } +static void +gnc_price_destroy (GNCPrice *p) +{ + gnc_engine_generate_event (&p->guid, GNC_EVENT_DESTROY); + xaccRemoveEntity(&p->guid); + + if(p->type) g_cache_remove(gnc_engine_get_string_cache(), p->type); + if(p->source) g_cache_remove(gnc_engine_get_string_cache(), p->source); + + memset(p, 0, sizeof(GNCPrice)); + g_free(p); +} + void gnc_price_ref(GNCPrice *p) { @@ -87,21 +84,17 @@ gnc_price_unref(GNCPrice *p) { if(!p) return; if(p->refcount == 0) { - PERR("refcount == 0!"); + PERR("refcount == 0 !!!!"); assert(p->refcount != 0); } - if(p->db != NULL && p->refcount == 1) { - PERR("last unref while price in database"); - } + p->refcount--; - if(p->refcount == 0) { - if(p->type) g_cache_remove(gnc_engine_get_string_cache(), p->type); - if(p->source) g_cache_remove(gnc_engine_get_string_cache(), p->source); - gnc_engine_generate_event (&p->guid, GNC_EVENT_DESTROY); - xaccRemoveEntity(&p->guid); - memset(p, 0, sizeof(GNCPrice)); - g_free(p); + if(p->refcount == 0) { + gnc_price_begin_edit (p); + p->do_free = TRUE; + gnc_price_commit_edit (p); + gnc_price_destroy (p); } } @@ -477,7 +470,6 @@ destroy_pricedb_commodity_hash_data(gpointer key, destroy_pricedb_currency_hash_data, NULL); g_hash_table_destroy(currency_hash); - currency_hash = NULL; } gboolean @@ -556,6 +548,7 @@ gnc_pricedb_add_price(GNCPriceDB *db, GNCPrice *p) gboolean gnc_pricedb_remove_price(GNCPriceDB *db, GNCPrice *p) { + guint num_currencies; GList *price_list; gnc_commodity *commodity; gnc_commodity *currency; @@ -577,13 +570,25 @@ gnc_pricedb_remove_price(GNCPriceDB *db, GNCPrice *p) gnc_price_unref(p); return FALSE; } + + /* if the price list is empty, then remove this currency from the commodity hash */ if(price_list) { g_hash_table_insert(currency_hash, currency, price_list); } else { g_hash_table_remove(currency_hash, currency); + + /* chances are good that this commodity had only one currency ... + * if there are no currencies, we may as well destroy the commodity too. */ + num_currencies = g_hash_table_size (currency_hash); + if (0 == num_currencies) { + g_hash_table_remove (db->commodity_hash, commodity); + g_hash_table_destroy (currency_hash); + } } db->dirty = TRUE; - p->db = NULL; + + /* don't set p->db to NULL, we need this pointer to successfully + * invoke the backend to delete the price. */ gnc_price_unref(p); return TRUE; } diff --git a/src/engine/sql/PostgresBackend.c b/src/engine/sql/PostgresBackend.c index df0e6b5bad0..1590e1760f2 100644 --- a/src/engine/sql/PostgresBackend.c +++ b/src/engine/sql/PostgresBackend.c @@ -1676,7 +1676,20 @@ pgend_price_commit_edit (Backend * bend, GNCPrice *pr) /* hack alert -- we should check a version number, to make * sure we aren't clobbering something newer in the database */ - pgendStorePriceNoLock (be, pr); + if (pr->do_free) + { + bufp = be->buff; + bufp = stpcpy (bufp, "DELETE FROM gncPrice WHERE priceGuid='"); + bufp = guid_to_string_buff (gnc_price_get_guid(pr), bufp); + bufp = stpcpy (bufp, "';"); + PINFO ("%s\n", be->buff ? be->buff : "(null)"); + SEND_QUERY (be,be->buff, 444); + FINISH_QUERY(be->connection); + } + else + { + pgendStorePriceNoLock (be, pr); + } bufp = "COMMIT;"; SEND_QUERY (be,bufp,333); diff --git a/src/engine/sql/README b/src/engine/sql/README index f8c4c037f3f..6144691ce35 100644 --- a/src/engine/sql/README +++ b/src/engine/sql/README @@ -165,8 +165,8 @@ Core bugs/features that still need work: -- add support for rlb's price db. Partial support is in place. mass save & restore for mode=single-file is implemented. - To Be Done: price deletion and price queries. - implement pgend_price_commit_edit() + price editing and deletion for mode=single-update is implemented. + To Be Done: price queries. -- error code should include strings passed back, to be shown in GUI dialogs. This is because the backend needs to return things @@ -228,6 +228,9 @@ This list only affects the multi-user and advanced/optional features. -- provide support for more query types in gncquery.c +-- add versioning support for price db. We should add version numbers + to the prices, and check version numbers when updating prices. + -- multi-user 'save-as' is incorrect: As it currently works, save-as (sync) is a mass-copy of all data out of the engine into the named storage location. If the indicated