|
GnuCash 2.4.99
|
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
1.7.4