37 #include "splint-defs.h" 44 #include "gnc-sql-connection.hpp" 45 #include "gnc-sql-backend.hpp" 46 #include "gnc-sql-object-backend.hpp" 47 #include "gnc-sql-column-table-entry.hpp" 50 #include <kvp-frame.hpp> 54 #define TABLE_NAME "slots" 55 #define TABLE_VERSION 4 70 KvpValue::Type value_type;
75 std::string parent_path;
79 static gpointer get_obj_guid (gpointer pObject);
80 static void set_obj_guid (
void);
81 static gpointer get_path (gpointer pObject);
82 static void set_path (gpointer pObject, gpointer pValue);
83 static KvpValue::Type get_slot_type (gpointer pObject);
84 static void set_slot_type (gpointer pObject, gpointer pValue);
85 static gint64 get_int64_val (gpointer pObject);
86 static void set_int64_val (gpointer pObject, gint64 pValue);
87 static gpointer get_string_val (gpointer pObject);
88 static void set_string_val (gpointer pObject, gpointer pValue);
89 static gpointer get_double_val (gpointer pObject);
90 static void set_double_val (gpointer pObject, gpointer pValue);
91 static time64 get_time_val (gpointer pObject);
92 static void set_time_val (gpointer pObject,
time64 t);
93 static gpointer get_guid_val (gpointer pObject);
94 static void set_guid_val (gpointer pObject, gpointer pValue);
95 static gnc_numeric get_numeric_val (gpointer pObject);
96 static void set_numeric_val (gpointer pObject, gnc_numeric value);
97 static GDate* get_gdate_val (gpointer pObject);
98 static void set_gdate_val (gpointer pObject, GDate* value);
102 #define SLOT_MAX_PATHNAME_LEN 4096 103 #define SLOT_MAX_STRINGVAL_LEN 4096 119 static const EntryVec col_table
122 gnc_sql_make_table_entry<CT_INT>(
123 "id", 0, COL_PKEY | COL_NNUL | COL_AUTOINC),
124 gnc_sql_make_table_entry<CT_GUID>(
"obj_guid", 0, COL_NNUL,
127 gnc_sql_make_table_entry<CT_STRING>(
"name", SLOT_MAX_PATHNAME_LEN, COL_NNUL,
129 gnc_sql_make_table_entry<CT_INT>(
"slot_type", 0, COL_NNUL,
132 gnc_sql_make_table_entry<CT_INT64>(
"int64_val", 0, 0,
135 gnc_sql_make_table_entry<CT_STRING>(
"string_val", SLOT_MAX_PATHNAME_LEN, 0,
138 gnc_sql_make_table_entry<CT_DOUBLE>(
"double_val", 0, 0,
141 gnc_sql_make_table_entry<CT_TIME>(
"timespec_val", 0, 0,
144 gnc_sql_make_table_entry<CT_GUID>(
"guid_val", 0, 0,
147 gnc_sql_make_table_entry<CT_NUMERIC>(
"numeric_val", 0, 0,
150 gnc_sql_make_table_entry<CT_GDATE>(
"gdate_val", 0, 0,
156 _retrieve_guid_ (gpointer pObject, gpointer pValue)
161 g_return_if_fail (pObject != NULL);
162 g_return_if_fail (pValue != NULL);
169 static const EntryVec obj_guid_col_table
171 gnc_sql_make_table_entry<CT_GUID>(
"obj_guid", 0, 0,
176 static const EntryVec gdate_col_table
178 gnc_sql_make_table_entry<CT_GDATE>(
"gdate_val", 0, 0),
181 GncSqlSlotsBackend::GncSqlSlotsBackend() :
183 TABLE_NAME, col_table) {}
190 if (!pInfo)
return "";
192 auto path = pInfo->path;
193 path.erase (0, pInfo->parent_path.size());
198 set_slot_from_value (
slot_info_t* pInfo, KvpValue* pValue)
200 g_return_if_fail (pInfo != NULL);
201 g_return_if_fail (pValue != NULL);
203 switch (pInfo->context)
207 auto key = get_key (pInfo);
208 pInfo->pKvpFrame->set ({key}, pValue);
213 pInfo->pList = g_list_append (pInfo->pList, pValue);
219 auto key = get_key (pInfo);
220 auto path = pInfo->parent_path;
221 auto frame = pInfo->pKvpFrame;
224 frame->set_path ({path, key}, pValue);
227 frame->set ({key}, pValue);
234 get_obj_guid (gpointer pObject)
238 g_return_val_if_fail (pObject != NULL, NULL);
240 return (gpointer)pInfo->guid;
250 get_path (gpointer pObject)
254 g_return_val_if_fail (pObject != NULL, NULL);
256 return (gpointer)pInfo->path.c_str();
260 set_path (gpointer pObject, gpointer pValue)
263 pInfo->path =
static_cast<char*
>(pValue);
264 if (pInfo->path.find (pInfo->parent_path) != 0)
265 pInfo->parent_path.clear();
268 static KvpValue::Type
269 get_slot_type (gpointer pObject)
273 g_return_val_if_fail (pObject != NULL, KvpValue::Type::INVALID);
276 return pInfo->value_type;
280 set_slot_type (gpointer pObject, gpointer pValue)
284 g_return_if_fail (pObject != NULL);
285 g_return_if_fail (pValue != NULL);
287 pInfo->value_type =
static_cast<KvpValue::Type
> (GPOINTER_TO_INT (pValue));
291 get_int64_val (gpointer pObject)
295 g_return_val_if_fail (pObject != NULL, 0);
297 if (pInfo->pKvpValue->get_type () == KvpValue::Type::INT64)
299 return pInfo->pKvpValue->get<int64_t> ();
308 set_int64_val (gpointer pObject, gint64 value)
311 KvpValue* pValue = NULL;
313 g_return_if_fail (pObject != NULL);
315 if (pInfo->value_type != KvpValue::Type::INT64)
return;
316 pValue =
new KvpValue {value};
317 set_slot_from_value (pInfo, pValue);
321 get_string_val (gpointer pObject)
325 g_return_val_if_fail (pObject != NULL, NULL);
327 if (pInfo->pKvpValue->get_type () == KvpValue::Type::STRING)
329 return (gpointer)pInfo->pKvpValue->get<
const char*> ();
338 set_string_val (gpointer pObject, gpointer pValue)
341 g_return_if_fail (pObject != NULL);
343 if (pInfo->value_type != KvpValue::Type::STRING || pValue == NULL)
345 auto value =
new KvpValue {g_strdup(static_cast<const char*> (pValue))};
346 set_slot_from_value (pInfo, value);
350 get_double_val (gpointer pObject)
353 g_return_val_if_fail (pObject != NULL, NULL);
355 if (pInfo->pKvpValue->get_type () == KvpValue::Type::DOUBLE)
357 d_val = pInfo->pKvpValue->get<
double> ();
358 return (gpointer)&d_val;
367 set_double_val (gpointer pObject, gpointer pValue)
370 KvpValue* value = NULL;
372 g_return_if_fail (pObject != NULL);
374 if (pInfo->value_type != KvpValue::Type::DOUBLE || pValue == NULL)
return;
375 value =
new KvpValue {* (
static_cast<double*
> (pValue))};
376 set_slot_from_value (pInfo, value);
380 get_time_val (gpointer pObject)
384 g_return_val_if_fail (pObject != NULL, 0);
387 auto t = pInfo->pKvpValue->get<
Time64> ();
392 set_time_val (gpointer pObject,
time64 time)
395 KvpValue* value = NULL;
397 g_return_if_fail (pObject != NULL);
399 if (pInfo->value_type != KvpValue::Type::TIME64)
return;
400 value =
new KvpValue {t};
401 set_slot_from_value (pInfo, value);
405 get_guid_val (gpointer pObject)
409 g_return_val_if_fail (pObject != NULL, NULL);
411 if (pInfo->pKvpValue->get_type () == KvpValue::Type::GUID)
413 return (gpointer)pInfo->pKvpValue->get<
GncGUID*> ();
422 set_guid_val (gpointer pObject, gpointer pValue)
426 g_return_if_fail (pObject != NULL);
427 if (pValue == NULL)
return;
429 switch (pInfo->value_type)
431 case KvpValue::Type::GUID:
433 auto new_guid =
guid_copy (static_cast<GncGUID*> (pValue));
434 set_slot_from_value (pInfo,
new KvpValue {new_guid});
437 case KvpValue::Type::GLIST:
440 KvpValue* pValue = NULL;
441 auto key = get_key (pInfo);
443 newInfo->context = LIST;
445 slots_load_info (newInfo);
446 pValue =
new KvpValue {newInfo->pList};
447 pInfo->pKvpFrame->set ({key.c_str()}, pValue);
451 case KvpValue::Type::FRAME:
454 auto newFrame =
new KvpFrame;
455 newInfo->pKvpFrame = newFrame;
457 switch (pInfo->context)
461 auto value =
new KvpValue {newFrame};
462 newInfo->path = get_key (pInfo);
463 pInfo->pList = g_list_append (pInfo->pList, value);
469 auto key = get_key (pInfo);
470 pInfo->pKvpFrame->set ({key.c_str()},
new KvpValue {newFrame});
475 newInfo->context = FRAME;
476 slots_load_info (newInfo);
486 get_numeric_val (gpointer pObject)
490 g_return_val_if_fail (pObject != NULL, gnc_numeric_zero ());
492 if (pInfo->pKvpValue->get_type () == KvpValue::Type::NUMERIC)
494 return pInfo->pKvpValue->get<gnc_numeric> ();
498 return gnc_numeric_zero ();
503 set_numeric_val (gpointer pObject, gnc_numeric value)
507 g_return_if_fail (pObject != NULL);
509 if (pInfo->value_type != KvpValue::Type::NUMERIC)
return;
510 set_slot_from_value (pInfo,
new KvpValue {value});
514 get_gdate_val (gpointer pObject)
519 g_return_val_if_fail (pObject != NULL, NULL);
521 if (pInfo->pKvpValue->get_type () == KvpValue::Type::GDATE)
523 date = pInfo->pKvpValue->get<GDate> ();
533 set_gdate_val (gpointer pObject, GDate* value)
537 g_return_if_fail (pObject != NULL);
539 if (pInfo->value_type != KvpValue::Type::GDATE)
return;
540 set_slot_from_value (pInfo,
new KvpValue {*value});
546 g_return_val_if_fail (pInfo != NULL, NULL);
549 newSlot->be = pInfo->be;
550 newSlot->guid = guid == NULL ? pInfo->guid : guid;
551 newSlot->is_ok = pInfo->is_ok;
552 newSlot->pKvpFrame = pInfo->pKvpFrame;
553 newSlot->value_type = pInfo->value_type;
554 newSlot->pList = pInfo->pList;
555 newSlot->context = pInfo->context;
556 newSlot->pKvpValue = pInfo->pKvpValue;
557 if (!pInfo->path.empty())
558 newSlot->parent_path = pInfo->path +
"/";
560 newSlot->parent_path = pInfo->parent_path;
565 save_slot (
const char* key, KvpValue* value,
slot_info_t & slot_info)
567 g_return_if_fail (value != NULL);
570 if (!slot_info.is_ok)
574 slot_info.pKvpValue = value;
575 slot_info.path = slot_info.parent_path + key;
576 slot_info.value_type = value->get_type ();
578 switch (slot_info.value_type)
580 case KvpValue::Type::FRAME:
582 auto pKvpFrame = value->get<KvpFrame*> ();
584 slot_info_t* pNewInfo = slot_info_copy (&slot_info, guid);
585 KvpValue* oldValue = slot_info.pKvpValue;
586 slot_info.pKvpValue =
new KvpValue {guid};
592 g_return_if_fail (slot_info.is_ok);
593 pKvpFrame->for_each_slot_temp (save_slot, *pNewInfo);
594 delete slot_info.pKvpValue;
595 slot_info.pKvpValue = oldValue;
599 case KvpValue::Type::GLIST:
602 slot_info_t* pNewInfo = slot_info_copy (&slot_info, guid);
603 KvpValue* oldValue = slot_info.pKvpValue;
604 slot_info.pKvpValue =
new KvpValue {guid};
610 g_return_if_fail (slot_info.is_ok);
611 for (
auto cursor = value->get<GList*> (); cursor; cursor = cursor->next)
613 auto val =
static_cast<KvpValue*
> (cursor->data);
614 save_slot (
"", val, *pNewInfo);
616 delete slot_info.pKvpValue;
617 slot_info.pKvpValue = oldValue;
637 slot_info_t slot_info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID,
638 NULL, FRAME, NULL,
"" };
639 KvpFrame* pFrame = qof_instance_get_slots (inst);
641 g_return_val_if_fail (sql_be != NULL, FALSE);
642 g_return_val_if_fail (guid != NULL, FALSE);
643 g_return_val_if_fail (pFrame != NULL, FALSE);
646 if (!sql_be->pristine() && !is_infant)
651 slot_info.be = sql_be;
652 slot_info.guid = guid;
653 pFrame->for_each_slot_temp (save_slot, slot_info);
655 return slot_info.is_ok;
663 slot_info_t slot_info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID,
664 NULL, FRAME, NULL,
"" };
666 g_return_val_if_fail (sql_be != NULL, FALSE);
667 g_return_val_if_fail (guid != NULL, FALSE);
671 buf = g_strdup_printf (
"SELECT * FROM %s WHERE obj_guid='%s' and slot_type in ('%d', '%d') and not guid_val is null",
672 TABLE_NAME, guid_buf, KvpValue::Type::FRAME, KvpValue::Type::GLIST);
673 auto stmt = sql_be->create_statement_from_sql(buf);
678 for (
auto row : *result)
680 const GncSqlColumnTableEntryPtr table_row =
681 col_table[guid_val_col];
683 auto val = row.get_string_at_col (table_row->name());
689 slot_info.be = sql_be;
690 slot_info.guid = guid;
691 slot_info.is_ok = TRUE;
693 TABLE_NAME, &slot_info,
696 return slot_info.is_ok;
704 g_return_if_fail (pInfo != NULL);
705 g_return_if_fail (pInfo->be != NULL);
706 g_return_if_fail (pInfo->pKvpFrame != NULL);
708 slot_info = slot_info_copy (pInfo, NULL);
710 gnc_sql_load_object (pInfo->be, row, TABLE_NAME, slot_info, col_table);
712 if (slot_info->pList != pInfo->pList)
714 if (pInfo->pList != NULL)
716 PWARN (
"Load slot returned a different list than the original");
720 pInfo->pList = slot_info->pList;
729 slot_info_t info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID,
730 NULL, FRAME, NULL,
"" };
731 g_return_if_fail (sql_be != NULL);
732 g_return_if_fail (inst != NULL);
736 info.pKvpFrame = qof_instance_get_slots (inst);
739 slots_load_info (&info);
745 g_return_if_fail (pInfo != NULL);
746 g_return_if_fail (pInfo->be != NULL);
747 g_return_if_fail (pInfo->guid != NULL);
748 g_return_if_fail (pInfo->pKvpFrame != NULL);
751 std::string sql(
"SELECT * FROM " TABLE_NAME
" WHERE obj_guid='");
752 sql += guid.to_string() +
"'";
753 auto stmt = pInfo->be->create_statement_from_sql(sql);
757 for (
auto row : *result)
758 load_slot (pInfo, row);
768 g_return_val_if_fail (sql_be != NULL, NULL);
770 gnc_sql_load_object (sql_be, row, NULL, &guid, obj_guid_col_table);
777 BookLookupFn lookup_fn)
779 slot_info_t slot_info = { NULL, NULL, TRUE, NULL, KvpValue::Type::INVALID,
780 NULL, FRAME, NULL,
"" };
784 g_return_if_fail (sql_be != NULL);
785 g_return_if_fail (lookup_fn != NULL);
787 guid = load_obj_guid (sql_be, row);
788 g_return_if_fail (guid != NULL);
789 inst = lookup_fn (guid, sql_be->book());
790 if (inst == NULL)
return;
792 slot_info.be = sql_be;
793 slot_info.pKvpFrame = qof_instance_get_slots (inst);
794 slot_info.path.clear();
796 gnc_sql_load_object (sql_be, row, TABLE_NAME, &slot_info, col_table);
809 const std::string subquery,
810 BookLookupFn lookup_fn)
812 g_return_if_fail (sql_be != NULL);
815 if (subquery.empty())
return;
817 std::string pkey(obj_guid_col_table[0]->name());
818 std::string sql(
"SELECT * FROM " TABLE_NAME
" WHERE ");
819 sql += pkey +
" IN (" + subquery +
")";
822 auto stmt = sql_be->create_statement_from_sql(sql);
825 PERR (
"stmt == NULL, SQL = '%s'\n", sql.c_str());
829 for (
auto row : *result)
830 load_slot_for_book_object (sql_be, row, lookup_fn);
841 g_return_if_fail (sql_be != NULL);
846 (void)sql_be->
create_table(TABLE_NAME, TABLE_VERSION, col_table);
848 ok = sql_be->
create_index (
"slots_guid_index", TABLE_NAME,
852 PERR (
"Unable to create index\n");
855 else if (version < m_version)
865 ok = sql_be->
create_index (
"slots_guid_index", TABLE_NAME,
869 PERR (
"Unable to create index\n");
872 else if (version == 2)
877 PERR (
"Unable to add gdate column\n");
885 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.