mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
* src/backend/postgres/txn.c: fix bugs restoring one transaction
from database. * src/backend/postgres/putil.h: add EXEC_QUERY * src/backend/postgres/price.h: add pgendGetCommodity * src/backend/postgres/price.c: add pgendGetCommodity git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@6391 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
@@ -57,22 +57,22 @@ static short module = MOD_BACKEND;
|
||||
static gpointer
|
||||
get_commodities_cb (PGBackend *be, PGresult *result, int j, gpointer data)
|
||||
{
|
||||
gnc_commodity_table *comtab = (gnc_commodity_table *) data;
|
||||
gnc_commodity_table *comtab = data;
|
||||
gnc_commodity *com;
|
||||
|
||||
/* first, lets see if we've already got this one */
|
||||
com = gnc_commodity_table_lookup(comtab,
|
||||
DB_GET_VAL("namespace",j), DB_GET_VAL("mnemonic",j));
|
||||
DB_GET_VAL("namespace",j),
|
||||
DB_GET_VAL("mnemonic",j));
|
||||
|
||||
if (com) return comtab;
|
||||
|
||||
/* no we don't ... restore it */
|
||||
com = gnc_commodity_new (
|
||||
DB_GET_VAL("fullname",j),
|
||||
DB_GET_VAL("namespace",j),
|
||||
DB_GET_VAL("mnemonic",j),
|
||||
DB_GET_VAL("code",j),
|
||||
atoi(DB_GET_VAL("fraction",j)));
|
||||
com = gnc_commodity_new (DB_GET_VAL("fullname",j),
|
||||
DB_GET_VAL("namespace",j),
|
||||
DB_GET_VAL("mnemonic",j),
|
||||
DB_GET_VAL("code",j),
|
||||
atoi(DB_GET_VAL("fraction",j)));
|
||||
|
||||
gnc_commodity_table_insert (comtab, com);
|
||||
return comtab;
|
||||
@@ -101,6 +101,38 @@ pgendGetAllCommodities (PGBackend *be)
|
||||
LEAVE (" ");
|
||||
}
|
||||
|
||||
void
|
||||
pgendGetCommodity (PGBackend *be, const char * unique_name)
|
||||
{
|
||||
gnc_commodity_table *comtab;
|
||||
sqlEscape *escape;
|
||||
char *p;
|
||||
|
||||
if (!be || !unique_name) return;
|
||||
|
||||
ENTER ("be=%p, conn=%p", be, be->connection);
|
||||
|
||||
comtab = gnc_book_get_commodity_table (be->book);
|
||||
if (!comtab) {
|
||||
PERR ("can't get commodity table");
|
||||
return;
|
||||
}
|
||||
|
||||
escape = sqlEscape_new ();
|
||||
|
||||
/* Get them ALL */
|
||||
p = be->buff;
|
||||
p = stpcpy (p, "SELECT * FROM gncCommodity WHERE gncCommodity.commodity='");
|
||||
p = stpcpy (p, sqlEscapeString (escape, unique_name));
|
||||
p = stpcpy (p, "';");
|
||||
|
||||
SEND_QUERY (be, be->buff, );
|
||||
pgendGetResults (be, get_commodities_cb, comtab);
|
||||
|
||||
sqlEscape_destroy (escape);
|
||||
|
||||
LEAVE (" ");
|
||||
}
|
||||
|
||||
/* ============================================================= */
|
||||
/* ============================================================= */
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include "PostgresBackend.h"
|
||||
|
||||
void pgendGetAllCommodities (PGBackend *be);
|
||||
void pgendGetCommodity (PGBackend *be, const char * unique_name);
|
||||
void pgendStorePriceDB (PGBackend *be, GNCPriceDB *prdb);
|
||||
void pgendStorePriceDBNoLock (PGBackend *be, GNCPriceDB *prdb);
|
||||
GNCPriceDB * pgendGetAllPrices (PGBackend *be, GNCPriceDB *prdb);
|
||||
|
||||
@@ -154,6 +154,32 @@ gnc_commodity * gnc_string_to_commodity (const char *str, GNCBook *book);
|
||||
} \
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
/* The EXEC_QUERY macro executes a query and returns the results
|
||||
* and makes sure that no errors occured. Results are left
|
||||
* in the result buffer.
|
||||
*/
|
||||
#define EXEC_QUERY(conn,buff,result) \
|
||||
{ \
|
||||
ExecStatusType status = 0; \
|
||||
result = PQexec (conn, buff); \
|
||||
if (result) \
|
||||
status = PQresultStatus(result); \
|
||||
if (!result || \
|
||||
((PGRES_COMMAND_OK != status) && \
|
||||
(PGRES_TUPLES_OK != status))) \
|
||||
{ \
|
||||
PERR("failed to get result to query:\n" \
|
||||
"\t%s", PQerrorMessage((conn))); \
|
||||
if (result) \
|
||||
PQclear (result); \
|
||||
result = NULL; \
|
||||
PQfinish (conn); \
|
||||
be->connection = NULL; \
|
||||
xaccBackendSetError (&be->be, ERR_BACKEND_SERVER_ERR); \
|
||||
} \
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------- */
|
||||
/* The IF_ONE_ROW macro counts the number of rows returned by
|
||||
* a query, reports an error if there is more than one row, and
|
||||
|
||||
@@ -43,9 +43,10 @@
|
||||
#include "Transaction.h"
|
||||
#include "TransactionP.h"
|
||||
|
||||
#include "PostgresBackend.h"
|
||||
#include "checkpoint.h"
|
||||
#include "kvp-sql.h"
|
||||
#include "PostgresBackend.h"
|
||||
#include "price.h"
|
||||
#include "txn.h"
|
||||
|
||||
#include "putil.h"
|
||||
@@ -570,7 +571,7 @@ pgendCopyTransactionToEngine (PGBackend *be, const GUID *trans_guid)
|
||||
PGresult *result;
|
||||
gboolean do_set_guid=FALSE;
|
||||
int engine_data_is_newer = 0;
|
||||
int i, j, nrows;
|
||||
int j;
|
||||
GList *node, *engine_splits;
|
||||
|
||||
ENTER ("be=%p", be);
|
||||
@@ -604,96 +605,102 @@ pgendCopyTransactionToEngine (PGBackend *be, const GUID *trans_guid)
|
||||
/* build the sql query to get the transaction */
|
||||
pbuff = be->buff;
|
||||
pbuff[0] = 0;
|
||||
pbuff = stpcpy (pbuff,
|
||||
"SELECT * FROM gncTransaction WHERE transGuid='");
|
||||
pbuff = stpcpy (pbuff, "SELECT * FROM gncTransaction WHERE transGuid='");
|
||||
pbuff = guid_to_string_buff(trans_guid, pbuff);
|
||||
pbuff = stpcpy (pbuff, "';");
|
||||
|
||||
SEND_QUERY (be,be->buff, 0);
|
||||
i=0; nrows=0;
|
||||
do {
|
||||
GET_RESULTS (be->connection, result);
|
||||
{
|
||||
int jrows;
|
||||
int ncols = PQnfields (result);
|
||||
jrows = PQntuples (result);
|
||||
nrows += jrows;
|
||||
PINFO ("query result %d has %d rows and %d cols",
|
||||
i, nrows, ncols);
|
||||
EXEC_QUERY (be->connection, be->buff, result);
|
||||
if (!result)
|
||||
return 0;
|
||||
|
||||
j = 0;
|
||||
if (0 == nrows)
|
||||
{
|
||||
PQclear (result);
|
||||
/* I beleive its a programming error to get this case.
|
||||
* Print a warning for now... */
|
||||
PERR ("no such transaction in the database. This is unexpected ...\n");
|
||||
xaccBackendSetError (&be->be, ERR_SQL_MISSING_DATA);
|
||||
pgendEnable(be);
|
||||
gnc_engine_resume_events();
|
||||
return 0;
|
||||
{
|
||||
int ncols = PQnfields (result);
|
||||
int nrows = PQntuples (result);
|
||||
|
||||
PINFO ("query result has %d rows and %d cols", nrows, ncols);
|
||||
|
||||
j = 0;
|
||||
if (0 == nrows)
|
||||
{
|
||||
PQclear (result);
|
||||
/* I beleive its a programming error to get this case.
|
||||
* Print a warning for now... */
|
||||
PERR ("no such transaction in the database. This is unexpected ...\n");
|
||||
xaccBackendSetError (&be->be, ERR_SQL_MISSING_DATA);
|
||||
pgendEnable(be);
|
||||
gnc_engine_resume_events();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (1 < nrows)
|
||||
{
|
||||
/* since the guid is primary key, this error is totally
|
||||
* and completely impossible, theoretically ... */
|
||||
PERR ("!!!!!!!!!!!SQL database is corrupt!!!!!!!\n"
|
||||
"too many transactions with GUID=%s\n",
|
||||
guid_to_string (trans_guid));
|
||||
xaccBackendSetError (&be->be, ERR_BACKEND_DATA_CORRUPT);
|
||||
pgendEnable(be);
|
||||
gnc_engine_resume_events();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* First order of business is to determine whose data is
|
||||
* newer: the engine cache, or the database. If the
|
||||
* database has newer stuff, we update the engine. If the
|
||||
* engine is equal or newer, we do nothing in this routine.
|
||||
* Of course, we know the database has newer data if this
|
||||
* transaction doesn't exist in the engine yet.
|
||||
*/
|
||||
if (!do_set_guid)
|
||||
{
|
||||
gint32 db_version, cache_version;
|
||||
db_version = atoi (DB_GET_VAL("version",j));
|
||||
cache_version = xaccTransGetVersion (trans);
|
||||
if (db_version == cache_version) {
|
||||
engine_data_is_newer = 0;
|
||||
} else
|
||||
if (db_version < cache_version) {
|
||||
engine_data_is_newer = +1;
|
||||
} else {
|
||||
engine_data_is_newer = -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (1 < nrows)
|
||||
{
|
||||
/* since the guid is primary key, this error is totally
|
||||
* and completely impossible, theoretically ... */
|
||||
PERR ("!!!!!!!!!!!SQL database is corrupt!!!!!!!\n"
|
||||
"too many transactions with GUID=%s\n",
|
||||
guid_to_string (trans_guid));
|
||||
if (jrows != nrows) xaccTransCommitEdit (trans);
|
||||
xaccBackendSetError (&be->be, ERR_BACKEND_DATA_CORRUPT);
|
||||
pgendEnable(be);
|
||||
gnc_engine_resume_events();
|
||||
return 0;
|
||||
}
|
||||
/* if the DB data is newer, copy it to engine */
|
||||
if (0 > engine_data_is_newer)
|
||||
{
|
||||
Timespec ts;
|
||||
gnc_commodity *currency;
|
||||
|
||||
/* First order of business is to determine whose data is
|
||||
* newer: the engine cache, or the database. If the
|
||||
* database has newer stuff, we update the engine. If the
|
||||
* engine is equal or newer, we do nothing in this routine.
|
||||
* Of course, we know the database has newer data if this
|
||||
* transaction doesn't exist in the engine yet.
|
||||
*/
|
||||
if (!do_set_guid)
|
||||
{
|
||||
gint32 db_version, cache_version;
|
||||
db_version = atoi (DB_GET_VAL("version",j));
|
||||
cache_version = xaccTransGetVersion (trans);
|
||||
if (db_version == cache_version) {
|
||||
engine_data_is_newer = 0;
|
||||
} else
|
||||
if (db_version < cache_version) {
|
||||
engine_data_is_newer = +1;
|
||||
} else {
|
||||
engine_data_is_newer = -1;
|
||||
}
|
||||
}
|
||||
currency = gnc_string_to_commodity (DB_GET_VAL("currency",j), be->book);
|
||||
if (!currency)
|
||||
{
|
||||
pgendGetCommodity (be, DB_GET_VAL("currency",j));
|
||||
currency = gnc_string_to_commodity (DB_GET_VAL("currency",j),
|
||||
be->book);
|
||||
}
|
||||
|
||||
/* if the DB data is newer, copy it to engine */
|
||||
if (0 > engine_data_is_newer)
|
||||
{
|
||||
Timespec ts;
|
||||
gnc_commodity *currency;
|
||||
if (!currency)
|
||||
{
|
||||
PERR ("currency not found: %s", DB_GET_VAL("currency",j));
|
||||
}
|
||||
|
||||
xaccTransBeginEdit (trans);
|
||||
if (do_set_guid) xaccTransSetGUID (trans, trans_guid);
|
||||
xaccTransSetNum (trans, DB_GET_VAL("num",j));
|
||||
xaccTransSetDescription (trans, DB_GET_VAL("description",j));
|
||||
ts = gnc_iso8601_to_timespec_local (DB_GET_VAL("date_posted",j));
|
||||
xaccTransSetDatePostedTS (trans, &ts);
|
||||
ts = gnc_iso8601_to_timespec_local (DB_GET_VAL("date_entered",j));
|
||||
xaccTransSetDateEnteredTS (trans, &ts);
|
||||
xaccTransSetVersion (trans, atoi(DB_GET_VAL("version",j)));
|
||||
currency = gnc_string_to_commodity (DB_GET_VAL("currency",j),
|
||||
be->book);
|
||||
xaccTransSetCurrency (trans, currency);
|
||||
trans->idata = atoi(DB_GET_VAL("iguid",j));
|
||||
}
|
||||
}
|
||||
PQclear (result);
|
||||
i++;
|
||||
} while (result);
|
||||
xaccTransBeginEdit (trans);
|
||||
if (do_set_guid) xaccTransSetGUID (trans, trans_guid);
|
||||
xaccTransSetNum (trans, DB_GET_VAL("num",j));
|
||||
xaccTransSetDescription (trans, DB_GET_VAL("description",j));
|
||||
ts = gnc_iso8601_to_timespec_local (DB_GET_VAL("date_posted",j));
|
||||
xaccTransSetDatePostedTS (trans, &ts);
|
||||
ts = gnc_iso8601_to_timespec_local (DB_GET_VAL("date_entered",j));
|
||||
xaccTransSetDateEnteredTS (trans, &ts);
|
||||
xaccTransSetVersion (trans, atoi(DB_GET_VAL("version",j)));
|
||||
xaccTransSetCurrency (trans, currency);
|
||||
trans->idata = atoi(DB_GET_VAL("iguid",j));
|
||||
}
|
||||
}
|
||||
|
||||
PQclear (result);
|
||||
|
||||
/* set timestamp as 'recent' for this data */
|
||||
trans->version_check = be->version_check;
|
||||
@@ -718,6 +725,12 @@ pgendCopyTransactionToEngine (PGBackend *be, const GUID *trans_guid)
|
||||
|
||||
if (0 != trans->idata)
|
||||
{
|
||||
if (!kvp_frame_is_empty (trans->kvp_data))
|
||||
{
|
||||
kvp_frame_delete (trans->kvp_data);
|
||||
trans->kvp_data = kvp_frame_new ();
|
||||
}
|
||||
|
||||
trans->kvp_data = pgendKVPFetch (be, trans->idata, trans->kvp_data);
|
||||
}
|
||||
|
||||
@@ -727,6 +740,12 @@ pgendCopyTransactionToEngine (PGBackend *be, const GUID *trans_guid)
|
||||
Split *s = node->data;
|
||||
if (0 != s->idata)
|
||||
{
|
||||
if (!kvp_frame_is_empty (s->kvp_data))
|
||||
{
|
||||
kvp_frame_delete (s->kvp_data);
|
||||
s->kvp_data = kvp_frame_new ();
|
||||
}
|
||||
|
||||
s->kvp_data = pgendKVPFetch (be, s->idata, s->kvp_data);
|
||||
}
|
||||
}
|
||||
@@ -890,7 +909,9 @@ pgend_trans_commit_edit (Backend * bend,
|
||||
* and crashes. We've fixed the bugs, but ...
|
||||
*/
|
||||
char buf[80];
|
||||
gnc_timespec_to_iso8601_buff (xaccTransRetDatePostedTS (trans), buf);
|
||||
gnc_timespec_to_iso8601_buff (xaccTransRetDatePostedTS (trans),
|
||||
buf);
|
||||
|
||||
PERR ("The impossible has happened, and thats not good!\n"
|
||||
"\tThe SQL database contains an active transaction that\n"
|
||||
"\talso appears in the audit trail as deleted !!\n"
|
||||
@@ -945,7 +966,8 @@ pgend_trans_commit_edit (Backend * bend,
|
||||
{
|
||||
Split *s = (Split *) node->data;
|
||||
Account *acc = xaccSplitGetAccount (s);
|
||||
pgendAccountRecomputeOneCheckpoint (be, acc, trans->orig->date_posted);
|
||||
pgendAccountRecomputeOneCheckpoint (be, acc,
|
||||
trans->orig->date_posted);
|
||||
}
|
||||
|
||||
/* set checkpoints for the new accounts */
|
||||
|
||||
Reference in New Issue
Block a user