GnuCash  4.8a-176-g88ecf8dd1
Public Member Functions
GncDbiBackend< Type > Class Template Reference
Inheritance diagram for GncDbiBackend< Type >:
GncSqlBackend QofBackend

Public Member Functions

 GncDbiBackend (GncSqlConnection *conn, QofBook *book)
 
void session_begin (QofSession *, const char *, SessionOpenMode) override
 Open the file or connect to the server. More...
 
void session_end () override
 
void load (QofBook *, QofBackendLoadType) override
 Load the minimal set of application data needed for the application to be operable at initial startup. More...
 
void safe_sync (QofBook *) override
 Safely resave a database by renaming all of its tables, recreating everything, and then dropping the backup tables only if there were no errors. More...
 
bool connected () const noexcept
 
void set_dbi_error (QofBackendError error, unsigned int repeat, bool retry) noexcept
 FIXME: Just a pass-through to m_conn:
 
void retry_connection (const char *msg) const noexcept
 
bool exists ()
 
void set_exists (bool exists)
 
template<>
void session_begin (QofSession *session, const char *new_uri, SessionOpenMode mode)
 Open the file or connect to the server. More...
 
template<>
void safe_sync (QofBook *book)
 Perform a sync in a way that prevents data loss on a DBI backend.
 
- Public Member Functions inherited from GncSqlBackend
 GncSqlBackend (GncSqlConnection *conn, QofBook *book)
 
void load (QofBook *, QofBackendLoadType) override
 Load the contents of an SQL database into a book. More...
 
void sync (QofBook *) override
 Save the contents of a book to an SQL database. More...
 
void begin (QofInstance *) override
 An object is about to be edited. More...
 
void commit (QofInstance *) override
 Object editing is complete and the object should be saved. More...
 
void rollback (QofInstance *) override
 Object editing has been cancelled. More...
 
void connect (GncSqlConnection *conn) noexcept
 Connect the backend to a GncSqlConnection. More...
 
void init_version_info () noexcept
 Initializes DB table version information. More...
 
bool reset_version_info () noexcept
 Resets the version table information by removing all version table info. More...
 
void finalize_version_info () noexcept
 Finalizes DB table version information. More...
 
GncSqlStatementPtr create_statement_from_sql (const std::string &str) const noexcept
 
GncSqlResultPtr execute_select_statement (const GncSqlStatementPtr &stmt) const noexcept
 Executes an SQL SELECT statement and returns the result rows. More...
 
int execute_nonselect_statement (const GncSqlStatementPtr &stmt) const noexcept
 
std::string quote_string (const std::string &) const noexcept
 
bool create_table (const std::string &table_name, const EntryVec &col_table) const noexcept
 Creates a table in the database. More...
 
bool create_table (const std::string &table_name, int table_version, const EntryVec &col_table) noexcept
 Creates a table in the database and sets its version. More...
 
void create_tables () noexcept
 Create/update all tables in the database.
 
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. More...
 
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. More...
 
void upgrade_table (const std::string &table_name, const EntryVec &col_table) noexcept
 Upgrades a table to a new structure. More...
 
uint_t get_table_version (const std::string &table_name) const noexcept
 Returns the version number for a DB table. More...
 
bool set_table_version (const std::string &table_name, uint_t version) noexcept
 Registers the version for a table. More...
 
void commodity_for_postload_processing (gnc_commodity *)
 Register a commodity to be committed after loading is complete. More...
 
GncSqlObjectBackendPtr get_object_backend (const std::string &type) const noexcept
 Get the GncSqlObjectBackend for the indicated type. More...
 
bool object_in_db (const char *table_name, QofIdTypeConst obj_name, const gpointer pObject, const EntryVec &table) const noexcept
 Checks whether an object is in the database or not. More...
 
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. More...
 
bool save_commodity (gnc_commodity *comm) noexcept
 Ensure that a commodity referenced in another object is in fact saved in the database. More...
 
QofBook * book () const noexcept
 
void set_loading (bool loading) noexcept
 
bool pristine () const noexcept
 
void update_progress (double pct) const noexcept
 
void finish_progress () const noexcept
 
- Public Member Functions inherited from QofBackend
 QofBackend (const QofBackend &)=delete
 
 QofBackend (const QofBackend &&)=delete
 
virtual void export_coa (QofBook *)
 Extract the chart of accounts from the current database and create a new database with it. More...
 
void set_error (QofBackendError err)
 Set the error value only if there isn't already an error already.
 
QofBackendError get_error ()
 Retrieve the currently-stored error and clear it.
 
bool check_error ()
 Report if there is an error.
 
void set_message (std::string &&)
 Set a descriptive message that can be displayed to the user when there's an error.
 
const std::string && get_message ()
 Retrieve and clear the stored error message.
 
void set_percentage (QofBePercentageFunc pctfn)
 Store and retrieve a backend-specific function for determining the progress in completing a long operation, for use with a progress meter.
 
QofBePercentageFunc get_percentage ()
 
const std::string & get_uri ()
 Retrieve the backend's storage URI.
 

Additional Inherited Members

- Static Public Member Functions inherited from QofBackend
static bool register_backend (const char *, const char *)
 Class methods for dynamically loading the several backends and for freeing them at shutdown.
 
static void release_backends ()
 
- Protected Attributes inherited from GncSqlBackend
GncSqlConnectionm_conn = nullptr
 SQL connection.
 
QofBook * m_book = nullptr
 The primary, main open book.
 
bool m_loading
 We are performing an initial load.
 
bool m_in_query
 We are processing a query.
 
bool m_is_pristine_db
 Are we saving to a new pristine db?
 
const char * m_time_format = nullptr
 Server-specific date-time string format.
 
VersionVec m_versions
 Version number for each table.
 
- Protected Attributes inherited from QofBackend
QofBePercentageFunc m_percentage
 
std::string m_fullpath
 Each backend resolves a fully-qualified file path. More...
 

Detailed Description

template<DbType Type>
class GncDbiBackend< Type >

Definition at line 89 of file gnc-backend-dbi.hpp.

Member Function Documentation

◆ load()

template<DbType Type>
void GncDbiBackend< Type >::load ( QofBook *  ,
QofBackendLoadType   
)
overridevirtual

Load the minimal set of application data needed for the application to be operable at initial startup.

It is assumed that the application will perform a 'run_query()' to obtain any additional data that it needs. For file-based backends, it is acceptable for the backend to return all data at load time; for SQL-based backends, it is acceptable for the backend to return no data.

Thus, for example, the old GnuCash postgres backend returned the account tree, all currencies, and the pricedb, as these were needed at startup. It did not have to return any transactions whatsoever, as these were obtained at a later stage when a user opened a register, resulting in a query being sent to the backend. The current DBI backend on the other hand loads the entire database into memory.

(Its OK to send over entities at this point, but one should be careful of the network load; also, its possible that whatever is sent is not what the user wanted anyway, which is why its better to wait for the query).

Implements QofBackend.

Definition at line 868 of file gnc-backend-dbi.cpp.

869 {
870  g_return_if_fail (book != nullptr);
871 
872  ENTER ("dbi_be=%p, book=%p", this, book);
873 
874  if (loadType == LOAD_TYPE_INITIAL_LOAD)
875  {
876 
877  // Set up table version information
879  assert (m_book == nullptr);
880  create_tables();
881  }
882 
883  GncSqlBackend::load(book, loadType);
884 
885  if (Type == DbType::DBI_SQLITE)
886  gnc_features_set_used(book, GNC_FEATURE_SQLITE3_ISO_DATES);
887 
888  if (GNUCASH_RESAVE_VERSION > get_table_version("Gnucash"))
889  {
890  /* The database was loaded with an older database schema or
891  * data semantics. In order to ensure consistency, the whole
892  * thing needs to be saved anew. */
894  }
895  else if (GNUCASH_RESAVE_VERSION < get_table_version("Gnucash-Resave"))
896  {
897  /* Worse, the database was created with a newer version. We
898  * can't safely write to this database, so the user will have
899  * to do a "save as" to make one that we can write to.
900  */
902  }
903 
904 
905  LEAVE ("");
906 }
void gnc_features_set_used(QofBook *book, const gchar *feature)
Indicate that the current book uses the given feature.
Definition: gnc-features.c:135
database is old and needs upgrading
Definition: qofbackend.h:113
void create_tables() noexcept
Create/update all tables in the database.
void load(QofBook *, QofBackendLoadType) override
Load the contents of an SQL database into a book.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
database is newer, we can&#39;t write to it
Definition: qofbackend.h:114
QofBook * m_book
The primary, main open book.
void init_version_info() noexcept
Initializes DB table version information.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
uint_t get_table_version(const std::string &table_name) const noexcept
Returns the version number for a DB table.
void set_error(QofBackendError err)
Set the error value only if there isn&#39;t already an error already.
Definition: qof-backend.cpp:59

