mirror of
https://github.com/Gnucash/gnucash.git
synced 2025-02-25 18:55:30 -06:00
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:
parent
3b1913a29f
commit
ccf1944f3a
@ -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;
|
||||
}
|
||||
|
||||
|
@ -17,6 +17,10 @@ struct _pgend {
|
||||
/* postgres-specific conection data */
|
||||
char * dbName;
|
||||
PGconn * connection;
|
||||
|
||||
/* scratch space for constructing queries */
|
||||
int bufflen;
|
||||
char *buff;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -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)
|
||||
);
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user