GnuCash  2.6.16
Files | Macros | Typedefs | Enumerations | Functions

Files

file  qofbackend.h
 API for data storage Backend.
 
file  qofsession.h
 Encapsulates a connection to a backend (persistent store)
 

Macros

#define QOF_MOD_BACKEND   "qof.backend"
 
#define QOF_MOD_SESSION   "qof.session"
 

Typedefs

typedef void(* QofBePercentageFunc) (const char *message, double percent)
 DOCUMENT ME!
 
typedef void(* QofPercentageFunc) (const char *message, double percent)
 

Enumerations

enum  QofBackendError {
  ERR_BACKEND_NO_ERR = 0, ERR_BACKEND_NO_HANDLER, ERR_BACKEND_NO_BACKEND, ERR_BACKEND_BAD_URL,
  ERR_BACKEND_NO_SUCH_DB, ERR_BACKEND_CANT_CONNECT, ERR_BACKEND_CONN_LOST, ERR_BACKEND_LOCKED,
  ERR_BACKEND_STORE_EXISTS, ERR_BACKEND_READONLY, ERR_BACKEND_TOO_NEW, ERR_BACKEND_DATA_CORRUPT,
  ERR_BACKEND_SERVER_ERR, ERR_BACKEND_ALLOC, ERR_BACKEND_PERM, ERR_BACKEND_MODIFIED,
  ERR_BACKEND_MOD_DESTROY, ERR_BACKEND_MISC, ERR_QOF_OVERFLOW, ERR_FILEIO_FILE_BAD_READ = 1000,
  ERR_FILEIO_FILE_EMPTY, ERR_FILEIO_FILE_LOCKERR, ERR_FILEIO_FILE_NOT_FOUND, ERR_FILEIO_FILE_TOO_OLD,
  ERR_FILEIO_UNKNOWN_FILE_TYPE, ERR_FILEIO_PARSE_ERROR, ERR_FILEIO_BACKUP_ERROR, ERR_FILEIO_WRITE_ERROR,
  ERR_FILEIO_READ_ERROR, ERR_FILEIO_NO_ENCODING, ERR_FILEIO_FILE_EACCES, ERR_FILEIO_RESERVED_WRITE,
  ERR_FILEIO_FILE_UPGRADE, ERR_NETIO_SHORT_READ = 2000, ERR_NETIO_WRONG_CONTENT_TYPE, ERR_NETIO_NOT_GNCXML,
  ERR_SQL_MISSING_DATA = 3000, ERR_SQL_DB_TOO_OLD, ERR_SQL_DB_TOO_NEW, ERR_SQL_DB_BUSY,
  ERR_SQL_BAD_DBI, ERR_SQL_DBI_UNTESTABLE, ERR_RPC_HOST_UNK = 4000, ERR_RPC_CANT_BIND,
  ERR_RPC_CANT_ACCEPT, ERR_RPC_NO_CONNECTION, ERR_RPC_BAD_VERSION, ERR_RPC_FAILED,
  ERR_RPC_NOT_ADDED
}
 The errors that can be reported to the GUI & other front-end users. More...
 

Functions

void qof_backend_set_error (QofBackend *be, QofBackendError err)
 
QofBackendError qof_backend_get_error (QofBackend *be)
 
gboolean qof_backend_check_error (QofBackend *be)
 
gboolean qof_load_backend_library (const gchar *directory, const gchar *module_name)
 Load a QOF-compatible backend shared library. More...
 
void qof_finalize_backend_libraries (void)
 Finalize all loaded backend sharable libraries.
 
QofBackend * qof_book_get_backend (const QofBook *book)
 Retrieve the backend used by this book.
 
void qof_book_set_backend (QofBook *book, QofBackend *)
 
QofSession * qof_session_new (void)
 
void qof_session_destroy (QofSession *session)
 
void qof_session_swap_data (QofSession *session_1, QofSession *session_2)
 
