GnuCash c935c2f+
Loading...
Searching...
No Matches
gnc-dbisqlresult.cpp
1/********************************************************************
2 * gnc-dbisqlresult.cpp: Encapsulate libdbi dbi_result *
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
24#include <guid.hpp>
25#include <config.h>
26#include <gnc-locale-utils.h>
27#include <dbi/dbi.h>
28/* For direct access to dbi data structs, sadly needed for datetime */
29#include <dbi/dbi-dev.h>
30#include <cmath>
31#include <gnc-datetime.hpp>
32#include "gnc-dbisqlresult.hpp"
33#include "gnc-dbisqlconnection.hpp"
34
35static QofLogModule log_module = G_LOG_DOMAIN;
36
37#if LIBDBI_VERSION >= 900
38#define HAVE_LIBDBI_TO_LONGLONG 1
39#else
40#define HAVE_LIBDBI_TO_LONGLONG 0
41#endif
42
43GncDbiSqlResult::~GncDbiSqlResult()
44{
45 int status = dbi_result_free (m_dbi_result);
46
47 if (status == 0)
48 return;
49
50 PERR ("Error %d in dbi_result_free() result.", m_conn->dberror() );
52}
53
54int
55GncDbiSqlResult::dberror() const noexcept
56{
57 return m_conn->dberror();
58}
59
61GncDbiSqlResult::begin()
62{
63
64 if (m_dbi_result == nullptr ||
65 dbi_result_get_numrows(m_dbi_result) == 0)
66 return m_sentinel;
67 int status = dbi_result_first_row(m_dbi_result);
68 if (status)
69 return m_row;
70 int error = dberror(); //
71
72 if (error != DBI_ERROR_BADIDX) //otherwise just an empty result set
73 {
74 PERR ("Error %d in dbi_result_first_row()", dberror());
76 }
77 return m_sentinel;
78}
79
80uint64_t
81GncDbiSqlResult::size() const noexcept
82{
83 return dbi_result_get_numrows(m_dbi_result);
84}
85/* --------------------------------------------------------- */
86
88GncDbiSqlResult::IteratorImpl::operator++()
89{
90 int status = dbi_result_next_row (m_inst->m_dbi_result);
91 if (status)
92 return m_inst->m_row;
93 int error = m_inst->dberror();
94 if (error == DBI_ERROR_BADIDX || error == 0) //ran off the end of the results
95 return m_inst->m_sentinel;
96 PERR("Error %d incrementing results iterator.", error);
97 qof_backend_set_error (m_inst->m_conn->qbe(), ERR_BACKEND_SERVER_ERR);
98 return m_inst->m_sentinel;
99}
100
101std::optional<int64_t>
102GncDbiSqlResult::IteratorImpl::get_int_at_col(const char* col) const
103{
104 auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col);
105 if(type != DBI_TYPE_INTEGER)
106 return std::nullopt;
107 return std::optional<int64_t>{dbi_result_get_longlong (m_inst->m_dbi_result, col)};
108}
109
110std::optional<double>
111GncDbiSqlResult::IteratorImpl::get_float_at_col(const char* col) const
112{
113 constexpr double float_precision = 1000000.0;
114 auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col);
115 auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col);
116 if(type != DBI_TYPE_DECIMAL ||
117 (attrs & DBI_DECIMAL_SIZEMASK) != DBI_DECIMAL_SIZE4)
118 return std::nullopt;
119 auto locale = gnc_push_locale (LC_NUMERIC, "C");
120 auto interim = dbi_result_get_float(m_inst->m_dbi_result, col);
121 gnc_pop_locale (LC_NUMERIC, locale);
122 double retval = static_cast<double>(round(interim * float_precision)) / float_precision;
123 return std::optional<double>{retval};
124}
125
126std::optional<double>
127GncDbiSqlResult::IteratorImpl::get_double_at_col(const char* col) const
128{
129 auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col);
130 auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col);
131 if(type != DBI_TYPE_DECIMAL ||
132 (attrs & DBI_DECIMAL_SIZEMASK) != DBI_DECIMAL_SIZE8)
133 return std::nullopt;
134 auto locale = gnc_push_locale (LC_NUMERIC, "C");
135 auto retval = dbi_result_get_double(m_inst->m_dbi_result, col);
136 gnc_pop_locale (LC_NUMERIC, locale);
137 return std::optional<double>{retval};
138}
139
140std::optional<std::string>
141GncDbiSqlResult::IteratorImpl::get_string_at_col(const char* col) const
142{
143 auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col);
144 dbi_result_get_field_attribs (m_inst->m_dbi_result, col);
145 if(type != DBI_TYPE_STRING)
146 return std::nullopt;
147 auto strval = dbi_result_get_string(m_inst->m_dbi_result, col);
148 return std::optional<std::string>{strval ? strval : ""};
149}
150
151std::optional<time64>
152GncDbiSqlResult::IteratorImpl::get_time64_at_col (const char* col) const
153{
154 auto result = (dbi_result_t*) (m_inst->m_dbi_result);
155 auto type = dbi_result_get_field_type (result, col);
156 dbi_result_get_field_attribs (result, col);
157 if (type != DBI_TYPE_DATETIME)
158 return std::nullopt;
159#if HAVE_LIBDBI_TO_LONGLONG
160 /* A less evil hack than the one required by libdbi-0.8, but
161 * still necessary to work around the same bug.
162 */
163 auto timeval = dbi_result_get_as_longlong(result, col);
164#else
165 /* A seriously evil hack to work around libdbi bug #15
166 * https://sourceforge.net/p/libdbi/bugs/15/. When libdbi
167 * v0.9 is widely available this can be replaced with
168 * dbi_result_get_as_longlong.
169 * Note: 0.9 is available in Debian Jessie and Fedora 21.
170 */
171 auto row = dbi_result_get_currow (result);
172 auto idx = dbi_result_get_field_idx (result, col) - 1;
173 time64 timeval = result->rows[row]->field_values[idx].d_datetime;
174#endif //HAVE_LIBDBI_TO_LONGLONG
175 if (timeval < MINTIME || timeval > MAXTIME)
176 timeval = 0;
177 return std::optional<time64>(timeval);
178}
179
180
181/* --------------------------------------------------------- */
182
int dberror() const noexcept override
Get the connection error value.
Row of SQL Query results.
void qof_backend_set_error(QofBackend *qof_be, QofBackendError err)
Set the error on the specified QofBackend.
@ ERR_BACKEND_SERVER_ERR
error in response from server
Definition qofbackend.h:71
gint64 time64
Most systems that are currently maintained, including Microsoft Windows, BSD-derived Unixes and Linux...
Definition gnc-date.h:87
#define PERR(format, args...)
Log a serious error.
Definition qoflog.h:244