Branch data Line data Source code
1 : : /***********************************************************************\
2 : : * gnc-sql-backend.hpp: Qof Backend for SQL Databases *
3 : : * *
4 : : * Copyright 2016 John Ralls <jralls@ceridwen.us> *
5 : : * *
6 : : * This program is free software; you can redistribute it and/or *
7 : : * modify it under the terms of the GNU General Public License as *
8 : : * published by the Free Software Foundation; either version 2 of *
9 : : * the License, or (at your option) any later version. *
10 : : * *
11 : : * This program is distributed in the hope that it will be useful, *
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 : : * GNU General Public License for more details. *
15 : : * *
16 : : * You should have received a copy of the GNU General Public License *
17 : : * along with this program; if not, contact: *
18 : : * *
19 : : * Free Software Foundation Voice: +1-617-542-5942 *
20 : : * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 : : * Boston, MA 02110-1301, USA gnu@gnu.org *
22 : : \***********************************************************************/
23 : :
24 : : #ifndef __GNC_SQL_BACKEND_HPP__
25 : : #define __GNC_SQL_BACKEND_HPP__
26 : :
27 : : #include <qof.h>
28 : : #include <Account.h>
29 : :
30 : : #include <memory>
31 : : #include <exception>
32 : : #include <sstream>
33 : : #include <vector>
34 : : #include <qof-backend.hpp>
35 : :
36 : : class GncSqlColumnTableEntry;
37 : : using GncSqlColumnTableEntryPtr = std::shared_ptr<GncSqlColumnTableEntry>;
38 : : using EntryVec = std::vector<GncSqlColumnTableEntryPtr>;
39 : : class GncSqlObjectBackend;
40 : : using GncSqlObjectBackendPtr = std::shared_ptr<GncSqlObjectBackend>;
41 : : using OBEEntry = std::tuple<std::string, GncSqlObjectBackendPtr>;
42 : : using OBEVec = std::vector<OBEEntry>;
43 : : class GncSqlConnection;
44 : : class GncSqlStatement;
45 : : using GncSqlStatementPtr = std::unique_ptr<GncSqlStatement>;
46 : : class GncSqlResult;
47 : : using GncSqlResultPtr = GncSqlResult*;
48 : : using VersionPair = std::pair<const std::string, unsigned int>;
49 : : using VersionVec = std::vector<VersionPair>;
50 : : using uint_t = unsigned int;
51 : :
52 : : typedef enum
53 : : {
54 : : OP_DB_INSERT,
55 : : OP_DB_UPDATE,
56 : : OP_DB_DELETE
57 : : } E_DB_OPERATION;
58 : :
59 : : /**
60 : : *
61 : : * Main SQL backend structure.
62 : : */
63 : : class GncSqlBackend : public QofBackend
64 : : {
65 : : public:
66 : : GncSqlBackend(GncSqlConnection *conn, QofBook* book);
67 : : virtual ~GncSqlBackend();
68 : : /**
69 : : * Load the contents of an SQL database into a book.
70 : : *
71 : : * @param book Book to be loaded
72 : : */
73 : : void load(QofBook*, QofBackendLoadType) override;
74 : : /**
75 : : * Save the contents of a book to an SQL database.
76 : : *
77 : : * @param book Book to be saved
78 : : */
79 : : void sync(QofBook*) override;
80 : : /**
81 : : * An object is about to be edited.
82 : : *
83 : : * @param inst Object being edited
84 : : */
85 : : void begin(QofInstance*) override;
86 : : /**
87 : : * Object editing is complete and the object should be saved.
88 : : *
89 : : * @param inst Object being edited
90 : : */
91 : : void commit(QofInstance*) override;
92 : : /**
93 : : * Object editing has been cancelled.
94 : : *
95 : : * @param inst Object being edited
96 : : */
97 : : void rollback(QofInstance*) override;
98 : : /** Connect the backend to a GncSqlConnection.
99 : : * Sets up version info. Calling with nullptr clears the connection and
100 : : * destroys the version info.
101 : : */
102 : : void connect(GncSqlConnection *conn) noexcept;
103 : : /**
104 : : * Initializes DB table version information.
105 : : */
106 : : void init_version_info() noexcept;
107 : : bool reset_version_info() noexcept;
108 : : /**
109 : : * Finalizes DB table version information.
110 : : */
111 : : void finalize_version_info() noexcept;
112 : : /* FIXME: These are just pass-throughs of m_conn functions. */
113 : : GncSqlStatementPtr create_statement_from_sql(const std::string& str) const noexcept;
114 : : /** Executes an SQL SELECT statement and returns the result rows. If an
115 : : * error occurs, an entry is added to the log, an error status is returned
116 : : * to qof and nullptr is returned.
117 : : *
118 : : * @param statement Statement
119 : : * @return Results, or nullptr if an error has occurred
120 : : */
121 : : GncSqlResultPtr execute_select_statement(const GncSqlStatementPtr& stmt) const noexcept;
122 : : int execute_nonselect_statement(const GncSqlStatementPtr& stmt) const noexcept;
123 : : std::string quote_string(const std::string&) const noexcept;
124 : : /**
125 : : * Creates a table in the database
126 : : *
127 : : * @param table_name Table name
128 : : * @param col_table DB table description
129 : : * @return TRUE if successful, FALSE if unsuccessful
130 : : */
131 : : bool create_table(const std::string& table_name, const EntryVec& col_table) const noexcept;
132 : : /**
133 : : * Creates a table in the database and sets its version
134 : : *
135 : : * @param table_name Table name
136 : : * @param table_version Table version
137 : : * @param col_table DB table description
138 : : * @return TRUE if successful, FALSE if unsuccessful
139 : : */
140 : : bool create_table(const std::string& table_name, int table_version,
141 : : const EntryVec& col_table) noexcept;
142 : : /**
143 : : * Create/update all tables in the database
144 : : */
145 : : void create_tables() noexcept;
146 : :
147 : : /**
148 : : * Creates an index in the database
149 : : *
150 : : * @param index_name Index name
151 : : * @param table_name Table name
152 : : * @param col_table Columns that the index should index
153 : : * @return TRUE if successful, FALSE if unsuccessful
154 : : */
155 : : bool create_index(const std::string& index_name,
156 : : const std::string& table_name,
157 : : const EntryVec& col_table) const noexcept;
158 : : /**
159 : : * Adds one or more columns to an existing table.
160 : : *
161 : : * @param table_name SQL table name
162 : : * @param new_col_table Column table for new columns
163 : : * @return TRUE if successful, FALSE if unsuccessful
164 : : */
165 : : bool add_columns_to_table(const std::string& table_name,
166 : : const EntryVec& col_table) const noexcept;
167 : : /**
168 : : * Upgrades a table to a new structure.
169 : : *
170 : : * The upgrade is done by creating a new table with the new structure,
171 : : * SELECTing the old data into the new table, deleting the old table, then
172 : : * renaming the new table. Therefore, this will only work if the new table
173 : : * structure is similar enough to the old table that the SELECT will work.
174 : : *
175 : : * @param table_name SQL table name
176 : : * @param col_table Column table
177 : : */
178 : : void upgrade_table (const std::string& table_name,
179 : : const EntryVec& col_table) noexcept;
180 : : /**
181 : : * Returns the version number for a DB table.
182 : : *
183 : : * @param table_name Table name
184 : : * @return Version number, or 0 if the table does not exist
185 : : */
186 : : uint_t get_table_version(const std::string& table_name) const noexcept;
187 : : bool set_table_version (const std::string& table_name, uint_t version) noexcept;
188 : : /**
189 : : * Register a commodity to be committed after loading is complete.
190 : : *
191 : : * Necessary to save corrections made while loading.
192 : : * @param comm The commodity item to be committed.
193 : : */
194 : : void commodity_for_postload_processing(gnc_commodity*);
195 : : /**
196 : : * Get the GncSqlObjectBackend for the indicated type.
197 : : *
198 : : * Required because we need to pass a pointer to this to a callback via a C
199 : : * function.
200 : : * @param type: The QofInstance type constant to select the object backend.
201 : : */
202 : : GncSqlObjectBackendPtr get_object_backend(const std::string& type) const noexcept;
203 : : /**
204 : : * Checks whether an object is in the database or not.
205 : : *
206 : : * @param table_name DB table name
207 : : * @param obj_name QOF object type name
208 : : * @param pObject Object to be checked
209 : : * @param table DB table description
210 : : * @return TRUE if the object is in the database, FALSE otherwise
211 : : */
212 : : bool object_in_db (const char* table_name, QofIdTypeConst obj_name,
213 : : const gpointer pObject, const EntryVec& table ) const noexcept;
214 : : /**
215 : : * Performs an operation on the database.
216 : : *
217 : : * @param op Operation type
218 : : * @param table_name SQL table name
219 : : * @param obj_name QOF object type name
220 : : * @param pObject Gnucash object
221 : : * @param table DB table description
222 : : * @return TRUE if successful, FALSE if not
223 : : */
224 : : bool do_db_operation (E_DB_OPERATION op, const char* table_name,
225 : : QofIdTypeConst obj_name, gpointer pObject,
226 : : const EntryVec& table) const noexcept;
227 : : /**
228 : : * Ensure that a commodity referenced in another object is in fact saved
229 : : * in the database.
230 : : *
231 : : * @param comm The commodity in question
232 : : * @return true if the commodity needed to be saved.
233 : : */
234 : : bool save_commodity(gnc_commodity* comm) noexcept;
235 : 409 : QofBook* book() const noexcept { return m_book; }
236 : 0 : void set_loading(bool loading) noexcept { m_loading = loading; }
237 : 188 : bool pristine() const noexcept { return m_is_pristine_db; }
238 : : void update_progress(double pct) const noexcept;
239 : : void finish_progress() const noexcept;
240 : :
241 : : protected:
242 : : GncSqlConnection* m_conn = nullptr; /**< SQL connection */
243 : : QofBook* m_book = nullptr; /**< The primary, main open book */
244 : : bool m_loading; /**< We are performing an initial load */
245 : : bool m_in_query; /**< We are processing a query */
246 : : bool m_is_pristine_db; /**< Are we saving to a new pristine db? */
247 : : const char* m_time_format = nullptr; /**< Server-specific date-time string format */
248 : : VersionVec m_versions; /**< Version number for each table */
249 : : private:
250 : : bool write_account_tree(Account*);
251 : : bool write_accounts();
252 : : bool write_transactions();
253 : : bool write_template_transactions();
254 : : bool write_schedXactions();
255 : : GncSqlStatementPtr build_insert_statement (const char* table_name,
256 : : QofIdTypeConst obj_name,
257 : : gpointer pObject,
258 : : const EntryVec& table) const noexcept;
259 : : GncSqlStatementPtr build_update_statement (const gchar* table_name,
260 : : QofIdTypeConst obj_name,
261 : : gpointer pObject,
262 : : const EntryVec& table) const noexcept;
263 : : GncSqlStatementPtr build_delete_statement (const char* table_name,
264 : : QofIdTypeConst obj_name,
265 : : gpointer pObject,
266 : : const EntryVec& table) const noexcept;
267 : :
268 : : class ObjectBackendRegistry
269 : : {
270 : : public:
271 : : ObjectBackendRegistry();
272 : : ObjectBackendRegistry(const ObjectBackendRegistry&) = delete;
273 : : ObjectBackendRegistry(const ObjectBackendRegistry&&) = delete;
274 : : ObjectBackendRegistry operator=(const ObjectBackendRegistry&) = delete;
275 : : ObjectBackendRegistry operator=(const ObjectBackendRegistry&&) = delete;
276 : 10 : ~ObjectBackendRegistry() = default;
277 : : void register_backend(OBEEntry&& entry) noexcept;
278 : : void register_backend(GncSqlObjectBackendPtr obe) noexcept;
279 : : GncSqlObjectBackendPtr get_object_backend(const std::string& type) const;
280 : : void load_remaining(GncSqlBackend*);
281 : 15 : OBEVec::iterator begin() { return m_registry.begin(); }
282 : 15 : OBEVec::iterator end() { return m_registry.end(); }
283 : 5 : OBEVec::size_type size() { return m_registry.size(); }
284 : : private:
285 : : OBEVec m_registry;
286 : : };
287 : : ObjectBackendRegistry m_backend_registry;
288 : : std::vector<gnc_commodity*> m_postload_commodities;
289 : : };
290 : :
291 : : #endif //__GNC_SQL_BACKEND_HPP__
|