static void gnc_dbi_destroy_backend (QofBackend* be) { g_return_if_fail (be != nullptr); /* Stop transaction logging */ xaccLogSetBaseName (nullptr); qof_backend_destroy (be); g_free (be); }
template <> void gnc_dbi_session_begin<DbType::DBI_SQLITE>(QofBackend* qbe, QofSession* session, const char* book_id, gboolean ignore_lock, gboolean create, gboolean force) { GncDbiBackend* be = (GncDbiBackend*)qbe; const char* msg = nullptr; gboolean file_exists; PairVec options; g_return_if_fail (qbe != nullptr); g_return_if_fail (session != nullptr); g_return_if_fail (book_id != nullptr); ENTER (" "); /* Remove uri type if present */ auto path = gnc_uri_get_path (book_id); std::string filepath{path}; g_free(path); GFileTest ftest = static_cast<decltype (ftest)> ( G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS) ; file_exists = g_file_test (filepath.c_str(), ftest); if (!create && !file_exists) { qof_backend_set_error (qbe, ERR_FILEIO_FILE_NOT_FOUND); qof_backend_set_message (qbe, "Sqlite3 file %s not found", filepath.c_str()); PWARN ("Sqlite3 file %s not found", filepath.c_str()); LEAVE("Error"); return; } if (create && !force && file_exists) { qof_backend_set_error (qbe, ERR_BACKEND_STORE_EXISTS); msg = "Might clobber, no force"; PWARN ("%s", msg); LEAVE("Error"); return; } be->connect(nullptr); /* dbi-sqlite3 documentation says that sqlite3 doesn't take a "host" option */ options.push_back(std::make_pair("host", "localhost")); auto dirname = g_path_get_dirname (filepath.c_str()); auto basename = g_path_get_basename (filepath.c_str()); options.push_back(std::make_pair("dbname", basename)); options.push_back(std::make_pair("sqlite3_dbdir", dirname)); if (basename != nullptr) g_free (basename); if (dirname != nullptr) g_free (dirname); UriStrings uri; auto conn = conn_setup<DbType::DBI_SQLITE>(qbe, options, uri); if (conn == nullptr) { LEAVE("Error"); return; } auto result = dbi_conn_connect (conn); if (result < 0) { dbi_conn_close(conn); PERR ("Unable to connect to %s: %d\n", book_id, result); qof_backend_set_error (qbe, ERR_BACKEND_BAD_URL); LEAVE("Error"); return; } if (!conn_test_dbi_library(conn, qbe)) { if (create && !file_exists) { /* File didn't exist before, but it does now, and we don't want to * leave it lying around. */ dbi_conn_close (conn); conn = nullptr; g_unlink (filepath.c_str()); } dbi_conn_close(conn); LEAVE("Bad DBI Library"); return; } try { be->connect(new GncDbiSqlConnection(DbType::DBI_SQLITE, qbe, conn, ignore_lock)); } catch (std::runtime_error& err) { return; } /* We should now have a proper session set up. * Let's start logging */ xaccLogSetBaseName (filepath.c_str()); PINFO ("logpath=%s", filepath.c_str() ? filepath.c_str() : "(null)"); LEAVE (""); }
template <DbType T> void gnc_dbi_session_begin (QofBackend* qbe, QofSession* session, const char* book_id, gboolean ignore_lock, gboolean create, gboolean force) { GncDbiBackend* be = (GncDbiBackend*)qbe; GncDbiTestResult dbi_test_result = GNC_DBI_PASS; PairVec options; g_return_if_fail (qbe != nullptr); g_return_if_fail (session != nullptr); g_return_if_fail (book_id != nullptr); ENTER (" "); /* Split the book-id * Format is protocol://username:password@hostname:port/dbname where username, password and port are optional) */ UriStrings uri(book_id); if (T == DbType::DBI_PGSQL) { if (uri.m_portnum == 0) uri.m_portnum = PGSQL_DEFAULT_PORT; /* Postgres's SQL interface coerces identifiers to lower case, but the * C interface is case-sensitive. This results in a mixed-case dbname * being created (with a lower case name) but then dbi can't conect to * it. To work around this, coerce the name to lowercase first. */ auto lcname = g_utf8_strdown (uri.dbname(), -1); uri.m_dbname = std::string{lcname}; g_free(lcname); } be->connect(nullptr); auto conn = conn_setup<T>(qbe, options, uri); if (conn == nullptr) { LEAVE("Error"); return; } be->set_exists(true); //May be unset in the error handler. auto result = dbi_conn_connect (conn); if (result == 0) { if (T == DbType::DBI_MYSQL) adjust_sql_options (conn); if(!conn_test_dbi_library(conn, qbe)) { dbi_conn_close(conn); LEAVE("Error"); return; } if (create && !force && save_may_clobber_data (conn, uri.quote_dbname(T))) { qof_backend_set_error (qbe, ERR_BACKEND_STORE_EXISTS); PWARN ("Databse already exists, Might clobber it."); dbi_conn_close(conn); LEAVE("Error"); return; } } else { if (be->exists()) { PERR ("Unable to connect to database '%s'\n", uri.dbname()); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); dbi_conn_close(conn); LEAVE("Error"); return; } if (create) { if (!create_database(T, qbe, conn, uri.quote_dbname(T).c_str())) { dbi_conn_close(conn); LEAVE("Error"); return; } conn = conn_setup<T>(qbe, options, uri); result = dbi_conn_connect (conn); if (result < 0) { PERR ("Unable to create database '%s'\n", uri.dbname()); qof_backend_set_error (qbe, ERR_BACKEND_SERVER_ERR); dbi_conn_close(conn); LEAVE("Error"); return; } if (T == DbType::DBI_MYSQL) adjust_sql_options (conn); if (!conn_test_dbi_library(conn, qbe)) { if (T == DbType::DBI_PGSQL) dbi_conn_select_db (conn, "template1"); dbi_conn_queryf (conn, "DROP DATABASE %s", uri.quote_dbname(T).c_str()); dbi_conn_close(conn); return; } } else { qof_backend_set_error (qbe, ERR_BACKEND_NO_SUCH_DB); qof_backend_set_message (qbe, "Database %s not found", uri.dbname()); } } be->connect(nullptr); try { be->connect(new GncDbiSqlConnection(T, qbe, conn, ignore_lock)); } catch (std::runtime_error& err) { return; } /* We should now have a proper session set up. * Let's start logging */ auto translog_path = gnc_build_translog_path (uri.basename().c_str()); xaccLogSetBaseName (translog_path); PINFO ("logpath=%s", translog_path ? translog_path : "(null)"); g_free (translog_path); LEAVE (" "); }
GncDbiBackend<Type>::~GncDbiBackend() { /* Stop transaction logging */ xaccLogSetBaseName (nullptr); }