void qof_session_begin (QofSession *session, const char *book_id, gboolean ignore_lock, gboolean create, gboolean force)
 
void qof_session_load (QofSession *session, QofPercentageFunc percentage_func)
 
QofBook * qof_session_get_book (const QofSession *session)
 
const char * qof_session_get_file_path (const QofSession *session)
 
const char * qof_session_get_url (const QofSession *session)
 
gboolean qof_session_save_in_progress (const QofSession *session)
 
void qof_session_save (QofSession *session, QofPercentageFunc percentage_func)
 
void qof_session_safe_save (QofSession *session, QofPercentageFunc percentage_func)
 
void qof_session_end (QofSession *session)
 

Allow access to the begin routine for this backend.

void qof_backend_run_begin (QofBackend *be, QofInstance *inst)
 
gboolean qof_backend_begin_exists (const QofBackend *be)
 
void qof_backend_run_commit (QofBackend *be, QofInstance *inst)
 
gboolean qof_backend_commit_exists (const QofBackend *be)
 

Session Errors

QofBackendError qof_session_get_error (QofSession *session)
 
const char * qof_session_get_error_message (const QofSession *session)
 
QofBackendError qof_session_pop_error (QofSession *session)
 

Detailed Description

The QOF Backend is a pseudo-object providing an interface between the engine and a persistent data store (e.g. a server, a database, or a file). Backends are not meant to be used directly by an application; instead the Session should be used to make a connection with some particular backend. There are no backend functions that are 'public' to users of the engine. The backend can, however, report errors to the GUI & other front-end users. This file defines these errors.

Backends are used to save and restore Entities in a Book.

The QOF Session encapsulates a connection to a storage backend. That is, it manages the connection to a persistent data store; whereas the backend is the thing that performs the actual datastore access.

This class provides several important services:

1) It resolves and loads the appropriate backend, based on the URL.

2) It reports backend errors (e.g. network errors, storage corruption errors) through a single, backend-independent API.

3) It reports non-error events received from the backend.

4) It helps manage global dataset locks. For example, for the file backend, the lock prevents multiple users from editing the same file at the same time, thus avoiding lost data due to race conditions. Thus, an open session implies that the associated file is locked.

5) Misc utilities, such as a search path for the file to be edited, and/or other URL resolution utilities. This should simplify install & maintenance problems for naive users who may not have a good grasp on what a file system is, or where they want to keep their data files.

6) In the future, this class is probably a good place to manage a portion of the user authentication process, and hold user credentials/cookies/keys/tokens. This is because at the coarsest level, authorization can happen at the datastore level: i.e. does this user even have the authority to connect to and open this datastore?

A brief note about books & sessions: A book encapsulates the datasets manipulated by QOF. A book holds the actual data. By contrast, the session mediates the connection between a book (the thing that lives in virtual memory in the local process) and the datastore (the place where book data lives permanently, e.g., file, database).

In the current design, a session may hold multiple books. For now, exactly what this means is somewhat vague, and code in various places makes some implicit assumptions: first, only one book is 'current' and open for editing. Next, its assumed that all of the books in a session are related in some way. i.e. that they are all earlier accounting periods of the currently open book. In particular, the backends probably make that assumption, in order to store the different accounting periods in a clump so that one can be found, given another.

If you want multiple books that are unrelated to each other, use multiple sessions.

The session now calls QofBackendProvider->check_data_type to check that the incoming path contains data that the backend provider can open. The backend provider should also check if it can contact it's storage media (disk, network, server, etc.) and abort if it can't. Malformed file URL's would be handled the same way.

Typedef Documentation

◆ QofPercentageFunc

typedef 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. When the URL points at a file, then this routine would load the data from the file. With remote backends, e.g. network or SQL, this would load only enough data to make the book actually usable; it would not cause all of the data to be loaded.

XXX the current design tries to accommodate multiple calls to 'load' for each session, each time wiping out the old books; this seems wrong to me, and should be restricted to allow only one load per session.

