Load account balances at startup. Load splits for an account as

required.


git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@17713 57a11ea4-9604-0410-9ed3-97b8803252fd
This commit is contained in:
Phil Longstaff 2008-11-23 18:04:16 +00:00
parent ed0548c6e3
commit f694f96e21
6 changed files with 358 additions and 92 deletions

View File

@ -441,6 +441,10 @@ init_sql_backend( GncDbiBackend* dbi_be )
be->load_config = NULL; be->load_config = NULL;
be->get_config = NULL; be->get_config = NULL;
be->compile_query = gnc_sql_compile_query;
be->run_query = gnc_sql_run_query;
be->free_query = gnc_sql_free_query;
be->export = NULL; be->export = NULL;
if( !initialized ) { if( !initialized ) {

View File

@ -183,6 +183,8 @@ load_all_accounts( GncSqlBackend* be )
Account* parent; Account* parent;
GList* l_accounts_needing_parents = NULL; GList* l_accounts_needing_parents = NULL;
GList* list = NULL; GList* list = NULL;
GSList* bal_slist;
GSList* bal;
g_return_if_fail( be != NULL ); g_return_if_fail( be != NULL );
@ -245,6 +247,20 @@ load_all_accounts( GncSqlBackend* be )
gnc_account_append_child( root, s->pAccount ); gnc_account_append_child( root, s->pAccount );
} }
} }
/* Load starting balances */
bal_slist = gnc_sql_get_account_balances_slist( be );
for( bal = bal_slist; bal != NULL; bal = bal->next ) {
acct_balances_t* balances = (acct_balances_t*)bal->data;
g_object_set( balances->acct,
"start-balance", &balances->balance,
"start-cleared-balance", &balances->cleared_balance,
"start-reconciled-balance", &balances->reconciled_balance,
NULL);
}
g_slist_free( bal_slist );
} }
} }

View File

