diff --git a/src/engine/sql/PostgresBackend.c b/src/engine/sql/PostgresBackend.c index 310968d744..9896d91ea6 100644 --- a/src/engine/sql/PostgresBackend.c +++ b/src/engine/sql/PostgresBackend.c @@ -21,12 +21,21 @@ static short module = MOD_BACKEND; -/* hack alert -- this is the query buffer, it might be too small. - we need to make it dynamic sized */ -#define QBUFSIZE 16350 - /* ============================================================= */ +#define SEND_QUERY(be) { \ + int rc; \ + rc = PQsendQuery (be->connection, be->buff); \ + if (!rc) \ + { \ + /* hack alert -- we need knider, gentler error handling */\ + PERR("send query failed:\n" \ + "\t%s", PQerrorMessage(be->connection)); \ + PQfinish (be->connection); \ + return; \ + } \ +} + #define FLUSH(conn) { \ PGresult *result; \ /* complete/commit the transaction, check the status */ \ @@ -48,6 +57,7 @@ static short module = MOD_BACKEND; /* ============================================================= */ /* This routine stores the indicated group structure into the database. * It does *not* chase pointers, traverse the tree, etc. + * It performs no locking. */ static void @@ -55,8 +65,7 @@ pgendStoreOneGroupOnly (PGBackend *be, AccountGroup *grp) { Account *parent; const GUID *parent_guid, *grp_guid; - char buff[QBUFSIZE]; - int i, nacc, rc; + int i, nacc; ENTER ("be=%p, grp=%p\n", be, grp); if (!be || !grp) return; @@ -70,7 +79,7 @@ pgendStoreOneGroupOnly (PGBackend *be, AccountGroup *grp) Account *acc = xaccGroupGetAccount(grp, i); /* hack alert -- values should be escaped so that no '' apear in them */ - snprintf (buff, QBUFSIZE, + snprintf (be->buff, be->bufflen, "INSERT INTO gncGroup " "(groupGuid, parentGuid, childGuid)" " values " @@ -79,14 +88,8 @@ pgendStoreOneGroupOnly (PGBackend *be, AccountGroup *grp) guid_to_string(parent_guid), guid_to_string(xaccAccountGetGUID (acc)) ); - rc = PQsendQuery (be->connection, buff); - if (!rc) - { - PERR("send query failed:\n" - "\t%s", PQerrorMessage(be->connection)); - PQfinish (be->connection); - return; - } + + SEND_QUERY(be); /* complete/commit the transaction, check the status */ FLUSH(be->connection); @@ -95,16 +98,88 @@ pgendStoreOneGroupOnly (PGBackend *be, AccountGroup *grp) LEAVE ("\n"); } +/* ============================================================= */ +/* This routine stores the indicated account structure into the database. + * It does *not* chase pointers, traverse the tree, etc. + * It performs no locking. + */ + +static void +pgendStoreOneAccountOnly (PGBackend *be, Account *acct) +{ + + ENTER ("be=%p, acct=%p\n", be, acct); + if (!be || !acct) return; + + /* hack alert -- values should be escaped so that no '' apear in them */ + snprintf (be->buff, be->bufflen, + "INSERT INTO gncAccount " + "(accountGuid, parentGuid, childrenGuid, " + "accountName, accountCode, description, notes, " + "type, currency, security)" + " values " + "('%s', '%s', '%s', '%s', '%s', '%s', '%s', " + "%d, '%s', '%s');", + guid_to_string(xaccAccountGetGUID (acct)), + guid_to_string(xaccGroupGetGUID (xaccAccountGetParent(acct))), + guid_to_string(xaccGroupGetGUID (xaccAccountGetChildren(acct))), + xaccAccountGetName (acct), + xaccAccountGetCode (acct), + xaccAccountGetDescription (acct), + xaccAccountGetNotes (acct), + xaccAccountGetType (acct), + xaccAccountGetCurrency (acct), + xaccAccountGetSecurity (acct) + ); + + SEND_QUERY (be); + + /* complete/commit the transaction, check the status */ + FLUSH(be->connection); + + LEAVE ("\n"); +} + +/* ============================================================= */ +/* This routine stores the indicated transaction structure into the database. + * It does *not* chase pointers, traverse the tree, etc. + * It performs no locking. + */ + +static void +pgendStoreOneTransactionOnly (PGBackend *be, Transaction *trans) +{ + + ENTER ("be=%p, trans=%p\n", be, trans); + if (!be || !trans) return; + + /* hack alert -- values should be escaped so that no '' apear in them */ + snprintf (be->buff, be->bufflen, + "INSERT INTO gncTransaction " + "(transGuid, num, description)" + " values " + "('%s', '%s', '%s');", + guid_to_string(xaccTransGetGUID (trans)), + xaccTransGetNum (trans), + xaccTransGetDescription (trans) + ); + + SEND_QUERY (be); + + /* complete/commit the transaction, check the status */ + FLUSH(be->connection); + + LEAVE ("\n"); +} + /* ============================================================= */ /* this routine stores the indicated split in the database */ static void -pgendStoreSplit (PGBackend *be, Split *split) +pgendStoreOneSplitOnly (PGBackend *be, Split *split) { Timespec ts; - char buff[QBUFSIZE]; - int rc; ENTER ("be=%p, split=%p\n", be, split); if (!be || !split) return; @@ -113,7 +188,7 @@ pgendStoreSplit (PGBackend *be, Split *split) xaccSplitGetDateReconciledTS (split, &ts); /* hack alert -- values should be escaped so that no '' apear in them */ - snprintf (buff, QBUFSIZE, + snprintf (be->buff, be->bufflen, "INSERT INTO gncEntry " "(entryGuid, accountGuid, transGuid, memo, action," "reconciled, amount, share_price)" @@ -128,14 +203,8 @@ pgendStoreSplit (PGBackend *be, Split *split) xaccSplitGetShareAmount(split), xaccSplitGetSharePrice(split) ); - rc = PQsendQuery (be->connection, buff); - if (!rc) - { - PERR("send query failed:\n" - "\t%s", PQerrorMessage(be->connection)); - PQfinish (be->connection); - return; - } + + SEND_QUERY (be); /* complete/commit the transaction, check the status */ FLUSH(be->connection); @@ -143,6 +212,80 @@ pgendStoreSplit (PGBackend *be, Split *split) LEAVE ("\n"); } +/* ============================================================= */ +/* This routine traverses the group structure and stores it into + * the database. The NoLock version doesn't lock up the tables. + */ + +static int +traverse_cb (Transaction *trans, void *cb_data) +{ + PGBackend *be = (PGBackend *) cb_data; + int i, nsplits; + + if (!be || !trans) return; + + pgendStoreOneTransactionOnly (be, trans); + + /* walk over the list of splits */ + nsplits = xaccTransGetNumSplits (trans); + for (i=0; ibuff, be->bufflen, "BEGIN;"); + SEND_QUERY (be); + FLUSH(be->connection); + + /* reset the write flags. We use this to amek sure we don't + * get caught in infinite recursion */ + xaccGroupBeginStagedTransactionTraversals(grp); + pgendStoreGroupNoLock (be, grp); + + /* recursively walk transactions */ + xaccGroupStagedTransactionTraversal (grp, 1, traverse_cb, be); + + snprintf (be->buff, be->bufflen, "COMMIT;"); + SEND_QUERY (be); + FLUSH(be->connection); +} + /* ============================================================= */ /* this routine fills in the structure pointed at by split * with data sucked out of the database @@ -177,6 +320,9 @@ pgend_session_begin (Session *sess, const char * sessionid) { PGBackend *be; + if (!sess) return; + be = (PGBackend *) xaccSessionGetBackend (sess); + ENTER("sessionid=%s\n", sessionid); /* connect to a bogus database ... */ /* hack alert -- clean this up ... */ @@ -195,6 +341,11 @@ pgend_session_begin (Session *sess, const char * sessionid) DEBUGCMD (PQtrace(be->connection, stderr)); +/* hack alert --- */ +/* just a quickie place to duimp stuff */ +xaccGroupSetBackend (xaccSessionGetGroup(sess), &(be->be)); +pgendStoreGroup (be, xaccSessionGetGroup(sess)); + LEAVE("\n"); return NULL; } @@ -214,7 +365,7 @@ pgend_trans_commit_edit (Backend * bend, Transaction * trans) nsplits = xaccTransCountSplits (trans); for (i=0; idbName = NULL; be->connection = NULL; + be->buff = malloc (QBUFSIZE); + be->bufflen = QBUFSIZE; + return (Backend *) be; } diff --git a/src/engine/sql/PostgresBackend.h b/src/engine/sql/PostgresBackend.h index ea33190cee..ad8056810b 100644 --- a/src/engine/sql/PostgresBackend.h +++ b/src/engine/sql/PostgresBackend.h @@ -17,6 +17,10 @@ struct _pgend { /* postgres-specific conection data */ char * dbName; PGconn * connection; + + /* scratch space for constructing queries */ + int bufflen; + char *buff; }; /* diff --git a/src/engine/sql/gnc-init.sql b/src/engine/sql/gnc-init.sql index 3f6e64114e..e893e526ae 100644 --- a/src/engine/sql/gnc-init.sql +++ b/src/engine/sql/gnc-init.sql @@ -10,9 +10,13 @@ CREATE TABLE gncGroup ( childGuid CHAR(32) ); +-- hack alert -- docref ?? + DROP TABLE gncAccount; CREATE TABLE gncAccount ( accountGuid CHAR(32) PRIMARY KEY, + parentGuid CHAR(32), + childrenGuid CHAR(32), accountName VARCHAR(40) DEFAULT 'xoxo', accountCode VARCHAR(8), description VARCHAR(120), @@ -22,12 +26,16 @@ CREATE TABLE gncAccount ( security VARCHAR(8) ); --- initialize with just enough bogus data to run the demo -INSERT INTO gncaccount (accountguid,accountName,description) values - ('asdfasdf','banky','some bogo bank'); -INSERT INTO gncaccount (accountguid,accountName,description) values - ('aqwerqwer','crebit dedit','bankruptcy follows'); +-- hack alert -- docref ?? +DROP TABLE gncTransaction; +CREATE TABLE gncTransaction ( + transGuid CHAR(32) PRIMARY KEY, + date_entered DATETIME, + date_posted DATETIME, + num VARCHAR(8), + description VARCHAR(32) +); -- a gncEntry is what we call 'Split' elsewhere in the engine @@ -44,13 +52,3 @@ CREATE TABLE gncEntry ( share_price FLOAT8 DEFAULT '0.0' ); -DROP TABLE gncTransaction; -CREATE TABLE gncTransaction ( - transGuid CHAR(32) PRIMARY KEY, - date_entered DATETIME, - date_posted DATETIME, - num VARCHAR(8), - description VARCHAR(32) -); - -