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 81 : set_autoinc_id (void* object, void* item)
47 : {
48 : // Nowhere to put the ID
49 81 : }
50 :
51 : QofAccessFunc
52 1121 : GncSqlColumnTableEntry::get_getter (QofIdTypeConst obj_name) const noexcept
53 : {
54 : QofAccessFunc getter;
55 :
56 1121 : g_return_val_if_fail (obj_name != NULL, NULL);
57 :
58 1121 : if (m_flags & COL_AUTOINC)
59 : {
60 0 : getter = get_autoinc_id;
61 : }
62 1121 : else if (m_qof_param_name != NULL)
63 : {
64 76 : getter = qof_class_get_parameter_getter (obj_name, m_qof_param_name);
65 : }
66 : else
67 : {
68 1045 : getter = m_getter;
69 : }
70 :
71 1121 : return getter;
72 : }
73 :
74 : QofSetterFunc
75 2983 : GncSqlColumnTableEntry::get_setter(QofIdTypeConst obj_name) const noexcept
76 : {
77 2983 : QofSetterFunc setter = nullptr;
78 2983 : if (m_flags & COL_AUTOINC)
79 : {
80 162 : setter = set_autoinc_id;
81 : }
82 2821 : else if (m_qof_param_name != nullptr)
83 : {
84 140 : g_assert (obj_name != NULL);
85 140 : setter = qof_class_get_parameter_setter (obj_name, m_qof_param_name);
86 : }
87 : else
88 : {
89 2681 : setter = m_setter;
90 : }
91 2983 : return setter;
92 : }
93 :
94 : void
95 147 : GncSqlColumnTableEntry::add_objectref_guid_to_query (QofIdTypeConst obj_name,
96 : const void* pObject,
97 : PairVec& vec) const noexcept
98 : {
99 147 : auto inst = get_row_value_from_object<QofInstance*>(obj_name, pObject);
100 147 : if (inst == nullptr) return;
101 100 : auto guid = qof_instance_get_guid (inst);
102 100 : if (guid != nullptr) {
103 100 : gchar *guid_s = guid_to_string(guid);
104 300 : vec.emplace_back (std::make_pair (std::string{m_col_name}, quote_string(guid_s)));
105 100 : g_free(guid_s);
106 : }
107 : }
108 :
109 : void
110 198 : GncSqlColumnTableEntry::add_objectref_guid_to_table (ColVec& vec) const noexcept
111 : {
112 198 : GncSqlColumnInfo info{*this, BCT_STRING, GUID_ENCODING_LENGTH, FALSE};
113 198 : vec.emplace_back(std::move(info));
114 198 : }
115 :
116 :
117 : /* ----------------------------------------------------------------- */
118 : template<> void
119 506 : GncSqlColumnTableEntryImpl<CT_STRING>::load (const GncSqlBackend* sql_be,
120 : GncSqlRow& row,
121 : QofIdTypeConst obj_name,
122 : gpointer pObject) const noexcept
123 : {
124 506 : g_return_if_fail (pObject != NULL);
125 506 : g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
126 :
127 506 : auto s = row.get_string_at_col (m_col_name);
128 506 : if (s)
129 506 : set_parameter(pObject, s->c_str(), get_setter(obj_name), m_gobj_param_name);
130 506 : }
131 :
132 : template<> void
133 324 : GncSqlColumnTableEntryImpl<CT_STRING>::add_to_table(ColVec& vec) const noexcept
134 : {
135 324 : GncSqlColumnInfo info{*this, BCT_STRING, m_size, TRUE};
136 324 : vec.emplace_back(std::move(info));
137 324 : }
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 789 : GncSqlColumnTableEntryImpl<CT_STRING>::add_to_query(QofIdTypeConst obj_name,
144 : const gpointer pObject,
145 : PairVec& vec) const noexcept
146 : {
147 789 : auto s = get_row_value_from_object<char*>(obj_name, pObject);
148 :
149 789 : if (s != nullptr)
150 : {
151 736 : std::ostringstream stream;
152 736 : stream << s;
153 1472 : vec.emplace_back (std::make_pair (std::string{m_col_name},
154 1472 : quote_string(stream.str())));
155 736 : return;
156 736 : }
157 : }
158 :
159 : /* ----------------------------------------------------------------- */
160 : typedef gint (*IntAccessFunc) (const gpointer);
161 : typedef void (*IntSetterFunc) (const gpointer, gint);
162 :
163 : template<> void
164 232 : GncSqlColumnTableEntryImpl<CT_INT>::load (const GncSqlBackend* sql_be,
165 : GncSqlRow& row,
166 : QofIdTypeConst obj_name,
167 : gpointer pObject) const noexcept
168 : {
169 :
170 232 : g_return_if_fail (pObject != NULL);
171 232 : g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
172 :
173 232 : auto val = row.get_int_at_col(m_col_name);
174 232 : if (val)
175 232 : set_parameter(pObject, *val,
176 232 : reinterpret_cast<IntSetterFunc>(get_setter(obj_name)),
177 232 : m_gobj_param_name);
178 : }
179 :
180 : template<> void
181 138 : GncSqlColumnTableEntryImpl<CT_INT>::add_to_table(ColVec& vec) const noexcept
182 : {
183 138 : GncSqlColumnInfo info{*this, BCT_INT, 0, FALSE};
184 138 : vec.emplace_back(std::move(info));
185 138 : }
186 :
187 : template<> void
188 199 : GncSqlColumnTableEntryImpl<CT_INT>::add_to_query(QofIdTypeConst obj_name,
189 : const gpointer pObject,
190 : PairVec& vec) const noexcept
191 : {
192 199 : add_value_to_vec<int>(obj_name, pObject, vec);
193 199 : }
194 :
195 : /* ----------------------------------------------------------------- */
196 : typedef gboolean (*BooleanAccessFunc) (const gpointer);
197 : typedef void (*BooleanSetterFunc) (const gpointer, gboolean);
198 :
199 : template<> void
200 160 : GncSqlColumnTableEntryImpl<CT_BOOLEAN>::load (const GncSqlBackend* sql_be,
201 : GncSqlRow& row,
202 : QofIdTypeConst obj_name,
203 : gpointer pObject)
204 : const noexcept
205 : {
206 160 : g_return_if_fail (pObject != NULL);
207 160 : g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
208 :
209 160 : auto val = row.get_int_at_col (m_col_name);
210 160 : if (val)
211 160 : set_parameter(pObject, static_cast<int>(*val),
212 160 : reinterpret_cast<BooleanSetterFunc>(get_setter(obj_name)),
213 160 : m_gobj_param_name);
214 : }
215 :
216 : template<> void
217 138 : GncSqlColumnTableEntryImpl<CT_BOOLEAN>::add_to_table(ColVec& vec) const noexcept
218 : {
219 138 : GncSqlColumnInfo info{*this, BCT_INT, 0, FALSE};
220 138 : vec.emplace_back(std::move(info));
221 138 : }
222 :
223 : template<> void
224 203 : GncSqlColumnTableEntryImpl<CT_BOOLEAN>::add_to_query(QofIdTypeConst obj_name,
225 : const gpointer pObject,
226 : PairVec& vec) const noexcept
227 : {
228 203 : add_value_to_vec<int>(obj_name, pObject, vec);
229 203 : }
230 :
231 : /* ----------------------------------------------------------------- */
232 : typedef gint64 (*Int64AccessFunc) (const gpointer);
233 : typedef void (*Int64SetterFunc) (const gpointer, gint64);
234 :
235 : template<> void
236 76 : GncSqlColumnTableEntryImpl<CT_INT64>::load (const GncSqlBackend* sql_be,
237 : GncSqlRow& row,
238 : QofIdTypeConst obj_name,
239 : gpointer pObject)
240 : const noexcept
241 : {
242 76 : g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
243 :
244 76 : auto val = row.get_int_at_col (m_col_name);
245 76 : if (val)
246 76 : set_parameter(pObject, *val,
247 76 : reinterpret_cast<Int64SetterFunc>(get_setter(obj_name)),
248 76 : m_gobj_param_name);
249 : }
250 :
251 : template<> void
252 12 : GncSqlColumnTableEntryImpl<CT_INT64>::add_to_table(ColVec& vec) const noexcept
253 : {
254 :
255 12 : GncSqlColumnInfo info{*this, BCT_INT64, 0, FALSE};
256 12 : vec.emplace_back(std::move(info));
257 12 : }
258 :
259 : template<> gint64
260 77 : GncSqlColumnTableEntry::get_row_value_from_object<int64_t>(QofIdTypeConst obj_name,
261 : const void* pObject) const
262 : {
263 77 : g_return_val_if_fail(obj_name != nullptr && pObject != nullptr,
264 : INT64_C(0));
265 77 : int64_t result = INT64_C(0);
266 77 : 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 75 : auto getter = (Int64AccessFunc)get_getter(obj_name);
272 75 : if (getter != nullptr)
273 75 : result = (getter)(const_cast<void*>(pObject));
274 : }
275 77 : return result;
276 : }
277 :
278 : template<> void
279 77 : GncSqlColumnTableEntryImpl<CT_INT64>::add_to_query(QofIdTypeConst obj_name,
280 : const gpointer pObject,
281 : PairVec& vec) const noexcept
282 : {
283 77 : add_value_to_vec<int64_t>(obj_name, pObject, vec);
284 77 : }
285 : /* ----------------------------------------------------------------- */
286 :
287 : template<> void
288 74 : GncSqlColumnTableEntryImpl<CT_DOUBLE>::load (const GncSqlBackend* sql_be,
289 : GncSqlRow& row,
290 : QofIdTypeConst obj_name,
291 : gpointer pObject)
292 : const noexcept
293 : {
294 74 : g_return_if_fail (pObject != NULL);
295 74 : g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
296 74 : double val{0.0};
297 :
298 74 : if (auto int_val{row.get_int_at_col(m_col_name)})
299 0 : val = static_cast<decltype(val)>(*int_val);
300 74 : else if (auto float_val{row.get_float_at_col(m_col_name)})
301 0 : val = static_cast<decltype(val)>(*float_val);
302 74 : else if (auto double_val{row.get_double_at_col(m_col_name)})
303 74 : val = *double_val;
304 :
305 74 : set_parameter(pObject, val, get_setter(obj_name), m_gobj_param_name);
306 : }
307 :
308 : template<> void
309 6 : GncSqlColumnTableEntryImpl<CT_DOUBLE>::add_to_table(ColVec& vec) const noexcept
310 : {
311 6 : GncSqlColumnInfo info{*this, BCT_DOUBLE, 0, FALSE};
312 6 : vec.emplace_back(std::move(info));
313 6 : }
314 :
315 : template<> void
316 75 : GncSqlColumnTableEntryImpl<CT_DOUBLE>::add_to_query(QofIdTypeConst obj_name,
317 : const gpointer pObject,
318 : PairVec& vec) const noexcept
319 : {
320 75 : add_value_to_vec<double*>(obj_name, pObject, vec);
321 75 : }
322 :
323 : /* ----------------------------------------------------------------- */
324 :
325 : template<> void
326 474 : 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 474 : g_return_if_fail (pObject != NULL);
336 474 : g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
337 :
338 474 : auto strval{row.get_string_at_col(m_col_name)};
339 474 : if (strval && string_to_guid (strval->c_str(), &guid))
340 395 : set_parameter(pObject, &guid, get_setter(obj_name), m_gobj_param_name);
341 474 : }
342 :
343 : template<> void
344 156 : GncSqlColumnTableEntryImpl<CT_GUID>::add_to_table(ColVec& vec) const noexcept
345 : {
346 156 : GncSqlColumnInfo info{*this, BCT_STRING, GUID_ENCODING_LENGTH, FALSE};
347 156 : vec.emplace_back(std::move(info));
348 156 : }
349 :
350 : template<> void
351 397 : GncSqlColumnTableEntryImpl<CT_GUID>::add_to_query(QofIdTypeConst obj_name,
352 : const gpointer pObject,
353 : PairVec& vec) const noexcept
354 : {
355 397 : auto s = get_row_value_from_object<GncGUID*>(obj_name, pObject);
356 :
357 397 : if (s != nullptr)
358 : {
359 327 : gchar *guid_s = guid_to_string(s);
360 981 : vec.emplace_back (std::make_pair (std::string{m_col_name}, quote_string(guid_s)));
361 327 : g_free(guid_s);
362 327 : 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 125 : GncSqlColumnTableEntryImpl<CT_TIME>::load (const GncSqlBackend* sql_be,
372 : GncSqlRow& row,
373 : QofIdTypeConst obj_name,
374 : gpointer pObject)
375 : const noexcept
376 : {
377 125 : time64 t{0};
378 125 : g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
379 125 : auto strval = row.get_string_at_col(m_col_name);
380 125 : if (strval)
381 : {
382 125 : if (!strval->empty())
383 : try
384 : {
385 124 : GncDateTime time(*strval);
386 124 : t = static_cast<time64>(time);
387 124 : }
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 125 : if (m_gobj_param_name != nullptr)
402 : {
403 47 : Time64 t64{t};
404 47 : set_parameter(pObject, &t64, m_gobj_param_name);
405 : }
406 : else
407 : {
408 78 : set_parameter(pObject, t,
409 78 : reinterpret_cast<Time64SetterFunc>(get_setter(obj_name)),
410 : nullptr);
411 : }
412 125 : }
413 :
414 : template<> void
415 66 : GncSqlColumnTableEntryImpl<CT_TIME>::add_to_table(ColVec& vec) const noexcept
416 : {
417 :
418 66 : GncSqlColumnInfo info{*this, BCT_DATETIME, TIME_COL_SIZE, FALSE};
419 66 : vec.emplace_back(std::move(info));
420 66 : }
421 :
422 : template<> void
423 123 : 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 123 : if (m_gobj_param_name != nullptr)
433 : {
434 : Time64* t;
435 44 : g_object_get (pObject, m_gobj_param_name, &t, nullptr);
436 44 : t64 = t->t;
437 : }
438 : else
439 : {
440 79 : auto getter = (Time64AccessFunc)get_getter (obj_name);
441 79 : g_return_if_fail(getter != nullptr);
442 79 : t64 = (*getter)(pObject);
443 : }
444 123 : if (t64 > MINTIME && t64 < MAXTIME)
445 : {
446 122 : GncDateTime time(t64);
447 122 : std::string timestr("'");
448 122 : timestr += time.format_iso8601() + "'";
449 244 : vec.emplace_back (std::make_pair (std::string{m_col_name}, timestr));
450 122 : }
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 87 : GncSqlColumnTableEntryImpl<CT_GDATE>::load (const GncSqlBackend* sql_be,
463 : GncSqlRow& row,
464 : QofIdTypeConst obj_name,
465 : gpointer pObject) const noexcept
466 : {
467 166 : g_return_if_fail (pObject != NULL);
468 87 : g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
469 87 : if (row.is_col_null(m_col_name))
470 79 : 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 30 : GncSqlColumnTableEntryImpl<CT_GDATE>::add_to_table(ColVec& vec) const noexcept
507 : {
508 30 : GncSqlColumnInfo info{*this, BCT_DATE, DATE_COL_SIZE, FALSE};
509 30 : vec.emplace_back(std::move(info));
510 30 : }
511 :
512 : template<> void
513 88 : GncSqlColumnTableEntryImpl<CT_GDATE>::add_to_query(QofIdTypeConst obj_name,
514 : const gpointer pObject,
515 : PairVec& vec) const noexcept
516 : {
517 88 : GDate *date = get_row_value_from_object<GDate*>(obj_name, pObject);
518 :
519 88 : 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 48 : void set_parameter<gpointer, gnc_numeric>(gpointer object,
543 : gnc_numeric item,
544 : const char* property)
545 : {
546 48 : qof_instance_increase_editlevel(object);
547 48 : g_object_set(object, property, &item, nullptr);
548 48 : qof_instance_decrease_editlevel(object);
549 48 : };
550 :
551 : template<> void
552 132 : GncSqlColumnTableEntryImpl<CT_NUMERIC>::load (const GncSqlBackend* sql_be,
553 : GncSqlRow& row,
554 : QofIdTypeConst obj_name,
555 : gpointer pObject) const noexcept
556 : {
557 :
558 :
559 132 : g_return_if_fail (pObject != NULL);
560 132 : g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
561 :
562 132 : auto buf = g_strdup_printf ("%s_num", m_col_name);
563 132 : auto num = row.get_int_at_col (buf);
564 132 : g_free (buf);
565 132 : buf = g_strdup_printf ("%s_denom", m_col_name);
566 132 : auto denom = row.get_int_at_col (buf);
567 132 : g_free (buf);
568 :
569 132 : if (num && denom)
570 : {
571 132 : auto n = gnc_numeric_create (*num, *denom);
572 132 : set_parameter(pObject, n,
573 132 : reinterpret_cast<NumericSetterFunc>(get_setter(obj_name)),
574 132 : m_gobj_param_name);
575 : }
576 : }
577 :
578 : template<> void
579 96 : GncSqlColumnTableEntryImpl<CT_NUMERIC>::add_to_table(ColVec& vec) const noexcept
580 : {
581 :
582 384 : for (auto const& subtable_row : numeric_col_table)
583 : {
584 192 : gchar* buf = g_strdup_printf("%s_%s", m_col_name,
585 192 : subtable_row->m_col_name);
586 384 : GncSqlColumnInfo info(buf, BCT_INT64, 0, false, false,
587 384 : m_flags & COL_PKEY, m_flags & COL_NNUL);
588 192 : g_free (buf);
589 192 : vec.emplace_back(std::move(info));
590 192 : }
591 96 : }
592 :
593 : template<> void
594 131 : 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 131 : g_return_if_fail (obj_name != NULL);
603 131 : g_return_if_fail (pObject != NULL);
604 :
605 131 : if (m_gobj_param_name != nullptr)
606 : {
607 : gnc_numeric* s;
608 46 : g_object_get (pObject, m_gobj_param_name, &s, NULL);
609 46 : n = *s;
610 : }
611 : else
612 : {
613 85 : getter = reinterpret_cast<NumericGetterFunc>(get_getter (obj_name));
614 85 : if (getter != NULL)
615 : {
616 85 : n = (*getter) (pObject);
617 : }
618 : else
619 : {
620 0 : n = gnc_numeric_zero ();
621 : }
622 : }
623 :
624 131 : std::ostringstream buf;
625 262 : std::string num_col{m_col_name};
626 262 : std::string denom_col{m_col_name};
627 131 : num_col += "_num";
628 131 : denom_col += "_denom";
629 131 : buf << gnc_numeric_num (n);
630 131 : vec.emplace_back (std::make_pair (num_col, buf.str ()));
631 131 : buf.str ("");
632 131 : buf << gnc_numeric_denom (n);
633 131 : vec.emplace_back (denom_col, buf.str ());
634 131 : }
635 :
636 : static void
637 98 : _retrieve_guid_ (gpointer pObject, gpointer pValue)
638 : {
639 98 : GncGUID* pGuid = (GncGUID*)pObject;
640 98 : GncGUID* guid = (GncGUID*)pValue;
641 :
642 98 : g_return_if_fail (pObject != NULL);
643 98 : g_return_if_fail (pValue != NULL);
644 :
645 98 : *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 98 : gnc_sql_load_guid (const GncSqlBackend* sql_be, GncSqlRow& row)
656 : {
657 : static GncGUID guid;
658 :
659 98 : g_return_val_if_fail (sql_be != NULL, NULL);
660 :
661 98 : gnc_sql_load_object (sql_be, row, NULL, &guid, guid_table);
662 :
663 98 : return &guid;
664 : }
665 :
666 : void
667 345 : gnc_sql_load_object (const GncSqlBackend* sql_be, GncSqlRow& row,
668 : QofIdTypeConst obj_name, gpointer pObject,
669 : const EntryVec& table)
670 : {
671 345 : g_return_if_fail (sql_be != NULL);
672 345 : g_return_if_fail (pObject != NULL);
673 :
674 2717 : for (auto const& table_row : table)
675 : {
676 2027 : 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 402 : GncSqlColumnTableEntry::get_row_value_from_object<int>(QofIdTypeConst obj_name,
708 : const void* pObject,
709 : std::false_type) const
710 : {
711 402 : g_return_val_if_fail(obj_name != nullptr && pObject != nullptr, 0);
712 402 : int result = 0;
713 402 : if (m_gobj_param_name != nullptr)
714 309 : g_object_get(const_cast<void*>(pObject), m_gobj_param_name, &result,
715 : nullptr);
716 : else
717 : {
718 93 : QofAccessFunc getter = get_getter(obj_name);
719 93 : if (getter != nullptr)
720 : {
721 93 : auto value = ((getter)(const_cast<void*>(pObject), nullptr));
722 93 : result = reinterpret_cast<uint64_t>(value) &
723 : UINT64_C(0x00000000FFFFFFFF);
724 : }
725 : }
726 402 : return result;
727 : }
728 : #endif
|