@ -669,7 +669,7 @@ compile_query_cb( const gchar* type, gpointer data_p, gpointer be_data_p )
} }
} }
static gpointer gpointer
gnc_sql_compile_query( QofBackend* pBEnd, QofQuery* pQuery ) gnc_sql_compile_query( QofBackend* pBEnd, QofQuery* pQuery )
{ {
GncSqlBackend *be = (GncSqlBackend*)pBEnd; GncSqlBackend *be = (GncSqlBackend*)pBEnd;
@ -752,7 +752,7 @@ free_query_cb( const gchar* type, gpointer data_p, gpointer be_data_p )
} }
} }
static void void
gnc_sql_free_query( QofBackend* pBEnd, gpointer pQuery ) gnc_sql_free_query( QofBackend* pBEnd, gpointer pQuery )
{ {
GncSqlBackend *be = (GncSqlBackend*)pBEnd; GncSqlBackend *be = (GncSqlBackend*)pBEnd;
@ -802,7 +802,7 @@ run_query_cb( const gchar* type, gpointer data_p, gpointer be_data_p )
} }
} }
static void void
gnc_sql_run_query( QofBackend* pBEnd, gpointer pQuery ) gnc_sql_run_query( QofBackend* pBEnd, gpointer pQuery )
{ {
GncSqlBackend *be = (GncSqlBackend*)pBEnd; GncSqlBackend *be = (GncSqlBackend*)pBEnd;

View File

@ -672,4 +672,8 @@ gboolean gnc_sql_commit_standard_item( GncSqlBackend* be, QofInstance* inst, con
void _retrieve_guid_( gpointer pObject, gpointer pValue ); void _retrieve_guid_( gpointer pObject, gpointer pValue );
gpointer gnc_sql_compile_query( QofBackend* pBEnd, QofQuery* pQuery );
void gnc_sql_free_query( QofBackend* pBEnd, gpointer pQuery );
void gnc_sql_run_query( QofBackend* pBEnd, gpointer pQuery );
#endif /* GNC_BACKEND_SQL_H_ */ #endif /* GNC_BACKEND_SQL_H_ */

View File

@ -235,7 +235,6 @@ load_all_splits_for_tx( GncSqlBackend* be, const GUID* tx_guid )
GncSqlStatement* stmt; GncSqlStatement* stmt;
GValue value; GValue value;
gchar* buf; gchar* buf;
GError* error = NULL;
g_return_if_fail( be != NULL ); g_return_if_fail( be != NULL );
g_return_if_fail( tx_guid != NULL ); g_return_if_fail( tx_guid != NULL );
@ -247,7 +246,6 @@ load_all_splits_for_tx( GncSqlBackend* be, const GUID* tx_guid )
buf = g_strdup_printf( "SELECT * FROM %s WHERE tx_guid='%s'", SPLIT_TABLE, guid_buf ); buf = g_strdup_printf( "SELECT * FROM %s WHERE tx_guid='%s'", SPLIT_TABLE, guid_buf );
stmt = gnc_sql_create_statement_from_sql( be, buf ); stmt = gnc_sql_create_statement_from_sql( be, buf );
g_free( buf );
result = gnc_sql_execute_select_statement( be, stmt ); result = gnc_sql_execute_select_statement( be, stmt );
gnc_sql_statement_dispose( stmt ); gnc_sql_statement_dispose( stmt );
@ -341,6 +339,78 @@ load_single_tx( GncSqlBackend* be, GncSqlRow* row )
return pTx; return pTx;
} }
/**
* Structure to hold start/end balances for each account. The values are
* saved before splits are loaded, and then used to adjust the start balances
* so that the end balances (which are calculated and correct on initial load)
* are unchanged.
*/
typedef struct {
Account* acc;
gnc_numeric start_bal;
gnc_numeric end_bal;
gnc_numeric start_cleared_bal;
gnc_numeric end_cleared_bal;
gnc_numeric start_reconciled_bal;
gnc_numeric end_reconciled_bal;
} full_acct_balances_t;
static Account* g_acct;
/**
* Save the start/end balances for an account.
*/
static void
save_account_balances( Account* acc, gpointer pData )
{
GSList** pBal_list = (GSList**)pData;
full_acct_balances_t* newbal;
gnc_numeric* pstart;
gnc_numeric* pend;
gnc_numeric* pstart_c;
gnc_numeric* pend_c;
gnc_numeric* pstart_r;
gnc_numeric* pend_r;
newbal = g_malloc( sizeof( full_acct_balances_t ) );
newbal->acc = acc;
g_object_get( acc,
"start-balance", &pstart,
"end-balance", &pend,
"start-cleared-balance", &pstart_c,
"end-cleared-balance", &pend_c,
"start-reconciled-balance", &pstart_r,
"end-reconciled-balance", &pend_r,
NULL );
newbal->start_bal = *pstart;
newbal->end_bal = *pend;
newbal->start_cleared_bal = *pstart_c;
newbal->end_cleared_bal = *pend_c;
newbal->start_reconciled_bal = *pstart_r;
newbal->end_reconciled_bal = *pend_r;
*pBal_list = g_slist_append( *pBal_list, newbal );
#if 0
{
if( g_acct == NULL ) {
const gchar* name = xaccAccountGetName( acc );
if( strcmp( name, "Dividend Income" ) == 0 ) {
g_acct = acc;
}
}
if( g_acct != NULL && g_acct == acc ) {
printf( "save_account_balance: baln = %s: %s\n",
gnc_numeric_to_string( newbal->start_bal ),
gnc_numeric_to_string( newbal->end_bal ) );
}
}
#endif
}
/**
* Executes a transaction query statement and loads the transactions and all
* of the splits.
*/
static void static void
query_transactions( GncSqlBackend* be, GncSqlStatement* stmt ) query_transactions( GncSqlBackend* be, GncSqlStatement* stmt )
{ {
@ -355,7 +425,20 @@ query_transactions( GncSqlBackend* be, GncSqlStatement* stmt )
GList* node; GList* node;
GncSqlRow* row; GncSqlRow* row;
Transaction* tx; Transaction* tx;
GSList* bal_list = NULL;
GSList* nextbal;
Account* root = gnc_book_get_root_account( be->primary_book );
qof_event_suspend();
xaccAccountBeginEdit( root );
// Save the start/ending balances (balance, cleared and reconciled) for
// every account.
gnc_account_foreach_descendant( gnc_book_get_root_account( be->primary_book ),
save_account_balances,
&bal_list );
// Load the transactions
row = gnc_sql_result_get_first_row( result ); row = gnc_sql_result_get_first_row( result );
while( row != NULL ) { while( row != NULL ) {
tx = load_single_tx( be, row ); tx = load_single_tx( be, row );
@ -366,6 +449,7 @@ query_transactions( GncSqlBackend* be, GncSqlStatement* stmt )
} }
gnc_sql_result_dispose( result ); gnc_sql_result_dispose( result );
// Load all splits and slots for the transactions
if( tx_list != NULL ) { if( tx_list != NULL ) {
gnc_sql_slots_load_for_list( be, tx_list ); gnc_sql_slots_load_for_list( be, tx_list );
load_splits_for_tx_list( be, tx_list ); load_splits_for_tx_list( be, tx_list );
@ -376,39 +460,77 @@ query_transactions( GncSqlBackend* be, GncSqlStatement* stmt )
Transaction* pTx = GNC_TRANSACTION(node->data); Transaction* pTx = GNC_TRANSACTION(node->data);
xaccTransCommitEdit( pTx ); xaccTransCommitEdit( pTx );
} }
// Update the account balances based on the loaded splits. If the end
// balance has changed, update the start balance so that the end
// balance is the same as it was before the splits were loaded.
// Repeat for cleared and reconciled balances.
for( nextbal = bal_list; nextbal != NULL; nextbal = nextbal->next ) {
full_acct_balances_t* balns = (full_acct_balances_t*)nextbal->data;
gnc_numeric* pnew_end_bal;
gnc_numeric* pnew_end_c_bal;
gnc_numeric* pnew_end_r_bal;
gnc_numeric adj;
g_object_get( balns->acc,
"end-balance", &pnew_end_bal,
"end-cleared-balance", &pnew_end_c_bal,
"end-reconciled-balance", &pnew_end_r_bal,
NULL );
#if 0
{
if( g_acct != NULL && balns->acc == g_acct ) {
printf( "Before: %s after %s\n",
gnc_numeric_to_string( balns->end_bal ),
gnc_numeric_to_string( *pnew_end_bal ) );
} }
} }
#endif
static void if( !gnc_numeric_eq( *pnew_end_bal, balns->end_bal ) ) {
load_tx_by_guid( GncSqlBackend* be, GUID* tx_guid ) adj = gnc_numeric_sub( balns->end_bal, *pnew_end_bal,
GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD );
#if 0
{ {
GncSqlStatement* stmt; if( g_acct != NULL && balns->acc == g_acct ) {
gchar* sql; printf( "adj: %s start (before) = %s", gnc_numeric_to_string( adj ), gnc_numeric_to_string( balns->start_bal ) );
gchar guid_buf[GUID_ENCODING_LENGTH+1]; }
g_return_if_fail( be != NULL );
g_return_if_fail( tx_guid != NULL );
guid_to_string_buff( tx_guid, guid_buf );
sql = g_strdup_printf( "SELECT * FROM %s WHERE guid = %s", TRANSACTION_TABLE, guid_buf );
stmt = gnc_sql_create_statement_from_sql( be, sql );
query_transactions( be, stmt );
gnc_sql_statement_dispose( stmt );
} }
#endif
/* ================================================================= */ balns->start_bal = gnc_numeric_add( balns->start_bal, adj,
static void GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD );
load_all_tx( GncSqlBackend* be ) #if 0
{ {
gchar* sql; if( g_acct != NULL && balns->acc == g_acct ) {
GncSqlStatement* stmt; printf( " start (after) = %s\n", gnc_numeric_to_string( balns->start_bal ) );
}
}
#endif
g_object_set( balns->acc, "start-balance", &balns->start_bal, NULL );
}
if( !gnc_numeric_eq( *pnew_end_c_bal, balns->end_cleared_bal ) ) {
adj = gnc_numeric_sub( balns->end_cleared_bal, *pnew_end_c_bal,
GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD );
balns->start_cleared_bal = gnc_numeric_add( balns->start_cleared_bal, adj,
GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD );
g_object_set( balns->acc, "start-cleared-balance", &balns->start_cleared_bal, NULL );
}
if( !gnc_numeric_eq( *pnew_end_r_bal, balns->end_reconciled_bal ) ) {
adj = gnc_numeric_sub( balns->end_reconciled_bal, *pnew_end_r_bal,
GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD );
balns->start_reconciled_bal = gnc_numeric_add( balns->start_reconciled_bal, adj,
GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD );
g_object_set( balns->acc, "start-reconciled-balance", &balns->start_reconciled_bal, NULL );
}
xaccAccountRecomputeBalance( balns->acc );
}
g_slist_free( bal_list );
g_return_if_fail( be != NULL ); xaccAccountCommitEdit( root );
qof_event_resume();
sql = g_strdup_printf( "SELECT * FROM %s", TRANSACTION_TABLE ); }
stmt = gnc_sql_create_statement_from_sql( be, sql );
query_transactions( be, stmt );
gnc_sql_statement_dispose( stmt );
} }
/* ================================================================= */ /* ================================================================= */
@ -626,77 +748,57 @@ get_guid_from_query( QofQuery* pQuery )
} }
} }
typedef struct {
GncSqlStatement* stmt;
Account* acct;
gboolean has_been_run;
} split_query_info_t;
static gpointer static gpointer
compile_split_query( GncSqlBackend* be, QofQuery* pQuery ) compile_split_query( GncSqlBackend* be, QofQuery* pQuery )
{ {
GString* sql;
const GUID* acct_guid; const GUID* acct_guid;
gchar guid_buf[GUID_ENCODING_LENGTH+1]; gchar guid_buf[GUID_ENCODING_LENGTH+1];
GncSqlResult* result; GncSqlResult* result;
gchar* buf; split_query_info_t* query_info;
gchar* subquery_sql;
gchar* query_sql;
g_return_val_if_fail( be != NULL, NULL ); g_return_val_if_fail( be != NULL, NULL );
g_return_val_if_fail( pQuery != NULL, NULL ); g_return_val_if_fail( pQuery != NULL, NULL );
acct_guid = get_guid_from_query( pQuery ); acct_guid = get_guid_from_query( pQuery );
guid_to_string_buff( acct_guid, guid_buf ); guid_to_string_buff( acct_guid, guid_buf );
sql = g_string_new( "" ); subquery_sql = g_strdup_printf( "SELECT DISTINCT tx_guid FROM %s WHERE account_guid='%s'", SPLIT_TABLE, guid_buf );
g_string_printf( sql, "SELECT DISTINCT tx_guid FROM %s WHERE account_guid='%s'", SPLIT_TABLE, guid_buf ); query_sql = g_strdup_printf( "SELECT * FROM %s WHERE guid IN (%s)", TRANSACTION_TABLE, subquery_sql );
result = gnc_sql_execute_select_sql( be, sql->str );
if( result != NULL ) {
int numRows;
int r;
GncSqlRow* row;
numRows = gnc_sql_result_get_num_rows( result ); query_info = g_malloc( sizeof(split_query_info_t) );
sql = g_string_sized_new( 40+(GUID_ENCODING_LENGTH+3)*numRows ); query_info->stmt = gnc_sql_create_statement_from_sql( be, query_sql );
query_info->has_been_run = FALSE;
query_info->acct = xaccAccountLookup( acct_guid, be->primary_book );
if( numRows != 1 ) { g_free( subquery_sql );
g_string_printf( sql, "SELECT * FROM %s WHERE guid IN (", TRANSACTION_TABLE );
} else {
g_string_printf( sql, "SELECT * FROM %s WHERE guid =", TRANSACTION_TABLE );
}
row = gnc_sql_result_get_first_row( result ); return query_info;
for( r = 0; row != NULL; r++ ) {
const GUID* guid;
guid = gnc_sql_load_tx_guid( be, row );
guid_to_string_buff( guid, guid_buf );
if( r != 0 ) {
g_string_append( sql, "," );
}
g_string_append( sql, "'" );
g_string_append( sql, guid_buf );
g_string_append( sql, "'" );
row = gnc_sql_result_get_next_row( result );
}
gnc_sql_result_dispose( result );
if( numRows != 1 ) {
g_string_append( sql, ")" );
}
}
buf = sql->str;
g_string_free( sql, FALSE );
return buf;
} }
static void static void
run_split_query( GncSqlBackend* be, gpointer pQuery ) run_split_query( GncSqlBackend* be, gpointer pQuery )
{ {
GncSqlStatement* stmt; split_query_info_t* query_info = (split_query_info_t*)pQuery;
gchar* sql;
g_return_if_fail( be != NULL ); g_return_if_fail( be != NULL );
g_return_if_fail( pQuery != NULL ); g_return_if_fail( pQuery != NULL );
sql = (gchar*)pQuery; // When the query to load all splits for the account has been run, set the
// mark so that this account's query is not reexecuted.
stmt = gnc_sql_create_statement_from_sql( be, sql ); if( !query_info->has_been_run && xaccAccountGetMark( query_info->acct ) == 0 ) {
query_transactions( be, stmt ); query_transactions( be, query_info->stmt );
gnc_sql_statement_dispose( stmt ); query_info->has_been_run = TRUE;
gnc_sql_statement_dispose( query_info->stmt );
query_info->stmt = NULL;
xaccAccountSetMark( query_info->acct, 1 );
}
} }
static void static void
@ -708,6 +810,145 @@ free_split_query( GncSqlBackend* be, gpointer pQuery )
g_free( pQuery ); g_free( pQuery );
} }
/* ----------------------------------------------------------------- */
typedef struct {
const GncSqlBackend* be;
Account* acct;
char reconcile_state;
gnc_numeric balance;
} single_acct_balance_t;
static void
set_acct_bal_account_from_guid( gpointer pObject, gpointer pValue )
{
single_acct_balance_t* bal = (single_acct_balance_t*)pObject;
const GUID* guid = (const GUID*)pValue;
g_return_if_fail( pObject != NULL );
g_return_if_fail( pValue != NULL );
bal->acct = xaccAccountLookup( guid, bal->be->primary_book );
}
static void
set_acct_bal_reconcile_state( gpointer pObject, gpointer pValue )
{
single_acct_balance_t* bal = (single_acct_balance_t*)pObject;
const gchar* s = (const gchar*)pValue;
g_return_if_fail( pObject != NULL );
g_return_if_fail( pValue != NULL );
bal->reconcile_state = s[0];
}
static void
set_acct_bal_balance( gpointer pObject, gnc_numeric value )
{
single_acct_balance_t* bal = (single_acct_balance_t*)pObject;
g_return_if_fail( pObject != NULL );
bal->balance = value;
}
static const GncSqlColumnTableEntry acct_balances_col_table[] =
{
{ "account_guid", CT_GUID, 0, 0, NULL, NULL, NULL, set_acct_bal_account_from_guid },
{ "reconcile_state", CT_STRING, 1, 0, NULL, NULL, NULL, set_acct_bal_reconcile_state },
{ "quantity", CT_NUMERIC, 0, 0, NULL, NULL, NULL, (QofSetterFunc)set_acct_bal_balance },
{ NULL }
};
static single_acct_balance_t*
load_single_acct_balances( const GncSqlBackend* be, GncSqlRow* row )
{
single_acct_balance_t* bal = NULL;
g_return_val_if_fail( be != NULL, NULL );
g_return_val_if_fail( row != NULL, NULL );
bal = g_malloc( sizeof(single_acct_balance_t) );
bal->be = be;
gnc_sql_load_object( be, row, NULL, bal, acct_balances_col_table );
return bal;
}
GSList*
gnc_sql_get_account_balances_slist( GncSqlBackend* be )
{
GncSqlResult* result;
gchar guid_buf[GUID_ENCODING_LENGTH+1];
GncSqlStatement* stmt;
GValue value;
gchar* buf;
GSList* bal_slist = NULL;
g_return_val_if_fail( be != NULL, NULL );
buf = g_strdup_printf( "SELECT account_guid, reconcile_state, sum(quantity_num) as quantity_num, quantity_denom FROM %s GROUP BY account_guid, reconcile_state, quantity_denom",
SPLIT_TABLE );
stmt = gnc_sql_create_statement_from_sql( be, buf );
result = gnc_sql_execute_select_statement( be, stmt );
gnc_sql_statement_dispose( stmt );
if( result != NULL ) {
int r;
GList* list = NULL;
GncSqlRow* row;
acct_balances_t* bal = NULL;
row = gnc_sql_result_get_first_row( result );
while( row != NULL ) {
single_acct_balance_t* single_bal;
// Get the next reconcile state balance and merge with other balances
single_bal = load_single_acct_balances( be, row );
if( single_bal != NULL ) {
if( bal != NULL && bal->acct != single_bal->acct ) {
bal->cleared_balance = gnc_numeric_add( bal->cleared_balance, bal->reconciled_balance,
GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD );
bal->balance = gnc_numeric_add( bal->balance, bal->cleared_balance,
GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD );
bal_slist = g_slist_append( bal_slist, bal );
bal = NULL;
}
if( bal == NULL ) {
bal = g_malloc( sizeof(acct_balances_t) );
bal->acct = single_bal->acct;
bal->balance = gnc_numeric_zero();
bal->cleared_balance = gnc_numeric_zero();
bal->reconciled_balance = gnc_numeric_zero();
}
if( single_bal->reconcile_state == 'n' ) {
bal->balance = gnc_numeric_add( bal->balance, single_bal->balance,
GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD );
} else if( single_bal->reconcile_state == 'c' ) {
bal->cleared_balance = gnc_numeric_add( bal->cleared_balance, single_bal->balance,
GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD );
} else if( single_bal->reconcile_state == 'y' ) {
bal->reconciled_balance = gnc_numeric_add( bal->reconciled_balance, single_bal->balance,
GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD );
}
}
row = gnc_sql_result_get_next_row( result );
}
// Add the final balance
if( bal != NULL ) {
bal->cleared_balance = gnc_numeric_add( bal->cleared_balance, bal->reconciled_balance,
GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD );
bal->balance = gnc_numeric_add( bal->balance, bal->cleared_balance,
GNC_DENOM_AUTO, GNC_HOW_DENOM_LCD );
bal_slist = g_slist_append( bal_slist, bal );
}
gnc_sql_result_dispose( result );
}
return bal_slist;
}
/* ----------------------------------------------------------------- */ /* ----------------------------------------------------------------- */
static void static void
load_tx_guid( const GncSqlBackend* be, GncSqlRow* row, load_tx_guid( const GncSqlBackend* be, GncSqlRow* row,
@ -755,7 +996,7 @@ gnc_sql_init_transaction_handler( void )
GNC_SQL_BACKEND_VERSION, GNC_SQL_BACKEND_VERSION,
GNC_ID_TRANS, GNC_ID_TRANS,
commit_transaction, /* commit */ commit_transaction, /* commit */
load_all_tx, /* initial_load */ NULL,
create_transaction_tables /* create tables */ create_transaction_tables /* create tables */
}; };
static GncSqlObjectBackend be_data_split = static GncSqlObjectBackend be_data_split =

