diff --git a/src/engine/BackendP.h b/src/engine/BackendP.h index 758f0b74b0..8f068fd168 100644 --- a/src/engine/BackendP.h +++ b/src/engine/BackendP.h @@ -48,6 +48,7 @@ #include "Query.h" #include "Transaction.h" #include "gnc-book.h" +#include "gnc-pricedb.h" /* * The book_begin() routine gives the backend a second initialization @@ -157,6 +158,7 @@ struct _backend int (*price_commit_edit) (Backend *, GNCPrice *); void (*run_query) (Backend *, Query *); + void (*price_lookup) (Backend *, GNCPriceLookup *); void (*sync) (Backend *, AccountGroup *); void (*sync_price) (Backend *, GNCPriceDB *); diff --git a/src/engine/NetIO.c b/src/engine/NetIO.c index f6aa511d63..24688f9d35 100644 --- a/src/engine/NetIO.c +++ b/src/engine/NetIO.c @@ -305,6 +305,7 @@ xmlendNew (void) be->be.price_begin_edit = NULL; be->be.price_commit_edit = NULL; be->be.run_query = xmlbeRunQuery; + be->be.price_lookup = NULL; be->be.sync = NULL; be->be.sync_price = NULL; be->be.events_pending = NULL; diff --git a/src/engine/gnc-pricedb-p.h b/src/engine/gnc-pricedb-p.h index 94f18c9d2e..f79902ec11 100644 --- a/src/engine/gnc-pricedb-p.h +++ b/src/engine/gnc-pricedb-p.h @@ -56,6 +56,24 @@ struct _GNCPriceDB { gboolean dirty; }; +/* These structs define the kind of price lookup being done + * so that it can be passed to the backend. This is a rather + * cheesy, low-brow interface. It could stand improvement. + */ +typedef enum { + LOOKUP_LATEST = 1, + LOOKUP_ALL, + LOOKUP_AT_TIME, + LOOKUP_NEAREST_IN_TIME +} PriceLookupType; + + +struct _GNCPriceLookup { + PriceLookupType type; + gnc_commodity *commodity; + gnc_commodity *currency; + Timespec date; +}; void gnc_pricedb_mark_clean(GNCPriceDB *db); void gnc_pricedb_substitute_commodity(GNCPriceDB *db, diff --git a/src/engine/gnc-pricedb.c b/src/engine/gnc-pricedb.c index 33a862d98d..e1019335f0 100644 --- a/src/engine/gnc-pricedb.c +++ b/src/engine/gnc-pricedb.c @@ -372,7 +372,7 @@ gnc_price_get_version(GNCPrice *p) } /* ==================================================================== */ -/* setters */ +/* price list manipulation functions */ static gint compare_prices_by_date(gconstpointer a, gconstpointer b) @@ -624,6 +624,7 @@ gnc_pricedb_remove_price(GNCPriceDB *db, GNCPrice *p) } /* ==================================================================== */ +/* lookup/query functions */ GNCPrice * gnc_pricedb_lookup_latest(GNCPriceDB *db, @@ -636,12 +637,23 @@ gnc_pricedb_lookup_latest(GNCPriceDB *db, if(!db || !commodity || !currency) return NULL; + if (db->backend && db->backend->price_lookup) + { + GNCPriceLookup pl; + pl.type = LOOKUP_LATEST; + pl.commodity = commodity; + pl.currency = currency; + (db->backend->price_lookup) (db->backend, &pl); + } + currency_hash = g_hash_table_lookup(db->commodity_hash, commodity); if(!currency_hash) return NULL; price_list = g_hash_table_lookup(currency_hash, currency); if(!price_list) return NULL; + /* This works magically because prices are inserted in date-sorted order, + * and the latest date always comes first. So return the first in the list. */ result = price_list->data; gnc_price_ref(result); return result; @@ -659,6 +671,15 @@ gnc_pricedb_get_prices(GNCPriceDB *db, if(!db || !commodity || !currency) return NULL; + if (db->backend && db->backend->price_lookup) + { + GNCPriceLookup pl; + pl.type = LOOKUP_ALL; + pl.commodity = commodity; + pl.currency = currency; + (db->backend->price_lookup) (db->backend, &pl); + } + currency_hash = g_hash_table_lookup(db->commodity_hash, commodity); if(!currency_hash) return NULL; @@ -685,6 +706,16 @@ gnc_pricedb_lookup_at_time(GNCPriceDB *db, if(!db || !c || !currency) return NULL; + if (db->backend && db->backend->price_lookup) + { + GNCPriceLookup pl; + pl.type = LOOKUP_AT_TIME; + pl.commodity = c; + pl.currency = currency; + pl.date = t; + (db->backend->price_lookup) (db->backend, &pl); + } + currency_hash = g_hash_table_lookup(db->commodity_hash, c); if(!currency_hash) return NULL; @@ -704,6 +735,79 @@ gnc_pricedb_lookup_at_time(GNCPriceDB *db, return result; } + +GNCPrice * +gnc_pricedb_lookup_nearest_in_time(GNCPriceDB *db, + gnc_commodity *c, + gnc_commodity *currency, + Timespec t) +{ + GList *price_list; + GNCPrice *current_price = NULL; + GNCPrice *next_price = NULL; + GNCPrice *result = NULL; + GList *item = NULL; + GHashTable *currency_hash; + + if(!db || !c || !currency) return NULL; + + if (db->backend && db->backend->price_lookup) + { + GNCPriceLookup pl; + pl.type = LOOKUP_NEAREST_IN_TIME; + pl.commodity = c; + pl.currency = currency; + pl.date = t; + (db->backend->price_lookup) (db->backend, &pl); + } + + currency_hash = g_hash_table_lookup(db->commodity_hash, c); + if(!currency_hash) return NULL; + + price_list = g_hash_table_lookup(currency_hash, currency); + if(!price_list) return NULL; + + item = price_list; + + /* default answer */ + current_price = item->data; + + /* find the first candidate past the one we want. Remember that + prices are in most-recent-first order. */ + while (!next_price && item) { + GNCPrice *p = item->data; + Timespec price_time = gnc_price_get_time(p); + if (timespec_cmp(&price_time, &t) <= 0) { + next_price = item->data; + break; + } + current_price = item->data; + item = item->next; + } + + if (current_price) { + if (!next_price) { + result = current_price; + } else { + Timespec current_t = gnc_price_get_time(current_price); + Timespec next_t = gnc_price_get_time(next_price); + Timespec diff_current = timespec_diff(¤t_t, &t); + Timespec diff_next = timespec_diff(&next_t, &t); + Timespec abs_current = timespec_abs(&diff_current); + Timespec abs_next = timespec_abs(&diff_next); + + if (timespec_cmp(&abs_current, &abs_next) <= 0) { + result = current_price; + } else { + result = next_price; + } + } + } + + gnc_price_ref(result); + return result; +} + /* ==================================================================== */ /* gnc_pricedb_foreach_price infrastructure */ @@ -842,72 +946,7 @@ gnc_pricedb_foreach_price(GNCPriceDB *db, } /* ==================================================================== */ - -GNCPrice * -gnc_pricedb_lookup_nearest_in_time(GNCPriceDB *db, - gnc_commodity *c, - gnc_commodity *currency, - Timespec t) -{ - GList *price_list; - GNCPrice *current_price = NULL; - GNCPrice *next_price = NULL; - GNCPrice *result = NULL; - GList *item = NULL; - GHashTable *currency_hash; - - if(!db || !c || !currency) return NULL; - - currency_hash = g_hash_table_lookup(db->commodity_hash, c); - if(!currency_hash) return NULL; - - price_list = g_hash_table_lookup(currency_hash, currency); - if(!price_list) return NULL; - - item = price_list; - - /* default answer */ - current_price = item->data; - - /* find the first candidate past the one we want. Remember that - prices are in most-recent-first order. */ - while (!next_price && item) { - GNCPrice *p = item->data; - Timespec price_time = gnc_price_get_time(p); - if (timespec_cmp(&price_time, &t) <= 0) { - next_price = item->data; - break; - } - current_price = item->data; - item = item->next; - } - - if (current_price) { - if (!next_price) { - result = current_price; - } else { - Timespec current_t = gnc_price_get_time(current_price); - Timespec next_t = gnc_price_get_time(next_price); - Timespec diff_current = timespec_diff(¤t_t, &t); - Timespec diff_next = timespec_diff(&next_t, &t); - Timespec abs_current = timespec_abs(&diff_current); - Timespec abs_next = timespec_abs(&diff_next); - - if (timespec_cmp(&abs_current, &abs_next) <= 0) { - result = current_price; - } else { - result = next_price; - } - } - } - - gnc_price_ref(result); - return result; -} - -/***************************************************************************/ -/* commodity substitution - */ +/* commodity substitution */ typedef struct { gnc_commodity *old_c; diff --git a/src/engine/gnc-pricedb.h b/src/engine/gnc-pricedb.h index 8035ae352b..44f49f059f 100644 --- a/src/engine/gnc-pricedb.h +++ b/src/engine/gnc-pricedb.h @@ -108,6 +108,7 @@ */ typedef struct _GNCPrice GNCPrice; +typedef struct _GNCPriceLookup GNCPriceLookup; /****************/ /* constructors */ diff --git a/src/engine/rpc/RpcBackend.c b/src/engine/rpc/RpcBackend.c index e93d96465a..b2c2c27f41 100644 --- a/src/engine/rpc/RpcBackend.c +++ b/src/engine/rpc/RpcBackend.c @@ -101,6 +101,7 @@ static void rpcendEnable (RPCBackend *be) be->be.price_begin_edit = be->snr.price_begin_edit; be->be.price_commit_edit = be->snr.price_commit_edit; be->be.run_query = be->snr.run_query; + be->be.price_lookup = be->snr.price_lookup; be->be.sync = be->snr.sync; be->be.sync_price = be->snr.sync_price; } @@ -123,6 +124,7 @@ static void rpcendDisable (RPCBackend *be) be->snr.price_begin_edit = be->be.price_begin_edit; be->snr.price_commit_edit = be->be.price_commit_edit; be->snr.run_query = be->be.run_query; + be->snr.price_lookup = be->be.price_lookup; be->snr.sync = be->be.sync; be->snr.sync_price = be->be.sync_price; @@ -135,6 +137,7 @@ static void rpcendDisable (RPCBackend *be) be->be.price_begin_edit = NULL; be->be.price_commit_edit = NULL; be->be.run_query = NULL; + be->be.price_lookup = NULL; be->be.sync = NULL; be->be.sync_price = NULL; } @@ -583,6 +586,11 @@ static int rpcend_price_commit_edit (Backend *bend, GNCPrice *pr) return 0; } +static void rpcend_price_lookup (Backend *bend, GNCPriceLookup *q) +{ + PERR ("not implemented"); +} + static void rpcend_run_query (Backend *bend, Query *q) { RPCBackend *be = (RPCBackend *)bend; @@ -928,6 +936,7 @@ static void rpcend_book_begin (GNCBook *book, const char *book_id, be->be.price_begin_edit = rpcend_price_begin_edit; be->be.price_commit_edit = rpcend_price_commit_edit; be->be.run_query = rpcend_run_query; + be->be.price_lookup = rpcend_price_lookup; be->be.sync = rpcend_sync; be->be.sync_price = rpcend_sync_price; be->be.events_pending = rpcend_events_pending; diff --git a/src/engine/sql/PostgresBackend.c b/src/engine/sql/PostgresBackend.c index 903eac4867..d32862934b 100644 --- a/src/engine/sql/PostgresBackend.c +++ b/src/engine/sql/PostgresBackend.c @@ -1546,6 +1546,14 @@ pgendGetAllPrices (PGBackend *be, GNCPriceDB *prdb) return prdb; } +/* ============================================================= */ + +static void +pgendPriceLookup (Backend *be, GNCPriceLookup *look) +{ + PERR ("not implemented, type=%d", look->type); +} + /* ============================================================= */ /* ============================================================= */ /* HIGHER LEVEL ROUTINES AND BACKEND PROPER */ @@ -2720,6 +2728,7 @@ pgend_session_begin (GNCBook *sess, const char * sessionid, be->be.price_begin_edit = NULL; be->be.price_commit_edit = NULL; be->be.run_query = NULL; + be->be.price_lookup = NULL; be->be.sync = pgendSyncSingleFile; be->be.sync_price = pgendSyncPriceDBSingleFile; PWARN ("MODE_SINGLE_FILE is beta -- \n" @@ -2739,6 +2748,7 @@ pgend_session_begin (GNCBook *sess, const char * sessionid, be->be.price_begin_edit = pgend_price_begin_edit; be->be.price_commit_edit = pgend_price_commit_edit; be->be.run_query = NULL; + be->be.price_lookup = NULL; be->be.sync = pgendSync; be->be.sync_price = pgendSyncPriceDB; PWARN ("MODE_SINGLE_UPDATE is beta -- \n" @@ -2757,6 +2767,7 @@ pgend_session_begin (GNCBook *sess, const char * sessionid, be->be.price_begin_edit = pgend_price_begin_edit; be->be.price_commit_edit = pgend_price_commit_edit; be->be.run_query = pgendRunQueryToCheckpoint; + be->be.price_lookup = pgendPriceLookup; be->be.sync = pgendSync; be->be.sync_price = pgendSyncPriceDB; PWARN ("MODE_POLL is experimental -- you might corrupt your data\n"); @@ -2798,6 +2809,7 @@ pgendDisable (PGBackend *be) be->snr.price_begin_edit = be->be.price_begin_edit; be->snr.price_commit_edit = be->be.price_commit_edit; be->snr.run_query = be->be.run_query; + be->snr.price_lookup = be->be.price_lookup; be->snr.sync = be->be.sync; be->snr.sync_price = be->be.sync_price; @@ -2809,6 +2821,7 @@ pgendDisable (PGBackend *be) be->be.price_begin_edit = NULL; be->be.price_commit_edit = NULL; be->be.run_query = NULL; + be->be.price_lookup = NULL; be->be.sync = NULL; be->be.sync_price = NULL; } @@ -2835,6 +2848,7 @@ pgendEnable (PGBackend *be) be->be.price_begin_edit = be->snr.price_begin_edit; be->be.price_commit_edit = be->snr.price_commit_edit; be->be.run_query = be->snr.run_query; + be->be.price_lookup = be->snr.price_lookup; be->be.sync = be->snr.sync; be->be.sync_price = be->snr.sync_price; } @@ -2870,6 +2884,7 @@ pgendInit (PGBackend *be) be->be.price_begin_edit = NULL; be->be.price_commit_edit = NULL; be->be.run_query = NULL; + be->be.price_lookup = NULL; be->be.sync = NULL; be->be.sync_price = NULL; be->be.events_pending = NULL;