29#include <glib/gstdio.h>
42#include "qofquery-p.h"
43#include "qofquerycore-p.h"
48#include "Recurrence.h"
53#include "gnc-locale-utils.h"
58#include "splint-defs.h"
61#include <boost/regex.hpp>
65#include <qofsession.hpp>
66#include <gnc-backend-prov.hpp>
68#include "gnc-backend-dbi.hpp"
70#include <gnc-sql-object-backend.hpp>
71#include "gnc-dbisqlresult.hpp"
72#include "gnc-dbisqlconnection.hpp"
74#if LIBDBI_VERSION >= 900
75#define HAVE_LIBDBI_R 1
76static dbi_inst dbi_instance =
nullptr;
78#define HAVE_LIBDBI_R 0
79#define HAVE_LIBDBI_TO_LONGLONG 0
82#define TRANSACTION_NAME "trans"
84static QofLogModule log_module = G_LOG_DOMAIN;
86#define FILE_URI_TYPE "file"
87#define FILE_URI_PREFIX (FILE_URI_TYPE "://")
88#define SQLITE3_URI_TYPE "sqlite3"
89#define SQLITE3_URI_PREFIX (SQLITE3_URI_TYPE "://")
90#define PGSQL_DEFAULT_PORT 5432
92static void adjust_sql_options (dbi_conn connection);
93template<DbType Type>
bool save_may_clobber_data (dbi_conn conn,
94 const std::string& dbname);
121 std::string basename()
const noexcept;
122 const char* dbname()
const noexcept;
123 std::string quote_dbname(DbType t)
const noexcept;
124 std::string m_protocol;
126 std::string m_dbname;
127 std::string m_username;
128 std::string m_password;
129 std::string m_basename;
133UriStrings::UriStrings(
const std::string& uri)
135 gchar *scheme, *host, *username, *password, *dbname;
139 m_protocol = std::string{scheme};
140 m_host = std::string{host};
142 m_dbname = std::string{dbname};
144 m_username = std::string{username};
146 m_password = std::string{password};
156UriStrings::basename() const noexcept
158 return m_protocol +
"_" + m_host +
"_" + m_username +
"_" + m_dbname;
162UriStrings::dbname() const noexcept
164 return m_dbname.c_str();
168UriStrings::quote_dbname(DbType t)
const noexcept
170 if (m_dbname.empty())
172 const char quote = (t == DbType::DBI_MYSQL ?
'`' :
'"');
173 std::string retval(1, quote);
174 retval += m_dbname + quote;
179set_options(dbi_conn conn,
const PairVec& options)
181 for (
const auto& option : options)
183 auto opt = option.first.c_str();
184 auto val = option.second.c_str();
185 auto result = dbi_conn_set_option(conn, opt, val);
188 const char *msg =
nullptr;
189 dbi_conn_error(conn, &msg);
190 PERR(
"Error setting %s option to %s: %s", opt, val, msg);
191 throw std::runtime_error(msg);
203template <DbType Type>
bool
209 options.push_back(std::make_pair(
"host", uri.m_host));
210 options.push_back(std::make_pair(
"dbname", uri.m_dbname));
211 options.push_back(std::make_pair(
"username", uri.m_username));
212 options.push_back(std::make_pair(
"password", uri.m_password));
213 options.push_back(std::make_pair(
"encoding",
"UTF-8"));
216 set_options(conn, options);
217 auto result = dbi_conn_set_option_numeric(conn,
"port", uri.m_portnum);
220 const char *msg =
nullptr;
221 auto err = dbi_conn_error(conn, &msg);
222 PERR(
"Error (%d) setting port option to %d: %s", err, uri.m_portnum, msg);
223 throw std::runtime_error(msg);
226 catch (std::runtime_error& err)
235template <DbType Type>
void error_handler(dbi_conn conn,
void* data);
236void error_handler(dbi_conn conn,
void* data);
238template <DbType Type> dbi_conn
241 const char* dbstr = (Type == DbType::DBI_SQLITE ?
"sqlite3" :
242 Type == DbType::DBI_MYSQL ?
"mysql" :
"pgsql");
244 dbi_conn conn =
nullptr;
246 conn = dbi_conn_new_r (dbstr, dbi_instance);
248 PERR (
"Attempt to connect with an uninitialized dbi_instance");
250 auto conn = dbi_conn_new (dbstr);
255 PERR (
"Unable to create %s dbi connection", dbstr);
260 dbi_conn_error_handler (conn, error_handler<Type>,
this);
261 if (!uri.m_dbname.empty() &&
262 !set_standard_connection_options(conn, uri))
264 dbi_conn_close(conn);
270 set_options(conn, options);
272 catch (std::runtime_error& err)
274 dbi_conn_close(conn);
283template <DbType Type>
bool
287 const char *dbcreate;
288 if (Type == DbType::DBI_MYSQL)
291 dbcreate =
"CREATE DATABASE %s CHARACTER SET utf8";
296 dbcreate =
"CREATE DATABASE %s WITH TEMPLATE template0 ENCODING 'UTF8'";
299 options.push_back(std::make_pair(
"dbname", dbname));
302 set_options(conn, options);
304 catch (std::runtime_error& err)
310 auto result = dbi_conn_connect (conn);
313 PERR (
"Unable to connect to %s database", dbname);
317 if (Type == DbType::DBI_MYSQL)
318 adjust_sql_options(conn);
319 auto dresult = dbi_conn_queryf (conn, dbcreate, db);
320 if (dresult ==
nullptr)
322 PERR (
"Unable to create database '%s'\n", db);
326 if (Type == DbType::DBI_PGSQL)
328 const char *alterdb =
"ALTER DATABASE %s SET "
329 "standard_conforming_strings TO on";
330 dbi_conn_queryf (conn, alterdb, db);
332 dbi_conn_close(conn);
338error_handler<DbType::DBI_SQLITE> (dbi_conn conn,
void* user_data)
342 static_cast<decltype(dbi_be)
>(user_data);
343 int err_num = dbi_conn_error (conn, &msg);
349 if (err_num == DBI_ERROR_BADIDX)
return;
350 PERR (
"DBI error: %s\n", msg);
351 if (dbi_be->connected())
360 gboolean file_exists;
363 g_return_if_fail (session !=
nullptr);
364 g_return_if_fail (new_uri !=
nullptr);
370 std::string filepath{path};
372 GFileTest ftest =
static_cast<decltype (ftest)
> (
373 G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS) ;
374 file_exists = g_file_test (filepath.c_str(), ftest);
376 if (!create && !file_exists)
379 std::string msg{
"Sqlite3 file "};
380 set_message (msg + filepath +
" not found");
381 PWARN (
"Sqlite3 file %s not found", filepath.c_str());
386 if (create && file_exists)
389 g_unlink (filepath.c_str());
393 auto msg =
"Might clobber, mode not SESSION_NEW_OVERWRITE";
402 options.push_back(std::make_pair(
"host",
"localhost"));
403 auto dirname = g_path_get_dirname (filepath.c_str());
404 auto basename = g_path_get_basename (filepath.c_str());
405 options.push_back(std::make_pair(
"dbname", basename));
406 options.push_back(std::make_pair(
"sqlite3_dbdir", dirname));
407 if (basename !=
nullptr) g_free (basename);
408 if (dirname !=
nullptr) g_free (dirname);
410 auto conn = conn_setup(options, uri);
417 auto result = dbi_conn_connect (conn);
421 dbi_conn_close(conn);
422 PERR (
"Unable to connect to %s: %d\n", new_uri, result);
430 if (create && !file_exists)
435 dbi_conn_close (conn);
437 g_unlink (filepath.c_str());
439 dbi_conn_close(conn);
440 LEAVE(
"Bad DBI Library");
449 catch (std::runtime_error& err)
457 PINFO (
"logpath=%s", filepath.c_str() ? filepath.c_str() :
"(null)");
463error_handler<DbType::DBI_MYSQL> (dbi_conn conn,
void* user_data)
466 static_cast<decltype(dbi_be)
>(user_data);
469 auto err_num = dbi_conn_error (conn, &msg);
475 if (err_num == DBI_ERROR_BADIDX)
return;
486 PINFO (
"DBI error: %s\n", msg);
487 dbi_be->set_exists(
false);
495 if (!dbi_be->connected())
497 PINFO (
"DBI error: %s\n", msg);
498 PINFO (
"Note: GncDbiSqlConnection not yet initialized. Skipping further error processing.");
505 PINFO (
"DBI error: %s - Reconnecting...\n", msg);
507 dbi_be->retry_connection(msg);
509 else if (err_num == 2003)
512 dbi_be->retry_connection (msg);
514 else if (err_num == 1007)
516 dbi_be->set_exists(
true);
522 PERR (
"DBI error: %s\n", msg);
527#define SQL_OPTION_TO_REMOVE "NO_ZERO_DATE"
534adjust_sql_options_string(
const std::string& str)
539 static const boost::regex reg{
"(?:," SQL_OPTION_TO_REMOVE
"$|\\b"
540 SQL_OPTION_TO_REMOVE
"\\b,?)"};
541 return regex_replace(str, reg, std::string{
""});
546adjust_sql_options (dbi_conn connection)
548 dbi_result result = dbi_conn_query( connection,
"SELECT @@sql_mode");
549 if (result ==
nullptr)
552 int err = dbi_conn_error(connection, &errmsg);
553 PERR(
"Unable to read sql_mode %d : %s", err, errmsg);
556 dbi_result_first_row(result);
557 std::string str{dbi_result_get_string_idx(result, 1)};
558 dbi_result_free(result);
562 int err = dbi_conn_error(connection, &errmsg);
564 PERR(
"Unable to get sql_mode %d : %s", err, errmsg);
566 PINFO(
"Sql_mode isn't set.");
569 PINFO(
"Initial sql_mode: %s", str.c_str());
570 if(str.find(SQL_OPTION_TO_REMOVE) != std::string::npos)
571 str = adjust_sql_options_string(str);
574 const char* backslash_option{
"NO_BACKSLASH_ESCAPES"};
576 if (str.find(backslash_option) == std::string::npos)
580 str.append(backslash_option);
583 PINFO(
"Setting sql_mode to %s", str.c_str());
584 std::string set_str{
"SET sql_mode='" + std::move(str) +
"'"};
585 dbi_result set_result = dbi_conn_query(connection,
589 dbi_result_free(set_result);
594 int err = dbi_conn_error(connection, &errmsg);
595 PERR(
"Unable to set sql_mode %d : %s", err, errmsg);
599template <DbType Type>
bool
600drop_database(dbi_conn conn,
const UriStrings& uri)
603 if (Type == DbType::DBI_PGSQL)
605 root_db =
"template1";
607 else if (Type == DbType::DBI_MYSQL)
613 PERR (
"Unknown database type, can't proceed.");
617 if (dbi_conn_select_db (conn, root_db) == -1)
619 PERR (
"Failed to switch out of %s, drop will fail.",
620 uri.quote_dbname(Type).c_str());
624 if (!dbi_conn_queryf (conn,
"DROP DATABASE %s",
625 uri.quote_dbname(Type).c_str()))
627 PERR (
"Failed to drop database %s prior to recreating it."
628 "Proceeding would combine old and new data.",
629 uri.quote_dbname(Type).c_str());
636template <DbType Type>
void
642 g_return_if_fail (session !=
nullptr);
643 g_return_if_fail (new_uri !=
nullptr);
652 if (Type == DbType::DBI_PGSQL)
654 if (uri.m_portnum == 0)
655 uri.m_portnum = PGSQL_DEFAULT_PORT;
660 auto lcname = g_utf8_strdown (uri.dbname(), -1);
661 uri.m_dbname = std::string{lcname};
667 auto conn = conn_setup(options, uri);
675 auto result = dbi_conn_connect (conn);
678 if (Type == DbType::DBI_MYSQL)
679 adjust_sql_options (conn);
682 dbi_conn_close(conn);
688 if (create && save_may_clobber_data<Type>(conn, uri.quote_dbname(Type)))
692 if (!drop_database<Type>(conn, uri))
698 PWARN (
"Database already exists, Might clobber it.");
699 dbi_conn_close(conn);
710 PERR (
"Unable to connect to database '%s'\n", uri.dbname());
712 dbi_conn_close(conn);
718 PERR (
"Database '%s' does not exist\n", uri.dbname());
720 std::string msg{
"Database "};
721 set_message(msg + uri.dbname() +
" not found");
729 !create_database(conn, uri.quote_dbname(Type).c_str()))
731 dbi_conn_close(conn);
735 conn = conn_setup(options, uri);
736 result = dbi_conn_connect (conn);
739 PERR (
"Unable to create database '%s'\n", uri.dbname());
741 dbi_conn_close(conn);
745 if (Type == DbType::DBI_MYSQL)
746 adjust_sql_options (conn);
747 if (!conn_test_dbi_library(conn))
749 if (Type == DbType::DBI_PGSQL)
750 dbi_conn_select_db (conn,
"template1");
751 dbi_conn_queryf (conn,
"DROP DATABASE %s",
752 uri.quote_dbname(Type).c_str());
753 dbi_conn_close(conn);
763 catch (std::runtime_error& err)
769 auto translog_path = gnc_build_translog_path (uri.basename().c_str());
771 PINFO (
"logpath=%s", translog_path ? translog_path :
"(null)");
772 g_free (translog_path);
778error_handler<DbType::DBI_PGSQL> (dbi_conn conn,
void* user_data)
781 static_cast<decltype(dbi_be)
>(user_data);
784 auto err_num = dbi_conn_error (conn, &msg);
790 if (err_num == DBI_ERROR_BADIDX)
return;
791 if (g_str_has_prefix (msg,
"FATAL: database") &&
792 g_str_has_suffix (msg,
"does not exist\n"))
794 PINFO (
"DBI error: %s\n", msg);
795 dbi_be->set_exists(
false);
797 else if (g_strrstr (msg,
798 "server closed the connection unexpectedly"))
800 if (!dbi_be->connected())
802 PWARN (
"DBI Error: Connection lost, connection pointer invalid");
805 PINFO (
"DBI error: %s - Reconnecting...\n", msg);
807 dbi_be->retry_connection(msg);
809 else if (g_str_has_prefix (msg,
"connection pointer is NULL") ||
810 g_str_has_prefix (msg,
"could not connect to server"))
813 if (!dbi_be->connected())
819 dbi_be->retry_connection (msg);
824 PERR (
"DBI error: %s\n", msg);
825 if (dbi_be->connected())
832template <DbType Type>
void
837 finalize_version_info ();
843template <DbType Type>
861template <DbType Type>
void
864 g_return_if_fail (book !=
nullptr);
866 ENTER (
"dbi_be=%p, book=%p",
this, book);
868 if (loadType == LOAD_TYPE_INITIAL_LOAD)
872 init_version_info ();
873 assert (m_book ==
nullptr);
879 if (Type == DbType::DBI_SQLITE)
882 if (GNUCASH_RESAVE_VERSION > get_table_version(
"Gnucash"))
889 else if (GNUCASH_RESAVE_VERSION < get_table_version(
"Gnucash-Resave"))
904template <DbType T>
bool
905save_may_clobber_data (dbi_conn conn,
const std::string& dbname)
909 auto result = dbi_conn_get_table_list (conn, dbname.c_str(),
nullptr);
913 retval = dbi_result_get_numrows (result) > 0;
914 dbi_result_free (result);
920save_may_clobber_data <DbType::DBI_PGSQL>(dbi_conn conn,
921 const std::string& dbname)
925 const char* query =
"SELECT relname FROM pg_class WHERE relname !~ '^(pg|sql)_' AND relkind = 'r' ORDER BY relname";
926 auto result = dbi_conn_query (conn, query);
930 retval = dbi_result_get_numrows (result) > 0;
931 dbi_result_free (result);
945template <DbType Type>
void
950 g_return_if_fail (conn !=
nullptr);
951 g_return_if_fail (book !=
nullptr);
953 ENTER (
"book=%p, primary=%p", book, m_book);
954 if (!conn->begin_transaction())
956 LEAVE(
"Failed to obtain a transaction.");
959 if (!conn->table_operation (TableOpType::backup))
961 conn->rollback_transaction();
962 LEAVE (
"Failed to rename tables");
965 if (!conn->drop_indexes())
967 conn->rollback_transaction();
968 LEAVE (
"Failed to drop indexes");
975 conn->rollback_transaction();
976 LEAVE (
"Failed to create new database tables");
979 conn->commit_transaction();
980 conn->table_operation (TableOpType::drop_backup);
981 LEAVE (
"book=%p", m_book);
993 g_return_if_fail (conn !=
nullptr);
994 g_return_if_fail (book !=
nullptr);
996 ENTER (
"book=%p, primary=%p", book, m_book);
997 if (!conn->table_operation (TableOpType::backup))
1000 conn->table_operation (TableOpType::rollback);
1001 LEAVE (
"Failed to rename tables");
1004 if (!conn->drop_indexes())
1006 conn->table_operation (TableOpType::rollback);
1008 set_message(
"Failed to drop indexes");
1009 LEAVE (
"Failed to drop indexes");
1016 conn->table_operation (TableOpType::rollback);
1017 LEAVE (
"Failed to create new database tables");
1020 conn->table_operation (TableOpType::drop_backup);
1021 LEAVE (
"book=%p", m_book);
1034 G_GNUC_UNUSED
size_t chars_read;
1039 g_return_val_if_fail (uri !=
nullptr, FALSE);
1042 f = g_fopen (filename,
"r");
1048 PINFO (
"doesn't exist (errno=%d) -> DBI", errno);
1053 chars_read = fread (buf,
sizeof (buf) - 1, 1, f);
1054 status = fclose (f);
1057 PERR (
"Error in fclose(): %d\n", errno);
1059 if (g_str_has_prefix (buf,
"SQLite format 3"))
1061 PINFO (
"has SQLite format string -> DBI");
1064 PINFO (
"exists, does not have SQLite format string -> not DBI");
1071gnc_module_init_backend_dbi (
void)
1073 const char* driver_dir;
1075 gboolean have_sqlite3_driver = FALSE;
1076 gboolean have_mysql_driver = FALSE;
1077 gboolean have_pgsql_driver = FALSE;
1081 driver_dir = g_getenv (
"GNC_DBD_DIR");
1082 if (driver_dir ==
nullptr)
1084 PINFO (
"GNC_DBD_DIR not set: using libdbi built-in default\n");
1091 num_drivers = dbi_initialize_r (driver_dir, &dbi_instance);
1093 num_drivers = dbi_initialize (driver_dir);
1095 if (num_drivers <= 0)
1100 dbi_shutdown_r (dbi_instance);
1101 dbi_instance =
nullptr;
1104 gchar *libdir = gnc_path_get_libdir ();
1105 gchar *dir = g_build_filename (libdir,
"dbd",
nullptr);
1108 num_drivers = dbi_initialize_r (dir, &dbi_instance);
1110 num_drivers = dbi_initialize (dir);
1114 if (num_drivers <= 0)
1116 PWARN (
"No DBD drivers found\n");
1120 dbi_driver driver =
nullptr;
1121 PINFO (
"%d DBD drivers found\n", num_drivers);
1126 driver = dbi_driver_list_r (driver, dbi_instance);
1128 driver = dbi_driver_list (driver);
1131 if (driver !=
nullptr)
1133 const gchar* name = dbi_driver_get_name (driver);
1135 PINFO (
"Driver: %s\n", name);
1136 if (strcmp (name,
"sqlite3") == 0)
1138 have_sqlite3_driver = TRUE;
1140 else if (strcmp (name,
"mysql") == 0)
1142 have_mysql_driver = TRUE;
1144 else if (strcmp (name,
"pgsql") == 0)
1146 have_pgsql_driver = TRUE;
1150 while (driver !=
nullptr);
1153 if (have_sqlite3_driver)
1155 const char* name =
"GnuCash Libdbi (SQLITE3) Backend";
1157 qof_backend_register_provider(std::move(prov));
1159 qof_backend_register_provider(std::move(prov));
1162 if (have_mysql_driver)
1164 const char *name =
"GnuCash Libdbi (MYSQL) Backend";
1166 qof_backend_register_provider(std::move(prov));
1169 if (have_pgsql_driver)
1171 const char* name =
"GnuCash Libdbi (POSTGRESQL) Backend";
1173 qof_backend_register_provider(std::move(prov));
1181#ifndef GNC_NO_LOADABLE_MODULES
1183qof_backend_module_init (
void)
1185 gnc_module_init_backend_dbi ();
1189qof_backend_module_finalize (
void)
1191 gnc_module_finalize_backend_dbi ();
1196gnc_module_finalize_backend_dbi (
void)
1201 dbi_shutdown_r (dbi_instance);
1202 dbi_instance =
nullptr;
1212log_failed_field(dbi_result result,
const char* fieldname)
1214 auto idx = dbi_result_get_field_idx(result, fieldname);
1215 if (dbi_result_field_is_null_idx(result, idx))
1216 PERR(
"Result field %s is NULL", fieldname);
1219 auto type = dbi_result_get_field_type_idx(result, idx);
1220 auto attribs = dbi_result_get_field_attribs_idx(result, idx);
1221 PERR(
"Result field %s has type %d and attribs %d",
1222 fieldname, type, attribs);
1235static GncDbiTestResult
1236dbi_library_test (dbi_conn conn)
1238 int64_t testlonglong = -9223372036854775807LL, resultlonglong = 0;
1239 uint64_t testulonglong = 9223372036854775807LLU, resultulonglong = 0;
1240 double testdouble = 1.7976921348623157E+307, resultdouble = 0.0;
1242 GncDbiTestResult retval = GNC_DBI_PASS;
1244 result = dbi_conn_query (conn,
"CREATE TEMPORARY TABLE numtest "
1245 "( test_int BIGINT, test_unsigned BIGINT,"
1246 " test_double FLOAT8 )");
1247 if (result ==
nullptr)
1249 PWARN (
"Test_DBI_Library: Create table failed");
1250 return GNC_DBI_FAIL_SETUP;
1252 dbi_result_free (result);
1253 std::stringstream querystr;
1254 querystr <<
"INSERT INTO numtest VALUES (" << testlonglong <<
1255 ", " << testulonglong <<
", " << std::setprecision(12) <<
1257 auto query = querystr.str();
1258 result = dbi_conn_query (conn, query.c_str());
1259 if (result ==
nullptr)
1261 PWARN (
"Test_DBI_Library: Failed to insert test row into table");
1262 return GNC_DBI_FAIL_SETUP;
1264 dbi_result_free (result);
1265 auto locale = gnc_push_locale (LC_NUMERIC,
"C");
1266 result = dbi_conn_query (conn,
"SELECT * FROM numtest");
1267 if (result ==
nullptr || !dbi_result_get_numrows(result))
1270 dbi_conn_error (conn, &errmsg);
1271 PWARN (
"Test_DBI_Library: Failed to retrieve test row into table: %s",
1273 dbi_conn_query (conn,
"DROP TABLE numtest");
1274 gnc_pop_locale (LC_NUMERIC, locale);
1275 return GNC_DBI_FAIL_SETUP;
1277 while (dbi_result_next_row (result))
1279 resultlonglong = dbi_result_get_longlong (result,
"test_int");
1280 if (!resultlonglong)
1281 log_failed_field(result,
"test_int");
1282 resultulonglong = dbi_result_get_ulonglong (result,
"test_unsigned");
1283 if (!resultulonglong)
1284 log_failed_field(result,
"test_unsigned");
1285 resultdouble = dbi_result_get_double (result,
"test_double");
1287 log_failed_field(result,
"test_double");
1289 dbi_conn_query (conn,
"DROP TABLE numtest");
1290 gnc_pop_locale (LC_NUMERIC, locale);
1291 if (testlonglong != resultlonglong)
1293 PWARN (
"Test_DBI_Library: LongLong Failed %" PRId64
" != % " PRId64,
1294 testlonglong, resultlonglong);
1295 retval = GNC_DBI_FAIL_TEST;
1297 if (testulonglong != resultulonglong)
1299 PWARN (
"Test_DBI_Library: Unsigned longlong Failed %" PRIu64
" != %"
1300 PRIu64, testulonglong, resultulonglong);
1301 retval = GNC_DBI_FAIL_TEST;
1304 if (testdouble >= resultdouble + 0.000001e307 ||
1305 testdouble <= resultdouble - 0.000001e307)
1307 PWARN (
"Test_DBI_Library: Double Failed %17e != %17e",
1308 testdouble, resultdouble);
1309 retval = GNC_DBI_FAIL_TEST;
1314template <DbType Type>
bool
1317 auto result = dbi_library_test (conn);
1323 case GNC_DBI_FAIL_SETUP:
1325 set_message (
"DBI library large number test incomplete");
1328 case GNC_DBI_FAIL_TEST:
1330 set_message (
"DBI library fails large number test");
1333 return result == GNC_DBI_PASS;
Account handling public routines.
Anchor Scheduled Transaction info in a book.
API for the transaction logger.
void load(QofBook *, QofBackendLoadType) override
Load the minimal set of application data needed for the application to be operable at initial startup...
void safe_sync(QofBook *) override
Safely resave a database by renaming all of its tables, recreating everything, and then dropping the ...
void set_dbi_error(QofBackendError error, unsigned int repeat, bool retry) noexcept
FIXME: Just a pass-through to m_conn:
void session_begin(QofSession *, const char *, SessionOpenMode) override
Open the file or connect to the server.
Encapsulate a libdbi dbi_conn connection.
void load(QofBook *, QofBackendLoadType) override
Load the contents of an SQL database into a book.
bool type_check(const char *type)
Distinguish two providers with same access method.
QofBackend * create_backend(void)
Return a new, fully initialized backend.
load and save data to SQL via libdbi
All type declarations for the whole Gnucash engine.
Utility functions for file access.
File path resolution utility functions.
Generic api to store and retrieve preferences.
Utility functions for convert uri in separate components and back.
void qof_backend_set_error(QofBackend *qof_be, QofBackendError err)
Set the error on the specified QofBackend.
SessionOpenMode
Mode for opening sessions.
@ ERR_BACKEND_NO_SUCH_DB
the named database doesn't exist
@ ERR_BACKEND_BAD_URL
Can't parse url.
@ ERR_BACKEND_STORE_EXISTS
File exists, data would be destroyed.
@ ERR_BACKEND_SERVER_ERR
error in response from server
@ ERR_SQL_DB_TOO_OLD
database is old and needs upgrading
@ ERR_SQL_DB_TOO_NEW
database is newer, we can't write to it
@ ERR_BACKEND_CANT_CONNECT
bad dbname/login/passwd or network failure
@ ERR_SQL_DBI_UNTESTABLE
could not complete test for LibDBI bug
@ ERR_BACKEND_MISC
undetermined error
@ ERR_FILEIO_FILE_NOT_FOUND
not found / no such file
@ ERR_BACKEND_CONN_LOST
Lost connection to server.
@ ERR_SQL_BAD_DBI
LibDBI has numeric errors.
@ SESSION_READ_ONLY
Create a new store at the URI even if a store already exists there.
@ SESSION_NEW_STORE
Open will fail if the URI doesn't exist or is locked.
@ SESSION_NEW_OVERWRITE
Create a new store at the URI.
#define PINFO(format, args...)
Print an informational note.
#define LEAVE(format, args...)
Print a function exit debugging message.
#define PERR(format, args...)
Log a serious error.
#define PWARN(format, args...)
Log a warning.
#define ENTER(format, args...)
Print a function entry debugging message.
void xaccLogSetBaseName(const char *basepath)
The xaccLogSetBaseName() method sets the base filepath and the root part of the journal file name.
void gnc_features_set_used(QofBook *book, const gchar *feature)
Indicate that the current book uses the given feature.
gchar * gnc_uri_get_path(const gchar *uri)
Extracts the path part from a uri.
void gnc_uri_get_components(const gchar *uri, gchar **scheme, gchar **hostname, gint32 *port, gchar **username, gchar **password, gchar **path)
Converts a uri in separate components.