more database hacking

git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@2325 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Linas Vepstas 2000-05-15 03:55:04 +00:00
parent 3b1913a29f
commit ccf1944f3a
3 changed files with 203 additions and 43 deletions

View File

@ -21,12 +21,21 @@
static short module = MOD_BACKEND; 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) { \ #define FLUSH(conn) { \
PGresult *result; \ PGresult *result; \
/* complete/commit the transaction, check the status */ \ /* 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. /* This routine stores the indicated group structure into the database.
* It does *not* chase pointers, traverse the tree, etc. * It does *not* chase pointers, traverse the tree, etc.
* It performs no locking.
*/ */
static void static void
@ -55,8 +65,7 @@ pgendStoreOneGroupOnly (PGBackend *be, AccountGroup *grp)
{ {
Account *parent; Account *parent;
const GUID *parent_guid, *grp_guid; const GUID *parent_guid, *grp_guid;
char buff[QBUFSIZE]; int i, nacc;
int i, nacc, rc;
ENTER ("be=%p, grp=%p\n", be, grp); ENTER ("be=%p, grp=%p\n", be, grp);
if (!be || !grp) return; if (!be || !grp) return;
@ -70,7 +79,7 @@ pgendStoreOneGroupOnly (PGBackend *be, AccountGroup *grp)
Account *acc = xaccGroupGetAccount(grp, i); Account *acc = xaccGroupGetAccount(grp, i);
/* hack alert -- values should be escaped so that no '' apear in them */ /* hack alert -- values should be escaped so that no '' apear in them */
snprintf (buff, QBUFSIZE, snprintf (be->buff, be->bufflen,
"INSERT INTO gncGroup " "INSERT INTO gncGroup "
"(groupGuid, parentGuid, childGuid)" "(groupGuid, parentGuid, childGuid)"
" values " " values "
@ -79,14 +88,8 @@ pgendStoreOneGroupOnly (PGBackend *be, AccountGroup *grp)
guid_to_string(parent_guid), guid_to_string(parent_guid),
guid_to_string(xaccAccountGetGUID (acc)) guid_to_string(xaccAccountGetGUID (acc))
); );
rc = PQsendQuery (be->connection, buff);
if (!rc) SEND_QUERY(be);
{
PERR("send query failed:\n"
"\t%s", PQerrorMessage(be->connection));
PQfinish (be->connection);
return;
}
/* complete/commit the transaction, check the status */ /* complete/commit the transaction, check the status */
FLUSH(be->connection); FLUSH(be->connection);
@ -95,16 +98,88 @@ pgendStoreOneGroupOnly (PGBackend *be, AccountGroup *grp)
LEAVE ("\n"); 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 /* this routine stores the indicated split in the database
*/ */
static void static void
pgendStoreSplit (PGBackend *be, Split *split) pgendStoreOneSplitOnly (PGBackend *be, Split *split)
{ {
Timespec ts; Timespec ts;
char buff[QBUFSIZE];
int rc;
ENTER ("be=%p, split=%p\n", be, split); ENTER ("be=%p, split=%p\n", be, split);
if (!be || !split) return; if (!be || !split) return;
@ -113,7 +188,7 @@ pgendStoreSplit (PGBackend *be, Split *split)
xaccSplitGetDateReconciledTS (split, &ts); xaccSplitGetDateReconciledTS (split, &ts);
/* hack alert -- values should be escaped so that no '' apear in them */ /* hack alert -- values should be escaped so that no '' apear in them */
snprintf (buff, QBUFSIZE, snprintf (be->buff, be->bufflen,
"INSERT INTO gncEntry " "INSERT INTO gncEntry "
"(entryGuid, accountGuid, transGuid, memo, action," "(entryGuid, accountGuid, transGuid, memo, action,"
"reconciled, amount, share_price)" "reconciled, amount, share_price)"
@ -128,14 +203,8 @@ pgendStoreSplit (PGBackend *be, Split *split)
xaccSplitGetShareAmount(split), xaccSplitGetShareAmount(split),
xaccSplitGetSharePrice(split) xaccSplitGetSharePrice(split)
); );
rc = PQsendQuery (be->connection, buff);
if (!rc) SEND_QUERY (be);
{
PERR("send query failed:\n"
"\t%s", PQerrorMessage(be->connection));
PQfinish (be->connection);
return;
}
/* complete/commit the transaction, check the status */ /* complete/commit the transaction, check the status */
FLUSH(be->connection); FLUSH(be->connection);
@ -143,6 +212,80 @@ pgendStoreSplit (PGBackend *be, Split *split)
LEAVE ("\n"); 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; i<nsplits; i++) {
Split * s = xaccTransGetSplit (trans, i);
pgendStoreOneSplitOnly (be, s);
}
return 0;
}
static void
pgendStoreGroupNoLock (PGBackend *be, AccountGroup *grp)
{
int i, nacc;
if (!be || !grp) return;
/* first, store the top-group */
pgendStoreOneGroupOnly (be, grp);
/* next, walk the account tree, and store subaccounts */
nacc = xaccGroupGetNumAccounts(grp);
for (i=0; i<nacc; i++) {
AccountGroup *subgrp;
Account *acc = xaccGroupGetAccount(grp, i);
pgendStoreOneAccountOnly (be, acc);
/* recursively walk to child accounts */
subgrp = xaccAccountGetChildren (acc);
if (subgrp) pgendStoreGroupNoLock(be, subgrp);
}
}
static void
pgendStoreGroup (PGBackend *be, AccountGroup *grp)
{
ENTER ("be=%p, grp=%p\n", be, grp);
if (!be || !grp) return;
/* lock it up so that we store atomically */
snprintf (be->buff, 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 /* this routine fills in the structure pointed at by split
* with data sucked out of the database * with data sucked out of the database
@ -177,6 +320,9 @@ pgend_session_begin (Session *sess, const char * sessionid)
{ {
PGBackend *be; PGBackend *be;
if (!sess) return;
be = (PGBackend *) xaccSessionGetBackend (sess);
ENTER("sessionid=%s\n", sessionid); ENTER("sessionid=%s\n", sessionid);
/* connect to a bogus database ... */ /* connect to a bogus database ... */
/* hack alert -- clean this up ... */ /* hack alert -- clean this up ... */
@ -195,6 +341,11 @@ pgend_session_begin (Session *sess, const char * sessionid)
DEBUGCMD (PQtrace(be->connection, stderr)); 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"); LEAVE("\n");
return NULL; return NULL;
} }
@ -214,7 +365,7 @@ pgend_trans_commit_edit (Backend * bend, Transaction * trans)
nsplits = xaccTransCountSplits (trans); nsplits = xaccTransCountSplits (trans);
for (i=0; i<nsplits; i++) { for (i=0; i<nsplits; i++) {
Split *s = xaccTransGetSplit (trans, i); Split *s = xaccTransGetSplit (trans, i);
pgendStoreSplit (be, s); pgendStoreOneSplitOnly (be, s);
} }
#if 0 #if 0
@ -234,6 +385,10 @@ pgend_trans_commit_edit (Backend * bend, Transaction * trans)
/* ============================================================= */ /* ============================================================= */
/* hack alert -- this is the query buffer, it might be too small.
we need to make it dynamic sized */
#define QBUFSIZE 16350
Backend * Backend *
pgendNew (void) pgendNew (void)
{ {
@ -255,6 +410,9 @@ pgendNew (void)
be->dbName = NULL; be->dbName = NULL;
be->connection = NULL; be->connection = NULL;
be->buff = malloc (QBUFSIZE);
be->bufflen = QBUFSIZE;
return (Backend *) be; return (Backend *) be;
} }

View File

@ -17,6 +17,10 @@ struct _pgend {
/* postgres-specific conection data */ /* postgres-specific conection data */
char * dbName; char * dbName;
PGconn * connection; PGconn * connection;
/* scratch space for constructing queries */
int bufflen;
char *buff;
}; };
/* /*

View File

@ -10,9 +10,13 @@ CREATE TABLE gncGroup (
childGuid CHAR(32) childGuid CHAR(32)
); );
-- hack alert -- docref ??
DROP TABLE gncAccount; DROP TABLE gncAccount;
CREATE TABLE gncAccount ( CREATE TABLE gncAccount (
accountGuid CHAR(32) PRIMARY KEY, accountGuid CHAR(32) PRIMARY KEY,
parentGuid CHAR(32),
childrenGuid CHAR(32),
accountName VARCHAR(40) DEFAULT 'xoxo', accountName VARCHAR(40) DEFAULT 'xoxo',
accountCode VARCHAR(8), accountCode VARCHAR(8),
description VARCHAR(120), description VARCHAR(120),
@ -22,12 +26,16 @@ CREATE TABLE gncAccount (
security VARCHAR(8) security VARCHAR(8)
); );
-- initialize with just enough bogus data to run the demo -- hack alert -- docref ??
INSERT INTO gncaccount (accountguid,accountName,description) values
('asdfasdf','banky','some bogo bank');
INSERT INTO gncaccount (accountguid,accountName,description) values
('aqwerqwer','crebit dedit','bankruptcy follows');
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 -- a gncEntry is what we call 'Split' elsewhere in the engine
@ -44,13 +52,3 @@ CREATE TABLE gncEntry (
share_price FLOAT8 DEFAULT '0.0' 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)
);