QOF: Session: Backend connections.

QOF 0.7.5

Files | Macros | Typedefs | Functions
Session: Backend connections.
Query Object Framework » Backends: Permanent storage for QOF entities.

## Files
file | qofsession.h
| Encapsulates a connection to a backend (persistent store)

## Macros
#define | QOF_MOD_SESSION "qof-session"
#define | QOF_STDOUT "file:"
| Allow session data to be printed to stdout. More...

## Typedefs
typedef struct _QofSession | QofSession
typedef void(* | QofPercentageFunc) (const gchar *message, gdouble percent)

## Functions
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 gchar *book_id, gboolean ignore_lock, gboolean create_if_nonexistent)
void | qof_session_load (QofSession *session, QofPercentageFunc percentage_func)
void | qof_session_add_book (QofSession *session, QofBook *book)
QofBook * | qof_session_get_book (QofSession *session)
const gchar * | qof_session_get_file_path (QofSession *session)
const gchar * | qof_session_get_url (QofSession *session)
gboolean | qof_session_not_saved (QofSession *session)
gboolean | qof_session_save_may_clobber_data (QofSession *session)
void | qof_session_save (QofSession *session, QofPercentageFunc percentage_func)
void | qof_session_end (QofSession *session)
void | qof_session_add_close_hook (GFunc fn, gpointer data)
void | qof_session_call_close_hooks (QofSession *session)

## Copying entities between sessions.
Only certain backends can cope with selective copying of entities and only fully defined QOF entities can be copied between sessions - see the QOF Serialisation Format (QSF) documentation (::qsf_write_file) for more information. The recommended backend for the new session is QSF or a future SQL backend. Using any of these entity copy functions sets a flag in the backend that this is now a partial QofBook. See Reference: Referring to entities outside a partial book.. When you save a session containing a partial QofBook, the session will check that the backend is able to handle the partial book. If not, the backend will be replaced by one that can handle partial books, preferably one using the same ::access_method. Currently, this means that a book using the GnuCash XML v2 file backend will be switched to QSF. Copied entities are identical to the source entity, all parameters defined with QofAccessFunc and QofSetterFunc in QOF are copied and the ::GUID of the original QofEntity is set in the new entity. Sessions containing copied entities are intended for use as mechanisms for data export. It is acceptable to add entities to new_session in batches. Note that any of these calls will fail if an entity already exists in new_session with the same GUID as any entity to be copied. To merge a whole QofBook or where there is any possibility of collisions or requirement for user intervention, see Merge: Merging QofBook structures
gboolean | qof_entity_copy_to_session (QofSession *new_session, QofEntity *original)
| Copy a single QofEntity to another session. More...
gboolean | qof_entity_copy_list (QofSession *new_session, GList *entity_list)
| Copy a GList of entities to another session. More...
gboolean | qof_entity_copy_coll (QofSession *new_session, QofCollection *entity_coll)
| Copy a QofCollection of entities. More...
gboolean | qof_entity_copy_coll_r (QofSession *new_session, QofCollection *coll)
| Recursively copy a collection of entities to a session. More...
gboolean | qof_entity_copy_one_r (QofSession *new_session, QofEntity *ent)
| Recursively copy a single entity to a new session. More...

## Event Handling
gboolean | qof_session_events_pending (QofSession *session)
gboolean | qof_session_process_events (QofSession *session)

## Detailed Description

The QOF Session encapsulates a connection to a storage backend. That is, it manages the connection to a persistant 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.

## Macro Definition Documentation

## ◆ QOF_STDOUT

#define QOF_STDOUT "file:"

Allow session data to be printed to stdout.

book_id can't be NULL and we do need to have an access_method, so use one to solve the other.

To print a session to stdout, use qof_session_begin. Example:

qof_session_begin(session,QOF_STDOUT,TRUE,FALSE);

When you call qof_session_save(session, NULL), the output will appear on stdout and can be piped or redirected to other processes.

Currently, only the QSF backend supports writing to stdout, other backends may return a ::QofBackendError.

Definition at line 385 of file qofsession.h.

## Typedef Documentation

## ◆ QofPercentageFunc

