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 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 GnuCash. 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.
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.
Files | |
| file | qof-be-utils.h |
| QOF Backend Utilities. | |
| file | qofbackend.h |
| API for data storage Backend. | |
| file | qofsession.h |
| Encapsulates a connection to a backend (persistent store). | |
Modules | |
| QOF Serialisation Format | |
Data Structures | |
| struct | QofBackendOption_s |
| struct | qof_entity_reference |
| External references in a partial QofBook. More... | |
Using a partial QofBook. | |
| Part of the handling for partial books requires a storage mechanism for references to entities that are not within reach of the partial book. This requires a GList in the book data to contain the reference QofIdType and GUID so that when the book is written out, the reference can be included. See qof_book_get_data. When the file is imported back in, the list needs to be rebuilt. The QSF backend rebuilds the references by linking to real entities. Other backends can process the hash table in similar ways. The list stores the QofEntityReference to the referenced entity - a struct that contains the GUID and the QofIdType of the referenced entity as well as the parameter used to obtain the reference.
Partial books need to be differentiated in the backend, the flag in the book data is used by qof_session_save to prevent a partial book being saved using a backend that requires a full book. | |
| #define | ENTITYREFERENCE "QofEntityReference" |
| #define | PARTIAL_QOFBOOK "PartialQofBook" |
| Flag indicating a partial QofBook. | |
| typedef qof_entity_reference | QofEntityReference |
| External references in a partial QofBook. | |
| QofEntityReference * | qof_entity_get_reference_from (QofEntity *ent, const QofParam *param) |
| Get a reference from this entity to another entity. | |
| void | qof_session_update_reference_list (QofSession *session, QofEntityReference *reference) |
| Adds a new reference to the partial book data hash. | |
Backend Configuration using KVP | |
| The backend uses qof_backend_get_config to pass back a KvpFrame of QofBackendOption that includes the translated strings that serve as description and tooltip for that option. i.e. backends need to run gettext in the init function. qof_backend_prepare_frame, qof_backend_prepare_option and qof_backend_complete_frame are intended to be used by the backend itself to create the options.
qof_backend_get_config, qof_backend_option_foreach and qof_backend_load_config are intended for either the backend or the frontend to retrieve the option data from the frame or set new data. | |
| typedef QofBackendOption_s | QofBackendOption |
| typedef void(* | QofBackendOptionCB )(QofBackendOption *, gpointer data) |
| void | qof_backend_prepare_frame (QofBackend *be) |
| void | qof_backend_prepare_option (QofBackend *be, QofBackendOption *option) |
| KvpFrame * | qof_backend_complete_frame (QofBackend *be) |
| void | qof_backend_option_foreach (KvpFrame *config, QofBackendOptionCB cb, gpointer data) |
| void | qof_backend_load_config (QofBackend *be, KvpFrame *config) |
| Load configuration options specific to this backend. | |
| KvpFrame * | qof_backend_get_config (QofBackend *be) |
| Get the available configuration options. | |
Allow access to the begin routine for this backend. | |
| QOF_BEGIN_EDIT and QOF_COMMIT_EDIT_PART1 and part2 rely on calling QofBackend *be->begin and be->commit. This means the QofBackend struct becomes part of the public API. These function replaces those calls to allow the macros to be used when QOF is built as a library. | |
| void | qof_backend_run_begin (QofBackend *be, QofInstance *inst) |
| gboolean | qof_backend_begin_exists (QofBackend *be) |
| void | qof_backend_run_commit (QofBackend *be, QofInstance *inst) |
| gboolean | qof_backend_commit_exists (QofBackend *be) |
Session Errors | |
| QofBackendError | qof_session_get_error (QofSession *session) |
| const char * | qof_session_get_error_message (QofSession *session) |
| QofBackendError | qof_session_pop_error (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. 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 Merging QofBook structures | |
| gboolean | qof_entity_copy_to_session (QofSession *new_session, QofEntity *original) |
| Copy a single QofEntity to another session. | |
| gboolean | qof_entity_copy_list (QofSession *new_session, GList *entity_list) |
| Copy a GList of entities to another session. | |
| gboolean | qof_entity_copy_coll (QofSession *new_session, QofCollection *entity_coll) |
| Copy a QofCollection of entities. | |
| gboolean | qof_entity_copy_coll_r (QofSession *new_session, QofCollection *coll) |
| Recursively copy a collection of entities to a session. | |
| gboolean | qof_entity_copy_one_r (QofSession *new_session, QofEntity *ent) |
| Recursively copy a single entity to a new session. | |
Event Handling | |
| gboolean | qof_session_events_pending (QofSession *session) |
| gboolean | qof_session_process_events (QofSession *session) |
Defines | |
| #define | QOF_BEGIN_EDIT(inst) |
| #define | QOF_COMMIT_EDIT_PART1(inst) |
| #define | QOF_COMMIT_EDIT_PART2(inst, on_error, on_done, on_free) |
| #define | QOF_STDOUT "file:" |
| Allow session data to be printed to stdout. | |
Typedefs | |
| typedef QofBackendProvider_s | QofBackendProvider |
| typedef QofBackend_s | QofBackend |
| Pseudo-object providing an interface between the engine and a persistant data store (e.g. a server, a database, or a file). | |
| typedef void(* | QofBePercentageFunc )(const char *message, double percent) |
| DOCUMENT ME! | |
| typedef _QofSession | QofSession |
| 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_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_QSF_INVALID_OBJ, ERR_QSF_INVALID_MAP, ERR_QSF_BAD_OBJ_GUID, ERR_QSF_BAD_QOF_VERSION, ERR_QSF_BAD_MAP, ERR_QSF_NO_MAP, ERR_QSF_WRONG_MAP, ERR_QSF_MAP_NOT_OBJ, ERR_QSF_OVERFLOW, ERR_QSF_OPEN_NOT_MERGE, 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_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_BUSY, 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_begin_edit (QofInstance *inst) |
| function version of QOF_BEGIN_EDIT | |
| void | qof_commit_edit (QofInstance *inst) |
| function version of QOF_COMMIT_EDIT_PART1 | |
| gboolean | qof_load_backend_library (const char *directory, const char *filename, const char *init_fcn) |
| Load a QOF-compatible backend shared library. | |
| QofBackend * | qof_book_get_backend (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) |
| QofSession * | qof_session_get_current_session (void) |
| void | qof_session_set_current_session (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_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 char * | qof_session_get_file_path (QofSession *session) |
| const char * | 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) |
|
|
Used as the key value for the QofBook data hash. Retrieved later by QSF (or any other suitable backend) to rebuild the references from the QofEntityReference struct that contains the QofIdType and GUID of the referenced entity of the original QofBook as well as the parameter data and the GUID of the original entity. Definition at line 479 of file qofsession.h. |
|
|
Flag indicating a partial QofBook. When set in the book data with a gboolean value of TRUE, the flag denotes that only a backend that supports partial books can be used to save this session. Definition at line 488 of file qofsession.h. |
|
|
Value: QofBackend * be; \ if (!(inst)) return; \ \ (inst)->editlevel++; \ if (1 < (inst)->editlevel) return; \ \ if (0 >= (inst)->editlevel) \ { \ PERR ("unbalanced call - resetting (was %d)", (inst)->editlevel); \ (inst)->editlevel = 1; \ } \ ENTER ("(inst=%p)", (inst)); \ \ /* See if there's a backend. If there is, invoke it. */ \ be = qof_book_get_backend ((inst)->book); \ if (be && qof_backend_begin_exists((be))) { \ qof_backend_run_begin((be), (inst)); \ } else { \ /* We tried and failed to start transaction! */ \ (inst)->dirty = TRUE; \ }
Uses newly created functions to allow the macro to be used when QOF is linked as a library. qofbackend-p.h is a private header. Definition at line 53 of file qof-be-utils.h. |
|
|
Value: { \
if (!(inst)) return; \
\
(inst)->editlevel--; \
if (0 < (inst)->editlevel) return; \
\
/* The pricedb sufffers from delayed update... */ \
/* This may be setting a bad precedent for other types, I fear. */ \
/* Other types probably really should handle begin like this. */ \
if ((-1 == (inst)->editlevel) && (inst)->dirty) \
{ \
QofBackend * be; \
be = qof_book_get_backend ((inst)->book); \
if (be && qof_backend_begin_exists((be))) { \
qof_backend_run_begin((be), (inst)); \
} \
(inst)->editlevel = 0; \
} \
if (0 > (inst)->editlevel) \
{ \
PERR ("unbalanced call - resetting (was %d)", (inst)->editlevel); \
(inst)->editlevel = 0; \
} \
ENTER ("(inst=%p) dirty=%d do-free=%d", \
(inst), (inst)->dirty, (inst)->do_free); \
}
Definition at line 97 of file qof-be-utils.h. |
|
|
part2 -- deal with the backend
Definition at line 144 of file qof-be-utils.h. |
|
|
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 508 of file qofsession.h. |
|
|
Pseudo-object providing an interface between the engine and a persistant data store (e.g. a server, a database, or a file). 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. Definition at line 149 of file qofbackend.h. |
|
|
A single Backend Configuration Option. |
|
|
Backend configuration option foreach callback prototype. Definition at line 207 of file qofbackend.h. |
|
|
A structure that declares backend services that can be gotten. The Provider specifies a URL access method, and specifies the function to create a backend that can handle that URL access function. Definition at line 139 of file qofbackend.h. |
|
|
External references in a partial QofBook. For use by any session that deals with partial QofBooks. It is used by the entity copy functions and by the QSF backend. Creates a GList stored in the Book hashtable to contain repeated references for a single entity. |
|
|
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 171 of file qofsession.h. |
|
|
The errors that can be reported to the GUI & other front-end users.
Definition at line 49 of file qofbackend.h. 00049 { 00050 ERR_BACKEND_NO_ERR = 0, 00051 ERR_BACKEND_NO_HANDLER, 00052 ERR_BACKEND_NO_BACKEND, 00053 ERR_BACKEND_BAD_URL, 00054 ERR_BACKEND_NO_SUCH_DB, 00055 ERR_BACKEND_CANT_CONNECT, 00056 ERR_BACKEND_CONN_LOST, 00057 ERR_BACKEND_LOCKED, 00058 ERR_BACKEND_READONLY, 00059 ERR_BACKEND_TOO_NEW, 00060 ERR_BACKEND_DATA_CORRUPT, 00061 ERR_BACKEND_SERVER_ERR, 00062 ERR_BACKEND_ALLOC, 00063 ERR_BACKEND_PERM, 00065 ERR_BACKEND_MODIFIED, 00067 ERR_BACKEND_MOD_DESTROY, 00069 ERR_BACKEND_MISC, 00071 /* QSF add-ons */ 00072 ERR_QSF_INVALID_OBJ, 00073 ERR_QSF_INVALID_MAP, 00074 ERR_QSF_BAD_OBJ_GUID, 00075 ERR_QSF_BAD_QOF_VERSION, 00076 ERR_QSF_BAD_MAP, 00081 ERR_QSF_NO_MAP, 00085 ERR_QSF_WRONG_MAP, 00090 ERR_QSF_MAP_NOT_OBJ, 00091 ERR_QSF_OVERFLOW, 00097 ERR_QSF_OPEN_NOT_MERGE, 00102 /* fileio errors */ 00103 ERR_FILEIO_FILE_BAD_READ = 1000, 00104 ERR_FILEIO_FILE_EMPTY, 00105 ERR_FILEIO_FILE_LOCKERR, 00106 ERR_FILEIO_FILE_NOT_FOUND, 00107 ERR_FILEIO_FILE_TOO_OLD, 00108 ERR_FILEIO_UNKNOWN_FILE_TYPE, 00109 ERR_FILEIO_PARSE_ERROR, 00110 ERR_FILEIO_BACKUP_ERROR, 00111 ERR_FILEIO_WRITE_ERROR, 00113 /* network errors */ 00114 ERR_NETIO_SHORT_READ = 2000, 00115 ERR_NETIO_WRONG_CONTENT_TYPE, 00116 ERR_NETIO_NOT_GNCXML, 00118 /* database errors */ 00119 ERR_SQL_MISSING_DATA = 3000, 00120 ERR_SQL_DB_TOO_OLD, 00121 ERR_SQL_DB_BUSY, 00123 /* RPC errors */ 00124 ERR_RPC_HOST_UNK = 4000, 00125 ERR_RPC_CANT_BIND, 00126 ERR_RPC_CANT_ACCEPT, 00127 ERR_RPC_NO_CONNECTION, 00128 ERR_RPC_BAD_VERSION, 00129 ERR_RPC_FAILED, 00130 ERR_RPC_NOT_ADDED, 00131 } QofBackendError;
|
|
|
Complete the backend_configuration and return the frame. Definition at line 245 of file qofbackend.c. 00246 { 00247 g_return_val_if_fail(be, NULL); 00248 be->config_count = 0; 00249 return be->backend_configuration; 00250 }
|
|
|
Get the available configuration options. To retrieve the options from the returned KvpFrame, the caller needs to parse the XML file that documents the option names and data types. The XML file itself is part of the backend and is installed in a directory determined by the backend. Therefore, loading a new backend requires two paths: the path to the .la file and the path to the xml. Both paths are available by including a generated header file, e.g. gncla-dir.h defines GNC_LIB_DIR for the location of the .la file and GNC_XML_DIR for the xml.
Definition at line 344 of file qofbackend.c. 00345 { 00346 if(!be) { return NULL; } 00347 if(!be->get_config) { return NULL; } 00348 return (be->get_config) (be); 00349 }
|
|
||||||||||||
|
Load configuration options specific to this backend.
Definition at line 336 of file qofbackend.c. 00337 { 00338 if(!be || !config) { return; } 00339 if(!be->load_config) { return; } 00340 (be->load_config) (be, config); 00341 }
|
|
||||||||||||||||
|
Iterate over the frame and process each option. Definition at line 321 of file qofbackend.c. 00322 { 00323 struct config_iterate helper; 00324 00325 if(!config || !cb) { return; } 00326 ENTER (" "); 00327 helper.fcn = cb; 00328 helper.count = 1; 00329 helper.data = data; 00330 helper.recursive = config; 00331 kvp_frame_for_each_slot(config, config_foreach_cb, &helper); 00332 LEAVE (" "); 00333 }
|
|
|
Initialise the backend_configuration Definition at line 176 of file qofbackend.c. 00177 { 00178 g_return_if_fail(be); 00179 if(!kvp_frame_is_empty(be->backend_configuration)) { 00180 kvp_frame_delete(be->backend_configuration); 00181 be->backend_configuration = kvp_frame_new(); 00182 } 00183 be->config_count = 0; 00184 }
|
|
||||||||||||
|
Add an option to the backend_configuration. Repeat for more. Definition at line 186 of file qofbackend.c. 00187 { 00188 KvpValue *value; 00189 gchar *temp; 00190 gint count; 00191 00192 g_return_if_fail(be || option); 00193 count = be->config_count; 00194 count++; 00195 value = NULL; 00196 ENTER (" %d", count); 00197 switch (option->type) 00198 { 00199 case KVP_TYPE_GINT64 : { 00200 value = kvp_value_new_gint64(*(gint64*)option->value); 00201 break; 00202 } 00203 case KVP_TYPE_DOUBLE : { 00204 value = kvp_value_new_double(*(double*)option->value); 00205 break; 00206 } 00207 case KVP_TYPE_NUMERIC : { 00208 value = kvp_value_new_numeric(*(gnc_numeric*)option->value); 00209 break; 00210 } 00211 case KVP_TYPE_STRING : { 00212 value = kvp_value_new_string((const char*)option->value); 00213 break; 00214 } 00215 case KVP_TYPE_GUID : { break; } /* unsupported */ 00216 case KVP_TYPE_TIMESPEC : { 00217 value = kvp_value_new_timespec(*(Timespec*)option->value); 00218 break; 00219 } 00220 case KVP_TYPE_BINARY : { break; } /* unsupported */ 00221 case KVP_TYPE_GLIST : { break; } /* unsupported */ 00222 case KVP_TYPE_FRAME : { break; } /* unsupported */ 00223 } 00224 if(value) { 00225 temp = g_strdup_printf("/%s", option->option_name); 00226 kvp_frame_set_value(be->backend_configuration, temp, value); 00227 PINFO (" setting value at %s", temp); 00228 g_free(temp); 00229 temp = g_strdup_printf("/%s/%s", QOF_CONFIG_DESC, option->option_name); 00230 PINFO (" setting description %s at %s", option->description, temp); 00231 kvp_frame_set_string(be->backend_configuration, temp, option->description); 00232 PINFO (" check= %s", kvp_frame_get_string(be->backend_configuration, temp)); 00233 g_free(temp); 00234 temp = g_strdup_printf("/%s/%s", QOF_CONFIG_TIP, option->option_name); 00235 PINFO (" setting tooltip %s at %s", option->tooltip, temp); 00236 kvp_frame_set_string(be->backend_configuration, temp, option->tooltip); 00237 PINFO (" check= %s", kvp_frame_get_string(be->backend_configuration, temp)); 00238 g_free(temp); 00239 /* only increment the counter if successful */ 00240 be->config_count = count; 00241 } 00242 LEAVE (" "); 00243 }
|
|
|
function version of QOF_BEGIN_EDIT The macro cannot be used in a function that returns a value, this function can be used instead. Definition at line 360 of file qofbackend.c. 00361 { 00362 QofBackend * be; 00363 00364 if (!inst) { return; } 00365 inst->editlevel++; 00366 if (1 < inst->editlevel) return; 00367 if (0 >= inst->editlevel) { inst->editlevel = 1; } 00368 be = qof_book_get_backend (inst->book); 00369 if (be && qof_backend_begin_exists(be)) { 00370 qof_backend_run_begin(be, inst); 00371 } else { inst->dirty = TRUE; } 00372 }
|
|
|
function version of QOF_COMMIT_EDIT_PART1 The macro cannot be used in a function that returns a value, this function can be used instead. Only Part1 is implemented. Definition at line 374 of file qofbackend.c. 00375 { 00376 QofBackend * be; 00377 00378 if (!inst) return; 00379 inst->editlevel--; 00380 if (0 < inst->editlevel) { return; } 00381 if ((-1 == inst->editlevel) && inst->dirty) 00382 { 00383 be = qof_book_get_backend ((inst)->book); 00384 if (be && qof_backend_begin_exists(be)) { 00385 qof_backend_run_begin(be, inst); 00386 } 00387 inst->editlevel = 0; 00388 } 00389 if (0 > inst->editlevel) { inst->editlevel = 0; } 00390 }
|
|
||||||||||||
|
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 Merging QofBook structures
Definition at line 643 of file qofsession.c. 00644 { 00645 QofEntityCopyData qecd; 00646 00647 gnc_engine_suspend_events(); 00648 qecd.param_list = NULL; 00649 qecd.new_session = new_session; 00650 qof_book_set_partial(qof_session_get_book(qecd.new_session)); 00651 qof_collection_foreach(entity_coll, qof_entity_coll_foreach, &qecd); 00652 qof_class_param_foreach(qof_collection_get_type(entity_coll), qof_entity_param_cb, &qecd); 00653 qof_collection_foreach(entity_coll, qof_entity_coll_copy, &qecd); 00654 if(qecd.param_list != NULL) { g_slist_free(qecd.param_list); } 00655 gnc_engine_resume_events(); 00656 return TRUE; 00657 }
|
|
||||||||||||
|
Recursively copy a collection of entities to a session.
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. e.g. GncInvoice refers to GncOwner which refers to GncCustomer which refers to GncAddress. See QofEntityReference.
Definition at line 759 of file qofsession.c. 00760 { 00761 struct recurse_s store; 00762 gboolean success; 00763 00764 if((!new_session)||(!coll)) { return FALSE; } 00765 store.session = new_session; 00766 success = TRUE; 00767 store.success = success; 00768 store.ent_list = NULL; 00769 store.ref_list = qof_class_get_referenceList(qof_collection_get_type(coll)); 00770 success = qof_entity_copy_coll(new_session, coll); 00771 if(success){ qof_collection_foreach(coll, recurse_ent_cb, &store); } 00772 return success; 00773 }
|
|
||||||||||||
|
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 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.
Definition at line 625 of file qofsession.c. 00626 { 00627 QofEntityCopyData *qecd; 00628 00629 if(!new_session || !entity_list) { return FALSE; } 00630 ENTER (" list=%d", g_list_length(entity_list)); 00631 qecd = g_new0(QofEntityCopyData, 1); 00632 gnc_engine_suspend_events(); 00633 qecd->param_list = NULL; 00634 qecd->new_session = new_session; 00635 qof_book_set_partial(qof_session_get_book(new_session)); 00636 g_list_foreach(entity_list, qof_entity_list_foreach, qecd); 00637 gnc_engine_resume_events(); 00638 g_free(qecd); 00639 LEAVE (" "); 00640 return TRUE; 00641 }
|
|
||||||||||||
|
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.
Definition at line 775 of file qofsession.c. 00776 { 00777 struct recurse_s store; 00778 QofCollection *coll; 00779 gboolean success; 00780 00781 if((!new_session)||(!ent)) { return FALSE; } 00782 store.session = new_session; 00783 success = TRUE; 00784 store.success = success; 00785 store.ref_list = qof_class_get_referenceList(ent->e_type); 00786 success = qof_entity_copy_to_session(new_session, ent); 00787 if(success == TRUE) { 00788 coll = qof_book_get_collection(qof_session_get_book(new_session), ent->e_type); 00789 qof_collection_foreach(coll, recurse_ent_cb, &store); 00790 } 00791 return success; 00792 }
|
|
||||||||||||
|
Copy a single QofEntity to another session. Checks first that no entity in the session book contains the GUID of the source entity.
Definition at line 598 of file qofsession.c. 00599 { 00600 QofEntityCopyData qecd; 00601 QofInstance *inst; 00602 QofBook *book; 00603 00604 if(!new_session || !original) { return FALSE; } 00605 if(qof_entity_guid_match(new_session, original)) { return FALSE; } 00606 gnc_engine_suspend_events(); 00607 qecd.param_list = NULL; 00608 book = qof_session_get_book(new_session); 00609 qecd.new_session = new_session; 00610 qof_book_set_partial(book); 00611 inst = (QofInstance*)qof_object_new_instance(original->e_type, book); 00612 qecd.to = &inst->entity; 00613 qecd.from = original; 00614 qof_entity_set_guid(qecd.to, qof_entity_get_guid(original)); 00615 qof_begin_edit(inst); 00616 qof_class_param_foreach(original->e_type, qof_entity_param_cb, &qecd); 00617 qof_commit_edit(inst); 00618 if(g_slist_length(qecd.param_list) == 0) { return FALSE; } 00619 g_slist_foreach(qecd.param_list, qof_entity_foreach_copy, &qecd); 00620 g_slist_free(qecd.param_list); 00621 gnc_engine_resume_events(); 00622 return TRUE; 00623 }
|
|
||||||||||||
|
Get a reference from this entity to another entity. Used in the preparation of a partial QofBook when the known entity (the one currently being copied into the partial book) refers to any other entity, usually as a parent or child. The routine calls the param_getfcn of the supplied parameter, which must return an object (QofEntity*), not a known QOF data type, to retrieve the referenced entity and therefore the GUID. The GUID of both entities are stored in the reference which then needs to be added to the reference list which is added to the partial book data hash. The reference itself is used by the backend to preserve the relationship between entities within and outside the partial book. See also qof_class_get_referenceList to obtain the list of parameters that provide references to the known entity whilst excluding parameters that return known QOF data types. Note that even if the referenced entity exists in the partial book (or will exist later), a reference must still be obtained and added to the reference list for the book itself. This maintains the integrity of the partial book during sequential copy operations.
Definition at line 362 of file qofsession.c. 00363 { 00364 QofEntityReference *reference; 00365 QofEntity *ref_ent; 00366 const GUID *cm_guid; 00367 char cm_sa[GUID_ENCODING_LENGTH + 1]; 00368 gchar *cm_string; 00369 00370 g_return_val_if_fail(param, NULL); 00371 ref_ent = (QofEntity*)param->param_getfcn(ent, param); 00372 if(ref_ent != NULL) { 00373 reference = g_new0(QofEntityReference, 1); 00374 reference->type = ent->e_type; 00375 reference->ref_guid = g_new(GUID, 1); 00376 reference->ent_guid = &ent->guid; 00377 reference->param = qof_class_get_parameter(ent->e_type, param->param_name); 00378 cm_guid = qof_entity_get_guid(ref_ent); 00379 guid_to_string_buff(cm_guid, cm_sa); 00380 cm_string = g_strdup(cm_sa); 00381 if(TRUE == string_to_guid(cm_string, reference->ref_guid)) { 00382 return reference; 00383 } 00384 } 00385 return NULL; 00386 }
|
|
||||||||||||||||
|
Load a QOF-compatible backend shared library.
Definition at line 396 of file qofbackend.c. 00398 { 00399 FILE *filehandle; 00400 void (*initfn) (void); 00401 void *dl_hand = NULL; 00402 #ifndef HAVE_GETLINE 00403 char lineptr[1024]; 00404 #else 00405 char *lineptr; 00406 #endif 00407 const char * err_str; 00408 gchar *dlname, *libdirpath, *tempstr; 00409 int errors; 00410 guint n, end; 00411 struct stat sbuf; 00412 00413 errors = 0; 00414 dlname = NULL; 00415 tempstr = NULL; 00416 libdirpath = NULL; 00417 g_return_val_if_fail((filename || init_fcn), FALSE); 00418 if(directory) 00419 { 00420 if(!g_str_has_suffix(directory, "/")) { 00421 tempstr = g_strconcat(directory, "/", filename, NULL); 00422 } 00423 else { 00424 tempstr = g_strconcat(directory, filename, NULL); 00425 } 00426 filename = tempstr; 00427 } 00428 g_return_val_if_fail(g_str_has_suffix (filename, ".la"), FALSE); 00429 /* now we have a filename ending in .la, see if we can open it. */ 00430 n = (guint)strlen(STR_DLNAME); 00431 g_return_val_if_fail((stat(filename, &sbuf) == 0), FALSE); 00432 filehandle = fopen(filename, "r"); 00433 g_return_val_if_fail((filehandle), FALSE); 00434 #ifndef HAVE_GETLINE 00435 while (NULL != (fgets(lineptr, sizeof(lineptr), filehandle))) 00436 #else 00437 lineptr = NULL; 00438 while (0 < getline(&lineptr, &n, filehandle)) 00439 #endif 00440 { 00441 n = (guint)strlen(STR_DLNAME); 00442 if (strncmp (lineptr, STR_DLNAME, n - 1) == 0) 00443 { 00444 /* obtain substring from dlname='.*'\n 00445 where .* matches the library .so|.dylib name 00446 allowing for single quotes, if used. */ 00447 tempstr = g_strdup(lineptr + n); 00448 if(tempstr[0] == '\'') { tempstr++; } 00449 dlname = g_strndup(tempstr, strlen(tempstr) - 1); 00450 end = strlen(dlname); 00451 if(dlname[end-1] == '\'') 00452 { 00453 tempstr = g_strndup(dlname, end - 1); 00454 dlname = tempstr; 00455 } 00456 } 00457 /* now get the path, just in case */ 00458 n = (guint)strlen(STR_LIBDIR); 00459 if (strncmp (lineptr, STR_LIBDIR, n - 1) == 0) 00460 { 00461 tempstr = g_strdup(lineptr + n); 00462 if(tempstr[0] == '\'') { tempstr++; } 00463 libdirpath = g_strndup(tempstr, strlen(tempstr) - 1); 00464 end = strlen(libdirpath); 00465 if(libdirpath[end-1] == '\'') 00466 { 00467 tempstr = g_strndup(libdirpath, end - 1); 00468 libdirpath = tempstr; 00469 } 00470 } 00471 } 00472 fclose(filehandle); 00473 tempstr = g_strconcat(libdirpath, "/", dlname, NULL); 00474 dlname = tempstr; 00475 g_free(libdirpath); 00476 dl_hand = dlopen (dlname, RTLD_LAZY); 00477 if (NULL == dl_hand) 00478 { 00479 err_str = dlerror(); 00480 g_message ("Can't load backend, %s\n", err_str); 00481 return FALSE; 00482 } 00483 initfn = dlsym (dl_hand, init_fcn); 00484 if (initfn) { (*initfn)(); } 00485 else 00486 { 00487 err_str = dlerror(); 00488 g_message("Can't find %s:%s, %s\n", dlname, init_fcn, err_str); 00489 return FALSE; 00490 } 00491 g_free(dlname); 00492 return TRUE; 00493 }
|
|
||||||||||||
|
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 257 of file qofsession.c. 00258 { 00259 GList *node; 00260 if (!session) return; 00261 00262 ENTER (" sess=%p book=%p", session, addbook); 00263 00264 /* See if this book is already there ... */ 00265 for (node=session->books; node; node=node->next) 00266 { 00267 QofBook *book = node->data; 00268 if (addbook == book) return; 00269 } 00270 00271 if ('y' == addbook->book_open) 00272 { 00273 /* hack alert -- someone should free all the books in the list, 00274 * but it should probably not be us ... since the books backends 00275 * should be shutdown first, etc */ 00276 /* XXX this should probably be an error XXX */ 00277 g_list_free (session->books); 00278 session->books = g_list_append (NULL, addbook); 00279 } 00280 else 00281 { 00282 /* XXX Need to tell the backend to add a book as well */ 00283 session->books = g_list_append (session->books, addbook); 00284 } 00285 00286 qof_book_set_backend (addbook, session->backend); 00287 LEAVE (" "); 00288 }
|
|
||||||||||||
|
Register a function to be called just before a session is closed.
Definition at line 80 of file qofsession.c. 00081 { 00082 GHook *hook; 00083 00084 if (session_closed_hooks == NULL) { 00085 session_closed_hooks = malloc(sizeof(GHookList)); 00086 g_hook_list_init (session_closed_hooks, sizeof(GHook)); 00087 } 00088 00089 hook = g_hook_alloc(session_closed_hooks); 00090 if (!hook) 00091 return; 00092 00093 hook->func = (GHookFunc)fn; 00094 hook->data = data; 00095 g_hook_append(session_closed_hooks, hook); 00096 }
|
|
||||||||||||||||||||
|
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. In the current implementation, the following URL's are supported -- File URI of the form "file:/home/somewhere/somedir/file.xac" The path part must be a valid path. The file-part must be a valid old-style-xacc or new-style-gnucash-format file. Paths may be relative or absolute. If the path is relative; that is, if the argument is "file:somefile.xac" then a sequence of search paths are checked for a file of this name. -- Postgres URI of the form "postgres://hostname.com/dbname" See the src/backend/postgres subdirectory for more info. -- RPC URI of the form rpc://hostname.com/rpcserver. 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 995 of file qofsession.c. 00997 { 00998 char *p, *access_method, *msg; 00999 int err; 01000 01001 if (!session) return; 01002 01003 ENTER (" sess=%p ignore_lock=%d, book-id=%s", 01004 session, ignore_lock, 01005 book_id ? book_id : "(null)"); 01006 01007 /* Clear the error condition of previous errors */ 01008 qof_session_clear_error (session); 01009 01010 /* Check to see if this session is already open */ 01011 if (session->book_id) 01012 { 01013 qof_session_push_error (session, ERR_BACKEND_LOCKED, NULL); 01014 LEAVE("push error book is already open "); 01015 return; 01016 } 01017 01018 /* seriously invalid */ 01019 if (!book_id) 01020 { 01021 qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL); 01022 LEAVE("push error missing book_id"); 01023 return; 01024 } 01025 01026 /* Store the session URL */ 01027 session->book_id = g_strdup (book_id); 01028 01029 /* destroy the old backend */ 01030 qof_session_destroy_backend(session); 01031 01032 /* Look for something of the form of "file:/", "http://" or 01033 * "postgres://". Everything before the colon is the access 01034 * method. Load the first backend found for that access method. 01035 */ 01036 p = strchr (book_id, ':'); 01037 if (p) 01038 { 01039 access_method = g_strdup (book_id); 01040 p = strchr (access_method, ':'); 01041 *p = 0; 01042 qof_session_load_backend(session, access_method); 01043 g_free (access_method); 01044 } 01045 else 01046 { 01047 /* If no colon found, assume it must be a file-path */ 01048 qof_session_load_backend(session, "file"); 01049 } 01050 01051 /* No backend was found. That's bad. */ 01052 if (NULL == session->backend) 01053 { 01054 qof_session_push_error (session, ERR_BACKEND_BAD_URL, NULL); 01055 LEAVE (" BAD: no backend: sess=%p book-id=%s", 01056 session, book_id ? book_id : "(null)"); 01057 return; 01058 } 01059 01060 /* If there's a begin method, call that. */ 01061 if (session->backend->session_begin) 01062 { 01063 01064 (session->backend->session_begin)(session->backend, session, 01065 session->book_id, ignore_lock, 01066 create_if_nonexistent); 01067 PINFO("Done running session_begin on backend"); 01068 err = qof_backend_get_error(session->backend); 01069 msg = qof_backend_get_message(session->backend); 01070 if (err != ERR_BACKEND_NO_ERR) 01071 { 01072 g_free(session->book_id); 01073 session->book_id = NULL; 01074 qof_session_push_error (session, err, msg); 01075 LEAVE(" backend error %d %s", err, msg); 01076 return; 01077 } 01078 if (msg != NULL) 01079 { 01080 PWARN("%s", msg); 01081 g_free(msg); 01082 } 01083 } 01084 01085 LEAVE (" sess=%p book-id=%s", 01086 session, book_id ? book_id : "(null)"); 01087 }
|
|
|
Call all registered session close hooks, informing them that the specified session is about to be closed.
Definition at line 99 of file qofsession.c. 00100 { 00101 GHook *hook; 00102 GFunc fn; 00103 00104 if (session_closed_hooks == NULL) 00105 return; 00106 00107 hook = g_hook_first_valid (session_closed_hooks, FALSE); 00108 while (hook) { 00109 fn = (GFunc)hook->func; 00110 fn(session, hook->data); 00111 hook = g_hook_next_valid (session_closed_hooks, hook, FALSE); 00112 } 00113 }
|
|
|
The qof_session_end() method will release the session lock. For the file backend, it will *not* save the account group 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 1390 of file qofsession.c. 01391 { 01392 if (!session) return; 01393 01394 ENTER ("sess=%p book_id=%s", session, session->book_id 01395 ? session->book_id : "(null)"); 01396 01397 /* close down the backend first */ 01398 if (session->backend && session->backend->session_end) 01399 { 01400 (session->backend->session_end)(session->backend); 01401 } 01402 01403 qof_session_clear_error (session); 01404 01405 g_free (session->book_id); 01406 session->book_id = NULL; 01407 01408 LEAVE ("sess=%p book_id=%s", session, session->book_id 01409 ? session->book_id : "(null)"); 01410 }
|
|
|
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 1478 of file qofsession.c. 01479 { 01480 if (!session) return FALSE; 01481 if (!session->backend) return FALSE; 01482 if (!session->backend->events_pending) return FALSE; 01483 01484 return session->backend->events_pending (session->backend); 01485 }
|
|
|
Definition at line 224 of file qofsession.c. 00225 { 00226 if (!current_session) 00227 { 00228 gnc_engine_suspend_events (); 00229 current_session = qof_session_new (); 00230 gnc_engine_resume_events (); 00231 } 00232 00233 return current_session; 00234 }
|
|
|
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 150 of file qofsession.c. 00151 { 00152 QofBackendError err; 00153 00154 if (!session) return ERR_BACKEND_NO_BACKEND; 00155 00156 /* if we have a local error, return that. */ 00157 if (ERR_BACKEND_NO_ERR != session->last_err) 00158 { 00159 return session->last_err; 00160 } 00161 00162 /* maybe we should return a no-backend error ??? */ 00163 if (! session->backend) return ERR_BACKEND_NO_ERR; 00164 00165 err = qof_backend_get_error (session->backend); 00166 session->last_err = err; 00167 return err; 00168 }
|
|
|
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 298 of file qofsession.c. 00299 { 00300 if (!session) return NULL; 00301 if (!session->backend) return NULL; 00302 return session->backend->fullpath; 00303 }
|
|
|
The qof_session_not_saved() subroutine will return TRUE if any data in the session hasn't been saved to long-term storage. |
|
|
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 186 of file qofsession.c. 00187 { 00188 QofBackendError err; 00189 00190 if (!session) return ERR_BACKEND_NO_BACKEND; 00191 00192 err = qof_session_get_error(session); 00193 qof_session_clear_error(session); 00194 00195 return err; 00196 }
|
|
|
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 1488 of file qofsession.c. 01489 { 01490 if (!session) return FALSE; 01491 if (!session->backend) return FALSE; 01492 if (!session->backend->process_events) return FALSE; 01493 01494 return session->backend->process_events (session->backend); 01495 }
|
|
||||||||||||
|
Definition at line 1203 of file qofsession.c. 01205 { 01206 GList *node; 01207 QofBackend *be; 01208 gboolean partial, change_backend; 01209 QofBackendProvider *prov; 01210 GSList *p; 01211 QofBook *book, *abook; 01212 int err; 01213 gint num; 01214 char *msg, *book_id; 01215 01216 if (!session) return; 01217 ENTER ("sess=%p book_id=%s", 01218 session, session->book_id ? session->book_id : "(null)"); 01219 /* Partial book handling. */ 01220 book = qof_session_get_book(session); 01221 partial = (gboolean)GPOINTER_TO_INT(qof_book_get_data(book, PARTIAL_QOFBOOK)); 01222 change_backend = FALSE; 01223 msg = g_strdup_printf(" "); 01224 book_id = g_strdup(session->book_id); 01225 if(partial == TRUE) 01226 { 01227 if(session->backend->provider) { 01228 prov = session->backend->provider; 01229 if(TRUE == prov->partial_book_supported) 01230 { 01231 /* if current backend supports partial, leave alone. */ 01232 change_backend = FALSE; 01233 } 01234 else { change_backend = TRUE; } 01235 } 01236 /* If provider is undefined, assume partial not supported. */ 01237 else { change_backend = TRUE; } 01238 } 01239 if(change_backend == TRUE) 01240 { 01241 qof_session_destroy_backend(session); 01242 if (NULL == provider_list) 01243 { 01244 for (num = 0; backend_list[num].filename != NULL; num++) { 01245 qof_load_backend_library(backend_list[num].libdir, 01246 backend_list[num].filename, backend_list[num].init_fcn); 01247 } 01248 } 01249 p = g_slist_copy(provider_list); 01250 while(p != NULL) 01251 { 01252 prov = p->data; 01253 if(TRUE == prov->partial_book_supported) 01254 { 01256 /* if((TRUE == prov->partial_book_supported) && 01257 (0 == strcasecmp (access_method, prov->access_method))) 01258 {*/ 01259 if (NULL == prov->backend_new) continue; 01260 /* Use the providers creation callback */ 01261 session->backend = (*(prov->backend_new))(); 01262 session->backend->provider = prov; 01263 if (session->backend->session_begin) 01264 { 01265 /* Call begin - what values to use for booleans? */ 01266 g_free(session->book_id); 01267 session->book_id = NULL; 01268 (session->backend->session_begin)(session->backend, session, 01269 book_id, TRUE, FALSE); 01270 PINFO("Done running session_begin on changed backend"); 01271 err = qof_backend_get_error(session->backend); 01272 msg = qof_backend_get_message(session->backend); 01273 if (err != ERR_BACKEND_NO_ERR) 01274 { 01275 g_free(session->book_id); 01276 session->book_id = NULL; 01277 qof_session_push_error (session, err, msg); 01278 LEAVE("changed backend error %d", err); 01279 return; 01280 } 01281 if (msg != NULL) 01282 { 01283 PWARN("%s", msg); 01284 g_free(msg); 01285 } 01286 } 01287 /* Tell the books about the backend that they'll be using. */ 01288 for (node=session->books; node; node=node->next) 01289 { 01290 book = node->data; 01291 qof_book_set_backend (book, session->backend); 01292 } 01293 p = NULL; 01294 } 01295 if(p) { 01296 p = p->next; 01297 } 01298 } 01299 if(!session->backend) 01300 { 01301 msg = g_strdup_printf("failed to load backend"); 01302 qof_session_push_error(session, ERR_BACKEND_NO_HANDLER, msg); 01303 return; 01304 } 01305 } 01306 /* If there is a backend, and the backend is reachable 01307 * (i.e. we can communicate with it), then synchronize with 01308 * the backend. If we cannot contact the backend (e.g. 01309 * because we've gone offline, the network has crashed, etc.) 01310 * then give the user the option to save to the local disk. 01311 * 01312 * hack alert -- FIXME -- XXX the code below no longer 01313 * does what the words above say. This needs fixing. 01314 */ 01315 be = session->backend; 01316 if (be) 01317 { 01318 for (node = session->books; node; node=node->next) 01319 { 01320 abook = node->data; 01321 /* if invoked as SaveAs(), then backend not yet set */ 01322 qof_book_set_backend (abook, be); 01323 be->percentage = percentage_func; 01324 if (be->sync) 01325 { 01326 (be->sync)(be, abook); 01327 if (save_error_handler(be, session)) return; 01328 } 01329 } 01330 /* If we got to here, then the backend saved everything 01331 * just fine, and we are done. So return. */ 01332 /* Return the book_id to previous value. */ 01333 qof_session_clear_error (session); 01334 LEAVE("Success"); 01335 return; 01336 } 01337 else 01338 { 01339 msg = g_strdup_printf("failed to load backend"); 01340 qof_session_push_error(session, ERR_BACKEND_NO_HANDLER, msg); 01341 } 01342 LEAVE("error -- No backend!"); 01343 }
|
|
|
FIXME: This isn't as thorough as we might want it to be... Definition at line 1179 of file qofsession.c. 01180 { 01181 if (!session) return FALSE; 01182 if (!session->backend) return FALSE; 01183 if (!session->backend->save_may_clobber_data) return FALSE; 01184 01185 return (*(session->backend->save_may_clobber_data)) (session->backend); 01186 }
|
|
||||||||||||
|
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 1446 of file qofsession.c. 01447 { 01448 GList *books_1, *books_2, *node; 01449 01450 if (session_1 == session_2) return; 01451 if (!session_1 || !session_2) return; 01452 01453 ENTER ("sess1=%p sess2=%p", session_1, session_2); 01454 01455 books_1 = session_1->books; 01456 books_2 = session_2->books; 01457 01458 session_1->books = books_2; 01459 session_2->books = books_1; 01460 01461 for (node=books_1; node; node=node->next) 01462 { 01463 QofBook *book_1 = node->data; 01464 qof_book_set_backend (book_1, session_2->backend); 01465 } 01466 for (node=books_2; node; node=node->next) 01467 { 01468 QofBook *book_2 = node->data; 01469 qof_book_set_backend (book_2, session_1->backend); 01470 } 01471 01472 LEAVE (" "); 01473 }
|
|
||||||||||||
|
Adds a new reference to the partial book data hash. Retrieves any existing reference list and appends the new reference. If the book is not already marked as partial, it will be marked as partial. Definition at line 336 of file qofsession.c. 00337 { 00338 QofBook *book; 00339 GList *book_ref_list; 00340 00341 book = qof_session_get_book(session); 00342 book_ref_list = (GList*)qof_book_get_data(book, ENTITYREFERENCE); 00343 book_ref_list = g_list_append(book_ref_list, reference); 00344 qof_book_set_data(book, ENTITYREFERENCE, book_ref_list); 00345 qof_book_set_partial(book); 00346 }
|
1.4.3-20050530