Definition at line 168 of file qofsession.h.

Enumeration Type Documentation

◆ QofBackendError

The errors that can be reported to the GUI & other front-end users.

Warning
(GnuCash) If you modify QofBackendError, please update src/engine/gw-engine-spec.scm
Enumerator
ERR_BACKEND_NO_HANDLER 

no backend handler found for this access method (ENOSYS)

ERR_BACKEND_NO_BACKEND 

Backend * pointer was unexpectedly null

ERR_BACKEND_BAD_URL 

Can't parse url

ERR_BACKEND_NO_SUCH_DB 

the named database doesn't exist

ERR_BACKEND_CANT_CONNECT 

bad dbname/login/passwd or network failure

ERR_BACKEND_CONN_LOST 

Lost connection to server

ERR_BACKEND_LOCKED 

in use by another user (ETXTBSY)

ERR_BACKEND_STORE_EXISTS 

File exists, data would be destroyed

ERR_BACKEND_READONLY 

cannot write to file/directory

ERR_BACKEND_TOO_NEW 

file/db version newer than what we can read

ERR_BACKEND_DATA_CORRUPT 

data in db is corrupt

ERR_BACKEND_SERVER_ERR 

error in response from server

ERR_BACKEND_ALLOC 

internal memory allocation failure

ERR_BACKEND_PERM 

user login successful, but no permissions to access the desired object

ERR_BACKEND_MODIFIED 

commit of object update failed because another user has modified the object

ERR_BACKEND_MOD_DESTROY 

commit of object update failed because another user has deleted the object

ERR_BACKEND_MISC 

undetermined error

ERR_QOF_OVERFLOW 

EOVERFLOW - generated by strtol or strtoll.

When converting XML strings into numbers, an overflow has been detected. The XML file contains invalid data in a field that is meant to hold a signed long integer or signed long long integer.

ERR_FILEIO_FILE_BAD_READ 

read failed or file prematurely truncated

ERR_FILEIO_FILE_EMPTY 

file exists, is readable, but is empty

ERR_FILEIO_FILE_LOCKERR 

mangled locks (unspecified error)

ERR_FILEIO_FILE_NOT_FOUND 

not found / no such file

ERR_FILEIO_FILE_TOO_OLD 

file version so old we can't read it

ERR_FILEIO_UNKNOWN_FILE_TYPE 

didn't recognize the file type

ERR_FILEIO_PARSE_ERROR 

couldn't parse the data in the file

ERR_FILEIO_BACKUP_ERROR 

couldn't make a backup of the file

ERR_FILEIO_WRITE_ERROR 

couldn't write to the file

ERR_FILEIO_READ_ERROR 

Could not open the file for reading.

ERR_FILEIO_NO_ENCODING 

file does not specify encoding

ERR_FILEIO_FILE_EACCES 

No read access permission for the given file

ERR_FILEIO_RESERVED_WRITE 

User attempt to write to a directory reserved for internal use by GnuCash

ERR_FILEIO_FILE_UPGRADE 

file will be upgraded and not be able to be read by prior versions - warn users

ERR_NETIO_SHORT_READ 

not enough bytes received

ERR_NETIO_WRONG_CONTENT_TYPE 

wrong kind of server, wrong data served

ERR_NETIO_NOT_GNCXML 

whatever it is, we can't parse it.

ERR_SQL_MISSING_DATA 

database doesn't contain expected data

ERR_SQL_DB_TOO_OLD 

database is old and needs upgrading

ERR_SQL_DB_TOO_NEW 

database is newer, we can't write to it

ERR_SQL_DB_BUSY 

database is busy, cannot upgrade version

ERR_SQL_BAD_DBI 

LibDBI has numeric errors

ERR_SQL_DBI_UNTESTABLE 

could not complete test for LibDBI bug

ERR_RPC_HOST_UNK 

Host unknown

ERR_RPC_CANT_BIND 

can't bind to address

ERR_RPC_CANT_ACCEPT 

