GnuCash 2.4.99
gnc-tax-table-sql.c
Go to the documentation of this file.
00001 /********************************************************************\
00002  * gnc-tax-table-sql.c -- tax table sql implementation              *
00003  *                                                                  *
00004  * This program is free software; you can redistribute it and/or    *
00005  * modify it under the terms of the GNU General Public License as   *
00006  * published by the Free Software Foundation; either version 2 of   *
00007  * the License, or (at your option) any later version.              *
00008  *                                                                  *
00009  * This program is distributed in the hope that it will be useful,  *
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
00012  * GNU General Public License for more details.                     *
00013  *                                                                  *
00014  * You should have received a copy of the GNU General Public License*
00015  * along with this program; if not, contact:                        *
00016  *                                                                  *
00017  * Free Software Foundation           Voice:  +1-617-542-5942       *
00018  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
00019  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
00020  *                                                                  *
00021 \********************************************************************/
00022 
00031 #include "config.h"
00032 
00033 #include <glib.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 
00037 #include "gnc-backend-sql.h"
00038 #include "gnc-slots-sql.h"
00039 
00040 #include "gncEntry.h"
00041 #include "gncTaxTableP.h"
00042 
00043 #include "gnc-tax-table-sql.h"
00044 
00045 #define _GNC_MOD_NAME   GNC_ID_TAXTABLE
00046 
00047 static QofLogModule log_module = G_LOG_DOMAIN;
00048 
00049 typedef struct
00050 {
00051     GncSqlBackend* be;
00052     const GncGUID* guid;
00053 } guid_info_t;
00054 
00055 static gpointer get_obj_guid( gpointer pObject, const QofParam* param );
00056 static void set_obj_guid( gpointer pObject, gpointer pValue );
00057 static gpointer get_child( gpointer pObject, const QofParam* param );
00058 static gpointer bt_get_parent( gpointer pObject );
00059 static void tt_set_parent( gpointer pObject, gpointer pValue );
00060 static void tt_set_parent_guid( gpointer pObject, gpointer pValue );
00061 
00062 #define MAX_NAME_LEN 50
00063 
00064 #define TT_TABLE_NAME "taxtables"
00065 #define TT_TABLE_VERSION 2
00066 
00067 static GncSqlColumnTableEntry tt_col_table[] =
00068 {
00069     { "guid",      CT_GUID,        0,            COL_NNUL | COL_PKEY, "guid" },
00070     { "name",      CT_STRING,      MAX_NAME_LEN, COL_NNUL,          "name" },
00071     { "refcount",  CT_INT64,       0,            COL_NNUL,          "ref-count" },
00072     { "invisible", CT_BOOLEAN,     0,            COL_NNUL,          "invisible" },
00073     /*  { "child",     CT_TAXTABLEREF, 0,                        0,                 NULL, NULL,
00074                         get_child, (QofSetterFunc)gncTaxTableSetChild }, */
00075     {
00076         "parent",    CT_GUID,        0,                  0,                 NULL, NULL,
00077         (QofAccessFunc)bt_get_parent, tt_set_parent
00078     },
00079     { NULL }
00080 };
00081 
00082 static GncSqlColumnTableEntry tt_parent_col_table[] =
00083 {
00084     { "parent", CT_GUID, 0, 0, NULL, NULL, NULL, tt_set_parent_guid },
00085     { NULL }
00086 };
00087 
00088 #define TTENTRIES_TABLE_NAME "taxtable_entries"
00089 #define TTENTRIES_TABLE_VERSION 3
00090 
00091 static GncSqlColumnTableEntry ttentries_col_table[] =
00092 {
00093     { "id",       CT_INT,         0, COL_PKEY | COL_NNUL | COL_AUTOINC },
00094     {
00095         "taxtable", CT_TAXTABLEREF, 0, COL_NNUL, NULL, NULL,
00096         (QofAccessFunc)gncTaxTableEntryGetTable, set_obj_guid
00097     },
00098     {
00099         "account",  CT_ACCOUNTREF,  0, COL_NNUL, NULL, NULL,
00100         (QofAccessFunc)gncTaxTableEntryGetAccount, (QofSetterFunc)gncTaxTableEntrySetAccount
00101     },
00102     {
00103         "amount",   CT_NUMERIC,     0, COL_NNUL, NULL, NULL,
00104         (QofAccessFunc)gncTaxTableEntryGetAmount, (QofSetterFunc)gncTaxTableEntrySetAmount
00105     },
00106     {
00107         "type",     CT_INT,         0, COL_NNUL, NULL, NULL,
00108         (QofAccessFunc)gncTaxTableEntryGetType, (QofSetterFunc)gncTaxTableEntrySetType
00109     },
00110     { NULL }
00111 };
00112 
00113 /* Special column table because we need to be able to access the table by
00114 a column other than the primary key */
00115 static GncSqlColumnTableEntry guid_col_table[] =
00116 {
00117     { "taxtable", CT_GUID, 0, 0, NULL, NULL, get_obj_guid, set_obj_guid },
00118     { NULL }
00119 };
00120 
00121 typedef struct
00122 {
00123     /*@ dependent @*/ GncTaxTable* tt;
00124     GncGUID guid;
00125     gboolean have_guid;
00126 } taxtable_parent_guid_struct;
00127 
00128 static gpointer
00129 get_obj_guid( gpointer pObject, const QofParam* param )
00130 {
00131     guid_info_t* pInfo = (guid_info_t*)pObject;
00132 
00133     g_return_val_if_fail( pInfo != NULL, NULL );
00134 
00135     return (gpointer)pInfo->guid;
00136 }
00137 
00138 static void
00139 set_obj_guid( gpointer pObject, gpointer pValue )
00140 {
00141     // Nowhere to put the GncGUID
00142 }
00143 
00144 static gpointer
00145 get_child( gpointer pObject, const QofParam* param )
00146 {
00147     GncTaxTable* tt = GNC_TAXTABLE(pObject);
00148 
00149     g_return_val_if_fail( pObject != NULL, NULL );
00150     g_return_val_if_fail( GNC_IS_TAXTABLE(pObject), NULL );
00151 
00152     return gncTaxTableGetChild( tt );
00153 }
00154 
00155 static /*@ null @*//*@ dependent @*/ gpointer
00156 bt_get_parent( gpointer pObject )
00157 {
00158     const GncTaxTable* tt;
00159     const GncTaxTable* pParent;
00160     const GncGUID* parent_guid;
00161 
00162     g_return_val_if_fail( pObject != NULL, NULL );
00163     g_return_val_if_fail( GNC_IS_TAXTABLE(pObject), NULL );
00164 
00165     tt = GNC_TAXTABLE(pObject);
00166     pParent = gncTaxTableGetParent( tt );
00167     if ( pParent == NULL )
00168     {
00169         parent_guid = NULL;
00170     }
00171     else
00172     {
00173         parent_guid = qof_instance_get_guid( QOF_INSTANCE(pParent) );
00174     }
00175 
00176     return (gpointer)parent_guid;
00177 }
00178 
00179 static void
00180 tt_set_parent( gpointer data, gpointer value )
00181 {
00182     GncTaxTable* tt;
00183     GncTaxTable* parent;
00184     QofBook* pBook;
00185     GncGUID* guid = (GncGUID*)value;
00186 
00187     g_return_if_fail( data != NULL );
00188     g_return_if_fail( GNC_IS_TAXTABLE(data) );
00189 
00190     tt = GNC_TAXTABLE(data);
00191     pBook = qof_instance_get_book( QOF_INSTANCE(tt) );
00192     if ( guid != NULL )
00193     {
00194         parent = gncTaxTableLookup( pBook, guid );
00195         if ( parent != NULL )
00196         {
00197             gncTaxTableSetParent( tt, parent );
00198             gncTaxTableSetChild( parent, tt );
00199         }
00200     }
00201 }
00202 
00203 static void
00204 tt_set_parent_guid( gpointer pObject, /*@ null @*/ gpointer pValue )
00205 {
00206     taxtable_parent_guid_struct* s = (taxtable_parent_guid_struct*)pObject;
00207     GncGUID* guid = (GncGUID*)pValue;
00208 
00209     g_return_if_fail( pObject != NULL );
00210     g_return_if_fail( pValue != NULL );
00211 
00212     s->guid = *guid;
00213     s->have_guid = TRUE;
00214 }
00215 
00216 static void
00217 load_single_ttentry( GncSqlBackend* be, GncSqlRow* row, GncTaxTable* tt )
00218 {
00219     GncTaxTableEntry* e = gncTaxTableEntryCreate();
00220 
00221     g_return_if_fail( be != NULL );
00222     g_return_if_fail( row != NULL );
00223     g_return_if_fail( tt != NULL );
00224 
00225     gnc_sql_load_object( be, row, GNC_ID_TAXTABLE, e, ttentries_col_table );
00226     gncTaxTableAddEntry( tt, e );
00227 }
00228 
00229 static void
00230 load_taxtable_entries( GncSqlBackend* be, GncTaxTable* tt )
00231 {
00232     GncSqlResult* result;
00233     gchar guid_buf[GUID_ENCODING_LENGTH+1];
00234     GValue value;
00235     gchar* buf;
00236     GncSqlStatement* stmt;
00237     GError* error = NULL;
00238 
00239     g_return_if_fail( be != NULL );
00240     g_return_if_fail( tt != NULL );
00241 
00242     guid_to_string_buff( qof_instance_get_guid( QOF_INSTANCE(tt) ), guid_buf );
00243     memset( &value, 0, sizeof( GValue ) );
00244     g_value_init( &value, G_TYPE_STRING );
00245     g_value_set_string( &value, guid_buf );
00246     buf = g_strdup_printf( "SELECT * FROM %s WHERE taxtable='%s'", TTENTRIES_TABLE_NAME, guid_buf );
00247     stmt = gnc_sql_connection_create_statement_from_sql( be->conn, buf );
00248     g_free( buf );
00249     result = gnc_sql_execute_select_statement( be, stmt );
00250     gnc_sql_statement_dispose( stmt );
00251     if ( result != NULL )
00252     {
00253         GncSqlRow* row;
00254 
00255         row = gnc_sql_result_get_first_row( result );
00256         while ( row != NULL )
00257         {
00258             load_single_ttentry( be, row, tt );
00259             row = gnc_sql_result_get_next_row( result );
00260         }
00261         gnc_sql_result_dispose( result );
00262     }
00263 }
00264 
00265 static void
00266 load_single_taxtable( GncSqlBackend* be, GncSqlRow* row,
00267                       GList** l_tt_needing_parents )
00268 {
00269     const GncGUID* guid;
00270     GncTaxTable* tt;
00271 
00272     g_return_if_fail( be != NULL );
00273     g_return_if_fail( row != NULL );
00274 
00275     guid = gnc_sql_load_guid( be, row );
00276     tt = gncTaxTableLookup( be->book, guid );
00277     if ( tt == NULL )
00278     {
00279         tt = gncTaxTableCreate( be->book );
00280     }
00281     gnc_sql_load_object( be, row, GNC_ID_TAXTABLE, tt, tt_col_table );
00282     gnc_sql_slots_load( be, QOF_INSTANCE(tt) );
00283     load_taxtable_entries( be, tt );
00284 
00285     /* If the tax table doesn't have a parent, it might be because it hasn't been loaded yet.
00286        If so, add this tax table to the list of tax tables with no parent, along with the parent
00287        GncGUID so that after they are all loaded, the parents can be fixed up. */
00288     if ( gncTaxTableGetParent( tt ) == NULL )
00289     {
00290         taxtable_parent_guid_struct* s = g_malloc( (gsize)sizeof(taxtable_parent_guid_struct) );
00291         g_assert( s != NULL );
00292 
00293         s->tt = tt;
00294         s->have_guid = FALSE;
00295         gnc_sql_load_object( be, row, GNC_ID_TAXTABLE, s, tt_parent_col_table );
00296         if ( s->have_guid )
00297         {
00298             *l_tt_needing_parents = g_list_prepend( *l_tt_needing_parents, s );
00299         }
00300         else
00301         {
00302             g_free( s );
00303         }
00304     }
00305 
00306     qof_instance_mark_clean( QOF_INSTANCE(tt) );
00307 }
00308 
00309 static void
00310 load_all_taxtables( GncSqlBackend* be )
00311 {
00312     GncSqlStatement* stmt;
00313     GncSqlResult* result;
00314 
00315     g_return_if_fail( be != NULL );
00316 
00317     /* First time, create the query */
00318     stmt = gnc_sql_create_select_statement( be, TT_TABLE_NAME );
00319     result = gnc_sql_execute_select_statement( be, stmt );
00320     gnc_sql_statement_dispose( stmt );
00321     if ( result != NULL )
00322     {
00323         GncSqlRow* row;
00324         GList* tt_needing_parents = NULL;
00325 
00326         row = gnc_sql_result_get_first_row( result );
00327         while ( row != NULL )
00328         {
00329             load_single_taxtable( be, row, &tt_needing_parents );
00330             row = gnc_sql_result_get_next_row( result );
00331         }
00332         gnc_sql_result_dispose( result );
00333 
00334         /* While there are items on the list of taxtables needing parents,
00335            try to see if the parent has now been loaded.  Theory says that if
00336            items are removed from the front and added to the back if the
00337            parent is still not available, then eventually, the list will
00338            shrink to size 0. */
00339         if ( tt_needing_parents != NULL )
00340         {
00341             gboolean progress_made = TRUE;
00342             GncTaxTable* root;
00343             Account* pParent;
00344             GList* elem;
00345 
00346             while ( progress_made )
00347             {
00348                 progress_made = FALSE;
00349                 for ( elem = tt_needing_parents; elem != NULL; elem = g_list_next( elem ) )
00350                 {
00351                     taxtable_parent_guid_struct* s = (taxtable_parent_guid_struct*)elem->data;
00352                     tt_set_parent( s->tt, &s->guid );
00353                     tt_needing_parents = g_list_delete_link( tt_needing_parents, elem );
00354                     progress_made = TRUE;
00355                 }
00356             }
00357         }
00358     }
00359 }
00360 
00361 /* ================================================================= */
00362 static void
00363 create_taxtable_tables( GncSqlBackend* be )
00364 {
00365     gint version;
00366 
00367     g_return_if_fail( be != NULL );
00368 
00369     version = gnc_sql_get_table_version( be, TT_TABLE_NAME );
00370     if ( version == 0 )
00371     {
00372         gnc_sql_create_table( be, TT_TABLE_NAME, TT_TABLE_VERSION, tt_col_table );
00373     }
00374     else if ( version == 1 )
00375     {
00376         /* Upgrade 64 bit int handling */
00377         gnc_sql_upgrade_table( be, TT_TABLE_NAME, tt_col_table );
00378         gnc_sql_set_table_version( be, TT_TABLE_NAME, TT_TABLE_VERSION );
00379         PINFO("Taxtables table upgraded from version 1 to version %d\n", TT_TABLE_VERSION);
00380     }
00381 
00382     version = gnc_sql_get_table_version( be, TTENTRIES_TABLE_NAME );
00383     if ( version == 0 )
00384     {
00385         gnc_sql_create_table( be, TTENTRIES_TABLE_NAME, TTENTRIES_TABLE_VERSION, ttentries_col_table );
00386     }
00387     else if ( version == 1 )
00388     {
00389         /* Upgrade 64 bit int handling */
00390         gnc_sql_upgrade_table( be, TTENTRIES_TABLE_NAME, ttentries_col_table );
00391         gnc_sql_set_table_version( be, TTENTRIES_TABLE_NAME, TTENTRIES_TABLE_VERSION );
00392         PINFO("Taxtable entries table upgraded from version 1 to version %d\n", TTENTRIES_TABLE_VERSION);
00393     }
00394 }
00395 
00396 /* ================================================================= */
00397 static gboolean
00398 delete_all_tt_entries( GncSqlBackend* be, const GncGUID* guid )
00399 {
00400     guid_info_t guid_info;
00401 
00402     g_return_val_if_fail( be != NULL, FALSE );
00403     g_return_val_if_fail( guid != NULL, FALSE );
00404 
00405     guid_info.be = be;
00406     guid_info.guid = guid;
00407     return gnc_sql_do_db_operation( be, OP_DB_DELETE, TTENTRIES_TABLE_NAME,
00408                                     TTENTRIES_TABLE_NAME, &guid_info, guid_col_table );
00409 }
00410 
00411 static gboolean
00412 save_tt_entries( GncSqlBackend* be, const GncGUID* guid, GList* entries )
00413 {
00414     GList* entry;
00415     gboolean is_ok;
00416 
00417     g_return_val_if_fail( be != NULL, FALSE );
00418     g_return_val_if_fail( guid != NULL, FALSE );
00419 
00420     /* First, delete the old entries for this object */
00421     is_ok = delete_all_tt_entries( be, guid );
00422 
00423     for ( entry = entries; entry != NULL && is_ok; entry = entry->next )
00424     {
00425         GncTaxTableEntry* e = (GncTaxTableEntry*)entry->data;
00426         is_ok = gnc_sql_do_db_operation( be,
00427                                          OP_DB_INSERT,
00428                                          TTENTRIES_TABLE_NAME,
00429                                          GNC_ID_TAXTABLE, e,
00430                                          ttentries_col_table );
00431     }
00432 
00433     return is_ok;
00434 }
00435 
00436 static gboolean
00437 save_taxtable( GncSqlBackend* be, QofInstance* inst )
00438 {
00439     GncTaxTable* tt;
00440     const GncGUID* guid;
00441     gint op;
00442     gboolean is_infant;
00443     gboolean is_ok;
00444 
00445     g_return_val_if_fail( inst != NULL, FALSE );
00446     g_return_val_if_fail( GNC_IS_TAXTABLE(inst), FALSE );
00447     g_return_val_if_fail( be != NULL, FALSE );
00448 
00449     tt = GNC_TAXTABLE(inst);
00450 
00451     is_infant = qof_instance_get_infant( inst );
00452     if ( qof_instance_get_destroying( inst ) )
00453     {
00454         op = OP_DB_DELETE;
00455     }
00456     else if ( be->is_pristine_db || is_infant )
00457     {
00458         op = OP_DB_INSERT;
00459     }
00460     else
00461     {
00462         op = OP_DB_UPDATE;
00463     }
00464     is_ok = gnc_sql_do_db_operation( be, op, TT_TABLE_NAME, GNC_ID_TAXTABLE, tt, tt_col_table );
00465 
00466     if ( is_ok )
00467     {
00468         // Now, commit or delete any slots and tax table entries
00469         guid = qof_instance_get_guid( inst );
00470         if ( !qof_instance_get_destroying(inst) )
00471         {
00472             is_ok = gnc_sql_slots_save( be, guid, is_infant, qof_instance_get_slots( inst ) );
00473             if ( is_ok )
00474             {
00475                 is_ok = save_tt_entries( be, guid, gncTaxTableGetEntries( tt ) );
00476             }
00477         }
00478         else
00479         {
00480             is_ok = gnc_sql_slots_delete( be, guid );
00481             if ( is_ok )
00482             {
00483                 is_ok = delete_all_tt_entries( be, guid );
00484             }
00485         }
00486     }
00487 
00488     return is_ok;
00489 }
00490 
00491 /* ================================================================= */
00492 static void
00493 save_next_taxtable( QofInstance* inst, gpointer data )
00494 {
00495     write_objects_t* s = (write_objects_t*)data;
00496 
00497     if ( s->is_ok )
00498     {
00499         s->is_ok = save_taxtable( s->be, inst );
00500     }
00501 }
00502 
00503 static gboolean
00504 write_taxtables( GncSqlBackend* be )
00505 {
00506     write_objects_t data;
00507 
00508     g_return_val_if_fail( be != NULL, FALSE );
00509 
00510     data.be = be;
00511     data.is_ok = TRUE;
00512     qof_object_foreach( GNC_ID_TAXTABLE, be->book, save_next_taxtable, &data );
00513 
00514     return data.is_ok;
00515 }
00516 
00517 /* ================================================================= */
00518 static void
00519 load_taxtable_guid( const GncSqlBackend* be, GncSqlRow* row,
00520                     QofSetterFunc setter, gpointer pObject,
00521                     const GncSqlColumnTableEntry* table_row )
00522 {
00523     const GValue* val;
00524     GncGUID guid;
00525     GncTaxTable* taxtable = NULL;
00526 
00527     g_return_if_fail( be != NULL );
00528     g_return_if_fail( row != NULL );
00529     g_return_if_fail( pObject != NULL );
00530     g_return_if_fail( table_row != NULL );
00531 
00532     val = gnc_sql_row_get_value_at_col_name( row, table_row->col_name );
00533     if ( val != NULL && G_VALUE_HOLDS_STRING( val ) && g_value_get_string( val ) != NULL )
00534     {
00535         string_to_guid( g_value_get_string( val ), &guid );
00536         taxtable = gncTaxTableLookup( be->book, &guid );
00537         if ( taxtable != NULL )
00538         {
00539             if ( table_row->gobj_param_name != NULL )
00540             {
00541                 g_object_set( pObject, table_row->gobj_param_name, taxtable, NULL );
00542             }
00543             else
00544             {
00545                 (*setter)( pObject, (const gpointer)taxtable );
00546             }
00547         }
00548         else
00549         {
00550             PWARN( "Taxtable ref '%s' not found", g_value_get_string( val ) );
00551         }
00552     }
00553 }
00554 
00555 static GncSqlColumnTypeHandler taxtable_guid_handler
00556 = { load_taxtable_guid,
00557     gnc_sql_add_objectref_guid_col_info_to_list,
00558     gnc_sql_add_colname_to_list,
00559     gnc_sql_add_gvalue_objectref_guid_to_slist
00560   };
00561 /* ================================================================= */
00562 void
00563 gnc_taxtable_sql_initialize( void )
00564 {
00565     static GncSqlObjectBackend be_data =
00566     {
00567         GNC_SQL_BACKEND_VERSION,
00568         GNC_ID_TAXTABLE,
00569         save_taxtable,                                          /* commit */
00570         load_all_taxtables,                                     /* initial_load */
00571         create_taxtable_tables,                         /* create_tables */
00572         NULL, NULL, NULL,
00573         write_taxtables                                         /* write */
00574     };
00575 
00576     qof_object_register_backend( GNC_ID_TAXTABLE, GNC_SQL_BACKEND, &be_data );
00577 
00578     gnc_sql_register_col_type_handler( CT_TAXTABLEREF, &taxtable_guid_handler );
00579 }
00580 /* ========================== END OF FILE ===================== */
00581 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines