From ddf85bd44593abfb0ccb73d58f58d51f9d74d514 Mon Sep 17 00:00:00 2001 From: Phil Longstaff Date: Sat, 6 Mar 2010 16:08:08 +0000 Subject: [PATCH] Fix parent/child relationships in billterms in case the parent hasn't been loaded yet. Remove child column from billterm table because it duplicates info in the parent column and just complicates loading objects. git-svn-id: svn+ssh://svn.gnucash.org/repo/gnucash/trunk@18857 57a11ea4-9604-0410-9ed3-97b8803252fd --- .../business-core/sql/gnc-bill-term-sql.c | 128 +++++++++++++++++- .../business-core/sql/gnc-tax-table-sql.c | 18 +-- 2 files changed, 133 insertions(+), 13 deletions(-) diff --git a/src/business/business-core/sql/gnc-bill-term-sql.c b/src/business/business-core/sql/gnc-bill-term-sql.c index 4c9b3e666e..4f95843d91 100644 --- a/src/business/business-core/sql/gnc-bill-term-sql.c +++ b/src/business/business-core/sql/gnc-bill-term-sql.c @@ -51,6 +51,9 @@ static QofLogModule log_module = G_LOG_DOMAIN; #define MAX_TYPE_LEN 2048 static void set_invisible( gpointer data, gboolean value ); +static gpointer bt_get_parent( gpointer data ); +static void bt_set_parent( gpointer data, gpointer value ); +static void bt_set_parent_guid( gpointer data, gpointer value ); #define TABLE_NAME "billterms" #define TABLE_VERSION 2 @@ -69,13 +72,15 @@ static GncSqlColumnTableEntry col_table[] = (QofAccessFunc)gncBillTermGetInvisible, (QofSetterFunc)set_invisible }, { - "parent", CT_BILLTERMREF, 0, 0, NULL, NULL, - (QofAccessFunc)gncBillTermGetParent, (QofSetterFunc)gncBillTermSetParent + "parent", CT_GUID, 0, 0, NULL, NULL, + (QofAccessFunc)bt_get_parent, (QofSetterFunc)bt_set_parent }, +#if 0 { "child", CT_BILLTERMREF, 0, 0, NULL, NULL, (QofAccessFunc)gncBillTermReturnChild, (QofSetterFunc)gncBillTermSetChild }, +#endif { "type", CT_STRING, MAX_TYPE_LEN, COL_NNUL, NULL, GNC_BILLTERM_TYPE }, { "duedays", CT_INT, 0, 0, 0, GNC_BILLTERM_DUEDAYS }, { "discountdays", CT_INT, 0, 0, 0, GNC_BILLTERM_DISCDAYS }, @@ -84,6 +89,18 @@ static GncSqlColumnTableEntry col_table[] = { NULL } }; +static GncSqlColumnTableEntry billterm_parent_col_table[] = +{ + { "parent", CT_GUID, 0, 0, NULL, NULL, NULL, (QofSetterFunc)bt_set_parent_guid }, + { NULL } +}; + +typedef struct { + /*@ dependent @*/ GncBillTerm* billterm; + GUID guid; + gboolean have_guid; +} billterm_parent_guid_struct; + static void set_invisible( gpointer data, gboolean value ) { @@ -97,8 +114,66 @@ set_invisible( gpointer data, gboolean value ) } } +static /*@ null @*//*@ dependent @*/ gpointer +bt_get_parent( gpointer pObject ) +{ + const GncBillTerm* billterm; + const GncBillTerm* pParent; + const GUID* parent_guid; + + g_return_val_if_fail( pObject != NULL, NULL ); + g_return_val_if_fail( GNC_IS_BILLTERM(pObject), NULL ); + + billterm = GNC_BILLTERM(pObject); + pParent = gncBillTermGetParent( billterm ); + if( pParent == NULL ) { + parent_guid = NULL; + } else { + parent_guid = qof_instance_get_guid( QOF_INSTANCE(pParent) ); + } + + return (gpointer)parent_guid; +} + +static void +bt_set_parent( gpointer data, gpointer value ) +{ + GncBillTerm* billterm; + GncBillTerm* parent; + QofBook* pBook; + GUID* guid = (GUID*)value; + + g_return_if_fail( data != NULL ); + g_return_if_fail( GNC_IS_BILLTERM(data) ); + + billterm = GNC_BILLTERM(data); + pBook = qof_instance_get_book( QOF_INSTANCE(billterm) ); + if ( guid != NULL ) + { + parent = gncBillTermLookup( pBook, guid ); + if( parent != NULL ) { + gncBillTermSetParent( billterm, parent ); + gncBillTermSetChild( parent, billterm ); + } + } +} + +static void +bt_set_parent_guid( gpointer pObject, /*@ null @*/ gpointer pValue ) +{ + billterm_parent_guid_struct* s = (billterm_parent_guid_struct*)pObject; + GUID* guid = (GUID*)pValue; + + g_return_if_fail( pObject != NULL ); + g_return_if_fail( pValue != NULL ); + + s->guid = *guid; + s->have_guid = TRUE; +} + static GncBillTerm* -load_single_billterm( GncSqlBackend* be, GncSqlRow* row ) +load_single_billterm( GncSqlBackend* be, GncSqlRow* row, + GList** l_billterms_needing_parents ) { const GUID* guid; GncBillTerm* pBillTerm; @@ -113,6 +188,28 @@ load_single_billterm( GncSqlBackend* be, GncSqlRow* row ) pBillTerm = gncBillTermCreate( be->primary_book ); } gnc_sql_load_object( be, row, GNC_ID_BILLTERM, pBillTerm, col_table ); + + /* If the billterm doesn't have a parent, it might be because it hasn't been loaded yet. + If so, add this billterm to the list of billterms with no parent, along with the parent + GUID so that after they are all loaded, the parents can be fixed up. */ + if ( gncBillTermGetParent( pBillTerm ) == NULL ) + { + billterm_parent_guid_struct* s = g_malloc( (gsize)sizeof(billterm_parent_guid_struct) ); + g_assert( s != NULL ); + + s->billterm = pBillTerm; + s->have_guid = FALSE; + gnc_sql_load_object( be, row, GNC_ID_TAXTABLE, s, billterm_parent_col_table ); + if ( s->have_guid ) + { + *l_billterms_needing_parents = g_list_prepend( *l_billterms_needing_parents, s ); + } + else + { + g_free( s ); + } + } + qof_instance_mark_clean( QOF_INSTANCE(pBillTerm) ); return pBillTerm; @@ -136,11 +233,12 @@ load_all_billterms( GncSqlBackend* be ) { GncSqlRow* row; GList* list = NULL; + GList* l_billterms_needing_parents = NULL; row = gnc_sql_result_get_first_row( result ); while ( row != NULL ) { - GncBillTerm* pBillTerm = load_single_billterm( be, row ); + GncBillTerm* pBillTerm = load_single_billterm( be, row, &l_billterms_needing_parents ); if ( pBillTerm != NULL ) { list = g_list_append( list, pBillTerm ); @@ -152,6 +250,28 @@ load_all_billterms( GncSqlBackend* be ) if ( list != NULL ) { gnc_sql_slots_load_for_list( be, list ); + } + + /* While there are items on the list of billterms needing parents, + try to see if the parent has now been loaded. Theory says that if + items are removed from the front and added to the back if the + parent is still not available, then eventually, the list will + shrink to size 0. */ + if( l_billterms_needing_parents != NULL ) { + gboolean progress_made = TRUE; + GncTaxTable* root; + Account* pParent; + GList* elem; + + while( progress_made ) { + progress_made = FALSE; + for( elem = l_billterms_needing_parents; elem != NULL; elem = g_list_next( elem ) ) { + billterm_parent_guid_struct* s = (billterm_parent_guid_struct*)elem->data; + bt_set_parent( s->billterm, &s->guid ); + l_billterms_needing_parents = g_list_delete_link( l_billterms_needing_parents, elem ); + progress_made = TRUE; + } + } } } } diff --git a/src/business/business-core/sql/gnc-tax-table-sql.c b/src/business/business-core/sql/gnc-tax-table-sql.c index c6c0b445ca..56c466c4c7 100644 --- a/src/business/business-core/sql/gnc-tax-table-sql.c +++ b/src/business/business-core/sql/gnc-tax-table-sql.c @@ -57,9 +57,9 @@ typedef struct static gpointer get_obj_guid( gpointer pObject, const QofParam* param ); static void set_obj_guid( gpointer pObject, gpointer pValue ); static gpointer get_child( gpointer pObject, const QofParam* param ); -static gpointer get_parent( gpointer pObject ); -static void set_parent( gpointer pObject, gpointer pValue ); -static void set_parent_guid( gpointer pObject, gpointer pValue ); +static gpointer bt_get_parent( gpointer pObject ); +static void tt_set_parent( gpointer pObject, gpointer pValue ); +static void tt_set_parent_guid( gpointer pObject, gpointer pValue ); #define MAX_NAME_LEN 50 @@ -77,14 +77,14 @@ static GncSqlColumnTableEntry tt_col_table[] = /* { "child", CT_TAXTABLEREF, 0, 0, NULL, NULL, get_child, (QofSetterFunc)gncTaxTableSetChild }, */ { "parent", CT_GUID, 0, 0, NULL, NULL, - (QofAccessFunc)get_parent, set_parent + (QofAccessFunc)bt_get_parent, tt_set_parent }, { NULL } }; static GncSqlColumnTableEntry tt_parent_col_table[] = { - { "parent", CT_GUID, 0, 0, NULL, NULL, NULL, set_parent_guid }, + { "parent", CT_GUID, 0, 0, NULL, NULL, NULL, tt_set_parent_guid }, { NULL } }; @@ -169,7 +169,7 @@ get_child( gpointer pObject, const QofParam* param ) } static /*@ null @*//*@ dependent @*/ gpointer -get_parent( gpointer pObject ) +bt_get_parent( gpointer pObject ) { const GncTaxTable* tt; const GncTaxTable* pParent; @@ -190,7 +190,7 @@ get_parent( gpointer pObject ) } static void -set_parent( gpointer data, gpointer value ) +tt_set_parent( gpointer data, gpointer value ) { GncTaxTable* tt; GncTaxTable* parent; @@ -213,7 +213,7 @@ set_parent( gpointer data, gpointer value ) } static void -set_parent_guid( gpointer pObject, /*@ null @*/ gpointer pValue ) +tt_set_parent_guid( gpointer pObject, /*@ null @*/ gpointer pValue ) { taxtable_parent_guid_struct* s = (taxtable_parent_guid_struct*)pObject; GUID* guid = (GUID*)pValue; @@ -354,7 +354,7 @@ load_all_taxtables( GncSqlBackend* be ) progress_made = FALSE; for( elem = tt_needing_parents; elem != NULL; elem = g_list_next( elem ) ) { taxtable_parent_guid_struct* s = (taxtable_parent_guid_struct*)elem->data; - set_parent( s->tt, &s->guid ); + tt_set_parent( s->tt, &s->guid ); tt_needing_parents = g_list_delete_link( tt_needing_parents, elem ); progress_made = TRUE; }