Backend
[Object: Dynamic Object Class Framework]


Detailed Description

The QOF Backend is a pseudo-object providing an interface between the engine and a persistant 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 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.
QofEntityReferenceqof_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)
KvpFrameqof_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.
KvpFrameqof_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.
QofBackendqof_book_get_backend (QofBook *book)
 Retrieve the backend used by this book.
void qof_book_set_backend (QofBook *book, QofBackend *)
QofSessionqof_session_new (void)
void qof_session_destroy (QofSession *session)
QofSessionqof_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)
QofBookqof_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)


Define Documentation

#define ENTITYREFERENCE   "QofEntityReference"
 

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.

#define PARTIAL_QOFBOOK   "PartialQofBook"
 

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.

#define QOF_BEGIN_EDIT inst   ) 
 

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;                                          \
  }
begin_edit helper

Parameters:
inst,: an instance of QofInstance
The caller should use this macro first and then perform any other operations.

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.

#define QOF_COMMIT_EDIT_PART1 inst   ) 
 

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);             \
}
part1 -- deal with the editlevel

Parameters:
inst,: an instance of QofInstance

Definition at line 97 of file qof-be-utils.h.

#define QOF_COMMIT_EDIT_PART2 inst,
on_error,
on_done,
on_free   ) 
 

part2 -- deal with the backend

Parameters:
inst,: an instance of QofInstance
on_error,: a function called if there is a backend error. void (*on_error)(inst, QofBackendError)
on_done,: a function called after the commit is complete but before the instect is freed. Perform any other operations after the commit. void (*on_done)(inst)
on_free,: a function called if inst->do_free is TRUE. void (*on_free)(inst)

Definition at line 144 of file qof-be-utils.h.

#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 508 of file qofsession.h.


Typedef Documentation

typedef struct 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).

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.

typedef struct QofBackendOption_s QofBackendOption
 

A single Backend Configuration Option.

typedef void(* QofBackendOptionCB)(QofBackendOption *, gpointer data)
 

Backend configuration option foreach callback prototype.

Definition at line 207 of file qofbackend.h.

typedef struct QofBackendProvider_s QofBackendProvider
 

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.

typedef struct qof_entity_reference QofEntityReference
 

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.

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 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.


Enumeration Type Documentation

enum 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_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_QSF_INVALID_OBJ  The QSF object failed to validate against the QSF object schema
ERR_QSF_INVALID_MAP  The QSF map failed to validate against the QSF map schema
ERR_QSF_BAD_OBJ_GUID  The QSF object contains one or more invalid GUIDs.
ERR_QSF_BAD_QOF_VERSION  QSF map or object doesn't match the current QOF_OBJECT_VERSION.
ERR_QSF_BAD_MAP  The selected map validates but is unusable.

This is usually because not all the required parameters for the defined objects have calculations described in the map.

ERR_QSF_NO_MAP  The QSF object file was loaded without a map

The QSF Object file requires a map but it was not provided.

ERR_QSF_WRONG_MAP  The selected map validates but is for different objects.

The list of objects defined in this map does not include all the objects described in the current QSF object file.

ERR_QSF_MAP_NOT_OBJ  Selected file is a QSF map and cannot be opened as a QSF object
ERR_QSF_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  QSF files cannot be opened alone. The data must be merged.

This error is more of a warning that can be ignored by any routine that uses qof_book_merge on the new session. 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_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_BUSY  database is busy, cannot upgrade version
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 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;


Function Documentation

KvpFrame* qof_backend_complete_frame QofBackend be  ) 
 

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 }

KvpFrame* qof_backend_get_config QofBackend be  ) 
 

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.

Parameters:
be The QofBackend to be configured.
Returns:
A new KvpFrame containing the available options or NULL on failure.

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 }

void qof_backend_load_config QofBackend be,
KvpFrame config
 

Load configuration options specific to this backend.

Parameters:
be The backend to configure.
config A KvpFrame of QofBackendOptions that this backend will recognise. Each backend needs to document their own config types and acceptable values.

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 }

void qof_backend_option_foreach KvpFrame config,
QofBackendOptionCB  cb,
gpointer  data
 

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 }

void qof_backend_prepare_frame QofBackend be  ) 
 

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 }

void qof_backend_prepare_option QofBackend be,
QofBackendOption option
 

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 }

void qof_begin_edit QofInstance inst  ) 
 

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 }

void qof_commit_edit QofInstance inst  ) 
 

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 }

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 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 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 }

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 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. e.g. GncInvoice refers to GncOwner which refers to GncCustomer which refers to GncAddress. 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 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 }

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 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 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 }

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 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 }

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 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 }

QofEntityReference* qof_entity_get_reference_from QofEntity ent,
const QofParam param
 

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.

Parameters:
ent The known entity.
param The parameter to use to get the referenced entity.
Returns:
FALSE on error, otherwise a pointer to the QofEntityReference.

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 }

gboolean qof_load_backend_library const char *  directory,
const char *  filename,
const char *  init_fcn
 

Load a QOF-compatible backend shared library.

Parameters:
directory Can be NULL if filename is a complete path.
filename Name of the .la file that describes the shared library. This provides platform independence, courtesy of libtool.
init_fcn The QofBackendProvider init function.
Returns:
FALSE in case or error, otherwise TRUE.

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 }

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 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 }

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 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 }

void qof_session_begin QofSession session,
const char *  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. 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 }

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 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 }

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 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 }

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 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 }

QofSession* qof_session_get_current_session void   ) 
 

Deprecated:
Each application should keep their own session context.

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 }

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 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 }

const char* 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 298 of file qofsession.c.

00299 {
00300    if (!session) return NULL;
00301    if (!session->backend) return NULL;
00302    return session->backend->fullpath;
00303 }

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.

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 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 }

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 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 }

void qof_session_save QofSession session,
QofPercentageFunc  percentage_func
 

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

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 }

gboolean qof_session_save_may_clobber_data QofSession session  ) 
 

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 }

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 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 }

void qof_session_update_reference_list QofSession session,
QofEntityReference reference
 

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 }


Generated on Sun Sep 4 18:09:07 2005 for GnuCash by  doxygen 1.4.3-20050530