GnuCash  5.6-150-g038405b370+
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 
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 GncSqlBillTermBackend::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 
114 using BillTermParentGuidVec = std::vector<BillTermParentGuidPtr>;
115 
116 static void
117 set_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 
129 static gpointer
130 bt_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 
153 static void
154 bt_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 
177 static void
178 bt_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 
188 static GncBillTerm*
189 load_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: */
225 static inline GncBillTerm*
226 gnc_billterm_lookup (const GncGUID *guid, const QofBook *book)
227 {
228  QOF_BOOK_RETURN_ENTITY(book, guid, GNC_ID_BILLTERM, GncBillTerm);
229 }
230 
231 void
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;
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,
268  [&](BillTermParentGuidPtr s)
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 
289 static void
290 do_save_billterm (QofInstance* inst, void* p2)
291 {
292  auto data = static_cast<write_objects_t*>(p2);
293  data->commit(inst);
294 }
295 
296 bool
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 /* ================================================================= */
307 void
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 
332 template<> 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 
344 template<> void
346 {
347  add_objectref_guid_to_table(vec);
348 }
349 
350 template<> 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 ===================== */
bool create_table(const std::string &table_name, const EntryVec &col_table) const noexcept
Creates a table in the database.
bool set_table_version(const std::string &table_name, uint_t version) noexcept
Registers the version for a table.
GncSqlResultPtr execute_select_statement(const GncSqlStatementPtr &stmt) const noexcept
Executes an SQL SELECT statement and returns the result rows.
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
void gnc_sql_slots_load_for_sql_subquery(GncSqlBackend *sql_be, const std::string subquery, BookLookupFn lookup_fn)
gnc_sql_slots_load_for_sql_subquery - Loads slots for all objects whose guid is supplied by a subquer...
QofBook * qof_instance_get_book(gconstpointer inst)
Return the book pointer.
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
const gchar * QofIdTypeConst
QofIdTypeConst declaration.
Definition: qofid.h:82
load and save accounts data to SQL
void create_tables(GncSqlBackend *) override
Conditionally create or update a database table from m_col_table.
void add_to_query(QofIdTypeConst obj_name, void *pObject, PairVec &vec) const noexcept override
Add a pair of the table column heading and object&#39;s value&#39;s string representation to a PairVec; used ...
#define QOF_BOOK_RETURN_ENTITY(book, guid, e_type, c_type)
Encapsulates all the information about a dataset manipulated by QOF.
Definition: qofbook.h:186
load and save accounts data to SQL
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
Definition: qofclass.h:185
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.
bool write(GncSqlBackend *) override
Write all objects of m_type_name to the database.
Row of SQL Query results.
void upgrade_table(const std::string &table_name, const EntryVec &col_table) noexcept
Upgrades a table to a new structure.
void qof_object_foreach(QofIdTypeConst type_name, QofBook *book, QofInstanceForeachCB cb, gpointer user_data)
Invoke the callback &#39;cb&#39; on every instance ov a particular object type.
Definition: qofobject.cpp:185
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition: qofclass.h:178
Encapsulates per-class table schema with functions to load, create a table, commit a changed front-en...
Business Invoice Interface.
Data-passing struct for callbacks to qof_object_foreach() used in GncSqlObjectBackend::write().
void load_all(GncSqlBackend *) override
Load all objects of m_type in the database into memory.
void add_to_table(ColVec &vec) const noexcept override
Add a GncSqlColumnInfo structure for the column type to a ColVec.
The type used to store guids in C.
Definition: guid.h:75
uint_t get_table_version(const std::string &table_name) const noexcept
Returns the version number for a DB table.
Main SQL backend structure.