diff --git a/src/engine/sql/PostgresBackend.c b/src/engine/sql/PostgresBackend.c index c6de40bb73..a2637efa10 100644 --- a/src/engine/sql/PostgresBackend.c +++ b/src/engine/sql/PostgresBackend.c @@ -200,6 +200,15 @@ pgendGetResults (PGBackend *be, return data; } +/* ============================================================= */ +/* version number callback for pgendGetResults */ + +static gpointer +get_version_cb (PGBackend *be, PGresult *result, int j, gpointer data) +{ + if (-1 != (int) data || 0 != j) return (gpointer) -1; + return ((gpointer) atoi(DB_GET_VAL ("version", 0))); +} /* ============================================================= */ /* include the auto-generated code */ @@ -232,30 +241,6 @@ static const char *table_drop_str = * two are equal. */ -static gpointer -acc_version_cb (PGBackend *be, PGresult *result, int j, gpointer data) -{ - if (-1 != (int) data || 0 != j) return (gpointer) -1; - return ((gpointer) atoi(DB_GET_VAL ("version", 0))); -} - -static int -pgendAccountCompareVersion (PGBackend *be, Account *acct) -{ - char *p; - int sql_version = 0; - - p = be->buff; *p = 0; - p = stpcpy (p, "SELECT version FROM gncAccount WHERE accountGuid ='"); - p = guid_to_string_buff (&(acct->guid), p); - p = stpcpy (p, "';"); - SEND_QUERY (be,be->buff, -1); - sql_version = (int) pgendGetResults (be, acc_version_cb, (gpointer) -1); - - if (-1 == sql_version) return -1; - return (sql_version - xaccAccountGetVersion (acct)); -} - /* ============================================================= */ /* the pgendStoreAccount() routine stores an account to the * database. That is, the engine data is written out to the @@ -599,39 +584,6 @@ is_trans_empty (Transaction *trans) return TRUE; } -/* ============================================================= */ -/* The pgendTransCompareVersion() routine compares the version - * number of the transaction in the engine and the sql database. It - * returns a negative number if the sql version is older (or the - * acount is not present in the sql db). It returns a positive - * number if the sql version is newer. It returns zero if the - * two are equal. - */ - -static gpointer -trans_version_cb (PGBackend *be, PGresult *result, int j, gpointer data) -{ - if (-1 != (int) data || 0 != j) return (gpointer) -1; - return ((gpointer) atoi(DB_GET_VAL ("version", 0))); -} - -static int -pgendTransCompareVersion (PGBackend *be, Transaction *trans) -{ - char *p; - int sql_version = 0; - - p = be->buff; *p = 0; - p = stpcpy (p, "SELECT version FROM gncTransaction WHERE transGuid ='"); - p = guid_to_string_buff (&(trans->guid), p); - p = stpcpy (p, "';"); - SEND_QUERY (be,be->buff, -1); - sql_version = (int) pgendGetResults (be, trans_version_cb, (gpointer) -1); - - if (-1 == sql_version) return -1; - return (sql_version - xaccTransGetVersion (trans)); -} - /* ============================================================= */ /* The pgendStoreTransactionNoLock() routine traverses the transaction * structure and stores/updates it in the database. If checks the @@ -677,7 +629,7 @@ pgendStoreTransactionNoLock (PGBackend *be, Transaction *trans, /* don't update the database if the database is newer ... */ if (do_check_version) { - if (0 < pgendTransCompareVersion (be, trans)) return; + if (0 < pgendTransactionCompareVersion (be, trans)) return; } trans->version ++; /* be sure to update the version !! */ @@ -1364,10 +1316,17 @@ pgendGetAllTransactions (PGBackend *be, AccountGroup *grp) /* store just one price */ static void -pgendStorePriceNoLock (PGBackend *be, GNCPrice *pr) +pgendStorePriceNoLock (PGBackend *be, GNCPrice *pr, + gboolean do_check_version) { gnc_commodity *modity; + if (do_check_version) + { + if (0 < pgendPriceCompareVersion (be, pr)) return; + } + pr->version ++; /* be sure to update the version !! */ + /* make sure that we've stored the commodity * and currency before we store the price. */ @@ -1777,7 +1736,7 @@ pgend_trans_commit_edit (Backend * bend, } } #else - if (0 < pgendTransCompareVersion (be, oldtrans)) rollback ++; + if (0 < pgendTransactionCompareVersion (be, oldtrans)) rollback ++; #endif if (rollback) { @@ -1841,8 +1800,26 @@ pgend_price_commit_edit (Backend * bend, GNCPrice *pr) SEND_QUERY (be,bufp, 555); FINISH_QUERY(be->connection); - /* hack alert -- we should check a version number, to make - * sure we aren't clobbering something newer in the database */ + /* check to see that the engine version is equal or newer than + * whats in the database. It its not, then some other user has + * made changes, and we must roll back. */ + if (0 < pgendPriceCompareVersion (be, pr)) + { + pr->do_free = FALSE; + bufp = "ROLLBACK;"; + SEND_QUERY (be,bufp,444); + FINISH_QUERY(be->connection); + + /* hack alert -- we should restore the price data from the + * sql back end at this point ! !!! */ + PWARN(" price data in engine is newer\n" + " price must be rolled back. This function\n" + " is not completely implemented !! \n"); + LEAVE ("rolled back"); + return 445; + } + pr->version ++; /* be sure to update the version !! */ + if (pr->do_free) { bufp = be->buff; @@ -1855,7 +1832,7 @@ pgend_price_commit_edit (Backend * bend, GNCPrice *pr) } else { - pgendStorePriceNoLock (be, pr); + pgendStorePriceNoLock (be, pr, FALSE); } bufp = "COMMIT;"; diff --git a/src/engine/sql/base-objects.m4 b/src/engine/sql/base-objects.m4 index 4cdaaba1fb..0c982258cc 100644 --- a/src/engine/sql/base-objects.m4 +++ b/src/engine/sql/base-objects.m4 @@ -24,3 +24,7 @@ put_one_only(modity) put_one_only(split) put_one_only(transaction) put_one_only(price) + +compare_version(account) +compare_version(transaction) +compare_version(price) diff --git a/src/engine/sql/table.m4 b/src/engine/sql/table.m4 index 0619411c1c..865424e0f4 100644 --- a/src/engine/sql/table.m4 +++ b/src/engine/sql/table.m4 @@ -192,6 +192,23 @@ cmp_fields_r(nextrec($@))')')') define(`cmp_fields', `cmp_fields_r(firstrec($@))') +/* -------- */ +/* return the name of the sql field associcate with the primary key */ + +define(`key_fieldname_r', `ifelse($#, 1, , +`ifelse($2, `KEY', $1, +`key_fieldname_r(nextrec($@))')')') + +define(`key_fieldname', `key_fieldname_r(firstrec($@))') + +/* -------- */ +/* return the getter function that deals with the version number */ +define(`version_function_r', `ifelse($#, 1, , +`ifelse($1, `version', $4, +`version_function_r(nextrec($@))')')') + +define(`version_function', `version_function_r(firstrec($@))') + /* -------- */ define(`store_one_only', @@ -235,8 +252,7 @@ define(`compare_one_only', */ static int -pgendCompareOne`'func_name($@)`'Only (PGBackend *be, - xacc_type($@) *ptr) +pgendCompareOne`'func_name($@)`'Only (PGBackend *be, xacc_type($@) *ptr) { const char *buf; PGresult *result; @@ -281,8 +297,7 @@ define(`put_one_only', */ static void -pgendPutOne`'func_name($@)`'Only (PGBackend *be, - xacc_type($@) *ptr) +pgendPutOne`'func_name($@)`'Only (PGBackend *be, xacc_type($@) *ptr) { int ndiffs; ndiffs = pgendCompareOne`'func_name($@)`'Only (be, ptr); @@ -295,5 +310,35 @@ pgendPutOne`'func_name($@)`'Only (PGBackend *be, ') -/* ------------------------------------------------------- */ +define(`compare_version', +` +/* ------------------------------------------------------ */ +/* This routine compares the version number of the account in + * the engine and the sql database. It returns a negative + * number if the sql version is older (or the item is not + * present in the sql db). It returns a positive number + * if the sql version is newer. It returns zero if the + * two are equal. + */ + +static int +pgend`'func_name($@)`'CompareVersion (PGBackend *be, xacc_type($@) *ptr) +{ + char *p; + int sql_version = 0; + + p = be->buff; *p = 0; + p = stpcpy (p, "SELECT version FROM tablename($@) WHERE key_fieldname($@) = ''`"); + p = guid_to_string_buff (&(ptr->guid), p); + p = stpcpy (p, "''`;"); + SEND_QUERY (be,be->buff, -1); + sql_version = (int) pgendGetResults (be, get_version_cb, (gpointer) -1); + + if (-1 == sql_version) return -1; + return (sql_version - version_function($@)); +} + +') + divert +/* DO NOT EDIT THIS FILE -- it is autogenerated -- edit table.m4 instead */