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