39 #include <sys/types.h> 45 # warning "<unistd.h> required." 52 static QofLogModule log_module = QOF_MOD_SESSION;
54 #include "qofbook-p.h" 55 #include "qof-backend.hpp" 56 #include "qofsession.hpp" 57 #include "gnc-backend-prov.hpp" 60 #include <boost/algorithm/string.hpp> 66 using ProviderVec = std::vector<QofBackendProvider_ptr>;
67 static ProviderVec s_providers;
68 static const std::string empty_string{};
74 ProviderVec& get_providers (
void );
75 bool get_providers_initialized (
void );
84 get_providers_initialized (
void)
86 return !s_providers.empty();
92 s_providers.emplace_back(std::move(prov));
96 qof_backend_unregister_all_providers ()
106 std::for_each(s_providers.begin(), s_providers.end(),
107 [&list](QofBackendProvider_ptr& provider) {
108 gpointer method =
reinterpret_cast<gpointer
>(
const_cast<char*
>(provider->access_method));
109 list = g_list_prepend(list, method);
118 QofSessionImpl::QofSessionImpl (QofBook* book) noexcept
128 QofSessionImpl::~QofSessionImpl () noexcept
130 ENTER (
"sess=%p uri=%s",
this, m_uri.c_str ());
133 qof_book_set_backend (m_book,
nullptr);
136 LEAVE (
"sess=%p",
this);
140 qof_session_destroy (QofSession * session)
146 qof_session_new (QofBook* book)
152 QofSessionImpl::destroy_backend () noexcept
159 qof_book_set_backend (m_book,
nullptr);
166 QofSessionImpl::load_backend (std::string access_method) noexcept
168 std::ostringstream s;
169 s <<
" list=" << s_providers.size();
170 ENTER (
"%s", s.str().c_str());
171 for (
auto const & prov : s_providers)
173 if (!boost::iequals (access_method, prov->access_method))
175 PINFO (
"The provider providers access_method, %s, but we're loading for access_method, %s. Skipping.",
176 prov->access_method, access_method.c_str ());
179 PINFO (
" Selected provider %s", prov->provider_name);
182 if (!m_creating && !prov->type_check (m_uri.c_str ()))
184 PINFO(
"Provider, %s, reported not being usable for book, %s.",
185 prov->provider_name, m_uri.c_str ());
188 m_backend = prov->create_backend();
192 std::string msg {
"failed to get_backend using access method \"" + access_method +
"\""};
203 if (!m_uri.size ())
return;
204 ENTER (
"sess=%p uri=%s",
this, m_uri.c_str ());
217 qof_book_set_backend (m_book, m_backend);
225 m_backend->set_percentage(percentage_func);
226 m_backend->load (m_book, LOAD_TYPE_INITIAL_LOAD);
227 push_error (m_backend->get_error(), {});
230 auto err = get_error ();
231 if ((err != ERR_BACKEND_NO_ERR) &&
242 LEAVE (
"error from backend %d", get_error ());
246 LEAVE (
"sess = %p, uri=%s",
this, m_uri.c_str ());
254 ENTER (
" sess=%p mode=%d, URI=%s",
this, mode, new_uri);
259 if (ERR_BACKEND_NO_ERR != get_error ())
261 LEAVE(
"push error book is already open ");
268 if (ERR_BACKEND_NO_ERR != get_error ())
270 LEAVE(
"push error missing new_uri");
274 char * scheme {g_uri_parse_scheme (new_uri)};
275 char * filename {
nullptr};
276 if (g_strcmp0 (scheme,
"file") == 0)
277 filename = g_filename_from_uri (new_uri,
nullptr,
nullptr);
279 filename = g_strdup (new_uri);
281 if (filename && g_file_test (filename, G_FILE_TEST_IS_DIR))
283 if (ERR_BACKEND_NO_ERR == get_error ())
287 LEAVE(
"Can't open a directory");
296 load_backend (
"file");
298 load_backend (scheme);
303 if (m_backend ==
nullptr)
306 if (ERR_BACKEND_NO_ERR == get_error ())
308 LEAVE (
" BAD: no backend: sess=%p book-id=%s",
314 m_backend->session_begin(
this, m_uri.c_str(), mode);
315 PINFO (
"Done running session_begin on backend");
317 auto msg (m_backend->get_message());
318 if (err != ERR_BACKEND_NO_ERR)
321 push_error (err, msg);
322 LEAVE (
" backend error %d %s", err, msg.empty() ?
"(null)" : msg.c_str());
327 PWARN(
"%s", msg.c_str());
330 LEAVE (
" sess=%p book-id=%s",
this, new_uri);
336 ENTER (
"sess=%p uri=%s",
this, m_uri.c_str ());
338 if (backend !=
nullptr)
339 backend->session_end();
342 LEAVE (
"sess=%p uri=%s",
this, m_uri.c_str ());
348 QofSessionImpl::clear_error () noexcept
350 m_last_err = ERR_BACKEND_NO_ERR;
351 m_error_message = {};
358 err = backend->get_error();
359 while (err != ERR_BACKEND_NO_ERR);
364 QofSessionImpl::push_error (
QofBackendError const err, std::string message) noexcept
367 m_error_message = message;
374 if (m_last_err != ERR_BACKEND_NO_ERR)
377 if (qof_be ==
nullptr)
return ERR_BACKEND_NO_ERR;
379 m_last_err = qof_be->get_error();
384 QofSessionImpl::get_error_message () const noexcept
386 return m_error_message;
390 QofSessionImpl::pop_error () noexcept
400 QofSessionImpl::get_book () const noexcept
402 if (!m_book)
return nullptr;
403 if (
'y' == m_book->book_open)
409 QofSession::get_backend () const noexcept
415 QofSessionImpl::get_file_path () const noexcept
418 if (!backend)
return empty_string;
419 return backend->get_uri();
429 QofSessionImpl::is_saving () const noexcept
442 ENTER (
"sess=%p uri=%s",
this, m_uri.c_str ());
454 qof_book_set_backend (m_book, m_backend);
455 m_backend->set_percentage(percentage_func);
456 m_backend->sync(m_book);
457 auto err = m_backend->get_error();
458 if (err != ERR_BACKEND_NO_ERR)
460 push_error (err, {});
472 LEAVE(
"error -- No backend!");
480 if (!(m_backend && m_book))
return;
482 qof_book_set_backend (m_book, m_backend);
483 m_backend->set_percentage(percentage_func);
484 m_backend->safe_sync(get_book ());
485 auto err = m_backend->get_error();
486 auto msg = m_backend->get_message();
487 if (err != ERR_BACKEND_NO_ERR)
490 push_error (err, msg);
495 QofSessionImpl::ensure_all_data_loaded () noexcept
497 if (!(m_backend && m_book))
return;
499 qof_book_set_backend (m_book, m_backend);
500 m_backend->
load(m_book, LOAD_TYPE_LOAD_ALL);
507 ENTER (
"sess1=%p sess2=%p",
this, &other);
509 if (m_book && other.m_book)
510 std::swap (m_book->read_only, other.m_book->read_only);
511 std::swap (m_book, other.m_book);
514 qof_book_set_backend (other.m_book, mybackend);
519 QofSessionImpl::events_pending () const noexcept
525 QofSessionImpl::process_events () const noexcept
538 auto real_book = real_session.get_book ();
539 ENTER (
"tmp_session=%p real_session=%p book=%p uri=%s",
540 this, &real_session, real_book, m_uri.c_str ());
545 if (!m_backend)
return false;
547 m_backend->set_percentage(percentage_func);
549 m_backend->export_coa(real_book);
550 auto err = m_backend->get_error();
551 if (err != ERR_BACKEND_NO_ERR)
560 qof_session_get_error_message (
const QofSession * session)
562 if (!session)
return "";
563 return session->get_error_message ().c_str ();
570 return session->pop_error ();
576 if (!session)
return NULL;
577 return session->get_book ();
583 if (!session)
return nullptr;
584 auto& path{session->get_file_path()};
585 return path.empty() ? nullptr : path.c_str ();
591 if (session ==
nullptr)
return;
592 return session->ensure_all_data_loaded ();
596 qof_session_get_url (
const QofSession *session)
598 if (!session)
return NULL;
599 return session->get_uri ().c_str ();
605 if (!session)
return NULL;
606 return session->get_backend ();
612 if (!session)
return;
613 session->begin(uri, mode);
617 qof_session_load (QofSession *session,
620 if (!session)
return;
621 session->load (percentage_func);
628 if (!session)
return;
629 session->save (percentage_func);
635 if (!session)
return;
636 session->safe_save (percentage_func);
642 if (!session)
return false;
643 return session->is_saving ();
649 if (!session)
return;
656 if (session_1 == session_2)
return;
657 if (!session_1 || !session_2)
return;
658 session_1->swap_books (*session_2);
664 if (!session)
return false;
665 return session->events_pending ();
671 if (!session)
return FALSE;
672 return session->process_events ();
676 qof_session_export (QofSession *tmp_session,
677 QofSession *real_session,
680 if ((!tmp_session) || (!real_session))
return FALSE;
681 return tmp_session->export_session (*real_session, percentage_func);
686 void init_static_qofsession_pointers (
void);
688 void qof_session_load_backend (QofSession * session,
const char * access_method)
690 session->load_backend (access_method);
694 qof_session_clear_error (QofSession * session)
696 session->clear_error ();
700 qof_session_destroy_backend (QofSession * session)
702 session->destroy_backend ();
705 void qof_session_set_uri (QofSession * session,
char const * uri)
710 session->m_uri = uri;
713 void (*p_qof_session_load_backend) (QofSession *,
const char * access_method);
714 void (*p_qof_session_clear_error) (QofSession *);
715 void (*p_qof_session_destroy_backend) (QofSession *);
716 void (*p_qof_session_set_uri) (QofSession *,
char const * uri);
719 init_static_qofsession_pointers (
void)
721 p_qof_session_load_backend = &qof_session_load_backend;
722 p_qof_session_clear_error = &qof_session_clear_error;
723 p_qof_session_destroy_backend = &qof_session_destroy_backend;
724 p_qof_session_set_uri = &qof_session_set_uri;
731 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.