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;
/* 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; 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
* 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; i<nsplits; i++) {
Split *s = xaccTransGetSplit (trans, i);
pgendStoreSplit (be, s);
pgendStoreOneSplitOnly (be, s);
}
#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 *
pgendNew (void)
{
@ -255,6 +410,9 @@ pgendNew (void)
be->dbName = NULL;
be->connection = NULL;
be->buff = malloc (QBUFSIZE);
be->bufflen = QBUFSIZE;
return (Backend *) be;
}

View File

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

View File

@ -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)
);