can't accept connection

ERR_RPC_NO_CONNECTION 

no connection to server

ERR_RPC_BAD_VERSION 

RPC Version Mismatch

ERR_RPC_FAILED 

Operation failed

ERR_RPC_NOT_ADDED 

object not added

Definition at line 55 of file qofbackend.h.

56 {
57  ERR_BACKEND_NO_ERR = 0,
86  /* fileio errors */
104  /* network errors */
105  ERR_NETIO_SHORT_READ = 2000,
109  /* database errors */
110  ERR_SQL_MISSING_DATA = 3000,
117  /* RPC errors */
118  ERR_RPC_HOST_UNK = 4000,
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:55

Function Documentation

◆ qof_backend_check_error()

gboolean qof_backend_check_error ( QofBackend *  be)

Report if the backend is in an error state. Since get_error resets the error state, its use for branching as the backend bubbles back up to the session would make the session think that there was no error.

Parameters
beThe backend being tested.
Returns
TRUE if the backend has an error set.

Definition at line 68 of file qofbackend.c.

69 {
70  g_return_val_if_fail (be != NULL, TRUE);
71  return be->last_err != ERR_BACKEND_NO_ERR;
72 }

◆ qof_backend_get_error()

QofBackendError qof_backend_get_error ( QofBackend *  be)

The qof_backend_get_error() routine pops an error code off the error stack.

Definition at line 56 of file qofbackend.c.

57 {
58  QofBackendError err;
59  if (!be) return ERR_BACKEND_NO_BACKEND;
60 
61  /* use 'stack-pop' semantics */
62  err = be->last_err;
63  be->last_err = ERR_BACKEND_NO_ERR;
64  return err;
65 }
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:55

◆ qof_backend_set_error()

void qof_backend_set_error ( QofBackend *  be,
QofBackendError  err 
)

The qof_backend_set_error() routine pushes an error code onto the error stack. (FIXME: the stack is 1 deep in current implementation).

Definition at line 46 of file qofbackend.c.

47 {
48  if (!be) return;
49 
50  /* use stack-push semantics. Only the earliest error counts */
51  if (ERR_BACKEND_NO_ERR != be->last_err) return;
52  be->last_err = err;
53 }

◆ qof_load_backend_library()

gboolean qof_load_backend_library ( const gchar *  directory,
const gchar *  module_name 
)

Load a QOF-compatible backend shared library.

Parameters
directoryCan be NULL if filename is a complete path.
module_nameName of the .la file that describes the shared library. This provides platform independence, courtesy of libtool.
Returns
FALSE in case or error, otherwise TRUE.

◆ qof_session_begin()

void qof_session_begin ( QofSession *  session,
const char *  book_id,
gboolean  ignore_lock,
gboolean  create,
gboolean  force 
)

The qof_session_begin () method begins a new session. It takes as an argument the book id. The book id must be a string in the form of a URI/URL. The access method specified depends on the loaded backends. Paths may be relative or absolute. If the path is relative; that is, if the argument is "file://somefile.xml" then the current working directory is assumed. Customized backends can choose to search other, application-specific, directories as well.

The 'ignore_lock' argument, if set to TRUE, will cause this routine to ignore any global-datastore locks (e.g. file locks) that it finds. If set to FALSE, then file/database-global locks will be tested and obeyed.

If the datastore exists, can be reached (e.g over the net), connected to, opened and read, and a lock can be obtained then a lock will be obtained. Note that while multi-user datastores (e.g. the SQL backend) typically will have record-level locking and therefor should not need to get a global lock, qof works by having a local copy of the whole database and can't be trusted to handle multiple users writing data, so we lock the database anyway.

If qof_session_begin is called with create == TRUE, then it will check for the existence of the file or database and return after posting a QOF_BACKEND_STORE_EXISTS error if it exists, unless force is also set to true.

If an error occurs, it will be pushed onto the session error stack, and that is where it should be examined.

Definition at line 421 of file qofsession.c.

423 {
424  gchar *scheme = NULL, *filename = NULL;
425 
426  if (!session) return;
427 
428  ENTER (" sess=%p ignore_lock=%d, book-id=%s",
429  session, ignore_lock,
430  book_id ? book_id : "(null)");
431 
432  /* Clear the error condition of previous errors */
433  qof_session_clear_error (session);
434 
435  /* Check to see if this session is already open */
436  if (session->book_id)
437  {
438  if (ERR_BACKEND_NO_ERR != qof_session_get_error(session))
439  qof_session_push_error (session, ERR_BACKEND_LOCKED, NULL);
440  LEAVE("push error book is already open ");
441  return;
442  }
443 
444  /* seriously invalid */
445  if (!book_id)
446  {
447  if (ERR_BACKEND_NO_ERR != qof_session_get_error(session))
448  qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL);
449  LEAVE("push error missing book_id");
450  return;
451  }
452  scheme = g_uri_parse_scheme (book_id);
453  if (g_strcmp0 (scheme, "file") == 0)
454  filename = g_filename_from_uri (book_id, NULL, NULL);
455  else if (!scheme)
456  filename = g_strdup (book_id);
457 
458  if (filename && g_file_test (filename, G_FILE_TEST_IS_DIR))
459  {
460  if (ERR_BACKEND_NO_ERR == qof_session_get_error(session))
461  qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL);
462  g_free (filename);
463  g_free (scheme);
464  LEAVE("Can't open a directory");
465  return;
466  }
467 
468 
469  /* destroy the old backend */
470  qof_session_destroy_backend(session);
471 
472  /* Store the session URL */
473  session->book_id = g_strdup (book_id);
474 
475  if (filename)
476  qof_session_load_backend(session, "file");
477  else /* access method found, load appropriate backend */
478  qof_session_load_backend(session, scheme);
479  g_free (filename);
480  g_free (scheme);
481 
482  /* No backend was found. That's bad. */
483  if (NULL == session->backend)
484  {
485  g_free(session->book_id);
486  session->book_id = NULL;
487  if (ERR_BACKEND_NO_ERR == qof_session_get_error(session))
488  qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL);
489  LEAVE (" BAD: no backend: sess=%p book-id=%s",
490  session, book_id ? book_id : "(null)");
491  return;
492  }
493 
494  /* If there's a begin method, call that. */
495  if (session->backend->session_begin)
496  {
497  char *msg;
498  int err;
499 
500  (session->backend->session_begin)(session->backend, session,
501  session->book_id, ignore_lock,
502  create, force);
503  PINFO("Done running session_begin on backend");
504  err = qof_backend_get_error(session->backend);
505  msg = qof_backend_get_message(session->backend);
506  if (err != ERR_BACKEND_NO_ERR)
507  {
508  g_free(session->book_id);
509  session->book_id = NULL;
510  qof_session_push_error (session, err, msg);
511  LEAVE(" backend error %d %s", err, msg ? msg : "(null)");
512  return;
513  }
514  if (msg != NULL)
515  {
516  PWARN("%s", msg);
517  g_free(msg);
518  }
519  }
520 
521  LEAVE (" sess=%p book-id=%s",
522  session, book_id ? book_id : "(null)");
523 }
char * qof_backend_get_message(QofBackend *be)
Definition: qofbackend.c:99
#define PINFO(format, args...)
Definition: qoflog.h:244
#define ENTER(format, args...)
Definition: qoflog.h:256
#define PWARN(format, args...)
Definition: qoflog.h:238
QofBackendError qof_session_get_error(QofSession *session)
Definition: qofsession.c:200
QofBackendError qof_backend_get_error(QofBackend *be)
Definition: qofbackend.c:56
#define LEAVE(format, args...)
Definition: qoflog.h:266

