GnuCash  5.6-150-g038405b370+
gnc-price-sql.cpp
1 /********************************************************************
2  * gnc-price-sql.c: load and save data to SQL *
3  * *
4  * This program is free software; you can redistribute it and/or *
5  * modify it under the terms of the GNU General Public License as *
6  * published by the Free Software Foundation; either version 2 of *
7  * the License, or (at your option) any later version. *
8  * *
9  * This program is distributed in the hope that it will be useful, *
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12  * GNU General Public License for more details. *
13  * *
14  * You should have received a copy of the GNU General Public License*
15  * along with this program; if not, contact: *
16  * *
17  * Free Software Foundation Voice: +1-617-542-5942 *
18  * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
19  * Boston, MA 02110-1301, USA gnu@gnu.org *
20 \********************************************************************/
28 #include <glib.h>
29 
30 #include <config.h>
31 
32 #include "qof.h"
33 #include "gnc-pricedb.h"
34 
35 #if defined( S_SPLINT_S )
36 #include "splint-defs.h"
37 #endif
38 
39 #include "gnc-sql-connection.hpp"
40 #include "gnc-sql-backend.hpp"
41 #include "gnc-sql-object-backend.hpp"
42 #include "gnc-sql-column-table-entry.hpp"
43 #include "gnc-commodity-sql.h"
44 #include "gnc-price-sql.h"
45 #include "gnc-slots-sql.h"
46 
47 
48 static QofLogModule log_module = G_LOG_DOMAIN;
49 
50 #define TABLE_NAME "prices"
51 #define TABLE_VERSION 3
52 
53 #define PRICE_MAX_SOURCE_LEN 2048
54 #define PRICE_MAX_TYPE_LEN 2048
55 
56 static const EntryVec col_table
57 ({
58  gnc_sql_make_table_entry<CT_GUID>("guid", 0, COL_NNUL | COL_PKEY, "guid"),
59  gnc_sql_make_table_entry<CT_COMMODITYREF>("commodity_guid", 0, COL_NNUL,
60  "commodity"),
61  gnc_sql_make_table_entry<CT_COMMODITYREF>("currency_guid", 0, COL_NNUL,
62  "currency"),
63  gnc_sql_make_table_entry<CT_TIME>("date", 0, COL_NNUL, "date"),
64  gnc_sql_make_table_entry<CT_STRING>("source", PRICE_MAX_SOURCE_LEN, 0,
65  "source"),
66  gnc_sql_make_table_entry<CT_STRING>("type", PRICE_MAX_TYPE_LEN, 0, "type"),
67  gnc_sql_make_table_entry<CT_NUMERIC>("value", 0, COL_NNUL, "value")
68 });
69 
70 GncSqlPriceBackend::GncSqlPriceBackend() :
71  GncSqlObjectBackend(TABLE_VERSION, GNC_ID_PRICE,
72  TABLE_NAME, col_table) {}
73 
74 /* ================================================================= */
75 
76 static GNCPrice*
77 load_single_price (GncSqlBackend* sql_be, GncSqlRow& row)
78 {
79  GNCPrice* pPrice;
80 
81  g_return_val_if_fail (sql_be != NULL, NULL);
82 
83  pPrice = gnc_price_create (sql_be->book());
84 
85  gnc_price_begin_edit (pPrice);
86  gnc_sql_load_object (sql_be, row, GNC_ID_PRICE, pPrice, col_table);
87  gnc_price_commit_edit (pPrice);
88 
89  return pPrice;
90 }
91 
92 void
94 {
95  QofBook* pBook;
96  GNCPriceDB* pPriceDB;
97 
98  g_return_if_fail (sql_be != NULL);
99 
100  pBook = sql_be->book();
101  pPriceDB = gnc_pricedb_get_db (pBook);
102  std::string sql("SELECT * FROM " TABLE_NAME);
103  auto stmt = sql_be->create_statement_from_sql(sql);
104  if (stmt != nullptr)
105  {
106  auto result = sql_be->execute_select_statement(stmt);
107  if (result->begin() == result->end())
108  return;
109 
110  GNCPrice* pPrice;
111 
112  gnc_pricedb_set_bulk_update (pPriceDB, TRUE);
113  for (auto row : *result)
114  {
115  pPrice = load_single_price (sql_be, row);
116 
117  if (pPrice != NULL)
118  {
119  (void)gnc_pricedb_add_price (pPriceDB, pPrice);
120  gnc_price_unref (pPrice);
121  }
122  }
123  gnc_pricedb_set_bulk_update (pPriceDB, FALSE);
124  std::string pkey(col_table[0]->name());
125  sql = "SELECT DISTINCT ";
126  sql += pkey + " FROM " TABLE_NAME;
128  (BookLookupFn)gnc_price_lookup);
129  }
130 }
131 
132 /* ================================================================= */
133 void
135 {
136  gint version;
137 
138  g_return_if_fail (sql_be != NULL);
139 
140  version = sql_be->get_table_version( TABLE_NAME);
141  if (version == 0)
142  {
143  (void)sql_be->create_table(TABLE_NAME, TABLE_VERSION, col_table);
144  }
145  else if (version < m_version)
146  {
147  /*
148  1->2: Upgrade 64 bit int handling
149  2->3: Use DATETIME instead of TIMESTAMP in MySQL
150  */
151  sql_be->upgrade_table(TABLE_NAME, col_table);
152  sql_be->set_table_version (TABLE_NAME, TABLE_VERSION);
153 
154  PINFO ("Prices table upgraded from version 1 to version %d\n", TABLE_VERSION);
155  }
156 }
157 
158 /* ================================================================= */
159 
160 bool
162 {
163  GNCPrice* pPrice = GNC_PRICE (inst);
164  E_DB_OPERATION op;
165  gboolean is_infant;
166  gboolean is_ok = TRUE;
167 
168  g_return_val_if_fail (sql_be != NULL, FALSE);
169  g_return_val_if_fail (inst != NULL, FALSE);
170  g_return_val_if_fail (GNC_IS_PRICE (inst), FALSE);
171 
172  is_infant = qof_instance_get_infant (inst);
173  if (qof_instance_get_destroying (inst))
174  {
175  op = OP_DB_DELETE;
176  }
177  else if (sql_be->pristine() || is_infant)
178  {
179  op = OP_DB_INSERT;
180  }
181  else
182  {
183  op = OP_DB_UPDATE;
184  }
185 
186  if (op != OP_DB_DELETE)
187  {
188  /* Ensure commodity and currency are in the db */
189  (void)sql_be->save_commodity(gnc_price_get_commodity(pPrice));
190  is_ok = sql_be->save_commodity(gnc_price_get_currency(pPrice));
191  }
192 
193  if (is_ok)
194  {
195  is_ok = sql_be->do_db_operation(op, TABLE_NAME, GNC_ID_PRICE, pPrice,
196  col_table);
197  }
198 
199  return is_ok;
200 }
201 
202 static gboolean
203 write_price (GNCPrice* p, gpointer data)
204 {
205  auto s = reinterpret_cast<write_objects_t*>(data);
206 
207  g_return_val_if_fail (p != NULL, FALSE);
208  g_return_val_if_fail (data != NULL, FALSE);
209 
210  if (s->is_ok && gnc_price_get_source (p) != PRICE_SOURCE_TEMP)
211  {
212  s->commit (QOF_INSTANCE(p));
213  }
214 
215  return s->is_ok;
216 }
217 
218 bool
220 {
221  g_return_val_if_fail (sql_be != NULL, FALSE);
222  write_objects_t data{sql_be, true, this};
223 
224  auto priceDB = gnc_pricedb_get_db (sql_be->book());
225  return gnc_pricedb_foreach_price (priceDB, write_price, &data, TRUE);
226 }
227 
228 /* ========================== END OF FILE ===================== */
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.
GNCPrice * gnc_price_create(QofBook *book)
gnc_price_create - returns a newly allocated and initialized price with a reference count of 1...
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.
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...
a simple price database for gnucash
#define G_LOG_DOMAIN
Functions providing the SX List as a plugin page.
#define PINFO(format, args...)
Print an informational note.
Definition: qoflog.h:256
load and save data to SQL
load and save accounts data to SQL
void gnc_price_unref(GNCPrice *p)
gnc_price_unref - indicate you&#39;re finished with a price (i.e.
gboolean qof_instance_get_destroying(gconstpointer ptr)
Retrieve the flag that indicates whether or not this object is about to be destroyed.
gboolean gnc_pricedb_add_price(GNCPriceDB *db, GNCPrice *p)
Add a price to the pricedb.
load and save data to SQL
GNCPriceDB * gnc_pricedb_get_db(QofBook *book)
Return the pricedb associated with the book.
bool commit(GncSqlBackend *sql_be, QofInstance *inst) override
UPDATE/INSERT a single instance of m_type_name into the database.
void load_all(GncSqlBackend *) override
Load all objects of m_type in the database into memory.
bool save_commodity(gnc_commodity *comm) noexcept
Ensure that a commodity referenced in another object is in fact saved in the database.
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.
Encapsulates per-class table schema with functions to load, create a table, commit a changed front-en...
void create_tables(GncSqlBackend *) override
Conditionally create or update a database table from m_col_table.
Data-passing struct for callbacks to qof_object_foreach() used in GncSqlObjectBackend::write().
bool write(GncSqlBackend *) override
Write all objects of m_type_name to the database.
void gnc_pricedb_set_bulk_update(GNCPriceDB *db, gboolean bulk_update)
Set flag to indicate whether duplication checks should be performed.
gboolean gnc_pricedb_foreach_price(GNCPriceDB *db, GncPriceForeachFunc f, gpointer user_data, gboolean stable_order)
Call a GncPriceForeachFunction once for each price in db, until the function returns FALSE...
uint_t get_table_version(const std::string &table_name) const noexcept
Returns the version number for a DB table.
Main SQL backend structure.