GnuCash  2.6.99
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
gnc-backend-sql.c
Go to the documentation of this file.
1 /********************************************************************
2  * gnc-backend-sql.c: load and save data to SQL *
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 \********************************************************************/
29 #include <stdlib.h>
30 #include "config.h"
31 
32 #include <errno.h>
33 #include <glib.h>
34 #include <glib/gi18n.h>
35 #include <glib/gstdio.h>
36 
37 #include "qof.h"
38 #include "qofquery-p.h"
39 #include "qofquerycore-p.h"
40 #include "Account.h"
41 #include "TransLog.h"
42 #include "gnc-engine.h"
43 #include "SX-book.h"
44 #include "Recurrence.h"
45 #include "gncBillTerm.h"
46 #include "gncTaxTable.h"
47 #include "gncInvoice.h"
48 
49 #include "gnc-backend-sql.h"
50 
51 #include "gnc-account-sql.h"
52 #include "gnc-book-sql.h"
53 #include "gnc-budget-sql.h"
54 #include "gnc-commodity-sql.h"
55 #include "gnc-lots-sql.h"
56 #include "gnc-price-sql.h"
57 #include "gnc-pricedb.h"
58 #include "gnc-recurrence-sql.h"
59 #include "gnc-schedxaction-sql.h"
60 #include "gnc-slots-sql.h"
61 #include "gnc-transaction-sql.h"
62 
63 #include "gnc-address-sql.h"
64 #include "gnc-bill-term-sql.h"
65 #include "gnc-customer-sql.h"
66 #include "gnc-employee-sql.h"
67 #include "gnc-entry-sql.h"
68 #include "gnc-invoice-sql.h"
69 #include "gnc-job-sql.h"
70 #include "gnc-order-sql.h"
71 #include "gnc-owner-sql.h"
72 #include "gnc-tax-table-sql.h"
73 #include "gnc-vendor-sql.h"
74 
75 #include "gnc-prefs.h"
76 
77 #if defined( S_SPLINT_S )
78 #include "splint-defs.h"
79 #endif
80 
81 static void gnc_sql_init_object_handlers( void );
82 static void update_progress( GncSqlBackend* be );
83 static void finish_progress( GncSqlBackend* be );
84 static void register_standard_col_type_handlers( void );
85 static gboolean reset_version_info( GncSqlBackend* be );
86 /*@ null @*/
87 static GncSqlStatement* build_insert_statement( GncSqlBackend* be,
88  const gchar* table_name,
89  QofIdTypeConst obj_name, gpointer pObject,
91 /*@ null @*/
92 static GncSqlStatement* build_update_statement( GncSqlBackend* be,
93  const gchar* table_name,
94  QofIdTypeConst obj_name, gpointer pObject,
96 /*@ null @*/
97 static GncSqlStatement* build_delete_statement( GncSqlBackend* be,
98  const gchar* table_name,
99  QofIdTypeConst obj_name, gpointer pObject,
100  const GncSqlColumnTableEntry* table );
101 
102 static GList *post_load_commodities = NULL;
103 
104 #define TRANSACTION_NAME "trans"
105 
106 typedef struct
107 {
108  /*@ dependent @*/ QofIdType searchObj;
109  /*@ dependent @*/
110  gpointer pCompiledQuery;
112 
113 /* callback structure */
114 typedef struct
115 {
116  gboolean is_known;
117  gboolean is_ok;
118  /*@ dependent @*/
119  GncSqlBackend* be;
120  /*@ dependent @*/
121  QofInstance* inst;
122  /*@ dependent @*/
123  QofQuery* pQuery;
124  /*@ dependent @*/
125  gpointer pCompiledQuery;
126  /*@ owned @*/
127  gnc_sql_query_info* pQueryInfo;
128 } sql_backend;
129 
130 static QofLogModule log_module = G_LOG_DOMAIN;
131 
132 #define SQLITE_PROVIDER_NAME "SQLite"
133 
134 /* ================================================================= */
135 
136 void
137 gnc_sql_init( /*@ unused @*/ GncSqlBackend* be )
138 {
139  static gboolean initialized = FALSE;
140 
141  if ( !initialized )
142  {
143  register_standard_col_type_handlers();
144  gnc_sql_init_object_handlers();
145  initialized = TRUE;
146  }
147 }
148 
149 /* ================================================================= */
150 
151 static void
152 create_tables_cb( const gchar* type, gpointer data_p, gpointer be_p )
153 {
154  GncSqlObjectBackend* pData = data_p;
155  GncSqlBackend* be = be_p;
156 
157  g_return_if_fail( type != NULL && data_p != NULL && be_p != NULL );
158  g_return_if_fail( pData->version == GNC_SQL_BACKEND_VERSION );
159 
160  if ( pData->create_tables != NULL )
161  {
162  update_progress( be );
163  (pData->create_tables)( be );
164  }
165 }
166 
167 /* ================================================================= */
168 
169 /* Main object load order */
170 static const gchar* fixed_load_order[] =
171 { GNC_ID_BOOK, GNC_ID_COMMODITY, GNC_ID_ACCOUNT, GNC_ID_LOT, NULL };
172 
173 /* Load order for objects from other modules */
174 static const gchar** other_load_order = NULL;
175 
176 void
177 gnc_sql_set_load_order( const gchar** load_order )
178 {
179  other_load_order = load_order;
180 }
181 
182 static void
183 initial_load_cb( const gchar* type, gpointer data_p, gpointer be_p )
184 {
185  GncSqlObjectBackend* pData = data_p;
186  GncSqlBackend* be = be_p;
187  gint i;
188 
189  g_return_if_fail( type != NULL && data_p != NULL && be_p != NULL );
190  g_return_if_fail( pData->version == GNC_SQL_BACKEND_VERSION );
191 
192  // Don't need to load anything if it has already been loaded with the fixed order
193  for ( i = 0; fixed_load_order[i] != NULL; i++ )
194  {
195  update_progress( be );
196  if ( g_ascii_strcasecmp( type, fixed_load_order[i] ) == 0 ) return;
197  }
198  if ( other_load_order != NULL )
199  {
200  for ( i = 0; other_load_order[i] != NULL; i++ )
201  {
202  update_progress( be );
203  if ( g_ascii_strcasecmp( type, other_load_order[i] ) == 0 ) return;
204  }
205  }
206 
207  if ( pData->initial_load != NULL )
208  {
209  (pData->initial_load)( be );
210  }
211 }
212 
213 void
215  gpointer *comm)
216 {
217  post_load_commodities = g_list_prepend(post_load_commodities, comm);
218 }
219 
220 static void
221 commit_commodity (gpointer data)
222 {
223  gnc_commodity *comm = GNC_COMMODITY (data);
224  gnc_sql_commit_commodity (comm);
225 }
226 
227 void
228 gnc_sql_load( GncSqlBackend* be, /*@ dependent @*/ QofBook *book, QofBackendLoadType loadType )
229 {
230  GncSqlObjectBackend* pData;
231  gint i;
232  Account* root;
233 
234  g_return_if_fail( be != NULL );
235  g_return_if_fail( book != NULL );
236 
237  ENTER( "be=%p, book=%p", be, book );
238 
239  be->loading = TRUE;
240 
241  if ( loadType == LOAD_TYPE_INITIAL_LOAD )
242  {
243  g_assert( be->book == NULL );
244  be->book = book;
245 
246  /* Load any initial stuff. Some of this needs to happen in a certain order */
247  for ( i = 0; fixed_load_order[i] != NULL; i++ )
248  {
249  pData = qof_object_lookup_backend( fixed_load_order[i], GNC_SQL_BACKEND );
250  if ( pData->initial_load != NULL )
251  {
252  update_progress( be );
253  (pData->initial_load)( be );
254  }
255  }
256  if ( other_load_order != NULL )
257  {
258  for ( i = 0; other_load_order[i] != NULL; i++ )
259  {
260  pData = qof_object_lookup_backend( other_load_order[i], GNC_SQL_BACKEND );
261  if ( pData->initial_load != NULL )
262  {
263  update_progress( be );
264  (pData->initial_load)( be );
265  }
266  }
267  }
268 
269  root = gnc_book_get_root_account( book );
270  gnc_account_foreach_descendant( root, (AccountCb)xaccAccountBeginEdit, NULL );
271 
272  qof_object_foreach_backend( GNC_SQL_BACKEND, initial_load_cb, be );
273 
274  gnc_account_foreach_descendant( root, (AccountCb)xaccAccountCommitEdit, NULL );
275  }
276  else if ( loadType == LOAD_TYPE_LOAD_ALL )
277  {
278  // Load all transactions
280  }
281 
282  be->loading = FALSE;
283  g_list_free_full (post_load_commodities, commit_commodity);
284  post_load_commodities = NULL;
285 
286  /* Mark the sessoion as clean -- though it should never be marked
287  * dirty with this backend
288  */
290  finish_progress( be );
291 
292  LEAVE( "" );
293 }
294 
295 /* ================================================================= */
296 
297 static gboolean
298 write_account_tree( GncSqlBackend* be, Account* root )
299 {
300  GList* descendants;
301  /*@ dependent @*/
302  GList* node;
303  gboolean is_ok = TRUE;
304 
305  g_return_val_if_fail( be != NULL, FALSE );
306  g_return_val_if_fail( root != NULL, FALSE );
307 
308  is_ok = gnc_sql_save_account( be, QOF_INSTANCE(root) );
309  if ( is_ok )
310  {
311  descendants = gnc_account_get_descendants( root );
312  for ( node = descendants; node != NULL && is_ok; node = g_list_next(node) )
313  {
314  is_ok = gnc_sql_save_account( be, QOF_INSTANCE(GNC_ACCOUNT(node->data)) );
315  if ( !is_ok ) break;
316  }
317  g_list_free( descendants );
318  }
319  update_progress( be );
320 
321  return is_ok;
322 }
323 
324 static gboolean
325 write_accounts( GncSqlBackend* be )
326 {
327  gboolean is_ok;
328 
329  g_return_val_if_fail( be != NULL, FALSE );
330 
331  update_progress( be );
332  is_ok = write_account_tree( be, gnc_book_get_root_account( be->book ) );
333  if ( is_ok )
334  {
335  update_progress( be );
336  is_ok = write_account_tree( be, gnc_book_get_template_root( be->book ) );
337  }
338 
339  return is_ok;
340 }
341 
342 static int
343 write_tx( Transaction* tx, gpointer data )
344 {
345  write_objects_t* s = (write_objects_t*)data;
346 
347  g_return_val_if_fail( tx != NULL, 0 );
348  g_return_val_if_fail( data != NULL, 0 );
349 
350  s->is_ok = gnc_sql_save_transaction( s->be, QOF_INSTANCE(tx) );
351  update_progress( s->be );
352 
353  if ( s->is_ok )
354  {
355  return 0;
356  }
357  else
358  {
359  return 1;
360  }
361 }
362 
363 static gboolean
364 write_transactions( GncSqlBackend* be )
365 {
366  write_objects_t data;
367 
368  g_return_val_if_fail( be != NULL, FALSE );
369 
370  data.be = be;
371  data.is_ok = TRUE;
373  gnc_book_get_root_account( be->book ), write_tx, &data );
374  update_progress( be );
375  return data.is_ok;
376 }
377 
378 static gboolean
379 write_template_transactions( GncSqlBackend* be )
380 {
381  Account* ra;
382  write_objects_t data;
383 
384  g_return_val_if_fail( be != NULL, FALSE );
385 
386  data.is_ok = TRUE;
387  data.be = be;
388  ra = gnc_book_get_template_root( be->book );
389  if ( gnc_account_n_descendants( ra ) > 0 )
390  {
391  (void)xaccAccountTreeForEachTransaction( ra, write_tx, &data );
392  update_progress( be );
393  }
394 
395  return data.is_ok;
396 }
397 
398 static gboolean
399 write_schedXactions( GncSqlBackend* be )
400 {
401  GList* schedXactions;
402  SchedXaction* tmpSX;
403  gboolean is_ok = TRUE;
404 
405  g_return_val_if_fail( be != NULL, FALSE );
406 
407  schedXactions = gnc_book_get_schedxactions( be->book )->sx_list;
408 
409  for ( ; schedXactions != NULL && is_ok; schedXactions = schedXactions->next )
410  {
411  tmpSX = schedXactions->data;
412  is_ok = gnc_sql_save_schedxaction( be, QOF_INSTANCE( tmpSX ) );
413  }
414  update_progress( be );
415 
416  return is_ok;
417 }
418 
419 static void
420 write_cb( const gchar* type, gpointer data_p, gpointer be_p )
421 {
422  GncSqlObjectBackend* pData = data_p;
423  GncSqlBackend* be = (GncSqlBackend*)be_p;
424 
425  g_return_if_fail( type != NULL && data_p != NULL && be_p != NULL );
426  g_return_if_fail( pData->version == GNC_SQL_BACKEND_VERSION );
427 
428  if ( pData->write != NULL )
429  {
430  (void)(pData->write)( be );
431  update_progress( be );
432  }
433 }
434 
435 static void
436 update_progress( GncSqlBackend* be )
437 {
438  if ( be->be.percentage != NULL )
439  (be->be.percentage)( NULL, 101.0 );
440 }
441 
442 static void
443 finish_progress( GncSqlBackend* be )
444 {
445  if ( be->be.percentage != NULL )
446  (be->be.percentage)( NULL, -1.0 );
447 }
448 
449 void
450 gnc_sql_sync_all( GncSqlBackend* be, /*@ dependent @*/ QofBook *book )
451 {
452  gboolean is_ok;
453 
454  g_return_if_fail( be != NULL );
455  g_return_if_fail( book != NULL );
456 
457  ENTER( "book=%p, be->book=%p", book, be->book );
458  update_progress( be );
459  (void)reset_version_info( be );
460 
461  /* Create new tables */
462  be->is_pristine_db = TRUE;
463  qof_object_foreach_backend( GNC_SQL_BACKEND, create_tables_cb, be );
464 
465  /* Save all contents */
466  be->book = book;
467  be->obj_total = 0;
468  be->obj_total += 1 + gnc_account_n_descendants( gnc_book_get_root_account( book ) );
469  be->obj_total += gnc_book_count_transactions( book );
470  be->operations_done = 0;
471 
472  is_ok = gnc_sql_connection_begin_transaction( be->conn );
473 
474  // FIXME: should write the set of commodities that are used
475  //write_commodities( be, book );
476  if ( is_ok )
477  {
478  is_ok = gnc_sql_save_book( be, QOF_INSTANCE(book) );
479  }
480  if ( is_ok )
481  {
482  is_ok = write_accounts( be );
483  }
484  if ( is_ok )
485  {
486  is_ok = write_transactions( be );
487  }
488  if ( is_ok )
489  {
490  is_ok = write_template_transactions( be );
491  }
492  if ( is_ok )
493  {
494  is_ok = write_schedXactions( be );
495  }
496  if ( is_ok )
497  {
498  qof_object_foreach_backend( GNC_SQL_BACKEND, write_cb, be );
499  }
500  if ( is_ok )
501  {
502  is_ok = gnc_sql_connection_commit_transaction( be->conn );
503  }
504  if ( is_ok )
505  {
506  be->is_pristine_db = FALSE;
507 
508  /* Mark the session as clean -- though it shouldn't ever get
509  * marked dirty with this backend
510  */
512  }
513  else
514  {
516  is_ok = gnc_sql_connection_rollback_transaction( be->conn );
517  }
518  finish_progress( be );
519  LEAVE( "book=%p", book );
520 }
521 
522 /* ================================================================= */
523 /* Routines to deal with the creation of multiple books. */
524 
525 void
527 {
528  g_return_if_fail( be != NULL );
529  g_return_if_fail( inst != NULL );
530 
531  ENTER( " " );
532  LEAVE( "" );
533 }
534 
535 void
537 {
538  g_return_if_fail( be != NULL );
539  g_return_if_fail( inst != NULL );
540 
541  ENTER( " " );
542  LEAVE( "" );
543 }
544 
545 static void
546 commit_cb( const gchar* type, gpointer data_p, gpointer be_data_p )
547 {
548  GncSqlObjectBackend* pData = data_p;
549  sql_backend* be_data = be_data_p;
550 
551  g_return_if_fail( type != NULL && pData != NULL && be_data != NULL );
552  g_return_if_fail( pData->version == GNC_SQL_BACKEND_VERSION );
553 
554  /* If this has already been handled, or is not the correct handler, return */
555  if ( strcmp( pData->type_name, be_data->inst->e_type ) != 0 ) return;
556  if ( be_data->is_known ) return;
557 
558  if ( pData->commit != NULL )
559  {
560  be_data->is_ok = (pData->commit)( be_data->be, be_data->inst );
561  be_data->is_known = TRUE;
562  }
563 }
564 
565 /* Commit_edit handler - find the correct backend handler for this object
566  * type and call its commit handler
567  */
568 void
570 {
571  sql_backend be_data;
572  gboolean is_dirty;
573  gboolean is_destroying;
574  gboolean is_infant;
575 
576  g_return_if_fail( be != NULL );
577  g_return_if_fail( inst != NULL );
578 
579  if ( qof_book_is_readonly( be->book ) )
580  {
582  (void)gnc_sql_connection_rollback_transaction( be->conn );
583  return;
584  }
585  /* During initial load where objects are being created, don't commit
586  anything, but do mark the object as clean. */
587  if ( be->loading )
588  {
589  qof_instance_mark_clean( inst );
590  return;
591  }
592 
593  // The engine has a PriceDB object but it isn't in the database
594  if ( strcmp( inst->e_type, "PriceDB" ) == 0 )
595  {
596  qof_instance_mark_clean( inst );
598  return;
599  }
600 
601  ENTER( " " );
602 
603  is_dirty = qof_instance_get_dirty_flag( inst );
604  is_destroying = qof_instance_get_destroying( inst );
605  is_infant = qof_instance_get_infant( inst );
606 
607  DEBUG( "%s dirty = %d, do_free = %d, infant = %d\n",
608  (inst->e_type ? inst->e_type : "(null)"),
609  is_dirty, is_destroying, is_infant );
610 
611  if ( !is_dirty && !is_destroying )
612  {
613  LEAVE( "!dirty OR !destroying" );
614  return;
615  }
616 
617  if ( !gnc_sql_connection_begin_transaction( be->conn ) )
618  {
619  PERR( "gnc_sql_commit_edit(): begin_transaction failed\n" );
620  LEAVE( "Rolled back - database transaction begin error" );
621  return;
622  }
623 
624  be_data.is_known = FALSE;
625  be_data.be = be;
626  be_data.inst = inst;
627  be_data.is_ok = TRUE;
628 
629  qof_object_foreach_backend( GNC_SQL_BACKEND, commit_cb, &be_data );
630 
631  if ( !be_data.is_known )
632  {
633  PERR( "gnc_sql_commit_edit(): Unknown object type '%s'\n", inst->e_type );
634  (void)gnc_sql_connection_rollback_transaction( be->conn );
635 
636  // Don't let unknown items still mark the book as being dirty
638  qof_instance_mark_clean(inst);
639  LEAVE( "Rolled back - unknown object type" );
640  return;
641  }
642  if ( !be_data.is_ok )
643  {
644  // Error - roll it back
645  (void)gnc_sql_connection_rollback_transaction( be->conn );
646 
647  // This *should* leave things marked dirty
648  LEAVE( "Rolled back - database error" );
649  return;
650  }
651 
652  (void)gnc_sql_connection_commit_transaction( be->conn );
653 
655  qof_instance_mark_clean(inst);
656 
657  LEAVE( "" );
658 }
659 /* ---------------------------------------------------------------------- */
660 
661 /* Query processing */
662 static void
663 handle_and_term( QofQueryTerm* pTerm, GString* sql )
664 {
665  GSList* pParamPath;
666  QofQueryPredData* pPredData;
667  gboolean isInverted;
668  GSList* name;
669  gchar val[G_ASCII_DTOSTR_BUF_SIZE];
670 
671  g_return_if_fail( pTerm != NULL );
672  g_return_if_fail( sql != NULL );
673 
674  pParamPath = qof_query_term_get_param_path( pTerm );
675  pPredData = qof_query_term_get_pred_data( pTerm );
676  isInverted = qof_query_term_is_inverted( pTerm );
677 
678  if ( strcmp( pPredData->type_name, QOF_TYPE_GUID ) == 0 )
679  {
680  query_guid_t guid_data = (query_guid_t)pPredData;
681  GList* guid_entry;
682 
683  for ( name = pParamPath; name != NULL; name = name->next )
684  {
685  if ( name != pParamPath ) g_string_append( sql, "." );
686  g_string_append( sql, name->data );
687  }
688 
689  if ( guid_data->options == QOF_GUID_MATCH_ANY )
690  {
691  if ( isInverted ) g_string_append( sql, " NOT " );
692  g_string_append( sql, " IN (" );
693  }
694  for ( guid_entry = guid_data->guids; guid_entry != NULL; guid_entry = guid_entry->next )
695  {
696  if ( guid_entry != guid_data->guids ) g_string_append( sql, "." );
697  (void)guid_to_string_buff( guid_entry->data, val );
698  g_string_append( sql, "'" );
699  g_string_append( sql, val );
700  g_string_append( sql, "'" );
701  }
702  if ( guid_data->options == QOF_GUID_MATCH_ANY )
703  {
704  g_string_append( sql, ")" );
705  }
706  }
707 
708  g_string_append( sql, "(" );
709  if ( isInverted )
710  {
711  g_string_append( sql, "!" );
712  }
713 
714  for ( name = pParamPath; name != NULL; name = name->next )
715  {
716  if ( name != pParamPath ) g_string_append( sql, "." );
717  g_string_append( sql, name->data );
718  }
719 
720  if ( pPredData->how == QOF_COMPARE_LT )
721  {
722  g_string_append( sql, "<" );
723  }
724  else if ( pPredData->how == QOF_COMPARE_LTE )
725  {
726  g_string_append( sql, "<=" );
727  }
728  else if ( pPredData->how == QOF_COMPARE_EQUAL )
729  {
730  g_string_append( sql, "=" );
731  }
732  else if ( pPredData->how == QOF_COMPARE_GT )
733  {
734  g_string_append( sql, ">" );
735  }
736  else if ( pPredData->how == QOF_COMPARE_GTE )
737  {
738  g_string_append( sql, ">=" );
739  }
740  else if ( pPredData->how == QOF_COMPARE_NEQ )
741  {
742  g_string_append( sql, "~=" );
743  }
744  else
745  {
746  g_string_append( sql, "??" );
747  }
748 
749  if ( strcmp( pPredData->type_name, "string" ) == 0 )
750  {
751  query_string_t pData = (query_string_t)pPredData;
752  g_string_append( sql, "'" );
753  g_string_append( sql, pData->matchstring );
754  g_string_append( sql, "'" );
755  }
756  else if ( strcmp( pPredData->type_name, "date" ) == 0 )
757  {
758  query_date_t pData = (query_date_t)pPredData;
759 
760  (void)gnc_timespec_to_iso8601_buff( pData->date, val );
761  g_string_append( sql, "'" );
762  //g_string_append( sql, val, 4+1+2+1+2 );
763  g_string_append( sql, "'" );
764  }
765  else if ( strcmp( pPredData->type_name, "numeric" ) == 0 )
766  {
767  /* query_numeric_t pData = (query_numeric_t)pPredData; */
768 
769  g_string_append( sql, "numeric" );
770  }
771  else if ( strcmp( pPredData->type_name, QOF_TYPE_GUID ) == 0 )
772  {
773  }
774  else if ( strcmp( pPredData->type_name, "gint32" ) == 0 )
775  {
776  query_int32_t pData = (query_int32_t)pPredData;
777 
778  sprintf( val, "%d", pData->val );
779  g_string_append( sql, val );
780  }
781  else if ( strcmp( pPredData->type_name, "gint64" ) == 0 )
782  {
783  query_int64_t pData = (query_int64_t)pPredData;
784 
785  sprintf( val, "%" G_GINT64_FORMAT, pData->val );
786  g_string_append( sql, val );
787  }
788  else if ( strcmp( pPredData->type_name, "double" ) == 0 )
789  {
790  query_double_t pData = (query_double_t)pPredData;
791 
792  g_ascii_dtostr( val, sizeof(val), pData->val );
793  g_string_append( sql, val );
794  }
795  else if ( strcmp( pPredData->type_name, "boolean" ) == 0 )
796  {
797  query_boolean_t pData = (query_boolean_t)pPredData;
798 
799  sprintf( val, "%d", pData->val );
800  g_string_append( sql, val );
801  }
802  else
803  {
804  g_assert( FALSE );
805  }
806 
807  g_string_append( sql, ")" );
808 }
809 
810 static void
811 compile_query_cb( const gchar* type, gpointer data_p, gpointer be_data_p )
812 {
813  GncSqlObjectBackend* pData = data_p;
814  sql_backend* be_data = be_data_p;
815 
816  g_return_if_fail( type != NULL && pData != NULL && be_data != NULL );
817  g_return_if_fail( pData->version == GNC_SQL_BACKEND_VERSION );
818 
819  // Is this the right item?
820  if ( strcmp( type, be_data->pQueryInfo->searchObj ) != 0 ) return;
821  if ( be_data->is_ok ) return;
822 
823  if ( pData->compile_query != NULL )
824  {
825  be_data->pQueryInfo->pCompiledQuery = (pData->compile_query)(
826  be_data->be,
827  be_data->pQuery );
828  be_data->is_ok = TRUE;
829  }
830 }
831 
832 gchar* gnc_sql_compile_query_to_sql( GncSqlBackend* be, QofQuery* query );
833 
834 /*@ null @*/
835 gpointer
836 gnc_sql_compile_query( QofBackend* pBEnd, QofQuery* pQuery )
837 {
838  GncSqlBackend *be = (GncSqlBackend*)pBEnd;
839  QofIdType searchObj;
840  sql_backend be_data;
841  gnc_sql_query_info* pQueryInfo;
842 
843  g_return_val_if_fail( pBEnd != NULL, NULL );
844  g_return_val_if_fail( pQuery != NULL, NULL );
845 
846  ENTER( " " );
847 
848 //gnc_sql_compile_query_to_sql( be, pQuery );
849  searchObj = qof_query_get_search_for( pQuery );
850 
851  pQueryInfo = g_malloc( (gsize)sizeof( gnc_sql_query_info ) );
852  g_assert( pQueryInfo != NULL );
853  pQueryInfo->pCompiledQuery = NULL;
854  pQueryInfo->searchObj = searchObj;
855 
856  // Try various objects first
857  be_data.is_ok = FALSE;
858  be_data.be = be;
859  be_data.pQuery = pQuery;
860  be_data.pQueryInfo = pQueryInfo;
861 
862  qof_object_foreach_backend( GNC_SQL_BACKEND, compile_query_cb, &be_data );
863  if ( be_data.is_ok )
864  {
865  LEAVE( "" );
866  return be_data.pQueryInfo;
867  }
868 
869  LEAVE( "" );
870 
871  return pQueryInfo;
872 }
873 
874 static const gchar*
875 convert_search_obj( QofIdType objType )
876 {
877  return (gchar*)objType;
878 }
879 
880 gchar*
881 gnc_sql_compile_query_to_sql( GncSqlBackend* be, QofQuery* query )
882 {
883  QofIdType searchObj;
884  GString* sql;
885 
886  g_return_val_if_fail( be != NULL, NULL );
887  g_return_val_if_fail( query != NULL, NULL );
888 
889  searchObj = qof_query_get_search_for( query );
890 
891  /* Convert search object type to table name */
892  sql = g_string_new( "" );
893  g_string_append( sql, "SELECT * FROM " );
894  g_string_append( sql, convert_search_obj( searchObj ) );
895  if ( !qof_query_has_terms( query ) )
896  {
897  g_string_append( sql, ";" );
898  }
899  else
900  {
901  GList* orterms = qof_query_get_terms( query );
902  GList* orTerm;
903 
904  g_string_append( sql, " WHERE " );
905 
906  for ( orTerm = orterms; orTerm != NULL; orTerm = orTerm->next )
907  {
908  GList* andterms = (GList*)orTerm->data;
909  GList* andTerm;
910 
911  if ( orTerm != orterms ) g_string_append( sql, " OR " );
912  g_string_append( sql, "(" );
913  for ( andTerm = andterms; andTerm != NULL; andTerm = andTerm->next )
914  {
915  if ( andTerm != andterms ) g_string_append( sql, " AND " );
916  handle_and_term( (QofQueryTerm*)andTerm->data, sql );
917  }
918  g_string_append( sql, ")" );
919  }
920  }
921 
922  DEBUG( "Compiled: %s\n", sql->str );
923  return g_string_free( sql, FALSE );
924 }
925 
926 static void
927 free_query_cb( const gchar* type, gpointer data_p, gpointer be_data_p )
928 {
929  GncSqlObjectBackend* pData = data_p;
930  sql_backend* be_data = be_data_p;
931 
932  g_return_if_fail( type != NULL && pData != NULL && be_data != NULL );
933  g_return_if_fail( pData->version == GNC_SQL_BACKEND_VERSION );
934  if ( be_data->is_ok ) return;
935  if ( strcmp( type, be_data->pQueryInfo->searchObj ) != 0 ) return;
936 
937  if ( pData->free_query != NULL )
938  {
939  (pData->free_query)( be_data->be, be_data->pCompiledQuery );
940  be_data->is_ok = TRUE;
941  }
942 }
943 
944 void
945 gnc_sql_free_query( QofBackend* pBEnd, gpointer pQuery )
946 {
947  GncSqlBackend *be = (GncSqlBackend*)pBEnd;
948  gnc_sql_query_info* pQueryInfo = (gnc_sql_query_info*)pQuery;
949  sql_backend be_data;
950 
951  g_return_if_fail( pBEnd != NULL );
952  g_return_if_fail( pQuery != NULL );
953 
954  ENTER( " " );
955 
956  // Try various objects first
957  be_data.is_ok = FALSE;
958  be_data.be = be;
959  be_data.pCompiledQuery = pQuery;
960  be_data.pQueryInfo = pQueryInfo;
961 
962  qof_object_foreach_backend( GNC_SQL_BACKEND, free_query_cb, &be_data );
963  if ( be_data.is_ok )
964  {
965  LEAVE( "" );
966  return;
967  }
968 
969  if ( pQueryInfo->pCompiledQuery != NULL )
970  {
971  DEBUG( "%s\n", (gchar*)pQueryInfo->pCompiledQuery );
972  g_free( pQueryInfo->pCompiledQuery );
973  }
974  g_free( pQueryInfo );
975 
976  LEAVE( "" );
977 }
978 
979 static void
980 run_query_cb( const gchar* type, gpointer data_p, gpointer be_data_p )
981 {
982  GncSqlObjectBackend* pData = data_p;
983  sql_backend* be_data = be_data_p;
984 
985  g_return_if_fail( type != NULL && pData != NULL && be_data != NULL );
986  g_return_if_fail( pData->version == GNC_SQL_BACKEND_VERSION );
987  if ( be_data->is_ok ) return;
988 
989  // Is this the right item?
990  if ( strcmp( type, be_data->pQueryInfo->searchObj ) != 0 ) return;
991 
992  if ( pData->run_query != NULL )
993  {
994  (pData->run_query)( be_data->be, be_data->pCompiledQuery );
995  be_data->is_ok = TRUE;
996  }
997 }
998 
999 void
1000 gnc_sql_run_query( QofBackend* pBEnd, gpointer pQuery )
1001 {
1002  GncSqlBackend *be = (GncSqlBackend*)pBEnd;
1003  gnc_sql_query_info* pQueryInfo = (gnc_sql_query_info*)pQuery;
1004  sql_backend be_data;
1005 
1006  g_return_if_fail( pBEnd != NULL );
1007  g_return_if_fail( pQuery != NULL );
1008  g_return_if_fail( !be->in_query );
1009 
1010  ENTER( " " );
1011 
1012  be->loading = TRUE;
1013  be->in_query = TRUE;
1014 
1016 
1017  // Try various objects first
1018  be_data.is_ok = FALSE;
1019  be_data.be = be;
1020  be_data.pCompiledQuery = pQueryInfo->pCompiledQuery;
1021  be_data.pQueryInfo = pQueryInfo;
1022 
1023  qof_object_foreach_backend( GNC_SQL_BACKEND, run_query_cb, &be_data );
1024  be->loading = FALSE;
1025  be->in_query = FALSE;
1026  qof_event_resume();
1027 // if( be_data.is_ok ) {
1028 // LEAVE( "" );
1029 // return;
1030 // }
1031 
1032  // Mark the book as clean
1033  qof_instance_mark_clean( QOF_INSTANCE(be->book) );
1034 
1035 // DEBUG( "%s\n", (gchar*)pQueryInfo->pCompiledQuery );
1036 
1037  LEAVE( "" );
1038 }
1039 
1040 /* ================================================================= */
1041 /* Order in which business objects need to be loaded */
1042 static const gchar* business_fixed_load_order[] =
1043 { GNC_ID_BILLTERM, GNC_ID_TAXTABLE, GNC_ID_INVOICE, NULL };
1044 
1045 static void
1046 business_core_sql_init(void)
1047 {
1048  /* Initialize our pointers into the backend subsystem */
1049  gnc_address_sql_initialize();
1050  gnc_billterm_sql_initialize();
1051  gnc_customer_sql_initialize();
1052  gnc_employee_sql_initialize();
1053  gnc_entry_sql_initialize();
1054  gnc_invoice_sql_initialize();
1055  gnc_job_sql_initialize();
1056  gnc_order_sql_initialize();
1057  gnc_owner_sql_initialize();
1058  gnc_taxtable_sql_initialize();
1059  gnc_vendor_sql_initialize();
1060 
1061  gnc_sql_set_load_order( business_fixed_load_order );
1062 }
1063 
1064 static void
1065 gnc_sql_init_object_handlers( void )
1066 {
1067  gnc_sql_init_book_handler();
1068  gnc_sql_init_commodity_handler();
1069  gnc_sql_init_account_handler();
1070  gnc_sql_init_budget_handler();
1071  gnc_sql_init_price_handler();
1072  gnc_sql_init_transaction_handler();
1073  gnc_sql_init_slots_handler();
1074  gnc_sql_init_recurrence_handler();
1075  gnc_sql_init_schedxaction_handler();
1076  gnc_sql_init_lot_handler();
1077 
1078  /* And the business objects */
1079  business_core_sql_init();
1080 }
1081 
1082 /* ================================================================= */
1083 
1084 gint64
1085 gnc_sql_get_integer_value( const GValue* value )
1086 {
1087  g_return_val_if_fail( value != NULL, 0 );
1088 
1089  if ( G_VALUE_HOLDS_INT(value) )
1090  {
1091  return (gint64)g_value_get_int( value );
1092  }
1093  else if ( G_VALUE_HOLDS_UINT(value) )
1094  {
1095  return (gint64)g_value_get_uint( value );
1096  }
1097  else if ( G_VALUE_HOLDS_LONG(value) )
1098  {
1099  return (gint64)g_value_get_long( value );
1100  }
1101  else if ( G_VALUE_HOLDS_ULONG(value) )
1102  {
1103  return (gint64)g_value_get_ulong( value );
1104  }
1105  else if ( G_VALUE_HOLDS_INT64(value) )
1106  {
1107  return g_value_get_int64( value );
1108  }
1109  else if ( G_VALUE_HOLDS_UINT64(value) )
1110  {
1111  return (gint64)g_value_get_uint64( value );
1112  }
1113  else if ( G_VALUE_HOLDS_STRING( value ) )
1114  {
1115  return g_ascii_strtoll( g_value_get_string( value ), NULL, 10 );
1116  }
1117  else
1118  {
1119  PWARN( "Unknown type: %s", G_VALUE_TYPE_NAME( value ) );
1120  }
1121 
1122  return 0;
1123 }
1124 
1125 /* ----------------------------------------------------------------- */
1126 /*@ null @*/ static gpointer
1127 get_autoinc_id()
1128 {
1129  // Just need a 0 to force a new autoinc value
1130  return (gpointer)0;
1131 }
1132 
1133 static void
1134 set_autoinc_id()
1135 {
1136  // Nowhere to put the ID
1137 }
1138 
1139 /*@ null @*/ QofAccessFunc
1141 {
1142  QofAccessFunc getter;
1143 
1144  g_return_val_if_fail( obj_name != NULL, NULL );
1145  g_return_val_if_fail( table_row != NULL, NULL );
1146 
1147  if ( (table_row->flags & COL_AUTOINC) != 0 )
1148  {
1149  getter = get_autoinc_id;
1150  }
1151  else if ( table_row->qof_param_name != NULL )
1152  {
1153  getter = qof_class_get_parameter_getter( obj_name,
1154  table_row->qof_param_name );
1155  }
1156  else
1157  {
1158  getter = table_row->getter;
1159  }
1160 
1161  return getter;
1162 }
1163 
1164 /* ----------------------------------------------------------------- */
1165 void
1166 gnc_sql_add_colname_to_list( const GncSqlColumnTableEntry* table_row, GList** pList )
1167 {
1168  (*pList) = g_list_append( (*pList), g_strdup( table_row->col_name ) );
1169 }
1170 
1171 /* ----------------------------------------------------------------- */
1172 void
1174 GList** pList )
1175 {
1176  const GncSqlColumnTableEntry* subtable_row;
1177  gchar* buf;
1178 
1179  for ( subtable_row = subtable; subtable_row->col_name != NULL; subtable_row++ )
1180  {
1181  buf = g_strdup_printf( "%s_%s", table_row->col_name, subtable_row->col_name );
1182  (*pList) = g_list_append( (*pList), buf );
1183  }
1184 }
1185 
1186 static GncSqlColumnInfo*
1187 create_column_info( const GncSqlColumnTableEntry* table_row, GncSqlBasicColumnType type,
1188 gint size, gboolean is_unicode )
1189 {
1190  GncSqlColumnInfo* info;
1191 
1192  info = g_new0( GncSqlColumnInfo, 1 );
1193  g_assert( info != NULL );
1194  info->name = g_strdup( table_row->col_name );
1195  info->type = type;
1196  info->size = size;
1197  info->is_primary_key = ((table_row->flags & COL_PKEY) != 0) ? TRUE : FALSE;
1198  info->null_allowed = ((table_row->flags & COL_NNUL) != 0) ? FALSE : TRUE;
1199  info->is_unicode = is_unicode;
1200  info->is_autoinc = ((table_row->flags & COL_AUTOINC) != 0) ? TRUE : FALSE;
1201 
1202  return info;
1203 }
1204 
1205 /* ----------------------------------------------------------------- */
1206 static void
1207 load_string( const GncSqlBackend* be, GncSqlRow* row,
1208 /*@ null @*/ QofSetterFunc setter, gpointer pObject,
1209 const GncSqlColumnTableEntry* table_row )
1210 {
1211  const GValue* val;
1212  const gchar* s;
1213 
1214  g_return_if_fail( be != NULL );
1215  g_return_if_fail( row != NULL );
1216  g_return_if_fail( pObject != NULL );
1217  g_return_if_fail( table_row != NULL );
1218  g_return_if_fail( table_row->gobj_param_name != NULL || setter != NULL );
1219 
1220  val = gnc_sql_row_get_value_at_col_name( row, table_row->col_name );
1221  g_return_if_fail( val != NULL );
1222  s = g_value_get_string( val );
1223  if ( table_row->gobj_param_name != NULL )
1224  {
1225  if (QOF_IS_INSTANCE (pObject))
1226  qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
1227  g_object_set( pObject, table_row->gobj_param_name, s, NULL );
1228  if (QOF_IS_INSTANCE (pObject))
1229  qof_instance_decrease_editlevel (QOF_INSTANCE (pObject));
1230  }
1231  else
1232  {
1233  g_return_if_fail( setter != NULL );
1234  (*setter)( pObject, (const gpointer)s );
1235  }
1236 }
1237 
1238 static void
1239 add_string_col_info_to_list( const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row,
1240 GList** pList )
1241 {
1242  GncSqlColumnInfo* info;
1243 
1244  g_return_if_fail( be != NULL );
1245  g_return_if_fail( table_row != NULL );
1246  g_return_if_fail( pList != NULL );
1247 
1248  info = create_column_info( table_row, BCT_STRING, table_row->size, TRUE );
1249 
1250  *pList = g_list_append( *pList, info );
1251 }
1252 
1253 static void
1254 add_gvalue_string_to_slist( const GncSqlBackend* be, QofIdTypeConst obj_name,
1255 const gpointer pObject, const GncSqlColumnTableEntry* table_row, GSList** pList )
1256 {
1257  QofAccessFunc getter;
1258  gchar* s = NULL;
1259  GValue* value;
1260 
1261  g_return_if_fail( be != NULL );
1262  g_return_if_fail( obj_name != NULL );
1263  g_return_if_fail( pObject != NULL );
1264  g_return_if_fail( table_row != NULL );
1265  g_return_if_fail( pList != NULL );
1266 
1267  value = g_new0( GValue, 1 );
1268  g_assert( value != NULL );
1269  memset( value, 0, sizeof( GValue ) );
1270  if ( table_row->gobj_param_name != NULL )
1271  {
1272  g_object_get( pObject, table_row->gobj_param_name, &s, NULL );
1273  }
1274  else
1275  {
1276  getter = gnc_sql_get_getter( obj_name, table_row );
1277  if ( getter != NULL )
1278  {
1279  s = (gchar*)(*getter)( pObject, NULL );
1280  if ( s != NULL )
1281  {
1282  s = g_strdup( s );
1283  }
1284  }
1285  }
1286  (void)g_value_init( value, G_TYPE_STRING );
1287  if ( s )
1288  {
1289  g_value_take_string( value, s );
1290  }
1291 
1292  (*pList) = g_slist_append( (*pList), value );
1293 }
1294 
1295 static GncSqlColumnTypeHandler string_handler
1296 =
1297 {
1298  load_string,
1299  add_string_col_info_to_list,
1301  add_gvalue_string_to_slist
1302 };
1303 /* ----------------------------------------------------------------- */
1304 typedef gint (*IntAccessFunc)( const gpointer );
1305 typedef void (*IntSetterFunc)( const gpointer, gint );
1306 
1307 static void
1308 load_int( const GncSqlBackend* be, GncSqlRow* row,
1309  /*@ null @*/ QofSetterFunc setter, gpointer pObject,
1310  const GncSqlColumnTableEntry* table_row )
1311 {
1312  const GValue* val;
1313  gint int_value;
1314  IntSetterFunc i_setter;
1315 
1316  g_return_if_fail( be != NULL );
1317  g_return_if_fail( row != NULL );
1318  g_return_if_fail( pObject != NULL );
1319  g_return_if_fail( table_row != NULL );
1320  g_return_if_fail( table_row->gobj_param_name != NULL || setter != NULL );
1321 
1322  val = gnc_sql_row_get_value_at_col_name( row, table_row->col_name );
1323  if ( val == NULL )
1324  {
1325  int_value = 0;
1326  }
1327  else
1328  {
1329  int_value = (gint)gnc_sql_get_integer_value( val );
1330  }
1331  if ( table_row->gobj_param_name != NULL )
1332  {
1333  if (QOF_IS_INSTANCE (pObject))
1334  qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
1335  g_object_set( pObject, table_row->gobj_param_name, int_value, NULL );
1336  if (QOF_IS_INSTANCE (pObject))
1337  qof_instance_decrease_editlevel (QOF_INSTANCE (pObject));
1338  }
1339  else
1340  {
1341  g_return_if_fail( setter != NULL );
1342  i_setter = (IntSetterFunc)setter;
1343  (*i_setter)( pObject, int_value );
1344  }
1345 }
1346 
1347 static void
1348 add_int_col_info_to_list( const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row,
1349  GList** pList )
1350 {
1351  GncSqlColumnInfo* info;
1352 
1353  g_return_if_fail( be != NULL );
1354  g_return_if_fail( table_row != NULL );
1355  g_return_if_fail( pList != NULL );
1356 
1357  info = create_column_info( table_row, BCT_INT, 0, FALSE );
1358 
1359  *pList = g_list_append( *pList, info );
1360 }
1361 
1362 static void
1363 add_gvalue_int_to_slist( const GncSqlBackend* be, QofIdTypeConst obj_name,
1364  const gpointer pObject, const GncSqlColumnTableEntry* table_row, GSList** pList )
1365 {
1366  gint int_value = 0;
1367  IntAccessFunc i_getter;
1368  GValue* value;
1369 
1370  g_return_if_fail( be != NULL );
1371  g_return_if_fail( obj_name != NULL );
1372  g_return_if_fail( pObject != NULL );
1373  g_return_if_fail( table_row != NULL );
1374  g_return_if_fail( pList != NULL );
1375 
1376  value = g_new0( GValue, 1 );
1377  g_assert( value != NULL );
1378  (void)g_value_init( value, G_TYPE_INT );
1379 
1380  if ( table_row->gobj_param_name != NULL )
1381  {
1382  g_object_get_property( pObject, table_row->gobj_param_name, value );
1383  }
1384  else
1385  {
1386  i_getter = (IntAccessFunc)gnc_sql_get_getter( obj_name, table_row );
1387  if ( i_getter != NULL )
1388  {
1389  int_value = (*i_getter)( pObject );
1390  }
1391  g_value_set_int( value, int_value );
1392  }
1393 
1394  (*pList) = g_slist_append( (*pList), value );
1395 }
1396 
1397 static GncSqlColumnTypeHandler int_handler
1398 =
1399 {
1400  load_int,
1401  add_int_col_info_to_list,
1403  add_gvalue_int_to_slist
1404 };
1405 /* ----------------------------------------------------------------- */
1406 typedef gboolean (*BooleanAccessFunc)( const gpointer );
1407 typedef void (*BooleanSetterFunc)( const gpointer, gboolean );
1408 
1409 static void
1410 load_boolean( const GncSqlBackend* be, GncSqlRow* row,
1411  /*@ null @*/ QofSetterFunc setter, gpointer pObject,
1412  const GncSqlColumnTableEntry* table_row )
1413 {
1414  const GValue* val;
1415  gint int_value;
1416  BooleanSetterFunc b_setter;
1417 
1418  g_return_if_fail( be != NULL );
1419  g_return_if_fail( row != NULL );
1420  g_return_if_fail( pObject != NULL );
1421  g_return_if_fail( table_row != NULL );
1422  g_return_if_fail( table_row->gobj_param_name != NULL || setter != NULL );
1423 
1424  val = gnc_sql_row_get_value_at_col_name( row, table_row->col_name );
1425  if ( val == NULL )
1426  {
1427  int_value = 0;
1428  }
1429  else
1430  {
1431  int_value = (gint)gnc_sql_get_integer_value( val );
1432  }
1433  if ( table_row->gobj_param_name != NULL )
1434  {
1435  if (QOF_IS_INSTANCE (pObject))
1436  qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
1437  g_object_set( pObject, table_row->gobj_param_name, int_value, NULL );
1438  if (QOF_IS_INSTANCE (pObject))
1439  qof_instance_decrease_editlevel (QOF_INSTANCE (pObject));
1440  }
1441  else
1442  {
1443  g_return_if_fail( setter != NULL );
1444  b_setter = (BooleanSetterFunc)setter;
1445  (*b_setter)( pObject, (int_value != 0) ? TRUE : FALSE );
1446  }
1447 }
1448 
1449 static void
1450 add_boolean_col_info_to_list( const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row,
1451  GList** pList )
1452 {
1453  GncSqlColumnInfo* info;
1454 
1455  g_return_if_fail( be != NULL );
1456  g_return_if_fail( table_row != NULL );
1457  g_return_if_fail( pList != NULL );
1458 
1459  info = create_column_info( table_row, BCT_INT, 0, FALSE );
1460 
1461  *pList = g_list_append( *pList, info );
1462 }
1463 
1464 static void
1465 add_gvalue_boolean_to_slist( const GncSqlBackend* be, QofIdTypeConst obj_name,
1466  const gpointer pObject, const GncSqlColumnTableEntry* table_row, GSList** pList )
1467 {
1468  gint int_value = 0;
1469  BooleanAccessFunc b_getter;
1470  GValue* value;
1471 
1472  g_return_if_fail( be != NULL );
1473  g_return_if_fail( obj_name != NULL );
1474  g_return_if_fail( pObject != NULL );
1475  g_return_if_fail( table_row != NULL );
1476  g_return_if_fail( pList != NULL );
1477 
1478  value = g_new0( GValue, 1 );
1479  g_assert( value != NULL );
1480 
1481  if ( table_row->gobj_param_name != NULL )
1482  {
1483  g_object_get( pObject, table_row->gobj_param_name, &int_value, NULL );
1484  }
1485  else
1486  {
1487  b_getter = (BooleanAccessFunc)gnc_sql_get_getter( obj_name, table_row );
1488  if ( b_getter != NULL )
1489  {
1490  int_value = ((*b_getter)( pObject )) ? 1 : 0;
1491  }
1492  }
1493  (void)g_value_init( value, G_TYPE_INT );
1494  g_value_set_int( value, int_value );
1495 
1496  (*pList) = g_slist_append( (*pList), value );
1497 }
1498 
1499 static GncSqlColumnTypeHandler boolean_handler
1500 =
1501 {
1502  load_boolean,
1503  add_boolean_col_info_to_list,
1505  add_gvalue_boolean_to_slist
1506 };
1507 /* ----------------------------------------------------------------- */
1508 typedef gint64 (*Int64AccessFunc)( const gpointer );
1509 typedef void (*Int64SetterFunc)( const gpointer, gint64 );
1510 
1511 static void
1512 load_int64( const GncSqlBackend* be, GncSqlRow* row,
1513  /*@ null @*/ QofSetterFunc setter, gpointer pObject,
1514  const GncSqlColumnTableEntry* table_row )
1515 {
1516  const GValue* val;
1517  gint64 i64_value = 0;
1518  Int64SetterFunc i64_setter = (Int64SetterFunc)setter;
1519 
1520  g_return_if_fail( be != NULL );
1521  g_return_if_fail( row != NULL );
1522  g_return_if_fail( table_row != NULL );
1523  g_return_if_fail( table_row->gobj_param_name != NULL || setter != NULL );
1524 
1525  val = gnc_sql_row_get_value_at_col_name( row, table_row->col_name );
1526  if ( val != NULL )
1527  {
1528  i64_value = gnc_sql_get_integer_value( val );
1529  }
1530  if ( table_row->gobj_param_name != NULL )
1531  {
1532  if (QOF_IS_INSTANCE (pObject))
1533  qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
1534  g_object_set( pObject, table_row->gobj_param_name, i64_value, NULL );
1535  if (QOF_IS_INSTANCE (pObject))
1536  qof_instance_decrease_editlevel (QOF_INSTANCE (pObject));
1537  }
1538  else
1539  {
1540  (*i64_setter)( pObject, i64_value );
1541  }
1542 }
1543 
1544 static void
1545 add_int64_col_info_to_list( const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row,
1546  GList** pList )
1547 {
1548  GncSqlColumnInfo* info;
1549 
1550  g_return_if_fail( be != NULL );
1551  g_return_if_fail( table_row != NULL );
1552  g_return_if_fail( pList != NULL );
1553 
1554  info = create_column_info( table_row, BCT_INT64, 0, FALSE );
1555 
1556  *pList = g_list_append( *pList, info );
1557 }
1558 
1559 static void
1560 add_gvalue_int64_to_slist( const GncSqlBackend* be, QofIdTypeConst obj_name,
1561  const gpointer pObject, const GncSqlColumnTableEntry* table_row, GSList** pList )
1562 {
1563  gint64 i64_value = 0;
1564  Int64AccessFunc getter;
1565  GValue* value;
1566 
1567  g_return_if_fail( be != NULL );
1568  g_return_if_fail( obj_name != NULL );
1569  g_return_if_fail( pObject != NULL );
1570  g_return_if_fail( table_row != NULL );
1571  g_return_if_fail( pList != NULL );
1572 
1573  value = g_new0( GValue, 1 );
1574  g_assert( value != NULL );
1575  if ( table_row->gobj_param_name != NULL )
1576  {
1577  g_object_get( pObject, table_row->gobj_param_name, &i64_value, NULL );
1578  }
1579  else
1580  {
1581  getter = (Int64AccessFunc)gnc_sql_get_getter( obj_name, table_row );
1582  if ( getter != NULL )
1583  {
1584  i64_value = (*getter)( pObject );
1585  }
1586  }
1587  (void)g_value_init( value, G_TYPE_INT64 );
1588  g_value_set_int64( value, i64_value );
1589 
1590  (*pList) = g_slist_append( (*pList), value );
1591 }
1592 
1593 static GncSqlColumnTypeHandler int64_handler
1594 =
1595 {
1596  load_int64,
1597  add_int64_col_info_to_list,
1599  add_gvalue_int64_to_slist
1600 };
1601 /* ----------------------------------------------------------------- */
1602 
1603 static void
1604 load_double( const GncSqlBackend* be, GncSqlRow* row,
1605  /*@ null @*/ QofSetterFunc setter, gpointer pObject,
1606  const GncSqlColumnTableEntry* table_row )
1607 {
1608  const GValue* val;
1609  gdouble d_value;
1610 
1611  g_return_if_fail( be != NULL );
1612  g_return_if_fail( row != NULL );
1613  g_return_if_fail( pObject != NULL );
1614  g_return_if_fail( table_row != NULL );
1615  g_return_if_fail( table_row->gobj_param_name != NULL || setter != NULL );
1616 
1617  val = gnc_sql_row_get_value_at_col_name( row, table_row->col_name );
1618  if ( val == NULL )
1619  {
1620  (*setter)( pObject, (gpointer)NULL );
1621  }
1622  else
1623  {
1624  if ( G_VALUE_HOLDS(val, G_TYPE_INT) )
1625  {
1626  d_value = (gdouble)g_value_get_int( val );
1627  }
1628  else if ( G_VALUE_HOLDS(val, G_TYPE_FLOAT) )
1629  {
1630  d_value = g_value_get_float( val );
1631  }
1632  else if (G_VALUE_HOLDS(val, G_TYPE_DOUBLE) )
1633  {
1634  d_value = g_value_get_double( val );
1635  }
1636  else
1637  {
1638  PWARN( "Unknown float value type: %s\n", g_type_name( G_VALUE_TYPE(val) ) );
1639  d_value = 0;
1640  }
1641  if ( table_row->gobj_param_name != NULL )
1642  {
1643  if (QOF_IS_INSTANCE (pObject))
1644  qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
1645  g_object_set( pObject, table_row->gobj_param_name, d_value, NULL );
1646  if (QOF_IS_INSTANCE (pObject))
1647  qof_instance_decrease_editlevel (QOF_INSTANCE (pObject));
1648  }
1649  else
1650  {
1651  (*setter)( pObject, (gpointer)&d_value );
1652  }
1653  }
1654 }
1655 
1656 static void
1657 add_double_col_info_to_list( const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row,
1658  GList** pList )
1659 {
1660  GncSqlColumnInfo* info;
1661 
1662  g_return_if_fail( be != NULL );
1663  g_return_if_fail( table_row != NULL );
1664  g_return_if_fail( pList != NULL );
1665 
1666  info = create_column_info( table_row, BCT_DOUBLE, 0, FALSE );
1667 
1668  *pList = g_list_append( *pList, info );
1669 }
1670 
1671 static void
1672 add_gvalue_double_to_slist( const GncSqlBackend* be, QofIdTypeConst obj_name,
1673  const gpointer pObject, const GncSqlColumnTableEntry* table_row, GSList** pList )
1674 {
1675  QofAccessFunc getter;
1676  gdouble* pDouble = NULL;
1677  gdouble d_value;
1678  GValue* value;
1679 
1680  g_return_if_fail( be != NULL );
1681  g_return_if_fail( obj_name != NULL );
1682  g_return_if_fail( pObject != NULL );
1683  g_return_if_fail( table_row != NULL );
1684 
1685  value = g_new0( GValue, 1 );
1686  g_assert( value != NULL );
1687  getter = gnc_sql_get_getter( obj_name, table_row );
1688  if ( getter != NULL )
1689  {
1690  pDouble = (*getter)( pObject, NULL );
1691  }
1692  if ( pDouble != NULL )
1693  {
1694  d_value = *pDouble;
1695  (void)g_value_init( value, G_TYPE_DOUBLE );
1696  g_value_set_double( value, d_value );
1697  }
1698  else
1699  {
1700  (void)g_value_init( value, G_TYPE_DOUBLE );
1701  g_value_set_double( value, 0.0 );
1702  }
1703 
1704  (*pList) = g_slist_append( (*pList), value );
1705 }
1706 
1707 static GncSqlColumnTypeHandler double_handler
1708 =
1709 {
1710  load_double,
1711  add_double_col_info_to_list,
1713  add_gvalue_double_to_slist
1714 };
1715 /* ----------------------------------------------------------------- */
1716 
1717 static void
1718 load_guid( const GncSqlBackend* be, GncSqlRow* row,
1719  /*@ null @*/ QofSetterFunc setter, gpointer pObject,
1720  const GncSqlColumnTableEntry* table_row )
1721 {
1722  const GValue* val;
1723  GncGUID guid;
1724  const GncGUID* pGuid;
1725 
1726  g_return_if_fail( be != NULL );
1727  g_return_if_fail( row != NULL );
1728  g_return_if_fail( pObject != NULL );
1729  g_return_if_fail( table_row != NULL );
1730  g_return_if_fail( table_row->gobj_param_name != NULL || setter != NULL );
1731 
1732  val = gnc_sql_row_get_value_at_col_name( row, table_row->col_name );
1733  if ( val == NULL || g_value_get_string( val ) == NULL )
1734  {
1735  pGuid = NULL;
1736  }
1737  else
1738  {
1739  (void)string_to_guid( g_value_get_string( val ), &guid );
1740  pGuid = &guid;
1741  }
1742  if ( pGuid != NULL )
1743  {
1744  if ( table_row->gobj_param_name != NULL )
1745  {
1746  if (QOF_IS_INSTANCE (pObject))
1747  qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
1748  g_object_set( pObject, table_row->gobj_param_name, pGuid, NULL );
1749  if (QOF_IS_INSTANCE (pObject))
1750  qof_instance_decrease_editlevel (QOF_INSTANCE (pObject));
1751  }
1752  else
1753  {
1754  g_return_if_fail( setter != NULL );
1755  (*setter)( pObject, (const gpointer)pGuid );
1756  }
1757  }
1758 }
1759 
1760 static void
1761 add_guid_col_info_to_list( const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row,
1762  GList** pList )
1763 {
1764  GncSqlColumnInfo* info;
1765 
1766  g_return_if_fail( be != NULL );
1767  g_return_if_fail( table_row != NULL );
1768  g_return_if_fail( pList != NULL );
1769 
1770  info = create_column_info( table_row, BCT_STRING, GUID_ENCODING_LENGTH, FALSE );
1771 
1772  *pList = g_list_append( *pList, info );
1773 }
1774 
1775 static void
1776 add_gvalue_guid_to_slist( const GncSqlBackend* be, QofIdTypeConst obj_name,
1777  const gpointer pObject, const GncSqlColumnTableEntry* table_row, GSList** pList )
1778 {
1779  QofAccessFunc getter;
1780  GncGUID* guid = NULL;
1781  gchar guid_buf[GUID_ENCODING_LENGTH+1];
1782  GValue* value;
1783 
1784  g_return_if_fail( be != NULL );
1785  g_return_if_fail( obj_name != NULL );
1786  g_return_if_fail( pObject != NULL );
1787  g_return_if_fail( table_row != NULL );
1788 
1789  value = g_new0( GValue, 1 );
1790  g_assert( value != NULL );
1791  if ( table_row->gobj_param_name != NULL )
1792  {
1793  g_object_get( pObject, table_row->gobj_param_name, &guid, NULL );
1794  }
1795  else
1796  {
1797  getter = gnc_sql_get_getter( obj_name, table_row );
1798  if ( getter != NULL )
1799  {
1800  guid = (*getter)( pObject, NULL );
1801  }
1802  }
1803  (void)g_value_init( value, G_TYPE_STRING );
1804  if ( guid != NULL )
1805  {
1806  (void)guid_to_string_buff( guid, guid_buf );
1807  g_value_set_string( value, guid_buf );
1808  }
1809 
1810  (*pList) = g_slist_append( (*pList), value );
1811 
1812 }
1813 
1814 static GncSqlColumnTypeHandler guid_handler
1815 =
1816 {
1817  load_guid,
1818  add_guid_col_info_to_list,
1820  add_gvalue_guid_to_slist
1821 };
1822 /* ----------------------------------------------------------------- */
1823 
1824 void
1826  const gpointer pObject, const GncSqlColumnTableEntry* table_row, GSList** pList )
1827 {
1828  QofAccessFunc getter;
1829  const GncGUID* guid = NULL;
1830  gchar guid_buf[GUID_ENCODING_LENGTH+1];
1831  QofInstance* inst = NULL;
1832  GValue* value;
1833 
1834  g_return_if_fail( be != NULL );
1835  g_return_if_fail( obj_name != NULL );
1836  g_return_if_fail( pObject != NULL );
1837  g_return_if_fail( table_row != NULL );
1838 
1839  value = g_new0( GValue, 1 );
1840  g_assert( value != NULL );
1841  if ( table_row->gobj_param_name != NULL )
1842  {
1843  g_object_get( pObject, table_row->gobj_param_name, &inst, NULL );
1844  }
1845  else
1846  {
1847  getter = gnc_sql_get_getter( obj_name, table_row );
1848  if ( getter != NULL )
1849  {
1850  inst = (*getter)( pObject, NULL );
1851  }
1852  }
1853  if ( inst != NULL )
1854  {
1855  guid = qof_instance_get_guid( inst );
1856  }
1857  (void)g_value_init( value, G_TYPE_STRING );
1858  if ( guid != NULL )
1859  {
1860  (void)guid_to_string_buff( guid, guid_buf );
1861  g_value_set_string( value, guid_buf );
1862  }
1863 
1864  (*pList) = g_slist_append( (*pList), value );
1865 }
1866 
1867 void
1869  const GncSqlColumnTableEntry* table_row,
1870  GList** pList )
1871 {
1872  add_guid_col_info_to_list( be, table_row, pList );
1873 }
1874 
1875 /* ----------------------------------------------------------------- */
1876 typedef Timespec (*TimespecAccessFunc)( const gpointer );
1877 typedef void (*TimespecSetterFunc)( const gpointer, Timespec );
1878 
1879 #define TIMESPEC_STR_FORMAT "%04d%02d%02d%02d%02d%02d"
1880 #define TIMESPEC_COL_SIZE (4+2+2+2+2+2)
1881 
1882 gchar*
1884 {
1885  time64 time;
1886  struct tm* tm;
1887  gint year;
1888  gchar* datebuf;
1889 
1890  time = timespecToTime64( ts );
1891  tm = gnc_gmtime( &time );
1892 
1893  year = tm->tm_year + 1900;
1894 
1895  datebuf = g_strdup_printf( be->timespec_format,
1896  year, tm->tm_mon + 1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec );
1897  gnc_tm_free (tm);
1898  return datebuf;
1899 }
1900 
1901 static void
1902 load_timespec( const GncSqlBackend* be, GncSqlRow* row,
1903  /*@ null @*/ QofSetterFunc setter, gpointer pObject,
1904  const GncSqlColumnTableEntry* table_row )
1905 {
1906  const GValue* val;
1907  Timespec ts = {0, 0};
1908  TimespecSetterFunc ts_setter;
1909  gboolean isOK = FALSE;
1910 
1911  g_return_if_fail( be != NULL );
1912  g_return_if_fail( row != NULL );
1913  g_return_if_fail( pObject != NULL );
1914  g_return_if_fail( table_row != NULL );
1915  g_return_if_fail( table_row->gobj_param_name != NULL || setter != NULL );
1916 
1917  ts_setter = (TimespecSetterFunc)setter;
1918  val = gnc_sql_row_get_value_at_col_name( row, table_row->col_name );
1919  if ( val == NULL )
1920  {
1921  isOK = TRUE;
1922  }
1923  else
1924  {
1925  if ( G_VALUE_HOLDS_INT64( val ) )
1926  {
1927  timespecFromTime64 (&ts, (time64)(g_value_get_int64 (val)));
1928  isOK = TRUE;
1929  }
1930  else if (G_VALUE_HOLDS_STRING (val))
1931  {
1932  const gchar* s = g_value_get_string( val );
1933  if ( s != NULL )
1934  {
1935  gchar* buf;
1936  buf = g_strdup_printf( "%c%c%c%c-%c%c-%c%c %c%c:%c%c:%c%c",
1937  s[0], s[1], s[2], s[3],
1938  s[4], s[5],
1939  s[6], s[7],
1940  s[8], s[9],
1941  s[10], s[11],
1942  s[12], s[13] );
1943  ts = gnc_iso8601_to_timespec_gmt( buf );
1944  g_free( buf );
1945  isOK = TRUE;
1946  }
1947  }
1948  else
1949  {
1950  PWARN( "Unknown timespec type: %s", G_VALUE_TYPE_NAME( val ) );
1951  }
1952  }
1953  if ( isOK )
1954  {
1955  if (table_row->gobj_param_name != NULL)
1956  {
1957  if (QOF_IS_INSTANCE (pObject))
1958  qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
1959  g_object_set( pObject, table_row->gobj_param_name, &ts, NULL );
1960  if (QOF_IS_INSTANCE (pObject))
1961  qof_instance_decrease_editlevel (QOF_INSTANCE (pObject));
1962  }
1963  else
1964  {
1965  (*ts_setter)( pObject, ts );
1966  }
1967  }
1968 }
1969 
1970 static void
1971 add_timespec_col_info_to_list( const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row,
1972  GList** pList )
1973 {
1974  GncSqlColumnInfo* info;
1975 
1976  g_return_if_fail( be != NULL );
1977  g_return_if_fail( table_row != NULL );
1978  g_return_if_fail( pList != NULL );
1979 
1980  info = create_column_info( table_row, BCT_DATETIME, TIMESPEC_COL_SIZE, FALSE );
1981 
1982  *pList = g_list_append( *pList, info );
1983 }
1984 
1985 static void
1986 add_gvalue_timespec_to_slist( const GncSqlBackend* be, QofIdTypeConst obj_name,
1987  const gpointer pObject, const GncSqlColumnTableEntry* table_row, GSList** pList )
1988 {
1989  TimespecAccessFunc ts_getter;
1990  Timespec ts;
1991  gchar* datebuf;
1992  GValue* value;
1993 
1994  g_return_if_fail( be != NULL );
1995  g_return_if_fail( obj_name != NULL );
1996  g_return_if_fail( pObject != NULL );
1997  g_return_if_fail( table_row != NULL );
1998  g_return_if_fail( pList != NULL );
1999 
2000  if ( table_row->gobj_param_name != NULL )
2001  {
2002  Timespec* pts;
2003  g_object_get( pObject, table_row->gobj_param_name, &pts, NULL );
2004  ts = *pts;
2005  }
2006  else
2007  {
2008  ts_getter = (TimespecAccessFunc)gnc_sql_get_getter( obj_name, table_row );
2009  g_return_if_fail( ts_getter != NULL );
2010  ts = (*ts_getter)( pObject );
2011  }
2012 
2013  value = g_new0( GValue, 1 );
2014  g_assert( value != NULL );
2015  (void)g_value_init( value, G_TYPE_STRING );
2016  if ( ts.tv_sec != 0 || ts.tv_nsec != 0 )
2017  {
2018  datebuf = gnc_sql_convert_timespec_to_string( be, ts );
2019  g_value_take_string( value, datebuf );
2020  }
2021 
2022  (*pList) = g_slist_append( (*pList), value );
2023 }
2024 
2025 static GncSqlColumnTypeHandler timespec_handler
2026 =
2027 {
2028  load_timespec,
2029  add_timespec_col_info_to_list,
2031  add_gvalue_timespec_to_slist
2032 };
2033 /* ----------------------------------------------------------------- */
2034 #define DATE_COL_SIZE 8
2035 
2036 static void
2037 load_date( const GncSqlBackend* be, GncSqlRow* row,
2038  /*@ null @*/ QofSetterFunc setter, gpointer pObject,
2039  const GncSqlColumnTableEntry* table_row )
2040 {
2041  const GValue* val;
2042 
2043  g_return_if_fail( be != NULL );
2044  g_return_if_fail( row != NULL );
2045  g_return_if_fail( pObject != NULL );
2046  g_return_if_fail( table_row != NULL );
2047  g_return_if_fail( table_row->gobj_param_name != NULL || setter != NULL );
2048 
2049  val = gnc_sql_row_get_value_at_col_name( row, table_row->col_name );
2050  if ( val != NULL )
2051  {
2052  if (G_VALUE_HOLDS_INT64 (val))
2053  {
2054  gint64 time = g_value_get_int64 (val);
2055  GDateTime *gdt = g_date_time_new_from_unix_utc (time);
2056  gint day, month, year;
2057  GDate *date;
2058  g_date_time_get_ymd (gdt, &year, &month, &day);
2059  date = g_date_new_dmy (day, month, year);
2060  g_date_time_unref (gdt);
2061  if ( table_row->gobj_param_name != NULL )
2062  {
2063  if (QOF_IS_INSTANCE (pObject))
2064  qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
2065  g_object_set( pObject, table_row->gobj_param_name, date, NULL );
2066  if (QOF_IS_INSTANCE (pObject))
2067  qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
2068  }
2069  else
2070  {
2071  (*setter)( pObject, date );
2072  }
2073  g_date_free( date );
2074  }
2075  else if ( G_VALUE_HOLDS_STRING( val ) )
2076  {
2077  // Format of date is YYYYMMDD
2078  const gchar* s = g_value_get_string( val );
2079  GDate *date;
2080  if ( s != NULL )
2081  {
2082  gchar buf[5];
2083  GDateDay day;
2084  guint month;
2085  GDateYear year;
2086 
2087  strncpy( buf, &s[0], 4 );
2088  buf[4] = '\0';
2089  year = (GDateYear)atoi( buf );
2090  strncpy( buf, &s[4], 2 );
2091  buf[2] = '\0';
2092  month = (guint)atoi( buf );
2093  strncpy( buf, &s[6], 2 );
2094  day = (GDateDay)atoi( buf );
2095 
2096  if ( year != 0 || month != 0 || day != (GDateDay)0 )
2097  {
2098  date = g_date_new_dmy( day, month, year );
2099  if ( table_row->gobj_param_name != NULL )
2100  {
2101  if (QOF_IS_INSTANCE (pObject))
2102  qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
2103  g_object_set (pObject, table_row->gobj_param_name,
2104  date, NULL);
2105  if (QOF_IS_INSTANCE (pObject))
2106  qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
2107  }
2108  else
2109  {
2110  (*setter)( pObject, date );
2111  }
2112  g_date_free( date );
2113  }
2114  }
2115  }
2116  else
2117  {
2118  PWARN( "Unknown date type: %s", G_VALUE_TYPE_NAME( val ) );
2119  }
2120  }
2121 }
2122 
2123 static void
2124 add_date_col_info_to_list( const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row,
2125  GList** pList )
2126 {
2127  GncSqlColumnInfo* info;
2128 
2129  g_return_if_fail( be != NULL );
2130  g_return_if_fail( table_row != NULL );
2131  g_return_if_fail( pList != NULL );
2132 
2133  info = create_column_info( table_row, BCT_DATE, DATE_COL_SIZE, FALSE );
2134 
2135  *pList = g_list_append( *pList, info );
2136 }
2137 
2138 static void
2139 add_gvalue_date_to_slist( const GncSqlBackend* be, QofIdTypeConst obj_name,
2140  const gpointer pObject,
2141  const GncSqlColumnTableEntry* table_row, GSList** pList )
2142 {
2143  GDate* date = NULL;
2144  QofAccessFunc getter;
2145  gchar* buf;
2146  GValue* value;
2147 
2148  g_return_if_fail( be != NULL );
2149  g_return_if_fail( obj_name != NULL );
2150  g_return_if_fail( pObject != NULL );
2151  g_return_if_fail( table_row != NULL );
2152 
2153  value = g_new0( GValue, 1 );
2154  g_assert( value != NULL );
2155  (void)g_value_init( value, G_TYPE_STRING );
2156  if ( table_row->gobj_param_name != NULL )
2157  {
2158  g_object_get( pObject, table_row->gobj_param_name, &date, NULL );
2159  }
2160  else
2161  {
2162  getter = gnc_sql_get_getter( obj_name, table_row );
2163  if ( getter != NULL )
2164  {
2165  date = (GDate*)(*getter)( pObject, NULL );
2166  }
2167  }
2168  if ( date && g_date_valid( date ) )
2169  {
2170  buf = g_strdup_printf( "%04d%02d%02d",
2171  g_date_get_year( date ), g_date_get_month( date ), g_date_get_day( date ) );
2172  g_value_take_string( value, buf );
2173  }
2174 
2175  (*pList) = g_slist_append( (*pList), value );
2176 }
2177 
2178 static GncSqlColumnTypeHandler date_handler
2179 =
2180 {
2181  load_date,
2182  add_date_col_info_to_list,
2184  add_gvalue_date_to_slist
2185 };
2186 /* ----------------------------------------------------------------- */
2187 typedef gnc_numeric (*NumericGetterFunc)( const gpointer );
2188 typedef void (*NumericSetterFunc)( gpointer, gnc_numeric );
2189 
2190 static const GncSqlColumnTableEntry numeric_col_table[] =
2191 {
2192  /*@ -full_init_block @*/
2193  { "num", CT_INT64, 0, COL_NNUL, "guid" },
2194  { "denom", CT_INT64, 0, COL_NNUL, "guid" },
2195  { NULL }
2196  /*@ +full_init_block @*/
2197 };
2198 
2199 static void
2200 load_numeric( const GncSqlBackend* be, GncSqlRow* row,
2201  /*@ null @*/ QofSetterFunc setter, gpointer pObject,
2202  const GncSqlColumnTableEntry* table_row )
2203 {
2204  const GValue* val;
2205  gchar* buf;
2206  gint64 num, denom;
2207  gnc_numeric n;
2208  gboolean isNull = FALSE;
2209 
2210  g_return_if_fail( be != NULL );
2211  g_return_if_fail( row != NULL );
2212  g_return_if_fail( pObject != NULL );
2213  g_return_if_fail( table_row != NULL );
2214  g_return_if_fail( table_row->gobj_param_name != NULL || setter != NULL );
2215 
2216  buf = g_strdup_printf( "%s_num", table_row->col_name );
2217  val = gnc_sql_row_get_value_at_col_name( row, buf );
2218  g_free( buf );
2219  if ( val == NULL )
2220  {
2221  isNull = TRUE;
2222  num = 0;
2223  }
2224  else
2225  {
2226  num = gnc_sql_get_integer_value( val );
2227  }
2228  buf = g_strdup_printf( "%s_denom", table_row->col_name );
2229  val = gnc_sql_row_get_value_at_col_name( row, buf );
2230  g_free( buf );
2231  if ( val == NULL )
2232  {
2233  isNull = TRUE;
2234  denom = 1;
2235  }
2236  else
2237  {
2238  denom = gnc_sql_get_integer_value( val );
2239  }
2240  n = gnc_numeric_create( num, denom );
2241  if ( !isNull )
2242  {
2243  if ( table_row->gobj_param_name != NULL )
2244  {
2245  if (QOF_IS_INSTANCE (pObject))
2246  qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
2247  g_object_set( pObject, table_row->gobj_param_name, &n, NULL );
2248  if (QOF_IS_INSTANCE (pObject))
2249  qof_instance_increase_editlevel (QOF_INSTANCE (pObject));
2250  }
2251  else
2252  {
2253  NumericSetterFunc n_setter = (NumericSetterFunc)setter;
2254  (*n_setter)( pObject, n );
2255  }
2256  }
2257 }
2258 
2259 static void
2260 add_numeric_col_info_to_list( const GncSqlBackend* be, const GncSqlColumnTableEntry* table_row,
2261  GList** pList )
2262 {
2263  GncSqlColumnInfo* info;
2264  gchar* buf;
2265  const GncSqlColumnTableEntry* subtable_row;
2266 
2267  g_return_if_fail( be != NULL );
2268  g_return_if_fail( table_row != NULL );
2269  g_return_if_fail( pList != NULL );
2270 
2271  for ( subtable_row = numeric_col_table; subtable_row->col_name != NULL; subtable_row++ )
2272  {
2273  buf = g_strdup_printf( "%s_%s", table_row->col_name, subtable_row->col_name );
2274  info = g_new0( GncSqlColumnInfo, 1 );
2275  g_assert( info != NULL );
2276  info->name = buf;
2277  info->type = BCT_INT64;
2278  info->is_primary_key = ((table_row->flags & COL_PKEY) != 0) ? TRUE : FALSE;
2279  info->null_allowed = ((table_row->flags & COL_NNUL) != 0) ? FALSE : TRUE;
2280  info->is_unicode = FALSE;
2281  *pList = g_list_append( *pList, info );
2282  }
2283 }
2284 
2285 static void
2286 add_numeric_colname_to_list( const GncSqlColumnTableEntry* table_row, GList** pList )
2287 {
2288  gnc_sql_add_subtable_colnames_to_list( table_row, numeric_col_table, pList );
2289 }
2290 
2291 static void
2292 add_gvalue_numeric_to_slist( const GncSqlBackend* be, QofIdTypeConst obj_name,
2293  const gpointer pObject, const GncSqlColumnTableEntry* table_row, GSList** pList )
2294 {
2295  NumericGetterFunc getter;
2296  gnc_numeric n;
2297  GValue* num_value;
2298  GValue* denom_value;
2299 
2300  g_return_if_fail( be != NULL );
2301  g_return_if_fail( obj_name != NULL );
2302  g_return_if_fail( pObject != NULL );
2303  g_return_if_fail( table_row != NULL );
2304 
2305  if ( table_row->gobj_param_name != NULL )
2306  {
2307  gnc_numeric *s;
2308  g_object_get( pObject, table_row->gobj_param_name, &s, NULL );
2309  n = *s;
2310  }
2311  else
2312  {
2313  getter = (NumericGetterFunc)gnc_sql_get_getter( obj_name, table_row );
2314  if ( getter != NULL )
2315  {
2316  n = (*getter)( pObject );
2317  }
2318  else
2319  {
2320  n = gnc_numeric_zero();
2321  }
2322  }
2323 
2324  num_value = g_new0( GValue, 1 );
2325  g_assert( num_value != NULL );
2326  (void)g_value_init( num_value, G_TYPE_INT64 );
2327  g_value_set_int64( num_value, gnc_numeric_num( n ) );
2328  denom_value = g_new0( GValue, 1 );
2329  g_assert( denom_value != NULL );
2330  (void)g_value_init( denom_value, G_TYPE_INT64 );
2331  g_value_set_int64( denom_value, gnc_numeric_denom( n ) );
2332 
2333  (*pList) = g_slist_append( (*pList), num_value );
2334  (*pList) = g_slist_append( (*pList), denom_value );
2335 }
2336 
2337 static GncSqlColumnTypeHandler numeric_handler
2338 = { load_numeric,
2339  add_numeric_col_info_to_list,
2340  add_numeric_colname_to_list,
2341  add_gvalue_numeric_to_slist
2342  };
2343 /* ================================================================= */
2344 
2345 static /*@ null @*//*@ only @*/ GHashTable* g_columnTypeHash = NULL;
2346 
2347 void
2348 gnc_sql_register_col_type_handler( const gchar* colType, const GncSqlColumnTypeHandler* handler )
2349 {
2350  g_return_if_fail( colType != NULL );
2351  g_return_if_fail( handler != NULL );
2352 
2353  if ( g_columnTypeHash == NULL )
2354  {
2355  g_columnTypeHash = g_hash_table_new( g_str_hash, g_str_equal );
2356  g_assert( g_columnTypeHash != NULL );
2357  }
2358 
2359  DEBUG( "Col type %s registered\n", colType );
2360  g_hash_table_insert( g_columnTypeHash, (gpointer)colType, (gpointer)handler );
2361 }
2362 
2363 /*@ dependent @*//*@ null @*/ static GncSqlColumnTypeHandler*
2364 get_handler( const GncSqlColumnTableEntry* table_row )
2365 {
2366  GncSqlColumnTypeHandler* pHandler;
2367 
2368  g_return_val_if_fail( table_row != NULL, NULL );
2369  g_return_val_if_fail( table_row->col_type != NULL, NULL );
2370 
2371  if ( g_columnTypeHash != NULL )
2372  {
2373  pHandler = g_hash_table_lookup( g_columnTypeHash, table_row->col_type );
2374  g_assert( pHandler != NULL );
2375  }
2376  else
2377  {
2378  pHandler = NULL;
2379  }
2380 
2381  return pHandler;
2382 }
2383 
2384 static void
2385 register_standard_col_type_handlers( void )
2386 {
2387  gnc_sql_register_col_type_handler( CT_STRING, &string_handler );
2388  gnc_sql_register_col_type_handler( CT_BOOLEAN, &boolean_handler );
2389  gnc_sql_register_col_type_handler( CT_INT, &int_handler );
2390  gnc_sql_register_col_type_handler( CT_INT64, &int64_handler );
2391  gnc_sql_register_col_type_handler( CT_DOUBLE, &double_handler );
2392  gnc_sql_register_col_type_handler( CT_GUID, &guid_handler );
2393  gnc_sql_register_col_type_handler( CT_TIMESPEC, &timespec_handler );
2394  gnc_sql_register_col_type_handler( CT_GDATE, &date_handler );
2395  gnc_sql_register_col_type_handler( CT_NUMERIC, &numeric_handler );
2396 }
2397 
2398 void
2399 _retrieve_guid_( gpointer pObject, /*@ null @*/ gpointer pValue )
2400 {
2401  GncGUID* pGuid = (GncGUID*)pObject;
2402  GncGUID* guid = (GncGUID*)pValue;
2403 
2404  g_return_if_fail( pObject != NULL );
2405  g_return_if_fail( pValue != NULL );
2406 
2407  memcpy( pGuid, guid, sizeof( GncGUID ) );
2408 }
2409 
2410 
2411 // Table to retrieve just the guid
2412 static GncSqlColumnTableEntry guid_table[] =
2413 {
2414  /*@ -full_init_block @*/
2415  { "guid", CT_GUID, 0, 0, NULL, NULL, NULL, _retrieve_guid_ },
2416  { NULL }
2417  /*@ +full_init_block @*/
2418 };
2419 
2420 /*@ null @*/
2421 const GncGUID*
2423 {
2424  static GncGUID guid;
2425 
2426  g_return_val_if_fail( be != NULL, NULL );
2427  g_return_val_if_fail( row != NULL, NULL );
2428 
2429  gnc_sql_load_object( be, row, NULL, &guid, guid_table );
2430 
2431  return &guid;
2432 }
2433 
2434 // Table to retrieve just the guid
2435 static GncSqlColumnTableEntry tx_guid_table[] =
2436 {
2437  /*@ -full_init_block @*/
2438  { "tx_guid", CT_GUID, 0, 0, NULL, NULL, NULL, _retrieve_guid_ },
2439  { NULL }
2440  /*@ +full_init_block @*/
2441 };
2442 
2443 /*@ null @*//*@ dependent @*/
2444 const GncGUID*
2446 {
2447  static GncGUID guid;
2448 
2449  g_return_val_if_fail( be != NULL, NULL );
2450  g_return_val_if_fail( row != NULL, NULL );
2451 
2452  gnc_sql_load_object( be, row, NULL, &guid, tx_guid_table );
2453 
2454  return &guid;
2455 }
2456 
2457 void
2459  /*@ null @*/ QofIdTypeConst obj_name, gpointer pObject,
2460  const GncSqlColumnTableEntry* table )
2461 {
2462  QofSetterFunc setter;
2463  GncSqlColumnTypeHandler* pHandler;
2464  const GncSqlColumnTableEntry* table_row;
2465 
2466  g_return_if_fail( be != NULL );
2467  g_return_if_fail( row != NULL );
2468  g_return_if_fail( pObject != NULL );
2469  g_return_if_fail( table != NULL );
2470 
2471  for ( table_row = table; table_row->col_name != NULL; table_row++ )
2472  {
2473  if ( (table_row->flags & COL_AUTOINC) != 0 )
2474  {
2475  setter = set_autoinc_id;
2476  }
2477  else if ( table_row->qof_param_name != NULL )
2478  {
2479  g_assert( obj_name != NULL );
2480  setter = qof_class_get_parameter_setter( obj_name,
2481  table_row->qof_param_name );
2482  }
2483  else
2484  {
2485  setter = table_row->setter;
2486  }
2487  pHandler = get_handler( table_row );
2488  g_assert( pHandler != NULL );
2489  pHandler->load_fn( be, row, setter, pObject, table_row );
2490  }
2491 }
2492 
2493 /* ================================================================= */
2494 /*@ null @*/ GncSqlStatement*
2495 gnc_sql_create_select_statement( GncSqlBackend* be, const gchar* table_name )
2496 {
2497  gchar* sql;
2498  GncSqlStatement* stmt;
2499 
2500  g_return_val_if_fail( be != NULL, NULL );
2501  g_return_val_if_fail( table_name != NULL, NULL );
2502 
2503  sql = g_strdup_printf( "SELECT * FROM %s", table_name );
2504  stmt = gnc_sql_create_statement_from_sql( be, sql );
2505  g_free( sql );
2506  return stmt;
2507 }
2508 
2509 /*@ null @*/ static GncSqlStatement*
2510 create_single_col_select_statement( GncSqlBackend* be,
2511  const gchar* table_name,
2512  const GncSqlColumnTableEntry* table_row )
2513 {
2514  gchar* sql;
2515  GncSqlStatement* stmt;
2516 
2517  g_return_val_if_fail( be != NULL, NULL );
2518  g_return_val_if_fail( table_name != NULL, NULL );
2519  g_return_val_if_fail( table_row != NULL, NULL );
2520 
2521  sql = g_strdup_printf( "SELECT %s FROM %s", table_row->col_name, table_name );
2522  stmt = gnc_sql_create_statement_from_sql( be, sql );
2523  g_free( sql );
2524  return stmt;
2525 }
2526 
2527 /* ================================================================= */
2528 
2529 /*@ null @*/ GncSqlResult*
2531 {
2532  GncSqlResult* result;
2533 
2534  g_return_val_if_fail( be != NULL, NULL );
2535  g_return_val_if_fail( stmt != NULL, NULL );
2536 
2537  result = gnc_sql_connection_execute_select_statement( be->conn, stmt );
2538  if ( result == NULL )
2539  {
2540  PERR( "SQL error: %s\n", gnc_sql_statement_to_sql( stmt ) );
2542  }
2543 
2544  return result;
2545 }
2546 
2547 /*@ null @*/ GncSqlStatement*
2549 {
2550  GncSqlStatement* stmt;
2551 
2552  g_return_val_if_fail( be != NULL, NULL );
2553  g_return_val_if_fail( sql != NULL, NULL );
2554 
2555  stmt = gnc_sql_connection_create_statement_from_sql( be->conn, sql );
2556  if ( stmt == NULL )
2557  {
2558  PERR( "SQL error: %s\n", sql );
2560  }
2561 
2562  return stmt;
2563 }
2564 
2565 /*@ null @*/ GncSqlResult*
2567 {
2568  GncSqlStatement* stmt;
2569  GncSqlResult* result = NULL;
2570 
2571  g_return_val_if_fail( be != NULL, NULL );
2572  g_return_val_if_fail( sql != NULL, NULL );
2573 
2574  stmt = gnc_sql_create_statement_from_sql( be, sql );
2575  if ( stmt == NULL )
2576  {
2577  return NULL;
2578  }
2579  result = gnc_sql_connection_execute_select_statement( be->conn, stmt );
2580  gnc_sql_statement_dispose( stmt );
2581  if ( result == NULL )
2582  {
2583  PERR( "SQL error: %s\n", sql );
2585  }
2586 
2587  return result;
2588 }
2589 
2590 gint
2592 {
2593  GncSqlStatement* stmt;
2594  gint result;
2595 
2596  g_return_val_if_fail( be != NULL, 0 );
2597  g_return_val_if_fail( sql != NULL, 0 );
2598 
2599  stmt = gnc_sql_create_statement_from_sql( be, sql );
2600  if ( stmt == NULL )
2601  {
2602  return -1;
2603  }
2604  result = gnc_sql_connection_execute_nonselect_statement( be->conn, stmt );
2605  gnc_sql_statement_dispose( stmt );
2606  return result;
2607 }
2608 
2609 static guint
2610 execute_statement_get_count( GncSqlBackend* be, GncSqlStatement* stmt )
2611 {
2612  GncSqlResult* result;
2613  guint count = 0;
2614 
2615  g_return_val_if_fail( be != NULL, 0 );
2616  g_return_val_if_fail( stmt != NULL, 0 );
2617 
2618  result = gnc_sql_execute_select_statement( be, stmt );
2619  if ( result != NULL )
2620  {
2621  count = gnc_sql_result_get_num_rows( result );
2622  gnc_sql_result_dispose( result );
2623  }
2624 
2625  return count;
2626 }
2627 
2628 guint
2629 gnc_sql_append_guid_list_to_sql( GString* sql, GList* list, guint maxCount )
2630 {
2631  gchar guid_buf[GUID_ENCODING_LENGTH+1];
2632  gboolean first_guid = TRUE;
2633  guint count;
2634 
2635  g_return_val_if_fail( sql != NULL, 0 );
2636 
2637  if ( list == NULL ) return 0;
2638 
2639  for ( count = 0; list != NULL && count < maxCount; list = list->next, count++ )
2640  {
2641  QofInstance* inst = QOF_INSTANCE(list->data);
2642  (void)guid_to_string_buff( qof_instance_get_guid( inst ), guid_buf );
2643 
2644  if ( !first_guid )
2645  {
2646  (void)g_string_append( sql, "," );
2647  }
2648  (void)g_string_append( sql, "'" );
2649  (void)g_string_append( sql, guid_buf );
2650  (void)g_string_append( sql, "'" );
2651  first_guid = FALSE;
2652  }
2653 
2654  return count;
2655 }
2656 /* ================================================================= */
2657 
2658 gboolean
2659 gnc_sql_object_is_it_in_db( GncSqlBackend* be, const gchar* table_name,
2660  QofIdTypeConst obj_name, gpointer pObject,
2661  const GncSqlColumnTableEntry* table )
2662 {
2663  GncSqlStatement* sqlStmt;
2664  guint count;
2665  GncSqlColumnTypeHandler* pHandler;
2666  GSList* list = NULL;
2667 
2668  g_return_val_if_fail( be != NULL, FALSE );
2669  g_return_val_if_fail( table_name != NULL, FALSE );
2670  g_return_val_if_fail( obj_name != NULL, FALSE );
2671  g_return_val_if_fail( pObject != NULL, FALSE );
2672  g_return_val_if_fail( table != NULL, FALSE );
2673 
2674  /* SELECT * FROM */
2675  sqlStmt = create_single_col_select_statement( be, table_name, table );
2676  g_assert( sqlStmt != NULL );
2677 
2678  /* WHERE */
2679  pHandler = get_handler( table );
2680  g_assert( pHandler != NULL );
2681  pHandler->add_gvalue_to_slist_fn( be, obj_name, pObject, table, &list );
2682  g_assert( list != NULL );
2683  gnc_sql_statement_add_where_cond( sqlStmt, obj_name, pObject, &table[0], (GValue*)(list->data) );
2684 
2685  count = execute_statement_get_count( be, sqlStmt );
2686  gnc_sql_statement_dispose( sqlStmt );
2687  if ( count == 0 )
2688  {
2689  return FALSE;
2690  }
2691  else
2692  {
2693  return TRUE;
2694  }
2695 }
2696 
2697 gboolean
2699  E_DB_OPERATION op,
2700  const gchar* table_name,
2701  QofIdTypeConst obj_name, gpointer pObject,
2702  const GncSqlColumnTableEntry* table )
2703 {
2704  GncSqlStatement* stmt = NULL;
2705  gboolean ok = FALSE;
2706 
2707  g_return_val_if_fail( be != NULL, FALSE );
2708  g_return_val_if_fail( table_name != NULL, FALSE );
2709  g_return_val_if_fail( obj_name != NULL, FALSE );
2710  g_return_val_if_fail( pObject != NULL, FALSE );
2711  g_return_val_if_fail( table != NULL, FALSE );
2712 
2713  if ( op == OP_DB_INSERT )
2714  {
2715  stmt = build_insert_statement( be, table_name, obj_name, pObject, table );
2716  }
2717  else if ( op == OP_DB_UPDATE )
2718  {
2719  stmt = build_update_statement( be, table_name, obj_name, pObject, table );
2720  }
2721  else if ( op == OP_DB_DELETE )
2722  {
2723  stmt = build_delete_statement( be, table_name, obj_name, pObject, table );
2724  }
2725  else
2726  {
2727  g_assert( FALSE );
2728  }
2729  if ( stmt != NULL )
2730  {
2731  gint result;
2732 
2733  result = gnc_sql_connection_execute_nonselect_statement( be->conn, stmt );
2734  if ( result == -1 )
2735  {
2736  PERR( "SQL error: %s\n", gnc_sql_statement_to_sql( stmt ) );
2738  }
2739  else
2740  {
2741  ok = TRUE;
2742  }
2743  gnc_sql_statement_dispose( stmt );
2744  }
2745 
2746  return ok;
2747 }
2748 
2749 static GSList*
2750 create_gslist_from_values( GncSqlBackend* be,
2751  QofIdTypeConst obj_name, gpointer pObject,
2752  const GncSqlColumnTableEntry* table )
2753 {
2754  GSList* list = NULL;
2755  GncSqlColumnTypeHandler* pHandler;
2756  const GncSqlColumnTableEntry* table_row;
2757 
2758  for ( table_row = table; table_row->col_name != NULL; table_row++ )
2759  {
2760  if (( table_row->flags & COL_AUTOINC ) == 0 )
2761  {
2762  pHandler = get_handler( table_row );
2763  g_assert( pHandler != NULL );
2764  pHandler->add_gvalue_to_slist_fn( be, obj_name, pObject, table_row, &list );
2765  }
2766  }
2767 
2768  g_assert( list != NULL );
2769  return list;
2770 }
2771 
2772 gchar*
2773 gnc_sql_get_sql_value( const GncSqlConnection* conn, const GValue* value )
2774 {
2775  if ( value != NULL && G_IS_VALUE( value ) )
2776  {
2777  GType type = G_VALUE_TYPE(value);
2778 
2779  if ( G_VALUE_HOLDS_STRING(value) )
2780  {
2781  if ( g_value_get_string( value ) != NULL )
2782  {
2783  gchar* before_str;
2784  gchar* after_str;
2785  before_str = g_value_dup_string( value );
2786  after_str = gnc_sql_connection_quote_string( conn, before_str );
2787  g_free( before_str );
2788  return after_str;
2789  }
2790  else
2791  {
2792  return g_strdup( "NULL" );
2793  }
2794  }
2795  else if ( type == G_TYPE_INT64 )
2796  {
2797  return g_strdup_printf( "%" G_GINT64_FORMAT, g_value_get_int64( value ) );
2798 
2799  }
2800  else if ( type == G_TYPE_INT )
2801  {
2802  return g_strdup_printf( "%d", g_value_get_int( value ) );
2803 
2804  }
2805  else if ( type == G_TYPE_DOUBLE )
2806  {
2807  gchar doublestr[G_ASCII_DTOSTR_BUF_SIZE];
2808  g_ascii_dtostr( doublestr, sizeof(doublestr),
2809  g_value_get_double( value ));
2810  return g_strdup( doublestr );
2811 
2812  }
2813  else if ( g_value_type_transformable( type, G_TYPE_STRING ) )
2814  {
2815  GValue* string;
2816  gchar* str;
2817 
2818  string = g_new0( GValue, 1 );
2819  g_assert( string != NULL );
2820  (void)g_value_init( string, G_TYPE_STRING );
2821  (void)g_value_transform( value, string );
2822  str = g_value_dup_string( string );
2823  g_value_unset( string );
2824  g_free( string );
2825  PWARN( "using g_value_transform(), gtype = '%s'\n", g_type_name( type ) );
2826  return str;
2827  }
2828  else
2829  {
2830  PWARN( "not transformable, gtype = '%s'\n", g_type_name( type ) );
2831  return g_strdup( "$$$" );
2832  }
2833  }
2834  else
2835  {
2836  PWARN( "value is NULL or not G_IS_VALUE()\n" );
2837  return g_strdup( "" );
2838  }
2839 }
2840 
2841 static void
2842 free_gvalue_list( GSList* list )
2843 {
2844  GSList* node;
2845  GValue* value;
2846 
2847  for ( node = list; node != NULL; node = node->next )
2848  {
2849  value = (GValue*)node->data;
2850 
2851  g_value_unset( value );
2852  g_free( value );
2853  }
2854  g_slist_free( list );
2855 }
2856 
2857 /*@ null @*/ static GncSqlStatement*
2858 build_insert_statement( GncSqlBackend* be,
2859  const gchar* table_name,
2860  QofIdTypeConst obj_name, gpointer pObject,
2861  const GncSqlColumnTableEntry* table )
2862 {
2863  GncSqlStatement* stmt;
2864  GString* sql;
2865  GSList* values;
2866  GSList* node;
2867  gchar* sqlbuf;
2868  GList* colnames = NULL;
2869  GList* colname;
2870  const GncSqlColumnTableEntry* table_row;
2871 
2872  g_return_val_if_fail( be != NULL, NULL );
2873  g_return_val_if_fail( table_name != NULL, NULL );
2874  g_return_val_if_fail( obj_name != NULL, NULL );
2875  g_return_val_if_fail( pObject != NULL, NULL );
2876  g_return_val_if_fail( table != NULL, NULL );
2877 
2878  sqlbuf = g_strdup_printf( "INSERT INTO %s(", table_name );
2879  sql = g_string_new( sqlbuf );
2880  g_free( sqlbuf );
2881 
2882  // Get all col names and all values
2883  for ( table_row = table; table_row->col_name != NULL; table_row++ )
2884  {
2885  if (( table_row->flags & COL_AUTOINC ) == 0 )
2886  {
2887  GncSqlColumnTypeHandler* pHandler;
2888 
2889  // Add col names to the list
2890  pHandler = get_handler( table_row );
2891  g_assert( pHandler != NULL );
2892  pHandler->add_colname_to_list_fn( table_row, &colnames );
2893  }
2894  }
2895  g_assert( colnames != NULL );
2896 
2897  for ( colname = colnames; colname != NULL; colname = colname->next )
2898  {
2899  if ( colname != colnames )
2900  {
2901  g_string_append( sql, "," );
2902  }
2903  g_string_append( sql, (gchar*)colname->data );
2904  g_free( colname->data );
2905  }
2906  g_list_free( colnames );
2907 
2908  g_string_append( sql, ") VALUES(" );
2909  values = create_gslist_from_values( be, obj_name, pObject, table );
2910  for ( node = values; node != NULL; node = node->next )
2911  {
2912  GValue* value = (GValue*)node->data;
2913  gchar* value_str;
2914  if ( node != values )
2915  {
2916  (void)g_string_append( sql, "," );
2917  }
2918  value_str = gnc_sql_get_sql_value( be->conn, value );
2919  (void)g_string_append( sql, value_str );
2920  g_free( value_str );
2921  (void)g_value_reset( value );
2922  }
2923  free_gvalue_list( values );
2924  (void)g_string_append( sql, ")" );
2925 
2926  stmt = gnc_sql_connection_create_statement_from_sql( be->conn, sql->str );
2927  (void)g_string_free( sql, TRUE );
2928 
2929  return stmt;
2930 }
2931 
2932 /*@ null @*/ static GncSqlStatement*
2933 build_update_statement( GncSqlBackend* be,
2934  const gchar* table_name,
2935  QofIdTypeConst obj_name, gpointer pObject,
2936  const GncSqlColumnTableEntry* table )
2937 {
2938  GncSqlStatement* stmt;
2939  GString* sql;
2940  GSList* values;
2941  GList* colnames = NULL;
2942  GSList* value;
2943  GList* colname;
2944  gboolean firstCol;
2945  const GncSqlColumnTableEntry* table_row;
2946  gchar* sqlbuf;
2947 
2948  g_return_val_if_fail( be != NULL, NULL );
2949  g_return_val_if_fail( table_name != NULL, NULL );
2950  g_return_val_if_fail( obj_name != NULL, NULL );
2951  g_return_val_if_fail( pObject != NULL, NULL );
2952  g_return_val_if_fail( table != NULL, NULL );
2953 
2954  // Get all col names and all values
2955  for ( table_row = table; table_row->col_name != NULL; table_row++ )
2956  {
2957  if (( table_row->flags & COL_AUTOINC ) == 0 )
2958  {
2959  GncSqlColumnTypeHandler* pHandler;
2960 
2961  // Add col names to the list
2962  pHandler = get_handler( table_row );
2963  g_assert( pHandler != NULL );
2964  pHandler->add_colname_to_list_fn( table_row, &colnames );
2965  }
2966  }
2967  g_assert( colnames != NULL );
2968  values = create_gslist_from_values( be, obj_name, pObject, table );
2969 
2970  // Create the SQL statement
2971  sqlbuf = g_strdup_printf( "UPDATE %s SET ", table_name );
2972  sql = g_string_new( sqlbuf );
2973  g_free( sqlbuf );
2974 
2975  firstCol = TRUE;
2976  for ( colname = colnames->next, value = values->next;
2977  colname != NULL && value != NULL;
2978  colname = colname->next, value = value->next )
2979  {
2980  gchar* value_str;
2981  if ( !firstCol )
2982  {
2983  (void)g_string_append( sql, "," );
2984  }
2985  (void)g_string_append( sql, (gchar*)colname->data );
2986  (void)g_string_append( sql, "=" );
2987  value_str = gnc_sql_get_sql_value( be->conn, (GValue*)(value->data) );
2988  (void)g_string_append( sql, value_str );
2989  g_free( value_str );
2990  firstCol = FALSE;
2991  }
2992  for ( colname = colnames; colname != NULL; colname = colname->next )
2993  {
2994  g_free( colname->data );
2995  }
2996  g_list_free( colnames );
2997  if ( value != NULL || colname != NULL )
2998  {
2999  PERR( "Mismatch in number of column names and values" );
3000  }
3001 
3002  stmt = gnc_sql_connection_create_statement_from_sql( be->conn, sql->str );
3003  gnc_sql_statement_add_where_cond( stmt, obj_name, pObject, &table[0], (GValue*)(values->data) );
3004  free_gvalue_list( values );
3005  (void)g_string_free( sql, TRUE );
3006 
3007  return stmt;
3008 }
3009 
3010 /*@ null @*/ static GncSqlStatement*
3011 build_delete_statement( GncSqlBackend* be,
3012  const gchar* table_name,
3013  QofIdTypeConst obj_name, gpointer pObject,
3014  const GncSqlColumnTableEntry* table )
3015 {
3016  GncSqlStatement* stmt;
3017  GncSqlColumnTypeHandler* pHandler;
3018  GSList* list = NULL;
3019  gchar* sqlbuf;
3020 
3021  g_return_val_if_fail( be != NULL, NULL );
3022  g_return_val_if_fail( table_name != NULL, NULL );
3023  g_return_val_if_fail( obj_name != NULL, NULL );
3024  g_return_val_if_fail( pObject != NULL, NULL );
3025  g_return_val_if_fail( table != NULL, NULL );
3026 
3027  sqlbuf = g_strdup_printf( "DELETE FROM %s ", table_name );
3028  stmt = gnc_sql_connection_create_statement_from_sql( be->conn, sqlbuf );
3029  g_free( sqlbuf );
3030 
3031  /* WHERE */
3032  pHandler = get_handler( table );
3033  g_assert( pHandler != NULL );
3034  pHandler->add_gvalue_to_slist_fn( be, obj_name, pObject, table, &list );
3035  g_assert( list != NULL );
3036  gnc_sql_statement_add_where_cond( stmt, obj_name, pObject, &table[0], (GValue*)(list->data) );
3037  free_gvalue_list( list );
3038 
3039  return stmt;
3040 }
3041 
3042 /* ================================================================= */
3043 gboolean
3044 gnc_sql_commit_standard_item( GncSqlBackend* be, QofInstance* inst, const gchar* tableName,
3045  QofIdTypeConst obj_name, const GncSqlColumnTableEntry* col_table )
3046 {
3047  const GncGUID* guid;
3048  gboolean is_infant;
3049  gint op;
3050  gboolean is_ok;
3051 
3052  is_infant = qof_instance_get_infant( inst );
3053  if ( qof_instance_get_destroying( inst ) )
3054  {
3055  op = OP_DB_DELETE;
3056  }
3057  else if ( be->is_pristine_db || is_infant )
3058  {
3059  op = OP_DB_INSERT;
3060  }
3061  else
3062  {
3063  op = OP_DB_UPDATE;
3064  }
3065  is_ok = gnc_sql_do_db_operation( be, op, tableName, obj_name, inst, col_table );
3066 
3067  if ( is_ok )
3068  {
3069  // Now, commit any slots
3070  guid = qof_instance_get_guid( inst );
3071  if ( !qof_instance_get_destroying(inst) )
3072  {
3073  is_ok = gnc_sql_slots_save( be, guid, is_infant, qof_instance_get_slots( inst ) );
3074  }
3075  else
3076  {
3077  is_ok = gnc_sql_slots_delete( be, guid );
3078  }
3079  }
3080 
3081  return is_ok;
3082 }
3083 
3084 /* ================================================================= */
3085 
3086 static gboolean
3087 do_create_table( const GncSqlBackend* be, const gchar* table_name,
3088  const GncSqlColumnTableEntry* col_table )
3089 {
3090  GList* col_info_list = NULL;
3091  gboolean ok = FALSE;
3092 
3093  g_return_val_if_fail( be != NULL, FALSE );
3094  g_return_val_if_fail( table_name != NULL, FALSE );
3095  g_return_val_if_fail( col_table != NULL, FALSE );
3096 
3097  for ( ; col_table->col_name != NULL; col_table++ )
3098  {
3099  GncSqlColumnTypeHandler* pHandler;
3100 
3101  pHandler = get_handler( col_table );
3102  g_assert( pHandler != NULL );
3103  pHandler->add_col_info_to_list_fn( be, col_table, &col_info_list );
3104  }
3105  g_assert( col_info_list != NULL );
3106  ok = gnc_sql_connection_create_table( be->conn, table_name, col_info_list );
3107  return ok;
3108 }
3109 
3110 gboolean
3111 gnc_sql_create_table( GncSqlBackend* be, const gchar* table_name,
3112  gint table_version, const GncSqlColumnTableEntry* col_table )
3113 {
3114  gboolean ok;
3115 
3116  g_return_val_if_fail( be != NULL, FALSE );
3117  g_return_val_if_fail( table_name != NULL, FALSE );
3118  g_return_val_if_fail( col_table != NULL, FALSE );
3119 
3120  DEBUG( "Creating %s table\n", table_name );
3121 
3122  ok = do_create_table( be, table_name, col_table );
3123  if ( ok )
3124  {
3125  ok = gnc_sql_set_table_version( be, table_name, table_version );
3126  }
3127  return ok;
3128 }
3129 
3130 gboolean
3131 gnc_sql_create_temp_table( const GncSqlBackend* be, const gchar* table_name,
3132  const GncSqlColumnTableEntry* col_table )
3133 {
3134  g_return_val_if_fail( be != NULL, FALSE );
3135  g_return_val_if_fail( table_name != NULL, FALSE );
3136  g_return_val_if_fail( col_table != NULL, FALSE );
3137 
3138  return do_create_table( be, table_name, col_table );
3139 }
3140 
3141 gboolean
3142 gnc_sql_create_index( const GncSqlBackend* be, const gchar* index_name,
3143  const gchar* table_name,
3144  const GncSqlColumnTableEntry* col_table )
3145 {
3146  gboolean ok;
3147 
3148  g_return_val_if_fail( be != NULL, FALSE );
3149  g_return_val_if_fail( index_name != NULL, FALSE );
3150  g_return_val_if_fail( table_name != NULL, FALSE );
3151  g_return_val_if_fail( col_table != NULL, FALSE );
3152 
3153  ok = gnc_sql_connection_create_index( be->conn, index_name, table_name,
3154  col_table );
3155  return ok;
3156 }
3157 
3158 gint
3159 gnc_sql_get_table_version( const GncSqlBackend* be, const gchar* table_name )
3160 {
3161  g_return_val_if_fail( be != NULL, 0 );
3162  g_return_val_if_fail( table_name != NULL, 0 );
3163 
3164  /* If the db is pristine because it's being saved, the table does not exist. */
3165  if ( be->is_pristine_db )
3166  {
3167  return 0;
3168  }
3169 
3170  return GPOINTER_TO_INT(g_hash_table_lookup( be->versions, table_name ));
3171 }
3172 
3173 /* Create a temporary table, copy the data from the old table, delete the
3174  old table, then rename the new one. */
3175 void
3176 gnc_sql_upgrade_table( GncSqlBackend* be, const gchar* table_name,
3177  const GncSqlColumnTableEntry* col_table )
3178 {
3179  gchar* sql;
3180  gchar* temp_table_name;
3181 
3182  g_return_if_fail( be != NULL );
3183  g_return_if_fail( table_name != NULL );
3184  g_return_if_fail( col_table != NULL );
3185 
3186  DEBUG( "Upgrading %s table\n", table_name );
3187 
3188  temp_table_name = g_strdup_printf( "%s_new", table_name );
3189  (void)gnc_sql_create_temp_table( be, temp_table_name, col_table );
3190  sql = g_strdup_printf( "INSERT INTO %s SELECT * FROM %s",
3191  temp_table_name, table_name );
3192  (void)gnc_sql_execute_nonselect_sql( be, sql );
3193  g_free( sql );
3194 
3195  sql = g_strdup_printf( "DROP TABLE %s", table_name );
3196  (void)gnc_sql_execute_nonselect_sql( be, sql );
3197  g_free( sql );
3198 
3199  sql = g_strdup_printf( "ALTER TABLE %s RENAME TO %s", temp_table_name, table_name );
3200  (void)gnc_sql_execute_nonselect_sql( be, sql );
3201  g_free( sql );
3202  g_free( temp_table_name );
3203 }
3204 
3205 /* Adds one or more columns to an existing table. */
3206 gboolean gnc_sql_add_columns_to_table( GncSqlBackend* be, const gchar* table_name,
3207  const GncSqlColumnTableEntry* new_col_table )
3208 {
3209  GList* col_info_list = NULL;
3210  gboolean ok = FALSE;
3211 
3212  g_return_val_if_fail( be != NULL, FALSE );
3213  g_return_val_if_fail( table_name != NULL, FALSE );
3214  g_return_val_if_fail( new_col_table != NULL, FALSE );
3215 
3216  for ( ; new_col_table->col_name != NULL; new_col_table++ )
3217  {
3218  GncSqlColumnTypeHandler* pHandler;
3219 
3220  pHandler = get_handler( new_col_table );
3221  g_assert( pHandler != NULL );
3222  pHandler->add_col_info_to_list_fn( be, new_col_table, &col_info_list );
3223  }
3224  g_assert( col_info_list != NULL );
3225  ok = gnc_sql_connection_add_columns_to_table( be->conn, table_name, col_info_list );
3226  return ok;
3227 }
3228 
3229 /* ================================================================= */
3230 #define VERSION_TABLE_NAME "versions"
3231 #define MAX_TABLE_NAME_LEN 50
3232 #define TABLE_COL_NAME "table_name"
3233 #define VERSION_COL_NAME "table_version"
3234 
3235 static GncSqlColumnTableEntry version_table[] =
3236 {
3237  /*@ -full_init_block @*/
3238  { TABLE_COL_NAME, CT_STRING, MAX_TABLE_NAME_LEN, COL_PKEY | COL_NNUL },
3239  { VERSION_COL_NAME, CT_INT, 0, COL_NNUL },
3240  { NULL }
3241  /*@ +full_init_block @*/
3242 };
3243 
3250 void
3252 {
3253  g_return_if_fail( be != NULL );
3254 
3255  if ( be->versions != NULL )
3256  {
3257  g_hash_table_destroy( be->versions );
3258  }
3259  be->versions = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, NULL );
3260 
3261  if ( gnc_sql_connection_does_table_exist( be->conn, VERSION_TABLE_NAME ) )
3262  {
3263  GncSqlResult* result;
3264  gchar* sql;
3265 
3266  sql = g_strdup_printf( "SELECT * FROM %s", VERSION_TABLE_NAME );
3267  result = gnc_sql_execute_select_sql( be, sql );
3268  g_free( sql );
3269  if ( result != NULL )
3270  {
3271  const GValue* name;
3272  const GValue* version;
3273  GncSqlRow* row;
3274 
3275  row = gnc_sql_result_get_first_row( result );
3276  while ( row != NULL )
3277  {
3278  name = gnc_sql_row_get_value_at_col_name( row, TABLE_COL_NAME );
3279  version = gnc_sql_row_get_value_at_col_name( row, VERSION_COL_NAME );
3280  g_hash_table_insert( be->versions,
3281  g_strdup( g_value_get_string( name ) ),
3282  GINT_TO_POINTER((gint)g_value_get_int64( version )) );
3283  row = gnc_sql_result_get_next_row( result );
3284  }
3285  gnc_sql_result_dispose( result );
3286  }
3287  }
3288  else
3289  {
3290  do_create_table( be, VERSION_TABLE_NAME, version_table );
3291  gnc_sql_set_table_version( be, "Gnucash",
3292  gnc_prefs_get_long_version() );
3293  gnc_sql_set_table_version( be, "Gnucash-Resave",
3294  GNUCASH_RESAVE_VERSION );
3295  }
3296 }
3297 
3305 static gboolean
3306 reset_version_info( GncSqlBackend* be )
3307 {
3308  gboolean ok;
3309 
3310  g_return_val_if_fail( be != NULL, FALSE );
3311 
3312  ok = do_create_table( be, VERSION_TABLE_NAME, version_table );
3313  if ( be->versions == NULL )
3314  {
3315  be->versions = g_hash_table_new_full( g_str_hash, g_str_equal, g_free, NULL );
3316  }
3317  else
3318  {
3319  g_hash_table_remove_all( be->versions );
3320  }
3321 
3322  gnc_sql_set_table_version( be, "Gnucash", gnc_prefs_get_long_version() );
3323  gnc_sql_set_table_version( be, "Gnucash-Resave", GNUCASH_RESAVE_VERSION );
3324  return ok;
3325 }
3326 
3332 void
3334 {
3335  g_return_if_fail( be != NULL );
3336 
3337  if ( be->versions != NULL )
3338  {
3339  g_hash_table_destroy( be->versions );
3340  be->versions = NULL;
3341  }
3342 }
3343 
3353 gboolean
3354 gnc_sql_set_table_version( GncSqlBackend* be, const gchar* table_name, gint version )
3355 {
3356  gchar* sql;
3357  gint cur_version;
3358  gint status;
3359 
3360  g_return_val_if_fail( be != NULL, FALSE );
3361  g_return_val_if_fail( table_name != NULL, FALSE );
3362  g_return_val_if_fail( version > 0, FALSE );
3363 
3364  cur_version = gnc_sql_get_table_version( be, table_name );
3365  if ( cur_version != version )
3366  {
3367  if ( cur_version == 0 )
3368  {
3369  sql = g_strdup_printf( "INSERT INTO %s VALUES('%s',%d)", VERSION_TABLE_NAME,
3370  table_name, version );
3371  }
3372  else
3373  {
3374  sql = g_strdup_printf( "UPDATE %s SET %s=%d WHERE %s='%s'", VERSION_TABLE_NAME,
3375  VERSION_COL_NAME, version,
3376  TABLE_COL_NAME, table_name );
3377  }
3378  status = gnc_sql_execute_nonselect_sql( be, sql );
3379  if ( status == -1 )
3380  {
3381  PERR( "SQL error: %s\n", sql );
3383  }
3384  g_free( sql );
3385  }
3386 
3387  g_hash_table_insert( be->versions, g_strdup( table_name ), GINT_TO_POINTER(version) );
3388 
3389  return TRUE;
3390 }
3391 
3392 /* ========================== END OF FILE ===================== */
gboolean(* commit)(GncSqlBackend *be, QofInstance *inst)
const gchar * qof_param_name
int xaccAccountTreeForEachTransaction(Account *acc, TransactionCallback proc, void *data)
QofIdType e_type
Definition: qofinstance.h:69
gboolean gnc_sql_object_is_it_in_db(GncSqlBackend *be, const gchar *table_name, QofIdTypeConst obj_name, gpointer pObject, const GncSqlColumnTableEntry *table)
load and save vendor data to SQL
gchar * gnc_timespec_to_iso8601_buff(Timespec ts, gchar *buff)
void gnc_sql_begin_edit(GncSqlBackend *be, QofInstance *inst)
void gnc_sql_finalize_version_info(GncSqlBackend *be)
void qof_backend_set_error(QofBackend *be, QofBackendError err)
time64 timespecToTime64(Timespec ts)
const GncGUID * qof_instance_get_guid(gconstpointer)
gint gnc_sql_get_table_version(const GncSqlBackend *be, const gchar *table_name)
gboolean loading
GHashTable * versions
gint gnc_account_n_descendants(const Account *account)
Definition: Account.c:2698
GNC_SQL_ADD_GVALUE_TO_SLIST_FN add_gvalue_to_slist_fn
gboolean(* write)(GncSqlBackend *be)
QofAccessFunc gnc_sql_get_getter(QofIdTypeConst obj_name, const GncSqlColumnTableEntry *table_row)
void gnc_sql_rollback_edit(GncSqlBackend *be, QofInstance *inst)
void gnc_account_foreach_descendant(const Account *acc, AccountCb thunk, gpointer user_data)
Definition: Account.c:2958
#define COL_AUTOINC
void gnc_sql_upgrade_table(GncSqlBackend *be, const gchar *table_name, const GncSqlColumnTableEntry *col_table)
const GncGUID * gnc_sql_load_tx_guid(const GncSqlBackend *be, GncSqlRow *row)
a simple price database for gnucash
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
load and save data to SQL
void gnc_sql_add_colname_to_list(const GncSqlColumnTableEntry *table_row, GList **pList)
void gnc_sql_init(GncSqlBackend *be)
const gchar * QofIdTypeConst
Definition: qofid.h:87
load and save accounts data to SQL
GncSqlStatement * gnc_sql_create_select_statement(GncSqlBackend *be, const gchar *table_name)
#define COL_NNUL
#define DEBUG(format, args...)
Definition: qoflog.h:255
gboolean qof_instance_get_destroying(gconstpointer ptr)
gboolean string_to_guid(const gchar *string, GncGUID *guid)
gint gnc_sql_execute_nonselect_sql(GncSqlBackend *be, const gchar *sql)
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)
Use a 64-bit unsigned int timespec.
Definition: gnc-date.h:299
load and save customer data to SQL
Account * gnc_book_get_template_root(const QofBook *book)
Definition: SX-book.c:65
GncSqlConnection * conn
gboolean gnc_sql_add_columns_to_table(GncSqlBackend *be, const gchar *table_name, const GncSqlColumnTableEntry *new_col_table)
QofBackend be
void gnc_sql_add_objectref_guid_col_info_to_list(const GncSqlBackend *be, const GncSqlColumnTableEntry *table_row, GList **pList)
gboolean in_query
gchar * guid_to_string_buff(const GncGUID *guid, gchar *buff)
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
Definition: qofclass.h:177
gboolean gnc_sql_save_transaction(GncSqlBackend *be, QofInstance *inst)
load and save accounts data to SQL
load and save data to SQL
#define PERR(format, args...)
Definition: qoflog.h:237
#define ENTER(format, args...)
Definition: qoflog.h:261
QofAccessFunc qof_class_get_parameter_getter(QofIdTypeConst obj_name, const char *parameter)
struct _QofQuery QofQuery
Definition: qofquery.h:90
gint64 gnc_sql_get_integer_value(const GValue *value)
QofBook * book
Definition: guid.h:65
#define COL_PKEY
gboolean gnc_sql_create_index(const GncSqlBackend *be, const gchar *index_name, const gchar *table_name, const GncSqlColumnTableEntry *col_table)
void(* run_query)(GncSqlBackend *be, gpointer pQuery)
void gnc_tm_free(struct tm *time)
free a struct tm* created with gnc_localtime() or gnc_gmtime()
#define PWARN(format, args...)
Definition: qoflog.h:243
const GncGUID * gnc_sql_load_guid(const GncSqlBackend *be, GncSqlRow *row)
const gchar * QofIdType
Definition: qofid.h:85
GncSqlBasicColumnType type
void gnc_sql_set_load_order(const gchar **load_order)
load and save accounts data to SQL
load and save order data to SQL
Account handling public routines.
void(* initial_load)(GncSqlBackend *be)
guint gnc_sql_append_guid_list_to_sql(GString *sql, GList *list, guint maxCount)
gboolean gnc_sql_set_table_version(GncSqlBackend *be, const gchar *table_name, gint version)
load and save owner data to SQL
void qof_book_mark_session_saved(QofBook *book)
load and save job data to SQL
load and save accounts data to SQL
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
load and save data to SQL
gboolean qof_instance_get_dirty_flag(gconstpointer ptr)
Anchor Scheduled Transaction info in a book. See src/doc/books.txt for design overview.
load and save employee data to SQL
load and save data to SQL
Tax Table programming interface.
gchar * gnc_sql_get_sql_value(const GncSqlConnection *conn, const GValue *value)
GNC_SQL_ADD_COL_INFO_TO_LIST_FN add_col_info_to_list_fn
GncSqlResult * gnc_sql_execute_select_statement(GncSqlBackend *be, GncSqlStatement *stmt)
Timespec gnc_iso8601_to_timespec_gmt(const gchar *)
All type declarations for the whole Gnucash engine.
void gnc_sql_load_object(const GncSqlBackend *be, GncSqlRow *row, QofIdTypeConst obj_name, gpointer pObject, const GncSqlColumnTableEntry *table)
const gchar * gobj_param_name
struct _gnc_numeric gnc_numeric
An rational-number type.
Definition: gnc-numeric.h:68
void gnc_sql_push_commodity_for_postload_processing(GncSqlBackend *be, gpointer *comm)
GNC_SQL_ADD_COLNAME_TO_LIST_FN add_colname_to_list_fn
gboolean gnc_sql_create_temp_table(const GncSqlBackend *be, const gchar *table_name, const GncSqlColumnTableEntry *col_table)
GncSqlBasicColumnType
load and save data to SQL
void gnc_sql_transaction_load_all_tx(GncSqlBackend *be)
Generic api to store and retrieve preferences.
void gnc_sql_commit_edit(GncSqlBackend *be, QofInstance *inst)
GList * gnc_account_get_descendants(const Account *account)
Definition: Account.c:2755
API for the transaction logger.
Business Invoice Interface.
guint gnc_book_count_transactions(QofBook *book)
Definition: Transaction.c:2483
gboolean gnc_sql_slots_delete(GncSqlBackend *be, const GncGUID *guid)
gboolean qof_book_is_readonly(const QofBook *book)
load and save address data to SQL
void gnc_sql_sync_all(GncSqlBackend *be, QofBook *book)
void(* free_query)(GncSqlBackend *be, gpointer pQuery)
void qof_event_suspend(void)
Suspend all engine events.
void xaccAccountBeginEdit(Account *acc)
Definition: Account.c:1280
QofIdType qof_query_get_search_for(const QofQuery *q)
void qof_event_resume(void)
load and save entry data to SQL
const gchar * type_name
gboolean gnc_sql_commit_standard_item(GncSqlBackend *be, QofInstance *inst, const gchar *tableName, QofIdTypeConst obj_name, const GncSqlColumnTableEntry *col_table)
#define LEAVE(format, args...)
Definition: qoflog.h:271
gboolean is_pristine_db
void(* QofSetterFunc)(gpointer, gpointer)
Definition: qofclass.h:184
struct tm * gnc_gmtime(const time64 *secs)
fill out a time struct from a 64-bit time value
gpointer(* compile_query)(GncSqlBackend *be, QofQuery *pQuery)
int qof_query_has_terms(QofQuery *q)
gboolean gnc_sql_do_db_operation(GncSqlBackend *be, E_DB_OPERATION op, const gchar *table_name, QofIdTypeConst obj_name, gpointer pObject, const GncSqlColumnTableEntry *table)
GncSqlStatement * gnc_sql_create_statement_from_sql(GncSqlBackend *be, const gchar *sql)
gint64 time64
Definition: gnc-date.h:83
void(* create_tables)(GncSqlBackend *be)
const gchar * timespec_format
load and save data to SQL
load and save invoice data to SQL
QofSetterFunc qof_class_get_parameter_setter(QofIdTypeConst obj_name, const char *parameter)
void xaccAccountCommitEdit(Account *acc)
Definition: Account.c:1321
void gnc_sql_init_version_info(GncSqlBackend *be)
struct timespec64 Timespec
Definition: gnc-date.h:93
void gnc_sql_add_subtable_colnames_to_list(const GncSqlColumnTableEntry *table_row, const GncSqlColumnTableEntry *subtable, GList **pList)
void gnc_sql_load(GncSqlBackend *be, QofBook *book, QofBackendLoadType loadType)
Billing Term interface.
gboolean gnc_sql_slots_save(GncSqlBackend *be, const GncGUID *guid, gboolean is_infant, KvpFrame *pFrame)
GncSqlResult * gnc_sql_execute_select_sql(GncSqlBackend *be, const gchar *sql)
const gchar * QofLogModule
Definition: qofid.h:89
load and save tax table data to SQL
void timespecFromTime64(Timespec *ts, time64 t)
gchar * gnc_sql_convert_timespec_to_string(const GncSqlBackend *be, Timespec ts)