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