Matthew Vanecek's PG patches...

* src/backend/postgres/Makefile.am: Changed the .sql.c target to
	not echo the beginning and ending quotes.  This is part of the
	gcc 3.x compatibility changes.

	* src/backend/postgres/PostgresBackend.c: Made some whitespace changes
	  for readability.
	- (pgend_book_load_poll): Commented out a PWARN about the old book
	  list not being empty. See added comments for why.
	- (pgend_book_load_poll): added a gnc_session_set_book() call so that
	  the session would have the correct book loaded (i.e., the book
	  that's stored in the DB).

	* src/backend/postgres/*.sql: Enclosed each line in a set of
	quotes "..".  The "multi-line literals" were causing compile errors
	for gcc 3.x.

	* src/backend/postgres/gncquery.c: ran indent on the file.
	- (STRING_TERM): Changed the comparison on STRING_MATCH_NORMAL to
	  STRING_MATCH_CASEINSENSITIVE for purposes of adding a '*' to the
	  comparison operator "~".  The code was writing a "=*" which is
	  invalid, but "~*" is valid for case-insensitive regex searches.
	- (sqlQuery_build): Added a "more_and = 0" to the final if statement
	  of the "for (il = qterms; il; il = il->next)" loop.  This will
	  prevent a stray "AND" being appended to the end of the "WHERE" clause
	  of a dynamic query.

	* src/backend/postgres/kvp-sql (store_cb): In "case KVP_TYPE_TIMESPEC",
	changed the 'cb_data->stype = "timespec"' to 'cb_data->stype = "time"'.
	The destination field in the database is defined as 4 characters, and
	the extra chars in stype were causing an insertion error.

	* src/backend/postgres/putil.h (FINISH_QUERY): Changed the error to use
	PQresultErrorMessage() instead of PQerrorMessage().

	* src/backend/postgres/test/db-control.sh (our_pg_ctl): Changed the
	script to return -1 if pg_ctl was not found in PATH.

	* src/backend/postgres/test/run-tests.sh: If db-control.sh returns
	failure, the attempt to connect to $PGHOST on $PGPORT.

	* src/backend/postgres/test/test-db.c: Included QueryNew.h.  Added the
	  _dbinfo struct to pass host, port, dbname, and mode information
	  around. Everywhere that used db_name/mode is now using DbInfor->*.
	- Ran indent on the file.
	- Added a drop_database function to call dropdb on the database used
	  for the tests.  This eventually needs to be changed so that every
	  "return FALSE" first calls gnc_session_destroy(session), before this
	  new function is called.
	- (db_file_url): Changed the function to handle TCP connections as well
	  as socket connections.
	- (load_db_file): Added a PGBackend object from which to get a PGconn
	  connection to store in DbInfo.
	- (test_raw_query): Added a call to gncQueryPrint() if
	  gnc_should_log(MOD_TEST, GNC_LOG_DETAIL)


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@7894 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Derek Atkins 2003-01-30 04:06:38 +00:00
parent bd57bf6706
commit eb3c5eb238
14 changed files with 2201 additions and 2085 deletions

View File

@ -1,3 +1,60 @@
2003-01-29 Matthew Vanecek <mevanecek@yahoo.com>
* src/backend/postgres/Makefile.am: Changed the .sql.c target to
not echo the beginning and ending quotes. This is part of the
gcc 3.x compatibility changes.
* src/backend/postgres/PostgresBackend.c: Made some whitespace changes
for readability.
- (pgend_book_load_poll): Commented out a PWARN about the old book
list not being empty. See added comments for why.
- (pgend_book_load_poll): added a gnc_session_set_book() call so that
the session would have the correct book loaded (i.e., the book
that's stored in the DB).
* src/backend/postgres/*.sql: Enclosed each line in a set of
quotes "..". The "multi-line literals" were causing compile errors
for gcc 3.x.
* src/backend/postgres/gncquery.c: ran indent on the file.
- (STRING_TERM): Changed the comparison on STRING_MATCH_NORMAL to
STRING_MATCH_CASEINSENSITIVE for purposes of adding a '*' to the
comparison operator "~". The code was writing a "=*" which is
invalid, but "~*" is valid for case-insensitive regex searches.
- (sqlQuery_build): Added a "more_and = 0" to the final if statement
of the "for (il = qterms; il; il = il->next)" loop. This will
prevent a stray "AND" being appended to the end of the "WHERE" clause
of a dynamic query.
* src/backend/postgres/kvp-sql (store_cb): In "case KVP_TYPE_TIMESPEC",
changed the 'cb_data->stype = "timespec"' to 'cb_data->stype = "time"'.
The destination field in the database is defined as 4 characters, and
the extra chars in stype were causing an insertion error.
* src/backend/postgres/putil.h (FINISH_QUERY): Changed the error to use
PQresultErrorMessage() instead of PQerrorMessage().
* src/backend/postgres/test/db-control.sh (our_pg_ctl): Changed the
script to return -1 if pg_ctl was not found in PATH.
* src/backend/postgres/test/run-tests.sh: If db-control.sh returns
failure, the attempt to connect to $PGHOST on $PGPORT.
* src/backend/postgres/test/test-db.c: Included QueryNew.h. Added the
_dbinfo struct to pass host, port, dbname, and mode information
around. Everywhere that used db_name/mode is now using DbInfor->*.
- Ran indent on the file.
- Added a drop_database function to call dropdb on the database used
for the tests. This eventually needs to be changed so that every
"return FALSE" first calls gnc_session_destroy(session), before this
new function is called.
- (db_file_url): Changed the function to handle TCP connections as well
as socket connections.
- (load_db_file): Added a PGBackend object from which to get a PGconn
connection to store in DbInfo.
- (test_raw_query): Added a call to gncQueryPrint() if
gnc_should_log(MOD_TEST, GNC_LOG_DETAIL)
2003-01-29 Herbert Thoma <herbie@hthoma.de> 2003-01-29 Herbert Thoma <herbie@hthoma.de>
* src/report/standard-reports/cash-flow.scm: only asset accounts * src/report/standard-reports/cash-flow.scm: only asset accounts

View File

@ -108,8 +108,6 @@ $(M4_SRC): table.m4
m4 -I ${srcdir} $< > $@ m4 -I ${srcdir} $< > $@
.sql.c: .sql.c:
echo \" > $@ echo "\"-- DO NOT EDIT THIS FILE. IT IS AUTOGENERATED.\"" > $@
echo "-- DO NOT EDIT THIS FILE. IT IS AUTOGENERATED." >> $@
cat $< >> $@ cat $< >> $@
echo \" >> $@

View File

@ -1473,7 +1473,6 @@ pgend_session_end (Backend *bend)
* the poll & event style load, where only the accounts, * the poll & event style load, where only the accounts,
* and never the transactions, need to be loaded. * and never the transactions, need to be loaded.
*/ */
static void static void
pgend_book_load_poll (Backend *bend, GNCBook *book) pgend_book_load_poll (Backend *bend, GNCBook *book)
{ {
@ -1493,12 +1492,20 @@ pgend_book_load_poll (Backend *bend, GNCBook *book)
if (be->blist) if (be->blist)
{ {
/* XXX not clear what this means ... should we free old books ?? */ /* XXX not clear what this means ... should we free old books ?? */
PWARN ("old book list not empty "); /* The old book list is set by the session when the session is
* created. It is an empty book, and should be discarded in favor
* of the Book retrieved from the database.
* PWARN ("old book list not empty ");
*/
g_list_free (be->blist); g_list_free (be->blist);
be->blist = NULL; be->blist = NULL;
} }
pgend_set_book (be, book); pgend_set_book (be, book);
pgendGetBook (be, book); pgendGetBook (be, book);
gnc_session_set_book(be->session, book);
PINFO("Book GUID = %s\n",
guid_to_string(gnc_book_get_guid(book)));
pgendGetAllAccountsInBook (be, book); pgendGetAllAccountsInBook (be, book);
@ -2272,7 +2279,6 @@ pgend_session_begin (Backend *backend,
be->be.begin = pgend_do_begin; be->be.begin = pgend_do_begin;
be->be.commit = pgend_do_commit; be->be.commit = pgend_do_commit;
be->be.rollback = pgend_do_rollback; be->be.rollback = pgend_do_rollback;
be->be.compile_query = NULL; be->be.compile_query = NULL;
be->be.free_query = NULL; be->be.free_query = NULL;
be->be.run_query = NULL; be->be.run_query = NULL;

View File

@ -1,69 +1,69 @@
-- "-- \n"
-- FILE: "-- FILE: \n"
-- functions.sql "-- functions.sql \n"
-- "-- \n"
-- FUNCTION: "-- FUNCTION: \n"
-- Define assorted utility functions. "-- Define assorted utility functions. \n"
-- "-- \n"
-- HISTORY: "-- HISTORY: \n"
-- Copyright (C) 2001 Linas Vepstas "-- Copyright (C) 2001 Linas Vepstas \n"
-- "-- \n"
" \n"
" \n"
-- utility functions to compute checkpoint balance subtotals "-- utility functions to compute checkpoint balance subtotals \n"
" \n"
CREATE FUNCTION gncSubtotalBalance (CHAR(32), TIMESTAMP, TIMESTAMP) "CREATE FUNCTION gncSubtotalBalance (CHAR(32), TIMESTAMP, TIMESTAMP) \n"
RETURNS INT8 " RETURNS INT8 \n"
AS 'SELECT INT8(sum(gncEntry.amount)) " AS 'SELECT INT8(sum(gncEntry.amount)) \n"
FROM gncEntry, gncTransaction " FROM gncEntry, gncTransaction \n"
WHERE " WHERE \n"
gncEntry.accountGuid = $1 AND " gncEntry.accountGuid = $1 AND \n"
gncEntry.transGuid = gncTransaction.transGuid AND " gncEntry.transGuid = gncTransaction.transGuid AND \n"
gncTransaction.date_posted BETWEEN $2 AND $3' " gncTransaction.date_posted BETWEEN $2 AND $3' \n"
LANGUAGE 'sql'; " LANGUAGE 'sql'; \n"
" \n"
CREATE FUNCTION gncSubtotalClearedBalance (CHAR(32), TIMESTAMP, TIMESTAMP) "CREATE FUNCTION gncSubtotalClearedBalance (CHAR(32), TIMESTAMP, TIMESTAMP) \n"
RETURNS INT8 " RETURNS INT8 \n"
AS 'SELECT INT8(sum(gncEntry.amount)) " AS 'SELECT INT8(sum(gncEntry.amount)) \n"
FROM gncEntry, gncTransaction " FROM gncEntry, gncTransaction \n"
WHERE " WHERE \n"
gncEntry.accountGuid = $1 AND " gncEntry.accountGuid = $1 AND \n"
gncEntry.transGuid = gncTransaction.transGuid AND " gncEntry.transGuid = gncTransaction.transGuid AND \n"
gncTransaction.date_posted BETWEEN $2 AND $3 AND " gncTransaction.date_posted BETWEEN $2 AND $3 AND \n"
gncEntry.reconciled <> \\'n\\'' " gncEntry.reconciled <> \\'n\\'' \n"
LANGUAGE 'sql'; " LANGUAGE 'sql'; \n"
" \n"
CREATE FUNCTION gncSubtotalReconedBalance (CHAR(32), TIMESTAMP, TIMESTAMP) "CREATE FUNCTION gncSubtotalReconedBalance (CHAR(32), TIMESTAMP, TIMESTAMP) \n"
RETURNS INT8 " RETURNS INT8 \n"
AS 'SELECT INT8(sum(gncEntry.amount)) " AS 'SELECT INT8(sum(gncEntry.amount)) \n"
FROM gncEntry, gncTransaction " FROM gncEntry, gncTransaction \n"
WHERE " WHERE \n"
gncEntry.accountGuid = $1 AND " gncEntry.accountGuid = $1 AND \n"
gncEntry.transGuid = gncTransaction.transGuid AND " gncEntry.transGuid = gncTransaction.transGuid AND \n"
gncTransaction.date_posted BETWEEN $2 AND $3 AND " gncTransaction.date_posted BETWEEN $2 AND $3 AND \n"
(gncEntry.reconciled = \\'y\\' OR " (gncEntry.reconciled = \\'y\\' OR \n"
gncEntry.reconciled = \\'f\\')' " gncEntry.reconciled = \\'f\\')' \n"
LANGUAGE 'sql'; " LANGUAGE 'sql'; \n"
" \n"
-- helper functions. These intentionally use the 'wrong' fraction. "-- helper functions. These intentionally use the 'wrong' fraction. \n"
-- This is because value_frac * amount * price = value * amount_frac "-- This is because value_frac * amount * price = value * amount_frac \n"
" \n"
CREATE FUNCTION gncHelperPrVal (gncEntry) "CREATE FUNCTION gncHelperPrVal (gncEntry) \n"
RETURNS INT8 " RETURNS INT8 \n"
AS 'SELECT abs($1 . value * gncCommodity.fraction) " AS 'SELECT abs($1 . value * gncCommodity.fraction) \n"
FROM gncEntry, gncAccount, gncCommodity " FROM gncEntry, gncAccount, gncCommodity \n"
WHERE " WHERE \n"
$1 . accountGuid = gncAccount.accountGuid AND " $1 . accountGuid = gncAccount.accountGuid AND \n"
gncAccount.commodity = gncCommodity.commodity' " gncAccount.commodity = gncCommodity.commodity' \n"
LANGUAGE 'sql'; " LANGUAGE 'sql'; \n"
" \n"
CREATE FUNCTION gncHelperPrAmt (gncEntry) "CREATE FUNCTION gncHelperPrAmt (gncEntry) \n"
RETURNS INT8 " RETURNS INT8 \n"
AS 'SELECT abs($1 . amount * gncCommodity.fraction) " AS 'SELECT abs($1 . amount * gncCommodity.fraction) \n"
FROM gncEntry, gncTransaction, gncCommodity " FROM gncEntry, gncTransaction, gncCommodity \n"
WHERE " WHERE \n"
$1 . transGuid = gncTransaction.transGuid AND " $1 . transGuid = gncTransaction.transGuid AND \n"
gncTransaction.currency = gncCommodity.commodity' " gncTransaction.currency = gncCommodity.commodity' \n"
LANGUAGE 'sql'; " LANGUAGE 'sql'; \n"
" \n"
-- end of file "-- end of file";

View File

@ -83,7 +83,8 @@ sqlQuery_new(void)
void void
sql_Query_destroy(sqlQuery * sq) sql_Query_destroy(sqlQuery * sq)
{ {
if (!sq) return; if (!sq)
return;
g_free(sq->q_base); g_free(sq->q_base);
sqlEscape_destroy(sq->escape); sqlEscape_destroy(sq->escape);
g_free(sq); g_free(sq);
@ -195,12 +196,9 @@ sql_sort_order (char *p, QueryNewSort_t sort)
p = sql_sort_get_type(p, path); p = sql_sort_get_type(p, path);
} }
if (TRUE == increasing) if (TRUE == increasing) {
{
p = stpcpy(p, " DESC "); p = stpcpy(p, " DESC ");
} } else {
else
{
p = stpcpy(p, " ASC "); p = stpcpy(p, " ASC ");
} }
@ -218,8 +216,7 @@ sql_sort_distinct (char *p, QueryNewSort_t sort)
path = gncQuerySortGetParamPath(sort); path = gncQuerySortGetParamPath(sort);
if (NULL != path) if (NULL != path) {
{
p = stpcpy(p, ", "); p = stpcpy(p, ", ");
} }
@ -268,8 +265,7 @@ sql_sort_need_account (Query *q)
gncQueryGetSorts(q, &s1, &s2, &s3); gncQueryGetSorts(q, &s1, &s2, &s3);
need_account = sql_sort_sort_need_account(s1) || need_account = sql_sort_sort_need_account(s1) ||
sql_sort_sort_need_account (s2) || sql_sort_sort_need_account(s2) || sql_sort_sort_need_account(s3);
sql_sort_sort_need_account (s3);
return need_account; return need_account;
} }
@ -305,8 +301,7 @@ sql_sort_need_entry (Query *q)
gncQueryGetSorts(q, &s1, &s2, &s3); gncQueryGetSorts(q, &s1, &s2, &s3);
need_entry = sql_sort_sort_need_entry(s1) || need_entry = sql_sort_sort_need_entry(s1) ||
sql_sort_sort_need_entry (s2) || sql_sort_sort_need_entry(s2) || sql_sort_sort_need_entry(s3);
sql_sort_sort_need_entry (s3);
return need_entry; return need_entry;
} }
@ -330,7 +325,7 @@ sql_sort_need_entry (Query *q)
sq->pq = stpcpy(sq->pq, fieldname " ~"); \ sq->pq = stpcpy(sq->pq, fieldname " ~"); \
else \ else \
sq->pq = stpcpy(sq->pq, fieldname " ="); \ sq->pq = stpcpy(sq->pq, fieldname " ="); \
if (pdata->options == STRING_MATCH_NORMAL) { \ if (pdata->options == STRING_MATCH_CASEINSENSITIVE) { \
sq->pq = stpcpy(sq->pq, "*"); \ sq->pq = stpcpy(sq->pq, "*"); \
} \ } \
sq->pq = stpcpy(sq->pq, " '"); \ sq->pq = stpcpy(sq->pq, " '"); \
@ -426,8 +421,7 @@ sql_sort_need_entry (Query *q)
static const char * static const char *
kvp_table_name(kvp_value_t value_t) kvp_table_name(kvp_value_t value_t)
{ {
switch (value_t) switch (value_t) {
{
case KVP_TYPE_GINT64: case KVP_TYPE_GINT64:
return "gnckvpvalue_int64"; return "gnckvpvalue_int64";
@ -458,8 +452,7 @@ kvp_path_name (GSList *path)
GString *s = g_string_new(NULL); GString *s = g_string_new(NULL);
char *name; char *name;
for ( ; path; path = path->next) for (; path; path = path->next) {
{
g_string_append_c(s, '/'); g_string_append_c(s, '/');
g_string_append(s, path->data); g_string_append(s, path->data);
} }
@ -473,8 +466,7 @@ kvp_path_name (GSList *path)
static const char * static const char *
compare_op_name(query_compare_t how) compare_op_name(query_compare_t how)
{ {
switch (how) switch (how) {
{
case COMPARE_LT: case COMPARE_LT:
return " < "; return " < ";
@ -510,8 +502,7 @@ kvp_left_operand (kvp_value *value)
kvptable = kvp_table_name(value_t); kvptable = kvp_table_name(value_t);
switch (value_t) switch (value_t) {
{
case KVP_TYPE_GINT64: case KVP_TYPE_GINT64:
case KVP_TYPE_DOUBLE: case KVP_TYPE_DOUBLE:
case KVP_TYPE_GUID: case KVP_TYPE_GUID:
@ -542,11 +533,11 @@ kvp_right_operand (sqlQuery *sq, kvp_value *value)
kvptable = kvp_table_name(value_t); kvptable = kvp_table_name(value_t);
switch (value_t) switch (value_t) {
{
case KVP_TYPE_GINT64: case KVP_TYPE_GINT64:
return g_strdup_printf("%lld", return g_strdup_printf("%lld",
(long long int) kvp_value_get_gint64 (value)); (long long int)
kvp_value_get_gint64(value));
case KVP_TYPE_DOUBLE: case KVP_TYPE_DOUBLE:
return g_strdup_printf(SQL_DBL_FMT, kvp_value_get_double(value)); return g_strdup_printf(SQL_DBL_FMT, kvp_value_get_double(value));
@ -631,8 +622,7 @@ sqlQuery_kvp_build (sqlQuery *sq, GSList *sort_path, query_compare_t how,
value_t = kvp_value_get_type(kpd->value); value_t = kvp_value_get_type(kpd->value);
if (value_t == KVP_TYPE_GUID && how != COMPARE_EQUAL) if (value_t == KVP_TYPE_GUID && how != COMPARE_EQUAL) {
{
PWARN("guid non-equality comparison not supported"); PWARN("guid non-equality comparison not supported");
return; return;
} }
@ -657,16 +647,13 @@ sqlQuery_kvp_build (sqlQuery *sq, GSList *sort_path, query_compare_t how,
if (invert) if (invert)
sq->pq = stpcpy(sq->pq, "NOT "); sq->pq = stpcpy(sq->pq, "NOT ");
sq->pq = stpcpy (sq->pq, sq->pq = stpcpy(sq->pq, " EXISTS ( SELECT true " " WHERE ");
" EXISTS ( SELECT true "
" WHERE ");
sq->pq = stpcpy(sq->pq, "gncPathCache.path = '"); sq->pq = stpcpy(sq->pq, "gncPathCache.path = '");
sq->pq = stpcpy(sq->pq, sqlEscapeString(sq->escape, path)); sq->pq = stpcpy(sq->pq, sqlEscapeString(sq->escape, path));
sq->pq = stpcpy(sq->pq, "'"); sq->pq = stpcpy(sq->pq, "'");
for (node = list; node; node = node->next) for (node = list; node; node = node->next) {
{
sq->pq = stpcpy(sq->pq, " AND "); sq->pq = stpcpy(sq->pq, " AND ");
add_kvp_clause(sq, kvptable, node->data, left, op, right); add_kvp_clause(sq, kvptable, node->data, left, op, right);
} }
@ -730,7 +717,8 @@ sqlQuery_build (sqlQuery *sq, Query *q)
gboolean need_account = FALSE; gboolean need_account = FALSE;
gboolean need_entry = FALSE; gboolean need_entry = FALSE;
if (!sq || !q) return NULL; if (!sq || !q)
return NULL;
/* Only Split searches are allowed */ /* Only Split searches are allowed */
if (safe_strcmp(gncQueryGetSearchFor(q), GNC_ID_SPLIT)) { if (safe_strcmp(gncQueryGetSearchFor(q), GNC_ID_SPLIT)) {
@ -742,13 +730,11 @@ sqlQuery_build (sqlQuery *sq, Query *q)
* tables. See note above for details. */ * tables. See note above for details. */
qterms = gncQueryGetTerms(q); qterms = gncQueryGetTerms(q);
for (il=qterms; il; il=il->next) for (il = qterms; il; il = il->next) {
{
/* andterms is GList of query terms that must be anded */ /* andterms is GList of query terms that must be anded */
andterms = il->data; andterms = il->data;
for (jl=andterms; jl; jl=jl->next) for (jl = andterms; jl; jl = jl->next) {
{
qt = (QueryNewTerm_t) jl->data; qt = (QueryNewTerm_t) jl->data;
pd = gncQueryTermGetPredData(qt); pd = gncQueryTermGetPredData(qt);
path = gncQueryTermGetParamPath(qt); path = gncQueryTermGetParamPath(qt);
@ -788,8 +774,7 @@ sqlQuery_build (sqlQuery *sq, Query *q)
/* reset the buffer pointers */ /* reset the buffer pointers */
sq->pq = sq->q_base; sq->pq = sq->q_base;
sq->pq = stpcpy(sq->pq, sq->pq = stpcpy(sq->pq, "SELECT DISTINCT gncTransaction.* ");
"SELECT DISTINCT gncTransaction.* ");
gncQueryGetSorts(q, &s1, &s2, &s3); gncQueryGetSorts(q, &s1, &s2, &s3);
@ -805,14 +790,12 @@ sqlQuery_build (sqlQuery *sq, Query *q)
if (need_trans_commodity) if (need_trans_commodity)
tables = g_list_prepend(tables, "gncCommodity trans_com"); tables = g_list_prepend(tables, "gncCommodity trans_com");
if (tables) if (tables) {
{
GList *node; GList *node;
sq->pq = stpcpy(sq->pq, " FROM "); sq->pq = stpcpy(sq->pq, " FROM ");
for (node = tables; node; node = node->next) for (node = tables; node; node = node->next) {
{
sq->pq = stpcpy(sq->pq, node->data); sq->pq = stpcpy(sq->pq, node->data);
if (node->next) if (node->next)
sq->pq = stpcpy(sq->pq, ", "); sq->pq = stpcpy(sq->pq, ", ");
@ -823,14 +806,12 @@ sqlQuery_build (sqlQuery *sq, Query *q)
sq->pq = stpcpy(sq->pq, " WHERE "); sq->pq = stpcpy(sq->pq, " WHERE ");
if (need_entry || need_account) if (need_entry || need_account) {
{
sq->pq = stpcpy(sq->pq, sq->pq = stpcpy(sq->pq,
" gncEntry.transGuid = gncTransaction.transGuid AND "); " gncEntry.transGuid = gncTransaction.transGuid AND ");
} }
if (need_account) if (need_account) {
{
sq->pq = stpcpy(sq->pq, sq->pq = stpcpy(sq->pq,
" gncEntry.accountGuid = gncAccount.accountGuid AND "); " gncEntry.accountGuid = gncAccount.accountGuid AND ");
} }
@ -842,25 +823,25 @@ sqlQuery_build (sqlQuery *sq, Query *q)
* that must be anded. Out strategy is to build the sql query * that must be anded. Out strategy is to build the sql query
* of the AND terms first, and OR these together ... * of the AND terms first, and OR these together ...
*/ */
for (il=qterms; il; il=il->next) for (il = qterms; il; il = il->next) {
{
/* andterms is GList of query terms that must be anded */ /* andterms is GList of query terms that must be anded */
andterms = il->data; andterms = il->data;
/* if there are andterms, open a brace */ /* if there are andterms, open a brace */
if (andterms) if (andterms) {
{
/* concatenate additional OR terms */ /* concatenate additional OR terms */
if (more_or) sq->pq = stpcpy (sq->pq, " OR "); if (more_or)
sq->pq = stpcpy(sq->pq, " OR ");
more_or = 1; more_or = 1;
sq->pq = stpcpy(sq->pq, "("); sq->pq = stpcpy(sq->pq, "(");
} }
more_and = 0; more_and = 0;
for (jl=andterms; jl; jl=jl->next) for (jl = andterms; jl; jl = jl->next) {
{
/* concatencate more terms together */ /* concatencate more terms together */
if(more_and) sq->pq = stpcpy(sq->pq, " AND "); if (more_and) {
sq->pq = stpcpy(sq->pq, " AND ");
}
more_and = 1; more_and = 1;
qt = (QueryNewTerm_t) jl->data; qt = (QueryNewTerm_t) jl->data;
@ -891,18 +872,21 @@ sqlQuery_build (sqlQuery *sq, Query *q)
} else if (!safe_strcmp(path->data, SPLIT_TRANS) && } else if (!safe_strcmp(path->data, SPLIT_TRANS) &&
!safe_strcmp(path->next->data, TRANS_SPLITLIST) && !safe_strcmp(path->next->data, TRANS_SPLITLIST) &&
!safe_strcmp (path->next->next->data, SPLIT_ACCOUNT_GUID)) { !safe_strcmp(path->next->next->data,
SPLIT_ACCOUNT_GUID)) {
field = "gncEntry.accountGUID"; field = "gncEntry.accountGUID";
g_assert(pdata->options == GUID_MATCH_ALL); g_assert(pdata->options == GUID_MATCH_ALL);
} else if (!safe_strcmp(path->data, QUERY_PARAM_BOOK) &&
!safe_strcmp(path->next->data, QUERY_PARAM_GUID)) {
/* XXX: Need to support the Book GUID? (gncAccount.bookGUID) */
field = "gncAccount.bookGUID";
g_assert(pdata->options != GUID_MATCH_ALL);
} else { } else {
PINFO("Unknown GUID parameter, %s", (char *)path->data); PINFO("Unknown GUID parameter, %s", (char *)path->data);
/* XXX: Need to support the Book GUID? (gncAccount.bookGUID) */
} }
if (field != NULL) { if (field != NULL) {
if (invert) if (invert)
sq->pq = stpcpy(sq->pq, "NOT "); sq->pq = stpcpy(sq->pq, "NOT ");
@ -918,7 +902,9 @@ sqlQuery_build (sqlQuery *sq, Query *q)
case GUID_MATCH_ANY: case GUID_MATCH_ANY:
sq->pq = stpcpy(sq->pq, field); sq->pq = stpcpy(sq->pq, field);
sq->pq = stpcpy(sq->pq, "='"); sq->pq = stpcpy(sq->pq, "='");
sq->pq = guid_to_string_buff ((GUID*) node->data, sq->pq); sq->pq =
guid_to_string_buff((GUID *) node->data,
sq->pq);
sq->pq = stpcpy(sq->pq, "'"); sq->pq = stpcpy(sq->pq, "'");
break; break;
@ -927,15 +913,17 @@ sqlQuery_build (sqlQuery *sq, Query *q)
" EXISTS ( SELECT true FROM gncEntry e" " EXISTS ( SELECT true FROM gncEntry e"
" WHERE " " WHERE "
"e.transGuid = gncTransaction.transGuid" "e.transGuid = gncTransaction.transGuid"
" AND " " AND " "e.accountGuid='");
"e.accountGuid='"); sq->pq =
sq->pq = guid_to_string_buff ((GUID*) node->data, sq->pq); guid_to_string_buff((GUID *) node->data,
sq->pq);
sq->pq = stpcpy(sq->pq, "')"); sq->pq = stpcpy(sq->pq, "')");
break; break;
default: default:
PERR ("unexpected guid match type: %d", pdata->options); PERR("unexpected guid match type: %d",
pdata->options);
break; break;
} }
@ -951,7 +939,8 @@ sqlQuery_build (sqlQuery *sq, Query *q)
break; break;
default: default:
PERR ("unexpected account match type: %d", pdata->options); PERR("unexpected account match type: %d",
pdata->options);
break; break;
} }
} }
@ -1046,7 +1035,8 @@ sqlQuery_build (sqlQuery *sq, Query *q)
sq->pq = stpcpy(sq->pq, field); sq->pq = stpcpy(sq->pq, field);
sq->pq = stpcpy(sq->pq, op); sq->pq = stpcpy(sq->pq, op);
sq->pq = stpcpy(sq->pq, "'"); sq->pq = stpcpy(sq->pq, "'");
sq->pq = gnc_timespec_to_iso8601_buff (pdata->date, sq->pq); sq->pq =
gnc_timespec_to_iso8601_buff(pdata->date, sq->pq);
sq->pq = stpcpy(sq->pq, "' "); sq->pq = stpcpy(sq->pq, "' ");
} }
@ -1092,7 +1082,11 @@ sqlQuery_build (sqlQuery *sq, Query *q)
} }
/* if there were and terms, close the brace */ /* if there were and terms, close the brace */
if (il->data) sq->pq = stpcpy(sq->pq, ")"); if (il->data) {
sq->pq = stpcpy(sq->pq, ")");
} else {
more_and = 0;
}
} }
sq->pq = stpcpy(sq->pq, ") "); sq->pq = stpcpy(sq->pq, ") ");
@ -1102,18 +1096,15 @@ sqlQuery_build (sqlQuery *sq, Query *q)
* if the limit is set to a finite number of rows. * if the limit is set to a finite number of rows.
*/ */
if (gncQuerySortGetParamPath (s1) != NULL) if (gncQuerySortGetParamPath(s1) != NULL) {
{
sq->pq = stpcpy(sq->pq, "ORDER BY "); sq->pq = stpcpy(sq->pq, "ORDER BY ");
sq->pq = sql_sort_order(sq->pq, s1); sq->pq = sql_sort_order(sq->pq, s1);
if (gncQuerySortGetParamPath (s2) != NULL) if (gncQuerySortGetParamPath(s2) != NULL) {
{
sq->pq = stpcpy(sq->pq, ", "); sq->pq = stpcpy(sq->pq, ", ");
sq->pq = sql_sort_order(sq->pq, s2); sq->pq = sql_sort_order(sq->pq, s2);
if (gncQuerySortGetParamPath (s3) != NULL) if (gncQuerySortGetParamPath(s3) != NULL) {
{
sq->pq = stpcpy(sq->pq, ", "); sq->pq = stpcpy(sq->pq, ", ");
sq->pq = sql_sort_order(sq->pq, s3); sq->pq = sql_sort_order(sq->pq, s3);
} }
@ -1123,8 +1114,7 @@ sqlQuery_build (sqlQuery *sq, Query *q)
/* ---------------------------------------------------- */ /* ---------------------------------------------------- */
/* limit the query result to a finite number of rows */ /* limit the query result to a finite number of rows */
max_rows = gncQueryGetMaxResults(q); max_rows = gncQueryGetMaxResults(q);
if (0 <= max_rows) if (0 <= max_rows) {
{
sq->pq = stpcpy(sq->pq, " LIMIT "); sq->pq = stpcpy(sq->pq, " LIMIT ");
sq->pq += snprintf(sq->pq, 30, "%d", max_rows); sq->pq += snprintf(sq->pq, 30, "%d", max_rows);
} }

View File

@ -286,7 +286,7 @@ store_cb (const char *key, kvp_value *val, gpointer p)
case KVP_TYPE_TIMESPEC: case KVP_TYPE_TIMESPEC:
{ {
PINFO ("path=%s type=timespec", cb_data->path); PINFO ("path=%s type=timespec", cb_data->path);
cb_data->stype = "timespec"; cb_data->stype = "time";
cb_data->u.ts = kvp_value_get_timespec (val); cb_data->u.ts = kvp_value_get_timespec (val);
pgendPutOneKVPtimespecOnly (be, cb_data); pgendPutOneKVPtimespecOnly (be, cb_data);
} }

View File

@ -121,8 +121,8 @@ int finishQuery(PGBackend *be);
PINFO ("clearing result %d", i); \ PINFO ("clearing result %d", i); \
status = PQresultStatus(result); \ status = PQresultStatus(result); \
if (PGRES_COMMAND_OK != status) { \ if (PGRES_COMMAND_OK != status) { \
PERR("finish query failed:\n" \ msg = PQresultErrorMessage(result); \
"\t%s", PQerrorMessage((conn))); \ PERR("finish query failed:\n\t%s", msg); \
PQclear(result); \ PQclear(result); \
xaccBackendSetMessage (&be->be, msg); \ xaccBackendSetMessage (&be->be, msg); \
xaccBackendSetError (&be->be, ERR_BACKEND_SERVER_ERR); \ xaccBackendSetError (&be->be, ERR_BACKEND_SERVER_ERR); \
@ -131,7 +131,7 @@ int finishQuery(PGBackend *be);
PQclear(result); \ PQclear(result); \
i++; \ i++; \
} while (result); \ } while (result); \
} } \
/* --------------------------------------------------------------- */ /* --------------------------------------------------------------- */
/* The GET_RESULTS macro grabs the result of an pgSQL query off the /* The GET_RESULTS macro grabs the result of an pgSQL query off the

View File

@ -1,174 +1,174 @@
-- "-- \n"
-- FILE: "-- FILE: \n"
-- table-audit.sql "-- table-audit.sql \n"
-- "-- \n"
-- FUNCTION: "-- FUNCTION: \n"
-- Define the audit trail tables "-- Define the audit trail tables \n"
-- Note that these tables must be kept manually in sync with those "-- Note that these tables must be kept manually in sync with those \n"
-- in table-create.sql "-- in table-create.sql \n"
-- "-- \n"
-- HISTORY: "-- HISTORY: \n"
-- Copyright (C) 2000, 2001 Linas Vepstas "-- Copyright (C) 2000, 2001 Linas Vepstas \n"
-- "-- \n"
-- The change field may be 'a' -- add, 'd' -- delete/drop, 'm' -- modify "-- The change field may be 'a' -- add, 'd' -- delete/drop, 'm' -- modify \n"
-- "-- \n"
-- The objtype field may be 'a' -- account, 'c' -- commodity, 'e' -- entry, "-- The objtype field may be 'a' -- account, 'c' -- commodity, 'e' -- entry, \n"
-- 'k' -- kvp, 'p' -- price, 't' -- transaction "-- 'k' -- kvp, 'p' -- price, 't' -- transaction \n"
-- "-- \n"
-- The objtype is the class type of the child class. "-- The objtype is the class type of the child class. \n"
-- "-- \n"
-- Note that SQL is only partially object-oriented. Thus, we use the "-- Note that SQL is only partially object-oriented. Thus, we use the \n"
-- gncAuditTrail table to define the parent class; the children inherit "-- gncAuditTrail table to define the parent class; the children inherit \n"
-- from it. Since SQL doesn't tell the parent who the child was, we use "-- from it. Since SQL doesn't tell the parent who the child was, we use \n"
-- the 'objtype' field to store the class type of the child. "-- the 'objtype' field to store the class type of the child. \n"
-- "-- \n"
-- Thus, we should really enforce a constraint on this field: "-- Thus, we should really enforce a constraint on this field: \n"
-- CREATE TABLE gncAccountTrail ( "-- CREATE TABLE gncAccountTrail ( \n"
-- objtype CHAR NOT NULL CHECK (objtype == 'a') "-- objtype CHAR NOT NULL CHECK (objtype == 'a') \n"
-- and so on. "-- and so on. \n"
" \n"
CREATE TABLE gncAuditTrail ( "CREATE TABLE gncAuditTrail ( \n"
sessionGuid CHAR(32) NOT NULL, -- who changed it " sessionGuid CHAR(32) NOT NULL, -- who changed it \n"
date_changed TIMESTAMP, -- when they changed it " date_changed TIMESTAMP, -- when they changed it \n"
change CHAR NOT NULL, " change CHAR NOT NULL, \n"
objtype CHAR NOT NULL " objtype CHAR NOT NULL \n"
); "); \n"
" \n"
-- would love to inherit, but can't because this wrecks the primary key "-- would love to inherit, but can't because this wrecks the primary key \n"
" \n"
CREATE TABLE gncAccountTrail ( "CREATE TABLE gncAccountTrail ( \n"
accountGuid CHAR(32) NOT NULL, -- override, not a primary key anymore " accountGuid CHAR(32) NOT NULL, -- override, not a primary key anymore \n"
parentGuid CHAR(32) NOT NULL, " parentGuid CHAR(32) NOT NULL, \n"
bookGuid CHAR(32) NOT NULL, " bookGuid CHAR(32) NOT NULL, \n"
accountName TEXT NOT NULL CHECK (accountName <> ''), " accountName TEXT NOT NULL CHECK (accountName <> ''), \n"
accountCode TEXT, " accountCode TEXT, \n"
description TEXT, " description TEXT, \n"
type TEXT NOT NULL, " type TEXT NOT NULL, \n"
commodity TEXT NOT NULL CHECK (commodity <>''), " commodity TEXT NOT NULL CHECK (commodity <>''), \n"
version INT4 NOT NULL, " version INT4 NOT NULL, \n"
iguid INT4 DEFAULT 0 " iguid INT4 DEFAULT 0 \n"
) INHERITS (gncAuditTrail); ") INHERITS (gncAuditTrail); \n"
" \n"
CREATE INDEX gncAccountTrail_account_idx ON gncAccountTrail (accountGuid); "CREATE INDEX gncAccountTrail_account_idx ON gncAccountTrail (accountGuid); \n"
" \n"
CREATE TABLE gncBookTrail ( "CREATE TABLE gncBookTrail ( \n"
bookGuid CHAR(32) NOT NULL, " bookGuid CHAR(32) NOT NULL, \n"
book_open CHAR DEFAULT 'n', " book_open CHAR DEFAULT 'n', \n"
version INT4 NOT NULL, " version INT4 NOT NULL, \n"
iguid INT4 DEFAULT 0 " iguid INT4 DEFAULT 0 \n"
) INHERITS (gncAuditTrail); ") INHERITS (gncAuditTrail); \n"
" \n"
CREATE INDEX gncBookTrail_book_idx ON gncBookTrail (bookGuid); "CREATE INDEX gncBookTrail_book_idx ON gncBookTrail (bookGuid); \n"
" \n"
CREATE TABLE gncCommodityTrail ( "CREATE TABLE gncCommodityTrail ( \n"
commodity TEXT NOT NULL, -- override, not a primary key anymore " commodity TEXT NOT NULL, -- override, not a primary key anymore \n"
fullname TEXT, " fullname TEXT, \n"
namespace TEXT NOT NULL, " namespace TEXT NOT NULL, \n"
mnemonic TEXT NOT NULL, " mnemonic TEXT NOT NULL, \n"
code TEXT, " code TEXT, \n"
fraction INT DEFAULT '100' " fraction INT DEFAULT '100' \n"
) INHERITS (gncAuditTrail); ") INHERITS (gncAuditTrail); \n"
" \n"
CREATE INDEX gncCommodityTrail_commodity_idx ON gncCommodityTrail (commodity); "CREATE INDEX gncCommodityTrail_commodity_idx ON gncCommodityTrail (commodity); \n"
" \n"
CREATE TABLE gncEntryTrail ( "CREATE TABLE gncEntryTrail ( \n"
entryGuid CHAR(32) NOT NULL, -- override, not a primary key anymore " entryGuid CHAR(32) NOT NULL, -- override, not a primary key anymore \n"
accountGuid CHAR(32) NOT NULL, " accountGuid CHAR(32) NOT NULL, \n"
transGuid CHAR(32) NOT NULL, " transGuid CHAR(32) NOT NULL, \n"
memo TEXT, " memo TEXT, \n"
action TEXT, " action TEXT, \n"
reconciled CHAR DEFAULT 'n', " reconciled CHAR DEFAULT 'n', \n"
date_reconciled TIMESTAMP, " date_reconciled TIMESTAMP, \n"
amount INT8 DEFAULT '0', " amount INT8 DEFAULT '0', \n"
value INT8 DEFAULT '0', " value INT8 DEFAULT '0', \n"
iguid INT4 DEFAULT 0 " iguid INT4 DEFAULT 0 \n"
) INHERITS (gncAuditTrail); ") INHERITS (gncAuditTrail); \n"
" \n"
CREATE INDEX gncEntryTrail_entry_idx ON gncEntryTrail (entryGuid); "CREATE INDEX gncEntryTrail_entry_idx ON gncEntryTrail (entryGuid); \n"
" \n"
CREATE TABLE gncPriceTrail ( "CREATE TABLE gncPriceTrail ( \n"
priceGuid CHAR(32) NOT NULL, -- override, not a primary key anymore " priceGuid CHAR(32) NOT NULL, -- override, not a primary key anymore \n"
commodity TEXT NOT NULL CHECK (commodity <>''), " commodity TEXT NOT NULL CHECK (commodity <>''), \n"
currency TEXT NOT NULL CHECK (commodity <>''), " currency TEXT NOT NULL CHECK (commodity <>''), \n"
time TIMESTAMP, " time TIMESTAMP, \n"
source TEXT, " source TEXT, \n"
type TEXT, " type TEXT, \n"
valueNum INT8 DEFAULT '0', " valueNum INT8 DEFAULT '0', \n"
valueDenom INT4 DEFAULT '100', " valueDenom INT4 DEFAULT '100', \n"
version INT4 NOT NULL, " version INT4 NOT NULL, \n"
bookGuid CHAR(32) NOT NULL " bookGuid CHAR(32) NOT NULL \n"
) INHERITS (gncAuditTrail); ") INHERITS (gncAuditTrail); \n"
" \n"
CREATE INDEX gncPriceTrail_price_idx ON gncPriceTrail (priceGuid); "CREATE INDEX gncPriceTrail_price_idx ON gncPriceTrail (priceGuid); \n"
" \n"
CREATE TABLE gncTransactionTrail ( "CREATE TABLE gncTransactionTrail ( \n"
transGuid CHAR(32) NOT NULL, -- override, not a primary key anymore " transGuid CHAR(32) NOT NULL, -- override, not a primary key anymore \n"
last_modified TIMESTAMP DEFAULT 'NOW', " last_modified TIMESTAMP DEFAULT 'NOW', \n"
date_entered TIMESTAMP, " date_entered TIMESTAMP, \n"
date_posted TIMESTAMP, " date_posted TIMESTAMP, \n"
num TEXT, " num TEXT, \n"
description TEXT, " description TEXT, \n"
currency TEXT NOT NULL CHECK (currency <> ''), " currency TEXT NOT NULL CHECK (currency <> ''), \n"
version INT4 NOT NULL, " version INT4 NOT NULL, \n"
iguid INT4 DEFAULT 0 " iguid INT4 DEFAULT 0 \n"
) INHERITS (gncAuditTrail); ") INHERITS (gncAuditTrail); \n"
" \n"
CREATE INDEX gncTransactionTrail_trans_idx ON gncTransactionTrail (transGuid); "CREATE INDEX gncTransactionTrail_trans_idx ON gncTransactionTrail (transGuid); \n"
" \n"
CREATE TABLE gncKVPvalueTrail ( "CREATE TABLE gncKVPvalueTrail ( \n"
iguid INT4, " iguid INT4, \n"
ipath INT4, " ipath INT4, \n"
type char(4) " type char(4) \n"
) INHERITS (gncAuditTrail); ") INHERITS (gncAuditTrail); \n"
" \n"
CREATE TABLE gncKVPvalue_int64Trail ( "CREATE TABLE gncKVPvalue_int64Trail ( \n"
iguid INT4, " iguid INT4, \n"
ipath INT4, " ipath INT4, \n"
type char(4), " type char(4), \n"
data INT8 " data INT8 \n"
) INHERITS (gncAuditTrail); ") INHERITS (gncAuditTrail); \n"
" \n"
CREATE TABLE gncKVPvalue_dblTrail ( "CREATE TABLE gncKVPvalue_dblTrail ( \n"
iguid INT4, " iguid INT4, \n"
ipath INT4, " ipath INT4, \n"
type char(4), " type char(4), \n"
data FLOAT8 " data FLOAT8 \n"
) INHERITS (gncAuditTrail); ") INHERITS (gncAuditTrail); \n"
" \n"
CREATE TABLE gncKVPvalue_numericTrail ( "CREATE TABLE gncKVPvalue_numericTrail ( \n"
iguid INT4, " iguid INT4, \n"
ipath INT4, " ipath INT4, \n"
type char(4), " type char(4), \n"
num INT8, " num INT8, \n"
denom INT8 " denom INT8 \n"
) INHERITS (gncAuditTrail); ") INHERITS (gncAuditTrail); \n"
" \n"
CREATE TABLE gncKVPvalue_strTrail ( "CREATE TABLE gncKVPvalue_strTrail ( \n"
iguid INT4, " iguid INT4, \n"
ipath INT4, " ipath INT4, \n"
type char(4), " type char(4), \n"
data TEXT " data TEXT \n"
) INHERITS (gncAuditTrail); ") INHERITS (gncAuditTrail); \n"
" \n"
CREATE TABLE gncKVPvalue_guidTrail ( "CREATE TABLE gncKVPvalue_guidTrail ( \n"
iguid INT4, " iguid INT4, \n"
ipath INT4, " ipath INT4, \n"
type char(4), " type char(4), \n"
data CHAR(32) " data CHAR(32) \n"
) INHERITS (gncAuditTrail); ") INHERITS (gncAuditTrail); \n"
" \n"
CREATE TABLE gncKVPvalue_timespecTrail ( "CREATE TABLE gncKVPvalue_timespecTrail ( \n"
iguid INT4, " iguid INT4, \n"
ipath INT4, " ipath INT4, \n"
type char(4), " type char(4), \n"
data TIMESTAMP " data TIMESTAMP \n"
) INHERITS (gncAuditTrail); ") INHERITS (gncAuditTrail); \n"
" \n"
CREATE TABLE gncKVPvalue_listTrail ( "CREATE TABLE gncKVPvalue_listTrail ( \n"
iguid INT4, " iguid INT4, \n"
ipath INT4, " ipath INT4, \n"
type char(4), " type char(4), \n"
data TEXT[] " data TEXT[] \n"
) INHERITS (gncAuditTrail); ") INHERITS (gncAuditTrail); \n"
" \n"
-- end of file "-- end of file";

View File

@ -1,246 +1,246 @@
-- "-- \n"
-- FILE: "-- FILE: \n"
-- table-create.sql "-- table-create.sql \n"
-- "-- \n"
-- FUNCTION: "-- FUNCTION: \n"
-- Define the tables needed to initialize a new GnuCash database "-- Define the tables needed to initialize a new GnuCash database \n"
-- "-- \n"
-- These tables roughly mirror the c structs in "-- These tables roughly mirror the c structs in \n"
-- TransactionP.h, AccountP.h, gnc-commodity.c "-- TransactionP.h, AccountP.h, gnc-commodity.c \n"
-- Please refer to the C files to get the right level of documentation. "-- Please refer to the C files to get the right level of documentation. \n"
-- "-- \n"
-- If these tables are changed or added to, a correspionding "-- If these tables are changed or added to, a correspionding \n"
-- audit-trail table (in table-audit.sql) must be updated as well. "-- audit-trail table (in table-audit.sql) must be updated as well. \n"
-- "-- \n"
-- These tables are specifically designed for the "-- These tables are specifically designed for the \n"
-- postgres database server, but are hopefull relatively portable. "-- postgres database server, but are hopefull relatively portable. \n"
-- "-- \n"
-- These tables are hand-built, but maybe they should be "-- These tables are hand-built, but maybe they should be \n"
-- auto-built with the m4 macros ... "-- auto-built with the m4 macros ... \n"
-- "-- \n"
-- HISTORY: "-- HISTORY: \n"
-- Copyright (C) 2000, 2001 Linas Vepstas "-- Copyright (C) 2000, 2001 Linas Vepstas \n"
-- "-- \n"
" \n"
CREATE TABLE gncVersion ( "CREATE TABLE gncVersion ( \n"
major INT NOT NULL, " major INT NOT NULL, \n"
minor INT NOT NULL, " minor INT NOT NULL, \n"
rev INT DEFAULT '0', " rev INT DEFAULT '0', \n"
name TEXT UNIQUE NOT NULL CHECK (name <> ''), " name TEXT UNIQUE NOT NULL CHECK (name <> ''), \n"
date TIMESTAMP DEFAULT 'NOW' " date TIMESTAMP DEFAULT 'NOW' \n"
); "); \n"
" \n"
-- Commodity structure "-- Commodity structure \n"
-- Store currency, security types. Namespace includes "-- Store currency, security types. Namespace includes \n"
-- ISO4217 for currencies, NASDAQ, AMEX, NYSE, EUREX for "-- ISO4217 for currencies, NASDAQ, AMEX, NYSE, EUREX for \n"
-- stocks. See the C documentation for details. "-- stocks. See the C documentation for details. \n"
" \n"
CREATE TABLE gncCommodity ( "CREATE TABLE gncCommodity ( \n"
commodity TEXT PRIMARY KEY, " commodity TEXT PRIMARY KEY, \n"
fullname TEXT, " fullname TEXT, \n"
namespace TEXT NOT NULL, " namespace TEXT NOT NULL, \n"
mnemonic TEXT NOT NULL, " mnemonic TEXT NOT NULL, \n"
code TEXT, " code TEXT, \n"
fraction INT DEFAULT '100' " fraction INT DEFAULT '100' \n"
); "); \n"
" \n"
CREATE TABLE gncBook ( "CREATE TABLE gncBook ( \n"
bookGuid CHAR(32) PRIMARY KEY, " bookGuid CHAR(32) PRIMARY KEY, \n"
book_open CHAR DEFAULT 'n', " book_open CHAR DEFAULT 'n', \n"
version INT4 NOT NULL, " version INT4 NOT NULL, \n"
iguid INT4 DEFAULT 0 " iguid INT4 DEFAULT 0 \n"
); "); \n"
" \n"
-- Account structure -- parentGUID points to parent account "-- Account structure -- parentGUID points to parent account \n"
-- guid. There is no supports for Groups in this schema. "-- guid. There is no supports for Groups in this schema. \n"
-- (there seems to be no strong need to have groups in the DB.) "-- (there seems to be no strong need to have groups in the DB.) \n"
" \n"
CREATE TABLE gncAccount ( "CREATE TABLE gncAccount ( \n"
accountGuid CHAR(32) PRIMARY KEY, " accountGuid CHAR(32) PRIMARY KEY, \n"
parentGuid CHAR(32) NOT NULL, " parentGuid CHAR(32) NOT NULL, \n"
bookGuid CHAR(32) NOT NULL, " bookGuid CHAR(32) NOT NULL, \n"
accountName TEXT NOT NULL CHECK (accountName <> ''), " accountName TEXT NOT NULL CHECK (accountName <> ''), \n"
accountCode TEXT, " accountCode TEXT, \n"
description TEXT, " description TEXT, \n"
type TEXT NOT NULL, " type TEXT NOT NULL, \n"
commodity TEXT NOT NULL CHECK (commodity <>''), " commodity TEXT NOT NULL CHECK (commodity <>''), \n"
version INT4 NOT NULL, " version INT4 NOT NULL, \n"
iguid INT4 DEFAULT 0 " iguid INT4 DEFAULT 0 \n"
); "); \n"
" \n"
-- CREATE INDEX gncAccount_pg_idx ON gncAccount (parentGuid); "-- CREATE INDEX gncAccount_pg_idx ON gncAccount (parentGuid); \n"
" \n"
CREATE TABLE gncTransaction ( "CREATE TABLE gncTransaction ( \n"
transGuid CHAR(32) PRIMARY KEY, " transGuid CHAR(32) PRIMARY KEY, \n"
last_modified TIMESTAMP DEFAULT 'NOW', " last_modified TIMESTAMP DEFAULT 'NOW', \n"
date_entered TIMESTAMP, " date_entered TIMESTAMP, \n"
date_posted TIMESTAMP, " date_posted TIMESTAMP, \n"
num TEXT, " num TEXT, \n"
description TEXT, " description TEXT, \n"
currency TEXT NOT NULL CHECK (currency <> ''), " currency TEXT NOT NULL CHECK (currency <> ''), \n"
version INT4 NOT NULL, " version INT4 NOT NULL, \n"
iguid INT4 DEFAULT 0 " iguid INT4 DEFAULT 0 \n"
); "); \n"
" \n"
CREATE INDEX gncTransaction_posted_idx ON gncTransaction (date_posted); "CREATE INDEX gncTransaction_posted_idx ON gncTransaction (date_posted); \n"
" \n"
-- a gncEntry is what we call 'Split' elsewhere in the engine "-- a gncEntry is what we call 'Split' elsewhere in the engine \n"
-- Here, we call it a 'journal entry' "-- Here, we call it a 'journal entry' \n"
" \n"
CREATE TABLE gncEntry ( "CREATE TABLE gncEntry ( \n"
entryGuid CHAR(32) PRIMARY KEY, " entryGuid CHAR(32) PRIMARY KEY, \n"
accountGuid CHAR(32) NOT NULL, " accountGuid CHAR(32) NOT NULL, \n"
transGuid CHAR(32) NOT NULL, " transGuid CHAR(32) NOT NULL, \n"
memo TEXT, " memo TEXT, \n"
action TEXT, " action TEXT, \n"
reconciled CHAR DEFAULT 'n', " reconciled CHAR DEFAULT 'n', \n"
date_reconciled TIMESTAMP, " date_reconciled TIMESTAMP, \n"
amount INT8 DEFAULT '0', " amount INT8 DEFAULT '0', \n"
value INT8 DEFAULT '0', " value INT8 DEFAULT '0', \n"
iguid INT4 DEFAULT 0 " iguid INT4 DEFAULT 0 \n"
); "); \n"
" \n"
CREATE INDEX gncEntry_acc_idx ON gncEntry (accountGuid); "CREATE INDEX gncEntry_acc_idx ON gncEntry (accountGuid); \n"
CREATE INDEX gncEntry_trn_idx ON gncEntry (transGuid); "CREATE INDEX gncEntry_trn_idx ON gncEntry (transGuid); \n"
" \n"
-- The checkpoint table provides balance information "-- The checkpoint table provides balance information \n"
-- The balance is provided in the indicated currency; "-- The balance is provided in the indicated currency; \n"
-- this allows the potential of maintaining balance information "-- this allows the potential of maintaining balance information \n"
-- in multiple currencies. "-- in multiple currencies. \n"
-- (e.g. report stock account balances in shares of stock, "-- (e.g. report stock account balances in shares of stock, \n"
-- and in dollars) "-- and in dollars) \n"
-- the 'type' field indicates what type of balance this is "-- the 'type' field indicates what type of balance this is \n"
-- (simple, FIFO, LIFO, or other accounting method) "-- (simple, FIFO, LIFO, or other accounting method) \n"
" \n"
CREATE TABLE gncCheckpoint ( "CREATE TABLE gncCheckpoint ( \n"
accountGuid CHAR(32) NOT NULL, " accountGuid CHAR(32) NOT NULL, \n"
date_start TIMESTAMP NOT NULL, " date_start TIMESTAMP NOT NULL, \n"
date_end TIMESTAMP NOT NULL, " date_end TIMESTAMP NOT NULL, \n"
commodity TEXT NOT NULL CHECK (commodity <>''), " commodity TEXT NOT NULL CHECK (commodity <>''), \n"
type TEXT DEFAULT 'simple', " type TEXT DEFAULT 'simple', \n"
balance INT8 DEFAULT '0', " balance INT8 DEFAULT '0', \n"
cleared_balance INT8 DEFAULT '0', " cleared_balance INT8 DEFAULT '0', \n"
reconciled_balance INT8 DEFAULT '0', " reconciled_balance INT8 DEFAULT '0', \n"
" \n"
PRIMARY KEY (accountGuid, date_start, commodity) " PRIMARY KEY (accountGuid, date_start, commodity) \n"
); "); \n"
" \n"
-- The price table stores the price of 'commodity' valued "-- The price table stores the price of 'commodity' valued \n"
-- in units of 'currency' "-- in units of 'currency' \n"
CREATE TABLE gncPrice ( "CREATE TABLE gncPrice ( \n"
priceGuid CHAR(32) PRIMARY KEY, " priceGuid CHAR(32) PRIMARY KEY, \n"
commodity TEXT NOT NULL CHECK (commodity <>''), " commodity TEXT NOT NULL CHECK (commodity <>''), \n"
currency TEXT NOT NULL CHECK (commodity <>''), " currency TEXT NOT NULL CHECK (commodity <>''), \n"
time TIMESTAMP, " time TIMESTAMP, \n"
source TEXT, " source TEXT, \n"
type TEXT, " type TEXT, \n"
valueNum INT8 DEFAULT '0', " valueNum INT8 DEFAULT '0', \n"
valueDenom INT4 DEFAULT '100', " valueDenom INT4 DEFAULT '100', \n"
version INT4 NOT NULL, " version INT4 NOT NULL, \n"
bookGuid CHAR(32) NOT NULL " bookGuid CHAR(32) NOT NULL \n"
); "); \n"
" \n"
" \n"
-- The session directory serves several purposes. First and formost, "-- The session directory serves several purposes. First and formost, \n"
-- it notes the database access type. There are three modes: "-- it notes the database access type. There are three modes: \n"
-- o 'Single User' -- Only one user can have access to the database "-- o 'Single User' -- Only one user can have access to the database \n"
-- at a time. "-- at a time. \n"
-- o 'Multi-User Polled' -- multiple users "-- o 'Multi-User Polled' -- multiple users \n"
-- o 'Muilti-User Event Driven' "-- o 'Muilti-User Event Driven' \n"
-- See Design.txt for more info. "-- See Design.txt for more info. \n"
-- Note that a client can lie about its identity, sign-on time, etc. "-- Note that a client can lie about its identity, sign-on time, etc. \n"
-- so these records aren't really sufficient for a true audit. "-- so these records aren't really sufficient for a true audit. \n"
" \n"
CREATE TABLE gncSession ( "CREATE TABLE gncSession ( \n"
sessionGuid CHAR(32) PRIMARY KEY, " sessionGuid CHAR(32) PRIMARY KEY, \n"
session_mode CHAR(16) NOT NULL, " session_mode CHAR(16) NOT NULL, \n"
hostname TEXT, " hostname TEXT, \n"
login_name TEXT, " login_name TEXT, \n"
gecos TEXT, " gecos TEXT, \n"
time_on TIMESTAMP NOT NULL, " time_on TIMESTAMP NOT NULL, \n"
time_off TIMESTAMP NOT NULL DEFAULT 'INFINITY' " time_off TIMESTAMP NOT NULL DEFAULT 'INFINITY' \n"
); "); \n"
" \n"
" \n"
-- The kvp path-cache replaces a long path name with a single unique "-- The kvp path-cache replaces a long path name with a single unique \n"
-- number. The guid-cache replaces a 32-byte guid with a shorter "-- number. The guid-cache replaces a 32-byte guid with a shorter \n"
-- 4-byte identifier. The KVP Value table stores the actual values. "-- 4-byte identifier. The KVP Value table stores the actual values. \n"
" \n"
CREATE TABLE gncPathCache ( "CREATE TABLE gncPathCache ( \n"
ipath SERIAL PRIMARY KEY, " ipath SERIAL PRIMARY KEY, \n"
path TEXT " path TEXT \n"
); "); \n"
" \n"
CREATE SEQUENCE gnc_iguid_seq START 1; "CREATE SEQUENCE gnc_iguid_seq START 1; \n"
" \n"
CREATE TABLE gncKVPvalue ( "CREATE TABLE gncKVPvalue ( \n"
iguid INT4, " iguid INT4, \n"
ipath INT4, " ipath INT4, \n"
type char(4), " type char(4), \n"
" \n"
PRIMARY KEY (iguid, ipath) " PRIMARY KEY (iguid, ipath) \n"
); "); \n"
" \n"
-- CREATE INDEX gncKVPvalue_iguid_idx ON gncKVPvalue (iguid); "-- CREATE INDEX gncKVPvalue_iguid_idx ON gncKVPvalue (iguid); \n"
" \n"
-- Add primary keys to each kvp table ... because key inheritance "-- Add primary keys to each kvp table ... because key inheritance \n"
-- is ambiguously defined and thus not implemented in postgres. "-- is ambiguously defined and thus not implemented in postgres. \n"
-- Note, however, adding these keys degrades performance by 20% "-- Note, however, adding these keys degrades performance by 20% \n"
-- (even after a vacuum analyze), and adding indexes degrades "-- (even after a vacuum analyze), and adding indexes degrades \n"
-- an additional 15% !! I find this result surprising, so I "-- an additional 15% !! I find this result surprising, so I \n"
-- simply leave these commented out ... (as of postgres 7.1.2) "-- simply leave these commented out ... (as of postgres 7.1.2) \n"
-- Note, indexex on the main, non-inherited tables *are* important "-- Note, indexex on the main, non-inherited tables *are* important \n"
-- for ensuring good performance, so this effect seems to be related "-- for ensuring good performance, so this effect seems to be related \n"
-- to inheritance "-- to inheritance \n"
" \n"
CREATE TABLE gncKVPvalue_int64 ( "CREATE TABLE gncKVPvalue_int64 ( \n"
data INT8 " data INT8 \n"
-- PRIMARY KEY (iguid, ipath) "-- PRIMARY KEY (iguid, ipath) \n"
) INHERITS (gncKVPvalue); ") INHERITS (gncKVPvalue); \n"
" \n"
-- CREATE INDEX gncKVPvalue_int64_iguid_idx ON gncKVPvalue_int64 (iguid); "-- CREATE INDEX gncKVPvalue_int64_iguid_idx ON gncKVPvalue_int64 (iguid); \n"
" \n"
CREATE TABLE gncKVPvalue_dbl ( "CREATE TABLE gncKVPvalue_dbl ( \n"
data FLOAT8 " data FLOAT8 \n"
-- PRIMARY KEY (iguid, ipath) "-- PRIMARY KEY (iguid, ipath) \n"
) INHERITS (gncKVPvalue); ") INHERITS (gncKVPvalue); \n"
" \n"
-- CREATE INDEX gncKVPvalue_dbl_iguid_idx ON gncKVPvalue_dbl (iguid); "-- CREATE INDEX gncKVPvalue_dbl_iguid_idx ON gncKVPvalue_dbl (iguid); \n"
" \n"
CREATE TABLE gncKVPvalue_numeric ( "CREATE TABLE gncKVPvalue_numeric ( \n"
num INT8, " num INT8, \n"
denom INT8 " denom INT8 \n"
-- PRIMARY KEY (iguid, ipath) "-- PRIMARY KEY (iguid, ipath) \n"
) INHERITS (gncKVPvalue); ") INHERITS (gncKVPvalue); \n"
" \n"
-- CREATE INDEX gncKVPvalue_numeric_iguid_idx ON gncKVPvalue_numeric (iguid); "-- CREATE INDEX gncKVPvalue_numeric_iguid_idx ON gncKVPvalue_numeric (iguid); \n"
" \n"
CREATE TABLE gncKVPvalue_str ( "CREATE TABLE gncKVPvalue_str ( \n"
data TEXT " data TEXT \n"
-- PRIMARY KEY (iguid, ipath) "-- PRIMARY KEY (iguid, ipath) \n"
) INHERITS (gncKVPvalue); ") INHERITS (gncKVPvalue); \n"
" \n"
-- CREATE INDEX gncKVPvalue_str_iguid_idx ON gncKVPvalue_str (iguid); "-- CREATE INDEX gncKVPvalue_str_iguid_idx ON gncKVPvalue_str (iguid); \n"
" \n"
CREATE TABLE gncKVPvalue_guid ( "CREATE TABLE gncKVPvalue_guid ( \n"
data CHAR(32) " data CHAR(32) \n"
-- PRIMARY KEY (iguid, ipath) "-- PRIMARY KEY (iguid, ipath) \n"
) INHERITS (gncKVPvalue); ") INHERITS (gncKVPvalue); \n"
" \n"
-- CREATE INDEX gncKVPvalue_guid_iguid_idx ON gncKVPvalue_guid (iguid); "-- CREATE INDEX gncKVPvalue_guid_iguid_idx ON gncKVPvalue_guid (iguid); \n"
" \n"
CREATE TABLE gncKVPvalue_timespec ( "CREATE TABLE gncKVPvalue_timespec ( \n"
data TIMESTAMP " data TIMESTAMP \n"
-- PRIMARY KEY (iguid, ipath) "-- PRIMARY KEY (iguid, ipath) \n"
) INHERITS (gncKVPvalue); ") INHERITS (gncKVPvalue); \n"
" \n"
-- CREATE INDEX gncKVPvalue_timespec_iguid_idx ON gncKVPvalue_timespec (iguid); "-- CREATE INDEX gncKVPvalue_timespec_iguid_idx ON gncKVPvalue_timespec (iguid); \n"
" \n"
CREATE TABLE gncKVPvalue_list ( "CREATE TABLE gncKVPvalue_list ( \n"
data TEXT[] " data TEXT[] \n"
-- PRIMARY KEY (iguid, ipath) "-- PRIMARY KEY (iguid, ipath) \n"
) INHERITS (gncKVPvalue); ") INHERITS (gncKVPvalue); \n"
" \n"
-- CREATE INDEX gncKVPvalue_list_iguid_idx ON gncKVPvalue_list (iguid); "-- CREATE INDEX gncKVPvalue_list_iguid_idx ON gncKVPvalue_list (iguid); \n"
" \n"
-- end of file "-- end of file";

View File

@ -1,26 +1,26 @@
-- "-- \n"
-- FILE: "-- FILE: \n"
-- table-drop.sql "-- table-drop.sql \n"
-- "-- \n"
-- FUNCTION: "-- FUNCTION: \n"
-- Drop the tables needed to run GnuCash database "-- Drop the tables needed to run GnuCash database \n"
" \n"
" \n"
DROP TABLE gncCommodity; "DROP TABLE gncCommodity; \n"
DROP TABLE gncAccount; "DROP TABLE gncAccount; \n"
DROP TABLE gncTransaction; "DROP TABLE gncTransaction; \n"
DROP TABLE gncEntry; "DROP TABLE gncEntry; \n"
DROP TABLE gncCheckpoint; "DROP TABLE gncCheckpoint; \n"
DROP TABLE gncSession; "DROP TABLE gncSession; \n"
-- "-- \n"
DROP TABLE gncPathCache; "DROP TABLE gncPathCache; \n"
DROP TABLE gncGUIDCache; "DROP TABLE gncGUIDCache; \n"
DROP TABLE gncKVPvalue; "DROP TABLE gncKVPvalue; \n"
DROP TABLE gncKVPvalue_int64; "DROP TABLE gncKVPvalue_int64; \n"
DROP TABLE gncKVPvalue_dbl; "DROP TABLE gncKVPvalue_dbl; \n"
DROP TABLE gncKVPvalue_numeric; "DROP TABLE gncKVPvalue_numeric; \n"
DROP TABLE gncKVPvalue_str; "DROP TABLE gncKVPvalue_str; \n"
DROP TABLE gncKVPvalue_guid; "DROP TABLE gncKVPvalue_guid; \n"
DROP TABLE gncKVPvalue_timespec; "DROP TABLE gncKVPvalue_timespec; \n"
DROP TABLE gncKVPvalue_list; "DROP TABLE gncKVPvalue_list; \n"
DROP TABLE gncKVPvalue_frame; "DROP TABLE gncKVPvalue_frame;";

View File

@ -1,19 +1,19 @@
-- "-- \n"
-- FILE: "-- FILE: \n"
-- table-version.sql "-- table-version.sql \n"
-- "-- \n"
-- FUNCTION: "-- FUNCTION: \n"
-- Insert the latest version information into the gncVersion table. "-- Insert the latest version information into the gncVersion table. \n"
-- "-- \n"
-- Inserting in the same query as creating the table does not "-- Inserting in the same query as creating the table does not \n"
-- work under Postgres 7.0 "-- work under Postgres 7.0 \n"
-- "-- \n"
-- HISTORY: "-- HISTORY: \n"
-- Copyright (C) 2001 Linux Developers Group "-- Copyright (C) 2001 Linux Developers Group \n"
-- "-- \n"
" \n"
INSERT INTO gncVersion (major,minor,rev,name) VALUES (1,0,0,'Version Table'); "INSERT INTO gncVersion (major,minor,rev,name) VALUES (1,0,0,'Version Table'); \n"
INSERT INTO gncVersion (major,minor,rev,name) VALUES (1,1,1,'iGUID in Main Tables'); "INSERT INTO gncVersion (major,minor,rev,name) VALUES (1,1,1,'iGUID in Main Tables'); \n"
INSERT INTO gncVersion (major,minor,rev,name) VALUES (1,2,1,'Fix gncSubtotalReconedBalance'); "INSERT INTO gncVersion (major,minor,rev,name) VALUES (1,2,1,'Fix gncSubtotalReconedBalance'); \n"
INSERT INTO gncVersion (major,minor,rev,name) VALUES (1,3,1,'Add kvp_timespec tables'); "INSERT INTO gncVersion (major,minor,rev,name) VALUES (1,3,1,'Add kvp_timespec tables'); \n"
INSERT INTO gncVersion (major,minor,rev,name) VALUES (1,4,1,'Add support for multiple books'); "INSERT INTO gncVersion (major,minor,rev,name) VALUES (1,4,1,'Add support for multiple books');";

View File

@ -3,30 +3,35 @@
EXIT_VALUE=0 EXIT_VALUE=0
PATH=/usr/lib/postgresql/bin:$PATH PATH=/usr/lib/postgresql/bin:$PATH
PGCTL=`which pg_ctl 2> /dev/null`
DB=$PWD/gnc_test_db DB=$PWD/gnc_test_db
SOCKDIR=$PWD/gnc_test_db_sock SOCKDIR=$PWD/gnc_test_db_sock
SOCKNUM=7777 SOCKNUM=7777
# I couldn't get this to work -- the shell seems to think "'-k" is an # I couldn't get this to work -- the shell seems to think "'-k" is an
# argument after it finishes expanding ${PG_CTL}... # argument after it finishes expanding ${PG_CTL}...
# PG_CTL="pg_ctl -D "${DB}" -o '-k ${SOCKDIR} -p ${SOCKNUM}'" # PG_CTL="pg_ctl -D "${DB}" -o '-k ${SOCKDIR} -p ${SOCKNUM}'"
our_pg_ctl () our_pg_ctl ()
{ {
if [ ${PGCTL}X == X ]; then
exit -1
fi
pg_ctl -D "${DB}" -o "-k ${SOCKDIR} -p ${SOCKNUM}" "$@"; pg_ctl -D "${DB}" -o "-k ${SOCKDIR} -p ${SOCKNUM}" "$@";
} }
case $1 in case $1 in
create) create)
our_pg_ctl status | grep "pid" && our_pg_ctl stop && sleep 1 our_pg_ctl status | grep "pid" && our_pg_ctl stop && sleep 1 || exit -1
rm -rf ${DB} rm -rf ${DB}
rm -rf ${SOCKDIR} rm -rf ${SOCKDIR}
initdb ${DB} || EXIT_VALUE=1 initdb ${DB} || EXIT_VALUE=1
mkdir ${SOCKDIR} || EXIT_VALUE=1 mkdir ${SOCKDIR} || EXIT_VALUE=1
;; ;;
destroy) destroy)
our_pg_ctl status | grep "pid" && our_pg_ctl stop && sleep 1 our_pg_ctl status | grep "pid" && our_pg_ctl stop && sleep 1 || exit -1
rm -rf ${DB} rm -rf ${DB}
rm -rf ${SOCKDIR} rm -rf ${SOCKDIR}
;; ;;
@ -34,13 +39,13 @@ case $1 in
our_pg_ctl start our_pg_ctl start
;; ;;
stop) stop)
pg_ctl -D ${DB} -o '-k ${SOCKDIR} -p 7777' stop pg_ctl -D ${DB} -o '-k ${SOCKDIR} -p 7777' stop || exit -1
;; ;;
status) status)
our_pg_ctl status our_pg_ctl status
;; ;;
connect) connect)
our_pg_ctl status | grep "not running" && our_pg_ctl start && sleep 1 our_pg_ctl status | grep "not running" && our_pg_ctl start && sleep 1 || exit -1
psql -h ${SOCKDIR} -p ${SOCKNUM} $2 psql -h ${SOCKDIR} -p ${SOCKNUM} $2
;; ;;
*) *)

View File

@ -2,17 +2,25 @@
EXIT_VALUE=0 EXIT_VALUE=0
rm -f test_file_*
./db-control.sh create
./db-control.sh start
# .libs/test-db || EXIT_VALUE=1 # .libs/test-db || EXIT_VALUE=1
# gdb .libs/test-db # gdb .libs/test-db
./test-db || EXIT_VALUE=1
rm -f test_file_*
if ./db-control.sh create; then
./db-control.sh start
./test-db localhost 7777 || EXIT_VALUE=1
./db-control.sh stop ./db-control.sh stop
./db-control.sh destroy
elif [ "${PGHOST}X" != "X" ]; then
# This expects the logged in user to have authority
# to create databases.
if [ "${PGPORT}X" == "X" ]; then
export PGPORT=5432
fi
./test-db $PGHOST $PGPORT || EXIT_VALUE=1
fi
if test $EXIT_VALUE != 0; then exit $EXIT_VALUE; fi if test $EXIT_VALUE != 0; then exit $EXIT_VALUE; fi
./db-control.sh destroy
exit $EXIT_VALUE exit $EXIT_VALUE

View File

@ -17,12 +17,21 @@
#include "gnc-module.h" #include "gnc-module.h"
#include "gnc-session-p.h" #include "gnc-session-p.h"
#include "gncquery.h" #include "gncquery.h"
#include "QueryNew.h"
#include "test-stuff.h" #include "test-stuff.h"
#include "test-engine-stuff.h" #include "test-engine-stuff.h"
/* Prevent compiler warnings. Uncomment if LEAVE/WARN/et al get used*/ static short module = MOD_TEST;
/* static short module = MOD_TEST; */
struct _dbinfo {
char *host;
char *port;
char *dbname;
char *mode;
PGconn *conn;
};
typedef struct _dbinfo DbInfo;
static void static void
save_xml_file(GNCSession * session, const char *filename_base) save_xml_file(GNCSession * session, const char *filename_base)
@ -63,38 +72,45 @@ save_xml_files (GNCSession *session_1, GNCSession *session_2)
} }
static char * static char *
db_file_url (const char *db_name, const char *mode) db_file_url(DbInfo *dbinfo)
{ {
char *db_socket_dir; char *db_socket_dir;
gchar *url;
g_return_val_if_fail (db_name && mode, NULL); g_return_val_if_fail(dbinfo->dbname && dbinfo->mode, NULL);
if ((!g_strncasecmp(dbinfo->port, "7777", 4)) &&
(!g_strncasecmp(dbinfo->host, "localhost", 8))) {
/* TEST_DB_SOCKET_DIR must be an absolute path */ /* TEST_DB_SOCKET_DIR must be an absolute path */
db_socket_dir = getenv("TEST_DB_SOCKET_DIR"); db_socket_dir = getenv("TEST_DB_SOCKET_DIR");
if(! db_socket_dir) g_warning("Couldn't getenv TEST_DB_SOCKET_DIR"); if (!db_socket_dir)
g_warning("Couldn't getenv TEST_DB_SOCKET_DIR");
g_return_val_if_fail(db_socket_dir, NULL); g_return_val_if_fail(db_socket_dir, NULL);
url = g_strdup_printf("postgres://%s:7777/%s?mode=%s",
return g_strdup_printf ("postgres://%s:7777/%s?mode=%s", db_socket_dir, dbinfo->dbname, dbinfo->mode);
db_socket_dir, db_name, mode); } else {
url = g_strdup_printf("postgres://%s:%s/%s?mode=%s",
dbinfo->host, dbinfo->port,
dbinfo->dbname, dbinfo->mode);
}
return url;
} }
static gboolean static gboolean
save_db_file (GNCSession *session, const char *db_name, const char *mode) save_db_file(GNCSession * session, DbInfo *dbinfo)
{ {
GNCBackendError io_err; GNCBackendError io_err;
char *filename; char *filename;
g_return_val_if_fail (session && db_name && mode, FALSE); g_return_val_if_fail(session && dbinfo->dbname && dbinfo->mode, FALSE);
filename = db_file_url (db_name, mode);
filename = db_file_url(dbinfo);
gnc_session_begin(session, filename, FALSE, TRUE); gnc_session_begin(session, filename, FALSE, TRUE);
io_err = gnc_session_get_error(session); io_err = gnc_session_get_error(session);
if (!do_test_args(io_err == ERR_BACKEND_NO_ERR, if (!do_test_args(io_err == ERR_BACKEND_NO_ERR,
"Beginning db session", "Beginning db session",
__FILE__, __LINE__, __FILE__, __LINE__,
"can't begin session for %s in mode %s", "can't begin session for %s in mode %s", dbinfo->dbname, dbinfo->mode))
db_name, mode))
return FALSE; return FALSE;
gnc_session_save(session, NULL); gnc_session_save(session, NULL);
@ -102,8 +118,7 @@ save_db_file (GNCSession *session, const char *db_name, const char *mode)
if (!do_test_args(io_err == ERR_BACKEND_NO_ERR, if (!do_test_args(io_err == ERR_BACKEND_NO_ERR,
"Saving db session", "Saving db session",
__FILE__, __LINE__, __FILE__, __LINE__,
"can't save session for %s in mode %s", "can't save session for %s in mode %s", dbinfo->dbname, dbinfo->mode))
db_name, mode))
return FALSE; return FALSE;
gnc_session_end(session); gnc_session_end(session);
@ -111,8 +126,7 @@ save_db_file (GNCSession *session, const char *db_name, const char *mode)
if (!do_test_args(io_err == ERR_BACKEND_NO_ERR, if (!do_test_args(io_err == ERR_BACKEND_NO_ERR,
"Ending db session", "Ending db session",
__FILE__, __LINE__, __FILE__, __LINE__,
"can't end session for %s in mode %s", "can't end session for %s in mode %s", dbinfo->dbname, dbinfo->mode))
db_name, mode))
return FALSE; return FALSE;
do_test(gnc_session_get_url(session) == NULL, "session url not NULL"); do_test(gnc_session_get_url(session) == NULL, "session url not NULL");
@ -123,23 +137,27 @@ save_db_file (GNCSession *session, const char *db_name, const char *mode)
} }
static gboolean static gboolean
load_db_file (GNCSession *session, const char *db_name, const char *mode, load_db_file(GNCSession * session, DbInfo *dbinfo, gboolean end_session)
gboolean end_session)
{ {
GNCBackendError io_err; GNCBackendError io_err;
PGBackend *be;
char *filename; char *filename;
g_return_val_if_fail (session && db_name && mode, FALSE); g_return_val_if_fail(session && dbinfo->dbname && dbinfo->mode, FALSE);
filename = db_file_url (db_name, mode); filename = db_file_url(dbinfo);
gnc_session_begin(session, filename, FALSE, FALSE); gnc_session_begin(session, filename, FALSE, FALSE);
be = (PGBackend *)gnc_session_get_backend(session);
dbinfo->conn = be->connection;
io_err = gnc_session_get_error(session); io_err = gnc_session_get_error(session);
if (!do_test_args(io_err == ERR_BACKEND_NO_ERR, if (!do_test_args(io_err == ERR_BACKEND_NO_ERR,
"Beginning db session", "Beginning db session",
__FILE__, __LINE__, __FILE__, __LINE__,
"can't begin session for %s in mode %s", "can't begin session for %s in mode %s",
db_name, mode)) dbinfo->dbname, dbinfo->mode))
return FALSE; return FALSE;
gnc_session_load(session, NULL); gnc_session_load(session, NULL);
@ -148,18 +166,17 @@ load_db_file (GNCSession *session, const char *db_name, const char *mode,
"Loading db session", "Loading db session",
__FILE__, __LINE__, __FILE__, __LINE__,
"can't load session for %s in mode %s", "can't load session for %s in mode %s",
db_name, mode)) dbinfo->dbname, dbinfo->mode))
return FALSE; return FALSE;
if (end_session) if (end_session) {
{
gnc_session_end(session); gnc_session_end(session);
io_err = gnc_session_get_error(session); io_err = gnc_session_get_error(session);
if (!do_test_args(io_err == ERR_BACKEND_NO_ERR, if (!do_test_args(io_err == ERR_BACKEND_NO_ERR,
"Ending db session", "Ending db session",
__FILE__, __LINE__, __FILE__, __LINE__,
"can't end session for %s in mode %s", "can't end session for %s in mode %s",
db_name, mode)) dbinfo->dbname, dbinfo->mode))
return FALSE; return FALSE;
do_test(gnc_session_get_url(session) == NULL, "session url not NULL"); do_test(gnc_session_get_url(session) == NULL, "session url not NULL");
@ -171,16 +188,16 @@ load_db_file (GNCSession *session, const char *db_name, const char *mode,
} }
static gboolean static gboolean
test_access (const char *db_name, const char *mode, gboolean multi_user) test_access(DbInfo *dbinfo, gboolean multi_user)
{ {
GNCBackendError io_err; GNCBackendError io_err;
GNCSession *session_1; GNCSession *session_1;
GNCSession *session_2; GNCSession *session_2;
char *filename; char *filename;
g_return_val_if_fail (db_name && mode, FALSE); g_return_val_if_fail(dbinfo->dbname && dbinfo->mode, FALSE);
filename = db_file_url (db_name, mode); filename = db_file_url(dbinfo);
session_1 = gnc_session_new(); session_1 = gnc_session_new();
@ -190,7 +207,7 @@ test_access (const char *db_name, const char *mode, gboolean multi_user)
"Beginning db session", "Beginning db session",
__FILE__, __LINE__, __FILE__, __LINE__,
"can't begin session for %s in mode %s", "can't begin session for %s in mode %s",
db_name, mode)) dbinfo->dbname, dbinfo->mode))
return FALSE; return FALSE;
session_2 = gnc_session_new(); session_2 = gnc_session_new();
@ -198,22 +215,19 @@ test_access (const char *db_name, const char *mode, gboolean multi_user)
gnc_session_begin(session_2, filename, FALSE, FALSE); gnc_session_begin(session_2, filename, FALSE, FALSE);
io_err = gnc_session_get_error(session_2); io_err = gnc_session_get_error(session_2);
if (multi_user) if (multi_user) {
{
if (!do_test_args(io_err == ERR_BACKEND_NO_ERR, if (!do_test_args(io_err == ERR_BACKEND_NO_ERR,
"Beginning second multi-user db session", "Beginning second multi-user db session",
__FILE__, __LINE__, __FILE__, __LINE__,
"can't begin second session for %s in mode %s", "can't begin second session for %s in mode %s",
db_name, mode)) dbinfo->dbname, dbinfo->mode))
return FALSE; return FALSE;
} } else {
else
{
if (!do_test_args(io_err != ERR_BACKEND_NO_ERR, if (!do_test_args(io_err != ERR_BACKEND_NO_ERR,
"Beginning second single-user db session", "Beginning second single-user db session",
__FILE__, __LINE__, __FILE__, __LINE__,
"began second session for %s in mode %s", "began second session for %s in mode %s",
db_name, mode)) dbinfo->dbname, dbinfo->mode))
return FALSE; return FALSE;
} }
@ -254,8 +268,7 @@ mark_price_commodities (GNCPrice *p, gpointer data)
return TRUE; return TRUE;
} }
typedef struct typedef struct {
{
GHashTable *hash; GHashTable *hash;
GList *to_delete; GList *to_delete;
} CommodityDeleteInfo; } CommodityDeleteInfo;
@ -287,16 +300,13 @@ remove_unneeded_commodities (GNCSession *session)
book = gnc_session_get_book(session); book = gnc_session_get_book(session);
xaccGroupForEachAccount(gnc_book_get_group(book), xaccGroupForEachAccount(gnc_book_get_group(book),
mark_account_commodities, mark_account_commodities, cdi.hash, TRUE);
cdi.hash, TRUE);
xaccGroupForEachTransaction(gnc_book_get_group(book), xaccGroupForEachTransaction(gnc_book_get_group(book),
mark_transaction_commodities, mark_transaction_commodities, cdi.hash);
cdi.hash);
gnc_pricedb_foreach_price(gnc_book_get_pricedb(book), gnc_pricedb_foreach_price(gnc_book_get_pricedb(book),
mark_price_commodities, mark_price_commodities, cdi.hash, FALSE);
cdi.hash, FALSE);
cdi.to_delete = NULL; cdi.to_delete = NULL;
@ -326,9 +336,7 @@ make_get_all_query (GNCSession * session)
CLEARED_NO | CLEARED_NO |
CLEARED_CLEARED | CLEARED_CLEARED |
CLEARED_RECONCILED | CLEARED_RECONCILED |
CLEARED_FROZEN | CLEARED_FROZEN | CLEARED_VOIDED, QUERY_AND);
CLEARED_VOIDED,
QUERY_AND);
return q; return q;
} }
@ -349,48 +357,46 @@ multi_user_get_everything (GNCSession *session, GNCSession *base)
/* load in prices from base */ /* load in prices from base */
if (base) if (base)
gnc_pricedb_equal(gnc_book_get_pricedb(gnc_session_get_book(base)), gnc_pricedb_equal(gnc_book_get_pricedb(gnc_session_get_book(base)),
gnc_book_get_pricedb (gnc_session_get_book (session))); gnc_book_get_pricedb(gnc_session_get_book
(session)));
} }
static gboolean static gboolean
test_updates (GNCSession *session, const char *db_name, const char *mode, test_updates(GNCSession * session, DbInfo *dbinfo, gboolean multi_user)
gboolean multi_user)
{ {
GNCBackendError io_err; GNCBackendError io_err;
GNCSession *session_2; GNCSession *session_2;
char *filename; char *filename;
gboolean ok; gboolean ok;
g_return_val_if_fail (session && db_name && mode, FALSE); g_return_val_if_fail(session && dbinfo->dbname && dbinfo->mode, FALSE);
filename = db_file_url (db_name, mode); filename = db_file_url(dbinfo);
gnc_session_begin(session, filename, FALSE, FALSE); gnc_session_begin(session, filename, FALSE, FALSE);
io_err = gnc_session_get_error(session); io_err = gnc_session_get_error(session);
if (!do_test_args(io_err == ERR_BACKEND_NO_ERR, if (!do_test_args(io_err == ERR_BACKEND_NO_ERR,
"Beginning db update session", "Beginning db update session",
__FILE__, __LINE__, __FILE__, __LINE__,
"can't begin session for %s in mode %s", "can't begin session for %s in mode %s", dbinfo->dbname, dbinfo->mode))
db_name, mode))
return FALSE; return FALSE;
make_random_changes_to_session(session); make_random_changes_to_session(session);
if (!multi_user) if (!multi_user) {
{
gnc_session_end(session); gnc_session_end(session);
io_err = gnc_session_get_error(session); io_err = gnc_session_get_error(session);
if (!do_test_args(io_err == ERR_BACKEND_NO_ERR, if (!do_test_args(io_err == ERR_BACKEND_NO_ERR,
"Ending db session", "Ending db session",
__FILE__, __LINE__, __FILE__, __LINE__,
"can't end session for %s in mode %s", "can't end session for %s in mode %s",
db_name, mode)) dbinfo->dbname, dbinfo->mode))
return FALSE; return FALSE;
} }
session_2 = gnc_session_new(); session_2 = gnc_session_new();
if (!load_db_file (session_2, db_name, mode, !multi_user)) if (!load_db_file(session_2, dbinfo, !multi_user))
return FALSE; return FALSE;
if (multi_user) if (multi_user)
@ -403,18 +409,20 @@ test_updates (GNCSession *session, const char *db_name, const char *mode,
gnc_session_get_book(session_2)); gnc_session_get_book(session_2));
do_test_args(ok, "Books equal after update", __FILE__, __LINE__, do_test_args(ok, "Books equal after update", __FILE__, __LINE__,
"Books not equal for session %s in mode %s", "Books not equal for session %s in mode %si\n"
db_name, mode); "book 1: %s,\nbook 2: %s",
dbinfo->dbname, dbinfo->mode,
guid_to_string(gnc_book_get_guid(gnc_session_get_book(session))),
guid_to_string(gnc_book_get_guid(gnc_session_get_book(session_2))));
if (multi_user) if (multi_user) {
{
gnc_session_end(session); gnc_session_end(session);
io_err = gnc_session_get_error(session); io_err = gnc_session_get_error(session);
if (!do_test_args(io_err == ERR_BACKEND_NO_ERR, if (!do_test_args(io_err == ERR_BACKEND_NO_ERR,
"Ending db session", "Ending db session",
__FILE__, __LINE__, __FILE__, __LINE__,
"can't end session for %s in mode %s", "can't end session for %s in mode %s",
db_name, mode)) dbinfo->dbname, dbinfo->mode))
return FALSE; return FALSE;
gnc_session_end(session_2); gnc_session_end(session_2);
@ -423,12 +431,11 @@ test_updates (GNCSession *session, const char *db_name, const char *mode,
"Ending db session", "Ending db session",
__FILE__, __LINE__, __FILE__, __LINE__,
"can't end session for %s in mode %s", "can't end session for %s in mode %s",
db_name, mode)) dbinfo->dbname, dbinfo->mode))
return FALSE; return FALSE;
} }
if (!ok) if (!ok) {
{
save_xml_files(session, session_2); save_xml_files(session, session_2);
return FALSE; return FALSE;
} }
@ -466,11 +473,9 @@ session_num_trans (GNCSession *session)
return num; return num;
} }
typedef struct typedef struct {
{
GNCSession *session_base; GNCSession *session_base;
const char *db_name; DbInfo *dbinfo;
const char *mode;
gint loaded; gint loaded;
gint total; gint total;
} QueryTestData; } QueryTestData;
@ -483,33 +488,37 @@ test_raw_query (GNCSession *session, Query *q)
PGBackend *be; PGBackend *be;
sqlQuery *sq; sqlQuery *sq;
gboolean ok; gboolean ok;
QueryNew *qn = q;
g_return_val_if_fail(session && q, FALSE); g_return_val_if_fail(session && q, FALSE);
be = (PGBackend *) gnc_session_get_backend(session); be = (PGBackend *) gnc_session_get_backend(session);
if (gnc_should_log(module, GNC_LOG_DETAIL))
gncQueryPrint(qn);
sq = sqlQuery_new(); sq = sqlQuery_new();
sql_query_string = sqlQuery_build(sq, q); sql_query_string = sqlQuery_build(sq, q);
result = PQexec(be->connection, sql_query_string); result = PQexec(be->connection, sql_query_string);
ok = (result && PQresultStatus(result) == PGRES_TUPLES_OK); ok = (result && PQresultStatus(result) == PGRES_TUPLES_OK);
if (!ok) if (!ok) {
{ failure_args("Raw query failed",
failure ("raw query failed"); __FILE__, __LINE__,
} "Error: %s\nQuery: %s",
else PQresultErrorMessage(result),
{ sql_query_string);
/* failure("raw query failed: %s", sql_query_string); */
} else {
ok = ok && (PQntuples(result) == 1); ok = ok && (PQntuples(result) == 1);
if (!ok) if (!ok)
failure_args("number returned test", failure_args("number returned test",
__FILE__, __LINE__, __FILE__, __LINE__,
"query returned %d tuples", "query returned %d tuples", PQntuples(result));
PQntuples (result));
} }
if (ok) if (ok) {
{
success("raw query succeeded"); success("raw query succeeded");
} }
@ -530,7 +539,7 @@ test_trans_query (Transaction *trans, gpointer data)
GList *list; GList *list;
Query *q; Query *q;
filename = db_file_url (qtd->db_name, qtd->mode); filename = db_file_url(qtd->dbinfo);
session = gnc_session_new(); session = gnc_session_new();
@ -539,8 +548,7 @@ test_trans_query (Transaction *trans, gpointer data)
if (!do_test_args(io_err == ERR_BACKEND_NO_ERR, if (!do_test_args(io_err == ERR_BACKEND_NO_ERR,
"Beginning db session", "Beginning db session",
__FILE__, __LINE__, __FILE__, __LINE__,
"can't begin session for %s", "can't begin session for %s", filename))
filename))
return FALSE; return FALSE;
gnc_session_load(session, NULL); gnc_session_load(session, NULL);
@ -548,8 +556,7 @@ test_trans_query (Transaction *trans, gpointer data)
if (!do_test_args(io_err == ERR_BACKEND_NO_ERR, if (!do_test_args(io_err == ERR_BACKEND_NO_ERR,
"Loading db session", "Loading db session",
__FILE__, __LINE__, __FILE__, __LINE__,
"can't load session for %s", "can't load session for %s", filename))
filename))
return FALSE; return FALSE;
book = gnc_session_get_book(session); book = gnc_session_get_book(session);
@ -557,15 +564,13 @@ test_trans_query (Transaction *trans, gpointer data)
q = make_trans_query(trans, get_random_query_type() | GUID_QT); q = make_trans_query(trans, get_random_query_type() | GUID_QT);
xaccQuerySetBook(q, book); xaccQuerySetBook(q, book);
if (!test_raw_query (session, q)) if (!test_raw_query(session, q)) {
{
failure("raw query failed"); failure("raw query failed");
return FALSE; return FALSE;
} }
list = xaccQueryGetTransactions(q, QUERY_TXN_MATCH_ANY); list = xaccQueryGetTransactions(q, QUERY_TXN_MATCH_ANY);
if (g_list_length (list) != 1) if (g_list_length(list) != 1) {
{
failure_args("test num returned", __FILE__, __LINE__, failure_args("test num returned", __FILE__, __LINE__,
"number of matching transactions %d not 1", "number of matching transactions %d not 1",
g_list_length(list)); g_list_length(list));
@ -576,8 +581,7 @@ test_trans_query (Transaction *trans, gpointer data)
qtd->loaded += session_num_trans(session); qtd->loaded += session_num_trans(session);
qtd->total += session_num_trans(qtd->session_base); qtd->total += session_num_trans(qtd->session_base);
if (!xaccTransEqual (trans, list->data, TRUE, TRUE)) if (!xaccTransEqual(trans, list->data, TRUE, TRUE)) {
{
failure("matching transaction is wrong"); failure("matching transaction is wrong");
g_list_free(list); g_list_free(list);
return FALSE; return FALSE;
@ -608,14 +612,12 @@ compare_balances (GNCSession *session_1, GNCSession *session_2)
ok = TRUE; ok = TRUE;
list = xaccGroupGetSubAccounts(gnc_book_get_group(book_1)); list = xaccGroupGetSubAccounts(gnc_book_get_group(book_1));
for (node = list; node; node = node->next) for (node = list; node; node = node->next) {
{
Account *account_1 = node->data; Account *account_1 = node->data;
Account *account_2; Account *account_2;
account_2 = xaccAccountLookup(xaccAccountGetGUID(account_1), book_2); account_2 = xaccAccountLookup(xaccAccountGetGUID(account_1), book_2);
if (!account_2) if (!account_2) {
{
failure_args("", __FILE__, __LINE__, failure_args("", __FILE__, __LINE__,
"session_1 has account %s but not session_2", "session_1 has account %s but not session_2",
guid_to_string(xaccAccountGetGUID(account_1))); guid_to_string(xaccAccountGetGUID(account_1)));
@ -623,8 +625,7 @@ compare_balances (GNCSession *session_1, GNCSession *session_2)
} }
if (!gnc_numeric_equal(xaccAccountGetBalance(account_1), if (!gnc_numeric_equal(xaccAccountGetBalance(account_1),
xaccAccountGetBalance (account_2))) xaccAccountGetBalance(account_2))) {
{
failure_args("", __FILE__, __LINE__, failure_args("", __FILE__, __LINE__,
"balances not equal for account %s", "balances not equal for account %s",
guid_to_string(xaccAccountGetGUID(account_1))); guid_to_string(xaccAccountGetGUID(account_1)));
@ -632,8 +633,7 @@ compare_balances (GNCSession *session_1, GNCSession *session_2)
} }
if (!gnc_numeric_equal(xaccAccountGetClearedBalance(account_1), if (!gnc_numeric_equal(xaccAccountGetClearedBalance(account_1),
xaccAccountGetClearedBalance (account_2))) xaccAccountGetClearedBalance(account_2))) {
{
failure_args("", __FILE__, __LINE__, failure_args("", __FILE__, __LINE__,
"cleared balances not equal for account %s", "cleared balances not equal for account %s",
guid_to_string(xaccAccountGetGUID(account_1))); guid_to_string(xaccAccountGetGUID(account_1)));
@ -641,8 +641,7 @@ compare_balances (GNCSession *session_1, GNCSession *session_2)
} }
if (!gnc_numeric_equal(xaccAccountGetReconciledBalance(account_1), if (!gnc_numeric_equal(xaccAccountGetReconciledBalance(account_1),
xaccAccountGetReconciledBalance (account_2))) xaccAccountGetReconciledBalance(account_2))) {
{
failure_args("", __FILE__, __LINE__, failure_args("", __FILE__, __LINE__,
"reconciled balances not equal for account %s", "reconciled balances not equal for account %s",
guid_to_string(xaccAccountGetGUID(account_1))); guid_to_string(xaccAccountGetGUID(account_1)));
@ -660,21 +659,20 @@ compare_balances (GNCSession *session_1, GNCSession *session_2)
} }
static gboolean static gboolean
test_queries (GNCSession *session_base, const char *db_name, const char *mode) test_queries(GNCSession * session_base, DbInfo *dbinfo)
{ {
QueryTestData qtd; QueryTestData qtd;
AccountGroup *group; AccountGroup *group;
GNCBook *book; GNCBook *book;
gboolean ok; gboolean ok;
g_return_val_if_fail (db_name && mode, FALSE); g_return_val_if_fail(dbinfo->dbname && dbinfo->mode, FALSE);
book = gnc_session_get_book(session_base); book = gnc_session_get_book(session_base);
group = gnc_book_get_group(book); group = gnc_book_get_group(book);
qtd.session_base = session_base; qtd.session_base = session_base;
qtd.db_name = db_name; qtd.dbinfo = dbinfo;
qtd.mode = mode;
qtd.loaded = 0; qtd.loaded = 0;
qtd.total = 0; qtd.total = 0;
@ -688,8 +686,7 @@ test_queries (GNCSession *session_base, const char *db_name, const char *mode)
return ok; return ok;
} }
typedef struct typedef struct {
{
GNCSession *session_1; GNCSession *session_1;
GNCSession *session_2; GNCSession *session_2;
@ -738,8 +735,7 @@ test_trans_update (Transaction *trans, gpointer data)
trans_2 = xaccTransLookup(&guid, book_2); trans_2 = xaccTransLookup(&guid, book_2);
/* This should get rolled back. */ /* This should get rolled back. */
if (trans_2) if (trans_2) {
{
xaccTransBeginEdit(trans_2); xaccTransBeginEdit(trans_2);
make_random_changes_to_transaction_and_splits(book_2, trans_2, make_random_changes_to_transaction_and_splits(book_2, trans_2,
td->accounts_2); td->accounts_2);
@ -776,8 +772,35 @@ add_trans_helper (Transaction *trans, gpointer data)
} }
static gboolean static gboolean
test_updates_2 (GNCSession *session_base, drop_database(DbInfo *dbinfo)
const char *db_name, const char *mode) {
gchar *dropdb = NULL;
int rc;
if (!g_strncasecmp(dbinfo->port, "7777", 4)) {
dropdb = g_strdup_printf("dropdb -p %s %s",
dbinfo->port, dbinfo->dbname);
} else {
dropdb = g_strdup_printf("dropdb -p %s -h %s %s",
dbinfo->port, dbinfo->host,
dbinfo->dbname);
}
/* Make sure everything is logged off */
sleep(5);
rc = system(dropdb);
printf("Executed %s,\nreturn code was %d\n", dropdb, rc);
if (rc) {
printf("Please run the command\n"
"\t%s\nwhen this process completes\n", dropdb);
}
g_free(dropdb);
dropdb = NULL;
return rc == 0 ? TRUE : FALSE;
}
static gboolean
test_updates_2(GNCSession * session_base, DbInfo *dbinfo)
{ {
UpdateTestData td; UpdateTestData td;
char *filename; char *filename;
@ -785,11 +808,11 @@ test_updates_2 (GNCSession *session_base,
GList *node; GList *node;
gboolean ok; gboolean ok;
g_return_val_if_fail (session_base && db_name && mode, FALSE); g_return_val_if_fail(session_base && dbinfo->dbname && dbinfo->mode, FALSE);
filename = db_file_url (db_name, mode); filename = db_file_url(dbinfo);
if (!load_db_file (session_base, db_name, mode, FALSE)) if (!load_db_file(session_base, dbinfo, FALSE))
return FALSE; return FALSE;
multi_user_get_everything(session_base, NULL); multi_user_get_everything(session_base, NULL);
@ -801,7 +824,7 @@ test_updates_2 (GNCSession *session_base,
td.session_2 = gnc_session_new(); td.session_2 = gnc_session_new();
if (!load_db_file (td.session_2, db_name, mode, FALSE)) if (!load_db_file(td.session_2, dbinfo, FALSE))
return FALSE; return FALSE;
multi_user_get_everything(td.session_2, NULL); multi_user_get_everything(td.session_2, NULL);
@ -813,8 +836,7 @@ test_updates_2 (GNCSession *session_base,
ok = TRUE; ok = TRUE;
transes = NULL; transes = NULL;
xaccGroupForEachTransaction(td.group_1, add_trans_helper, &transes); xaccGroupForEachTransaction(td.group_1, add_trans_helper, &transes);
for (node = transes; node; node = node->next) for (node = transes; node; node = node->next) {
{
ok = test_trans_update(node->data, &td); ok = test_trans_update(node->data, &td);
if (!ok) if (!ok)
return FALSE; return FALSE;
@ -822,8 +844,7 @@ test_updates_2 (GNCSession *session_base,
g_list_free(transes); g_list_free(transes);
#if 0 #if 0
for (node = td.accounts_1; node; node = node->next) for (node = td.accounts_1; node; node = node->next) {
{
Account *account_1 = node->data; Account *account_1 = node->data;
Account *account_2 = Account *account_2 =
xaccAccountLookup(xaccAccountGetGUID(account_1), td.book_2); xaccAccountLookup(xaccAccountGetGUID(account_1), td.book_2);
@ -835,7 +856,8 @@ test_updates_2 (GNCSession *session_base,
if (account_1 && account_2) if (account_1 && account_2)
ok = ok && (account_1->version == account_2->version); ok = ok && (account_1->version == account_2->version);
ok = ok && (gnc_session_get_error (td.session_2) == ERR_BACKEND_MODIFIED); ok = ok
&& (gnc_session_get_error(td.session_2) == ERR_BACKEND_MODIFIED);
if (!do_test_args(ok, if (!do_test_args(ok,
"test account rollback", "test account rollback",
@ -860,8 +882,7 @@ test_updates_2 (GNCSession *session_base,
xaccAccountCommitEdit(account); xaccAccountCommitEdit(account);
xaccTransBeginEdit(trans); xaccTransBeginEdit(trans);
for (node = xaccTransGetSplitList (trans); node; node = node->next) for (node = xaccTransGetSplitList(trans); node; node = node->next) {
{
Split *split = node->data; Split *split = node->data;
xaccAccountInsertSplit(child, split); xaccAccountInsertSplit(child, split);
@ -878,14 +899,14 @@ test_updates_2 (GNCSession *session_base,
xaccFreeQuery(q); xaccFreeQuery(q);
if (ok) if (ok) {
{
Transaction *trans_2; Transaction *trans_2;
Account *account_2; Account *account_2;
Account *child_2; Account *child_2;
trans_2 = xaccTransLookup(xaccTransGetGUID(trans), td.book_2); trans_2 = xaccTransLookup(xaccTransGetGUID(trans), td.book_2);
account_2 = xaccAccountLookup (xaccAccountGetGUID (account), td.book_2); account_2 =
xaccAccountLookup(xaccAccountGetGUID(account), td.book_2);
child_2 = xaccAccountLookup(xaccAccountGetGUID(child), td.book_2); child_2 = xaccAccountLookup(xaccAccountGetGUID(child), td.book_2);
ok = ok && xaccTransEqual(trans, trans_2, TRUE, TRUE); ok = ok && xaccTransEqual(trans, trans_2, TRUE, TRUE);
@ -911,27 +932,29 @@ test_updates_2 (GNCSession *session_base,
} }
static gboolean static gboolean
test_mode (const char *db_name, const char *mode, test_mode(DbInfo *dbinfo, gboolean updates, gboolean multi_user)
gboolean updates, gboolean multi_user)
{ {
GNCSession *session; GNCSession *session;
GNCSession *session_db; GNCSession *session_db;
gboolean ok; gboolean ok;
gchar *modesave = dbinfo->mode;
gchar *sumode = "single-update";
session = get_random_session(); session = get_random_session();
add_random_transactions_to_book(gnc_session_get_book(session), 20); add_random_transactions_to_book(gnc_session_get_book(session), 20);
if (!save_db_file (session, db_name, "single-update")) dbinfo->mode = sumode;
if (!save_db_file(session, dbinfo))
return FALSE; return FALSE;
dbinfo->mode = modesave;
session_db = gnc_session_new(); session_db = gnc_session_new();
if (!load_db_file (session_db, db_name, mode, !multi_user)) if (!load_db_file(session_db, dbinfo, !multi_user))
return FALSE; return FALSE;
if (multi_user) if (multi_user) {
{
if (!compare_balances(session, session_db)) if (!compare_balances(session, session_db))
return FALSE; return FALSE;
@ -943,10 +966,9 @@ test_mode (const char *db_name, const char *mode,
do_test_args(ok, "Books equal", __FILE__, __LINE__, do_test_args(ok, "Books equal", __FILE__, __LINE__,
"Books not equal for session %s in mode %s", "Books not equal for session %s in mode %s",
db_name, mode); dbinfo->dbname, dbinfo->mode);
if (multi_user) if (multi_user) {
{
GNCBackendError io_err; GNCBackendError io_err;
gnc_session_end(session_db); gnc_session_end(session_db);
@ -955,26 +977,25 @@ test_mode (const char *db_name, const char *mode,
"Ending db session", "Ending db session",
__FILE__, __LINE__, __FILE__, __LINE__,
"can't end session for %s in mode %s", "can't end session for %s in mode %s",
db_name, mode)) dbinfo->dbname, dbinfo->mode))
return FALSE; return FALSE;
} }
if (!ok) if (!ok) {
{
save_xml_files(session, session_db); save_xml_files(session, session_db);
return FALSE; return FALSE;
} }
if (!test_access (db_name, mode, multi_user)) if (!test_access(dbinfo, multi_user))
return FALSE; return FALSE;
if (updates && !test_updates (session_db, db_name, mode, multi_user)) if (updates && !test_updates(session_db, dbinfo, multi_user))
return FALSE; return FALSE;
if (multi_user && !test_queries (session_db, db_name, mode)) if (multi_user && !test_queries(session_db, dbinfo))
return FALSE; return FALSE;
if (updates && !test_updates_2 (session_db, db_name, mode)) if (updates && !test_updates_2(session_db, dbinfo))
return FALSE; return FALSE;
gnc_session_destroy(session); gnc_session_destroy(session);
@ -984,8 +1005,9 @@ test_mode (const char *db_name, const char *mode,
} }
static void static void
run_test (void) run_test(DbInfo *dbinfo)
{ {
#if 0 #if 0
if (!test_mode("single_file", "single-file", FALSE, FALSE)) if (!test_mode("single_file", "single-file", FALSE, FALSE))
return; return;
@ -1002,30 +1024,39 @@ run_test (void)
#endif #endif
#if 1 #if 1
if (!test_mode ("multi_user_poll", "multi-user-poll", TRUE, TRUE)) dbinfo->dbname = "multi_user_poll";
return; dbinfo->mode = "multi-user-poll";
/** Account for previous failed checks */
drop_database(dbinfo);
test_mode(dbinfo, TRUE, TRUE);
#endif #endif
drop_database(dbinfo);
} }
#if 0 #if 0
static void static void
test_performance (const char *db_name, const char *mode) test_performance(DbInfo *dbinfo)
{ {
GNCSession *session; GNCSession *session;
gchar *modesave = dbinfo->mode;
gchar *sumode = "single-update";
session = get_random_session(); session = get_random_session();
gnc_set_log_level(MOD_TEST, GNC_LOG_WARNING); gnc_set_log_level(MOD_TEST, GNC_LOG_WARNING);
dbinfo->mode = sumode;
START_CLOCK(0, "Starting to save session"); START_CLOCK(0, "Starting to save session");
if (!save_db_file (session, db_name, "single-update")) if (!save_db_file(session, dbinfo))
return; return;
REPORT_CLOCK(0, "Finished saving session"); REPORT_CLOCK(0, "Finished saving session");
dbinfo->mode = modesave;
gnc_session_destroy(session); gnc_session_destroy(session);
session = gnc_session_new(); session = gnc_session_new();
if (!load_db_file (session, db_name, mode, FALSE)) if (!load_db_file(session, dbinfo, FALSE))
return; return;
gnc_set_log_level(MOD_TEST, GNC_LOG_INFO); gnc_set_log_level(MOD_TEST, GNC_LOG_INFO);
@ -1046,8 +1077,29 @@ test_performance (const char *db_name, const char *mode)
static void static void
guile_main(int argc, char **argv) guile_main(int argc, char **argv)
{ {
DbInfo *dbinfo;
GNCModule *mod;
gnc_module_system_init(); gnc_module_system_init();
gnc_module_load ("gnucash/engine", 0); mod = gnc_module_load("gnucash/engine", 0);
dbinfo = g_new0(DbInfo, 1);
if (argc >= 2)
dbinfo->host = argv[1];
else {
dbinfo->host = getenv("PGHOST");
if (!dbinfo->host)
dbinfo->host = "localhost";
}
if (argc >= 3)
dbinfo->port = argv[2];
else {
dbinfo->port = getenv("PGPORT");
if (!dbinfo->port)
dbinfo->port = "5432";
}
/* g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING); */ /* g_log_set_always_fatal (G_LOG_LEVEL_CRITICAL | G_LOG_LEVEL_WARNING); */
@ -1071,7 +1123,7 @@ guile_main (int argc, char **argv)
xaccLogDisable(); xaccLogDisable();
run_test (); run_test(dbinfo);
print_test_results(); print_test_results();
exit(get_rv()); exit(get_rv());