typedef void(* QofPercentageFunc) (const gchar *message, gdouble 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 accomodate 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.

## Function Documentation

## ◆ qof_entity_copy_coll()

gboolean qof_entity_copy_coll | ( | QofSession * | new_session,
|  | QofCollection * | entity_coll
| ) |  |

Copy a QofCollection of entities.

The QofBook in the new_session must not contain any entities with the same GUID as any entities in the collection - there is no support for handling collisions - instead, use Merge: Merging QofBook structures

Parameters

  new_session | - the target session
  entity_coll | - a QofCollection of any QofIdType.

Returns
  FALSE, without copying, if new_session contains any entities with the same GUID. Otherwise TRUE.

Definition at line 710 of file qofsession.c.

712 {
713 QofEntityCopyData qecd;
714
715 g_return_val_if_fail (new_session, FALSE);
716 if (!entity_coll)
717 {
718 return FALSE;
719 }
720 qof_event_suspend ();
721 qecd.param_list = NULL;
722 qecd.new_session = new_session;
723 qof_book_set_partial (qof_session_get_book (qecd.new_session));
724 qof_collection_foreach (entity_coll, qof_entity_coll_foreach, &qecd);
725 qof_class_param_foreach (qof_collection_get_type (entity_coll),
726 qof_entity_param_cb, &qecd);
727 qof_collection_foreach (entity_coll, qof_entity_coll_copy, &qecd);
728 if (qecd.param_list != NULL)
729 {
730 g_slist_free (qecd.param_list);
731 }
732 qof_event_resume ();
733 return TRUE;
734 }
qof_class_param_foreach
void qof_class_param_foreach(QofIdTypeConst obj_name, QofParamForeachCB cb, gpointer user_data)
Definition: qofclass.c:267
qof_collection_foreach
void qof_collection_foreach(QofCollection *col, QofEntityForeachCB cb_func, gpointer user_data)
Definition: qofid.c:421
qof_collection_get_type
QofIdType qof_collection_get_type(QofCollection *col)
Definition: qofid.c:175
qof_event_suspend
void qof_event_suspend(void)
Suspend all engine events.
Definition: qofevent.c:189
qof_event_resume
void qof_event_resume(void)
Definition: qofevent.c:200

## ◆ qof_entity_copy_coll_r()

gboolean qof_entity_copy_coll_r | ( | QofSession * | new_session,
|  | QofCollection * | coll
| ) |  |

Recursively copy a collection of entities to a session.

Note
  This function creates a partial QofBook. See qof_entity_copy_to_session for more information.

The QofBook in the new_session must not contain any entities with the same GUID as any entities to be copied - there is no support for handling collisions - instead, use Merge: Merging QofBook structures

Objects can be defined solely in terms of QOF data types or as a mix of data types and other objects, which may in turn include other objects. These references can be copied recursively down to the third level. See QofEntityReference.

Note
  This is a deep recursive copy - every referenced entity is copied to the new session, including all parameters. The starting point is all entities in the top level collection. It can take some time.

Parameters

  coll | A QofCollection of entities that may or may not have references.
  new_session | The QofSession to receive the copied entities.

Returns
  TRUE on success; if any individual copy fails, returns FALSE. Note : Some entities may have been copied successfully even if one of the references fails to copy.

Definition at line 884 of file qofsession.c.

885 {
886 struct recurse_s store;
887 gboolean success;
888
889 if ((!new_session) || (!coll))
890 {
891 return FALSE;
892 }
893 store.session = new_session;
894 success = TRUE;
895 store.success = success;
896 store.ent_list = NULL;
897 store.ref_list =
898 qof_class_get_referenceList (qof_collection_get_type (coll));
899 success = qof_entity_copy_coll (new_session, coll);
900 if (success)
901 {
902 qof_collection_foreach (coll, recurse_ent_cb, &store);
903 }
904 return success;
905 }
recurse_ent_cb
static void recurse_ent_cb(QofEntity *ent, gpointer user_data)
Definition: qofsession.c:766
qof_entity_copy_coll
gboolean qof_entity_copy_coll(QofSession *new_session, QofCollection *entity_coll)
Copy a QofCollection of entities.
Definition: qofsession.c:710
qof_collection_foreach
void qof_collection_foreach(QofCollection *col, QofEntityForeachCB cb_func, gpointer user_data)
Definition: qofid.c:421
qof_class_get_referenceList
GList * qof_class_get_referenceList(QofIdTypeConst type)
List of the parameters that could be references.
Definition: qofclass.c:332
qof_collection_get_type
QofIdType qof_collection_get_type(QofCollection *col)
Definition: qofid.c:175

## ◆ qof_entity_copy_list()

gboolean qof_entity_copy_list | ( | QofSession * | new_session,
|  | GList * | entity_list
| ) |  |

Copy a GList of entities to another session.

The QofBook in the new_session must not contain any entities with the same GUID as any of the source entities - there is no support for handling collisions, instead use Merge: Merging QofBook structures

Note that the GList (e.g. from qof_sql_query_run) can contain QofEntity pointers of any QofIdType, in any sequence. As long as all members of the list are QofEntity*, and all GUID's are unique, the list can be copied.

Parameters

  new_session | - the target session
  entity_list | - a GList of QofEntity pointers of any type(s).

Returns
  FALSE, without copying, if new_session contains any entities with the same GUID. Otherwise TRUE.

Definition at line 688 of file qofsession.c.

689 {
690 QofEntityCopyData *qecd;
691
692 if (!new_session || !entity_list)
693 return FALSE;
694 ENTER (" list=%d", g_list_length (entity_list));
695 qecd = g_new0 (QofEntityCopyData, 1);
696 qof_event_suspend ();
697 qecd->param_list = NULL;
698 qecd->new_session = new_session;
699 qof_book_set_partial (qof_session_get_book (new_session));
700 g_list_foreach (entity_list, qof_entity_list_foreach, qecd);
701 qof_event_resume ();
702 if (qecd->error)
703 PWARN (" some/all entities in the list could not be copied.");
704 g_free (qecd);
705 LEAVE (" ");
706 return TRUE;
707 }
LEAVE
#define LEAVE(format, args...)
Definition: qoflog.h:227
PWARN
#define PWARN(format, args...)
Definition: qoflog.h:191
qof_event_suspend
void qof_event_suspend(void)
Suspend all engine events.
Definition: qofevent.c:189
qof_event_resume
void qof_event_resume(void)
Definition: qofevent.c:200
ENTER
#define ENTER(format, args...)
Definition: qoflog.h:217

## ◆ qof_entity_copy_one_r()

gboolean qof_entity_copy_one_r | ( | QofSession * | new_session,
|  | QofEntity * | ent
| ) |  |

Recursively copy a single entity to a new session.

Copy the single entity and all referenced entities to the second level.

Only entities that are directly referenced by the top level entity are copied.

This is a deep copy - all parameters of all referenced entities are copied. If the top level entity has no references, this is identical to qof_entity_copy_to_session.

Parameters

  ent | A single entity that may or may not have references.
  new_session | The QofSession to receive the copied entities.

Returns
  TRUE on success; if any individual copy fails, returns FALSE. Note : Some entities may have been copied successfully even if one of the references fails to copy.

Definition at line 908 of file qofsession.c.

909 {
910 struct recurse_s store;
911 QofCollection *coll;
912 gboolean success;
913
914 if ((!new_session) || (!ent))
915 {
916 return FALSE;
917 }
918 store.session = new_session;
919 success = TRUE;
920 store.success = success;
921 store.ref_list = qof_class_get_referenceList (ent->e_type);
922 success = qof_entity_copy_to_session (new_session, ent);
923 if (success == TRUE)
924 {
925 coll =
926 qof_book_get_collection (qof_session_get_book (new_session),
927 ent->e_type);
928 if (coll)
929 {
930 qof_collection_foreach (coll, recurse_ent_cb, &store);
931 }
932 }
933 return success;
934 }
recurse_ent_cb
static void recurse_ent_cb(QofEntity *ent, gpointer user_data)
Definition: qofsession.c:766
qof_book_get_collection
QofCollection * qof_book_get_collection(QofBook *book, QofIdType entity_type)
Definition: qofbook.c:220
QofCollection
struct QofCollection_s QofCollection
Definition: qofid.h:138
qof_collection_foreach
void qof_collection_foreach(QofCollection *col, QofEntityForeachCB cb_func, gpointer user_data)
Definition: qofid.c:421
qof_entity_copy_to_session
gboolean qof_entity_copy_to_session(QofSession *new_session, QofEntity *original)
Copy a single QofEntity to another session.
Definition: qofsession.c:656
qof_class_get_referenceList
GList * qof_class_get_referenceList(QofIdTypeConst type)
List of the parameters that could be references.
Definition: qofclass.c:332

## ◆ qof_entity_copy_to_session()

gboolean qof_entity_copy_to_session | ( | QofSession * | new_session,
|  | QofEntity * | original
| ) |  |

Copy a single QofEntity to another session.

Checks first that no entity in the session book contains the GUID of the source entity.

Parameters

  new_session | - the target session
  original | - the QofEntity* to copy

Returns
  FALSE without copying if the session contains an entity with the same GUID already, otherwise TRUE.

Definition at line 656 of file qofsession.c.

657 {
658 QofEntityCopyData qecd;
659 QofInstance *inst;
660 QofBook *book;
661
662 if (!new_session || !original)
663 return FALSE;
664 if (qof_entity_guid_match (new_session, original))
665 return FALSE;
666 if (!qof_object_compliance (original->e_type, TRUE))
667 return FALSE;
668 qof_event_suspend ();
669 qecd.param_list = NULL;
670 book = qof_session_get_book (new_session);
671 qecd.new_session = new_session;
672 qof_book_set_partial (book);
673 inst =
674 (QofInstance *) qof_object_new_instance (original->e_type, book);
675 qecd.to = &inst->entity;
676 qecd.from = original;
677 qof_entity_set_guid (qecd.to, qof_entity_get_guid (original));
678 qof_class_param_foreach (original->e_type, qof_entity_param_cb, &qecd);
679 if (g_slist_length (qecd.param_list) == 0)
680 return FALSE;
681 g_slist_foreach (qecd.param_list, qof_entity_foreach_copy, &qecd);
682 g_slist_free (qecd.param_list);
683 qof_event_resume ();
684 return TRUE;
685 }
qof_object_new_instance
gpointer qof_object_new_instance(QofIdTypeConst type_name, QofBook *book)
Definition: qofobject.c:42
qof_entity_foreach_copy
static void qof_entity_foreach_copy(gpointer data, gpointer user_data)
Definition: qofsession.c:299
QofInstance_s
Definition: qofinstance-p.h:35
qof_class_param_foreach
void qof_class_param_foreach(QofIdTypeConst obj_name, QofParamForeachCB cb, gpointer user_data)
Definition: qofclass.c:267
qof_object_compliance
gboolean qof_object_compliance(QofIdTypeConst type_name, gboolean warn)
check an object can be created and supports iteration
Definition: qofobject.c:155
QofInstance_s::entity
QofEntity entity
Definition: qofinstance-p.h:38
qof_event_suspend
void qof_event_suspend(void)
Suspend all engine events.
Definition: qofevent.c:189
qof_entity_get_guid
const GUID * qof_entity_get_guid(QofEntity *ent)
Definition: qofid.c:105
qof_event_resume
void qof_event_resume(void)
Definition: qofevent.c:200
qof_entity_set_guid
void qof_entity_set_guid(QofEntity *ent, const GUID *guid)
Definition: qofid.c:92
_QofBook
Definition: qofbook-p.h:48

## ◆ qof_session_add_book()

void qof_session_add_book | ( | QofSession * | session,
|  | QofBook * | book
| ) |  |

The qof_session_add_book() allows additional books to be added to a session. XXX Under construction, clarify the following when done: XXX There must already be an open book in the session already!? XXX Only one open book at a time per session is allowed!? XXX each book gets its own unique backend ???

Definition at line 148 of file qofsession.c.

149 {
150 GList *node;
151 if (!session)
152 return;
153
154 ENTER (" sess=%p book=%p", session, addbook);
155
156 /* See if this book is already there ... */
157 for (node = session->books; node; node = node->next)
158 {
159 QofBook *book = node->data;
160 if (addbook == book)
161 return;
162 }
163
164 if ('y' == addbook->book_open)
165 {
166 /* hack alert -- someone should free all the books in the list,
167 * but it should probably not be us ... since the books backends
168 * should be shutdown first, etc */
169 /* XXX this should probably be an error XXX */
170 g_list_free (session->books);
171 session->books = g_list_append (NULL, addbook);
172 }
173 else
174 {
175 /* XXX Need to tell the backend to add a book as well */
176 session->books = g_list_append (session->books, addbook);
177 }
178
179 qof_book_set_backend (addbook, session->backend);
180 LEAVE (" ");
181 }
LEAVE
#define LEAVE(format, args...)
Definition: qoflog.h:227
qof_book_set_backend
void qof_book_set_backend(QofBook *book, QofBackend *)
Set the backend used by this book.
Definition: qofbook.c:170
_QofBook
Definition: qofbook-p.h:48
ENTER
#define ENTER(format, args...)
Definition: qoflog.h:217

## ◆ qof_session_add_close_hook()

void qof_session_add_close_hook | ( | GFunc | fn,
|  | gpointer | data
| ) |  |

Register a function to be called just before a session is closed.

Parameters

  fn | The function to be called. The function definition must be func(gpointer session, gpointer user_data);
  data | The data to be passed to the function.

Definition at line 69 of file qofsession.c.

70 {
71 GHook *hook;
72
73 if (session_closed_hooks == NULL)
74 {
75 session_closed_hooks = malloc (sizeof (GHookList)); /* LEAKED */
76 g_hook_list_init (session_closed_hooks, sizeof (GHook));
77 }
78
79 hook = g_hook_alloc (session_closed_hooks);
80 if (!hook)
81 return;
82
83 hook->func = (GHookFunc) fn;
84 hook->data = data;
85 g_hook_append (session_closed_hooks, hook);
86 }

## ◆ qof_session_begin()

void qof_session_begin | ( | QofSession * | session,
|  | const gchar * | book_id,
|  | gboolean | ignore_lock,
|  | gboolean | create_if_nonexistent
| ) |  |

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. In the absence of a customised backend, only QSF XML would be accepted). 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. Customised 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 multi-user datastores (e.g. the SQL backend) typically will not need to get a global lock, and thus, the user will not be locked out. That's the whole point of 'multi-user'.

