GnuCash  4.8a-176-g88ecf8dd1
qof-backend.hpp
1 /********************************************************************\
2  * qof-backend.hpp Declare QofBackend class *
3  * Copyright 2016 John Ralls <jralls@ceridwen.us> *
4  * *
5  * This program is free software; you can redistribute it and/or *
6  * modify it under the terms of the GNU General Public License as *
7  * published by the Free Software Foundation; either version 2 of *
8  * the License, or (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License*
16  * along with this program; if not, contact: *
17  * *
18  * Free Software Foundation Voice: +1-617-542-5942 *
19  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
20  * Boston, MA 02110-1301, USA gnu@gnu.org *
21  * *
22 \********************************************************************/
42 #ifndef __QOF_BACKEND_HPP__
43 #define __QOF_BACKEND_HPP__
44 extern "C"
45 {
46 #include "qofbackend.h"
47 #include "qofbook.h"
48 #include "qofquery.h"
49 #include "qofsession.h"
50 #include <gmodule.h>
51 }
52 
53 #include "qofinstance-p.h"
54 #include <string>
55 #include <algorithm>
56 #include <vector>
57 /* NOTE: The following comments were musings by the original developer about how
58  * some additional API might work. The compile/free/run_query functions were
59  * implemented for the DBI backend but never put into use; the rest were never
60  * implemented. They're here as something to consider if we ever decide to
61  * implement them.
62  *
63  * The compile_query() method compiles a QOF query object into
64  * a backend-specific data structure and returns the compiled
65  * query. For an SQL backend, the contents of the query object
66  * need to be turned into a corresponding SQL query statement, and
67  * sent to the database for evaluation.
68  *
69  * The free_query() method frees the data structure returned from
70  * compile_query()
71  *
72  * The run_query() callback takes a compiled query (generated by
73  * compile_query) and runs the query in across the backend,
74  * inserting the responses into the engine. The database will
75  * return a set of splits and transactions and this callback needs
76  * to poke these into the account-group hierarchy held by the query
77  * object.
78  *
79  * For a network-communications backend, essentially the same is
80  * done, except that this routine would convert the query to wire
81  * protocol, get an answer from the remote server, and push that
82  * into the account-group object.
83  *
84  * The returned list of entities can be used to build a local
85  * cache of the matching data. This will allow the QOF client to
86  * continue functioning even when disconnected from the server:
87  * this is because it will have its local cache of data from which to work.
88  *
89  * The events_pending() routines should return true if there are
90  * external events which need to be processed to bring the
91  * engine up to date with the backend.
92  *
93  * The process_events() routine should process any events indicated
94  * by the events_pending() routine. It should return TRUE if
95  * the engine was changed while engine events were suspended.
96  *
97  * For support of book partitioning, use special "Book" begin_edit()
98  * and commit_edit() QOF_ID types.
99  *
100  * Call the book begin() at the beginning of a book partitioning. A
101  * 'partitioning' is the splitting off of a chunk of the current
102  * book into a second book by means of a query. Every transaction
103  * in that query is to be moved ('transferred') to the second book
104  * from the existing book. The argument of this routine is a
105  * pointer to the second book, where the results of the query
106  * should go.
107  *
108  * Call the book commit() to complete the book partitioning.
109  *
110  * After the begin(), there will be a call to run_query(), followed
111  * probably by a string of object calls, and completed by commit().
112  * It should be explicitly understood that the results of that
113  * run_query() precisely constitute the set of objects that are to
114  * be moved between the initial and the new book. This specification
115  * can be used by a clever backend to avoid excess data movement
116  * between the server and the QOF client, as explained below.
117  *
118  * There are several possible ways in which a backend may choose to
119  * implement the book splitting process. A 'file-type' backend may
120  * choose to ignore this call, and the subsequent query, and simply
121  * write out the new book to a file when the commit() call is made.
122  * By that point, the engine will have performed all of the
123  * nitty-gritty of moving transactions from one book to the other.
124  *
125  * A 'database-type' backend has several interesting choices. One
126  * simple choice is to simply perform the run_query() as it
127  * normally would, and likewise treat the object edits as usual.
128  * In this scenario, the commit() is more or less a no-op.
129  * This implementation has a drawback, however: the run_query() may
130  * cause the transfer of a <b>huge</b> amount of data between the backend
131  * and the engine. For a large dataset, this is quite undesirable.
132  * In addition, there are risks associated with the loss of network
133  * connectivity during the transfer; thus a partition might terminate
134  * half-finished, in some indeterminate state, due to network errors.
135  * It might be difficult to recover from such errors: the engine does
136  * not take any special safety measures during the transfer.
137  *
138  * Thus, for a large database, an alternate implementation
139  * might be to use the run_query() call as an opportunity to
140  * transfer entities between the two books in the database,
141  * and not actually return any new data to the engine. In
142  * this scenario, the engine will attempt to transfer those
143  * entities that it does know about. It does not, however,
144  * need to know about all the other entities that also would
145  * be transferred over. In this way, a backend could perform
146  * a mass transfer of entities between books without having
147  * to actually move much (or any) data to the engine.
148  *
149  * To support configuration options from the frontend, the backend
150  * can be passed a KvpFrame - according to the allowed options
151  * for that backend, using load_config(). Configuration can be
152  * updated at any point - it is up to the frontend to load the
153  * data in time for whatever the backend needs to do. e.g. an
154  * option to save a new book in a compressed format need not be
155  * loaded until the backend is about to save. If the configuration
156  * is updated by the user, the frontend should call load_config
157  * again to update the backend.
158  *
159  * Backends are responsible for ensuring that any supported
160  * configuration options are initialised to usable values.
161  * This should be done in the function called from backend_new.
162  */
163 
164 
165 typedef enum
166 {
167  LOAD_TYPE_INITIAL_LOAD,
168  LOAD_TYPE_LOAD_ALL
169 } QofBackendLoadType;
170 
171 using GModuleVec = std::vector<GModule*>;
173 {
174 public:
175  /* For reasons that aren't a bit clear, using the default constructor
176  * sometimes initializes m_last_err incorrectly with Xcode8 and a 32-bit
177  * build unless the initialization is stepped-through in a debugger.
178  */
179  QofBackend() :
180  m_percentage{nullptr}, m_fullpath{}, m_last_err{ERR_BACKEND_NO_ERR},
181  m_error_msg{} {}
182  QofBackend(const QofBackend&) = delete;
183  QofBackend(const QofBackend&&) = delete;
184  virtual ~QofBackend() = default;
191  virtual void session_begin(QofSession *session, const char* new_uri,
192  SessionOpenMode mode) = 0;
193  virtual void session_end() = 0;
214  virtual void load (QofBook*, QofBackendLoadType) = 0;
219  virtual void begin(QofInstance*) {}
223  virtual void commit (QofInstance*);
227  virtual void rollback(QofInstance*) {}
245  virtual void sync(QofBook *) = 0;
248  virtual void safe_sync(QofBook *) = 0;
252  virtual void export_coa(QofBook *) {}
255  void set_error(QofBackendError err);
261  bool check_error();
265  void set_message(std::string&&);
268  const std::string&& get_message();
272  void set_percentage(QofBePercentageFunc pctfn) { m_percentage = pctfn; }
273  QofBePercentageFunc get_percentage() { return m_percentage; }
276  const std::string& get_uri() { return m_fullpath; }
281  static bool register_backend(const char*, const char*);
282  static void release_backends();
283 protected:
284  QofBePercentageFunc m_percentage;
288  std::string m_fullpath;
289 private:
290  static GModuleVec c_be_registry;
291  QofBackendError m_last_err;
292  std::string m_error_msg;
293 };
294 
295 /* @} */
296 /* @} */
297 /* @} */
298 
299 #endif /* __QOF_BACKEND_HPP__ */
void set_percentage(QofBePercentageFunc pctfn)
Store and retrieve a backend-specific function for determining the progress in completing a long oper...
Encapsulates a connection to a backend (persistent store)
API for data storage Backend.
const std::string && get_message()
Retrieve and clear the stored error message.
Definition: qof-backend.cpp:88
void set_message(std::string &&)
Set a descriptive message that can be displayed to the user when there&#39;s an error.
Definition: qof-backend.cpp:82
QofBackendError
The errors that can be reported to the GUI & other front-end users.
Definition: qofbackend.h:57
virtual void commit(QofInstance *)
Commits the changes from the engine to the backend data storage.
Definition: qof-backend.cpp:52
virtual void session_begin(QofSession *session, const char *new_uri, SessionOpenMode mode)=0
Open the file or connect to the server.
find objects that match a certain expression.
virtual void begin(QofInstance *)
Called when the engine is about to make a change to a data structure.
static bool register_backend(const char *, const char *)
Class methods for dynamically loading the several backends and for freeing them at shutdown...
Definition: qof-backend.cpp:94
virtual void export_coa(QofBook *)
Extract the chart of accounts from the current database and create a new database with it...
std::string m_fullpath
Each backend resolves a fully-qualified file path.
virtual void load(QofBook *, QofBackendLoadType)=0
Load the minimal set of application data needed for the application to be operable at initial startup...
Encapsulate all the information about a dataset.
virtual void safe_sync(QofBook *)=0
Perform a sync in a way that prevents data loss on a DBI backend.
SessionOpenMode
Mode for opening sessions.
Definition: qofsession.h:120
virtual void rollback(QofInstance *)
Revert changes in the engine and unlock the backend.
void(* QofBePercentageFunc)(const char *message, double percent)
DOCUMENT ME!
Definition: qofbackend.h:163
virtual void sync(QofBook *)=0
Synchronizes the engine contents to the backend.
bool check_error()
Report if there is an error.
Definition: qof-backend.cpp:76
const std::string & get_uri()
Retrieve the backend&#39;s storage URI.
void set_error(QofBackendError err)
Set the error value only if there isn&#39;t already an error already.
Definition: qof-backend.cpp:59
QofBackendError get_error()
Retrieve the currently-stored error and clear it.
Definition: qof-backend.cpp:67