static void test_load_file(const char *filename) { QofSession *session; QofBook *book; Account *root; gboolean ignore_lock; gchar *logdomain = "GConf"; guint loglevel = G_LOG_LEVEL_WARNING; TestErrorStruct check = { loglevel, logdomain, NULL }; g_log_set_handler (logdomain, loglevel, (GLogFunc)test_checked_handler, &check); session = qof_session_new(); remove_locks(filename); ignore_lock = (safe_strcmp(g_getenv("SRCDIR"), ".") != 0); qof_session_begin(session, filename, ignore_lock, FALSE, TRUE); qof_session_load(session, NULL); book = qof_session_get_book (session); root = gnc_book_get_root_account(book); do_test (gnc_account_get_book (root) == book, "book and root account don't match"); do_test_args(qof_session_get_error(session) == ERR_BACKEND_NO_ERR, "session load xml2", __FILE__, __LINE__, "qof error=%d for file [%s]", qof_session_get_error(session), filename); /* Uncomment the line below to generate corrected files */ qof_session_save( session, NULL ); qof_session_end(session); }
/* Given a synthetic session, use the same logic as * QofSession::save_as to save it to a specified sql url, then load it * back and compare. */ void test_dbi_store_and_reload( const gchar* driver, QofSession* session_1, const gchar* url ) { QofSession* session_2; QofSession* session_3; gchar *msg = "[gnc_dbi_unlock()] There was no lock entry in the Lock table"; gchar *log_domain = "gnc.backend.dbi"; guint loglevel = G_LOG_LEVEL_WARNING, hdlr; TestErrorStruct check = { loglevel, log_domain, msg }; g_test_message ( "Testing %s\n", driver ); // Save the session data session_2 = qof_session_new(); hdlr = g_log_set_handler (log_domain, loglevel, (GLogFunc)test_checked_handler, &check); qof_session_begin( session_2, url, FALSE, TRUE, TRUE ); if (session_2 && qof_session_get_error(session_2) != ERR_BACKEND_NO_ERR) { g_warning("Session Error: %d, %s", qof_session_get_error(session_2), qof_session_get_error_message(session_2)); do_test( FALSE, "First DB Session Creation Failed"); return; } qof_session_swap_data( session_1, session_2 ); qof_session_save( session_2, NULL ); if (session_2 && qof_session_get_error(session_2) != ERR_BACKEND_NO_ERR) { g_warning("Session Error: %s", qof_session_get_error_message(session_2)); do_test( FALSE, "First DB Session Save Failed"); return; } // Reload the session data session_3 = qof_session_new(); qof_session_begin( session_3, url, TRUE, FALSE, FALSE ); if (session_3 && qof_session_get_error(session_3) != ERR_BACKEND_NO_ERR) { g_warning("Session Error: %s", qof_session_get_error_message(session_3)); do_test( FALSE, "Second DB Session Creation Failed"); return; } qof_session_load( session_3, NULL ); if (session_3 && qof_session_get_error(session_3) != ERR_BACKEND_NO_ERR) { g_warning("Session Error: %s", qof_session_get_error_message(session_3)); do_test( FALSE, "Second DBI Session Load Failed"); return; } // Compare with the original data compare_books( qof_session_get_book( session_2 ), qof_session_get_book( session_3 ) ); qof_session_end( session_1 ); qof_session_destroy( session_1 ); qof_session_end( session_2 ); qof_session_destroy( session_2 ); qof_session_end( session_3 ); qof_session_destroy( session_3 ); g_log_remove_handler (log_domain, hdlr); }
static void inner_main_add_price_quotes(void *closure, int argc, char **argv) { SCM mod, add_quotes, scm_book, scm_result = SCM_BOOL_F; QofSession *session = NULL; scm_c_eval_string("(debug-set! stack 200000)"); mod = scm_c_resolve_module("gnucash price-quotes"); scm_set_current_module(mod); load_gnucash_modules(); qof_event_suspend(); scm_c_eval_string("(gnc:price-quotes-install-sources)"); if (!gnc_quote_source_fq_installed()) { g_print("%s", _("No quotes retrieved. Finance::Quote isn't " "installed properly.\n")); goto fail; } add_quotes = scm_c_eval_string("gnc:book-add-quotes"); session = gnc_get_current_session(); if (!session) goto fail; qof_session_begin(session, add_quotes_file, FALSE, FALSE); if (qof_session_get_error(session) != ERR_BACKEND_NO_ERR) goto fail; qof_session_load(session, NULL); if (qof_session_get_error(session) != ERR_BACKEND_NO_ERR) goto fail; scm_book = gnc_book_to_scm(qof_session_get_book(session)); scm_result = scm_call_2(add_quotes, SCM_BOOL_F, scm_book); qof_session_save(session, NULL); if (qof_session_get_error(session) != ERR_BACKEND_NO_ERR) goto fail; qof_session_destroy(session); if (!scm_is_true(scm_result)) { g_warning("Failed to add quotes to %s.", add_quotes_file); goto fail; } qof_event_resume(); gnc_shutdown(0); return; fail: if (session && qof_session_get_error(session) != ERR_BACKEND_NO_ERR) g_warning("Session Error: %s", qof_session_get_error_message(session)); qof_event_resume(); gnc_shutdown(1); }
/* Given an already-created url (yeah, bad testing practice: Should * start fresh from a synthetic session) load and safe-save it, then * load it again into a new session and compare the two. Since * safe-save is a more-or-less atomic function call, there's no way to * be sure that it's actually doing what it's supposed to without * running this test in a debugger and stopping in the middle of the * safe-save and inspecting the database. */ void test_dbi_safe_save( const gchar* driver, const gchar* url ) { QofSession *session_1 = NULL, *session_2 = NULL; printf( "Testing safe save %s\n", driver ); // Load the session data session_1 = qof_session_new(); qof_session_begin( session_1, url, TRUE, FALSE, FALSE ); if (session_1 && qof_session_get_error(session_1) != ERR_BACKEND_NO_ERR) { g_warning("Session Error: %d, %s", qof_session_get_error(session_1), qof_session_get_error_message(session_1)); do_test( FALSE, "DB Session Creation Failed"); goto cleanup; } qof_session_load( session_1, NULL ); /* Do a safe save */ qof_session_safe_save( session_1, NULL ); if (session_1 && qof_session_get_error(session_1) != ERR_BACKEND_NO_ERR) { g_warning("Session Error: %s", qof_session_get_error_message(session_1)); do_test( FALSE, "DB Session Safe Save Failed"); goto cleanup; } /* Destroy the session and reload it */ session_2 = qof_session_new(); qof_session_begin( session_2, url, TRUE, FALSE, FALSE ); if (session_2 && qof_session_get_error(session_2) != ERR_BACKEND_NO_ERR) { g_warning("Session Error: %d, %s", qof_session_get_error(session_2), qof_session_get_error_message(session_2)); do_test( FALSE, "DB Session re-creation Failed"); goto cleanup; } qof_session_load( session_2, NULL ); compare_books( qof_session_get_book( session_1 ), qof_session_get_book( session_2 ) ); cleanup: if (session_2 != NULL) { qof_session_end( session_2 ); qof_session_destroy( session_2 ); } if (session_1 != NULL) { qof_session_end( session_1 ); qof_session_destroy( session_1 ); } return; }
/* Given a synthetic session, use the same logic as * QofSession::save_as to save it to a specified sql url, then load it * back and compare. */ void test_dbi_store_and_reload( const gchar* driver, QofSession* session_1, const gchar* url ) { QofSession* session_2; QofSession* session_3; printf( "Testing %s\n", driver ); // Save the session data session_2 = qof_session_new(); qof_session_begin( session_2, url, FALSE, TRUE, TRUE ); if (session_2 && qof_session_get_error(session_2) != ERR_BACKEND_NO_ERR) { g_warning("Session Error: %d, %s", qof_session_get_error(session_2), qof_session_get_error_message(session_2)); do_test( FALSE, "First DB Session Creation Failed"); return; } qof_session_swap_data( session_1, session_2 ); qof_session_save( session_2, NULL ); if (session_2 && qof_session_get_error(session_2) != ERR_BACKEND_NO_ERR) { g_warning("Session Error: %s", qof_session_get_error_message(session_2)); do_test( FALSE, "First DB Session Save Failed"); return; } // Reload the session data session_3 = qof_session_new(); qof_session_begin( session_3, url, TRUE, FALSE, FALSE ); if (session_3 && qof_session_get_error(session_3) != ERR_BACKEND_NO_ERR) { g_warning("Session Error: %s", qof_session_get_error_message(session_3)); do_test( FALSE, "Second DB Session Creation Failed"); return; } qof_session_load( session_3, NULL ); if (session_3 && qof_session_get_error(session_3) != ERR_BACKEND_NO_ERR) { g_warning("Session Error: %s", qof_session_get_error_message(session_3)); do_test( FALSE, "Second DBI Session Load Failed"); return; } // Compare with the original data compare_books( qof_session_get_book( session_2 ), qof_session_get_book( session_3 ) ); qof_session_end( session_1 ); qof_session_destroy( session_1 ); qof_session_end( session_2 ); qof_session_destroy( session_2 ); g_print(" You may ignore the warning about the lock file having no entries: We had to ignore locking to run two sessions on the same database\n"); qof_session_end( session_3 ); qof_session_destroy( session_3 ); }
static void gnc_plugin_business_cmd_export_employee (GtkAction *action, GncMainWindowActionData *mw) { QofSession *current_session, *chart_session; QofBook *book; QofCollection *coll; gchar *filename; gboolean success; current_session = gnc_get_current_session(); book = qof_session_get_book(current_session); chart_session = qof_session_new(); success = FALSE; filename = gnc_file_dialog(_("Export Employees to XML"), NULL, NULL, GNC_FILE_DIALOG_EXPORT); if (filename) { gchar* url = g_strdup_printf( "qsf:%s", filename ); qof_session_begin(chart_session, url, TRUE, TRUE); coll = qof_book_get_collection(book, GNC_ID_EMPLOYEE); success = qof_instance_copy_coll_r(chart_session, coll); if (success) { qof_session_save(chart_session, NULL); } g_free(url); } show_session_error(qof_session_get_error(chart_session), filename, GNC_FILE_DIALOG_EXPORT); qof_session_end(chart_session); g_free(filename); gnc_set_current_session(current_session); }
void qof_session_save (QofSession *session, QofPercentageFunc percentage_func) { QofBackend *be; if (!session) return; if (!g_atomic_int_dec_and_test(&session->lock)) goto leave; ENTER ("sess=%p book_id=%s", session, session->book_id ? session->book_id : "(null)"); /* If there is a backend, and the backend is reachable * (i.e. we can communicate with it), then synchronize with * the backend. If we cannot contact the backend (e.g. * because we've gone offline, the network has crashed, etc.) * then give the user the option to save to the local disk. * * hack alert -- FIXME -- XXX the code below no longer * does what the words above say. This needs fixing. */ be = session->backend; if (be) { /* if invoked as SaveAs(), then backend not yet set */ qof_book_set_backend (session->book, be); be->percentage = percentage_func; if (be->sync) { (be->sync)(be, session->book); if (save_error_handler(be, session)) goto leave; } /* If we got to here, then the backend saved everything * just fine, and we are done. So return. */ /* Return the book_id to previous value. */ qof_session_clear_error (session); LEAVE("Success"); goto leave; } else { if (ERR_BACKEND_NO_ERR != qof_session_get_error(session)) { /* push_error strdups, stack const is fine. */ const char *msg = "failed to load backend"; qof_session_push_error(session, ERR_BACKEND_NO_HANDLER, msg); } } LEAVE("error -- No backend!"); leave: g_atomic_int_inc(&session->lock); return; }
QofBackendError qof_session_pop_error (QofSession * session) { QofBackendError err; if (!session) return ERR_BACKEND_NO_BACKEND; err = qof_session_get_error(session); qof_session_clear_error(session); return err; }
static gboolean gxi_save_file (GncXmlImportData *data) { QofBackendError io_err; g_return_val_if_fail (data && data->session, FALSE); gxi_update_progress_bar (_("Writing file..."), 0.0); qof_session_save (data->session, gxi_update_progress_bar); gxi_update_progress_bar (NULL, -1.0); io_err = qof_session_get_error (data->session); if (io_err == ERR_BACKEND_NO_ERR) { return TRUE; } else { gxi_session_destroy (data); return FALSE; } }
/* Given an already-created url (yeah, bad testing practice: Should * start fresh from a synthetic session) load and safe-save it, then * load it again into a new session and compare the two. Since * safe-save is a more-or-less atomic function call, there's no way to * be sure that it's actually doing what it's supposed to without * running this test in a debugger and stopping in the middle of the * safe-save and inspecting the database. */ void test_dbi_safe_save( const gchar* driver, const gchar* url ) { QofSession *session_1 = NULL, *session_2 = NULL; gchar *msg = "[gnc_dbi_unlock()] There was no lock entry in the Lock table"; gchar *log_domain = "gnc.backend.dbi"; guint loglevel = G_LOG_LEVEL_WARNING, hdlr; TestErrorStruct check = { loglevel, log_domain, msg }; g_test_message ( "Testing safe save %s\n", driver ); // Load the session data session_1 = qof_session_new(); qof_session_begin( session_1, url, TRUE, FALSE, FALSE ); if (session_1 && qof_session_get_error(session_1) != ERR_BACKEND_NO_ERR) { g_warning("Session Error: %d, %s", qof_session_get_error(session_1), qof_session_get_error_message(session_1)); do_test( FALSE, "DB Session Creation Failed"); goto cleanup; } qof_session_load( session_1, NULL ); /* Do a safe save */ qof_session_safe_save( session_1, NULL ); if (session_1 && qof_session_get_error(session_1) != ERR_BACKEND_NO_ERR) { g_warning("Session Error: %s", qof_session_get_error_message(session_1)); do_test( FALSE, "DB Session Safe Save Failed"); goto cleanup; } /* Destroy the session and reload it */ session_2 = qof_session_new(); qof_session_begin( session_2, url, TRUE, FALSE, FALSE ); if (session_2 && qof_session_get_error(session_2) != ERR_BACKEND_NO_ERR) { g_warning("Session Error: %d, %s", qof_session_get_error(session_2), qof_session_get_error_message(session_2)); do_test( FALSE, "DB Session re-creation Failed"); goto cleanup; } qof_session_load( session_2, NULL ); compare_books( qof_session_get_book( session_1 ), qof_session_get_book( session_2 ) ); cleanup: hdlr = g_log_set_handler (log_domain, loglevel, (GLogFunc)test_checked_handler, &check); if (session_2 != NULL) { qof_session_end( session_2 ); qof_session_destroy( session_2 ); } if (session_1 != NULL) { qof_session_end( session_1 ); qof_session_destroy( session_1 ); } g_log_remove_handler (log_domain, hdlr); return; }
/* Test the gnc_dbi_load logic that forces a newer database to be * opened read-only and an older one to be safe-saved. Again, it would * be better to do this starting from a fresh file, but instead we're * being lazy and using an existing one. */ void test_dbi_version_control( const gchar* driver, const gchar* url ) { QofSession *sess; QofBook *book; QofBackend *qbe; QofBackendError err; gint ourversion = gnc_get_long_version(); g_test_message ( "Testing safe save %s\n", driver ); // Load the session data sess = qof_session_new(); qof_session_begin( sess, url, TRUE, FALSE, FALSE ); if (sess && qof_session_get_error(sess) != ERR_BACKEND_NO_ERR) { g_warning("Session Error: %d, %s", qof_session_get_error(sess), qof_session_get_error_message(sess)); do_test( FALSE, "DB Session Creation Failed"); goto cleanup; } qof_session_load( sess, NULL ); qbe = qof_session_get_backend( sess ); book = qof_session_get_book( sess ); qof_book_begin_edit( book ); gnc_sql_set_table_version( (GncSqlBackend*)qbe, "Gnucash", GNUCASH_RESAVE_VERSION - 1 ); qof_book_commit_edit( book ); qof_session_end( sess ); qof_session_destroy( sess ); sess = qof_session_new(); qof_session_begin( sess, url, TRUE, FALSE, FALSE ); qof_session_load( sess, NULL ); err = qof_session_pop_error( sess ); do_test( err == ERR_SQL_DB_TOO_OLD, "DB Failed to flag too old" ); qbe = qof_session_get_backend( sess ); book = qof_session_get_book( sess ); qof_book_begin_edit( book ); gnc_sql_set_table_version( (GncSqlBackend*)qbe, "Gnucash", ourversion ); gnc_sql_set_table_version( (GncSqlBackend*)qbe, "Gnucash-Resave", ourversion + 1 ); qof_book_commit_edit( book ); qof_session_end( sess ); qof_session_destroy( sess ); sess = qof_session_new(); qof_session_begin( sess, url, TRUE, FALSE, FALSE ); qof_session_load( sess, NULL ); qof_session_ensure_all_data_loaded( sess ); err = qof_session_pop_error( sess ); do_test( err == ERR_SQL_DB_TOO_NEW, "DB Failed to flag too new" ); cleanup: qbe = qof_session_get_backend( sess ); book = qof_session_get_book( sess ); qof_book_begin_edit( book ); gnc_sql_set_table_version( (GncSqlBackend*)qbe, "Gnucash-Resave", GNUCASH_RESAVE_VERSION ); qof_book_commit_edit( book ); qof_session_end( sess ); qof_session_destroy( sess ); }
void test_qofsession_aqb_kvp( void ) { /* load the accounts from the users datafile */ /* but first, check to make sure we've got a session going. */ QofBackendError io_err; char *file1 = get_filepath("file-book.gnucash"); char *file2 = get_filepath("file-book-hbcislot.gnucash"); if (1) { // A file with no content at all, but a valid XML file QofSession *new_session = qof_session_new (); char *newfile = g_strdup_printf("file://%s", file1); qof_session_begin (new_session, newfile, TRUE, FALSE, FALSE); io_err = qof_session_get_error (new_session); //printf("io_err1 = %d\n", io_err); g_assert(io_err != ERR_BACKEND_NO_HANDLER); // Do not have no handler g_assert(io_err != ERR_BACKEND_NO_SUCH_DB); // DB must exist g_assert(io_err != ERR_BACKEND_LOCKED); g_assert(io_err == 0); qof_session_load (new_session, NULL); io_err = qof_session_get_error (new_session); //printf("io_err2 = %d\n", io_err); g_assert(io_err == 0); g_free(newfile); g_free(file1); gnc_hook_run(HOOK_BOOK_CLOSED, new_session); //qof_session_destroy(new_session); // tries to delete the LCK file but it wasn't created in the first place } if (1) { // A file with no content except for the book_template_list kvp // slot QofSession *new_session = qof_session_new (); char *newfile = g_strdup_printf("file://%s", file2); qof_session_begin (new_session, newfile, TRUE, FALSE, FALSE); io_err = qof_session_get_error (new_session); //printf("io_err1 = %d\n", io_err); g_assert(io_err != ERR_BACKEND_NO_HANDLER); // Do not have no handler g_assert(io_err != ERR_BACKEND_NO_SUCH_DB); // DB must exist g_assert(io_err != ERR_BACKEND_LOCKED); g_assert(io_err == 0); qof_session_load (new_session, NULL); io_err = qof_session_get_error (new_session); //printf("io_err2 = %d\n", io_err); g_assert(io_err == 0); { GList *templ_list; GncABTransTempl *templ; QofBook *book = qof_session_get_book(new_session); const char* ORIGINAL_NAME = "Some Name"; const char* CHANGED_NAME = "Some Changed Name"; templ_list = gnc_ab_trans_templ_list_new_from_book (book); g_assert_cmpint(g_list_length(templ_list), ==, 1); templ = templ_list->data; //Raise the edit level so that we can check that it's marked dirty. qof_instance_increase_editlevel(QOF_INSTANCE(book)); g_assert_cmpstr(gnc_ab_trans_templ_get_name(templ), ==, ORIGINAL_NAME); // ok, name from file is here // Now we change the name into something else and verify it can be saved gnc_ab_trans_templ_set_name(templ, CHANGED_NAME); { g_assert(!qof_instance_get_dirty(QOF_INSTANCE(book))); // not yet dirty // Here we save the changed kvp gnc_ab_set_book_template_list(book, templ_list); g_assert(qof_instance_get_dirty(QOF_INSTANCE(book))); // yup, now dirty gnc_ab_trans_templ_list_free(templ_list); } { templ_list = gnc_ab_trans_templ_list_new_from_book (book); g_assert_cmpint(g_list_length(templ_list), ==, 1); templ = templ_list->data; g_assert_cmpstr(gnc_ab_trans_templ_get_name(templ), ==, CHANGED_NAME); // ok, the change has been saved! gnc_ab_trans_templ_list_free(templ_list); } } { // Check the kvp slots of a aqbanking-enabled account QofBook *book = qof_session_get_book(new_session); Account* account = gnc_book_get_root_account(book); GDate retrieved_date, original_date; gchar buff[MAX_DATE_LENGTH]; g_assert(account); // The interesting test case here: Can we read the correct date // from the xml file? if (1) { Timespec retrieved_ts = gnc_ab_get_account_trans_retrieval(account); g_test_message("retrieved_ts=%s\n", gnc_print_date(retrieved_ts)); //printf("Time=%s\n", gnc_print_date(retrieved_ts)); retrieved_date = timespec_to_gdate(retrieved_ts); g_date_set_dmy(&original_date, 29, 8, 2014); g_assert_cmpint(g_date_compare(&retrieved_date, &original_date), ==, 0); } // A lower-level test here: Can we write and read again the // trans_retrieval date? This wouldn't need this particular // Account, just a general Account object. if (0) { Timespec original_ts = timespec_now(), retrieved_ts; // Check whether the "ab-trans-retrieval" property of Account // is written and read again correctly. gnc_ab_set_account_trans_retrieval(account, original_ts); retrieved_ts = gnc_ab_get_account_trans_retrieval(account); // printf("original_ts=%s = %d retrieved_ts=%s = %d\n", // gnc_print_date(original_ts), original_ts.tv_sec, // gnc_print_date(retrieved_ts), retrieved_ts.tv_sec); original_date = timespec_to_gdate(original_ts); retrieved_date = timespec_to_gdate(retrieved_ts); qof_print_gdate (buff, sizeof (buff), &original_date); //printf("original_date=%s\n", buff); qof_print_gdate (buff, sizeof (buff), &retrieved_date); //printf("retrieved_date=%s\n", buff); // Is the retrieved date identical to the one written g_assert_cmpint(g_date_compare(&retrieved_date, &original_date), ==, 0); }
QofBackendError get_error () { return qof_session_get_error(gobj()); }
void qof_session_begin (QofSession *session, const char * book_id, gboolean ignore_lock, gboolean create, gboolean force) { gchar **splituri; if (!session) return; ENTER (" sess=%p ignore_lock=%d, book-id=%s", session, ignore_lock, book_id ? book_id : "(null)"); /* Clear the error condition of previous errors */ qof_session_clear_error (session); /* Check to see if this session is already open */ if (session->book_id) { if (ERR_BACKEND_NO_ERR != qof_session_get_error(session)) qof_session_push_error (session, ERR_BACKEND_LOCKED, NULL); LEAVE("push error book is already open "); return; } /* seriously invalid */ if (!book_id) { if (ERR_BACKEND_NO_ERR != qof_session_get_error(session)) qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL); LEAVE("push error missing book_id"); return; } /* destroy the old backend */ qof_session_destroy_backend(session); /* Store the session URL */ session->book_id = g_strdup (book_id); /* Look for something of the form of "file://", "http://" or * "postgres://". Everything before the colon is the access * method. Load the first backend found for that access method. */ splituri = g_strsplit ( book_id, "://", 2 ); if ( splituri[1] == NULL ) /* no access method in the uri, use generic "file" backend */ qof_session_load_backend(session, "file"); else /* access method found, load appropriate backend */ qof_session_load_backend(session, splituri[0]); g_strfreev ( splituri ); /* No backend was found. That's bad. */ if (NULL == session->backend) { g_free(session->book_id); session->book_id = NULL; if (ERR_BACKEND_NO_ERR == qof_session_get_error(session)) qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL); LEAVE (" BAD: no backend: sess=%p book-id=%s", session, book_id ? book_id : "(null)"); return; } /* If there's a begin method, call that. */ if (session->backend->session_begin) { char *msg; int err; (session->backend->session_begin)(session->backend, session, session->book_id, ignore_lock, create, force); PINFO("Done running session_begin on backend"); err = qof_backend_get_error(session->backend); msg = qof_backend_get_message(session->backend); if (err != ERR_BACKEND_NO_ERR) { g_free(session->book_id); session->book_id = NULL; qof_session_push_error (session, err, msg); LEAVE(" backend error %d %s", err, msg ? msg : "(null)"); return; } if (msg != NULL) { PWARN("%s", msg); g_free(msg); } } LEAVE (" sess=%p book-id=%s", session, book_id ? book_id : "(null)"); }
void qof_session_load (QofSession *session, QofPercentageFunc percentage_func) { QofBook *newbook, *oldbook; QofBackend *be; QofBackendError err; if (!session) return; if (!session->book_id) return; ENTER ("sess=%p book_id=%s", session, session->book_id ? session->book_id : "(null)"); /* At this point, we should are supposed to have a valid book * id and a lock on the file. */ oldbook = session->book; /* XXX why are we creating a book here? I think the books * need to be handled by the backend ... especially since * the backend may need to load multiple books ... XXX. FIXME. */ newbook = qof_book_new(); session->book = newbook; PINFO ("new book=%p", newbook); qof_session_clear_error (session); /* This code should be sufficient to initialize *any* backend, * whether http, postgres, or anything else that might come along. * Basically, the idea is that by now, a backend has already been * created & set up. At this point, we only need to get the * top-level account group out of the backend, and that is a * generic, backend-independent operation. */ be = session->backend; qof_book_set_backend(newbook, be); /* Starting the session should result in a bunch of accounts * and currencies being downloaded, but probably no transactions; * The GUI will need to do a query for that. */ if (be) { be->percentage = percentage_func; if (be->load) { be->load (be, newbook, LOAD_TYPE_INITIAL_LOAD); qof_session_push_error (session, qof_backend_get_error(be), NULL); } } /* XXX if the load fails, then we try to restore the old set of books; * however, we don't undo the session id (the URL). Thus if the * user attempts to save after a failed load, they weill be trying to * save to some bogus URL. This is wrong. XXX FIXME. */ err = qof_session_get_error(session); if ((err != ERR_BACKEND_NO_ERR) && (err != ERR_FILEIO_FILE_TOO_OLD) && (err != ERR_FILEIO_NO_ENCODING) && (err != ERR_FILEIO_FILE_UPGRADE) && (err != ERR_SQL_DB_TOO_OLD) && (err != ERR_SQL_DB_TOO_NEW)) { /* Something broke, put back the old stuff */ qof_book_set_backend (newbook, NULL); qof_book_destroy (newbook); session->book = oldbook; LEAVE("error from backend %d", qof_session_get_error(session)); return; } qof_book_set_backend (oldbook, NULL); qof_book_destroy (oldbook); LEAVE ("sess = %p, book_id=%s", session, session->book_id ? session->book_id : "(null)"); }
void qof_session_begin (QofSession *session, const char * book_id, gboolean ignore_lock, gboolean create, gboolean force) { gchar *scheme = NULL, *filename = NULL; if (!session) return; ENTER (" sess=%p ignore_lock=%d, book-id=%s", session, ignore_lock, book_id ? book_id : "(null)"); /* Clear the error condition of previous errors */ qof_session_clear_error (session); /* Check to see if this session is already open */ if (session->book_id) { if (ERR_BACKEND_NO_ERR != qof_session_get_error(session)) qof_session_push_error (session, ERR_BACKEND_LOCKED, NULL); LEAVE("push error book is already open "); return; } /* seriously invalid */ if (!book_id) { if (ERR_BACKEND_NO_ERR != qof_session_get_error(session)) qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL); LEAVE("push error missing book_id"); return; } scheme = g_uri_parse_scheme (book_id); if (g_strcmp0 (scheme, "file") == 0) filename = g_filename_from_uri (book_id, NULL, NULL); else if (!scheme) filename = g_strdup (book_id); if (filename && g_file_test (filename, G_FILE_TEST_IS_DIR)) { if (ERR_BACKEND_NO_ERR == qof_session_get_error(session)) qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL); g_free (filename); g_free (scheme); LEAVE("Can't open a directory"); return; } /* destroy the old backend */ qof_session_destroy_backend(session); /* Store the session URL */ session->book_id = g_strdup (book_id); if (filename) qof_session_load_backend(session, "file"); else /* access method found, load appropriate backend */ qof_session_load_backend(session, scheme); g_free (filename); g_free (scheme); /* No backend was found. That's bad. */ if (NULL == session->backend) { g_free(session->book_id); session->book_id = NULL; if (ERR_BACKEND_NO_ERR == qof_session_get_error(session)) qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL); LEAVE (" BAD: no backend: sess=%p book-id=%s", session, book_id ? book_id : "(null)"); return; } /* If there's a begin method, call that. */ if (session->backend->session_begin) { char *msg; QofBackendError err; (session->backend->session_begin)(session->backend, session, session->book_id, ignore_lock, create, force); PINFO("Done running session_begin on backend"); err = qof_backend_get_error(session->backend); msg = qof_backend_get_message(session->backend); if (err != ERR_BACKEND_NO_ERR) { g_free(session->book_id); session->book_id = NULL; qof_session_push_error (session, err, msg); LEAVE(" backend error %d %s", err, msg ? msg : "(null)"); return; } if (msg != NULL) { PWARN("%s", msg); g_free(msg); } } LEAVE (" sess=%p book-id=%s", session, book_id ? book_id : "(null)"); }
void qof_session_save (QofSession *session, QofPercentageFunc percentage_func) { GList *node; QofBackend *be; gboolean partial, change_backend; QofBackendProvider *prov; GSList *p; QofBook *book, *abook; int err; gint num; char *msg = NULL; char *book_id; if (!session) return; if (!g_atomic_int_dec_and_test(&session->lock)) goto leave; ENTER ("sess=%p book_id=%s", session, session->book_id ? session->book_id : "(null)"); /* Partial book handling. */ book = qof_session_get_book(session); partial = (gboolean)GPOINTER_TO_INT(qof_book_get_data(book, PARTIAL_QOFBOOK)); change_backend = FALSE; msg = g_strdup_printf(" "); book_id = g_strdup(session->book_id); if (partial == TRUE) { if (session->backend && session->backend->provider) { prov = session->backend->provider; if (TRUE == prov->partial_book_supported) { /* if current backend supports partial, leave alone. */ change_backend = FALSE; } else { change_backend = TRUE; } } /* If provider is undefined, assume partial not supported. */ else { change_backend = TRUE; } } if (change_backend == TRUE) { qof_session_destroy_backend(session); if (!qof_providers_initialized) { qof_providers_initialized = TRUE; } p = provider_list; while (p != NULL) { prov = p->data; if (TRUE == prov->partial_book_supported) { /** \todo check the access_method too, not in scope here, yet. */ /* if((TRUE == prov->partial_book_supported) && (0 == g_ascii_strcasecmp (access_method, prov->access_method))) {*/ if (NULL == prov->backend_new) continue; /* Use the providers creation callback */ session->backend = (*(prov->backend_new))(); session->backend->provider = prov; if (session->backend->session_begin) { /* Call begin - backend has been changed, so make sure a file can be written, use ignore_lock and force create */ g_free(session->book_id); session->book_id = NULL; (session->backend->session_begin)(session->backend, session, book_id, TRUE, TRUE, TRUE); PINFO("Done running session_begin on changed backend"); err = qof_backend_get_error(session->backend); msg = qof_backend_get_message(session->backend); if (err != ERR_BACKEND_NO_ERR) { g_free(session->book_id); session->book_id = NULL; qof_session_push_error (session, err, msg); LEAVE("changed backend error %d", err); goto leave; } if (msg != NULL) { PWARN("%s", msg); g_free(msg); msg = NULL; } } /* Tell the books about the backend that they'll be using. */ for (node = session->books; node; node = node->next) { book = node->data; qof_book_set_backend (book, session->backend); } p = NULL; } if (p) { p = p->next; } } if (!session->backend) { if (ERR_BACKEND_NO_ERR != qof_session_get_error(session)) { msg = g_strdup_printf("failed to load backend"); qof_session_push_error(session, ERR_BACKEND_NO_HANDLER, msg); } goto leave; } } /* If there is a backend, and the backend is reachable * (i.e. we can communicate with it), then synchronize with * the backend. If we cannot contact the backend (e.g. * because we've gone offline, the network has crashed, etc.) * then give the user the option to save to the local disk. * * hack alert -- FIXME -- XXX the code below no longer * does what the words above say. This needs fixing. */ be = session->backend; if (be) { for (node = session->books; node; node = node->next) { abook = node->data; /* if invoked as SaveAs(), then backend not yet set */ qof_book_set_backend (abook, be); be->percentage = percentage_func; if (be->sync) { (be->sync)(be, abook); if (save_error_handler(be, session)) goto leave; } } /* If we got to here, then the backend saved everything * just fine, and we are done. So return. */ /* Return the book_id to previous value. */ qof_session_clear_error (session); LEAVE("Success"); goto leave; } else { if (ERR_BACKEND_NO_ERR != qof_session_get_error(session)) { msg = g_strdup_printf("failed to load backend"); qof_session_push_error(session, ERR_BACKEND_NO_HANDLER, msg); } } LEAVE("error -- No backend!"); leave: if (msg != NULL) g_free(msg); g_atomic_int_inc(&session->lock); return; }
static gboolean gxi_parse_file (GncXmlImportData *data) { QofSession *session = NULL; QofBook *book; QofBackend *backend; QofBackendError io_err = ERR_BACKEND_NO_ERR; gchar *message = NULL; gboolean success = FALSE; if (data->n_unassigned || data->n_impossible) goto cleanup_parse_file; /* fill subst hash table with byte sequence substitutions */ data->subst = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); g_hash_table_foreach (data->ambiguous_ht, (GHFunc) subst_insert_amb, data); g_hash_table_foreach (data->unique, (GHFunc) subst_insert_unique, data); if (!data->subst) goto cleanup_parse_file; /* create a temporary QofSession */ gxi_session_destroy (data); session = qof_session_new (); data->session = session; qof_session_begin (session, data->filename, TRUE, FALSE, FALSE); io_err = qof_session_get_error (session); if (io_err != ERR_BACKEND_NO_ERR) { message = _("The file could not be reopened."); goto cleanup_parse_file; } xaccLogDisable (); gxi_update_progress_bar (_("Reading file..."), 0.0); qof_session_load (session, gxi_update_progress_bar); gxi_update_progress_bar (NULL, -1.0); xaccLogEnable (); io_err = qof_session_get_error (session); if (io_err == ERR_BACKEND_NO_ERR) { /* loaded sucessfully now. strange, but ok */ success = TRUE; goto cleanup_parse_file; } else if (io_err != ERR_FILEIO_NO_ENCODING) { /* another error, cannot handle this here */ message = _("The file could not be reopened."); goto cleanup_parse_file; } qof_session_pop_error (session); book = qof_session_get_book (session); backend = qof_book_get_backend (book); gxi_update_progress_bar (_("Parsing file..."), 0.0); success = gnc_xml2_parse_with_subst (backend, book, data->subst); gxi_update_progress_bar (NULL, -1.0); if (success) data->session = session; else message = _("There was an error parsing the file."); cleanup_parse_file: if (data->subst) { g_hash_table_destroy (data->subst); data->subst = NULL; } if (message) { gnc_error_dialog (data->assistant, "%s", message); } if (!success) gxi_session_destroy (data); return success; }