◆ safe_sync()

template<DbType Type>
void GncDbiBackend< Type >::safe_sync ( QofBook *  book)
overridevirtual

Safely resave a database by renaming all of its tables, recreating everything, and then dropping the backup tables only if there were no errors.

If there are errors, drop the new tables and restore the originals.

Parameters
bookQofBook to be saved in the database.

Implements QofBackend.

Definition at line 952 of file gnc-backend-dbi.cpp.

953 {
954  auto conn = dynamic_cast<GncDbiSqlConnection*>(m_conn);
955 
956  g_return_if_fail (conn != nullptr);
957  g_return_if_fail (book != nullptr);
958 
959  ENTER ("book=%p, primary=%p", book, m_book);
960  if (!conn->begin_transaction())
961  {
962  LEAVE("Failed to obtain a transaction.");
963  return;
964  }
965  if (!conn->table_operation (TableOpType::backup))
966  {
967  conn->rollback_transaction();
968  LEAVE ("Failed to rename tables");
969  return;
970  }
971  if (!conn->drop_indexes())
972  {
973  conn->rollback_transaction();
974  LEAVE ("Failed to drop indexes");
975  return;
976  }
977 
978  sync(m_book);
979  if (check_error())
980  {
981  conn->rollback_transaction();
982  LEAVE ("Failed to create new database tables");
983  return;
984  }
985  conn->table_operation (TableOpType::drop_backup);
986  conn->commit_transaction();
987  LEAVE ("book=%p", m_book);
988 }
GncSqlConnection * m_conn
SQL connection.
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
void sync(QofBook *) override
Save the contents of a book to an SQL database.
QofBook * m_book
The primary, main open book.
Encapsulate a libdbi dbi_conn connection.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
bool check_error()
Report if there is an error.
Definition: qof-backend.cpp:76

◆ session_begin() [1/2]

template<DbType Type>
void GncDbiBackend< Type >::session_begin ( QofSession *  session,
const char *  new_uri,
SessionOpenMode  mode 
)
overridevirtual

Open the file or connect to the server.

Parameters
sessionThe QofSession that will control the backend.
new_uriThe location of the data store that the backend will use.
modeThe session open mode. See qof_session_begin().

Implements QofBackend.

Definition at line 642 of file gnc-backend-dbi.cpp.

