gnucash/libgnucash/backend/dbi/gnc-dbisqlresult.cpp
John Ralls bf55c30aeb Fix most of the unused assignment errors from static analysis.
There are a very few left that need deeper study, but this gets
rid of most of the noise. For the most part it's just getting rid of
extra variables or removing an assignment that is always
replaced later but before any reads of the variable. A few are
discarded result variables.
2018-11-30 15:08:41 +09:00

190 lines
6.8 KiB
C++

/********************************************************************
* gnc-dbisqlresult.cpp: Encapsulate libdbi dbi_result *
* *
* Copyright 2016 John Ralls <jralls@ceridwen.us> *
* *
* This program is free software; you can redistribute it and/or *
* modify it under the terms of the GNU General Public License as *
* published by the Free Software Foundation; either version 2 of *
* the License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License*
* along with this program; if not, contact: *
* *
* Free Software Foundation Voice: +1-617-542-5942 *
* 51 Franklin Street, Fifth Floor Fax: +1-617-542-2652 *
* Boston, MA 02110-1301, USA gnu@gnu.org *
\********************************************************************/
#include <guid.hpp>
extern "C"
{
#include <config.h>
#include <gnc-locale-utils.h>
#include <dbi/dbi.h>
/* For direct access to dbi data structs, sadly needed for datetime */
#include <dbi/dbi-dev.h>
}
#include <cmath>
#include <gnc-datetime.hpp>
#include "gnc-dbisqlresult.hpp"
#include "gnc-dbisqlconnection.hpp"
static QofLogModule log_module = G_LOG_DOMAIN;
#if LIBDBI_VERSION >= 900
#define HAVE_LIBDBI_TO_LONGLONG 1
#else
#define HAVE_LIBDBI_TO_LONGLONG 0
#endif
GncDbiSqlResult::~GncDbiSqlResult()
{
int status = dbi_result_free (m_dbi_result);
if (status == 0)
return;
PERR ("Error %d in dbi_result_free() result.", m_conn->dberror() );
qof_backend_set_error (m_conn->qbe(), ERR_BACKEND_SERVER_ERR);
}
int
GncDbiSqlResult::dberror() const noexcept
{
return m_conn->dberror();
}
GncSqlRow&
GncDbiSqlResult::begin()
{
if (m_dbi_result == nullptr ||
dbi_result_get_numrows(m_dbi_result) == 0)
return m_sentinel;
int status = dbi_result_first_row(m_dbi_result);
if (status)
return m_row;
int error = dberror(); //
if (error != DBI_ERROR_BADIDX) //otherwise just an empty result set
{
PERR ("Error %d in dbi_result_first_row()", dberror());
qof_backend_set_error (m_conn->qbe(), ERR_BACKEND_SERVER_ERR);
}
return m_sentinel;
}
uint64_t
GncDbiSqlResult::size() const noexcept
{
return dbi_result_get_numrows(m_dbi_result);
}
/* --------------------------------------------------------- */
GncSqlRow&
GncDbiSqlResult::IteratorImpl::operator++()
{
int status = dbi_result_next_row (m_inst->m_dbi_result);
if (status)
return m_inst->m_row;
int error = m_inst->dberror();
if (error == DBI_ERROR_BADIDX || error == 0) //ran off the end of the results
return m_inst->m_sentinel;
PERR("Error %d incrementing results iterator.", error);
qof_backend_set_error (m_inst->m_conn->qbe(), ERR_BACKEND_SERVER_ERR);
return m_inst->m_sentinel;
}
int64_t
GncDbiSqlResult::IteratorImpl::get_int_at_col(const char* col) const
{
auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col);
if(type != DBI_TYPE_INTEGER)
throw (std::invalid_argument{"Requested integer from non-integer column."});
return dbi_result_get_longlong (m_inst->m_dbi_result, col);
}
double
GncDbiSqlResult::IteratorImpl::get_float_at_col(const char* col) const
{
constexpr double float_precision = 1000000.0;
auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col);
auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col);
if(type != DBI_TYPE_DECIMAL ||
(attrs & DBI_DECIMAL_SIZEMASK) != DBI_DECIMAL_SIZE4)
throw (std::invalid_argument{"Requested float from non-float column."});
auto locale = gnc_push_locale (LC_NUMERIC, "C");
auto interim = dbi_result_get_float(m_inst->m_dbi_result, col);
gnc_pop_locale (LC_NUMERIC, locale);
double retval = static_cast<double>(round(interim * float_precision)) / float_precision;
return retval;
}
double
GncDbiSqlResult::IteratorImpl::get_double_at_col(const char* col) const
{
auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col);
auto attrs = dbi_result_get_field_attribs (m_inst->m_dbi_result, col);
if(type != DBI_TYPE_DECIMAL ||
(attrs & DBI_DECIMAL_SIZEMASK) != DBI_DECIMAL_SIZE8)
throw (std::invalid_argument{"Requested double from non-double column."});
auto locale = gnc_push_locale (LC_NUMERIC, "C");
auto retval = dbi_result_get_double(m_inst->m_dbi_result, col);
gnc_pop_locale (LC_NUMERIC, locale);
return retval;
}
std::string
GncDbiSqlResult::IteratorImpl::get_string_at_col(const char* col) const
{
auto type = dbi_result_get_field_type (m_inst->m_dbi_result, col);
dbi_result_get_field_attribs (m_inst->m_dbi_result, col);
if(type != DBI_TYPE_STRING)
throw (std::invalid_argument{"Requested string from non-string column."});
auto strval = dbi_result_get_string(m_inst->m_dbi_result, col);
if (strval == nullptr)
{
throw (std::invalid_argument{"Column empty."});
}
auto retval = std::string{strval};
return retval;
}
time64
GncDbiSqlResult::IteratorImpl::get_time64_at_col (const char* col) const
{
auto result = (dbi_result_t*) (m_inst->m_dbi_result);
auto type = dbi_result_get_field_type (result, col);
dbi_result_get_field_attribs (result, col);
if (type != DBI_TYPE_DATETIME)
throw (std::invalid_argument{"Requested time64 from non-time64 column."});
#if HAVE_LIBDBI_TO_LONGLONG
/* A less evil hack than the one required by libdbi-0.8, but
* still necessary to work around the same bug.
*/
auto retval = dbi_result_get_as_longlong(result, col);
#else
/* A seriously evil hack to work around libdbi bug #15
* https://sourceforge.net/p/libdbi/bugs/15/. When libdbi
* v0.9 is widely available this can be replaced with
* dbi_result_get_as_longlong.
* Note: 0.9 is available in Debian Jessie and Fedora 21.
*/
auto row = dbi_result_get_currow (result);
auto idx = dbi_result_get_field_idx (result, col) - 1;
time64 retval = result->rows[row]->field_values[idx].d_datetime;
#endif //HAVE_LIBDBI_TO_LONGLONG
if (retval < MINTIME || retval > MAXTIME)
retval = 0;
return retval;
}
/* --------------------------------------------------------- */