GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-tax-table-sql.c
Go to the documentation of this file.
1 /********************************************************************\
2  * gnc-tax-table-sql.c -- tax table sql implementation *
3  * *
4  * This program is free software; you can redistribute it and/or *
5  * modify it under the terms of the GNU General Public License as *
6  * published by the Free Software Foundation; either version 2 of *
7  * the License, or (at your option) any later version. *
8  * *
9  * This program is distributed in the hope that it will be useful, *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12  * GNU General Public License for more details. *
13  * *
14  * You should have received a copy of the GNU General Public License*
15  * along with this program; if not, contact: *
16  * *
17  * Free Software Foundation Voice: +1-617-542-5942 *
18  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
19  * Boston, MA 02110-1301, USA [email protected] *
20  * *
21 \********************************************************************/
22 
31 #include "config.h"
32 
33 #include <glib.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 #include "gnc-backend-sql.h"
38 #include "gnc-slots-sql.h"
39 
40 #include "gncEntry.h"
41 #include "gncTaxTableP.h"
42 
43 #include "gnc-tax-table-sql.h"
44 
45 #define _GNC_MOD_NAME GNC_ID_TAXTABLE
46 
47 static QofLogModule log_module = G_LOG_DOMAIN;
48 
49 typedef struct
50 {
51  GncSqlBackend* be;
52  const GncGUID* guid;
53 } guid_info_t;
54 
55 static gpointer get_obj_guid( gpointer pObject, const QofParam* param );
56 static void set_obj_guid( gpointer pObject, gpointer pValue );
57 static gpointer bt_get_parent( gpointer pObject );
58 static void tt_set_parent( gpointer pObject, gpointer pValue );
59 static void tt_set_parent_guid( gpointer pObject, gpointer pValue );
60 
61 #define MAX_NAME_LEN 50
62 
63 #define TT_TABLE_NAME "taxtables"
64 #define TT_TABLE_VERSION 2
65 
66 static GncSqlColumnTableEntry tt_col_table[] =
67 {
68  { "guid", CT_GUID, 0, COL_NNUL | COL_PKEY, "guid" },
69  { "name", CT_STRING, MAX_NAME_LEN, COL_NNUL, "name" },
70  { "refcount", CT_INT64, 0, COL_NNUL, "ref-count" },
71  { "invisible", CT_BOOLEAN, 0, COL_NNUL, "invisible" },
72  /* { "child", CT_TAXTABLEREF, 0, 0, NULL, NULL,
73  get_child, (QofSetterFunc)gncTaxTableSetChild }, */
74  {
75  "parent", CT_GUID, 0, 0, NULL, NULL,
76  (QofAccessFunc)bt_get_parent, tt_set_parent
77  },
78  { NULL }
79 };
80 
81 static GncSqlColumnTableEntry tt_parent_col_table[] =
82 {
83  { "parent", CT_GUID, 0, 0, NULL, NULL, NULL, tt_set_parent_guid },
84  { NULL }
85 };
86 
87 #define TTENTRIES_TABLE_NAME "taxtable_entries"
88 #define TTENTRIES_TABLE_VERSION 3
89 
90 static GncSqlColumnTableEntry ttentries_col_table[] =
91 {
92  { "id", CT_INT, 0, COL_PKEY | COL_NNUL | COL_AUTOINC },
93  {
94  "taxtable", CT_TAXTABLEREF, 0, COL_NNUL, NULL, NULL,
95  (QofAccessFunc)gncTaxTableEntryGetTable, set_obj_guid
96  },
97  {
98  "account", CT_ACCOUNTREF, 0, COL_NNUL, NULL, NULL,
99  (QofAccessFunc)gncTaxTableEntryGetAccount, (QofSetterFunc)gncTaxTableEntrySetAccount
100  },
101  {
102  "amount", CT_NUMERIC, 0, COL_NNUL, NULL, NULL,
103  (QofAccessFunc)gncTaxTableEntryGetAmount, (QofSetterFunc)gncTaxTableEntrySetAmount
104  },
105  {
106  "type", CT_INT, 0, COL_NNUL, NULL, NULL,
107  (QofAccessFunc)gncTaxTableEntryGetType, (QofSetterFunc)gncTaxTableEntrySetType
108  },
109  { NULL }
110 };
111 
112 /* Special column table because we need to be able to access the table by
113 a column other than the primary key */
114 static GncSqlColumnTableEntry guid_col_table[] =
115 {
116  { "taxtable", CT_GUID, 0, 0, NULL, NULL, get_obj_guid, set_obj_guid },
117  { NULL }
118 };
119 
120 typedef struct
121 {
122  /*@ dependent @*/ GncTaxTable* tt;
123  GncGUID guid;
124  gboolean have_guid;
126 
127 static gpointer
128 get_obj_guid( gpointer pObject, const QofParam* param )
129 {
130  guid_info_t* pInfo = (guid_info_t*)pObject;
131 
132  g_return_val_if_fail( pInfo != NULL, NULL );
133 
134  return (gpointer)pInfo->guid;
135 }
136 
137 static void
138 set_obj_guid( gpointer pObject, gpointer pValue )
139 {
140  // Nowhere to put the GncGUID
141 }
142 
143 static /*@ null @*//*@ dependent @*/ gpointer
144 bt_get_parent( gpointer pObject )
145 {
146  const GncTaxTable* tt;
147  const GncTaxTable* pParent;
148  const GncGUID* parent_guid;
149 
150  g_return_val_if_fail( pObject != NULL, NULL );
151  g_return_val_if_fail( GNC_IS_TAXTABLE(pObject), NULL );
152 
153  tt = GNC_TAXTABLE(pObject);
154  pParent = gncTaxTableGetParent( tt );
155  if ( pParent == NULL )
156  {
157  parent_guid = NULL;
158  }
159  else
160  {
161  parent_guid = qof_instance_get_guid( QOF_INSTANCE(pParent) );
162  }
163 
164  return (gpointer)parent_guid;
165 }
166 
167 static void
168 tt_set_parent( gpointer data, gpointer value )
169 {
170  GncTaxTable* tt;
171  GncTaxTable* parent;
172  QofBook* pBook;
173  GncGUID* guid = (GncGUID*)value;
174 
175  g_return_if_fail( data != NULL );
176  g_return_if_fail( GNC_IS_TAXTABLE(data) );
177 
178  tt = GNC_TAXTABLE(data);
179  pBook = qof_instance_get_book( QOF_INSTANCE(tt) );
180  if ( guid != NULL )
181  {
182  parent = gncTaxTableLookup( pBook, guid );
183  if ( parent != NULL )
184  {
185  gncTaxTableSetParent( tt, parent );
186  gncTaxTableSetChild( parent, tt );
187  }
188  }
189 }
190 
191 static void
192 tt_set_parent_guid( gpointer pObject, /*@ null @*/ gpointer pValue )
193 {
195  GncGUID* guid = (GncGUID*)pValue;
196 
197  g_return_if_fail( pObject != NULL );
198  g_return_if_fail( pValue != NULL );
199 
200  s->guid = *guid;
201  s->have_guid = TRUE;
202 }
203 
204 static void
205 load_single_ttentry( GncSqlBackend* be, GncSqlRow* row, GncTaxTable* tt )
206 {
207  GncTaxTableEntry* e = gncTaxTableEntryCreate();
208 
209  g_return_if_fail( be != NULL );
210  g_return_if_fail( row != NULL );
211  g_return_if_fail( tt != NULL );
212 
213  gnc_sql_load_object( be, row, GNC_ID_TAXTABLE, e, ttentries_col_table );
214  gncTaxTableAddEntry( tt, e );
215 }
216 
217 static void
218 load_taxtable_entries( GncSqlBackend* be, GncTaxTable* tt )
219 {
220  GncSqlResult* result;
221  gchar guid_buf[GUID_ENCODING_LENGTH+1];
222  GValue value;
223  gchar* buf;
224  GncSqlStatement* stmt;
225 
226  g_return_if_fail( be != NULL );
227  g_return_if_fail( tt != NULL );
228 
229  guid_to_string_buff( qof_instance_get_guid( QOF_INSTANCE(tt) ), guid_buf );
230  memset( &value, 0, sizeof( GValue ) );
231  g_value_init( &value, G_TYPE_STRING );
232  g_value_set_string( &value, guid_buf );
233  buf = g_strdup_printf( "SELECT * FROM %s WHERE taxtable='%s'", TTENTRIES_TABLE_NAME, guid_buf );
234  stmt = gnc_sql_connection_create_statement_from_sql( be->conn, buf );
235  g_free( buf );
236  result = gnc_sql_execute_select_statement( be, stmt );
237  gnc_sql_statement_dispose( stmt );
238  if ( result != NULL )
239  {
240  GncSqlRow* row;
241 
242  row = gnc_sql_result_get_first_row( result );
243  while ( row != NULL )
244  {
245  load_single_ttentry( be, row, tt );
246  row = gnc_sql_result_get_next_row( result );
247  }
248  gnc_sql_result_dispose( result );
249  }
250 }
251 
252 static void
253 load_single_taxtable( GncSqlBackend* be, GncSqlRow* row,
254  GList** l_tt_needing_parents )
255 {
256  const GncGUID* guid;
257  GncTaxTable* tt;
258 
259  g_return_if_fail( be != NULL );
260  g_return_if_fail( row != NULL );
261 
262  guid = gnc_sql_load_guid( be, row );
263  tt = gncTaxTableLookup( be->book, guid );
264  if ( tt == NULL )
265  {
266  tt = gncTaxTableCreate( be->book );
267  }
268  gnc_sql_load_object( be, row, GNC_ID_TAXTABLE, tt, tt_col_table );
269  gnc_sql_slots_load( be, QOF_INSTANCE(tt) );
270  load_taxtable_entries( be, tt );
271 
272  /* If the tax table doesn't have a parent, it might be because it hasn't been loaded yet.
273  If so, add this tax table to the list of tax tables with no parent, along with the parent
274  GncGUID so that after they are all loaded, the parents can be fixed up. */
275  if ( gncTaxTableGetParent( tt ) == NULL )
276  {
277  taxtable_parent_guid_struct* s = g_malloc( (gsize)sizeof(taxtable_parent_guid_struct) );
278  g_assert( s != NULL );
279 
280  s->tt = tt;
281  s->have_guid = FALSE;
282  gnc_sql_load_object( be, row, GNC_ID_TAXTABLE, s, tt_parent_col_table );
283  if ( s->have_guid )
284  {
285  *l_tt_needing_parents = g_list_prepend( *l_tt_needing_parents, s );
286  }
287  else
288  {
289  g_free( s );
290  }
291  }
292 
293  qof_instance_mark_clean( QOF_INSTANCE(tt) );
294 }
295 
296 static void
297 load_all_taxtables( GncSqlBackend* be )
298 {
299  GncSqlStatement* stmt;
300  GncSqlResult* result;
301 
302  g_return_if_fail( be != NULL );
303 
304  /* First time, create the query */
305  stmt = gnc_sql_create_select_statement( be, TT_TABLE_NAME );
306  result = gnc_sql_execute_select_statement( be, stmt );
307  gnc_sql_statement_dispose( stmt );
308  if ( result != NULL )
309  {
310  GncSqlRow* row;
311  GList* tt_needing_parents = NULL;
312 
313  row = gnc_sql_result_get_first_row( result );
314  while ( row != NULL )
315  {
316  load_single_taxtable( be, row, &tt_needing_parents );
317  row = gnc_sql_result_get_next_row( result );
318  }
319  gnc_sql_result_dispose( result );
320 
321  /* While there are items on the list of taxtables needing parents,
322  try to see if the parent has now been loaded. Theory says that if
323  items are removed from the front and added to the back if the
324  parent is still not available, then eventually, the list will
325  shrink to size 0. */
326  if ( tt_needing_parents != NULL )
327  {
328  gboolean progress_made = TRUE;
329  GList* elem;
330 
331  while ( progress_made )
332  {
333  progress_made = FALSE;
334  for ( elem = tt_needing_parents; elem != NULL; elem = g_list_next( elem ) )
335  {
337  tt_set_parent( s->tt, &s->guid );
338  tt_needing_parents = g_list_delete_link( tt_needing_parents, elem );
339  progress_made = TRUE;
340  }
341  }
342  }
343  }
344 }
345 
346 /* ================================================================= */
347 static void
348 create_taxtable_tables( GncSqlBackend* be )
349 {
350  gint version;
351 
352  g_return_if_fail( be != NULL );
353 
354  version = gnc_sql_get_table_version( be, TT_TABLE_NAME );
355  if ( version == 0 )
356  {
357  gnc_sql_create_table( be, TT_TABLE_NAME, TT_TABLE_VERSION, tt_col_table );
358  }
359  else if ( version == 1 )
360  {
361  /* Upgrade 64 bit int handling */
362  gnc_sql_upgrade_table( be, TT_TABLE_NAME, tt_col_table );
363  gnc_sql_set_table_version( be, TT_TABLE_NAME, TT_TABLE_VERSION );
364  PINFO("Taxtables table upgraded from version 1 to version %d\n", TT_TABLE_VERSION);
365  }
366 
367  version = gnc_sql_get_table_version( be, TTENTRIES_TABLE_NAME );
368  if ( version == 0 )
369  {
370  gnc_sql_create_table( be, TTENTRIES_TABLE_NAME, TTENTRIES_TABLE_VERSION, ttentries_col_table );
371  }
372  else if ( version == 1 )
373  {
374  /* Upgrade 64 bit int handling */
375  gnc_sql_upgrade_table( be, TTENTRIES_TABLE_NAME, ttentries_col_table );
376  gnc_sql_set_table_version( be, TTENTRIES_TABLE_NAME, TTENTRIES_TABLE_VERSION );
377  PINFO("Taxtable entries table upgraded from version 1 to version %d\n", TTENTRIES_TABLE_VERSION);
378  }
379 }
380 
381 /* ================================================================= */
382 static gboolean
383 delete_all_tt_entries( GncSqlBackend* be, const GncGUID* guid )
384 {
385  guid_info_t guid_info;
386 
387  g_return_val_if_fail( be != NULL, FALSE );
388  g_return_val_if_fail( guid != NULL, FALSE );
389 
390  guid_info.be = be;
391  guid_info.guid = guid;
392  return gnc_sql_do_db_operation( be, OP_DB_DELETE, TTENTRIES_TABLE_NAME,
393  TTENTRIES_TABLE_NAME, &guid_info, guid_col_table );
394 }
395 
396 static gboolean
397 save_tt_entries( GncSqlBackend* be, const GncGUID* guid, GList* entries )
398 {
399  GList* entry;
400  gboolean is_ok;
401 
402  g_return_val_if_fail( be != NULL, FALSE );
403  g_return_val_if_fail( guid != NULL, FALSE );
404 
405  /* First, delete the old entries for this object */
406  is_ok = delete_all_tt_entries( be, guid );
407 
408  for ( entry = entries; entry != NULL && is_ok; entry = entry->next )
409  {
410  GncTaxTableEntry* e = (GncTaxTableEntry*)entry->data;
411  is_ok = gnc_sql_do_db_operation( be,
412  OP_DB_INSERT,
413  TTENTRIES_TABLE_NAME,
414  GNC_ID_TAXTABLE, e,
415  ttentries_col_table );
416  }
417 
418  return is_ok;
419 }
420 
421 static gboolean
422 save_taxtable( GncSqlBackend* be, QofInstance* inst )
423 {
424  GncTaxTable* tt;
425  const GncGUID* guid;
426  gint op;
427  gboolean is_infant;
428  gboolean is_ok;
429 
430  g_return_val_if_fail( inst != NULL, FALSE );
431  g_return_val_if_fail( GNC_IS_TAXTABLE(inst), FALSE );
432  g_return_val_if_fail( be != NULL, FALSE );
433 
434  tt = GNC_TAXTABLE(inst);
435 
436  is_infant = qof_instance_get_infant( inst );
437  if ( qof_instance_get_destroying( inst ) )
438  {
439  op = OP_DB_DELETE;
440  }
441  else if ( be->is_pristine_db || is_infant )
442  {
443  op = OP_DB_INSERT;
444  }
445  else
446  {
447  op = OP_DB_UPDATE;
448  }
449  is_ok = gnc_sql_do_db_operation( be, op, TT_TABLE_NAME, GNC_ID_TAXTABLE, tt, tt_col_table );
450 
451  if ( is_ok )
452  {
453  // Now, commit or delete any slots and tax table entries
454  guid = qof_instance_get_guid( inst );
455  if ( !qof_instance_get_destroying(inst) )
456  {
457  is_ok = gnc_sql_slots_save( be, guid, is_infant, qof_instance_get_slots( inst ) );
458  if ( is_ok )
459  {
460  is_ok = save_tt_entries( be, guid, gncTaxTableGetEntries( tt ) );
461  }
462  }
463  else
464  {
465  is_ok = gnc_sql_slots_delete( be, guid );
466  if ( is_ok )
467  {
468  is_ok = delete_all_tt_entries( be, guid );
469  }
470  }
471  }
472 
473  return is_ok;
474 }
475 
476 /* ================================================================= */
477 static void
478 save_next_taxtable( QofInstance* inst, gpointer data )
479 {
480  write_objects_t* s = (write_objects_t*)data;
481 
482  if ( s->is_ok )
483  {
484  s->is_ok = save_taxtable( s->be, inst );
485  }
486 }
487 
488 static gboolean
489 write_taxtables( GncSqlBackend* be )
490 {
491  write_objects_t data;
492 
493  g_return_val_if_fail( be != NULL, FALSE );
494 
495  data.be = be;
496  data.is_ok = TRUE;
497  qof_object_foreach( GNC_ID_TAXTABLE, be->book, save_next_taxtable, &data );
498 
499  return data.is_ok;
500 }
501 
502 /* ================================================================= */
503 static void
504 load_taxtable_guid( const GncSqlBackend* be, GncSqlRow* row,
505  QofSetterFunc setter, gpointer pObject,
506  const GncSqlColumnTableEntry* table_row )
507 {
508  const GValue* val;
509  GncGUID guid;
510  GncTaxTable* taxtable = NULL;
511 
512  g_return_if_fail( be != NULL );
513  g_return_if_fail( row != NULL );
514  g_return_if_fail( pObject != NULL );
515  g_return_if_fail( table_row != NULL );
516 
517  val = gnc_sql_row_get_value_at_col_name( row, table_row->col_name );
518  if ( val != NULL && G_VALUE_HOLDS_STRING( val ) && g_value_get_string( val ) != NULL )
519  {
520  string_to_guid( g_value_get_string( val ), &guid );
521  taxtable = gncTaxTableLookup( be->book, &guid );
522  if ( taxtable != NULL )
523  {
524  if ( table_row->gobj_param_name != NULL )
525  {
526  qof_instance_increase_editlevel (pObject);
527  g_object_set( pObject, table_row->gobj_param_name, taxtable, NULL );
528  qof_instance_decrease_editlevel (pObject);
529  }
530  else
531  {
532  (*setter)( pObject, (const gpointer)taxtable );
533  }
534  }
535  else
536  {
537  PWARN( "Taxtable ref '%s' not found", g_value_get_string( val ) );
538  }
539  }
540 }
541 
542 static GncSqlColumnTypeHandler taxtable_guid_handler
543 = { load_taxtable_guid,
547  };
548 /* ================================================================= */
549 void
550 gnc_taxtable_sql_initialize( void )
551 {
552  static GncSqlObjectBackend be_data =
553  {
554  GNC_SQL_BACKEND_VERSION,
555  GNC_ID_TAXTABLE,
556  save_taxtable, /* commit */
557  load_all_taxtables, /* initial_load */
558  create_taxtable_tables, /* create_tables */
559  NULL, NULL, NULL,
560  write_taxtables /* write */
561  };
562 
563  qof_object_register_backend( GNC_ID_TAXTABLE, GNC_SQL_BACKEND, &be_data );
564 
565  gnc_sql_register_col_type_handler( CT_TAXTABLEREF, &taxtable_guid_handler );
566 }
567 /* ========================== END OF FILE ===================== */
568 
gboolean qof_object_register_backend(QofIdTypeConst type_name, const char *backend_name, gpointer be_data)
const GncGUID * qof_instance_get_guid(gconstpointer)
gint gnc_sql_get_table_version(const GncSqlBackend *be, const gchar *table_name)
#define COL_AUTOINC
QofBook * qof_instance_get_book(gconstpointer)
void gnc_sql_upgrade_table(GncSqlBackend *be, const gchar *table_name, const GncSqlColumnTableEntry *col_table)
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
#define PINFO(format, args...)
Definition: qoflog.h:249
void gnc_sql_add_colname_to_list(const GncSqlColumnTableEntry *table_row, GList **pList)
load and save accounts data to SQL
GncSqlStatement * gnc_sql_create_select_statement(GncSqlBackend *be, const gchar *table_name)
#define COL_NNUL
gboolean qof_instance_get_destroying(gconstpointer ptr)
gboolean string_to_guid(const gchar *string, GncGUID *guid)
gboolean gnc_sql_create_table(GncSqlBackend *be, const gchar *table_name, gint table_version, const GncSqlColumnTableEntry *col_table)
load and save data to SQL
void gnc_sql_register_col_type_handler(const gchar *colType, const GncSqlColumnTypeHandler *handler)
GncSqlConnection * conn
void gnc_sql_add_objectref_guid_col_info_to_list(const GncSqlBackend *be, const GncSqlColumnTableEntry *table_row, GList **pList)
gchar * guid_to_string_buff(const GncGUID *guid, gchar *buff)
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
Definition: qofclass.h:177
QofBook * book
Definition: guid.h:65
#define COL_PKEY
#define PWARN(format, args...)
Definition: qoflog.h:243
const GncGUID * gnc_sql_load_guid(const GncSqlBackend *be, GncSqlRow *row)
gboolean gnc_sql_set_table_version(GncSqlBackend *be, const gchar *table_name, gint version)
void gnc_sql_add_gvalue_objectref_guid_to_slist(const GncSqlBackend *be, QofIdTypeConst obj_name, const gpointer pObject, const GncSqlColumnTableEntry *table_row, GSList **pList)
#define GUID_ENCODING_LENGTH
Definition: guid.h:74
void qof_object_foreach(QofIdTypeConst type_name, QofBook *book, QofInstanceForeachCB cb, gpointer user_data)
void gnc_sql_slots_load(GncSqlBackend *be, QofInstance *inst)
GncSqlResult * gnc_sql_execute_select_statement(GncSqlBackend *be, GncSqlStatement *stmt)
void gnc_sql_load_object(const GncSqlBackend *be, GncSqlRow *row, QofIdTypeConst obj_name, gpointer pObject, const GncSqlColumnTableEntry *table)
const gchar * gobj_param_name
gboolean gnc_sql_slots_delete(GncSqlBackend *be, const GncGUID *guid)
gboolean is_pristine_db
void(* QofSetterFunc)(gpointer, gpointer)
Definition: qofclass.h:184
gboolean gnc_sql_do_db_operation(GncSqlBackend *be, E_DB_OPERATION op, const gchar *table_name, QofIdTypeConst obj_name, gpointer pObject, const GncSqlColumnTableEntry *table)
Business Entry Interface.
gboolean gnc_sql_slots_save(GncSqlBackend *be, const GncGUID *guid, gboolean is_infant, KvpFrame *pFrame)
const gchar * QofLogModule
Definition: qofid.h:89
load and save tax table data to SQL