Permalink
Browse files

Merge pull request #65 from vnaydionov/master

Improve input parameter binding in Firebird backend.
  • Loading branch information...
mloskot committed Feb 13, 2013
2 parents 142e6bf + 7a49b20 commit ab1495fb934075bf7e50fb58ce840a6dd97626d5
@@ -27,10 +27,16 @@ namespace firebird
char * allocBuffer(XSQLVAR* var)
{
std::size_t size;
if ((var->sqltype & ~1) == SQL_VARYING)
int type = var->sqltype & ~1;
if (type == SQL_VARYING)
{
size = var->sqllen + sizeof(short);
}
else if (type == SQL_TIMESTAMP or type == SQL_TYPE_TIME
or type == SQL_TYPE_DATE)
{
size = sizeof(std::tm);
}
else
{
size = var->sqllen;
@@ -84,7 +90,7 @@ void tmDecode(short type, void * src, std::tm * dst)
void setTextParam(char const * s, std::size_t size, char * buf_,
XSQLVAR * var)
{
std::cerr << "setTextParam: var->sqltype=" << var->sqltype << std::endl;
//std::cerr << "setTextParam: var->sqltype=" << var->sqltype << std::endl;
short sz = 0;
if (size < static_cast<std::size_t>(var->sqllen))
{
@@ -110,39 +116,15 @@ void setTextParam(char const * s, std::size_t size, char * buf_,
}
else if ((var->sqltype & ~1) == SQL_SHORT)
{
unsigned short t1;
short t2;
if (!*str2int(s, t1))
std::memcpy(buf_, &t1, sizeof(t1));
else if (!*str2int(s, t2))
std::memcpy(buf_, &t2, sizeof(t2));
else
throw soci_error("Could not parse int16 value.");
to_isc<short>(buf_, var);
parse_decimal<short, unsigned short>(buf_, var, s);
}
else if ((var->sqltype & ~1) == SQL_LONG)
{
unsigned t1;
int t2;
if (!*str2int(s, t1))
std::memcpy(buf_, &t1, sizeof(t1));
else if (!*str2int(s, t2))
std::memcpy(buf_, &t2, sizeof(t2));
else
throw soci_error("Could not parse int32 value.");
to_isc<int>(buf_, var);
parse_decimal<int, unsigned int>(buf_, var, s);
}
else if ((var->sqltype & ~1) == SQL_INT64)
{
unsigned long long t1;
long long t2;
if (!*str2int(s, t1))
std::memcpy(buf_, &t1, sizeof(t1));
else if (!*str2int(s, t2))
std::memcpy(buf_, &t2, sizeof(t2));
else
throw soci_error("Could not parse int64 value.");
to_isc<long long>(buf_, var);
parse_decimal<long long, unsigned long long>(buf_, var, s);
}
else if ((var->sqltype & ~1) == SQL_TIMESTAMP
or (var->sqltype & ~1) == SQL_TYPE_DATE)
@@ -195,7 +177,7 @@ void setTextParam(char const * s, std::size_t size, char * buf_,
std::string getTextParam(XSQLVAR const *var)
{
std::cerr << "getTextParam: var->sqltype=" << var->sqltype << std::endl;
//std::cerr << "getTextParam: var->sqltype=" << var->sqltype << std::endl;
short size;
std::size_t offset = 0;
@@ -38,7 +38,7 @@ void setTextParam(char const * s, std::size_t size, char * buf_,
std::string getTextParam(XSQLVAR const *var);
template <typename IntType>
const char *str2int(const char * s, IntType &out)
const char *str2dec(const char * s, IntType &out, int &scale)
{
int sign = 1;
if ('+' == *s)
@@ -48,9 +48,18 @@ const char *str2int(const char * s, IntType &out)
sign = -1;
++s;
}
scale = 0;
bool period = false;
IntType res = 0;
for (out = 0; *s; ++s, out = res)
{
if (*s == '.')
{
if (period)
return s;
period = true;
continue;
}
int d = *s - '0';
if (d < 0 || d > 9)
return s;
@@ -65,17 +74,19 @@ const char *str2int(const char * s, IntType &out)
if (res > out)
return s;
}
if (period)
++scale;
}
return s;
}
template<typename T1>
void to_isc(void * val, XSQLVAR * var)
void to_isc(void * val, XSQLVAR * var, int x_scale = 0)
{
T1 value = *reinterpret_cast<T1*>(val);
short scale = var->sqlscale;
short scale = var->sqlscale + x_scale;
short type = var->sqltype & ~1;
ISC_INT64 tens = 1;
long long divisor = 1, multiplier = 1;
if ((std::numeric_limits<T1>::is_integer == false) && scale >= 0 &&
(type == SQL_SHORT || type == SQL_LONG || type == SQL_INT64))
@@ -84,27 +95,27 @@ void to_isc(void * val, XSQLVAR * var)
}
for (int i = 0; i > scale; --i)
{
tens *= 10;
}
multiplier *= 10;
for (int i = 0; i < scale; ++i)
divisor *= 10;
switch (var->sqltype & ~1)
switch (type)
{
case SQL_SHORT:
{
short tmp = static_cast<short>(value*tens);
short tmp = static_cast<short>(value*multiplier/divisor);
std::memcpy(var->sqldata, &tmp, sizeof(short));
}
break;
case SQL_LONG:
{
int tmp = static_cast<int>(value*tens);
int tmp = static_cast<int>(value*multiplier/divisor);
std::memcpy(var->sqldata, &tmp, sizeof(int));
}
break;
case SQL_INT64:
{
long long tmp = static_cast<long long>(value*tens);
long long tmp = static_cast<long long>(value*multiplier/divisor);
std::memcpy(var->sqldata, &tmp, sizeof(long long));
}
break;
@@ -125,6 +136,21 @@ void to_isc(void * val, XSQLVAR * var)
}
}
template<typename IntType, typename UIntType>
void parse_decimal(void * val, XSQLVAR * var, const char * s)
{
int scale;
UIntType t1;
IntType t2;
if (!*str2dec(s, t1, scale))
std::memcpy(val, &t1, sizeof(t1));
else if (!*str2dec(s, t2, scale))
std::memcpy(val, &t2, sizeof(t2));
else
throw soci_error("Could not parse decimal value.");
to_isc<IntType>(val, var, scale);
}
template<typename T1>
T1 from_isc(XSQLVAR * var)
{
@@ -287,7 +287,7 @@ void firebird_statement_backend::rewriteQuery(
void firebird_statement_backend::prepare(std::string const & query,
statement_type /* eType */)
{
std::cerr << "prepare: query=" << query << std::endl;
//std::cerr << "prepare: query=" << query << std::endl;
// clear named parametes
names_.clear();
@@ -15,6 +15,7 @@
#include <cassert>
#include <ctime>
#include <cstring>
#include <cmath>
using namespace soci;
@@ -1052,6 +1053,50 @@ void test11()
std::cout << "test 11 passed" << std::endl;
}
void test12()
{
session sql(backEnd, connectString);
try
{
sql << "drop table test12";
}
catch (std::runtime_error &)
{} // ignore if error
sql << "create table test12(a decimal(10,3), b timestamp, c date, d time)";
sql.commit();
sql.begin();
// Check if passing input parameters as strings works
// for different column types.
{
std::string a = "-3.14150", b = "2013-02-28 23:36:01",
c = "2013-02-28", d = "23:36:01";
statement st = (sql.prepare <<
"insert into test12(a, b, c, d) values (?, ?, ?, ?)",
use(a), use(b), use(c), use(d));
st.execute(1);
assert(getRowCount(st, eRowsInserted) == 1);
}
{
double a;
std::tm b, c, d;
sql << "select a, b, c, d from test12",
into(a), into(b), into(c), into(d);
assert(std::fabs(a - (-3.141)) < 0.000001);
assert(b.tm_year + 1900 == 2013 && b.tm_mon + 1 == 2 && b.tm_mday == 28);
assert(b.tm_hour == 23 && b.tm_min == 36 && b.tm_sec == 1);
assert(c.tm_year + 1900 == 2013 && c.tm_mon + 1 == 2 && c.tm_mday == 28);
assert(c.tm_hour == 0 && c.tm_min == 0 && c.tm_sec == 0);
assert(d.tm_hour == 23 && d.tm_min == 36 && d.tm_sec == 1);
}
sql << "drop table test12";
std::cout << "test 12 passed" << std::endl;
}
//
// Support for soci Common Tests
//
@@ -1171,6 +1216,7 @@ int main(int argc, char** argv)
test9();
test10();
test11();
test12();
std::cout << "\nOK, all tests passed.\n\n";

0 comments on commit ab1495f

Please sign in to comment.