◆ qof_session_end()

void qof_session_end ( QofSession *  session)

The qof_session_end() method will release the session lock. For the file backend, it will not save the data to a file. Thus, this method acts as an "abort" or "rollback" primitive. However, for other backends, such as the sql backend, the data would have been written out before this, and so this routines wouldn't roll-back anything; it would just shut the connection.

Definition at line 809 of file qofsession.c.

810 {
811  if (!session) return;
812 
813  ENTER ("sess=%p book_id=%s", session, session->book_id
814  ? session->book_id : "(null)");
815 
816  /* close down the backend first */
817  if (session->backend && session->backend->session_end)
818  {
819  (session->backend->session_end)(session->backend);
820  }
821 
822  qof_session_clear_error (session);
823 
824  g_free (session->book_id);
825  session->book_id = NULL;
826 
827  LEAVE ("sess=%p book_id=%s", session, session->book_id
828  ? session->book_id : "(null)");
829 }
#define ENTER(format, args...)
Definition: qoflog.h:256
#define LEAVE(format, args...)
Definition: qoflog.h:266

◆ qof_session_get_book()

QofBook* qof_session_get_book ( const QofSession *  session)

Returns the QofBook of this session.

Definition at line 273 of file qofsession.c.

274 {
275  if (!session) return NULL;
276  if (!session->book) return NULL;
277 
278  if ('y' == session->book->book_open)
279  {
280  return session->book;
281  }
282  else
283  {
284  return NULL;
285  }
286 }

