backend/wbpublic/sqlide/sqlide_generics.h (337 lines of code) (raw):
/*
* Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0,
* as published by the Free Software Foundation.
*
* This program is designed to work with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms, as
* designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an additional
* permission to link the program and your derivative works with the
* separately licensed software that they have either included with
* the program or referenced in the documentation.
* 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, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _SQLIDE_GENERICS_H_
#define _SQLIDE_GENERICS_H_
#include "wbpublic_public_interface.h"
#include <sqlite/result.hpp>
#include <sqlite/connection.hpp>
#include <limits>
#include <ctime>
#include <base/string_utilities.h>
#include <sstream>
namespace sqlide {
using namespace sqlite;
class WBPUBLICBACKEND_PUBLIC_FUNC VarEq : public boost::static_visitor<bool> {
public:
VarEq() {
}
template <typename T>
result_type operator()(const null_t &v1, const T &v2) const {
return false;
}
template <typename T>
result_type operator()(const T &v1, const null_t &v2) const {
return false;
}
result_type operator()(const null_t &v1, const null_t &v2) const {
return true;
}
template <class T>
result_type cmp(const unknown_t &v1, const T &v2) const {
return false;
}
template <class T>
result_type cmp(const T &v1, const unknown_t &v2) const {
return false;
}
result_type operator()(const unknown_t &v1, const unknown_t &v2) const {
return false;
}
template <class T1, class T2>
result_type operator()(const T1 &v1, const T2 &v2) const {
return false;
}
template <typename T>
result_type operator()(const T &v1, const T &v2) const {
return v1 == v2;
}
};
class WBPUBLICBACKEND_PUBLIC_FUNC VarConvBase : public boost::static_visitor<std::string> {
public:
VarConvBase() {
_ss.precision(std::numeric_limits<long double>::digits10);
}
protected:
class StateKeeper {
public:
inline StateKeeper(VarConvBase *obj) : _obj(obj) {
}
inline ~StateKeeper() {
_obj->reset();
}
private:
VarConvBase *_obj;
};
friend class StateKeeper;
mutable std::stringstream _ss;
inline void reset() {
_ss.str("");
}
};
class WBPUBLICBACKEND_PUBLIC_FUNC VarToStr : public VarConvBase {
public:
VarToStr() : VarConvBase(), is_truncation_enabled(false), truncation_threshold(std::string::npos) {
}
bool is_truncation_enabled;
std::string::size_type truncation_threshold;
result_type operator()(const unknown_t &v) const {
return "";
}
result_type operator()(const null_t &v) const {
return "";
}
result_type operator()(const blob_ref_t &v) const {
// if (is_truncation_enabled)
return "...";
// else
// throw std::runtime_error("Can't convert BLOB to string value");
}
result_type operator()(const std::string &v) const {
return (is_truncation_enabled && (truncation_threshold < v.size()))
? base::truncate_text(v, (int)truncation_threshold)
: v;
}
template <typename T>
result_type operator()(const T &v) const {
StateKeeper sk(const_cast<VarConvBase *>((const VarConvBase *)this));
_ss << v;
return _ss.str();
}
};
class WBPUBLICBACKEND_PUBLIC_FUNC VarCast : public boost::static_visitor<variant_t> {
public:
result_type operator()(const null_t &t, const std::string &v) {
return t;
}
result_type operator()(const unknown_t &t, const std::string &v) {
return v;
}
result_type operator()(const blob_ref_t &t, const std::string &v) {
blob_ref_t res(new blob_t());
res->reserve(v.size());
std::copy(v.begin(), v.end(), std::back_inserter(*res));
return res;
}
result_type operator()(const std::string &t, const std::string &v) {
return v;
}
template <typename T>
result_type operator()(const T &t, const std::string &v) {
T res;
std::stringstream ss(v);
ss.precision(std::numeric_limits<long double>::digits10);
ss >> res;
return res;
}
template <typename T>
result_type operator()(const T &t, const T &v) {
return v;
}
result_type operator()(const null_t &t, const null_t &v) {
return v;
}
template <typename T>
result_type operator()(const T &t, const null_t &v) {
return v;
}
template <typename T, typename V>
result_type operator()(const T &t, const V &v) {
return t;
//! throw std::runtime_error("Conversion for types pair is not implemented");
}
};
class VarToInt : public boost::static_visitor<std::int64_t> {
public:
result_type operator()(const int &v) const {
return v;
}
result_type operator()(const std::int64_t &v) const {
return v;
}
result_type operator()(const null_t &v) const {
return 0;
}
template <typename T>
result_type operator()(const T &v) const {
return -1;
//! throw std::runtime_error(std::string("Variant: wrong type: '")+typeid(T).name()+"' instead of
//! '"+typeid(result_type).name()+"'");
}
};
class VarToBool : public boost::static_visitor<bool> {
public:
result_type operator()(const bool &v) const {
return v;
}
result_type operator()(const null_t &v) const {
return false;
}
template <typename T>
result_type operator()(const T &v) const {
return false;
//! throw std::runtime_error(std::string("Variant: wrong type: '")+typeid(T).name()+"' instead of
//! '"+typeid(result_type).name()+"'");
}
};
class WBPUBLICBACKEND_PUBLIC_FUNC VarToLongDouble : public boost::static_visitor<long double> {
public:
result_type operator()(const long double &v) const {
return v;
}
result_type operator()(const int &v) const {
return v;
}
result_type operator()(const std::int64_t &v) const {
return (long double)v;
}
result_type operator()(const null_t &v) const {
return 0;
}
template <typename T>
result_type operator()(const T &v) const {
return -1;
//! throw std::runtime_error(std::string("Variant: wrong type: '")+typeid(T).name()+"' instead of
//! '"+typeid(result_type).name()+"'");
}
};
class WBPUBLICBACKEND_PUBLIC_FUNC QuoteVar : public VarConvBase {
public:
QuoteVar() : quote("'"), store_unknown_as_string(true), allow_func_escaping(false), bitMode(false), needQuote(true) {
}
typedef std::function<std::string(const std::string &)> Escape_sql_string;
Escape_sql_string escape_string;
std::string quote;
typedef std::function<std::string(const unsigned char *, size_t)> Blob_to_string;
Blob_to_string blob_to_string;
bool store_unknown_as_string;
bool allow_func_escaping;
bool bitMode;
bool needQuote;
static std::string escape_ansi_sql_string(const std::string &text) // used by sqlite
{
std::string escaped;
std::string::size_type p, s, len = text.length();
// escapes '
p = 0;
s = 0;
while (p < len) {
switch (text[p]) {
case '\'':
if (p > s)
escaped.append(text.substr(s, p - s));
escaped.append("\'");
escaped.append(text.substr(p, 1));
s = p + 1;
break;
}
p++;
}
if (p > s)
escaped.append(text.substr(s));
return escaped;
}
static std::string blob_to_hex_string(const unsigned char *data, size_t size) {
static const char hex_dig[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
std::string out(size * 2 + 2, ' ');
std::string::iterator p = out.begin();
*p++ = '0';
*p++ = 'x';
for (const unsigned char *d = data, *end = d + size; d < end; ++d) {
*p++ = hex_dig[*d >> 4];
*p++ = hex_dig[*d & 0x0F];
}
return out;
}
result_type operator()(const unknown_t &, const std::string &v) const {
static std::string t;
return store_unknown_as_string ? operator()(t, v) : v;
}
template <typename T>
result_type operator()(const T &, const unknown_t &) const {
return "";
}
template <typename T>
result_type operator()(const T &, const null_t &) const {
return "NULL";
}
template <typename T>
result_type operator()(const T &x, const std::string &v) const {
if (allow_func_escaping) {
//! temporary convention to allow function call as a cell value
// escape sequnce "\func " at start denotes the rest of the value is actual value and it should go unquoted
// to enter "\func " value as literal user will have to enter "\\func "
static const std::string func_call_seq = "\\func ";
static const std::string func_call_exc = "\\\\func ";
if (!v.empty() && (v[0] == '\\')) {
if ((v.size() > func_call_seq.size()) && (v.compare(0, func_call_seq.size(), func_call_seq) == 0))
return v.substr(func_call_seq.size());
else if ((v.size() > func_call_exc.size()) && (v.compare(0, func_call_exc.size(), func_call_exc) == 0))
return (needQuote ? ((bitMode ? "b" : "" ) + quote) : "") + escape_string(v.substr(1)) + (needQuote ? quote : "");
}
}
return (needQuote ? ((bitMode ? "b" : "" ) + quote) : "") + escape_string(v) + (needQuote ? quote : "");
}
template <typename T>
result_type operator()(const T &, const blob_ref_t &v) const {
return !blob_to_string ? "?" /*bind variable placeholder*/ : blob_to_string(&(*v)[0], v->size());
}
result_type operator()(const blob_ref_t &, const blob_ref_t &v) const {
return !blob_to_string ? "?" /*bind variable placeholder*/ : blob_to_string(&(*v)[0], v->size());
}
result_type operator()(const blob_ref_t &, const std::string &v) const {
return !blob_to_string ? "?" /*bind variable placeholder*/ : blob_to_string((const unsigned char *)v.data(),
v.size());
}
result_type operator()(const blob_ref_t &, const null_t &) const {
return !blob_to_string ? "?" /*bind variable placeholder*/ : "NULL";
}
template <typename T, typename V>
result_type operator()(const T &, const V &v) const {
StateKeeper sk(const_cast<VarConvBase *>((const VarConvBase *)this));
_ss << v;
return _ss.str();
}
};
class WBPUBLICBACKEND_PUBLIC_FUNC TypeOfVar : public boost::static_visitor<std::string> {
public:
result_type operator()(const long double &v) const {
return "FLOAT";
}
result_type operator()(const int &v) const {
return "INTEGER";
}
result_type operator()(const std::string &v) const {
return "VARCHAR";
}
result_type operator()(const blob_ref_t &v) const {
return "BLOB";
}
template <typename T>
result_type operator()(const T &v) const {
return "VARCHAR";
}
};
WBPUBLICBACKEND_PUBLIC_FUNC bool is_var_null(const sqlite::variant_t &value);
WBPUBLICBACKEND_PUBLIC_FUNC bool is_var_unknown(const sqlite::variant_t &value);
WBPUBLICBACKEND_PUBLIC_FUNC bool is_var_blob(const sqlite::variant_t &value);
WBPUBLICBACKEND_PUBLIC_FUNC void optimize_sqlite_connection_for_speed(sqlite::connection *conn);
class WBPUBLICBACKEND_PUBLIC_FUNC Sqlite_transaction_guarder {
public:
Sqlite_transaction_guarder(sqlite::connection *conn, bool use_immediate = true);
~Sqlite_transaction_guarder();
void commit();
void commit_and_start_new_transaction();
private:
sqlite::connection *_conn;
bool _in_trans;
};
}
typedef size_t RowId;
typedef size_t ColumnId;
typedef std::vector<sqlite::variant_t> Data;
template <typename C>
inline void reinit(C &c) {
C tmp;
c.swap(tmp);
}
template <typename T>
class AutoSwap {
public:
AutoSwap(T &v1, T &v2) : _v1(v1), _v2(v2) {
std::swap(_v1, _v2);
}
~AutoSwap() {
std::swap(_v1, _v2);
}
private:
T &_v1;
T &_v2;
};
// double WBPUBLICBACKEND_PUBLIC_FUNC timestamp();
std::tm WBPUBLICBACKEND_PUBLIC_FUNC local_timestamp();
std::string WBPUBLICBACKEND_PUBLIC_FUNC format_time(const std::tm &t, const char *format = "%H:%M:%S");
std::string WBPUBLICBACKEND_PUBLIC_FUNC current_time(const char *format = "%H:%M:%S");
#endif /* _SQLIDE_GENERICS_H_ */