GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-dbiproviderimpl.hpp
1/************************************************************************
2 * gnc-dbiproviderimpl.hpp: Encapsulate differences among Dbi backends. *
3 * *
4 * Copyright 2016 John Ralls <jralls@ceridwen.us> *
5 * *
6 * This program is free software; you can redistribute it and/or *
7 * modify it under the terms of the GNU General Public License as *
8 * published by the Free Software Foundation; either version 2 of *
9 * the License, or (at your option) any later version. *
10 * *
11 * This program is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program; if not, contact: *
18 * *
19 * Free Software Foundation Voice: +1-617-542-5942 *
20 * 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
21 * Boston, MA 02110-1301, USA gnu@gnu.org *
22\***********************************************************************/
23#ifndef __GNC_DBISQLPROVIDERIMPL_HPP__
24#define __GNC_DBISQLPROVIDERIMPL_HPP__
25#include <guid.hpp>
26#include <config.h>
27
28#include <string>
29#include <algorithm>
30#include <vector>
31
32#include "gnc-backend-dbi.hpp"
33#include "gnc-dbiprovider.hpp"
34#include "gnc-backend-dbi.h"
35#include <gnc-sql-column-table-entry.hpp>
36
37using StrVec = std::vector<std::string>;
38
39template <DbType T>
41{
42public:
43 StrVec get_table_list(dbi_conn conn, const std::string& table);
44 void append_col_def(std::string& ddl, const GncSqlColumnInfo& info);
45 StrVec get_index_list (dbi_conn conn);
46 void drop_index(dbi_conn conn, const std::string& index);
47};
48
49template <DbType T> GncDbiProviderPtr
50make_dbi_provider()
51{
52 return GncDbiProviderPtr(new GncDbiProviderImpl<T>);
53}
54
55template<> void
57 const GncSqlColumnInfo& info)
58{
59 const char* type_name = nullptr;
60
61 if (info.m_type == BCT_INT)
62 {
63 type_name = "integer";
64 }
65 else if (info.m_type == BCT_INT64)
66 {
67 type_name = "bigint";
68 }
69 else if (info.m_type == BCT_DOUBLE)
70 {
71 type_name = "float8";
72 }
73 else if (info.m_type == BCT_STRING || info.m_type == BCT_DATE
74 || info.m_type == BCT_DATETIME)
75 {
76 type_name = "text";
77 }
78 else
79 {
80 PERR ("Unknown column type: %d\n", info.m_type);
81 type_name = "";
82 }
83 ddl += (info.m_name + " " + type_name);
84 if (info.m_size != 0)
85 {
86 ddl += "(" + std::to_string(info.m_size) + ")";
87 }
88 if (info.m_primary_key)
89 {
90 ddl += " PRIMARY KEY";
91 }
92 if (info.m_autoinc)
93 {
94 ddl += " AUTOINCREMENT";
95 }
96 if (info.m_not_null)
97 {
98 ddl += " NOT NULL";
99 }
100}
101
102
103template<> void
105 const GncSqlColumnInfo& info)
106{
107 const char* type_name = nullptr;
108
109 if (info.m_type == BCT_INT)
110 {
111 type_name = "integer";
112 }
113 else if (info.m_type == BCT_INT64)
114 {
115 type_name = "bigint";
116 }
117 else if (info.m_type == BCT_DOUBLE)
118 {
119 type_name = "double";
120 }
121 else if (info.m_type == BCT_STRING)
122 {
123 type_name = "varchar";
124 }
125 else if (info.m_type == BCT_DATE)
126 {
127 type_name = "date";
128 }
129 else if (info.m_type == BCT_DATETIME)
130 {
131 type_name = "DATETIME NULL DEFAULT '1970-01-01 00:00:00'";
132 }
133 else
134 {
135 PERR ("Unknown column type: %d\n", info.m_type);
136 type_name = "";
137 }
138 ddl += info.m_name + " " + type_name;
139 if (info.m_size != 0 && info.m_type == BCT_STRING)
140 {
141 ddl += "(" + std::to_string(info.m_size) + ")";
142 }
143 if (info.m_unicode)
144 {
145 ddl += " CHARACTER SET utf8";
146 }
147 if (info.m_primary_key)
148 {
149 ddl += " PRIMARY KEY";
150 }
151 if (info.m_autoinc)
152 {
153 ddl += " AUTO_INCREMENT";
154 }
155 if (info.m_not_null)
156 {
157 ddl += " NOT NULL";
158 }
159}
160
161
162template<> void
164 const GncSqlColumnInfo& info)
165{
166 const char* type_name = nullptr;
167
168 if (info.m_type == BCT_INT)
169 {
170 if (info.m_autoinc)
171 {
172 type_name = "serial";
173 }
174 else
175 {
176 type_name = "integer";
177 }
178 }
179 else if (info.m_type == BCT_INT64)
180 {
181 type_name = "int8";
182 }
183 else if (info.m_type == BCT_DOUBLE)
184
185 {
186 type_name = "double precision";
187 }
188 else if (info.m_type == BCT_STRING)
189 {
190 type_name = "varchar";
191 }
192 else if (info.m_type == BCT_DATE)
193 {
194 type_name = "date";
195 }
196 else if (info.m_type == BCT_DATETIME)
197 {
198 type_name = "timestamp without time zone";
199 }
200 else
201 {
202 PERR ("Unknown column type: %d\n", info.m_type);
203 type_name = "";
204 }
205 ddl += info.m_name + " " + type_name;
206 if (info.m_size != 0 && info.m_type == BCT_STRING)
207 {
208 ddl += "(" + std::to_string(info.m_size) + ")";
209 }
210 if (info.m_primary_key)
211 {
212 ddl += " PRIMARY KEY";
213 }
214 if (info.m_not_null)
215 {
216 ddl += " NOT NULL";
217 }
218}
219
220static StrVec
221conn_get_table_list (dbi_conn conn, const std::string& dbname,
222 const std::string& table)
223{
224 StrVec retval;
225 const char* tableptr = (table.empty() ? nullptr : table.c_str());
226 auto tables = dbi_conn_get_table_list (conn, dbname.c_str(), tableptr);
227 while (dbi_result_next_row (tables) != 0)
228 {
229 std::string table_name {dbi_result_get_string_idx (tables, 1)};
230 retval.push_back(table_name);
231 }
232 dbi_result_free (tables);
233 return retval;
234}
235
236template<> StrVec
238 const std::string& table)
239{
240 /* Return the list, but remove the tables that sqlite3 adds for
241 * its own use. */
242 std::string dbname (dbi_conn_get_option (conn, "dbname"));
243 auto list = conn_get_table_list (conn, dbname, table);
244 auto end = std::remove(list.begin(), list.end(), "sqlite_sequence");
245 list.erase(end, list.end());
246 return list;
247}
248
249template<> StrVec
251 const std::string& table)
252{
253 std::string dbname (dbi_conn_get_option (conn, "dbname"));
254 dbname.insert((std::string::size_type)0, 1, '`');
255 dbname += '`';
256 return conn_get_table_list (conn, dbname, table);
257}
258
259template<> StrVec
261 const std::string& table)
262{
263 const char* query_no_regex = "SELECT relname FROM pg_class WHERE relname"
264 "!~ '^(pg|sql)_' AND relkind = 'r' ORDER BY relname";
265 std::string query_with_regex = "SELECT relname FROM pg_class WHERE relname LIKE '";
266 query_with_regex += table + "' AND relkind = 'r' ORDER BY relname";
267 dbi_result result;
268 if (table.empty())
269 result = dbi_conn_query (conn, query_no_regex);
270 else
271 result = dbi_conn_query (conn, query_with_regex.c_str());
272
273 StrVec list;
274 const char* errmsg;
275 if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE)
276 {
277 PWARN ("Table List Retrieval Error: %s\n", errmsg);
278 return list;
279 }
280
281 while (dbi_result_next_row (result) != 0)
282 {
283 std::string index_name {dbi_result_get_string_idx (result, 1)};
284 list.push_back(index_name);
285 }
286 dbi_result_free (result);
287 return list;
288}
289
290template<> StrVec
292{
293 StrVec retval;
294 const char* errmsg;
295 dbi_result result = dbi_conn_query (conn,
296 "SELECT name FROM sqlite_master WHERE type = 'index' AND name NOT LIKE 'sqlite_autoindex%'");
297 if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE)
298 {
299 PWARN ("Index Table Retrieval Error: %s\n", errmsg);
300 return retval;
301 }
302 while (dbi_result_next_row (result) != 0)
303 {
304 std::string index_name {dbi_result_get_string_idx (result, 1)};
305 retval.push_back(index_name);
306 }
307 dbi_result_free (result);
308 return retval;
309}
310
311template<> StrVec
313{
314 StrVec retval;
315 const char* errmsg;
316 auto tables = get_table_list(conn, "");
317 for (auto table_name : tables)
318 {
319 auto result = dbi_conn_queryf (conn,
320 "SHOW INDEXES IN %s WHERE Key_name != 'PRIMARY'",
321 table_name.c_str());
322 if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE)
323 {
324 PWARN ("Index Table Retrieval Error: %s on table %s\n",
325 errmsg, table_name.c_str());
326 continue;
327 }
328
329 while (dbi_result_next_row (result) != 0)
330 {
331 std::string index_name {dbi_result_get_string_idx (result, 3)};
332 retval.push_back(index_name + " " + table_name);
333 }
334 dbi_result_free (result);
335 }
336
337 return retval;
338}
339
340template<> StrVec
342{
343 StrVec retval;
344 const char* errmsg;
345 PINFO ("Retrieving postgres index list\n");
346 auto result = dbi_conn_query (conn,
347 "SELECT relname FROM pg_class AS a INNER JOIN pg_index AS b ON (b.indexrelid = a.oid) INNER JOIN pg_namespace AS c ON (a.relnamespace = c.oid) WHERE reltype = '0' AND indisprimary = 'f' AND nspname = 'public'");
348 if (dbi_conn_error (conn, &errmsg) != DBI_ERROR_NONE)
349 {
350 PWARN("Index Table Retrieval Error: %s\n", errmsg);
351 return retval;
352 }
353 while (dbi_result_next_row (result) != 0)
354 {
355 std::string index_name {dbi_result_get_string_idx (result, 1)};
356 retval.push_back(index_name);
357 }
358 dbi_result_free (result);
359 return retval;
360}
361
362template <DbType P> void
363GncDbiProviderImpl<P>::drop_index(dbi_conn conn, const std::string& index)
364{
365 dbi_result result = dbi_conn_queryf (conn, "DROP INDEX %s", index.c_str());
366 if (result)
367 dbi_result_free (result);
368}
369
370template<> void
371GncDbiProviderImpl<DbType::DBI_MYSQL>::drop_index (dbi_conn conn, const std::string& index)
372{
373
374 auto sep = index.find(' ', 0);
375 if (index.find(' ', sep + 1) != std::string::npos)
376 {
377 PWARN("Drop index error: invalid MySQL index format (<index> <table>): %s",
378 index.c_str());
379 return;
380 }
381
382 auto result = dbi_conn_queryf (conn, "DROP INDEX %s ON %s",
383 index.substr(0, sep).c_str(),
384 index.substr(sep + 1).c_str());
385 if (result)
386 dbi_result_free (result);
387}
388#endif //__GNC_DBISQLPROVIDERIMPL_HPP__
load and save data to SQL via libdbi
#define PINFO(format, args...)
Print an informational note.
Definition qoflog.h:256
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244
#define PWARN(format, args...)
Log a warning.
Definition qoflog.h:250
information required to create a column in a table.