GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-bill-term-sql.cpp
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
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
54static 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
60static void set_invisible (gpointer data, gboolean value);
61static gpointer bt_get_parent (gpointer data);
62static void bt_set_parent (gpointer data, gpointer value);
63static void bt_set_parent_guid (gpointer data, gpointer value);
64
65#define TABLE_NAME "billterms"
66#define TABLE_VERSION 2
67
68static 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
96static 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
102GncSqlBillTermBackend::GncSqlBillTermBackend() :
103 GncSqlObjectBackend(TABLE_VERSION, GNC_ID_BILLTERM,
104 TABLE_NAME, col_table) {}
105
107{
108 GncBillTerm* billterm;
109 GncGUID guid;
110 bool have_guid;
111};
112
114using BillTermParentGuidVec = std::vector<BillTermParentGuidPtr>;
115
116static void
117set_invisible (gpointer data, gboolean value)
118{
119 GncBillTerm* term = GNC_BILLTERM (data);
120
121 g_return_if_fail (term != NULL);
122
123 if (value)
124 {
125 gncBillTermMakeInvisible (term);
126 }
127}
128
129static gpointer
130bt_get_parent (gpointer pObject)
131{
132 const GncBillTerm* billterm;
133 const GncBillTerm* pParent;
134 const GncGUID* parent_guid;
135
136 g_return_val_if_fail (pObject != NULL, NULL);
137 g_return_val_if_fail (GNC_IS_BILLTERM (pObject), NULL);
138
139 billterm = GNC_BILLTERM (pObject);
140 pParent = gncBillTermGetParent (billterm);
141 if (pParent == NULL)
142 {
143 parent_guid = NULL;
144 }
145 else
146 {
147 parent_guid = qof_instance_get_guid (QOF_INSTANCE (pParent));
148 }
149
150 return (gpointer)parent_guid;
151}
152
153static void
154bt_set_parent (gpointer data, gpointer value)
155{
156 GncBillTerm* billterm;
157 GncBillTerm* parent;
158 QofBook* pBook;
159 GncGUID* guid = (GncGUID*)value;
160
161 g_return_if_fail (data != NULL);
162 g_return_if_fail (GNC_IS_BILLTERM (data));
163
164 billterm = GNC_BILLTERM (data);
165 pBook = qof_instance_get_book (QOF_INSTANCE (billterm));
166 if (guid != NULL)
167 {
168 parent = gncBillTermLookup (pBook, guid);
169 if (parent != NULL)
170 {
171 gncBillTermSetParent (billterm, parent);
172 gncBillTermSetChild (parent, billterm);
173 }
174 }
175}
176
177static void
178bt_set_parent_guid (gpointer pObject, gpointer pValue)
179{
180 g_return_if_fail (pObject != NULL);
181 g_return_if_fail (pValue != NULL);
182
183 auto s = static_cast<BillTermParentGuidPtr>(pObject);
184 s->guid = *static_cast<GncGUID*>(pValue);
185 s->have_guid = true;
186}
187
188static GncBillTerm*
189load_single_billterm (GncSqlBackend* sql_be, GncSqlRow& row,
190 BillTermParentGuidVec& l_billterms_needing_parents)
191{
192 g_return_val_if_fail (sql_be != NULL, NULL);
193
194 auto guid = gnc_sql_load_guid (sql_be, row);
195 auto pBillTerm = gncBillTermLookup (sql_be->book(), guid);
196 if (pBillTerm == nullptr)
197 {
198 pBillTerm = gncBillTermCreate (sql_be->book());
199 }
200 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 if (gncBillTermGetParent (pBillTerm) == NULL)
207 {
209
210 s.billterm = pBillTerm;
211 s.have_guid = false;
212 gnc_sql_load_object (sql_be, row, GNC_ID_BILLTERM, &s,
213 billterm_parent_col_table);
214 if (s.have_guid)
215 l_billterms_needing_parents.push_back(new BillTermParentGuid(s));
216
217 }
218
219 qof_instance_mark_clean (QOF_INSTANCE (pBillTerm));
220
221 return pBillTerm;
222}
223
224/* Because gncBillTermLookup has the arguments backwards: */
225static inline GncBillTerm*
226gnc_billterm_lookup (const GncGUID *guid, const QofBook *book)
227{
228 QOF_BOOK_RETURN_ENTITY(book, guid, GNC_ID_BILLTERM, GncBillTerm);
229}
230
231void
233{
234
235 g_return_if_fail (sql_be != NULL);
236
237 std::string sql("SELECT * FROM " TABLE_NAME);
238 auto stmt = sql_be->create_statement_from_sql(sql);
239 auto result = sql_be->execute_select_statement(stmt);
240 BillTermParentGuidVec l_billterms_needing_parents;
241
242 for (auto row : *result)
243 {
244 load_single_billterm (sql_be, row, l_billterms_needing_parents);
245 }
246 delete result;
247 std::string pkey(col_table[0]->name());
248 sql = "SELECT DISTINCT ";
249 sql += pkey + " FROM " TABLE_NAME;
250 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 if (!l_billterms_needing_parents.empty())
259 {
260 bool progress_made = true;
261 std::reverse(l_billterms_needing_parents.begin(),
262 l_billterms_needing_parents.end());
263 auto end = l_billterms_needing_parents.end();
264 while (progress_made)
265 {
266 progress_made = false;
267 end = std::remove_if(l_billterms_needing_parents.begin(), end,
269 {
270 auto pBook = qof_instance_get_book (QOF_INSTANCE (s->billterm));
271 auto parent = gncBillTermLookup (pBook,
272 &s->guid);
273 if (parent != nullptr)
274 {
275 gncBillTermSetParent (s->billterm, parent);
276 gncBillTermSetChild (parent, s->billterm);
277 progress_made = true;
278 delete s;
279 return true;
280 }
281 return false;
282 });
283 }
284 }
285}
286
287/* ================================================================= */
288
289static void
290do_save_billterm (QofInstance* inst, void* p2)
291{
292 auto data = static_cast<write_objects_t*>(p2);
293 data->commit(inst);
294}
295
296bool
298{
299 g_return_val_if_fail (sql_be != NULL, FALSE);
300
301 write_objects_t data {sql_be, true, this};
302 qof_object_foreach (GNC_ID_BILLTERM, sql_be->book(), do_save_billterm, &data);
303 return data.is_ok;
304}
305
306/* ================================================================= */
307void
309{
310 gint version;
311
312 g_return_if_fail (sql_be != NULL);
313
314 version = sql_be->get_table_version( TABLE_NAME);
315 if (version == 0)
316 {
317 sql_be->create_table(TABLE_NAME, TABLE_VERSION, col_table);
318 }
319 else if (version < m_version)
320 {
321 /* Upgrade 64 bit int handling */
322 sql_be->upgrade_table(TABLE_NAME, col_table);
323 sql_be->set_table_version (TABLE_NAME, TABLE_VERSION);
324
325 PINFO ("Billterms table upgraded from version 1 to version %d\n",
326 TABLE_VERSION);
327 }
328}
329
330/* ================================================================= */
331
332template<> void
334 GncSqlRow& row,
335 QofIdTypeConst obj_name,
336 gpointer pObject) const noexcept
337{
338 load_from_guid_ref(row, obj_name, pObject,
339 [sql_be](GncGUID* g){
340 return gncBillTermLookup(sql_be->book(), g);
341 });
342}
343
344template<> void
346{
347 add_objectref_guid_to_table(vec);
348}
349
350template<> void
352 const gpointer pObject,
353 PairVec& vec) const noexcept
354{
355 add_objectref_guid_to_query(obj_name, pObject, vec);
356}
357
358/* ========================== END OF FILE ===================== */
Main SQL backend structure.
uint_t get_table_version(const std::string &table_name) const noexcept
Returns the version number for a DB table.
bool create_table(const std::string &table_name, const EntryVec &col_table) const noexcept
Creates a table in the database.
GncSqlResultPtr execute_select_statement(const GncSqlStatementPtr &stmt) const noexcept
Executes an SQL SELECT statement and returns the result rows.
void upgrade_table(const std::string &table_name, const EntryVec &col_table) noexcept
Upgrades a table to a new structure.
bool set_table_version(const std::string &table_name, uint_t version) noexcept
Registers the version for a table.
void create_tables(GncSqlBackend *) override
Conditionally create or update a database table from m_col_table.
bool write(GncSqlBackend *) override
Write all objects of m_type_name to the database.
void load_all(GncSqlBackend *) override
Load all objects of m_type in the database into memory.
void add_to_query(QofIdTypeConst obj_name, void *pObject, PairVec &vec) const noexcept override
Add a pair of the table column heading and object's value's string representation to a PairVec; used ...
void add_to_table(ColVec &vec) const noexcept override
Add a GncSqlColumnInfo structure for the column type to a ColVec.
void load(const GncSqlBackend *sql_be, GncSqlRow &row, QofIdTypeConst obj_name, void *pObject) const noexcept override
Load a value into an object from the database row.
Encapsulates per-class table schema with functions to load, create a table, commit a changed front-en...
Row of SQL Query results.
load and save accounts data to SQL
load and save accounts data to SQL
Business Invoice Interface.
#define QOF_BOOK_RETURN_ENTITY(book, guid, e_type, c_type)
Encapsulates all the information about a dataset manipulated by QOF.
Definition qofbook.h:101
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition qofclass.h:123
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
Definition qofclass.h:130
const gchar * QofIdTypeConst
QofIdTypeConst declaration.
Definition qofid.h:82
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
#define PINFO(format, args...)
Print an informational note.
Definition qoflog.h:256
void qof_object_foreach(QofIdTypeConst type_name, QofBook *book, QofInstanceForeachCB cb, gpointer user_data)
Invoke the callback 'cb' on every instance ov a particular object type.
The type used to store guids in C.
Definition guid.h:75
QofBook reference.
Definition qofbook-p.hpp:47
Data-passing struct for callbacks to qof_object_foreach() used in GncSqlObjectBackend::write().