GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-sql-column-table-entry.cpp
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
35static QofLogModule log_module = G_LOG_DOMAIN;
36
37/* ================================================================= */
38static gpointer
39get_autoinc_id (void* object, const QofParam* param)
40{
41 // Just need a 0 to force a new autoinc value
42 return (gpointer)0;
43}
44
45static void
46set_autoinc_id (void* object, void* item)
47{
48 // Nowhere to put the ID
49}
50
53{
54 QofAccessFunc getter;
55
56 g_return_val_if_fail (obj_name != NULL, NULL);
57
58 if (m_flags & COL_AUTOINC)
59 {
60 getter = get_autoinc_id;
61 }
62 else if (m_qof_param_name != NULL)
63 {
64 getter = qof_class_get_parameter_getter (obj_name, m_qof_param_name);
65 }
66 else
67 {
68 getter = m_getter;
69 }
70
71 return getter;
72}
73
76{
77 QofSetterFunc setter = nullptr;
78 if (m_flags & COL_AUTOINC)
79 {
80 setter = set_autoinc_id;
81 }
82 else if (m_qof_param_name != nullptr)
83 {
84 g_assert (obj_name != NULL);
85 setter = qof_class_get_parameter_setter (obj_name, m_qof_param_name);
86 }
87 else
88 {
89 setter = m_setter;
90 }
91 return setter;
92}
93
94void
96 const void* pObject,
97 PairVec& vec) const noexcept
98{
99 auto inst = get_row_value_from_object<QofInstance*>(obj_name, pObject);
100 if (inst == nullptr) return;
101 auto guid = qof_instance_get_guid (inst);
102 if (guid != nullptr) {
103 gchar *guid_s = guid_to_string(guid);
104 vec.emplace_back (std::make_pair (std::string{m_col_name}, quote_string(guid_s)));
105 g_free(guid_s);
106 }
107}
108
109void
111{
112 GncSqlColumnInfo info{*this, BCT_STRING, GUID_ENCODING_LENGTH, FALSE};
113 vec.emplace_back(std::move(info));
114}
115
116
117/* ----------------------------------------------------------------- */
118template<> void
120 GncSqlRow& row,
121 QofIdTypeConst obj_name,
122 gpointer pObject) const noexcept
123{
124 g_return_if_fail (pObject != NULL);
125 g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
126
127 auto s = row.get_string_at_col (m_col_name);
128 if (s)
129 set_parameter(pObject, s->c_str(), get_setter(obj_name), m_gobj_param_name);
130}
131
132template<> void
134{
135 GncSqlColumnInfo info{*this, BCT_STRING, m_size, TRUE};
136 vec.emplace_back(std::move(info));
137}
138
139/* char is unusual in that we get a pointer but don't deref it to pass
140 * it to operator<<().
141 */
142template<> void
144 const gpointer pObject,
145 PairVec& vec) const noexcept
146{
147 auto s = get_row_value_from_object<char*>(obj_name, pObject);
148
149 if (s != nullptr)
150 {
151 std::ostringstream stream;
152 stream << s;
153 vec.emplace_back (std::make_pair (std::string{m_col_name},
154 quote_string(stream.str())));
155 return;
156 }
157}
158
159/* ----------------------------------------------------------------- */
160typedef gint (*IntAccessFunc) (const gpointer);
161typedef void (*IntSetterFunc) (const gpointer, gint);
162
163template<> void
165 GncSqlRow& row,
166 QofIdTypeConst obj_name,
167 gpointer pObject) const noexcept
168{
169
170 g_return_if_fail (pObject != NULL);
171 g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
172
173 auto val = row.get_int_at_col(m_col_name);
174 if (val)
175 set_parameter(pObject, *val,
176 reinterpret_cast<IntSetterFunc>(get_setter(obj_name)),
177 m_gobj_param_name);
178}
179
180template<> void
182{
183 GncSqlColumnInfo info{*this, BCT_INT, 0, FALSE};
184 vec.emplace_back(std::move(info));
185}
186
187template<> void
189 const gpointer pObject,
190 PairVec& vec) const noexcept
191{
192 add_value_to_vec<int>(obj_name, pObject, vec);
193}
194
195/* ----------------------------------------------------------------- */
196typedef gboolean (*BooleanAccessFunc) (const gpointer);
197typedef void (*BooleanSetterFunc) (const gpointer, gboolean);
198
199template<> void
201 GncSqlRow& row,
202 QofIdTypeConst obj_name,
203 gpointer pObject)
204 const noexcept
205{
206 g_return_if_fail (pObject != NULL);
207 g_return_if_fail (m_gobj_param_name != NULL || get_setter(obj_name) != NULL);
208
209 auto val = row.get_int_at_col (m_col_name);
210 if (val)
211 set_parameter(pObject, static_cast<int>(*val),
212 reinterpret_cast<BooleanSetterFunc>(get_setter(obj_name)),
213 m_gobj_param_name);
214}
215
216template<> void
218{
219 GncSqlColumnInfo info{*this, BCT_INT, 0, FALSE};
220 vec.emplace_back(std::move(info));
221}
222
223template<> void
225 const gpointer pObject,
226 PairVec& vec) const noexcept
227{
228 add_value_to_vec<int>(obj_name, pObject, vec);
229}
230
231/* ----------------------------------------------------------------- */
232typedef gint64 (*Int64AccessFunc) (const gpointer);
233typedef void (*Int64SetterFunc) (const gpointer, gint64);
234
235template<> void
237 GncSqlRow& row,
238 QofIdTypeConst obj_name,
239 gpointer pObject)
240 const noexcept
241{
242 g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
243
244 auto val = row.get_int_at_col (m_col_name);
245 if (val)
246 set_parameter(pObject, *val,
247 reinterpret_cast<Int64SetterFunc>(get_setter(obj_name)),
248 m_gobj_param_name);
249}
250
251template<> void
253{
254
255 GncSqlColumnInfo info{*this, BCT_INT64, 0, FALSE};
256 vec.emplace_back(std::move(info));
257}
258
259template<> gint64
260GncSqlColumnTableEntry::get_row_value_from_object<int64_t>(QofIdTypeConst obj_name,
261 const void* pObject) const
262{
263 g_return_val_if_fail(obj_name != nullptr && pObject != nullptr,
264 INT64_C(0));
265 int64_t result = INT64_C(0);
266 if (m_gobj_param_name != nullptr)
267 g_object_get(const_cast<void*>(pObject), m_gobj_param_name,
268 &result, nullptr);
269 else
270 {
271 auto getter = (Int64AccessFunc)get_getter(obj_name);
272 if (getter != nullptr)
273 result = (getter)(const_cast<void*>(pObject));
274 }
275 return result;
276}
277
278template<> void
280 const gpointer pObject,
281 PairVec& vec) const noexcept
282{
283 add_value_to_vec<int64_t>(obj_name, pObject, vec);
284}
285/* ----------------------------------------------------------------- */
286
287template<> void
289 GncSqlRow& row,
290 QofIdTypeConst obj_name,
291 gpointer pObject)
292 const noexcept
293{
294 g_return_if_fail (pObject != NULL);
295 g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
296 double val{0.0};
297
298 if (auto int_val{row.get_int_at_col(m_col_name)})
299 val = static_cast<decltype(val)>(*int_val);
300 else if (auto float_val{row.get_float_at_col(m_col_name)})
301 val = static_cast<decltype(val)>(*float_val);
302 else if (auto double_val{row.get_double_at_col(m_col_name)})
303 val = *double_val;
304
305 set_parameter(pObject, val, get_setter(obj_name), m_gobj_param_name);
306}
307
308template<> void
310{
311 GncSqlColumnInfo info{*this, BCT_DOUBLE, 0, FALSE};
312 vec.emplace_back(std::move(info));
313}
314
315template<> void
317 const gpointer pObject,
318 PairVec& vec) const noexcept
319{
320 add_value_to_vec<double*>(obj_name, pObject, vec);
321}
322
323/* ----------------------------------------------------------------- */
324
325template<> void
327 GncSqlRow& row,
328 QofIdTypeConst obj_name,
329 gpointer pObject)
330 const noexcept
331{
332
333 GncGUID guid;
334
335 g_return_if_fail (pObject != NULL);
336 g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
337
338 auto strval{row.get_string_at_col(m_col_name)};
339 if (strval && string_to_guid (strval->c_str(), &guid))
340 set_parameter(pObject, &guid, get_setter(obj_name), m_gobj_param_name);
341}
342
343template<> void
345{
346 GncSqlColumnInfo info{*this, BCT_STRING, GUID_ENCODING_LENGTH, FALSE};
347 vec.emplace_back(std::move(info));
348}
349
350template<> void
352 const gpointer pObject,
353 PairVec& vec) const noexcept
354{
355 auto s = get_row_value_from_object<GncGUID*>(obj_name, pObject);
356
357 if (s != nullptr)
358 {
359 gchar *guid_s = guid_to_string(s);
360 vec.emplace_back (std::make_pair (std::string{m_col_name}, quote_string(guid_s)));
361 g_free(guid_s);
362 return;
363 }
364}
365/* ----------------------------------------------------------------- */
366typedef time64 (*Time64AccessFunc) (const gpointer);
367typedef void (*Time64SetterFunc) (const gpointer, time64);
368constexpr int TIME_COL_SIZE = 4 + 3 + 3 + 3 + 3 + 3;
369
370template<> void
372 GncSqlRow& row,
373 QofIdTypeConst obj_name,
374 gpointer pObject)
375 const noexcept
376{
377 time64 t{0};
378 g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
379 auto strval = row.get_string_at_col(m_col_name);
380 if (strval)
381 {
382 if (!strval->empty())
383 try
384 {
385 GncDateTime time(*strval);
386 t = static_cast<time64>(time);
387 }
388 catch (const std::invalid_argument& err)
389 {
390 PWARN("An invalid date %s was found in your database."
391 "It has been set to 1 January 1970.",
392 strval->c_str());
393 }
394 }
395 else
396 {
397 if (auto time64val = row.get_time64_at_col (m_col_name))
398 t = *time64val;
399 }
400
401 if (m_gobj_param_name != nullptr)
402 {
403 Time64 t64{t};
404 set_parameter(pObject, &t64, m_gobj_param_name);
405 }
406 else
407 {
408 set_parameter(pObject, t,
409 reinterpret_cast<Time64SetterFunc>(get_setter(obj_name)),
410 nullptr);
411 }
412}
413
414template<> void
416{
417
418 GncSqlColumnInfo info{*this, BCT_DATETIME, TIME_COL_SIZE, FALSE};
419 vec.emplace_back(std::move(info));
420}
421
422template<> void
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 if (m_gobj_param_name != nullptr)
433 {
434 Time64* t;
435 g_object_get (pObject, m_gobj_param_name, &t, nullptr);
436 t64 = t->t;
437 }
438 else
439 {
440 auto getter = (Time64AccessFunc)get_getter (obj_name);
441 g_return_if_fail(getter != nullptr);
442 t64 = (*getter)(pObject);
443 }
444 if (t64 > MINTIME && t64 < MAXTIME)
445 {
446 GncDateTime time(t64);
447 std::string timestr("'");
448 timestr += time.format_iso8601() + "'";
449 vec.emplace_back (std::make_pair (std::string{m_col_name}, timestr));
450 }
451 else
452 {
453 vec.emplace_back (std::make_pair (std::string{m_col_name},
454 "NULL"));
455 }
456}
457
458/* ----------------------------------------------------------------- */
459#define DATE_COL_SIZE 8
460
461template<> void
463 GncSqlRow& row,
464 QofIdTypeConst obj_name,
465 gpointer pObject) const noexcept
466{
467 g_return_if_fail (pObject != NULL);
468 g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
469 if (row.is_col_null(m_col_name))
470 return;
471 GDate date;
472 g_date_clear (&date, 1);
473
474 auto strval{row.get_string_at_col(m_col_name)};
475 if (strval)
476 {
477 if (strval->empty())
478 return;
479 auto year = static_cast<GDateYear>(stoi (strval->substr (0,4)));
480 auto month = static_cast<GDateMonth>(stoi (strval->substr (4,2)));
481 auto day = static_cast<GDateDay>(stoi (strval->substr (6,2)));
482
483 if (year != 0 || month != 0 || day != (GDateDay)0)
484 g_date_set_dmy(&date, day, month, year);
485 }
486 else
487 {
488 auto timeval = row.get_time64_at_col(m_col_name);
489 if (!timeval)
490 return;
491 /* time64_to_gdate applies the tz, and gdates are saved
492 * as ymd, so we don't want that.
493 */
494 auto time = *timeval;
495 auto tm = gnc_gmtime(&time);
496 g_date_set_dmy(&date, tm->tm_mday,
497 static_cast<GDateMonth>(tm->tm_mon + 1),
498 tm->tm_year + 1900);
499 free(tm);
500 }
501
502 set_parameter(pObject, &date, get_setter(obj_name), m_gobj_param_name);
503}
504
505template<> void
507{
508 GncSqlColumnInfo info{*this, BCT_DATE, DATE_COL_SIZE, FALSE};
509 vec.emplace_back(std::move(info));
510}
511
512template<> void
514 const gpointer pObject,
515 PairVec& vec) const noexcept
516{
517 GDate *date = get_row_value_from_object<GDate*>(obj_name, pObject);
518
519 if (date && g_date_valid (date))
520 {
521 std::ostringstream buf;
522 buf << std::setfill ('0') << std::setw (4) << g_date_get_year (date) <<
523 std::setw (2) << g_date_get_month (date) <<
524 std::setw (2) << static_cast<int>(g_date_get_day (date));
525 vec.emplace_back (std::make_pair (std::string{m_col_name},
526 quote_string(buf.str())));
527 return;
528 }
529}
530
531/* ----------------------------------------------------------------- */
532typedef gnc_numeric (*NumericGetterFunc) (const gpointer);
533typedef void (*NumericSetterFunc) (gpointer, gnc_numeric);
534
535static 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
541template <>
542void set_parameter<gpointer, gnc_numeric>(gpointer object,
543 gnc_numeric item,
544 const char* property)
545{
546 qof_instance_increase_editlevel(object);
547 g_object_set(object, property, &item, nullptr);
548 qof_instance_decrease_editlevel(object);
549};
550
551template<> void
553 GncSqlRow& row,
554 QofIdTypeConst obj_name,
555 gpointer pObject) const noexcept
556{
557
558
559 g_return_if_fail (pObject != NULL);
560 g_return_if_fail (m_gobj_param_name != nullptr || get_setter(obj_name) != nullptr);
561
562 auto buf = g_strdup_printf ("%s_num", m_col_name);
563 auto num = row.get_int_at_col (buf);
564 g_free (buf);
565 buf = g_strdup_printf ("%s_denom", m_col_name);
566 auto denom = row.get_int_at_col (buf);
567 g_free (buf);
568
569 if (num && denom)
570 {
571 auto n = gnc_numeric_create (*num, *denom);
572 set_parameter(pObject, n,
573 reinterpret_cast<NumericSetterFunc>(get_setter(obj_name)),
574 m_gobj_param_name);
575 }
576}
577
578template<> void
580{
581
582 for (auto const& subtable_row : numeric_col_table)
583 {
584 gchar* buf = g_strdup_printf("%s_%s", m_col_name,
585 subtable_row->m_col_name);
586 GncSqlColumnInfo info(buf, BCT_INT64, 0, false, false,
587 m_flags & COL_PKEY, m_flags & COL_NNUL);
588 g_free (buf);
589 vec.emplace_back(std::move(info));
590 }
591}
592
593template<> void
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 g_return_if_fail (obj_name != NULL);
603 g_return_if_fail (pObject != NULL);
604
605 if (m_gobj_param_name != nullptr)
606 {
607 gnc_numeric* s;
608 g_object_get (pObject, m_gobj_param_name, &s, NULL);
609 n = *s;
610 }
611 else
612 {
613 getter = reinterpret_cast<NumericGetterFunc>(get_getter (obj_name));
614 if (getter != NULL)
615 {
616 n = (*getter) (pObject);
617 }
618 else
619 {
620 n = gnc_numeric_zero ();
621 }
622 }
623
624 std::ostringstream buf;
625 std::string num_col{m_col_name};
626 std::string denom_col{m_col_name};
627 num_col += "_num";
628 denom_col += "_denom";
629 buf << gnc_numeric_num (n);
630 vec.emplace_back (std::make_pair (num_col, buf.str ()));
631 buf.str ("");
632 buf << gnc_numeric_denom (n);
633 vec.emplace_back (denom_col, buf.str ());
634}
635
636static void
637_retrieve_guid_ (gpointer pObject, gpointer pValue)
638{
639 GncGUID* pGuid = (GncGUID*)pObject;
640 GncGUID* guid = (GncGUID*)pValue;
641
642 g_return_if_fail (pObject != NULL);
643 g_return_if_fail (pValue != NULL);
644
645 *pGuid = *guid;
646}
647
648// Table to retrieve just the guid
649static EntryVec guid_table
650{
651 gnc_sql_make_table_entry<CT_GUID>("guid", 0, 0, nullptr, _retrieve_guid_)
652};
653
654const GncGUID*
655gnc_sql_load_guid (const GncSqlBackend* sql_be, GncSqlRow& row)
656{
657 static GncGUID guid;
658
659 g_return_val_if_fail (sql_be != NULL, NULL);
660
661 gnc_sql_load_object (sql_be, row, NULL, &guid, guid_table);
662
663 return &guid;
664}
665
666void
667gnc_sql_load_object (const GncSqlBackend* sql_be, GncSqlRow& row,
668 QofIdTypeConst obj_name, gpointer pObject,
669 const EntryVec& table)
670{
671 g_return_if_fail (sql_be != NULL);
672 g_return_if_fail (pObject != NULL);
673
674 for (auto const& table_row : table)
675 {
676 table_row->load (sql_be, row, obj_name, pObject);
677 }
678}
679
680uint_t
681gnc_sql_append_guids_to_sql (std::stringstream& sql,
682 const InstanceVec& instances)
683{
684 char guid_buf[GUID_ENCODING_LENGTH + 1];
685
686 for (auto inst : instances)
687 {
688 (void)guid_to_string_buff (qof_instance_get_guid (inst), guid_buf);
689
690 if (inst != *(instances.begin()))
691 {
692 sql << ",";
693 }
694 sql << "'" << guid_buf << "'";
695 }
696
697 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__
706template <> int
707GncSqlColumnTableEntry::get_row_value_from_object<int>(QofIdTypeConst obj_name,
708 const void* pObject,
709 std::false_type) const
710{
711 g_return_val_if_fail(obj_name != nullptr && pObject != nullptr, 0);
712 int result = 0;
713 if (m_gobj_param_name != nullptr)
714 g_object_get(const_cast<void*>(pObject), m_gobj_param_name, &result,
715 nullptr);
716 else
717 {
718 QofAccessFunc getter = get_getter(obj_name);
719 if (getter != nullptr)
720 {
721 auto value = ((getter)(const_cast<void*>(pObject), nullptr));
722 result = reinterpret_cast<uint64_t>(value) &
723 UINT64_C(0x00000000FFFFFFFF);
724 }
725 }
726 return result;
727}
728#endif
GnuCash DateTime class.
Main SQL backend structure.
void add_to_query(QofIdTypeConst obj_name, void *pObject, PairVec &vec) const noexcept override
Add a pair of the table column heading and object's value's string representation to a PairVec; used ...
void add_to_table(ColVec &vec) const noexcept override
Add a GncSqlColumnInfo structure for the column type to a ColVec.
void load(const GncSqlBackend *sql_be, GncSqlRow &row, QofIdTypeConst obj_name, void *pObject) const noexcept override
Load a value into an object from the database row.
QofSetterFunc get_setter(QofIdTypeConst obj_name) const noexcept
Retrieve the setter function depending on whether it's an auto-increment field, a QofClass getter,...
void add_objectref_guid_to_query(QofIdTypeConst obj_name, const void *pObject, PairVec &vec) const noexcept
Adds a name/guid std::pair to a PairVec for creating a query.
void add_objectref_guid_to_table(ColVec &vec) const noexcept
Adds a column info structure for an object reference GncGUID to a ColVec.
QofAccessFunc get_getter(QofIdTypeConst obj_name) const noexcept
Retrieve the getter function depending on whether it's an auto-increment field, a QofClass getter,...
Row of SQL Query results.
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Definition qofclass.h:123
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
Definition qofclass.h:130
QofSetterFunc qof_class_get_parameter_setter(QofIdTypeConst obj_name, const char *parameter)
Return the object's parameter setter function.
Definition qofclass.cpp:172
QofAccessFunc qof_class_get_parameter_getter(QofIdTypeConst obj_name, const char *parameter)
Return the object's parameter getter function.
Definition qofclass.cpp:156
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
struct tm * gnc_gmtime(const time64 *secs)
fill out a time struct from a 64-bit time value
Definition gnc-date.cpp:178
const gchar * QofIdTypeConst
QofIdTypeConst declaration.
Definition qofid.h:82
gchar * guid_to_string(const GncGUID *guid)
The guid_to_string() routine returns a null-terminated string encoding of the id.
Definition guid.cpp:199
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
Definition guid.h:84
gchar * guid_to_string_buff(const GncGUID *guid, gchar *str)
The guid_to_string_buff() routine puts a null-terminated string encoding of the id into the memory po...
Definition guid.cpp:208
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
The type used to store guids in C.
Definition guid.h:75
information required to create a column in a table.