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" 61 #include <boost/algorithm/string.hpp> 67 using ProviderVec = std::vector<QofBackendProvider_ptr>;
68 static ProviderVec s_providers;
69 static const std::string empty_string{};
75 ProviderVec& get_providers (
void );
76 bool get_providers_initialized (
void );
85 get_providers_initialized (
void)
87 return !s_providers.empty();
93 s_providers.emplace_back(std::move(prov));
97 qof_backend_unregister_all_providers ()
107 std::for_each(s_providers.begin(), s_providers.end(),
108 [&list](QofBackendProvider_ptr& provider) {
109 gpointer method =
reinterpret_cast<gpointer
>(
const_cast<char*
>(provider->access_method));
110 list = g_list_prepend(list, method);
119 QofSessionImpl::QofSessionImpl (QofBook* book) noexcept
129 QofSessionImpl::~QofSessionImpl () noexcept
131 ENTER (
"sess=%p uri=%s",
this, m_uri.c_str ());
134 qof_book_set_backend (m_book,
nullptr);
137 LEAVE (
"sess=%p",
this);
141 qof_session_destroy (QofSession * session)
147 qof_session_new (QofBook* book)
153 QofSessionImpl::destroy_backend () noexcept
160 qof_book_set_backend (m_book,
nullptr);
167 QofSessionImpl::load_backend (std::string access_method) noexcept
169 std::ostringstream s;
170 s <<
" list=" << s_providers.size();
171 ENTER (
"%s", s.str().c_str());
172 for (
auto const & prov : s_providers)
174 if (!boost::iequals (access_method, prov->access_method))
176 PINFO (
"The provider providers access_method, %s, but we're loading for access_method, %s. Skipping.",
177 prov->access_method, access_method.c_str ());
180 PINFO (
" Selected provider %s", prov->provider_name);
183 if (!m_creating && !prov->type_check (m_uri.c_str ()))
185 PINFO(
"Provider, %s, reported not being usable for book, %s.",
186 prov->provider_name, m_uri.c_str ());
189 m_backend = prov->create_backend();
193 std::string msg {
"failed to get_backend using access method \"" + access_method +
"\""};
204 if (!m_uri.size ())
return;
205 ENTER (
"sess=%p uri=%s",
this, m_uri.c_str ());
218 qof_book_set_backend (m_book, m_backend);
226 m_backend->set_percentage(percentage_func);
227 m_backend->load (m_book, LOAD_TYPE_INITIAL_LOAD);
228 push_error (m_backend->get_error(), {});
231 auto err = get_error ();
232 if ((err != ERR_BACKEND_NO_ERR) &&
243 LEAVE (
"error from backend %d", get_error ());
247 LEAVE (
"sess = %p, uri=%s",
this, m_uri.c_str ());
255 ENTER (
" sess=%p mode=%d, URI=%s",
this, mode, new_uri);
260 if (ERR_BACKEND_NO_ERR != get_error ())
262 LEAVE(
"push error book is already open ");
269 if (ERR_BACKEND_NO_ERR != get_error ())
271 LEAVE(
"push error missing new_uri");
275 char * scheme {g_uri_parse_scheme (new_uri)};
276 char * filename {
nullptr};
277 if (g_strcmp0 (scheme,
"file") == 0)
280 filename = g_strdup (new_uri);
282 if (filename && g_file_test (filename, G_FILE_TEST_IS_DIR))
284 if (ERR_BACKEND_NO_ERR == get_error ())
288 LEAVE(
"Can't open a directory");
297 load_backend (
"file");
299 load_backend (scheme);
304 if (m_backend ==
nullptr)
307 if (ERR_BACKEND_NO_ERR == get_error ())
309 LEAVE (
" BAD: no backend: sess=%p book-id=%s",
315 m_backend->session_begin(
this, m_uri.c_str(), mode);
316 PINFO (
"Done running session_begin on backend");
318 auto msg (m_backend->get_message());
319 if (err != ERR_BACKEND_NO_ERR)
322 push_error (err, msg);
323 LEAVE (
" backend error %d %s", err, msg.empty() ?
"(null)" : msg.c_str());
328 PWARN(
"%s", msg.c_str());
331 LEAVE (
" sess=%p book-id=%s",
this, new_uri);
337 ENTER (
"sess=%p uri=%s",
this, m_uri.c_str ());
339 if (backend !=
nullptr)
340 backend->session_end();
343 LEAVE (
"sess=%p uri=%s",
this, m_uri.c_str ());
349 QofSessionImpl::clear_error () noexcept
351 m_last_err = ERR_BACKEND_NO_ERR;
352 m_error_message = {};
359 err = backend->get_error();
360 while (err != ERR_BACKEND_NO_ERR);
365 QofSessionImpl::push_error (
QofBackendError const err, std::string message) noexcept
368 m_error_message = message;
375 if (m_last_err != ERR_BACKEND_NO_ERR)
378 if (qof_be ==
nullptr)
return ERR_BACKEND_NO_ERR;
380 m_last_err = qof_be->get_error();
385 QofSessionImpl::get_error_message () const noexcept
387 return m_error_message;
391 QofSessionImpl::pop_error () noexcept
401 QofSessionImpl::get_book () const noexcept
403 if (!m_book)
return nullptr;
404 if (
'y' == m_book->book_open)
410 QofSession::get_backend () const noexcept
416 QofSessionImpl::get_file_path () const noexcept
419 if (!backend)
return empty_string;
420 return backend->get_uri();
430 QofSessionImpl::is_saving () const noexcept
443 ENTER (
"sess=%p uri=%s",
this, m_uri.c_str ());
455 qof_book_set_backend (m_book, m_backend);
456 m_backend->set_percentage(percentage_func);
457 m_backend->sync(m_book);
458 auto err = m_backend->get_error();
459 if (err != ERR_BACKEND_NO_ERR)
461 push_error (err, {});
473 LEAVE(
"error -- No backend!");
481 if (!(m_backend && m_book))
return;
483 qof_book_set_backend (m_book, m_backend);
484 m_backend->set_percentage(percentage_func);
485 m_backend->safe_sync(get_book ());
486 auto err = m_backend->get_error();
487 auto msg = m_backend->get_message();
488 if (err != ERR_BACKEND_NO_ERR)
491 push_error (err, msg);
496 QofSessionImpl::ensure_all_data_loaded () noexcept
498 if (!(m_backend && m_book))
return;
500 qof_book_set_backend (m_book, m_backend);
501 m_backend->
load(m_book, LOAD_TYPE_LOAD_ALL);
508 ENTER (
"sess1=%p sess2=%p",
this, &other);
510 if (m_book && other.m_book)
511 std::swap (m_book->read_only, other.m_book->read_only);
512 std::swap (m_book, other.m_book);
515 qof_book_set_backend (other.m_book, mybackend);
520 QofSessionImpl::events_pending () const noexcept
526 QofSessionImpl::process_events () const noexcept
539 auto real_book = real_session.get_book ();
540 ENTER (
"tmp_session=%p real_session=%p book=%p uri=%s",
541 this, &real_session, real_book, m_uri.c_str ());
546 if (!m_backend)
return false;
548 m_backend->set_percentage(percentage_func);
550 m_backend->export_coa(real_book);
551 auto err = m_backend->get_error();
552 if (err != ERR_BACKEND_NO_ERR)
561 qof_session_get_error_message (
const QofSession * session)
563 if (!session)
return "";
564 return session->get_error_message ().c_str ();
571 return session->pop_error ();
577 if (!session)
return NULL;
578 return session->get_book ();
584 if (!session)
return nullptr;
585 auto& path{session->get_file_path()};
586 return path.empty() ? nullptr : path.c_str ();
592 if (session ==
nullptr)
return;
593 return session->ensure_all_data_loaded ();
597 qof_session_get_url (
const QofSession *session)
599 if (!session)
return NULL;
600 return session->get_uri ().c_str ();
606 if (!session)
return NULL;
607 return session->get_backend ();
613 if (!session)
return;
614 session->begin(uri, mode);
618 qof_session_load (QofSession *session,
621 if (!session)
return;
622 session->load (percentage_func);
629 if (!session)
return;
630 session->save (percentage_func);
636 if (!session)
return;
637 session->safe_save (percentage_func);
643 if (!session)
return false;
644 return session->is_saving ();
650 if (!session)
return;
657 if (session_1 == session_2)
return;
658 if (!session_1 || !session_2)
return;
659 session_1->swap_books (*session_2);
665 if (!session)
return false;
666 return session->events_pending ();
672 if (!session)
return FALSE;
673 return session->process_events ();
677 qof_session_export (QofSession *tmp_session,
678 QofSession *real_session,
681 if ((!tmp_session) || (!real_session))
return FALSE;
682 return tmp_session->export_session (*real_session, percentage_func);
687 void init_static_qofsession_pointers (
void);
689 void qof_session_load_backend (QofSession * session,
const char * access_method)
691 session->load_backend (access_method);
695 qof_session_clear_error (QofSession * session)
697 session->clear_error ();
701 qof_session_destroy_backend (QofSession * session)
703 session->destroy_backend ();
706 void qof_session_set_uri (QofSession * session,
char const * uri)
711 session->m_uri = uri;
714 void (*p_qof_session_load_backend) (QofSession *,
const char * access_method);
715 void (*p_qof_session_clear_error) (QofSession *);
716 void (*p_qof_session_destroy_backend) (QofSession *);
717 void (*p_qof_session_set_uri) (QofSession *,
char const * uri);
720 init_static_qofsession_pointers (
void)
722 p_qof_session_load_backend = &qof_session_load_backend;
723 p_qof_session_clear_error = &qof_session_clear_error;
724 p_qof_session_destroy_backend = &qof_session_destroy_backend;
725 p_qof_session_set_uri = &qof_session_set_uri;
732 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
gchar * gnc_uri_get_path(const gchar *uri)
Extracts the path part from a uri.
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.
Utility functions for convert uri in separate components and back.
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.