◆ qof_session_get_error()

QofBackendError qof_session_get_error ( QofSession *  session)

The qof_session_get_error() routine can be used to obtain the reason for any failure. Calling this routine returns the current error.

Definition at line 200 of file qofsession.c.

201 {
202  QofBackendError err;
203 
204  if (!session) return ERR_BACKEND_NO_BACKEND;
205 
206  /* if we have a local error, return that. */
207  if (ERR_BACKEND_NO_ERR != session->last_err)
208  {
209  return session->last_err;
210  }
211 
212  /* maybe we should return a no-backend error ??? */
213  if (! session->backend) return ERR_BACKEND_NO_ERR;
214 
215  err = qof_backend_get_error (session->backend);
216  session->last_err = err;
217  return err;
218 }
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:55
QofBackendError qof_backend_get_error(QofBackend *be)
Definition: qofbackend.c:56

◆ qof_session_get_file_path()

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. That is, if a relative or partial filename was for the session, then it had to have been fully resolved to open the session. This routine returns the result of this resolution. The path is always guaranteed to reside in the local file system, even if the session itself was opened as a URL. (currently, the filepath is derived from the url by substituting commas for slashes).

The qof_session_get_url() routine returns the url that was opened. URL's for local files take the form of file:/some/where/some/file.gml

Definition at line 296 of file qofsession.c.

297 {
298  if (!session) return NULL;
299  if (!session->backend) return NULL;
300  return session->backend->fullpath;
301 }

◆ qof_session_pop_error()

QofBackendError qof_session_pop_error ( QofSession *  session)

The qof_session_pop_error() routine can be used to obtain the reason for any failure. Calling this routine resets the error value.

This routine allows an implementation of multiple error values, e.g. in a stack, where this routine pops the top value. The current implementation has a stack that is one-deep.

See qofbackend.h for a listing of returned errors.

Definition at line 236 of file qofsession.c.

237 {
238  QofBackendError err;
239 
240  if (!session) return ERR_BACKEND_NO_BACKEND;
241 
242  err = qof_session_get_error(session);
243  qof_session_clear_error(session);
244 
245  return err;
246 }
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:55
QofBackendError qof_session_get_error(QofSession *session)
Definition: qofsession.c:200

◆ qof_session_safe_save()

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, then saves everything to new tables, then deletes the old tables after the save is completed without error. If there are errors, it removes the old tables and renames the new tables back.

Definition at line 781 of file qofsession.c.

