From 5f6813ed1e2e528083877f8b94b83eb7e6e6acbd Mon Sep 17 00:00:00 2001 From: Phil Longstaff Date: Sat, 15 Aug 2009 19:02:27 +0000 Subject: [PATCH] Add budget amounts table. This table contains 1 record per budget per account per period which has an amount set. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@18250 57a11ea4-9604-0410-9ed3-97b8803252fd --- src/backend/sql/gnc-backend-sql.h | 3 +- src/backend/sql/gnc-budget-sql.c | 267 +++++++++++++++++++++++++++++- 2 files changed, 267 insertions(+), 3 deletions(-) diff --git a/src/backend/sql/gnc-backend-sql.h b/src/backend/sql/gnc-backend-sql.h index 59ea6778b2..464c8cb9e7 100644 --- a/src/backend/sql/gnc-backend-sql.h +++ b/src/backend/sql/gnc-backend-sql.h @@ -310,9 +310,10 @@ typedef struct { #define CT_DOUBLE "ct_double" #define CT_BOOLEAN "ct_boolean" #define CT_ACCOUNTREF "ct_accountref" +#define CT_BUDGETREF "ct_budgetref" #define CT_COMMODITYREF "ct_commodityref" -#define CT_TXREF "ct_txref" #define CT_LOTREF "ct_lotref" +#define CT_TXREF "ct_txref" /** * @struct GncSqlColumnTableEntry diff --git a/src/backend/sql/gnc-budget-sql.c b/src/backend/sql/gnc-budget-sql.c index fca2b6d196..8f72672f67 100644 --- a/src/backend/sql/gnc-budget-sql.c +++ b/src/backend/sql/gnc-budget-sql.c @@ -48,6 +48,8 @@ #define BUDGET_TABLE "budgets" #define TABLE_VERSION 1 +#define AMOUNTS_TABLE "budget_amounts" +#define AMOUNTS_TABLE_VERSION 1 /*@ unused @*/ static QofLogModule log_module = G_LOG_DOMAIN; @@ -65,7 +67,213 @@ static const GncSqlColumnTableEntry col_table[] = /*@ +full_init_block @*/ }; +static /*@ dependent @*//*@ null @*/ QofInstance* get_budget( gpointer pObj ); +static /*@ dependent @*//*@ null @*/ QofInstance* get_account( gpointer pObj ); +static void set_account( gpointer pObj, gpointer val ); +static gint get_period_num( gpointer pObj ); +static void set_period_num( gpointer pObj, gpointer val ); +static gnc_numeric get_amount( gpointer pObj ); +static void set_amount( gpointer pObj, gnc_numeric value ); + +typedef struct { + GncBudget* budget; + Account* account; + guint period_num; +} budget_amount_info_t; + +static const GncSqlColumnTableEntry budget_amounts_col_table[] = +{ + /*@ -full_init_block @*/ + { "id", CT_INT, 0, COL_NNUL|COL_PKEY|COL_AUTOINC }, + { "budget_guid", CT_BUDGETREF, 0, COL_NNUL, NULL, NULL, + (QofAccessFunc)get_budget }, + { "account_guid", CT_ACCOUNTREF, 0, COL_NNUL, NULL, NULL, + (QofAccessFunc)get_account, (QofSetterFunc)set_account }, + { "period_num", CT_INT, 0, COL_NNUL, NULL, NULL, + (QofAccessFunc)get_period_num, (QofSetterFunc)set_period_num }, + { "amount", CT_NUMERIC, 0, COL_NNUL, NULL, NULL, + (QofAccessFunc)get_amount, (QofSetterFunc)set_amount }, + { NULL } + /*@ +full_init_block @*/ +}; + /* ================================================================= */ +static /*@ dependent @*//*@ null@ */ QofInstance* +get_budget( gpointer pObj ) +{ + budget_amount_info_t* info = (budget_amount_info_t*)pObj; + + g_return_val_if_fail( pObj != NULL, NULL ); + + return QOF_INSTANCE(info->budget); +} + +static /*@ dependent @*//*@ null @*/ QofInstance* +get_account( gpointer pObj ) +{ + budget_amount_info_t* info = (budget_amount_info_t*)pObj; + + g_return_val_if_fail( pObj != NULL, NULL ); + + return QOF_INSTANCE(info->account); +} + +static void +set_account( gpointer pObj, gpointer val ) +{ + budget_amount_info_t* info = (budget_amount_info_t*)pObj; + + g_return_if_fail( pObj != NULL ); + g_return_if_fail( val != NULL ); + g_return_if_fail( GNC_IS_ACCOUNT(val) ); + + info->account = GNC_ACCOUNT(val); +} + +static gint +get_period_num( gpointer pObj ) +{ + budget_amount_info_t* info = (budget_amount_info_t*)pObj; + + g_return_val_if_fail( pObj != NULL, 0 ); + + return info->period_num; +} + +static void +set_period_num( gpointer pObj, gpointer val ) +{ + budget_amount_info_t* info = (budget_amount_info_t*)pObj; + + g_return_if_fail( pObj != NULL ); + + info->period_num = (guint)val; +} + +static gnc_numeric +get_amount( gpointer pObj ) +{ + budget_amount_info_t* info = (budget_amount_info_t*)pObj; + + g_return_val_if_fail( pObj != NULL, gnc_numeric_zero() ); + + return gnc_budget_get_account_period_value( info->budget, info->account, info->period_num ); +} + +static void +set_amount( gpointer pObj, gnc_numeric value ) +{ + budget_amount_info_t* info = (budget_amount_info_t*)pObj; + + g_return_if_fail( pObj != NULL ); + + return gnc_budget_set_account_period_value( info->budget, info->account, info->period_num, value ); +} + +/*----------------------------------------------------------------*/ +/** + * Loads the budget amounts for a budget. + * + * @param be SQL backend + * @param budget Budget + */ +static void +load_budget_amounts( GncSqlBackend* be, GncBudget* budget ) +{ + gchar guid_buf[GUID_ENCODING_LENGTH+1]; + gchar* sql; + GncSqlStatement* stmt; + GncSqlResult* result; + + g_return_if_fail( be != NULL ); + g_return_if_fail( budget != NULL ); + + (void)guid_to_string_buff( qof_instance_get_guid( QOF_INSTANCE(budget) ), guid_buf ); + sql = g_strdup_printf( "SELECT * FROM %s WHERE budget_guid='%s'", AMOUNTS_TABLE, guid_buf ); + stmt = gnc_sql_create_statement_from_sql( be, sql ); + g_free( sql ); + if( stmt != NULL ) { + result = gnc_sql_execute_select_statement( be, stmt ); + gnc_sql_statement_dispose( stmt ); + if( result != NULL ) { + GncSqlRow* row = gnc_sql_result_get_first_row( result ); + budget_amount_info_t info; + + info.budget = budget; + + while( row != NULL ) { + gnc_sql_load_object( be, row, NULL, &info, budget_amounts_col_table ); + row = gnc_sql_result_get_next_row( result ); + } + gnc_sql_result_dispose( result ); + } + } +} + +/** + * Deletes the budget amounts for a budget. + * + * @param be SQL backend + * @param budget Budget + */ +static gboolean +delete_budget_amounts( GncSqlBackend* be, GncBudget* budget ) +{ + gchar guid_buf[GUID_ENCODING_LENGTH+1]; + gchar* sql; + + g_return_val_if_fail( be != NULL, FALSE ); + g_return_val_if_fail( budget != NULL, FALSE ); + + (void)guid_to_string_buff( qof_instance_get_guid( QOF_INSTANCE(budget) ), guid_buf ); + sql = g_strdup_printf( "DELETE FROM %s WHERE budget_guid='%s'", AMOUNTS_TABLE, guid_buf ); + (void)gnc_sql_execute_nonselect_sql( be, sql ); + g_free( sql ); + + return TRUE; +} + +/** + * Saves the budget amounts for a budget. + * + * @param be SQL backend + * @param budget Budget + */ +static gboolean +save_budget_amounts( GncSqlBackend* be, GncBudget* budget ) +{ + GList* descendants; + /*@ dependent @*/ GList* node; + budget_amount_info_t info; + guint num_periods; + gboolean is_ok = TRUE;; + + g_return_val_if_fail( be != NULL, FALSE ); + g_return_val_if_fail( budget != NULL, FALSE ); + + // Delete the amounts, then save + delete_budget_amounts( be, budget ); + + info.budget = budget; + num_periods = gnc_budget_get_num_periods( budget ); + descendants = gnc_account_get_descendants( gnc_book_get_root_account( be->primary_book ) ); + for( node = descendants; node != NULL && is_ok; node = g_list_next(node) ) { + guint i; + + info.account = GNC_ACCOUNT(node->data); + for( i = 0; i < num_periods && is_ok; i++ ) { + if( gnc_budget_is_account_period_value_set( budget, info.account, i ) ) { + info.period_num = i; + is_ok = gnc_sql_do_db_operation( be, OP_DB_INSERT, AMOUNTS_TABLE, "", &info, + budget_amounts_col_table ); + } + } + } + g_list_free( descendants ); + + return is_ok; +} +/*----------------------------------------------------------------*/ static /*@ dependent @*//*@ null @*/ GncBudget* load_single_budget( GncSqlBackend* be, GncSqlRow* row ) { @@ -86,6 +294,7 @@ load_single_budget( GncSqlBackend* be, GncSqlRow* row ) gnc_budget_begin_edit( pBudget ); gnc_sql_load_object( be, row, GNC_ID_BUDGET, pBudget, col_table ); + load_budget_amounts( be, pBudget ); r = gnc_sql_recurrence_load( be, gnc_budget_get_guid( pBudget ) ); if( r != NULL ) { gnc_budget_set_recurrence( pBudget, r ); @@ -142,6 +351,11 @@ create_budget_tables( GncSqlBackend* be ) if( version == 0 ) { (void)gnc_sql_create_table( be, BUDGET_TABLE, TABLE_VERSION, col_table ); } + + version = gnc_sql_get_table_version( be, AMOUNTS_TABLE ); + if( version == 0 ) { + (void)gnc_sql_create_table( be, AMOUNTS_TABLE, AMOUNTS_TABLE_VERSION, budget_amounts_col_table ); + } } /* ================================================================= */ @@ -172,12 +386,18 @@ save_budget( GncSqlBackend* be, QofInstance* inst ) if( is_ok ) { guid = qof_instance_get_guid( inst ); if( !qof_instance_get_destroying(inst) ) { - is_ok = gnc_sql_recurrence_save( be, guid, gnc_budget_get_recurrence( pBudget ) ); + is_ok = save_budget_amounts( be, pBudget ); + if( is_ok ) { + is_ok = gnc_sql_recurrence_save( be, guid, gnc_budget_get_recurrence( pBudget ) ); + } if( is_ok ) { is_ok = gnc_sql_slots_save( be, guid, is_infant, qof_instance_get_slots( inst ) ); } } else { - is_ok = gnc_sql_recurrence_delete( be, guid ); + is_ok = delete_budget_amounts( be, pBudget ); + if( is_ok ) { + is_ok = gnc_sql_recurrence_delete( be, guid ); + } if( is_ok ) { (void)gnc_sql_slots_delete( be, guid ); } @@ -212,6 +432,47 @@ write_budgets( GncSqlBackend* be ) return data.is_ok; } +/* ================================================================= */ +static void +load_budget_guid( const GncSqlBackend* be, GncSqlRow* row, + /*@ null @*/ QofSetterFunc setter, gpointer pObject, + const GncSqlColumnTableEntry* table_row ) +{ + const GValue* val; + GUID guid; + const GUID* pGuid; + GncBudget* budget = NULL; + + g_return_if_fail( be != NULL ); + g_return_if_fail( row != NULL ); + g_return_if_fail( pObject != NULL ); + g_return_if_fail( table_row != NULL ); + + val = gnc_sql_row_get_value_at_col_name( row, table_row->col_name ); + if( val == NULL ) { + pGuid = NULL; + } else { + (void)string_to_guid( g_value_get_string( val ), &guid ); + pGuid = &guid; + } + if( pGuid != NULL ) { + budget = gnc_budget_lookup( pGuid, be->primary_book ); + } + if( budget != NULL ) { + if( table_row->gobj_param_name != NULL ) { + g_object_set( pObject, table_row->gobj_param_name, budget, NULL ); + } else { + g_return_if_fail( setter != NULL ); + (*setter)( pObject, (const gpointer)budget ); + } + } +} + +static GncSqlColumnTypeHandler budget_guid_handler + = { load_budget_guid, + gnc_sql_add_objectref_guid_col_info_to_list, + gnc_sql_add_colname_to_list, + gnc_sql_add_gvalue_objectref_guid_to_slist }; /* ================================================================= */ void gnc_sql_init_budget_handler( void ) @@ -230,5 +491,7 @@ gnc_sql_init_budget_handler( void ) }; (void)qof_object_register_backend( GNC_ID_BUDGET, GNC_SQL_BACKEND, &be_data ); + + gnc_sql_register_col_type_handler( CT_BUDGETREF, &budget_guid_handler ); } /* ========================== END OF FILE ===================== */