Branch data Line data Source code
1 : : /********************************************************************\
2 : : * gnc-bill-term-sql.c -- billing term sql 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 : :
23 : : /** @file gnc-bill-term-sql.c
24 : : * @brief load and save address data to SQL
25 : : * @author Copyright (c) 2007-2008 Phil Longstaff <plongstaff@rogers.com>
26 : : *
27 : : * This file implements the top-level QofBackend API for saving/
28 : : * restoring data to/from an SQL database
29 : : */
30 : : #include <guid.hpp>
31 : : #include <config.h>
32 : :
33 : : #include <glib.h>
34 : : #include <stdlib.h>
35 : : #include <string.h>
36 : :
37 : : #include "gncBillTermP.h"
38 : : #include "gncInvoice.h"
39 : : #include "qof.h"
40 : :
41 : : #include <string>
42 : : #include <vector>
43 : : #include <algorithm>
44 : :
45 : : #include "gnc-sql-connection.hpp"
46 : : #include "gnc-sql-backend.hpp"
47 : : #include "gnc-sql-object-backend.hpp"
48 : : #include "gnc-sql-column-table-entry.hpp"
49 : : #include "gnc-slots-sql.h"
50 : : #include "gnc-bill-term-sql.h"
51 : :
52 : : #define _GNC_MOD_NAME GNC_ID_BILLTERM
53 : :
54 : : static QofLogModule log_module = G_LOG_DOMAIN;
55 : :
56 : : #define MAX_NAME_LEN 2048
57 : : #define MAX_DESCRIPTION_LEN 2048
58 : : #define MAX_TYPE_LEN 2048
59 : :
60 : : static void set_invisible (gpointer data, gboolean value);
61 : : static gpointer bt_get_parent (gpointer data);
62 : : static void bt_set_parent (gpointer data, gpointer value);
63 : : static void bt_set_parent_guid (gpointer data, gpointer value);
64 : :
65 : : #define TABLE_NAME "billterms"
66 : : #define TABLE_VERSION 2
67 : :
68 : : static EntryVec col_table
69 : : {
70 : : gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid"),
71 : : gnc_sql_make_table_entry<CT_STRING>("name", MAX_NAME_LEN, COL_NNUL, "name"),
72 : : gnc_sql_make_table_entry<CT_STRING>("description", MAX_DESCRIPTION_LEN,
73 : : COL_NNUL, GNC_BILLTERM_DESC,
74 : : true),
75 : : gnc_sql_make_table_entry<CT_INT>("refcount", 0, COL_NNUL,
76 : : (QofAccessFunc)gncBillTermGetRefcount,
77 : : (QofSetterFunc)gncBillTermSetRefcount),
78 : : gnc_sql_make_table_entry<CT_BOOLEAN>("invisible", 0, COL_NNUL,
79 : : (QofAccessFunc)gncBillTermGetInvisible,
80 : : (QofSetterFunc)set_invisible),
81 : : gnc_sql_make_table_entry<CT_GUID>("parent", 0, 0,
82 : : (QofAccessFunc)bt_get_parent,
83 : : (QofSetterFunc)bt_set_parent),
84 : : gnc_sql_make_table_entry<CT_STRING>("type", MAX_TYPE_LEN, COL_NNUL,
85 : : GNC_BILLTERM_TYPE, true),
86 : : gnc_sql_make_table_entry<CT_INT>("duedays", 0, 0, GNC_BILLTERM_DUEDAYS,
87 : : true),
88 : : gnc_sql_make_table_entry<CT_INT>("discountdays", 0, 0,
89 : : GNC_BILLTERM_DISCDAYS, true),
90 : : gnc_sql_make_table_entry<CT_NUMERIC>("discount", 0, 0,
91 : : GNC_BILLTERM_DISCOUNT, true),
92 : : gnc_sql_make_table_entry<CT_INT>("cutoff", 0, 0, GNC_BILLTERM_CUTOFF,
93 : : true),
94 : : };
95 : :
96 : : static EntryVec billterm_parent_col_table
97 : : {
98 : : gnc_sql_make_table_entry<CT_GUID>("parent", 0, 0, nullptr,
99 : : bt_set_parent_guid),
100 : : };
101 : :
102 : 10 : GncSqlBillTermBackend::GncSqlBillTermBackend() :
103 : : GncSqlObjectBackend(TABLE_VERSION, GNC_ID_BILLTERM,
104 : 10 : TABLE_NAME, col_table) {}
105 : :
106 : : struct BillTermParentGuid
107 : : {
108 : : GncBillTerm* billterm;
109 : : GncGUID guid;
110 : : bool have_guid;
111 : : };
112 : :
113 : : using BillTermParentGuidPtr = BillTermParentGuid*;
114 : : using BillTermParentGuidVec = std::vector<BillTermParentGuidPtr>;
115 : :
116 : : static void
117 : 0 : set_invisible (gpointer data, gboolean value)
118 : : {
119 : 0 : GncBillTerm* term = GNC_BILLTERM (data);
120 : :
121 : 0 : g_return_if_fail (term != NULL);
122 : :
123 : 0 : if (value)
124 : : {
125 : 0 : gncBillTermMakeInvisible (term);
126 : : }
127 : : }
128 : :
129 : : static gpointer
130 : 0 : bt_get_parent (gpointer pObject)
131 : : {
132 : : const GncBillTerm* billterm;
133 : : const GncBillTerm* pParent;
134 : : const GncGUID* parent_guid;
135 : :
136 : 0 : g_return_val_if_fail (pObject != NULL, NULL);
137 : 0 : g_return_val_if_fail (GNC_IS_BILLTERM (pObject), NULL);
138 : :
139 : 0 : billterm = GNC_BILLTERM (pObject);
140 : 0 : pParent = gncBillTermGetParent (billterm);
141 : 0 : if (pParent == NULL)
142 : : {
143 : 0 : parent_guid = NULL;
144 : : }
145 : : else
146 : : {
147 : 0 : parent_guid = qof_instance_get_guid (QOF_INSTANCE (pParent));
148 : : }
149 : :
150 : 0 : return (gpointer)parent_guid;
151 : : }
152 : :
153 : : static void
154 : 0 : bt_set_parent (gpointer data, gpointer value)
155 : : {
156 : : GncBillTerm* billterm;
157 : : GncBillTerm* parent;
158 : : QofBook* pBook;
159 : 0 : GncGUID* guid = (GncGUID*)value;
160 : :
161 : 0 : g_return_if_fail (data != NULL);
162 : 0 : g_return_if_fail (GNC_IS_BILLTERM (data));
163 : :
164 : 0 : billterm = GNC_BILLTERM (data);
165 : 0 : pBook = qof_instance_get_book (QOF_INSTANCE (billterm));
166 : 0 : if (guid != NULL)
167 : : {
168 : 0 : parent = gncBillTermLookup (pBook, guid);
169 : 0 : if (parent != NULL)
170 : : {
171 : 0 : gncBillTermSetParent (billterm, parent);
172 : 0 : gncBillTermSetChild (parent, billterm);
173 : : }
174 : : }
175 : : }
176 : :
177 : : static void
178 : 0 : bt_set_parent_guid (gpointer pObject, gpointer pValue)
179 : : {
180 : 0 : g_return_if_fail (pObject != NULL);
181 : 0 : g_return_if_fail (pValue != NULL);
182 : :
183 : 0 : auto s = static_cast<BillTermParentGuidPtr>(pObject);
184 : 0 : s->guid = *static_cast<GncGUID*>(pValue);
185 : 0 : s->have_guid = true;
186 : : }
187 : :
188 : : static GncBillTerm*
189 : 0 : load_single_billterm (GncSqlBackend* sql_be, GncSqlRow& row,
190 : : BillTermParentGuidVec& l_billterms_needing_parents)
191 : : {
192 : 0 : g_return_val_if_fail (sql_be != NULL, NULL);
193 : :
194 : 0 : auto guid = gnc_sql_load_guid (sql_be, row);
195 : 0 : auto pBillTerm = gncBillTermLookup (sql_be->book(), guid);
196 : 0 : if (pBillTerm == nullptr)
197 : : {
198 : 0 : pBillTerm = gncBillTermCreate (sql_be->book());
199 : : }
200 : 0 : gnc_sql_load_object (sql_be, row, GNC_ID_BILLTERM, pBillTerm, col_table);
201 : :
202 : : /* If the billterm doesn't have a parent, it might be because it hasn't been
203 : : loaded yet. If so, add this billterm to the list of billterms with no
204 : : parent, along with the parent GncGUID so that after they are all loaded,
205 : : the parents can be fixed up. */
206 : 0 : if (gncBillTermGetParent (pBillTerm) == NULL)
207 : : {
208 : : BillTermParentGuid s;
209 : :
210 : 0 : s.billterm = pBillTerm;
211 : 0 : s.have_guid = false;
212 : 0 : gnc_sql_load_object (sql_be, row, GNC_ID_BILLTERM, &s,
213 : : billterm_parent_col_table);
214 : 0 : if (s.have_guid)
215 : 0 : l_billterms_needing_parents.push_back(new BillTermParentGuid(s));
216 : :
217 : : }
218 : :
219 : 0 : qof_instance_mark_clean (QOF_INSTANCE (pBillTerm));
220 : :
221 : 0 : return pBillTerm;
222 : : }
223 : :
224 : : /* Because gncBillTermLookup has the arguments backwards: */
225 : : static inline GncBillTerm*
226 : 0 : gnc_billterm_lookup (const GncGUID *guid, const QofBook *book)
227 : : {
228 : 0 : QOF_BOOK_RETURN_ENTITY(book, guid, GNC_ID_BILLTERM, GncBillTerm);
229 : : }
230 : :
231 : : void
232 : 5 : GncSqlBillTermBackend::load_all (GncSqlBackend* sql_be)
233 : : {
234 : :
235 : 5 : g_return_if_fail (sql_be != NULL);
236 : :
237 : 5 : std::string sql("SELECT * FROM " TABLE_NAME);
238 : 5 : auto stmt = sql_be->create_statement_from_sql(sql);
239 : 5 : auto result = sql_be->execute_select_statement(stmt);
240 : 5 : BillTermParentGuidVec l_billterms_needing_parents;
241 : :
242 : 5 : for (auto row : *result)
243 : : {
244 : 0 : load_single_billterm (sql_be, row, l_billterms_needing_parents);
245 : 5 : }
246 : 5 : delete result;
247 : 5 : std::string pkey(col_table[0]->name());
248 : 5 : sql = "SELECT DISTINCT ";
249 : 5 : sql += pkey + " FROM " TABLE_NAME;
250 : 5 : gnc_sql_slots_load_for_sql_subquery (sql_be, sql,
251 : : (BookLookupFn)gnc_billterm_lookup);
252 : :
253 : : /* While there are items on the list of billterms needing parents,
254 : : try to see if the parent has now been loaded. Theory says that if
255 : : items are removed from the front and added to the back if the
256 : : parent is still not available, then eventually, the list will
257 : : shrink to size 0. */
258 : 5 : if (!l_billterms_needing_parents.empty())
259 : : {
260 : 0 : bool progress_made = true;
261 : 0 : std::reverse(l_billterms_needing_parents.begin(),
262 : : l_billterms_needing_parents.end());
263 : 0 : auto end = l_billterms_needing_parents.end();
264 : 0 : while (progress_made)
265 : : {
266 : 0 : progress_made = false;
267 : 0 : end = std::remove_if(l_billterms_needing_parents.begin(), end,
268 : 0 : [&](BillTermParentGuidPtr s)
269 : : {
270 : 0 : auto pBook = qof_instance_get_book (QOF_INSTANCE (s->billterm));
271 : 0 : auto parent = gncBillTermLookup (pBook,
272 : 0 : &s->guid);
273 : 0 : if (parent != nullptr)
274 : : {
275 : 0 : gncBillTermSetParent (s->billterm, parent);
276 : 0 : gncBillTermSetChild (parent, s->billterm);
277 : 0 : progress_made = true;
278 : 0 : delete s;
279 : 0 : return true;
280 : : }
281 : 0 : return false;
282 : : });
283 : : }
284 : : }
285 : 5 : }
286 : :
287 : : /* ================================================================= */
288 : :
289 : : static void
290 : 0 : do_save_billterm (QofInstance* inst, void* p2)
291 : : {
292 : 0 : auto data = static_cast<write_objects_t*>(p2);
293 : 0 : data->commit(inst);
294 : 0 : }
295 : :
296 : : bool
297 : 5 : GncSqlBillTermBackend::write (GncSqlBackend* sql_be)
298 : : {
299 : 5 : g_return_val_if_fail (sql_be != NULL, FALSE);
300 : :
301 : 5 : write_objects_t data {sql_be, true, this};
302 : 5 : qof_object_foreach (GNC_ID_BILLTERM, sql_be->book(), do_save_billterm, &data);
303 : 5 : return data.is_ok;
304 : : }
305 : :
306 : : /* ================================================================= */
307 : : void
308 : 10 : GncSqlBillTermBackend::create_tables (GncSqlBackend* sql_be)
309 : : {
310 : : gint version;
311 : :
312 : 10 : g_return_if_fail (sql_be != NULL);
313 : :
314 : 10 : version = sql_be->get_table_version( TABLE_NAME);
315 : 10 : if (version == 0)
316 : : {
317 : 5 : sql_be->create_table(TABLE_NAME, TABLE_VERSION, col_table);
318 : : }
319 : 5 : else if (version < m_version)
320 : : {
321 : : /* Upgrade 64 bit int handling */
322 : 0 : sql_be->upgrade_table(TABLE_NAME, col_table);
323 : 0 : sql_be->set_table_version (TABLE_NAME, TABLE_VERSION);
324 : :
325 : 0 : PINFO ("Billterms table upgraded from version 1 to version %d\n",
326 : : TABLE_VERSION);
327 : : }
328 : : }
329 : :
330 : : /* ================================================================= */
331 : :
332 : : template<> void
333 : 3 : GncSqlColumnTableEntryImpl<CT_BILLTERMREF>::load (const GncSqlBackend* sql_be,
334 : : GncSqlRow& row,
335 : : QofIdTypeConst obj_name,
336 : : gpointer pObject) const noexcept
337 : : {
338 : 3 : load_from_guid_ref(row, obj_name, pObject,
339 : 0 : [sql_be](GncGUID* g){
340 : 0 : return gncBillTermLookup(sql_be->book(), g);
341 : : });
342 : 3 : }
343 : :
344 : : template<> void
345 : 15 : GncSqlColumnTableEntryImpl<CT_BILLTERMREF>::add_to_table(ColVec& vec) const noexcept
346 : : {
347 : 15 : add_objectref_guid_to_table(vec);
348 : 15 : }
349 : :
350 : : template<> void
351 : 3 : GncSqlColumnTableEntryImpl<CT_BILLTERMREF>::add_to_query(QofIdTypeConst obj_name,
352 : : const gpointer pObject,
353 : : PairVec& vec) const noexcept
354 : : {
355 : 3 : add_objectref_guid_to_query(obj_name, pObject, vec);
356 : 3 : }
357 : :
358 : : /* ========================== END OF FILE ===================== */
|