644 {
645  GncDbiTestResult dbi_test_result = GNC_DBI_PASS;
646  PairVec options;
647 
648  g_return_if_fail (session != nullptr);
649  g_return_if_fail (new_uri != nullptr);
650 
651  ENTER (" ");
652 
653  /* Split the book-id
654  * Format is protocol://username:password@hostname:port/dbname
655  where username, password and port are optional) */
656  UriStrings uri(new_uri);
657 
658  if (Type == DbType::DBI_PGSQL)
659  {
660  if (uri.m_portnum == 0)
661  uri.m_portnum = PGSQL_DEFAULT_PORT;
662  /* Postgres's SQL interface coerces identifiers to lower case, but the
663  * C interface is case-sensitive. This results in a mixed-case dbname
664  * being created (with a lower case name) but then dbi can't connect to
665  * it. To work around this, coerce the name to lowercase first. */
666  auto lcname = g_utf8_strdown (uri.dbname(), -1);
667  uri.m_dbname = std::string{lcname};
668  g_free(lcname);
669  }
670  connect(nullptr);
671 
672  bool create{mode == SESSION_NEW_STORE || mode == SESSION_NEW_OVERWRITE};
673  auto conn = conn_setup(options, uri);
674  if (conn == nullptr)
675  {
676  LEAVE("Error");
677  return;
678  }
679 
680  m_exists = true; //May be unset in the error handler.
681  auto result = dbi_conn_connect (conn);
682  if (result == 0)
683  {
684  if (Type == DbType::DBI_MYSQL)
685  adjust_sql_options (conn);
686  if(!conn_test_dbi_library(conn))
687  {
688  dbi_conn_close(conn);
689  LEAVE("Error");
690  return;
691  }
692  bool create = (mode == SESSION_NEW_STORE ||
693  mode == SESSION_NEW_OVERWRITE);
694  if (create && save_may_clobber_data<Type>(conn, uri.quote_dbname(Type)))
695  {
696  if (mode == SESSION_NEW_OVERWRITE)
697  {
698  if (!drop_database<Type>(conn, uri))
699  return;
700  }
701  else
702  {
704  PWARN ("Database already exists, Might clobber it.");
705  dbi_conn_close(conn);
706  LEAVE("Error");
707  return;
708  }
709  /* Drop successful. */
710  m_exists = false;
711  }
712 
713  }
714  else if (m_exists)
715  {
716  PERR ("Unable to connect to database '%s'\n", uri.dbname());
718  dbi_conn_close(conn);
719  LEAVE("Error");
720  return;
721  }
722  else if (!create)
723  {
724  PERR ("Database '%s' does not exist\n", uri.dbname());
726  std::string msg{"Database "};
727  set_message(msg + uri.dbname() + " not found");
728  LEAVE("Error");
729  return;
730  }
731 
732  if (create)
733  {
734  if (!m_exists &&
735  !create_database(conn, uri.quote_dbname(Type).c_str()))
736  {
737  dbi_conn_close(conn);
738  LEAVE("Error");
739  return;
740  }
741  conn = conn_setup(options, uri);
742  result = dbi_conn_connect (conn);
743  if (result < 0)
744  {
745  PERR ("Unable to create database '%s'\n", uri.dbname());
747  dbi_conn_close(conn);
748  LEAVE("Error");
749  return;
750  }
751  if (Type == DbType::DBI_MYSQL)
752  adjust_sql_options (conn);
753  if (!conn_test_dbi_library(conn))
754  {
755  if (Type == DbType::DBI_PGSQL)
756  dbi_conn_select_db (conn, "template1");
757  dbi_conn_queryf (conn, "DROP DATABASE %s",
758  uri.quote_dbname(Type).c_str());
759  dbi_conn_close(conn);
760  return;
761  }
762  }
763 
764  connect(nullptr);
765  try
766  {
767  connect(new GncDbiSqlConnection(Type, this, conn, mode));
768  }
769  catch (std::runtime_error& err)
770  {
771  return;
772  }
773  /* We should now have a proper session set up.
774  * Let's start logging */
775  auto translog_path = gnc_build_translog_path (uri.basename().c_str());
776  xaccLogSetBaseName (translog_path);
777  PINFO ("logpath=%s", translog_path ? translog_path : "(null)");
778  g_free (translog_path);
779 
780  LEAVE (" ");
781 }
void set_message(std::string &&)
Set a descriptive message that can be displayed to the user when there&#39;s an error.
Definition: qof-backend.cpp:82
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
Create a new store at the URI.
Definition: qofsession.h:126
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
error in response from server
Definition: qofbackend.h:71
gchar * gnc_build_translog_path(const gchar *filename)
Make a path to filename in the translog subdirectory of the user&#39;s configuration directory.
the named database doesn&#39;t exist
Definition: qofbackend.h:63
Encapsulate a libdbi dbi_conn connection.
File exists, data would be destroyed.
Definition: qofbackend.h:67
void xaccLogSetBaseName(const char *basepath)
The xaccLogSetBaseName() method sets the base filepath and the root part of the journal file name...
Definition: TransLog.c:119
void connect(GncSqlConnection *conn) noexcept
Connect the backend to a GncSqlConnection.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
void set_error(QofBackendError err)
Set the error value only if there isn&#39;t already an error already.
Definition: qof-backend.cpp:59
Open will fail if the URI doesn&#39;t exist or is locked.
Definition: qofsession.h:124

◆ session_begin() [2/2]

template<>
void GncDbiBackend< DbType::DBI_SQLITE >::session_begin ( QofSession *  session,
const char *  new_uri,
SessionOpenMode  mode 
)
virtual

Open the file or connect to the server.

Parameters
sessionThe QofSession that will control the backend.
new_uriThe location of the data store that the backend will use.
modeThe session open mode. See qof_session_begin().

Implements QofBackend.

Definition at line 361 of file gnc-backend-dbi.cpp.

