37 #include "splint-defs.h" 43 #include "gnc-sql-connection.hpp" 44 #include "gnc-sql-backend.hpp" 45 #include "gnc-sql-object-backend.hpp" 46 #include "gnc-sql-column-table-entry.hpp" 49 #include <kvp-frame.hpp> 53 #define TABLE_NAME "slots" 54 #define TABLE_VERSION 4 69 KvpValue::Type value_type;
74 std::string parent_path;
78 static gpointer get_obj_guid (gpointer pObject);
79 static void set_obj_guid (
void);
80 static gpointer get_path (gpointer pObject);
81 static void set_path (gpointer pObject, gpointer pValue);
82 static KvpValue::Type get_slot_type (gpointer pObject);
83 static void set_slot_type (gpointer pObject, gpointer pValue);
84 static gint64 get_int64_val (gpointer pObject);
85 static void set_int64_val (gpointer pObject, gint64 pValue);
86 static gpointer get_string_val (gpointer pObject);
87 static void set_string_val (gpointer pObject, gpointer pValue);
88 static gpointer get_double_val (gpointer pObject);
89 static void set_double_val (gpointer pObject, gpointer pValue);
90 static time64 get_time_val (gpointer pObject);
91 static void set_time_val (gpointer pObject,
time64 t);
92 static gpointer get_guid_val (gpointer pObject);
93 static void set_guid_val (gpointer pObject, gpointer pValue);
94 static gnc_numeric get_numeric_val (gpointer pObject);
95 static void set_numeric_val (gpointer pObject, gnc_numeric value);
96 static GDate* get_gdate_val (gpointer pObject);
97 static void set_gdate_val (gpointer pObject, GDate* value);
101 #define SLOT_MAX_PATHNAME_LEN 4096 102 #define SLOT_MAX_STRINGVAL_LEN 4096 118 static const EntryVec col_table
121 gnc_sql_make_table_entry<CT_INT>(
122 "id", 0, COL_PKEY | COL_NNUL | COL_AUTOINC),
123 gnc_sql_make_table_entry<CT_GUID>(
"obj_guid", 0, COL_NNUL,
126 gnc_sql_make_table_entry<CT_STRING>(
"name", SLOT_MAX_PATHNAME_LEN, COL_NNUL,
128 gnc_sql_make_table_entry<CT_INT>(
"slot_type", 0, COL_NNUL,
131 gnc_sql_make_table_entry<CT_INT64>(
"int64_val", 0, 0,
134 gnc_sql_make_table_entry<CT_STRING>(
"string_val", SLOT_MAX_PATHNAME_LEN, 0,
137 gnc_sql_make_table_entry<CT_DOUBLE>(
"double_val", 0, 0,
140 gnc_sql_make_table_entry<CT_TIME>(
"timespec_val", 0, 0,
143 gnc_sql_make_table_entry<CT_GUID>(
"guid_val", 0, 0,
146 gnc_sql_make_table_entry<CT_NUMERIC>(
"numeric_val", 0, 0,
149 gnc_sql_make_table_entry<CT_GDATE>(
"gdate_val", 0, 0,
155 _retrieve_guid_ (gpointer pObject, gpointer pValue)
160 g_return_if_fail (pObject != NULL);
161 g_return_if_fail (pValue != NULL);
168 static const EntryVec obj_guid_col_table
170 gnc_sql_make_table_entry<CT_GUID>(
"obj_guid", 0, 0,
175 static const EntryVec gdate_col_table
177 gnc_sql_make_table_entry<CT_GDATE>(
"gdate_val", 0, 0),
180 GncSqlSlotsBackend::GncSqlSlotsBackend() :
182 TABLE_NAME, col_table) {}
189 if (!pInfo)
return "";
191 auto path = pInfo->path;
192 path.erase (0, pInfo->parent_path.size());
197 set_slot_from_value (
slot_info_t* pInfo, KvpValue* pValue)
199 g_return_if_fail (pInfo != NULL);
200 g_return_if_fail (pValue != NULL);
202 switch (pInfo->context)
206 auto key = get_key (pInfo);
207 pInfo->pKvpFrame->set ({key}, pValue);
212 pInfo->pList = g_list_append (pInfo->pList, pValue);
218 auto key = get_key (pInfo);
219 auto path = pInfo->parent_path;
220 auto frame = pInfo->pKvpFrame;
223 frame->set_path ({path, key}, pValue);
226 frame->set ({key}, pValue);
233 get_obj_guid (gpointer pObject)
237 g_return_val_if_fail (pObject != NULL, NULL);
239 return (gpointer)pInfo->guid;
249 get_path (gpointer pObject)
253 g_return_val_if_fail (pObject != NULL, NULL);
255 return (gpointer)pInfo->path.c_str();
259 set_path (gpointer pObject, gpointer pValue)
262 pInfo->path =
static_cast<char*
>(pValue);
263 if (pInfo->path.find (pInfo->parent_path) != 0)
264 pInfo->parent_path.clear();
267 static KvpValue::Type
268 get_slot_type (gpointer pObject)
272 g_return_val_if_fail (pObject != NULL, KvpValue::Type::INVALID);
275 return pInfo->value_type;
279 set_slot_type (gpointer pObject, gpointer pValue)
283 g_return_if_fail (pObject != NULL);
284 g_return_if_fail (pValue != NULL);
286 pInfo->value_type =
static_cast<KvpValue::Type
> (GPOINTER_TO_INT (pValue));
290 get_int64_val (gpointer pObject)
294 g_return_val_if_fail (pObject != NULL, 0);
296 if (pInfo->pKvpValue->get_type () == KvpValue::Type::INT64)
298 return pInfo->pKvpValue->get<int64_t> ();
307 set_int64_val (gpointer pObject, gint64 value)
310 KvpValue* pValue = NULL;
312 g_return_if_fail (pObject != NULL);
314 if (pInfo->value_type != KvpValue::Type::INT64)
return;
315 pValue =
new KvpValue {value};
316 set_slot_from_value (pInfo, pValue);
320 get_string_val (gpointer pObject)
324 g_return_val_if_fail (pObject != NULL, NULL);
326 if (pInfo->pKvpValue->get_type () == KvpValue::Type::STRING)
328 return (gpointer)pInfo->pKvpValue->get<
const char*> ();
337 set_string_val (gpointer pObject, gpointer pValue)
340 g_return_if_fail (pObject != NULL);
342 if (pInfo->value_type != KvpValue::Type::STRING || pValue == NULL)
344 auto value =
new KvpValue {g_strdup(static_cast<const char*> (pValue))};
345 set_slot_from_value (pInfo, value);
349 get_double_val (gpointer pObject)
352 g_return_val_if_fail (pObject != NULL, NULL);
354 if (pInfo->pKvpValue->get_type () == KvpValue::Type::DOUBLE)
356 d_val = pInfo->pKvpValue->get<
double> ();
357 return (gpointer)&d_val;
366 set_double_val (gpointer pObject, gpointer pValue)
369 KvpValue* value = NULL;
371 g_return_if_fail (pObject != NULL);
373 if (pInfo->value_type != KvpValue::Type::DOUBLE || pValue == NULL)
return;
374 value =
new KvpValue {* (
static_cast<double*
> (pValue))};
375 set_slot_from_value (pInfo, value);
379 get_time_val (gpointer pObject)
383 g_return_val_if_fail (pObject != NULL, 0);
386 auto t = pInfo->pKvpValue->get<
Time64> ();
391 set_time_val (gpointer pObject,
time64 time)
394 KvpValue* value = NULL;
396 g_return_if_fail (pObject != NULL);
398 if (pInfo->value_type != KvpValue::Type::TIME64)
return;
399 value =
new KvpValue {t};
400 set_slot_from_value (pInfo, value);
404 get_guid_val (gpointer pObject)
408 g_return_val_if_fail (pObject != NULL, NULL);
410 if (pInfo->pKvpValue->get_type () == KvpValue::Type::GUID)
412 return (gpointer)pInfo->pKvpValue->get<
GncGUID*> ();
421 set_guid_val (gpointer pObject, gpointer pValue)
425 g_return_if_fail (pObject != NULL);
426 if (pValue == NULL)
return;
428 switch (pInfo->value_type)
430 case KvpValue::Type::GUID:
432 auto new_guid =
guid_copy (static_cast<GncGUID*> (pValue));
433 set_slot_from_value (pInfo,
new KvpValue {new_guid});
436 case KvpValue::Type::GLIST:
439 KvpValue* pValue = NULL;
440 auto key = get_key (pInfo);
442 newInfo->context = LIST;
444 slots_load_info (newInfo);
445 pValue =
new KvpValue {newInfo->pList};
446 pInfo->pKvpFrame->set ({key.c_str()}, pValue);
450 case KvpValue::Type::FRAME:
453 auto newFrame =
new KvpFrame;
454 newInfo->pKvpFrame = newFrame;
456 switch (pInfo->context)
460 auto value =
new KvpValue {newFrame};
461 newInfo->path = get_key (pInfo);
462 pInfo->pList = g_list_append (pInfo->pList, value);
468 auto key = get_key (pInfo);
469 pInfo->pKvpFrame->set ({key.c_str()},
new KvpValue {newFrame});
474 newInfo->context = FRAME;
475 slots_load_info (newInfo);
485 get_numeric_val (gpointer pObject)
489 g_return_val_if_fail (pObject != NULL, gnc_numeric_zero ());
491 if (pInfo->pKvpValue->get_type () == KvpValue::Type::NUMERIC)
493 return pInfo->pKvpValue->get<gnc_numeric> ();
497 return gnc_numeric_zero ();
502 set_numeric_val (gpointer pObject, gnc_numeric value)
506 g_return_if_fail (pObject != NULL);
508 if (pInfo->value_type != KvpValue::Type::NUMERIC)
return;
509 set_slot_from_value (pInfo,
new KvpValue {value});
513 get_gdate_val (gpointer pObject)
518 g_return_val_if_fail (pObject != NULL, NULL);
520 if (pInfo->pKvpValue->get_type () == KvpValue::Type::GDATE)
522 date = pInfo->pKvpValue->get<GDate> ();
532 set_gdate_val (gpointer pObject, GDate* value)
536 g_return_if_fail (pObject != NULL);
538 if (pInfo->value_type != KvpValue::Type::GDATE)
return;
539 set_slot_from_value (pInfo,
new KvpValue {*value});
545 g_return_val_if_fail (pInfo != NULL, NULL);
548 newSlot->be = pInfo->be;
549 newSlot->guid = guid == NULL ? pInfo->guid : guid;
550 newSlot->is_ok = pInfo->is_ok;
551 newSlot->pKvpFrame = pInfo->pKvpFrame;
552 newSlot->value_type = pInfo->value_type;
553 newSlot->pList = pInfo->pList;
554 newSlot->context = pInfo->context;
555 newSlot->pKvpValue = pInfo->pKvpValue;
556 if (!pInfo->path.empty())
557 newSlot->parent_path = pInfo->path +
"/";
559 newSlot->parent_path = pInfo->parent_path;
564 save_slot (
const char* key, KvpValue* value,
slot_info_t & slot_info)
566 g_return_if_fail (value != NULL);
569 if (!slot_info.is_ok)
573 slot_info.pKvpValue = value;
574 slot_info.path = slot_info.parent_path + key;
575 slot_info.value_type = value->get_type ();
577 switch (slot_info.value_type)
579 case KvpValue::Type::FRAME:
581 auto pKvpFrame = value->get<KvpFrame*> ();
583 slot_info_t* pNewInfo = slot_info_copy (&slot_info, guid);
584 KvpValue* oldValue = slot_info.pKvpValue;
585 slot_info.pKvpValue =
new KvpValue {guid};
591 g_return_if_fail (slot_info.is_ok);
592 pKvpFrame->for_each_slot_temp (save_slot, *pNewInfo);
593 delete slot_info.pKvpValue;
594 slot_info.pKvpValue = oldValue;
598 case KvpValue::Type::GLIST:
601 slot_info_t* pNewInfo = slot_info_copy (&slot_info, guid);
602 KvpValue* oldValue = slot_info.pKvpValue;
603 slot_info.pKvpValue =
new KvpValue {guid};
609 g_return_if_fail (slot_info.is_ok);
610 for (
auto cursor = value->get<GList*> (); cursor; cursor = cursor->next)
612 auto val =
static_cast<KvpValue*
> (cursor->data);
613 save_slot (
"", val, *pNewInfo);
615 delete slot_info.pKvpValue;
616 slot_info.pKvpValue = oldValue;
636 slot_info_t slot_info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID,
637 NULL, FRAME, NULL,
"" };
638 KvpFrame* pFrame = qof_instance_get_slots (inst);
640 g_return_val_if_fail (sql_be != NULL, FALSE);
641 g_return_val_if_fail (guid != NULL, FALSE);
642 g_return_val_if_fail (pFrame != NULL, FALSE);
645 if (!sql_be->pristine() && !is_infant)
650 slot_info.be = sql_be;
651 slot_info.guid = guid;
652 pFrame->for_each_slot_temp (save_slot, slot_info);
654 return slot_info.is_ok;
662 slot_info_t slot_info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID,
663 NULL, FRAME, NULL,
"" };
665 g_return_val_if_fail (sql_be != NULL, FALSE);
666 g_return_val_if_fail (guid != NULL, FALSE);
670 buf = g_strdup_printf (
"SELECT * FROM %s WHERE obj_guid='%s' and slot_type in ('%d', '%d') and not guid_val is null",
671 TABLE_NAME, guid_buf, KvpValue::Type::FRAME, KvpValue::Type::GLIST);
672 auto stmt = sql_be->create_statement_from_sql(buf);
677 for (
auto row : *result)
679 const GncSqlColumnTableEntryPtr table_row =
680 col_table[guid_val_col];
682 auto val = row.get_string_at_col (table_row->name());
688 slot_info.be = sql_be;
689 slot_info.guid = guid;
690 slot_info.is_ok = TRUE;
692 TABLE_NAME, &slot_info,
695 return slot_info.is_ok;
703 g_return_if_fail (pInfo != NULL);
704 g_return_if_fail (pInfo->be != NULL);
705 g_return_if_fail (pInfo->pKvpFrame != NULL);
707 slot_info = slot_info_copy (pInfo, NULL);
709 gnc_sql_load_object (pInfo->be, row, TABLE_NAME, slot_info, col_table);
711 if (slot_info->pList != pInfo->pList)
713 if (pInfo->pList != NULL)
715 PWARN (
"Load slot returned a different list than the original");
719 pInfo->pList = slot_info->pList;
728 slot_info_t info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID,
729 NULL, FRAME, NULL,
"" };
730 g_return_if_fail (sql_be != NULL);
731 g_return_if_fail (inst != NULL);
735 info.pKvpFrame = qof_instance_get_slots (inst);
738 slots_load_info (&info);
744 g_return_if_fail (pInfo != NULL);
745 g_return_if_fail (pInfo->be != NULL);
746 g_return_if_fail (pInfo->guid != NULL);
747 g_return_if_fail (pInfo->pKvpFrame != NULL);
750 std::string sql(
"SELECT * FROM " TABLE_NAME
" WHERE obj_guid='");
751 sql += guid.to_string() +
"'";
752 auto stmt = pInfo->be->create_statement_from_sql(sql);
756 for (
auto row : *result)
757 load_slot (pInfo, row);
767 g_return_val_if_fail (sql_be != NULL, NULL);
769 gnc_sql_load_object (sql_be, row, NULL, &guid, obj_guid_col_table);
776 BookLookupFn lookup_fn)
778 slot_info_t slot_info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID,
779 NULL, FRAME, NULL,
"" };
783 g_return_if_fail (sql_be != NULL);
784 g_return_if_fail (lookup_fn != NULL);
786 guid = load_obj_guid (sql_be, row);
787 g_return_if_fail (guid != NULL);
788 inst = lookup_fn (guid, sql_be->book());
789 if (inst == NULL)
return;
791 slot_info.be = sql_be;
792 slot_info.pKvpFrame = qof_instance_get_slots (inst);
793 slot_info.path.clear();
795 gnc_sql_load_object (sql_be, row, TABLE_NAME, &slot_info, col_table);
808 const std::string subquery,
809 BookLookupFn lookup_fn)
811 g_return_if_fail (sql_be != NULL);
814 if (subquery.empty())
return;
816 std::string pkey(obj_guid_col_table[0]->name());
817 std::string sql(
"SELECT * FROM " TABLE_NAME
" WHERE ");
818 sql += pkey +
" IN (" + subquery +
")";
821 auto stmt = sql_be->create_statement_from_sql(sql);
824 PERR (
"stmt == NULL, SQL = '%s'\n", sql.c_str());
828 for (
auto row : *result)
829 load_slot_for_book_object (sql_be, row, lookup_fn);
840 g_return_if_fail (sql_be != NULL);
845 (void)sql_be->
create_table(TABLE_NAME, TABLE_VERSION, col_table);
847 ok = sql_be->
create_index (
"slots_guid_index", TABLE_NAME,
851 PERR (
"Unable to create index\n");
854 else if (version < m_version)
864 ok = sql_be->
create_index (
"slots_guid_index", TABLE_NAME,
868 PERR (
"Unable to create index\n");
871 else if (version == 2)
876 PERR (
"Unable to add gdate column\n");
884 PINFO (
"Slots table upgraded from version %d to version %d\n", version,
bool do_db_operation(E_DB_OPERATION op, const char *table_name, QofIdTypeConst obj_name, gpointer pObject, const EntryVec &table) const noexcept
Performs an operation on the database.
bool add_columns_to_table(const std::string &table_name, const EntryVec &col_table) const noexcept
Adds one or more columns to an existing table.
bool create_table(const std::string &table_name, const EntryVec &col_table) const noexcept
Creates a table in the database.
bool set_table_version(const std::string &table_name, uint_t version) noexcept
Registers the version for a table.
GncSqlResultPtr execute_select_statement(const GncSqlStatementPtr &stmt) const noexcept
Executes an SQL SELECT statement and returns the result rows.
const GncGUID * qof_instance_get_guid(gconstpointer inst)
Return the GncGUID of this instance.
void gnc_sql_slots_load_for_sql_subquery(GncSqlBackend *sql_be, const std::string subquery, BookLookupFn lookup_fn)
gnc_sql_slots_load_for_sql_subquery - Loads slots for all objects whose guid is supplied by a subquer...
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
#define PINFO(format, args...)
Print an informational note.
load and save accounts data to SQL
GncGUID * guid_copy(const GncGUID *guid)
Returns a newly allocated GncGUID that matches the passed-in GUID.
gboolean string_to_guid(const gchar *string, GncGUID *guid)
Given a string, replace the given guid with the parsed one unless the given value is null...
GncGUID * guid_new(void)
Allocate and construct a new GUID.
gboolean gnc_sql_slots_save(GncSqlBackend *sql_be, const GncGUID *guid, gboolean is_infant, QofInstance *inst)
gnc_sql_slots_save - Saves slots for an object to the db.
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...
#define PERR(format, args...)
Log a serious error.
void(* QofSetterFunc)(gpointer, gpointer)
The QofSetterFunc defines an function pointer for parameter setters.
#define PWARN(format, args...)
Log a warning.
void create_tables(GncSqlBackend *) override
Conditionally create or update a database table from m_col_table.
Row of SQL Query results.
void upgrade_table(const std::string &table_name, const EntryVec &col_table) noexcept
Upgrades a table to a new structure.
#define GUID_ENCODING_LENGTH
Number of characters needed to encode a guid as a string not including the null terminator.
gpointer(* QofAccessFunc)(gpointer object, const QofParam *param)
The QofAccessFunc defines an arbitrary function pointer for access functions.
Encapsulates per-class table schema with functions to load, create a table, commit a changed front-en...
All type declarations for the whole Gnucash engine.
bool create_index(const std::string &index_name, const std::string &table_name, const EntryVec &col_table) const noexcept
Creates an index in the database.
gboolean gnc_sql_slots_delete(GncSqlBackend *sql_be, const GncGUID *guid)
gnc_sql_slots_delete - Deletes slots for an object from the db.
void gnc_sql_slots_load(GncSqlBackend *sql_be, QofInstance *inst)
Loads slots for an object from the db.
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
The type used to store guids in C.
uint_t get_table_version(const std::string &table_name) const noexcept
Returns the version number for a DB table.
Main SQL backend structure.