42 #include <sys/types.h> 48 # warning "<unistd.h> required." 55 static QofLogModule log_module = QOF_MOD_SESSION;
58 #include "qofbook-p.h" 59 #include "qof-backend.hpp" 60 #include "qofsession.hpp" 61 #include "gnc-backend-prov.hpp" 64 #include <boost/algorithm/string.hpp> 70 using ProviderVec = std::vector<QofBackendProvider_ptr>;
71 static ProviderVec s_providers;
72 static const std::string empty_string{};
78 ProviderVec& get_providers (
void );
79 bool get_providers_initialized (
void );
88 get_providers_initialized (
void)
90 return !s_providers.empty();
96 s_providers.emplace_back(std::move(prov));
100 qof_backend_unregister_all_providers ()
102 s_providers.clear ();
110 std::for_each(s_providers.begin(), s_providers.end(),
111 [&list](QofBackendProvider_ptr& provider) {
112 gpointer method =
reinterpret_cast<gpointer
>(
const_cast<char*
>(provider->access_method));
113 list = g_list_prepend(list, method);
122 QofSessionImpl::QofSessionImpl (QofBook* book) noexcept
132 QofSessionImpl::~QofSessionImpl () noexcept
134 ENTER (
"sess=%p uri=%s",
this, m_uri.c_str ());
137 qof_book_set_backend (m_book,
nullptr);
140 LEAVE (
"sess=%p",
this);
144 qof_session_destroy (QofSession * session)
150 qof_session_new (QofBook* book)
156 QofSessionImpl::destroy_backend () noexcept
163 qof_book_set_backend (m_book,
nullptr);
170 QofSessionImpl::load_backend (std::string access_method) noexcept
172 std::ostringstream s;
173 s <<
" list=" << s_providers.size();
174 ENTER (
"%s", s.str().c_str());
175 for (
auto const & prov : s_providers)
177 if (!boost::iequals (access_method, prov->access_method))
179 PINFO (
"The provider providers access_method, %s, but we're loading for access_method, %s. Skipping.",
180 prov->access_method, access_method.c_str ());
183 PINFO (
" Selected provider %s", prov->provider_name);
186 if (!m_creating && !prov->type_check (m_uri.c_str ()))
188 PINFO(
"Provider, %s, reported not being usable for book, %s.",
189 prov->provider_name, m_uri.c_str ());
192 m_backend = prov->create_backend();
196 std::string msg {
"failed to get_backend using access method \"" + access_method +
"\""};
207 if (!m_uri.size ())
return;
208 ENTER (
"sess=%p uri=%s",
this, m_uri.c_str ());
221 qof_book_set_backend (m_book, m_backend);
229 m_backend->set_percentage(percentage_func);
230 m_backend->load (m_book, LOAD_TYPE_INITIAL_LOAD);
231 push_error (m_backend->get_error(), {});
234 auto err = get_error ();
235 if ((err != ERR_BACKEND_NO_ERR) &&
246 LEAVE (
"error from backend %d", get_error ());
250 LEAVE (
"sess = %p, uri=%s",
this, m_uri.c_str ());
258 ENTER (
" sess=%p mode=%d, URI=%s",
this, mode, new_uri);
263 if (ERR_BACKEND_NO_ERR != get_error ())
265 LEAVE(
"push error book is already open ");
272 if (ERR_BACKEND_NO_ERR != get_error ())
274 LEAVE(
"push error missing new_uri");
278 char * scheme {g_uri_parse_scheme (new_uri)};
279 char * filename {
nullptr};
280 if (g_strcmp0 (scheme,
"file") == 0)
281 filename = g_filename_from_uri (new_uri,
nullptr,
nullptr);
283 filename = g_strdup (new_uri);
285 if (filename && g_file_test (filename, G_FILE_TEST_IS_DIR))
287 if (ERR_BACKEND_NO_ERR == get_error ())
291 LEAVE(
"Can't open a directory");
300 load_backend (
"file");
302 load_backend (scheme);
307 if (m_backend ==
nullptr)
310 if (ERR_BACKEND_NO_ERR == get_error ())
312 LEAVE (
" BAD: no backend: sess=%p book-id=%s",
318 m_backend->session_begin(
this, m_uri.c_str(), mode);
319 PINFO (
"Done running session_begin on backend");
321 auto msg (m_backend->get_message());
322 if (err != ERR_BACKEND_NO_ERR)
325 push_error (err, msg);
326 LEAVE (
" backend error %d %s", err, msg.empty() ?
"(null)" : msg.c_str());
331 PWARN(
"%s", msg.c_str());
334 LEAVE (
" sess=%p book-id=%s",
this, new_uri);
340 ENTER (
"sess=%p uri=%s",
this, m_uri.c_str ());
342 if (backend !=
nullptr)
343 backend->session_end();
346 LEAVE (
"sess=%p uri=%s",
this, m_uri.c_str ());
352 QofSessionImpl::clear_error () noexcept
354 m_last_err = ERR_BACKEND_NO_ERR;
355 m_error_message = {};
362 err = backend->get_error();
363 while (err != ERR_BACKEND_NO_ERR);
368 QofSessionImpl::push_error (
QofBackendError const err, std::string message) noexcept
371 m_error_message = message;
378 if (m_last_err != ERR_BACKEND_NO_ERR)
381 if (qof_be ==
nullptr)
return ERR_BACKEND_NO_ERR;
383 m_last_err = qof_be->get_error();
388 QofSessionImpl::get_error_message () const noexcept
390 return m_error_message;
394 QofSessionImpl::pop_error () noexcept
404 QofSessionImpl::get_book () const noexcept
406 if (!m_book)
return nullptr;
407 if (
'y' == m_book->book_open)
413 QofSession::get_backend () const noexcept
419 QofSessionImpl::get_file_path () const noexcept
422 if (!backend)
return empty_string;
423 return backend->get_uri();
433 QofSessionImpl::is_saving () const noexcept
446 ENTER (
"sess=%p uri=%s",
this, m_uri.c_str ());
458 qof_book_set_backend (m_book, m_backend);
459 m_backend->set_percentage(percentage_func);
460 m_backend->sync(m_book);
461 auto err = m_backend->get_error();
462 if (err != ERR_BACKEND_NO_ERR)
464 push_error (err, {});
476 LEAVE(
"error -- No backend!");
484 if (!(m_backend && m_book))
return;
486 qof_book_set_backend (m_book, m_backend);
487 m_backend->set_percentage(percentage_func);
488 m_backend->safe_sync(get_book ());
489 auto err = m_backend->get_error();
490 auto msg = m_backend->get_message();
491 if (err != ERR_BACKEND_NO_ERR)
494 push_error (err, msg);
499 QofSessionImpl::ensure_all_data_loaded () noexcept
501 if (!(m_backend && m_book))
return;
503 qof_book_set_backend (m_book, m_backend);
504 m_backend->
load(m_book, LOAD_TYPE_LOAD_ALL);
511 ENTER (
"sess1=%p sess2=%p",
this, &other);
513 if (m_book && other.m_book)
514 std::swap (m_book->read_only, other.m_book->read_only);
515 std::swap (m_book, other.m_book);
518 qof_book_set_backend (other.m_book, mybackend);
523 QofSessionImpl::events_pending () const noexcept
529 QofSessionImpl::process_events () const noexcept
542 auto real_book = real_session.get_book ();
543 ENTER (
"tmp_session=%p real_session=%p book=%p uri=%s",
544 this, &real_session, real_book, m_uri.c_str ());
549 if (!m_backend)
return false;
551 m_backend->set_percentage(percentage_func);
553 m_backend->export_coa(real_book);
554 auto err = m_backend->get_error();
555 if (err != ERR_BACKEND_NO_ERR)
564 qof_session_get_error_message (
const QofSession * session)
566 if (!session)
return "";
567 return session->get_error_message ().c_str ();
574 return session->pop_error ();
580 if (!session)
return NULL;
581 return session->get_book ();
587 if (!session)
return nullptr;
588 auto& path{session->get_file_path()};
589 return path.empty() ? nullptr : path.c_str ();
595 if (session ==
nullptr)
return;
596 return session->ensure_all_data_loaded ();
600 qof_session_get_url (
const QofSession *session)
602 if (!session)
return NULL;
603 return session->get_uri ().c_str ();
609 if (!session)
return NULL;
610 return session->get_backend ();
616 if (!session)
return;
617 session->begin(uri, mode);
621 qof_session_load (QofSession *session,
624 if (!session)
return;
625 session->load (percentage_func);
632 if (!session)
return;
633 session->save (percentage_func);
639 if (!session)
return;
640 session->safe_save (percentage_func);
646 if (!session)
return false;
647 return session->is_saving ();
653 if (!session)
return;
660 if (session_1 == session_2)
return;
661 if (!session_1 || !session_2)
return;
662 session_1->swap_books (*session_2);
668 if (!session)
return false;
669 return session->events_pending ();
675 if (!session)
return FALSE;
676 return session->process_events ();
680 qof_session_export (QofSession *tmp_session,
681 QofSession *real_session,
684 if ((!tmp_session) || (!real_session))
return FALSE;
685 return tmp_session->export_session (*real_session, percentage_func);
690 void init_static_qofsession_pointers (
void);
692 void qof_session_load_backend (QofSession * session,
const char * access_method)
694 session->load_backend (access_method);
698 qof_session_clear_error (QofSession * session)
700 session->clear_error ();
704 qof_session_destroy_backend (QofSession * session)
706 session->destroy_backend ();
709 void qof_session_set_uri (QofSession * session,
char const * uri)
714 session->m_uri = uri;
717 void (*p_qof_session_load_backend) (QofSession *,
const char * access_method);
718 void (*p_qof_session_clear_error) (QofSession *);
719 void (*p_qof_session_destroy_backend) (QofSession *);
720 void (*p_qof_session_set_uri) (QofSession *,
char const * uri);
723 init_static_qofsession_pointers (
void)
725 p_qof_session_load_backend = &qof_session_load_backend;
726 p_qof_session_clear_error = &qof_session_clear_error;
727 p_qof_session_destroy_backend = &qof_session_destroy_backend;
728 p_qof_session_set_uri = &qof_session_set_uri;
735 return session->get_error();
void qof_session_save(QofSession *session, QofPercentageFunc percentage_func)
The qof_session_save() method will commit all changes that have been made to the session.
void swap_books(QofSessionImpl &) noexcept
Swap books with another session.
gboolean qof_session_save_in_progress(const QofSession *session)
The qof_session_not_saved() subroutine will return TRUE if any data in the session hasn't been saved ...
void(* QofPercentageFunc)(const char *message, double percent)
The qof_session_load() method causes the QofBook to be made ready to to use with this URL/datastore...
#define PINFO(format, args...)
Print an informational note.
gboolean qof_session_events_pending(const QofSession *session)
The qof_session_events_pending() method will return TRUE if the backend has pending events which must...
QofBackendError
The errors that can be reported to the GUI & other front-end users.
void qof_session_safe_save(QofSession *session, QofPercentageFunc percentage_func)
A special version of save used in the sql backend which moves the existing tables aside...
void qof_backend_register_provider(QofBackendProvider_ptr &&prov)
Let the system know about a new provider of backends.
void end() noexcept
Terminates the current backend.
void qof_session_begin(QofSession *session, const char *uri, SessionOpenMode mode)
Begins a new session.
QofBook * qof_book_new(void)
Allocate, initialise and return a new QofBook.
database is old and needs upgrading
in use by another user (ETXTBSY)
Create a new store at the URI.
const char * qof_session_get_file_path(const QofSession *session)
The qof_session_get_file_path() routine returns the fully-qualified file path for the session...
void qof_session_ensure_all_data_loaded(QofSession *session)
Ensure all of the data is loaded from the session.
#define ENTER(format, args...)
Print a function entry debugging message.
file will be upgraded and not be able to be read by prior versions - warn users
the Core Object Registration/Lookup Private Interface
#define PWARN(format, args...)
Log a warning.
gboolean qof_book_empty(const QofBook *book)
Check if the book has had anything loaded into it.
std::string const & get_uri() const noexcept
We return by reference so that a pointer to the data of the string lives long enough to make it back ...
file does not specify encoding
database is newer, we can't write to it
QofBook * qof_session_get_book(const QofSession *session)
Returns the QofBook of this session.
QofBackendError qof_session_pop_error(QofSession *session)
The qof_session_pop_error() routine can be used to obtain the reason for any failure.
GList * qof_backend_get_registered_access_method_list(void)
Return a list of strings for the registered access methods.
QofBackendError get_error() noexcept
Returns and clears the local cached error.
QofBackendError qof_session_get_error(QofSession *session)
The qof_session_get_error() routine can be used to obtain the reason for any failure.
void qof_session_swap_data(QofSession *session_1, QofSession *session_2)
The qof_session_swap_data () method swaps the book of the two given sessions.
no backend handler found for this access method (ENOSYS)
gboolean qof_book_session_not_saved(const QofBook *book)
qof_book_not_saved() returns the value of the session_dirty flag, set when changes to any object in t...
virtual void load(QofBook *, QofBackendLoadType)=0
Load the minimal set of application data needed for the application to be operable at initial startup...
SessionOpenMode
Mode for opening sessions.
Backend * pointer was unexpectedly null.
void begin(const char *new_uri, SessionOpenMode mode) noexcept
Begin this session.
#define LEAVE(format, args...)
Print a function exit debugging message.
void qof_session_end(QofSession *session)
The qof_session_end() method will release the session lock.
QofBackend * qof_book_get_backend(const QofBook *book)
Retrieve the backend used by this book.
QofBackend * qof_session_get_backend(const QofSession *session)
Returns the qof session's backend.
gboolean qof_session_process_events(QofSession *session)
The qof_session_process_events() method will process any events indicated by the qof_session_events_p...
file version so old we can't read it
Open will fail if the URI doesn't exist or is locked.
void qof_book_destroy(QofBook *book)
End any editing sessions associated with book, and free all memory associated with it...
QofBackendError get_error()
Retrieve the currently-stored error and clear it.