364 {
365  gboolean file_exists;
366  PairVec options;
367 
368  g_return_if_fail (session != nullptr);
369  g_return_if_fail (new_uri != nullptr);
370 
371  ENTER (" ");
372 
373  /* Remove uri type if present */
374  auto path = gnc_uri_get_path (new_uri);
375  std::string filepath{path};
376  g_free(path);
377  GFileTest ftest = static_cast<decltype (ftest)> (
378  G_FILE_TEST_IS_REGULAR | G_FILE_TEST_EXISTS) ;
379  file_exists = g_file_test (filepath.c_str(), ftest);
380  bool create{mode == SESSION_NEW_STORE || mode == SESSION_NEW_OVERWRITE};
381  if (!create && !file_exists)
382  {
384  std::string msg{"Sqlite3 file "};
385  set_message (msg + filepath + " not found");
386  PWARN ("Sqlite3 file %s not found", filepath.c_str());
387  LEAVE("Error");
388  return;
389  }
390 
391  if (create && file_exists)
392  {
393  if (mode == SESSION_NEW_OVERWRITE)
394  g_unlink (filepath.c_str());
395  else
396  {
398  auto msg = "Might clobber, mode not SESSION_NEW_OVERWRITE";
399  PWARN ("%s", msg);
400  LEAVE("Error");
401  return;
402  }
403  }
404 
405  connect(nullptr);
406  /* dbi-sqlite3 documentation says that sqlite3 doesn't take a "host" option */
407  options.push_back(std::make_pair("host", "localhost"));
408  auto dirname = g_path_get_dirname (filepath.c_str());
409  auto basename = g_path_get_basename (filepath.c_str());
410  options.push_back(std::make_pair("dbname", basename));
411  options.push_back(std::make_pair("sqlite3_dbdir", dirname));
412  if (basename != nullptr) g_free (basename);
413  if (dirname != nullptr) g_free (dirname);
414  UriStrings uri;
415  auto conn = conn_setup(options, uri);
416  if (conn == nullptr)
417  {
418  LEAVE("Error");
419  return;
420  }
421 
422  auto result = dbi_conn_connect (conn);
423 
424  if (result < 0)
425  {
426  dbi_conn_close(conn);
427  PERR ("Unable to connect to %s: %d\n", new_uri, result);
429  LEAVE("Error");
430  return;
431  }
432 
433  if (!conn_test_dbi_library(conn))
434  {
435  if (create && !file_exists)
436  {
437  /* File didn't exist before, but it does now, and we don't want to
438  * leave it lying around.
439  */
440  dbi_conn_close (conn);
441  conn = nullptr;
442  g_unlink (filepath.c_str());
443  }
444  dbi_conn_close(conn);
445  LEAVE("Bad DBI Library");
446  return;
447  }
448 
449  try
450  {
451  connect(new GncDbiSqlConnection(DbType::DBI_SQLITE,
452  this, conn, mode));
453  }
454  catch (std::runtime_error& err)
455  {
456  return;
457  }
458 
459  /* We should now have a proper session set up.
460  * Let's start logging */
461  xaccLogSetBaseName (filepath.c_str());
462  PINFO ("logpath=%s", filepath.c_str() ? filepath.c_str() : "(null)");
463  LEAVE ("");
464 }
not found / no such file
Definition: qofbackend.h:92
void set_message(std::string &&)
Set a descriptive message that can be displayed to the user when there&#39;s an error.
Definition: qof-backend.cpp:82
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
gchar * gnc_uri_get_path(const gchar *uri)
Extracts the path part from a uri.
Can&#39;t parse url.
Definition: qofbackend.h:62
Create a new store at the URI.
Definition: qofsession.h:126
#define PERR(format, args...)
Log a serious error.
Definition: qoflog.h:244
#define ENTER(format, args...)
Print a function entry debugging message.
Definition: qoflog.h:272
#define PWARN(format, args...)
Log a warning.
Definition: qoflog.h:250
Encapsulate a libdbi dbi_conn connection.
File exists, data would be destroyed.
Definition: qofbackend.h:67
void xaccLogSetBaseName(const char *basepath)
The xaccLogSetBaseName() method sets the base filepath and the root part of the journal file name...
Definition: TransLog.c:119
void connect(GncSqlConnection *conn) noexcept
Connect the backend to a GncSqlConnection.
#define LEAVE(format, args...)
Print a function exit debugging message.
Definition: qoflog.h:282
void set_error(QofBackendError err)
Set the error value only if there isn&#39;t already an error already.
Definition: qof-backend.cpp:59
Open will fail if the URI doesn&#39;t exist or is locked.
Definition: qofsession.h:124

The documentation for this class was generated from the following files: