1 /********************************************************************\
2  * qofbackend-p.h -- private api for data storage backend           *
3  *                                                                  *
4  * This program is free software; you can redistribute it and/or    *
5  * modify it under the terms of the GNU General Public License as   *
6  * published by the Free Software Foundation; either version 2 of   *
7  * the License, or (at your option) any later version.              *
8  *                                                                  *
9  * This program is distributed in the hope that it will be useful,  *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of   *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
12  * GNU General Public License for more details.                     *
13  *                                                                  *
14  * You should have received a copy of the GNU General Public License*
15  * along with this program; if not, contact:                        *
16  *                                                                  *
17  * Free Software Foundation           Voice:  +1-617-542-5942       *
18  * 51 Franklin Street, Fifth Floor    Fax:    +1-617-542-2652       *
19  * Boston, MA  02110-1301,  USA       gnu@gnu.org                   *
20  *                                                                  *
21 \********************************************************************/
22 /** @addtogroup Object
23     @{ */
24 /** @addtogroup Object_Private
25     @{ */
26 /** @name  Backend_Private
27    Pseudo-object defining how the engine can interact with different
28    back-ends (which may be SQL databases, or network interfaces to
29    remote QOF servers. File-io is just one type of backend).
30 
31    The callbacks will be called at the appropriate times during
32    a book session to allow the backend to store the data as needed.
33 
34    @file qofbackend-p.h
35    @brief private api for data storage backend
36    @author Copyright (c) 2000,2001,2004 Linas Vepstas <linas@linas.org>
37    @author Copyright (c) 2005-2008 Neil Williams <linux@codehelp.co.uk>
38 @{ */
39 
40 #ifndef QOF_BACKEND_P_H
41 #define QOF_BACKEND_P_H
42 
43 #include "qofinstance-p.h"
44 #include "qofquery.h"
45 #include "qofsession.h"
46 
47 /**
48  * The backend_new routine sets the functions that will be used
49  *    by the backend to perform the actions required by QOF. A
50  *    basic minimum is session_begin, session_end, load and
51  *    sync. Any unused functions should be set to NULL. If the
52  *    backend uses configuration options, backend_new must ensure
53  *    that these are set to usable defaults before returning. To use
54  *    configuration options, load_config and get_config must also
55  *    be defined.
56  *
57  * The session_begin() routine gives the backend a second initialization
58  *    opportunity.  It is suggested that the backend check that
59  *    the URL is syntactically correct, and that it is actually
60  *    reachable.  This is probably(?) a good time to initialize
61  *    the actual network connection.
62  *
63  *    The 'ignore_lock' argument indicates whether the single-user
64  *    lock on the backend should be cleared.  The typical GUI sequence
65  *    leading to this is: (1) GUI attempts to open the backend
66  *    by calling this routine with FALSE==ignore_lock.  (2) If backend
67  *    error'ed BACKEND_LOCK, then GUI asks user what to do. (3) if user
68  *    answers 'break & enter' then this routine is called again with
69  *    TRUE==ignore_lock.
70  *
71  *    The 'create_if_nonexistent' argument indicates whether this
72  *    routine should create a new 'database', if it doesn't already
73  *    exist. For example, for a file-backend, this would create the
74  *    file, if it didn't already exist.  For an SQL backend, this
75  *    would create the database (the schema) if it didn't already
76  *    exist.  This flag is used to implement the 'SaveAs' GUI, where
77  *    the user requests to save data to a new backend.
78  *
79  * The load() routine should load the minimal set of application data
80  *    needed for the application to be operable at initial startup.
81  *    It is assumed that the application will perform a 'run_query()'
82  *    to obtain any additional data that it needs.  For file-based
83  *    backends, it is acceptable for the backend to return all data
84  *    at load time; for SQL-based backends, it is acceptable for the
85  *    backend to return no data.
86  *
87  *    Thus, for example, the GnuCash postgres backend returned
88  *    the account tree, all currencies, and the pricedb, as these
89  *    were needed at startup.  It did not have to return any
90  *    transactions whatsoever, as these were obtained at a later stage
91  *    when a user opened a register, resulting in a query being sent to
92  *    the backend.
93  *
94  *    (Its OK to send over entities at this point, but one should
95  *    be careful of the network load; also, its possible that whatever
96  *    is sent is not what the user wanted anyway, which is why its
97  *    better to wait for the query).
98  *
99  * The begin() routine is called when the engine is about to
100  *    make a change to a data structure. It can provide an advisory
101  *    lock on data.
102  *
103  * The commit() routine commits the changes from the engine to the
104  *    backend data storage.
105  *
106  * The rollback() routine is used to revert changes in the engine
107  *    and unlock the backend.
108  *
109  *    If the second user tries to modify an entity that
110  *    the first user deleted, then the backend should set the error
111  *    to ERR_BACKEND_MOD_DESTROY from this routine, so that the
112  *    engine can properly clean up.
113  *
114  * The compile_query() method compiles a QOF query object into
115  *    a backend-specific data structure and returns the compiled
116  *    query. For an SQL backend, the contents of the query object
117  *    need to be turned into a corresponding SQL query statement, and
118  *    sent to the database for evaluation.
119  *
120  * The free_query() method frees the data structure returned from
121  *    compile_query()
122  *
123  * The run_query() callback takes a compiled query (generated by
124  *    compile_query) and runs the query in across the backend,
125  *    inserting the responses into the engine. The database will
126  *    return a set of splits and transactions and this callback needs
127  *    to poke these into the account-group hierarchy held by the query
128  *    object.
129  *
130  *    For a network-communications backend, essentially the same is
131  *    done, except that this routine would convert the query to wire
132  *    protocol, get an answer from the remote server, and push that
133  *    into the account-group object.
134  *
135  *    The returned list of entities can be used to build a local
136  *    cache of the matching data.  This will allow the QOF client to
137  *    continue functioning even when disconnected from the server:
138  *    this is because it will have its local cache of data from which to work.
139  *
140  * The sync() routine synchronizes the engine contents to the backend.
141  *    This should done by using version numbers (hack alert -- the engine
142  *    does not currently contain version numbers).
143  *    If the engine contents are newer than what is in the backend, the
144  *    data is stored to the backend. If the engine contents are older,
145  *    then the engine contents are updated.
146  *
147  *    Note that this sync operation is only meant to apply to the
148  *    current contents of the engine. This routine is not intended
149  *    to be used to fetch entity data from the backend.
150  *
151  *    File based backends tend to use sync as if it was called dump.
152  *    Data is written out into the backend, overwriting the previous
153  *    data. Database backends should implement a more intelligent
154  *    solution.
155  *
156  * The counter() routine increments the named counter and returns the
157  *    post-incremented value.  Returns -1 if there is a problem.
158  *
159  * The events_pending() routines should return true if there are
160  *    external events which need to be processed to bring the
161  *    engine up to date with the backend.
162  *
163  * The process_events() routine should process any events indicated
164  *    by the events_pending() routine. It should return TRUE if
165  *    the engine was changed while engine events were suspended.
166  *
167  * The last_err member indicates the last error that occurred.
168  *    It should probably be implemented as an array (actually,
169  *    a stack) of all the errors that have occurred.
170  *
171  * For support of book partitioning, use special "Book"  begin_edit()
172  *    and commit_edit() QOF_ID types.
173  *
174  *    Call the book begin() at the begining of a book partitioning.  A
175  *    'partitioning' is the splitting off of a chunk of the current
176  *    book into a second book by means of a query.  Every transaction
177  *    in that query is to be moved ('transfered') to the second book
178  *    from the existing book.  The argument of this routine is a
179  *    pointer to the second book, where the results of the query
180  *    should go.
181  *
182  *    Cann the book commit() to complete the book partitioning.
183  *
184  *    After the begin(), there will be a call to run_query(), followed
185  *    probably by a string of object calls, and completed by commit().
186  *    It should be explicitly understood that the results of that
187  *    run_query() precisely constitute the set of objects that are to
188  *    be moved between the initial and the new book. This specification
189  *    can be used by a clever backend to avoid excess data movement
190  *    between the server and the QOF client, as explained below.
191  *
192  *    There are several possible ways in which a backend may choose to
193  *    implement the book splitting process.  A 'file-type' backend may
194  *    choose to ignore this call, and the subsequent query, and simply
195  *    write out the new book to a file when the commit() call is made.
196  *    By that point, the engine will have performed all of the
197  *    nitty-gritty of moving transactions from one book to the other.
198  *
199  *    A 'database-type' backend has several interesting choices.  One
200  *    simple choice is to simply perform the run_query() as it
201  *    normally would, and likewise treat the object edits as usual.
202  *    In this scenario, the commit() is more or less a no-op.
203  *    This implementation has a drawback, however: the run_query() may
204  *    cause the transfer of a <b>huge</b> amount of data between the backend
205  *    and the engine.  For a large dataset, this is quite undesirable.
206  *    In addition, there are risks associated with the loss of network
207  *    connectivity during the transfer; thus a partition might terminate
208  *    half-finished, in some indeterminate state, due to network errors.
209  *    It might be difficult to recover from such errors: the engine does
210  *    not take any special safety measures during the transfer.
211  *
212  *    Thus, for a large database, an alternate implementation
213  *    might be to use the run_query() call as an opportunity to
214  *    transfer entities between the two books in the database,
215  *    and not actually return any new data to the engine.  In
216  *    this scenario, the engine will attempt to transfer those
217  *    entities that it does know about.  It does not, however,
218  *    need to know about all the other entities that also would
219  *    be transfered over.  In this way, a backend could perform
220  *    a mass transfer of entities between books without having
221  *    to actually move much (or any) data to the engine.
222  *
223  * To support configuration options from the frontend, the backend
224  *    can be passed a KvpFrame - according to the allowed options
225  *    for that backend, using load_config(). Configuration can be
226  *    updated at any point - it is up to the frontend to load the
227  *    data in time for whatever the backend needs to do. e.g. an
228  *    option to save a new book in a compressed format need not be
229  *    loaded until the backend is about to save. If the configuration
230  *    is updated by the user, the frontend should call load_config
231  *    again to update the backend.
232  *
233  *    Backends are responsible for ensuring that any supported
234  *    configuration options are initialised to usable values.
235  *    This should be done in the function called from backend_new.
236  */
237 
238 struct QofBackendProvider_s
239 {
240 /** Some arbitrary name given for this particular backend provider */
241 	const gchar *provider_name;
242 
243 /** The access method that this provider provides, for example,
244 file:// http:// postgres:// or sqlite://, but without
245 the :// at the end
246 */
247 	const gchar *access_method;
248 
249 /** \brief Partial QofBook handler
250 
251 TRUE if the backend handles external references
252 to entities outside this book and can save a QofBook that
253 does not contain any specific QOF objects. */
254 	gboolean partial_book_supported;
255 
256 /** Return a new, fully initialized backend.
257 
258 If the backend supports configuration, all configuration options
259 should be initialised to usable values here. */
260 	QofBackend *(*backend_new) (void);
261 
262 /** \brief Distinguish two providers with same access method.
263 
264 More than 1 backend can be registered under the same access_method,
265 so each one is passed the path to the data (e.g. a file) and
266 should return TRUE only:
267 -# if the backend recognises the type as one that it can load and
268 write or
269 -# if the path contains no data but can be used (e.g. a new session).
270 
271 \note If the backend can cope with more than one type, the backend
272 should not try to store or cache the sub-type for this data.
273 It is sufficient only to return TRUE if any ONE of the supported
274 types match the incoming data. The backend should not assume that
275 returning TRUE will mean that the data will naturally follow.
276 */
277 	  gboolean (*check_data_type) (const gchar *);
278 
279 /** Free this structure, unregister this backend handler. */
280 	void (*provider_free) (QofBackendProvider *);
281 };
282 
283 struct QofBackend_s
284 {
285 	void (*session_begin) (QofBackend * be,
286 						   QofSession * session,
287 						   const gchar * book_id,
288 						   gboolean ignore_lock,
289 						   gboolean create_if_nonexistent);
290 	void (*session_end) (QofBackend *);
291 	void (*destroy_backend) (QofBackend *);
292 	void (*load) (QofBackend *, QofBook *);
293 	void (*begin) (QofBackend *, QofInstance *);
294 	void (*commit) (QofBackend *, QofInstance *);
295 	void (*rollback) (QofBackend *, QofInstance *);
296 	gpointer (*compile_query) (QofBackend *, QofQuery *);
297 	void (*free_query) (QofBackend *, gpointer);
298 	void (*run_query) (QofBackend *, gpointer);
299 	void (*sync) (QofBackend *, QofBook *);
300 	void (*load_config) (QofBackend *, KvpFrame *);
301 	KvpFrame *(*get_config) (QofBackend *);
302 	gint64 (*counter) (QofBackend *, const gchar * counter_name);
303 	gboolean (*events_pending) (QofBackend *);
304 	gboolean (*process_events) (QofBackend *);
305 	QofBePercentageFunc percentage;
306 	QofBackendProvider *provider;
307 
308 /** Detect if the sync operation will overwrite data
309 
310 File based backends tend to consider the original file
311 as 'stale' immediately the data finishes loading. New data
312 only exists in memory and the data in the file is completely
313 replaced when qof_session_save is called. e.g. this routine can be
314 used to detect if a Save As... operation would overwrite a
315 possibly unrelated file. Not all file backends use this function.
316 
317 @return TRUE if the user may need to be warned about possible
318 data loss, otherwise FALSE.
319 */
320 	gboolean (*save_may_clobber_data) (QofBackend *);
321 
322 	/* stack of previous errors.
323 	   Similar errors can repeat within the stack. */
324 	GList * error_stack;
325 
326 
327 	KvpFrame *backend_configuration;
328 	gint config_count;
329 /** Each backend resolves a fully-qualified file path.
330 This holds the filepath and communicates it to the frontends.
331 */
332 	gchar *fullpath;
333 
334 };
335 
336 /** Let the sytem know about a new provider of backends.  This
337 function is typically called by the provider library at library
338 load time. This function allows the backend library to tell
339 QOF infrastructure that it can handle URL's of a certain type.
340 Note that a single backend library may register more than one
341 provider, if it is capable of handling more than one URL access
342 method. */
343 void
344 qof_backend_register_provider (QofBackendProvider *);
345 
346 void qof_backend_init (QofBackend * be);
347 
348 /** Allow backends to see if the book is open
349 
350 @return 'y' if book is open, otherwise 'n'.
351 */
352 gchar qof_book_get_open_marker (QofBook * book);
353 
354 /** get the book version
355 
356 used for tracking multiuser updates in backends.
357 
358 @return -1 if no book exists, 0 if the book is
359 new, otherwise the book version number.
360 */
361 gint32 qof_book_get_version (QofBook * book);
362 
363 /** get the book tag number
364 
365 used for kvp management in sql backends.
366 */
367 guint32 qof_book_get_idata (QofBook * book);
368 
369 void qof_book_set_version (QofBook * book, gint32 version);
370 
371 void qof_book_set_idata (QofBook * book, guint32 idata);
372 
373 /** @} */
374 /** @} */
375 /** @} */
376 #endif /* QOF_BACKEND_P_H */
377