782 {
783  QofBackend *be = session->backend;
784  gint err;
785  char *msg = NULL;
786  g_return_if_fail( be != NULL );
787  g_return_if_fail( be->safe_sync != NULL );
788  be->percentage = percentage_func;
789  (be->safe_sync)( be, qof_session_get_book( session ));
790  err = qof_backend_get_error(session->backend);
791  msg = qof_backend_get_message(session->backend);
792  if (err != ERR_BACKEND_NO_ERR)
793  {
794  g_free(session->book_id);
795  session->book_id = NULL;
796  qof_session_push_error (session, err, msg);
797  }
798 }
char * qof_backend_get_message(QofBackend *be)
Definition: qofbackend.c:99
QofBook * qof_session_get_book(const QofSession *session)
Definition: qofsession.c:273
QofBackendError qof_backend_get_error(QofBackend *be)
Definition: qofbackend.c:56

◆ qof_session_save()

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. For the file backend, this is nothing more than a write to the file of the current Accounts & etc. For the SQL backend, this is typically a no-op (since all data has already been written out to the database.

Todo:
check the access_method too, not in scope here, yet.

Definition at line 625 of file qofsession.c.

627 {
628  QofBackend *be;
629  gboolean partial, change_backend;
630  QofBackendProvider *prov;
631  GSList *p;
632  QofBook *book;
633  int err;
634  char *msg = NULL;
635  char *book_id;
636 
637  if (!session) return;
638  if (!g_atomic_int_dec_and_test(&session->lock))
639  goto leave;
640  ENTER ("sess=%p book_id=%s",
641  session, session->book_id ? session->book_id : "(null)");
642  /* Partial book handling. */
643  book = qof_session_get_book(session);
644  partial = (gboolean)GPOINTER_TO_INT(qof_book_get_data(book, PARTIAL_QOFBOOK));
645  change_backend = FALSE;
646  msg = g_strdup_printf(" ");
647  book_id = g_strdup(session->book_id);
648  if (partial == TRUE)
649  {
650  if (session->backend && session->backend->provider)
651  {
652  prov = session->backend->provider;
653  if (TRUE == prov->partial_book_supported)
654  {
655  /* if current backend supports partial, leave alone. */
656  change_backend = FALSE;
657  }
658  else
659  {
660  change_backend = TRUE;
661  }
662  }
663  /* If provider is undefined, assume partial not supported. */
664  else
665  {
666  change_backend = TRUE;
667  }
668  }
669  if (change_backend == TRUE)
670  {
671  qof_session_destroy_backend(session);
672  if (!qof_providers_initialized)
673  {
674  qof_providers_initialized = TRUE;
675  }
676  p = provider_list;
677  while (p != NULL)
678  {
679  prov = p->data;
680  if (TRUE == prov->partial_book_supported)
681  {
683  /* if((TRUE == prov->partial_book_supported) &&
684  (0 == g_ascii_strcasecmp (access_method, prov->access_method)))
685  {*/
686  if (NULL == prov->backend_new) continue;
687  /* Use the providers creation callback */
688  session->backend = (*(prov->backend_new))();
689  session->backend->provider = prov;
690  if (session->backend->session_begin)
691  {
692  /* Call begin - backend has been changed,
693  so make sure a file can be written,
694  use ignore_lock and force create */
695  g_free(session->book_id);
696  session->book_id = NULL;
697  (session->backend->session_begin)(session->backend, session,
698  book_id, TRUE, TRUE, TRUE);
699  PINFO("Done running session_begin on changed backend");
700  err = qof_backend_get_error(session->backend);
701  msg = qof_backend_get_message(session->backend);
702  if (err != ERR_BACKEND_NO_ERR)
703  {
704  g_free(session->book_id);
705  session->book_id = NULL;
706  qof_session_push_error (session, err, msg);
707  LEAVE("changed backend error %d", err);
708  goto leave;
709  }
710  if (msg != NULL)
711  {
712  PWARN("%s", msg);
713  g_free(msg);
714  msg = NULL;
715  }
716  }
717  /* Tell the book about the backend that they'll be using. */
718  qof_book_set_backend (session->book, session->backend);
719  p = NULL;
720  }
721  if (p)
722  {
723  p = p->next;
724  }
725  }
726  if (!session->backend)
727  {
728  if (ERR_BACKEND_NO_ERR != qof_session_get_error(session))
729  {
730  msg = g_strdup_printf("failed to load backend");
731  qof_session_push_error(session, ERR_BACKEND_NO_HANDLER, msg);
732  }
733  goto leave;
734  }
735  }
736  /* If there is a backend, and the backend is reachable
737  * (i.e. we can communicate with it), then synchronize with
738  * the backend. If we cannot contact the backend (e.g.
739  * because we've gone offline, the network has crashed, etc.)
740  * then give the user the option to save to the local disk.
741  *
742  * hack alert -- FIXME -- XXX the code below no longer
743  * does what the words above say. This needs fixing.
744  */
745  be = session->backend;
746  if (be)
747  {
748  /* if invoked as SaveAs(), then backend not yet set */
749  qof_book_set_backend (session->book, be);
750  be->percentage = percentage_func;
751  if (be->sync)
752  {
753  (be->sync)(be, session->book);
754  if (save_error_handler(be, session))
755  goto leave;
756  }
757 
758  /* If we got to here, then the backend saved everything
759  * just fine, and we are done. So return. */
760  /* Return the book_id to previous value. */
761  qof_session_clear_error (session);
762  LEAVE("Success");
763  goto leave;
764  }
765  else
766  {
767  if (ERR_BACKEND_NO_ERR != qof_session_get_error(session))
768  {
769  msg = g_strdup_printf("failed to load backend");
770  qof_session_push_error(session, ERR_BACKEND_NO_HANDLER, msg);
771  }
772  }
773  LEAVE("error -- No backend!");
774 leave:
775  if (msg != NULL) g_free(msg);
776  g_atomic_int_inc(&session->lock);
777  return;
778 }
char * qof_backend_get_message(QofBackend *be)
Definition: qofbackend.c:99
#define PINFO(format, args...)
Definition: qoflog.h:244
#define ENTER(format, args...)
Definition: qoflog.h:256
#define PWARN(format, args...)
Definition: qoflog.h:238
QofBook * qof_session_get_book(const QofSession *session)
Definition: qofsession.c:273
QofBackendError qof_session_get_error(QofSession *session)
Definition: qofsession.c:200
QofBackendError qof_backend_get_error(QofBackend *be)
Definition: qofbackend.c:56
#define LEAVE(format, args...)
Definition: qoflog.h:266
gpointer qof_book_get_data(const QofBook *book, const gchar *key)
#define PARTIAL_QOFBOOK
Flag indicating a partial QofBook.
Definition: qofreference.h:135

◆ qof_session_save_in_progress()

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 to long-term storage.

Definition at line 803 of file qofsession.c.

804 {
805  return (session && g_atomic_int_get(&session->lock) != 1);
806 }

◆ qof_session_swap_data()

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. It is useful for 'Save As' type functionality.

Definition at line 857 of file qofsession.c.

858 {
859  QofBook *book_1, *book_2;
860  gboolean tmp;
861 
862  if (session_1 == session_2) return;
863  if (!session_1 || !session_2) return;
864 
865  ENTER ("sess1=%p sess2=%p", session_1, session_2);
866 
867  book_1 = session_1->book;
868  book_2 = session_2->book;
869 
870  // Swap the read_only flags backwards.
871  tmp = book_1->read_only;
872  book_1->read_only = book_2->read_only;
873  book_2->read_only = tmp;
874 
875  session_1->book = book_2;
876  session_2->book = book_1;
877 
878  qof_book_set_backend (book_1, session_2->backend);
879  qof_book_set_backend (book_2, session_1->backend);
880 
881  LEAVE (" ");
882 }
#define ENTER(format, args...)
Definition: qoflog.h:256
#define LEAVE(format, args...)
Definition: qoflog.h:266