If the file/database doesn't exist, and the create_if_nonexistent flag is set to TRUE, then the database is created.

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

Definition at line 1057 of file qofsession.c.

1059 {
1060 gchar *p, *access_method;
1061
1062 if (!session)
1063 return;
1064
1065 ENTER (" sess=%p ignore_lock=%d, book-id=%s",
1066 session, ignore_lock, book_id ? book_id : "(null)");
1067
1068 /* Clear the error condition of previous errors */
1069 qof_error_clear (session);
1070
1071 /* Check to see if this session is already open */
1072 if (session->book_id)
1073 {
1074 qof_error_set (session, qof_error_register
1075 (_("This book appears to be open already."), FALSE));
1076 LEAVE (" push error book is already open ");
1077 return;
1078 }
1079
1080 if (!book_id)
1081 {
1082 LEAVE (" using stdout");
1083 return;
1084 }
1085
1086 /* Store the session URL */
1087 session->book_id = g_strdup (book_id);
1088
1089 /* destroy the old backend */
1090 qof_session_destroy_backend (session);
1091
1092 /* Look for something of the form of "file:/", "http://" or
1093 * "postgres://". Everything before the colon is the access
1094 * method. Load the first backend found for that access method.
1095 */
1096 p = strchr (book_id, ':');
1097 if (p)
1098 {
1099 access_method = g_strdup (book_id);
1100 p = strchr (access_method, ':');
1101 *p = 0;
1102 qof_session_load_backend (session, access_method);
1103 g_free (access_method);
1104 }
1105 else
1106 {
1107 /* If no colon found, assume it must be a file-path */
1108 qof_session_load_backend (session, "file");
1109 }
1110
1111 /* No backend was found. That's bad. */
1112 if (NULL == session->backend)
1113 {
1114 gchar * msg;
1115
1116 msg = g_strdup_printf (_("Unable to locate a "
1117 "suitable backend for '%s' - please check "
1118 "you have specified an access method "
1119 "like file: or sqlite:"), book_id);
1120 qof_error_set (session, qof_error_register
1121 (msg, FALSE));
1122 DEBUG (" msg=%s", msg);
1123 LEAVE (" BAD: no backend: sess=%p book-id=%s",
1124 session, book_id ? book_id : "(null)");
1125 g_free (msg);
1126 return;
1127 }
1128
1129 /* If there's a begin method, call that. */
1130 if (session->backend->session_begin)
1131 {
1132 (session->backend->session_begin) (session->backend, session,
1133 session->book_id, ignore_lock, create_if_nonexistent);
1134 PINFO (" Done running session_begin on backend");
1135 if (qof_error_check(session) != QOF_SUCCESS)
1136 {
1137 g_free (session->book_id);
1138 session->book_id = NULL;
1139 LEAVE (" backend error ");
1140 return;
1141 }
1142 }
1143 qof_error_clear (session);
1144 LEAVE (" sess=%p book-id=%s", session, book_id ? book_id : "(null)");
1145 }
qof_error_register
QofErrorId qof_error_register(const gchar *err_message, gboolean use_file)
Generate and register a new error.
Definition: qoferror.c:91
PINFO
#define PINFO(format, args...)
Definition: qoflog.h:199
qof_error_check
QofErrorId qof_error_check(QofSession *session)
Definition: qoferror.c:227
LEAVE
#define LEAVE(format, args...)
Definition: qoflog.h:227
qof_error_set
void qof_error_set(QofSession *session, QofErrorId error)
Add an error to the stack for this session.
Definition: qoferror.c:133
QOF_SUCCESS
#define QOF_SUCCESS
Definition: qoferror.h:124
DEBUG
#define DEBUG(format, args...)
Definition: qoflog.h:208
qof_error_clear
void qof_error_clear(QofSession *session)
clear the error stack for the session.
Definition: qoferror.c:209
ENTER
#define ENTER(format, args...)
Definition: qoflog.h:217

## ◆ qof_session_call_close_hooks()

void qof_session_call_close_hooks | ( | QofSession * | session | ) |

Call all registered session close hooks, informing them that the specified session is about to be closed.

Parameters

  session | A pointer to the session being closed.

Definition at line 89 of file qofsession.c.

90 {
91 GHook *hook;
92 GFunc fn;
93
94 if (session_closed_hooks == NULL)
95 return;
96
97 hook = g_hook_first_valid (session_closed_hooks, FALSE);
98 while (hook)
99 {
100 fn = (GFunc) hook->func;
101 fn (session, hook->data);
102 hook = g_hook_next_valid (session_closed_hooks, hook, FALSE);
103 }
104 }

## ◆ 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 1399 of file qofsession.c.

1400 {
1401 if (!session)
1402 return;
1403
1404 ENTER (" sess=%p book_id=%s", session, session->book_id
1405 ? session->book_id : "(null)");
1406
1407 /* close down the backend first */
1408 if (session->backend && session->backend->session_end)
1409 {
1410 (session->backend->session_end) (session->backend);
1411 }
1412
1413 qof_error_clear (session);
1414
1415 g_free (session->book_id);
1416 session->book_id = NULL;
1417
1418 LEAVE (" sess=%p book_id=%s", session, session->book_id
1419 ? session->book_id : "(null)");
1420 }
LEAVE
#define LEAVE(format, args...)
Definition: qoflog.h:227
qof_error_clear
void qof_error_clear(QofSession *session)
clear the error stack for the session.
Definition: qoferror.c:209
ENTER
#define ENTER(format, args...)
Definition: qoflog.h:217

## ◆ qof_session_events_pending()

gboolean qof_session_events_pending | ( | QofSession * | session | ) |

The qof_session_events_pending() method will return TRUE if the backend has pending events which must be processed to bring the engine up to date with the backend.

Definition at line 1492 of file qofsession.c.

1493 {
1494 if (!session)
1495 return FALSE;
1496 if (!session->backend)
1497 return FALSE;
1498 if (!session->backend->events_pending)
1499 return FALSE;
1500
1501 return session->backend->events_pending (session->backend);
1502 }

## ◆ qof_session_get_file_path()

const gchar* qof_session_get_file_path | ( | 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 192 of file qofsession.c.

193 {
194 if (!session)
195 return NULL;
196 if (!session->backend)
197 return NULL;
198 return session->backend->fullpath;
199 }
QofBackend_s::fullpath
gchar * fullpath
Definition: qofbackend-p.h:338

## ◆ qof_session_not_saved()

gboolean qof_session_not_saved | ( | 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.

## ◆ qof_session_process_events()

gboolean qof_session_process_events | ( | QofSession * | session | ) |

The qof_session_process_events() method will process any events indicated by the qof_session_events_pending() method. It returns TRUE if the engine was modified while engine events were suspended.

Definition at line 1505 of file qofsession.c.

1506 {
1507 if (!session)
1508 return FALSE;
1509 if (!session->backend)
1510 return FALSE;
1511 if (!session->backend->process_events)
1512 return FALSE;
1513
1514 return session->backend->process_events (session->backend);
1515 }

## ◆ 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 AccountGroup & 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 1245 of file qofsession.c.

1247 {
1248 GList *node;
1249 QofBackend *be;
1250 gboolean partial, change_backend;
1251 QofBackendProvider *prov;
1252 GSList *p;
1253 QofBook *book, *abook;
1254 gint num;
1255 gchar *msg, *book_id;
1256
1257 if (!session)
1258 return;
1259 ENTER (" sess=%p book_id=%s",
1260 session, session->book_id ? session->book_id : "(null)");
1261 /* Partial book handling. */
1262 book = qof_session_get_book (session);
1263 partial =
1264 (gboolean)
1265 GPOINTER_TO_INT (qof_book_get_data (book, PARTIAL_QOFBOOK));
1266 change_backend = FALSE;
1267 msg = g_strdup_printf (" ");
1268 book_id = g_strdup (session->book_id);
1269 if (partial == TRUE)
1270 {
1271 if (session->backend && session->backend->provider)
1272 {
1273 prov = session->backend->provider;
1274 if (TRUE == prov->partial_book_supported)
1275 {
1276 /* if current backend supports partial, leave alone. */
1277 change_backend = FALSE;
1278 }
1279 else
1280 {
1281 change_backend = TRUE;
1282 }
1283 }
1284 /* If provider is undefined, assume partial not supported. */
1285 else
1286 {
1287 change_backend = TRUE;
1288 }
1289 }
1290 if (change_backend == TRUE)
1291 {
1292 qof_session_destroy_backend (session);
1293 if (NULL == provider_list)
1294 {
1295 for (num = 0; backend_list[num].filename != NULL; num++)
1296 {
1297 qof_load_backend_library (backend_list[num].libdir,
1298 backend_list[num].filename,
1299 backend_list[num].init_fcn);
1300 }
1301 }
1302 p = g_slist_copy (provider_list);
1303 while (p != NULL)
1304 {
1305 prov = p->data;
1306 if (TRUE == prov->partial_book_supported)
1307 {
1309 /* if((TRUE == prov->partial_book_supported) &&
1310 (0 == strcasecmp (access_method, prov->access_method)))
1311 { */
1312 if (NULL == prov->backend_new)
1313 continue;
1314 /* Use the providers creation callback */
1315 session->backend = (*(prov->backend_new)) ();
1316 session->backend->provider = prov;
1317 if (session->backend->session_begin)
1318 {
1319 /* Call begin - backend has been changed,
1320 so make sure a file can be written,
1321 use ignore_lock and create_if_nonexistent */
1322 g_free (session->book_id);
1323 session->book_id = NULL;
1324 (session->backend->session_begin) (session->backend,
1325 session, book_id, TRUE, TRUE);
1326 PINFO
1327 (" Done running session_begin on changed backend");
1328 if (qof_error_check (session) != QOF_SUCCESS)
1329 {
1330 g_free (session->book_id);
1331 session->book_id = NULL;
1332 LEAVE (" changed backend error");
1333 return;
1334 }
1335 }
1336 /* Tell the books about the backend that they'll be using. */
1337 for (node = session->books; node; node = node->next)
1338 {
1339 book = node->data;
1340 qof_book_set_backend (book, session->backend);
1341 }
1342 p = NULL;
1343 }
1344 if (p)
1345 {
1346 p = p->next;
1347 }
1348 }
1349 if (!session->backend)
1350 {
1351 msg = g_strdup_printf (" failed to load backend");
1352 qof_error_set (session, qof_error_register
1353 (_("Failed to load backend, no suitable handler."),
1354 FALSE));
1355 return;
1356 }
1357 }
1358 /* If there is a backend, and the backend is reachable
1359 * (i.e. we can communicate with it), then synchronize with
1360 * the backend. If we cannot contact the backend (e.g.
1361 * because we've gone offline, the network has crashed, etc.)
1362 * then give the user the option to save to the local disk.
1363 *
1364 * hack alert -- FIXME -- XXX the code below no longer
1365 * does what the words above say. This needs fixing.
1366 */
1367 be = session->backend;
1368 if (be)
1369 {
1370 for (node = session->books; node; node = node->next)
1371 {
1372 abook = node->data;
1373 /* if invoked as SaveAs(), then backend not yet set */
1374 qof_book_set_backend (abook, be);
1375 be->percentage = percentage_func;
1376 if (be->sync)
1377 (be->sync) (be, abook);
1378 }
1379 /* If we got to here, then the backend saved everything
1380 * just fine, and we are done. So return. */
1381 /* Return the book_id to previous value. */
1382 qof_error_clear (session);
1383 LEAVE (" Success");
1384 return;
1385 }
1386 else
1387 {
1388 msg = g_strdup_printf (" failed to load backend");
1389 qof_error_set (session, qof_error_register
1390 (_("Failed to load backend, no suitable handler."),
1391 FALSE));
1392 }
1393 LEAVE (" error -- No backend!");
1394 }
qof_error_register
QofErrorId qof_error_register(const gchar *err_message, gboolean use_file)
Generate and register a new error.
Definition: qoferror.c:91
PINFO
#define PINFO(format, args...)
Definition: qoflog.h:199
QofBackendProvider_s
Definition: qofbackend-p.h:238
qof_error_check
QofErrorId qof_error_check(QofSession *session)
Definition: qoferror.c:227
qof_book_get_data
gpointer qof_book_get_data(QofBook *book, const gchar *key)
Definition: qofbook.c:212
QofBackendProvider_s::partial_book_supported
gboolean partial_book_supported
Partial QofBook handler.
Definition: qofbackend-p.h:254
qof_load_backend_library
gboolean qof_load_backend_library(const gchar *directory, const gchar *filename, const gchar *init_fcn)
Load a QOF-compatible backend shared library.
Definition: qofbackend.c:431
LEAVE
#define LEAVE(format, args...)
Definition: qoflog.h:227
qof_error_set
void qof_error_set(QofSession *session, QofErrorId error)
Add an error to the stack for this session.
Definition: qoferror.c:133
qof_book_set_backend
void qof_book_set_backend(QofBook *book, QofBackend *)
Set the backend used by this book.
Definition: qofbook.c:170
QOF_SUCCESS
#define QOF_SUCCESS
Definition: qoferror.h:124
QofBackendProvider_s::backend_new
QofBackend *(* backend_new)(void)
Definition: qofbackend-p.h:260
qof_error_clear
void qof_error_clear(QofSession *session)
clear the error stack for the session.
Definition: qoferror.c:209
_QofBook
Definition: qofbook-p.h:48
ENTER
#define ENTER(format, args...)
Definition: qoflog.h:217
QofBackend_s
Definition: qofbackend-p.h:283
PARTIAL_QOFBOOK
#define PARTIAL_QOFBOOK
Flag indicating a partial QofBook.
Definition: qofreference.h:146

## ◆ qof_session_save_may_clobber_data()

gboolean qof_session_save_may_clobber_data | ( | QofSession * | session | ) |

Allows the backend to warn the user if a dataset already exists.

Definition at line 1232 of file qofsession.c.

1233 {
1234 if (!session)
1235 return FALSE;
1236 if (!session->backend)
1237 return FALSE;
1238 if (!session->backend->save_may_clobber_data)
1239 return FALSE;
1240
1241 return (*(session->backend->save_may_clobber_data)) (session->backend);
1242 }
QofBackend_s::save_may_clobber_data
gboolean(* save_may_clobber_data)(QofBackend *)
Definition: qofbackend-p.h:320

## ◆ 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 1458 of file qofsession.c.

1459 {
1460 GList *books_1, *books_2, *node;
1461
1462 if (session_1 == session_2)
1463 return;
1464 if (!session_1 || !session_2)
1465 return;
1466
1467 ENTER (" sess1=%p sess2=%p", session_1, session_2);
1468
1469 books_1 = session_1->books;
1470 books_2 = session_2->books;
1471
1472 session_1->books = books_2;
1473 session_2->books = books_1;
1474
1475 for (node = books_1; node; node = node->next)
1476 {
1477 QofBook *book_1 = node->data;
1478 qof_book_set_backend (book_1, session_2->backend);
1479 }
1480 for (node = books_2; node; node = node->next)
1481 {
1482 QofBook *book_2 = node->data;
1483 qof_book_set_backend (book_2, session_1->backend);
1484 }
1485
1486 LEAVE (" ");
1487 }
LEAVE
#define LEAVE(format, args...)
Definition: qoflog.h:227
qof_book_set_backend
void qof_book_set_backend(QofBook *book, QofBackend *)
Set the backend used by this book.
Definition: qofbook.c:170
_QofBook
Definition: qofbook-p.h:48
ENTER
#define ENTER(format, args...)
Definition: qoflog.h:217