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 15 : GncSqlBillTermBackend::GncSqlBillTermBackend() :
103 30 : GncSqlObjectBackend(TABLE_VERSION, GNC_ID_BILLTERM,
104 75 : 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 7 : GncSqlBillTermBackend::load_all (GncSqlBackend* sql_be)
233 : {
234 :
235 7 : g_return_if_fail (sql_be != NULL);
236 :
237 7 : std::string sql("SELECT * FROM " TABLE_NAME);
238 7 : auto stmt = sql_be->create_statement_from_sql(sql);
239 7 : auto result = sql_be->execute_select_statement(stmt);
240 7 : BillTermParentGuidVec l_billterms_needing_parents;
241 :
242 7 : for (auto row : *result)
243 : {
244 0 : load_single_billterm (sql_be, row, l_billterms_needing_parents);
245 0 : }
246 7 : delete result;
247 7 : std::string pkey(col_table[0]->name());
248 7 : sql = "SELECT DISTINCT ";
249 7 : sql += pkey + " FROM " TABLE_NAME;
250 7 : 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 7 : 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 7 : }
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 6 : GncSqlBillTermBackend::write (GncSqlBackend* sql_be)
298 : {
299 6 : g_return_val_if_fail (sql_be != NULL, FALSE);
300 :
301 6 : write_objects_t data {sql_be, true, this};
302 6 : qof_object_foreach (GNC_ID_BILLTERM, sql_be->book(), do_save_billterm, &data);
303 6 : return data.is_ok;
304 : }
305 :
306 : /* ================================================================= */
307 : void
308 13 : GncSqlBillTermBackend::create_tables (GncSqlBackend* sql_be)
309 : {
310 : gint version;
311 :
312 13 : g_return_if_fail (sql_be != NULL);
313 :
314 26 : version = sql_be->get_table_version( TABLE_NAME);
315 13 : if (version == 0)
316 : {
317 18 : sql_be->create_table(TABLE_NAME, TABLE_VERSION, col_table);
318 : }
319 7 : 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 18 : GncSqlColumnTableEntryImpl<CT_BILLTERMREF>::add_to_table(ColVec& vec) const noexcept
346 : {
347 18 : add_objectref_guid_to_table(vec);
348 18 : }
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 ===================== */
|