View File

@ -35,17 +35,18 @@
void gnc_sql_init_transaction_handler( void ); void gnc_sql_init_transaction_handler( void );
void gnc_sql_transaction_commit_splits( GncSqlBackend* be, Transaction* pTx ); void gnc_sql_transaction_commit_splits( GncSqlBackend* be, Transaction* pTx );
gboolean gnc_sql_save_transaction( GncSqlBackend* be, QofInstance* inst ); gboolean gnc_sql_save_transaction( GncSqlBackend* be, QofInstance* inst );
void gnc_sql_get_account_balances( GncSqlBackend* be, Account* pAccount,
gnc_numeric* start_balance,
gnc_numeric* cleared_balance,
gnc_numeric* reconciled_balance );
typedef struct { typedef struct {
Account* acct; Account* acct;
gnc_numeric start_balance; gnc_numeric balance;
gnc_numeric cleared_balance; gnc_numeric cleared_balance;
gnc_numeric reconciled_balance; gnc_numeric reconciled_balance;
} acct_balances_t; } acct_balances_t;
GList* gnc_sql_get_account_balances_for_list( GncSqlBackend* be, GList* list );
/**
* Returns a list of acct_balances_t structures, one for each account which
* has splits.
*/
GSList* gnc_sql_get_account_balances_slist( GncSqlBackend* be );
#endif /* GNC_TRANSACTION_SQL_H_ */ #endif /* GNC_TRANSACTION_SQL_H_ */