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 <gnc-datetime.hpp>
29 : : #include "gnc-sql-backend.hpp"
30 : : #include "gnc-sql-object-backend.hpp"
31 : : #include "gnc-sql-column-table-entry.hpp"
32 : : #include "gnc-sql-result.hpp"
33 : :
34 : : static QofLogModule log_module = G_LOG_DOMAIN;
35 : :
36 : : /* ================================================================= */
37 : : static gpointer
38 : 0 : get_autoinc_id (void* object, const QofParam* param)
39 : : {
40 : : // Just need a 0 to force a new autoinc value
41 : 0 : return (gpointer)0;
42 : : }
43 : :
44 : : static void
45 : 65 : set_autoinc_id (void* object, void* item)
46 : : {
47 : : // Nowhere to put the ID
48 : 65 : }
49 : :
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 : 88 : 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 : 654 : 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<> void
260 : 67 : GncSqlColumnTableEntryImpl<CT_INT64>::add_to_query(QofIdTypeConst obj_name,
261 : : const gpointer pObject,
262 : : PairVec& vec) const noexcept
263 : : {
264 : 67 : add_value_to_vec<int64_t>(obj_name, pObject, vec);
265 : 67 : }
266 : : /* ----------------------------------------------------------------- */
267 : :
268 : : template<> void
269 : 58 : GncSqlColumnTableEntryImpl<CT_DOUBLE>::load (const GncSqlBackend* sql_be,
270 : : GncSqlRow& row,
271 : : QofIdTypeConst obj_name,
272 : : gpointer pObject)
273 : : const noexcept
274 : : {
275 : 58 : g_return_if_fail (pObject != NULL);
276 : 58 : g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
277 : 58 : double val{0.0};
278 : :
279 : 58 : if (auto int_val{row.get_int_at_col(m_col_name)})
280 : 0 : val = static_cast<decltype(val)>(*int_val);
281 : 58 : else if (auto float_val{row.get_float_at_col(m_col_name)})
282 : 6 : val = static_cast<decltype(val)>(*float_val);
283 : 52 : else if (auto double_val{row.get_double_at_col(m_col_name)})
284 : 52 : val = *double_val;
285 : :
286 : 58 : set_parameter(pObject, val, get_setter(obj_name), m_gobj_param_name);
287 : : }
288 : :
289 : : template<> void
290 : 5 : GncSqlColumnTableEntryImpl<CT_DOUBLE>::add_to_table(ColVec& vec) const noexcept
291 : : {
292 : 5 : GncSqlColumnInfo info{*this, BCT_DOUBLE, 0, FALSE};
293 : 5 : vec.emplace_back(std::move(info));
294 : 5 : }
295 : :
296 : : template<> void
297 : 65 : GncSqlColumnTableEntryImpl<CT_DOUBLE>::add_to_query(QofIdTypeConst obj_name,
298 : : const gpointer pObject,
299 : : PairVec& vec) const noexcept
300 : : {
301 : 65 : add_value_to_vec<double*>(obj_name, pObject, vec);
302 : 65 : }
303 : :
304 : : /* ----------------------------------------------------------------- */
305 : :
306 : : template<> void
307 : 376 : GncSqlColumnTableEntryImpl<CT_GUID>::load (const GncSqlBackend* sql_be,
308 : : GncSqlRow& row,
309 : : QofIdTypeConst obj_name,
310 : : gpointer pObject)
311 : : const noexcept
312 : : {
313 : :
314 : : GncGUID guid;
315 : :
316 : 376 : g_return_if_fail (pObject != NULL);
317 : 376 : g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
318 : :
319 : 376 : auto strval{row.get_string_at_col(m_col_name)};
320 : 376 : if (strval && string_to_guid (strval->c_str(), &guid))
321 : 316 : set_parameter(pObject, &guid, get_setter(obj_name), m_gobj_param_name);
322 : 376 : }
323 : :
324 : : template<> void
325 : 130 : GncSqlColumnTableEntryImpl<CT_GUID>::add_to_table(ColVec& vec) const noexcept
326 : : {
327 : 130 : GncSqlColumnInfo info{*this, BCT_STRING, GUID_ENCODING_LENGTH, FALSE};
328 : 130 : vec.emplace_back(std::move(info));
329 : 130 : }
330 : :
331 : : template<> void
332 : 344 : GncSqlColumnTableEntryImpl<CT_GUID>::add_to_query(QofIdTypeConst obj_name,
333 : : const gpointer pObject,
334 : : PairVec& vec) const noexcept
335 : : {
336 : 344 : auto s = get_row_value_from_object<GncGUID*>(obj_name, pObject);
337 : :
338 : 344 : if (s != nullptr)
339 : : {
340 : 284 : gchar *guid_s = guid_to_string(s);
341 : 284 : vec.emplace_back (std::make_pair (std::string{m_col_name}, quote_string(guid_s)));
342 : 284 : g_free(guid_s);
343 : 284 : return;
344 : : }
345 : : }
346 : : /* ----------------------------------------------------------------- */
347 : : typedef time64 (*Time64AccessFunc) (const gpointer);
348 : : typedef void (*Time64SetterFunc) (const gpointer, time64);
349 : : constexpr int TIME_COL_SIZE = 4 + 3 + 3 + 3 + 3 + 3;
350 : :
351 : : template<> void
352 : 98 : GncSqlColumnTableEntryImpl<CT_TIME>::load (const GncSqlBackend* sql_be,
353 : : GncSqlRow& row,
354 : : QofIdTypeConst obj_name,
355 : : gpointer pObject)
356 : : const noexcept
357 : : {
358 : 98 : time64 t{0};
359 : 98 : g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
360 : 98 : auto strval = row.get_string_at_col(m_col_name);
361 : 98 : if (strval)
362 : : {
363 : 98 : if (!strval->empty())
364 : : try
365 : : {
366 : 97 : GncDateTime time(*strval);
367 : 97 : t = static_cast<time64>(time);
368 : 97 : }
369 : 0 : catch (const std::invalid_argument& err)
370 : : {
371 : 0 : PWARN("An invalid date %s was found in your database."
372 : : "It has been set to 1 January 1970.",
373 : : strval->c_str());
374 : 0 : }
375 : : }
376 : : else
377 : : {
378 : 0 : if (auto time64val = row.get_time64_at_col (m_col_name))
379 : 0 : t = *time64val;
380 : : }
381 : :
382 : 98 : if (m_gobj_param_name != nullptr)
383 : : {
384 : 36 : Time64 t64{t};
385 : 36 : set_parameter(pObject, &t64, m_gobj_param_name);
386 : : }
387 : : else
388 : : {
389 : 62 : set_parameter(pObject, t,
390 : 62 : reinterpret_cast<Time64SetterFunc>(get_setter(obj_name)),
391 : : nullptr);
392 : : }
393 : 98 : }
394 : :
395 : : template<> void
396 : 55 : GncSqlColumnTableEntryImpl<CT_TIME>::add_to_table(ColVec& vec) const noexcept
397 : : {
398 : :
399 : 55 : GncSqlColumnInfo info{*this, BCT_DATETIME, TIME_COL_SIZE, FALSE};
400 : 55 : vec.emplace_back(std::move(info));
401 : 55 : }
402 : :
403 : : template<> void
404 : 105 : GncSqlColumnTableEntryImpl<CT_TIME>::add_to_query(QofIdTypeConst obj_name,
405 : : const gpointer pObject,
406 : : PairVec& vec) const noexcept
407 : : {
408 : : /* We still can't use get_row_value_from_object because while g_value could
409 : : * contentedly store a time64 in an int64, KVP wouldn't be able to tell them
410 : : * apart, so we have the struct Time64 hack, see engine/gnc-date.c.
411 : : */
412 : : time64 t64;
413 : 105 : if (m_gobj_param_name != nullptr)
414 : : {
415 : : Time64* t;
416 : 36 : g_object_get (pObject, m_gobj_param_name, &t, nullptr);
417 : 36 : t64 = t->t;
418 : : }
419 : : else
420 : : {
421 : 69 : auto getter = (Time64AccessFunc)get_getter (obj_name);
422 : 69 : g_return_if_fail(getter != nullptr);
423 : 69 : t64 = (*getter)(pObject);
424 : : }
425 : 105 : if (t64 > MINTIME && t64 < MAXTIME)
426 : : {
427 : 104 : GncDateTime time(t64);
428 : 104 : std::string timestr("'");
429 : 104 : timestr += time.format_iso8601() + "'";
430 : 104 : vec.emplace_back (std::make_pair (std::string{m_col_name}, timestr));
431 : 104 : }
432 : : else
433 : : {
434 : 1 : vec.emplace_back (std::make_pair (std::string{m_col_name},
435 : : "NULL"));
436 : : }
437 : : }
438 : :
439 : : /* ----------------------------------------------------------------- */
440 : : #define DATE_COL_SIZE 8
441 : :
442 : : template<> void
443 : 71 : GncSqlColumnTableEntryImpl<CT_GDATE>::load (const GncSqlBackend* sql_be,
444 : : GncSqlRow& row,
445 : : QofIdTypeConst obj_name,
446 : : gpointer pObject) const noexcept
447 : : {
448 : 134 : g_return_if_fail (pObject != NULL);
449 : 71 : g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
450 : 71 : if (row.is_col_null(m_col_name))
451 : 63 : return;
452 : : GDate date;
453 : 8 : g_date_clear (&date, 1);
454 : :
455 : 8 : auto strval{row.get_string_at_col(m_col_name)};
456 : 8 : if (strval)
457 : : {
458 : 8 : if (strval->empty())
459 : 0 : return;
460 : 8 : auto year = static_cast<GDateYear>(stoi (strval->substr (0,4)));
461 : 8 : auto month = static_cast<GDateMonth>(stoi (strval->substr (4,2)));
462 : 8 : auto day = static_cast<GDateDay>(stoi (strval->substr (6,2)));
463 : :
464 : 8 : if (year != 0 || month != 0 || day != (GDateDay)0)
465 : 8 : g_date_set_dmy(&date, day, month, year);
466 : : }
467 : : else
468 : : {
469 : 0 : auto timeval = row.get_time64_at_col(m_col_name);
470 : 0 : if (!timeval)
471 : 0 : return;
472 : : /* time64_to_gdate applies the tz, and gdates are saved
473 : : * as ymd, so we don't want that.
474 : : */
475 : 0 : auto time = *timeval;
476 : 0 : auto tm = gnc_gmtime(&time);
477 : 0 : g_date_set_dmy(&date, tm->tm_mday,
478 : 0 : static_cast<GDateMonth>(tm->tm_mon + 1),
479 : 0 : tm->tm_year + 1900);
480 : 0 : free(tm);
481 : : }
482 : :
483 : 8 : set_parameter(pObject, &date, get_setter(obj_name), m_gobj_param_name);
484 : 8 : }
485 : :
486 : : template<> void
487 : 25 : GncSqlColumnTableEntryImpl<CT_GDATE>::add_to_table(ColVec& vec) const noexcept
488 : : {
489 : 25 : GncSqlColumnInfo info{*this, BCT_DATE, DATE_COL_SIZE, FALSE};
490 : 25 : vec.emplace_back(std::move(info));
491 : 25 : }
492 : :
493 : : template<> void
494 : 78 : GncSqlColumnTableEntryImpl<CT_GDATE>::add_to_query(QofIdTypeConst obj_name,
495 : : const gpointer pObject,
496 : : PairVec& vec) const noexcept
497 : : {
498 : 78 : GDate *date = get_row_value_from_object<GDate*>(obj_name, pObject);
499 : :
500 : 78 : if (date && g_date_valid (date))
501 : : {
502 : 8 : std::ostringstream buf;
503 : 8 : buf << std::setfill ('0') << std::setw (4) << g_date_get_year (date) <<
504 : 8 : std::setw (2) << g_date_get_month (date) <<
505 : 8 : std::setw (2) << static_cast<int>(g_date_get_day (date));
506 : 8 : vec.emplace_back (std::make_pair (std::string{m_col_name},
507 : 16 : quote_string(buf.str())));
508 : 8 : return;
509 : 8 : }
510 : : }
511 : :
512 : : /* ----------------------------------------------------------------- */
513 : : typedef gnc_numeric (*NumericGetterFunc) (const gpointer);
514 : : typedef void (*NumericSetterFunc) (gpointer, gnc_numeric);
515 : :
516 : : static const EntryVec numeric_col_table =
517 : : {
518 : : gnc_sql_make_table_entry<CT_INT64>("num", 0, COL_NNUL, "guid"),
519 : : gnc_sql_make_table_entry<CT_INT64>("denom", 0, COL_NNUL, "guid")
520 : : };
521 : :
522 : : template <>
523 : 38 : void set_parameter<gpointer, gnc_numeric>(gpointer object,
524 : : gnc_numeric item,
525 : : const char* property)
526 : : {
527 : 38 : qof_instance_increase_editlevel(object);
528 : 38 : g_object_set(object, property, &item, nullptr);
529 : 38 : qof_instance_decrease_editlevel(object);
530 : 38 : };
531 : :
532 : : template<> void
533 : 106 : GncSqlColumnTableEntryImpl<CT_NUMERIC>::load (const GncSqlBackend* sql_be,
534 : : GncSqlRow& row,
535 : : QofIdTypeConst obj_name,
536 : : gpointer pObject) const noexcept
537 : : {
538 : :
539 : :
540 : 106 : g_return_if_fail (pObject != NULL);
541 : 106 : g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
542 : :
543 : 106 : auto buf = g_strdup_printf ("%s_num", m_col_name);
544 : 106 : auto num = row.get_int_at_col (buf);
545 : 106 : g_free (buf);
546 : 106 : buf = g_strdup_printf ("%s_denom", m_col_name);
547 : 106 : auto denom = row.get_int_at_col (buf);
548 : 106 : g_free (buf);
549 : :
550 : 106 : if (num && denom)
551 : : {
552 : 106 : auto n = gnc_numeric_create (*num, *denom);
553 : 106 : set_parameter(pObject, n,
554 : 106 : reinterpret_cast<NumericSetterFunc>(get_setter(obj_name)),
555 : 106 : m_gobj_param_name);
556 : : }
557 : : }
558 : :
559 : : template<> void
560 : 80 : GncSqlColumnTableEntryImpl<CT_NUMERIC>::add_to_table(ColVec& vec) const noexcept
561 : : {
562 : :
563 : 240 : for (auto const& subtable_row : numeric_col_table)
564 : : {
565 : 160 : gchar* buf = g_strdup_printf("%s_%s", m_col_name,
566 : 160 : subtable_row->m_col_name);
567 : : GncSqlColumnInfo info(buf, BCT_INT64, 0, false, false,
568 : 320 : m_flags & COL_PKEY, m_flags & COL_NNUL);
569 : 160 : g_free (buf);
570 : 160 : vec.emplace_back(std::move(info));
571 : 160 : }
572 : 80 : }
573 : :
574 : : template<> void
575 : 113 : GncSqlColumnTableEntryImpl<CT_NUMERIC>::add_to_query(QofIdTypeConst obj_name,
576 : : const gpointer pObject,
577 : : PairVec& vec) const noexcept
578 : : {
579 : : /* We can't use get_row_value_from_object for the same reason as time64. */
580 : : NumericGetterFunc getter;
581 : : gnc_numeric n;
582 : :
583 : 113 : g_return_if_fail (obj_name != NULL);
584 : 113 : g_return_if_fail (pObject != NULL);
585 : :
586 : 113 : if (m_gobj_param_name != nullptr)
587 : : {
588 : : gnc_numeric* s;
589 : 38 : g_object_get (pObject, m_gobj_param_name, &s, NULL);
590 : 38 : n = *s;
591 : : }
592 : : else
593 : : {
594 : 75 : getter = reinterpret_cast<NumericGetterFunc>(get_getter (obj_name));
595 : 75 : if (getter != NULL)
596 : : {
597 : 75 : n = (*getter) (pObject);
598 : : }
599 : : else
600 : : {
601 : 0 : n = gnc_numeric_zero ();
602 : : }
603 : : }
604 : :
605 : 113 : std::ostringstream buf;
606 : 113 : std::string num_col{m_col_name};
607 : 113 : std::string denom_col{m_col_name};
608 : 113 : num_col += "_num";
609 : 113 : denom_col += "_denom";
610 : 113 : buf << gnc_numeric_num (n);
611 : 113 : vec.emplace_back (std::make_pair (num_col, buf.str ()));
612 : 113 : buf.str ("");
613 : 113 : buf << gnc_numeric_denom (n);
614 : 113 : vec.emplace_back (denom_col, buf.str ());
615 : 113 : }
616 : :
617 : : static void
618 : 80 : _retrieve_guid_ (gpointer pObject, gpointer pValue)
619 : : {
620 : 80 : GncGUID* pGuid = (GncGUID*)pObject;
621 : 80 : GncGUID* guid = (GncGUID*)pValue;
622 : :
623 : 80 : g_return_if_fail (pObject != NULL);
624 : 80 : g_return_if_fail (pValue != NULL);
625 : :
626 : 80 : *pGuid = *guid;
627 : : }
628 : :
629 : : // Table to retrieve just the guid
630 : : static EntryVec guid_table
631 : : {
632 : : gnc_sql_make_table_entry<CT_GUID>("guid", 0, 0, nullptr, _retrieve_guid_)
633 : : };
634 : :
635 : : const GncGUID*
636 : 80 : gnc_sql_load_guid (const GncSqlBackend* sql_be, GncSqlRow& row)
637 : : {
638 : : static GncGUID guid;
639 : :
640 : 80 : g_return_val_if_fail (sql_be != NULL, NULL);
641 : :
642 : 80 : gnc_sql_load_object (sql_be, row, NULL, &guid, guid_table);
643 : :
644 : 80 : return &guid;
645 : : }
646 : :
647 : : void
648 : 275 : gnc_sql_load_object (const GncSqlBackend* sql_be, GncSqlRow& row,
649 : : QofIdTypeConst obj_name, gpointer pObject,
650 : : const EntryVec& table)
651 : : {
652 : 275 : g_return_if_fail (sql_be != NULL);
653 : 275 : g_return_if_fail (pObject != NULL);
654 : :
655 : 1912 : for (auto const& table_row : table)
656 : : {
657 : 1637 : table_row->load (sql_be, row, obj_name, pObject);
658 : : }
659 : : }
660 : :
661 : : uint_t
662 : 0 : gnc_sql_append_guids_to_sql (std::stringstream& sql,
663 : : const InstanceVec& instances)
664 : : {
665 : : char guid_buf[GUID_ENCODING_LENGTH + 1];
666 : :
667 : 0 : for (auto inst : instances)
668 : : {
669 : 0 : (void)guid_to_string_buff (qof_instance_get_guid (inst), guid_buf);
670 : :
671 : 0 : if (inst != *(instances.begin()))
672 : : {
673 : 0 : sql << ",";
674 : : }
675 : 0 : sql << "'" << guid_buf << "'";
676 : : }
677 : :
678 : 0 : return instances.size();
679 : : }
680 : :
681 : : /* This is necessary for 64-bit builds because g++ complains
682 : : * that reinterpret_casting a void* (64 bits) to an int (32 bits)
683 : : * loses precision, so we have to explicitly dispose of the precision.
684 : : * FIXME: We shouldn't be storing ints in ptrs in the first place.
685 : : */
686 : : #ifdef __LP64__
687 : : template <> int
688 : 364 : GncSqlColumnTableEntry::get_row_value_from_object<int>(QofIdTypeConst obj_name,
689 : : const void* pObject,
690 : : std::false_type) const
691 : : {
692 : 364 : g_return_val_if_fail(obj_name != nullptr && pObject != nullptr, 0);
693 : 364 : int result = 0;
694 : 364 : if (m_gobj_param_name != nullptr)
695 : 281 : g_object_get(const_cast<void*>(pObject), m_gobj_param_name, &result,
696 : : nullptr);
697 : : else
698 : : {
699 : 83 : QofAccessFunc getter = get_getter(obj_name);
700 : 83 : if (getter != nullptr)
701 : : {
702 : 83 : auto value = ((getter)(const_cast<void*>(pObject), nullptr));
703 : 83 : result = reinterpret_cast<uint64_t>(value) &
704 : : UINT64_C(0x00000000FFFFFFFF);
705 : : }
706 : : }
707 : 364 : return result;
708 : : }
709 : : #endif
|