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; }