GnuCash  5.6-150-g038405b370+
gnc-entry-sql.cpp
1 /********************************************************************\
2  * gnc-entry-sql.c -- entry 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 <glib.h>
31 
32 #include <config.h>
33 
34 #include <stdlib.h>
35 #include <string.h>
36 
37 #include "gncEntryP.h"
38 #include "gncOrderP.h"
39 #include "gncInvoiceP.h"
40 #include "gncTaxTableP.h"
41 
42 #include "gnc-sql-connection.hpp"
43 #include "gnc-sql-backend.hpp"
44 #include "gnc-sql-object-backend.hpp"
45 #include "gnc-sql-column-table-entry.hpp"
46 #include "gnc-slots-sql.h"
47 #include "gnc-bill-term-sql.h"
48 #include "gnc-entry-sql.h"
49 #include "gnc-invoice-sql.h"
50 #include "gnc-order-sql.h"
51 #include "gnc-tax-table-sql.h"
52 
53 #define _GNC_MOD_NAME GNC_ID_ENTRY
54 
55 static QofLogModule log_module = G_LOG_DOMAIN;
56 
57 #define TABLE_NAME "entries"
58 #define TABLE_VERSION 4
59 #define MAX_DESCRIPTION_LEN 2048
60 #define MAX_ACTION_LEN 2048
61 #define MAX_NOTES_LEN 2048
62 #define MAX_DISCTYPE_LEN 2048
63 #define MAX_DISCHOW_LEN 2048
64 
65 static void entry_set_invoice (gpointer pObject, gpointer val);
66 static void entry_set_bill (gpointer pObject, gpointer val);
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_TIME>("date", 0, COL_NNUL, ENTRY_DATE,
72  true),
73  gnc_sql_make_table_entry<CT_TIME>("date_entered", 0, 0,
74  ENTRY_DATE_ENTERED, true),
75  gnc_sql_make_table_entry<CT_STRING>(
76  "description", MAX_DESCRIPTION_LEN, 0, "description"),
77  gnc_sql_make_table_entry<CT_STRING>("action", MAX_ACTION_LEN, 0,
78  ENTRY_ACTION, true),
79  gnc_sql_make_table_entry<CT_STRING>("notes", MAX_NOTES_LEN, 0, ENTRY_NOTES,
80  true),
81  gnc_sql_make_table_entry<CT_NUMERIC>("quantity", 0, 0, ENTRY_QTY,
82  true),
83  gnc_sql_make_table_entry<CT_ACCOUNTREF>("i_acct", 0, 0, ENTRY_IACCT,
84  true),
85  gnc_sql_make_table_entry<CT_NUMERIC>("i_price", 0, 0, ENTRY_IPRICE,
86  true),
87  gnc_sql_make_table_entry<CT_NUMERIC>("i_discount", 0, 0,
88  (QofAccessFunc)gncEntryGetInvDiscount,
89  (QofSetterFunc)gncEntrySetInvDiscount),
90  gnc_sql_make_table_entry<CT_INVOICEREF>("invoice", 0, 0,
91  (QofAccessFunc)gncEntryGetInvoice,
92  (QofSetterFunc)entry_set_invoice),
93  gnc_sql_make_table_entry<CT_STRING>("i_disc_type", MAX_DISCTYPE_LEN, 0,
94  ENTRY_INV_DISC_TYPE, true),
95  gnc_sql_make_table_entry<CT_STRING>("i_disc_how", MAX_DISCHOW_LEN, 0,
96  ENTRY_INV_DISC_HOW, true),
97  gnc_sql_make_table_entry<CT_BOOLEAN>("i_taxable", 0, 0, ENTRY_INV_TAXABLE,
98  true),
99  gnc_sql_make_table_entry<CT_BOOLEAN>("i_taxincluded", 0, 0,
100  ENTRY_INV_TAX_INC, true),
101  gnc_sql_make_table_entry<CT_TAXTABLEREF>("i_taxtable", 0, 0,
102  (QofAccessFunc)gncEntryGetInvTaxTable,
103  (QofSetterFunc)gncEntrySetInvTaxTable),
104  gnc_sql_make_table_entry<CT_ACCOUNTREF>("b_acct", 0, 0, ENTRY_BACCT,
105  true),
106  gnc_sql_make_table_entry<CT_NUMERIC>("b_price", 0, 0, ENTRY_BPRICE,
107  true),
108  gnc_sql_make_table_entry<CT_INVOICEREF>("bill", 0, 0,
109  (QofAccessFunc)gncEntryGetBill,
110  (QofSetterFunc)entry_set_bill),
111  gnc_sql_make_table_entry<CT_BOOLEAN>("b_taxable", 0, 0, ENTRY_BILL_TAXABLE,
112  true),
113  gnc_sql_make_table_entry<CT_BOOLEAN>("b_taxincluded", 0, 0,
114  ENTRY_BILL_TAX_INC, true),
115  gnc_sql_make_table_entry<CT_TAXTABLEREF>("b_taxtable", 0, 0,
116  (QofAccessFunc)gncEntryGetBillTaxTable,
117  (QofSetterFunc)gncEntrySetBillTaxTable),
118  gnc_sql_make_table_entry<CT_INT>("b_paytype", 0, 0,
119  (QofAccessFunc)gncEntryGetBillPayment,
120  (QofSetterFunc)gncEntrySetBillPayment),
121  gnc_sql_make_table_entry<CT_BOOLEAN>("billable", 0, 0, ENTRY_BILLABLE,
122  true),
123  gnc_sql_make_table_entry<CT_OWNERREF>("billto", 0, 0, ENTRY_BILLTO, true),
124  gnc_sql_make_table_entry<CT_ORDERREF>("order_guid", 0, 0,
125  (QofAccessFunc)gncEntryGetOrder,
126  (QofSetterFunc)gncEntrySetOrder),
127 });
128 
129 GncSqlEntryBackend::GncSqlEntryBackend() :
130  GncSqlObjectBackend(TABLE_VERSION, GNC_ID_ENTRY,
131  TABLE_NAME, col_table) {}
132 
133 static void
134 entry_set_invoice (gpointer pObject, gpointer val)
135 {
136  GncEntry* entry;
137  GncInvoice* invoice;
138 
139  g_return_if_fail (pObject != NULL);
140  g_return_if_fail (GNC_IS_ENTRY (pObject));
141  g_return_if_fail (val != NULL);
142  g_return_if_fail (GNC_IS_INVOICE (val));
143 
144  entry = GNC_ENTRY (pObject);
145  invoice = GNC_INVOICE (val);
146 
147  gncInvoiceAddEntry (invoice, entry);
148 }
149 
150 static void
151 entry_set_bill (gpointer pObject, gpointer val)
152 {
153  GncEntry* entry;
154  GncInvoice* bill;
155 
156  g_return_if_fail (pObject != NULL);
157  g_return_if_fail (GNC_IS_ENTRY (pObject));
158  g_return_if_fail (val != NULL);
159  g_return_if_fail (GNC_IS_INVOICE (val));
160 
161  entry = GNC_ENTRY (pObject);
162  bill = GNC_INVOICE (val);
163 
164  gncBillAddEntry (bill, entry);
165 }
166 
167 static GncEntry*
168 load_single_entry (GncSqlBackend* sql_be, GncSqlRow& row)
169 {
170  const GncGUID* guid;
171  GncEntry* pEntry;
172 
173  g_return_val_if_fail (sql_be != NULL, NULL);
174 
175  guid = gnc_sql_load_guid (sql_be, row);
176  pEntry = gncEntryLookup (sql_be->book(), guid);
177  if (pEntry == NULL)
178  {
179  pEntry = gncEntryCreate (sql_be->book());
180  }
181  gnc_sql_load_object (sql_be, row, GNC_ID_ENTRY, pEntry, col_table);
182  qof_instance_mark_clean (QOF_INSTANCE (pEntry));
183 
184  return pEntry;
185 }
186 
187 /* Because gncEntryLookup has the arguments backwards: */
188 static inline GncEntry*
189 gnc_entry_lookup (const GncGUID *guid, const QofBook *book)
190 {
191  QOF_BOOK_RETURN_ENTITY(book, guid, GNC_ID_ENTRY, GncEntry);
192 }
193 
194 void
196 {
197  g_return_if_fail (sql_be != NULL);
198 
199  std::string sql("SELECT * FROM " TABLE_NAME);
200  auto stmt = sql_be->create_statement_from_sql(sql);
201  auto result = sql_be->execute_select_statement(stmt);
202 
203  for (auto row : *result)
204  load_single_entry (sql_be, row);
205 
206  std::string pkey(col_table[0]->name());
207  sql = "SELECT DISTINCT ";
208  sql += pkey + " FROM " TABLE_NAME;
210  (BookLookupFn)gnc_entry_lookup);
211 }
212 
213 /* ================================================================= */
214 void
216 {
217  gint version;
218 
219  g_return_if_fail (sql_be != NULL);
220 
221  version = sql_be->get_table_version( TABLE_NAME);
222  if (version == 0)
223  {
224  sql_be->create_table(TABLE_NAME, TABLE_VERSION, col_table);
225  }
226  else if (version < TABLE_VERSION)
227  {
228  /* Upgrade:
229  1->2: 64 bit int handling
230  2->3: "entered" -> "date_entered", and it can be NULL
231  3->4: Use DATETIME instead of TIMESTAMP in MySQL
232  */
233  sql_be->upgrade_table(TABLE_NAME, col_table);
234  sql_be->set_table_version (TABLE_NAME, TABLE_VERSION);
235 
236  PINFO ("Entries table upgraded from version %d to version %d\n", version,
237  TABLE_VERSION);
238  }
239 }
240 
241 /* ================================================================= */
242 static void
243 write_single_entry (QofInstance* term_p, gpointer data_p)
244 {
245  write_objects_t* s = (write_objects_t*)data_p;
246  GncEntry* entry = GNC_ENTRY (term_p);
247 
248  g_return_if_fail (term_p != NULL);
249  g_return_if_fail (GNC_IS_ENTRY (term_p));
250  g_return_if_fail (data_p != NULL);
251 
252  /* Only save if attached */
253  if (s->is_ok && (gncEntryGetOrder (entry) != NULL ||
254  gncEntryGetInvoice (entry) != NULL ||
255  gncEntryGetBill (entry) != NULL))
256  {
257  s->commit (term_p);
258  }
259 }
260 
261 bool
263 {
264  g_return_val_if_fail (sql_be != NULL, FALSE);
265  write_objects_t data{sql_be, true, this};
266 
267  qof_object_foreach (GNC_ID_ENTRY, sql_be->book(), write_single_entry, &data);
268 
269  return data.is_ok;
270 }
271 
272 
273 /* ========================== 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.
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...
#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
load and save accounts data to SQL
void load_all(GncSqlBackend *) override
Load all objects of m_type in the database into memory.
#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
bool write(GncSqlBackend *) override
Write all objects of m_type_name to the database.
load and save accounts data to SQL
void create_tables(GncSqlBackend *) override
Conditionally create or update a database table from m_col_table.
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
Definition: qofclass.h:185
load and save order data to SQL
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 gncBillAddEntry(GncInvoice *bill, GncEntry *entry)
Call this function when adding an entry to a bill instead of an invoice.
Definition: gncInvoice.c:719
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...
Data-passing struct for callbacks to qof_object_foreach() used in GncSqlObjectBackend::write().
load and save entry data to SQL
load and save invoice data to SQL
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.
load and save tax table data to SQL