Branch data Line data Source code
1 : : /********************************************************************
2 : : * gnc-sql-column-table-entry.cpp: Implement GncSqlColumnTableEntry *
3 : : * *
4 : : * Copyright 2016 John Ralls <jralls@ceridwen.us> *
5 : : * *
6 : : * This program is free software; you can redistribute it and/or *
7 : : * modify it under the terms of the GNU General Public License as *
8 : : * published by the Free Software Foundation; either version 2 of *
9 : : * the License, or (at your option) any later version. *
10 : : * *
11 : : * This program is distributed in the hope that it will be useful, *
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 : : * GNU General Public License for more details. *
15 : : * *
16 : : * You should have received a copy of the GNU General Public License*
17 : : * along with this program; if not, contact: *
18 : : * *
19 : : * Free Software Foundation Voice: +1-617-542-5942 *
20 : : * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 : : * Boston, MA 02110-1301, USA gnu@gnu.org *
22 : : \********************************************************************/
23 : :
24 : : #include <config.h>
25 : : #include <qof.h>
26 : : #include <sstream>
27 : : #include <iomanip>
28 : : #include <cstdint>
29 : : #include <gnc-datetime.hpp>
30 : : #include "gnc-sql-backend.hpp"
31 : : #include "gnc-sql-object-backend.hpp"
32 : : #include "gnc-sql-column-table-entry.hpp"
33 : : #include "gnc-sql-result.hpp"
34 : :
35 : : static QofLogModule log_module = G_LOG_DOMAIN;
36 : :
37 : : /* ================================================================= */
38 : : static gpointer
39 : 0 : get_autoinc_id (void* object, const QofParam* param)
40 : : {
41 : : // Just need a 0 to force a new autoinc value
42 : 0 : return (gpointer)0;
43 : : }
44 : :
45 : : static void
46 : 65 : set_autoinc_id (void* object, void* item)
47 : : {
48 : : // Nowhere to put the ID
49 : 65 : }
50 : :
51 : : QofAccessFunc
52 : 985 : GncSqlColumnTableEntry::get_getter (QofIdTypeConst obj_name) const noexcept
53 : : {
54 : : QofAccessFunc getter;
55 : :
56 : 985 : g_return_val_if_fail (obj_name != NULL, NULL);
57 : :
58 : 985 : if (m_flags & COL_AUTOINC)
59 : : {
60 : 0 : getter = get_autoinc_id;
61 : : }
62 : 985 : else if (m_qof_param_name != NULL)
63 : : {
64 : 72 : getter = qof_class_get_parameter_getter (obj_name, m_qof_param_name);
65 : : }
66 : : else
67 : : {
68 : 913 : getter = m_getter;
69 : : }
70 : :
71 : 985 : return getter;
72 : : }
73 : :
74 : : QofSetterFunc
75 : 2409 : GncSqlColumnTableEntry::get_setter(QofIdTypeConst obj_name) const noexcept
76 : : {
77 : 2409 : QofSetterFunc setter = nullptr;
78 : 2409 : if (m_flags & COL_AUTOINC)
79 : : {
80 : 130 : setter = set_autoinc_id;
81 : : }
82 : 2279 : else if (m_qof_param_name != nullptr)
83 : : {
84 : 124 : g_assert (obj_name != NULL);
85 : 124 : setter = qof_class_get_parameter_setter (obj_name, m_qof_param_name);
86 : : }
87 : : else
88 : : {
89 : 2155 : setter = m_setter;
90 : : }
91 : 2409 : return setter;
92 : : }
93 : :
94 : : void
95 : 129 : GncSqlColumnTableEntry::add_objectref_guid_to_query (QofIdTypeConst obj_name,
96 : : const void* pObject,
97 : : PairVec& vec) const noexcept
98 : : {
99 : 129 : auto inst = get_row_value_from_object<QofInstance*>(obj_name, pObject);
100 : 129 : if (inst == nullptr) return;
101 : 88 : auto guid = qof_instance_get_guid (inst);
102 : 88 : if (guid != nullptr) {
103 : 88 : gchar *guid_s = guid_to_string(guid);
104 : 264 : vec.emplace_back (std::make_pair (std::string{m_col_name}, quote_string(guid_s)));
105 : 88 : g_free(guid_s);
106 : : }
107 : : }
108 : :
109 : : void
110 : 165 : GncSqlColumnTableEntry::add_objectref_guid_to_table (ColVec& vec) const noexcept
111 : : {
112 : 165 : GncSqlColumnInfo info{*this, BCT_STRING, GUID_ENCODING_LENGTH, FALSE};
113 : 165 : vec.emplace_back(std::move(info));
114 : 165 : }
115 : :
116 : :
117 : : /* ----------------------------------------------------------------- */
118 : : template<> void
119 : 409 : GncSqlColumnTableEntryImpl<CT_STRING>::load (const GncSqlBackend* sql_be,
120 : : GncSqlRow& row,
121 : : QofIdTypeConst obj_name,
122 : : gpointer pObject) const noexcept
123 : : {
124 : 409 : g_return_if_fail (pObject != NULL);
125 : 409 : g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
126 : :
127 : 409 : auto s = row.get_string_at_col (m_col_name);
128 : 409 : if (s)
129 : 409 : set_parameter(pObject, s->c_str(), get_setter(obj_name), m_gobj_param_name);
130 : 409 : }
131 : :
132 : : template<> void
133 : 270 : GncSqlColumnTableEntryImpl<CT_STRING>::add_to_table(ColVec& vec) const noexcept
134 : : {
135 : 270 : GncSqlColumnInfo info{*this, BCT_STRING, m_size, TRUE};
136 : 270 : vec.emplace_back(std::move(info));
137 : 270 : }
138 : :
139 : : /* char is unusual in that we get a pointer but don't deref it to pass
140 : : * it to operator<<().
141 : : */
142 : : template<> void
143 : 701 : GncSqlColumnTableEntryImpl<CT_STRING>::add_to_query(QofIdTypeConst obj_name,
144 : : const gpointer pObject,
145 : : PairVec& vec) const noexcept
146 : : {
147 : 701 : auto s = get_row_value_from_object<char*>(obj_name, pObject);
148 : :
149 : 701 : if (s != nullptr)
150 : : {
151 : 654 : std::ostringstream stream;
152 : 654 : stream << s;
153 : 1308 : vec.emplace_back (std::make_pair (std::string{m_col_name},
154 : 1308 : quote_string(stream.str())));
155 : 654 : return;
156 : 654 : }
157 : : }
158 : :
159 : : /* ----------------------------------------------------------------- */
160 : : typedef gint (*IntAccessFunc) (const gpointer);
161 : : typedef void (*IntSetterFunc) (const gpointer, gint);
162 : :
163 : : template<> void
164 : 190 : GncSqlColumnTableEntryImpl<CT_INT>::load (const GncSqlBackend* sql_be,
165 : : GncSqlRow& row,
166 : : QofIdTypeConst obj_name,
167 : : gpointer pObject) const noexcept
168 : : {
169 : :
170 : 190 : g_return_if_fail (pObject != NULL);
171 : 190 : g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
172 : :
173 : 190 : auto val = row.get_int_at_col(m_col_name);
174 : 190 : if (val)
175 : 190 : set_parameter(pObject, *val,
176 : 190 : reinterpret_cast<IntSetterFunc>(get_setter(obj_name)),
177 : 190 : m_gobj_param_name);
178 : : }
179 : :
180 : : template<> void
181 : 115 : GncSqlColumnTableEntryImpl<CT_INT>::add_to_table(ColVec& vec) const noexcept
182 : : {
183 : 115 : GncSqlColumnInfo info{*this, BCT_INT, 0, FALSE};
184 : 115 : vec.emplace_back(std::move(info));
185 : 115 : }
186 : :
187 : : template<> void
188 : 179 : GncSqlColumnTableEntryImpl<CT_INT>::add_to_query(QofIdTypeConst obj_name,
189 : : const gpointer pObject,
190 : : PairVec& vec) const noexcept
191 : : {
192 : 179 : add_value_to_vec<int>(obj_name, pObject, vec);
193 : 179 : }
194 : :
195 : : /* ----------------------------------------------------------------- */
196 : : typedef gboolean (*BooleanAccessFunc) (const gpointer);
197 : : typedef void (*BooleanSetterFunc) (const gpointer, gboolean);
198 : :
199 : : template<> void
200 : 134 : GncSqlColumnTableEntryImpl<CT_BOOLEAN>::load (const GncSqlBackend* sql_be,
201 : : GncSqlRow& row,
202 : : QofIdTypeConst obj_name,
203 : : gpointer pObject)
204 : : const noexcept
205 : : {
206 : 134 : g_return_if_fail (pObject != NULL);
207 : 134 : g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
208 : :
209 : 134 : auto val = row.get_int_at_col (m_col_name);
210 : 134 : if (val)
211 : 134 : set_parameter(pObject, static_cast<int>(*val),
212 : 134 : reinterpret_cast<BooleanSetterFunc>(get_setter(obj_name)),
213 : 134 : m_gobj_param_name);
214 : : }
215 : :
216 : : template<> void
217 : 115 : GncSqlColumnTableEntryImpl<CT_BOOLEAN>::add_to_table(ColVec& vec) const noexcept
218 : : {
219 : 115 : GncSqlColumnInfo info{*this, BCT_INT, 0, FALSE};
220 : 115 : vec.emplace_back(std::move(info));
221 : 115 : }
222 : :
223 : : template<> void
224 : 185 : GncSqlColumnTableEntryImpl<CT_BOOLEAN>::add_to_query(QofIdTypeConst obj_name,
225 : : const gpointer pObject,
226 : : PairVec& vec) const noexcept
227 : : {
228 : 185 : add_value_to_vec<int>(obj_name, pObject, vec);
229 : 185 : }
230 : :
231 : : /* ----------------------------------------------------------------- */
232 : : typedef gint64 (*Int64AccessFunc) (const gpointer);
233 : : typedef void (*Int64SetterFunc) (const gpointer, gint64);
234 : :
235 : : template<> void
236 : 60 : GncSqlColumnTableEntryImpl<CT_INT64>::load (const GncSqlBackend* sql_be,
237 : : GncSqlRow& row,
238 : : QofIdTypeConst obj_name,
239 : : gpointer pObject)
240 : : const noexcept
241 : : {
242 : 60 : g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
243 : :
244 : 60 : auto val = row.get_int_at_col (m_col_name);
245 : 60 : if (val)
246 : 60 : set_parameter(pObject, *val,
247 : 60 : reinterpret_cast<Int64SetterFunc>(get_setter(obj_name)),
248 : 60 : m_gobj_param_name);
249 : : }
250 : :
251 : : template<> void
252 : 10 : GncSqlColumnTableEntryImpl<CT_INT64>::add_to_table(ColVec& vec) const noexcept
253 : : {
254 : :
255 : 10 : GncSqlColumnInfo info{*this, BCT_INT64, 0, FALSE};
256 : 10 : vec.emplace_back(std::move(info));
257 : 10 : }
258 : :
259 : : template<> gint64
260 : 67 : GncSqlColumnTableEntry::get_row_value_from_object<int64_t>(QofIdTypeConst obj_name,
261 : : const void* pObject) const
262 : : {
263 : 67 : g_return_val_if_fail(obj_name != nullptr && pObject != nullptr,
264 : : INT64_C(0));
265 : 67 : int64_t result = INT64_C(0);
266 : 67 : if (m_gobj_param_name != nullptr)
267 : 2 : g_object_get(const_cast<void*>(pObject), m_gobj_param_name,
268 : : &result, nullptr);
269 : : else
270 : : {
271 : 65 : auto getter = (Int64AccessFunc)get_getter(obj_name);
272 : 65 : if (getter != nullptr)
273 : 65 : result = (getter)(const_cast<void*>(pObject));
274 : : }
275 : 67 : return result;
276 : : }
277 : :
278 : : template<> void
279 : 67 : GncSqlColumnTableEntryImpl<CT_INT64>::add_to_query(QofIdTypeConst obj_name,
280 : : const gpointer pObject,
281 : : PairVec& vec) const noexcept
282 : : {
283 : 67 : add_value_to_vec<int64_t>(obj_name, pObject, vec);
284 : 67 : }
285 : : /* ----------------------------------------------------------------- */
286 : :
287 : : template<> void
288 : 58 : GncSqlColumnTableEntryImpl<CT_DOUBLE>::load (const GncSqlBackend* sql_be,
289 : : GncSqlRow& row,
290 : : QofIdTypeConst obj_name,
291 : : gpointer pObject)
292 : : const noexcept
293 : : {
294 : 58 : g_return_if_fail (pObject != NULL);
295 : 58 : g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
296 : 58 : double val{0.0};
297 : :
298 : 58 : if (auto int_val{row.get_int_at_col(m_col_name)})
299 : 0 : val = static_cast<decltype(val)>(*int_val);
300 : 58 : else if (auto float_val{row.get_float_at_col(m_col_name)})
301 : 0 : val = static_cast<decltype(val)>(*float_val);
302 : 58 : else if (auto double_val{row.get_double_at_col(m_col_name)})
303 : 58 : val = *double_val;
304 : :
305 : 58 : set_parameter(pObject, val, get_setter(obj_name), m_gobj_param_name);
306 : : }
307 : :
308 : : template<> void
309 : 5 : GncSqlColumnTableEntryImpl<CT_DOUBLE>::add_to_table(ColVec& vec) const noexcept
310 : : {
311 : 5 : GncSqlColumnInfo info{*this, BCT_DOUBLE, 0, FALSE};
312 : 5 : vec.emplace_back(std::move(info));
313 : 5 : }
314 : :
315 : : template<> void
316 : 65 : GncSqlColumnTableEntryImpl<CT_DOUBLE>::add_to_query(QofIdTypeConst obj_name,
317 : : const gpointer pObject,
318 : : PairVec& vec) const noexcept
319 : : {
320 : 65 : add_value_to_vec<double*>(obj_name, pObject, vec);
321 : 65 : }
322 : :
323 : : /* ----------------------------------------------------------------- */
324 : :
325 : : template<> void
326 : 376 : GncSqlColumnTableEntryImpl<CT_GUID>::load (const GncSqlBackend* sql_be,
327 : : GncSqlRow& row,
328 : : QofIdTypeConst obj_name,
329 : : gpointer pObject)
330 : : const noexcept
331 : : {
332 : :
333 : : GncGUID guid;
334 : :
335 : 376 : g_return_if_fail (pObject != NULL);
336 : 376 : g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
337 : :
338 : 376 : auto strval{row.get_string_at_col(m_col_name)};
339 : 376 : if (strval && string_to_guid (strval->c_str(), &guid))
340 : 316 : set_parameter(pObject, &guid, get_setter(obj_name), m_gobj_param_name);
341 : 376 : }
342 : :
343 : : template<> void
344 : 130 : GncSqlColumnTableEntryImpl<CT_GUID>::add_to_table(ColVec& vec) const noexcept
345 : : {
346 : 130 : GncSqlColumnInfo info{*this, BCT_STRING, GUID_ENCODING_LENGTH, FALSE};
347 : 130 : vec.emplace_back(std::move(info));
348 : 130 : }
349 : :
350 : : template<> void
351 : 344 : GncSqlColumnTableEntryImpl<CT_GUID>::add_to_query(QofIdTypeConst obj_name,
352 : : const gpointer pObject,
353 : : PairVec& vec) const noexcept
354 : : {
355 : 344 : auto s = get_row_value_from_object<GncGUID*>(obj_name, pObject);
356 : :
357 : 344 : if (s != nullptr)
358 : : {
359 : 284 : gchar *guid_s = guid_to_string(s);
360 : 852 : vec.emplace_back (std::make_pair (std::string{m_col_name}, quote_string(guid_s)));
361 : 284 : g_free(guid_s);
362 : 284 : return;
363 : : }
364 : : }
365 : : /* ----------------------------------------------------------------- */
366 : : typedef time64 (*Time64AccessFunc) (const gpointer);
367 : : typedef void (*Time64SetterFunc) (const gpointer, time64);
368 : : constexpr int TIME_COL_SIZE = 4 + 3 + 3 + 3 + 3 + 3;
369 : :
370 : : template<> void
371 : 98 : GncSqlColumnTableEntryImpl<CT_TIME>::load (const GncSqlBackend* sql_be,
372 : : GncSqlRow& row,
373 : : QofIdTypeConst obj_name,
374 : : gpointer pObject)
375 : : const noexcept
376 : : {
377 : 98 : time64 t{0};
378 : 98 : g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
379 : 98 : auto strval = row.get_string_at_col(m_col_name);
380 : 98 : if (strval)
381 : : {
382 : 98 : if (!strval->empty())
383 : : try
384 : : {
385 : 97 : GncDateTime time(*strval);
386 : 97 : t = static_cast<time64>(time);
387 : 97 : }
388 : 0 : catch (const std::invalid_argument& err)
389 : : {
390 : 0 : PWARN("An invalid date %s was found in your database."
391 : : "It has been set to 1 January 1970.",
392 : : strval->c_str());
393 : 0 : }
394 : : }
395 : : else
396 : : {
397 : 0 : if (auto time64val = row.get_time64_at_col (m_col_name))
398 : 0 : t = *time64val;
399 : : }
400 : :
401 : 98 : if (m_gobj_param_name != nullptr)
402 : : {
403 : 36 : Time64 t64{t};
404 : 36 : set_parameter(pObject, &t64, m_gobj_param_name);
405 : : }
406 : : else
407 : : {
408 : 62 : set_parameter(pObject, t,
409 : 62 : reinterpret_cast<Time64SetterFunc>(get_setter(obj_name)),
410 : : nullptr);
411 : : }
412 : 98 : }
413 : :
414 : : template<> void
415 : 55 : GncSqlColumnTableEntryImpl<CT_TIME>::add_to_table(ColVec& vec) const noexcept
416 : : {
417 : :
418 : 55 : GncSqlColumnInfo info{*this, BCT_DATETIME, TIME_COL_SIZE, FALSE};
419 : 55 : vec.emplace_back(std::move(info));
420 : 55 : }
421 : :
422 : : template<> void
423 : 105 : GncSqlColumnTableEntryImpl<CT_TIME>::add_to_query(QofIdTypeConst obj_name,
424 : : const gpointer pObject,
425 : : PairVec& vec) const noexcept
426 : : {
427 : : /* We still can't use get_row_value_from_object because while g_value could
428 : : * contentedly store a time64 in an int64, KVP wouldn't be able to tell them
429 : : * apart, so we have the struct Time64 hack, see engine/gnc-date.c.
430 : : */
431 : : time64 t64;
432 : 105 : if (m_gobj_param_name != nullptr)
433 : : {
434 : : Time64* t;
435 : 36 : g_object_get (pObject, m_gobj_param_name, &t, nullptr);
436 : 36 : t64 = t->t;
437 : : }
438 : : else
439 : : {
440 : 69 : auto getter = (Time64AccessFunc)get_getter (obj_name);
441 : 69 : g_return_if_fail(getter != nullptr);
442 : 69 : t64 = (*getter)(pObject);
443 : : }
444 : 105 : if (t64 > MINTIME && t64 < MAXTIME)
445 : : {
446 : 104 : GncDateTime time(t64);
447 : 104 : std::string timestr("'");
448 : 104 : timestr += time.format_iso8601() + "'";
449 : 208 : vec.emplace_back (std::make_pair (std::string{m_col_name}, timestr));
450 : 104 : }
451 : : else
452 : : {
453 : 3 : vec.emplace_back (std::make_pair (std::string{m_col_name},
454 : : "NULL"));
455 : : }
456 : : }
457 : :
458 : : /* ----------------------------------------------------------------- */
459 : : #define DATE_COL_SIZE 8
460 : :
461 : : template<> void
462 : 71 : GncSqlColumnTableEntryImpl<CT_GDATE>::load (const GncSqlBackend* sql_be,
463 : : GncSqlRow& row,
464 : : QofIdTypeConst obj_name,
465 : : gpointer pObject) const noexcept
466 : : {
467 : 134 : g_return_if_fail (pObject != NULL);
468 : 71 : g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
469 : 71 : if (row.is_col_null(m_col_name))
470 : 63 : return;
471 : : GDate date;
472 : 8 : g_date_clear (&date, 1);
473 : :
474 : 8 : auto strval{row.get_string_at_col(m_col_name)};
475 : 8 : if (strval)
476 : : {
477 : 8 : if (strval->empty())
478 : 0 : return;
479 : 8 : auto year = static_cast<GDateYear>(stoi (strval->substr (0,4)));
480 : 8 : auto month = static_cast<GDateMonth>(stoi (strval->substr (4,2)));
481 : 8 : auto day = static_cast<GDateDay>(stoi (strval->substr (6,2)));
482 : :
483 : 8 : if (year != 0 || month != 0 || day != (GDateDay)0)
484 : 8 : g_date_set_dmy(&date, day, month, year);
485 : : }
486 : : else
487 : : {
488 : 0 : auto timeval = row.get_time64_at_col(m_col_name);
489 : 0 : if (!timeval)
490 : 0 : return;
491 : : /* time64_to_gdate applies the tz, and gdates are saved
492 : : * as ymd, so we don't want that.
493 : : */
494 : 0 : auto time = *timeval;
495 : 0 : auto tm = gnc_gmtime(&time);
496 : 0 : g_date_set_dmy(&date, tm->tm_mday,
497 : 0 : static_cast<GDateMonth>(tm->tm_mon + 1),
498 : 0 : tm->tm_year + 1900);
499 : 0 : free(tm);
500 : : }
501 : :
502 : 8 : set_parameter(pObject, &date, get_setter(obj_name), m_gobj_param_name);
503 : 8 : }
504 : :
505 : : template<> void
506 : 25 : GncSqlColumnTableEntryImpl<CT_GDATE>::add_to_table(ColVec& vec) const noexcept
507 : : {
508 : 25 : GncSqlColumnInfo info{*this, BCT_DATE, DATE_COL_SIZE, FALSE};
509 : 25 : vec.emplace_back(std::move(info));
510 : 25 : }
511 : :
512 : : template<> void
513 : 78 : GncSqlColumnTableEntryImpl<CT_GDATE>::add_to_query(QofIdTypeConst obj_name,
514 : : const gpointer pObject,
515 : : PairVec& vec) const noexcept
516 : : {
517 : 78 : GDate *date = get_row_value_from_object<GDate*>(obj_name, pObject);
518 : :
519 : 78 : if (date && g_date_valid (date))
520 : : {
521 : 8 : std::ostringstream buf;
522 : 8 : buf << std::setfill ('0') << std::setw (4) << g_date_get_year (date) <<
523 : 8 : std::setw (2) << g_date_get_month (date) <<
524 : 8 : std::setw (2) << static_cast<int>(g_date_get_day (date));
525 : 16 : vec.emplace_back (std::make_pair (std::string{m_col_name},
526 : 16 : quote_string(buf.str())));
527 : 8 : return;
528 : 8 : }
529 : : }
530 : :
531 : : /* ----------------------------------------------------------------- */
532 : : typedef gnc_numeric (*NumericGetterFunc) (const gpointer);
533 : : typedef void (*NumericSetterFunc) (gpointer, gnc_numeric);
534 : :
535 : : static const EntryVec numeric_col_table =
536 : : {
537 : : gnc_sql_make_table_entry<CT_INT64>("num", 0, COL_NNUL, "guid"),
538 : : gnc_sql_make_table_entry<CT_INT64>("denom", 0, COL_NNUL, "guid")
539 : : };
540 : :
541 : : template <>
542 : 38 : void set_parameter<gpointer, gnc_numeric>(gpointer object,
543 : : gnc_numeric item,
544 : : const char* property)
545 : : {
546 : 38 : qof_instance_increase_editlevel(object);
547 : 38 : g_object_set(object, property, &item, nullptr);
548 : 38 : qof_instance_decrease_editlevel(object);
549 : 38 : };
550 : :
551 : : template<> void
552 : 106 : GncSqlColumnTableEntryImpl<CT_NUMERIC>::load (const GncSqlBackend* sql_be,
553 : : GncSqlRow& row,
554 : : QofIdTypeConst obj_name,
555 : : gpointer pObject) const noexcept
556 : : {
557 : :
558 : :
559 : 106 : g_return_if_fail (pObject != NULL);
560 : 106 : g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
561 : :
562 : 106 : auto buf = g_strdup_printf ("%s_num", m_col_name);
563 : 106 : auto num = row.get_int_at_col (buf);
564 : 106 : g_free (buf);
565 : 106 : buf = g_strdup_printf ("%s_denom", m_col_name);
566 : 106 : auto denom = row.get_int_at_col (buf);
567 : 106 : g_free (buf);
568 : :
569 : 106 : if (num && denom)
570 : : {
571 : 106 : auto n = gnc_numeric_create (*num, *denom);
572 : 106 : set_parameter(pObject, n,
573 : 106 : reinterpret_cast<NumericSetterFunc>(get_setter(obj_name)),
574 : 106 : m_gobj_param_name);
575 : : }
576 : : }
577 : :
578 : : template<> void
579 : 80 : GncSqlColumnTableEntryImpl<CT_NUMERIC>::add_to_table(ColVec& vec) const noexcept
580 : : {
581 : :
582 : 240 : for (auto const& subtable_row : numeric_col_table)
583 : : {
584 : 160 : gchar* buf = g_strdup_printf("%s_%s", m_col_name,
585 : 160 : subtable_row->m_col_name);
586 : : GncSqlColumnInfo info(buf, BCT_INT64, 0, false, false,
587 : 320 : m_flags & COL_PKEY, m_flags & COL_NNUL);
588 : 160 : g_free (buf);
589 : 160 : vec.emplace_back(std::move(info));
590 : 160 : }
591 : 80 : }
592 : :
593 : : template<> void
594 : 113 : GncSqlColumnTableEntryImpl<CT_NUMERIC>::add_to_query(QofIdTypeConst obj_name,
595 : : const gpointer pObject,
596 : : PairVec& vec) const noexcept
597 : : {
598 : : /* We can't use get_row_value_from_object for the same reason as time64. */
599 : : NumericGetterFunc getter;
600 : : gnc_numeric n;
601 : :
602 : 113 : g_return_if_fail (obj_name != NULL);
603 : 113 : g_return_if_fail (pObject != NULL);
604 : :
605 : 113 : if (m_gobj_param_name != nullptr)
606 : : {
607 : : gnc_numeric* s;
608 : 38 : g_object_get (pObject, m_gobj_param_name, &s, NULL);
609 : 38 : n = *s;
610 : : }
611 : : else
612 : : {
613 : 75 : getter = reinterpret_cast<NumericGetterFunc>(get_getter (obj_name));
614 : 75 : if (getter != NULL)
615 : : {
616 : 75 : n = (*getter) (pObject);
617 : : }
618 : : else
619 : : {
620 : 0 : n = gnc_numeric_zero ();
621 : : }
622 : : }
623 : :
624 : 113 : std::ostringstream buf;
625 : 226 : std::string num_col{m_col_name};
626 : 226 : std::string denom_col{m_col_name};
627 : 113 : num_col += "_num";
628 : 113 : denom_col += "_denom";
629 : 113 : buf << gnc_numeric_num (n);
630 : 113 : vec.emplace_back (std::make_pair (num_col, buf.str ()));
631 : 113 : buf.str ("");
632 : 113 : buf << gnc_numeric_denom (n);
633 : 113 : vec.emplace_back (denom_col, buf.str ());
634 : 113 : }
635 : :
636 : : static void
637 : 80 : _retrieve_guid_ (gpointer pObject, gpointer pValue)
638 : : {
639 : 80 : GncGUID* pGuid = (GncGUID*)pObject;
640 : 80 : GncGUID* guid = (GncGUID*)pValue;
641 : :
642 : 80 : g_return_if_fail (pObject != NULL);
643 : 80 : g_return_if_fail (pValue != NULL);
644 : :
645 : 80 : *pGuid = *guid;
646 : : }
647 : :
648 : : // Table to retrieve just the guid
649 : : static EntryVec guid_table
650 : : {
651 : : gnc_sql_make_table_entry<CT_GUID>("guid", 0, 0, nullptr, _retrieve_guid_)
652 : : };
653 : :
654 : : const GncGUID*
655 : 80 : gnc_sql_load_guid (const GncSqlBackend* sql_be, GncSqlRow& row)
656 : : {
657 : : static GncGUID guid;
658 : :
659 : 80 : g_return_val_if_fail (sql_be != NULL, NULL);
660 : :
661 : 80 : gnc_sql_load_object (sql_be, row, NULL, &guid, guid_table);
662 : :
663 : 80 : return &guid;
664 : : }
665 : :
666 : : void
667 : 275 : gnc_sql_load_object (const GncSqlBackend* sql_be, GncSqlRow& row,
668 : : QofIdTypeConst obj_name, gpointer pObject,
669 : : const EntryVec& table)
670 : : {
671 : 275 : g_return_if_fail (sql_be != NULL);
672 : 275 : g_return_if_fail (pObject != NULL);
673 : :
674 : 1912 : for (auto const& table_row : table)
675 : : {
676 : 1637 : table_row->load (sql_be, row, obj_name, pObject);
677 : : }
678 : : }
679 : :
680 : : uint_t
681 : 0 : gnc_sql_append_guids_to_sql (std::stringstream& sql,
682 : : const InstanceVec& instances)
683 : : {
684 : : char guid_buf[GUID_ENCODING_LENGTH + 1];
685 : :
686 : 0 : for (auto inst : instances)
687 : : {
688 : 0 : (void)guid_to_string_buff (qof_instance_get_guid (inst), guid_buf);
689 : :
690 : 0 : if (inst != *(instances.begin()))
691 : : {
692 : 0 : sql << ",";
693 : : }
694 : 0 : sql << "'" << guid_buf << "'";
695 : : }
696 : :
697 : 0 : return instances.size();
698 : : }
699 : :
700 : : /* This is necessary for 64-bit builds because g++ complains
701 : : * that reinterpret_casting a void* (64 bits) to an int (32 bits)
702 : : * loses precision, so we have to explicitly dispose of the precision.
703 : : * FIXME: We shouldn't be storing ints in ptrs in the first place.
704 : : */
705 : : #ifdef __LP64__
706 : : template <> int
707 : 364 : GncSqlColumnTableEntry::get_row_value_from_object<int>(QofIdTypeConst obj_name,
708 : : const void* pObject,
709 : : std::false_type) const
710 : : {
711 : 364 : g_return_val_if_fail(obj_name != nullptr && pObject != nullptr, 0);
712 : 364 : int result = 0;
713 : 364 : if (m_gobj_param_name != nullptr)
714 : 281 : g_object_get(const_cast<void*>(pObject), m_gobj_param_name, &result,
715 : : nullptr);
716 : : else
717 : : {
718 : 83 : QofAccessFunc getter = get_getter(obj_name);
719 : 83 : if (getter != nullptr)
720 : : {
721 : 83 : auto value = ((getter)(const_cast<void*>(pObject), nullptr));
722 : 83 : result = reinterpret_cast<uint64_t>(value) &
723 : : UINT64_C(0x00000000FFFFFFFF);
724 : : }
725 : : }
726 : 364 : return result;
727 : : }
728 : : #endif
|