GnuCash  5.6-150-g038405b370+
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 88 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 862 of file gnc-backend-dbi.cpp.

863 {
864  g_return_if_fail (book != nullptr);
865 
866  ENTER ("dbi_be=%p, book=%p", this, book);
867 
868  if (loadType == LOAD_TYPE_INITIAL_LOAD)
869  {
870 
871  // Set up table version information
873  assert (m_book == nullptr);
874  create_tables();
875  }
876 
877  GncSqlBackend::load(book, loadType);
878 
879  if (Type == DbType::DBI_SQLITE)
880  gnc_features_set_used(book, GNC_FEATURE_SQLITE3_ISO_DATES);
881 
882  if (GNUCASH_RESAVE_VERSION > get_table_version("Gnucash"))
883  {
884  /* The database was loaded with an older database schema or
885  * data semantics. In order to ensure consistency, the whole
886  * thing needs to be saved anew. */
888  }
889  else if (GNUCASH_RESAVE_VERSION < get_table_version("Gnucash-Resave"))
890  {
891  /* Worse, the database was created with a newer version. We
892  * can't safely write to this database, so the user will have
893  * to do a "save as" to make one that we can write to.
894  */
896  }
897 
898 
899  LEAVE ("");
900 }
void gnc_features_set_used(QofBook *book, const gchar *feature)
Indicate that the current book uses the given feature.
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:56

◆ 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 946 of file gnc-backend-dbi.cpp.

947 {
948  auto conn = dynamic_cast<GncDbiSqlConnection*>(m_conn);
949 
950  g_return_if_fail (conn != nullptr);
951  g_return_if_fail (book != nullptr);
952 
953  ENTER ("book=%p, primary=%p", book, m_book);
954  if (!conn->begin_transaction())
955  {
956  LEAVE("Failed to obtain a transaction.");
957  return;
958  }
959  if (!conn->table_operation (TableOpType::backup))
960  {
961  conn->rollback_transaction();
962  LEAVE ("Failed to rename tables");
963  return;
964  }
965  if (!conn->drop_indexes())
966  {
967  conn->rollback_transaction();
968  LEAVE ("Failed to drop indexes");
969  return;
970  }
971 
972  sync(m_book);
973  if (check_error())
974  {
975  conn->rollback_transaction();
976  LEAVE ("Failed to create new database tables");
977  return;
978  }
979  conn->table_operation (TableOpType::drop_backup);
980  conn->commit_transaction();
981  LEAVE ("book=%p", m_book);
982 }
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:73

◆ 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 637 of file gnc-backend-dbi.cpp.

639 {
640  PairVec options;
641 
642  g_return_if_fail (session != nullptr);
643  g_return_if_fail (new_uri != nullptr);
644 
645  ENTER (" ");
646 
647  /* Split the book-id
648  * Format is protocol://username:password@hostname:port/dbname
649  where username, password and port are optional) */
650  UriStrings uri(new_uri);
651 
652  if (Type == DbType::DBI_PGSQL)
653  {
654  if (uri.m_portnum == 0)
655  uri.m_portnum = PGSQL_DEFAULT_PORT;
656  /* Postgres's SQL interface coerces identifiers to lower case, but the
657  * C interface is case-sensitive. This results in a mixed-case dbname
658  * being created (with a lower case name) but then dbi can't connect to
659  * it. To work around this, coerce the name to lowercase first. */
660  auto lcname = g_utf8_strdown (uri.dbname(), -1);
661  uri.m_dbname = std::string{lcname};
662  g_free(lcname);
663  }
664  connect(nullptr);
665 
666  bool create{mode == SESSION_NEW_STORE || mode == SESSION_NEW_OVERWRITE};
667  auto conn = conn_setup(options, uri);
668  if (conn == nullptr)
669  {
670  LEAVE("Error");
671  return;
672  }
673 
674  m_exists = true; //May be unset in the error handler.
675  auto result = dbi_conn_connect (conn);
676  if (result == 0)
677  {
678  if (Type == DbType::DBI_MYSQL)
679  adjust_sql_options (conn);
680  if(!conn_test_dbi_library(conn))
681  {
682  dbi_conn_close(conn);
683  LEAVE("Error");
684  return;
685  }
686  bool create = (mode == SESSION_NEW_STORE ||
687  mode == SESSION_NEW_OVERWRITE);
688  if (create && save_may_clobber_data<Type>(conn, uri.quote_dbname(Type)))
689  {
690  if (mode == SESSION_NEW_OVERWRITE)
691  {
692  if (!drop_database<Type>(conn, uri))
693  return;
694  }
695  else
696  {
698  PWARN ("Database already exists, Might clobber it.");
699  dbi_conn_close(conn);
700  LEAVE("Error");
701  return;
702  }
703  /* Drop successful. */
704  m_exists = false;
705  }
706 
707  }
708  else if (m_exists)
709  {
710  PERR ("Unable to connect to database '%s'\n", uri.dbname());
712  dbi_conn_close(conn);
713  LEAVE("Error");
714  return;
715  }
716  else if (!create)
717  {
718  PERR ("Database '%s' does not exist\n", uri.dbname());
720  std::string msg{"Database "};
721  set_message(msg + uri.dbname() + " not found");
722  LEAVE("Error");
723  return;
724  }
725 
726  if (create)
727  {
728  if (!m_exists &&
729  !create_database(conn, uri.quote_dbname(Type).c_str()))
730  {
731  dbi_conn_close(conn);
732  LEAVE("Error");
733  return;
734  }
735  conn = conn_setup(options, uri);
736  result = dbi_conn_connect (conn);
737  if (result < 0)
738  {
739  PERR ("Unable to create database '%s'\n", uri.dbname());
741  dbi_conn_close(conn);
742  LEAVE("Error");
743  return;
744  }
745  if (Type == DbType::DBI_MYSQL)
746  adjust_sql_options (conn);
747  if (!conn_test_dbi_library(conn))
748  {
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);
754  return;
755  }
756  }
757 
758  connect(nullptr);
759  try
760  {
761  connect(new GncDbiSqlConnection(Type, this, conn, mode));
762  }
763  catch (std::runtime_error& err)
764  {
765  return;
766  }
767  /* We should now have a proper session set up.
768  * Let's start logging */
769  auto translog_path = gnc_build_translog_path (uri.basename().c_str());
770  xaccLogSetBaseName (translog_path);
771  PINFO ("logpath=%s", translog_path ? translog_path : "(null)");
772  g_free (translog_path);
773 
774  LEAVE (" ");
775 }
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:79
#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.cpp: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:56
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 356 of file gnc-backend-dbi.cpp.

359 {
360  gboolean file_exists;
361  PairVec options;
362 
363  g_return_if_fail (session != nullptr);
364  g_return_if_fail (new_uri != nullptr);
365 
366  ENTER (" ");
367 
368  /* Remove uri type if present */
369  auto path = gnc_uri_get_path (new_uri);
370  std::string filepath{path};
371  g_free(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);
375  bool create{mode == SESSION_NEW_STORE || mode == SESSION_NEW_OVERWRITE};
376  if (!create && !file_exists)
377  {
379  std::string msg{"Sqlite3 file "};
380  set_message (msg + filepath + " not found");
381  PWARN ("Sqlite3 file %s not found", filepath.c_str());
382  LEAVE("Error");
383  return;
384  }
385 
386  if (create && file_exists)
387  {
388  if (mode == SESSION_NEW_OVERWRITE)
389  g_unlink (filepath.c_str());
390  else
391  {
393  auto msg = "Might clobber, mode not SESSION_NEW_OVERWRITE";
394  PWARN ("%s", msg);
395  LEAVE("Error");
396  return;
397  }
398  }
399 
400  connect(nullptr);
401  /* dbi-sqlite3 documentation says that sqlite3 doesn't take a "host" option */
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);
409  UriStrings uri;
410  auto conn = conn_setup(options, uri);
411  if (conn == nullptr)
412  {
413  LEAVE("Error");
414  return;
415  }
416 
417  auto result = dbi_conn_connect (conn);
418 
419  if (result < 0)
420  {
421  dbi_conn_close(conn);
422  PERR ("Unable to connect to %s: %d\n", new_uri, result);
424  LEAVE("Error");
425  return;
426  }
427 
428  if (!conn_test_dbi_library(conn))
429  {
430  if (create && !file_exists)
431  {
432  /* File didn't exist before, but it does now, and we don't want to
433  * leave it lying around.
434  */
435  dbi_conn_close (conn);
436  conn = nullptr;
437  g_unlink (filepath.c_str());
438  }
439  dbi_conn_close(conn);
440  LEAVE("Bad DBI Library");
441  return;
442  }
443 
444  try
445  {
446  connect(new GncDbiSqlConnection(DbType::DBI_SQLITE,
447  this, conn, mode));
448  }
449  catch (std::runtime_error& err)
450  {
451  return;
452  }
453 
454  /* We should now have a proper session set up.
455  * Let's start logging */
456  xaccLogSetBaseName (filepath.c_str());
457  PINFO ("logpath=%s", filepath.c_str() ? filepath.c_str() : "(null)");
458  LEAVE ("");
459 }
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:79
#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.cpp: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:56
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: