The SOCI backend for SQLite does not support binding 64 bit integer
values because statement::describe_column is missing the relevant type
comparison. I have added it.
cheers,
Sören
//
// Copyright (C) 2004-2006 Maciej Sobczak, Stephen Hutton, David Courtney
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
#include "soci-sqlite3.h"
// std
#include <algorithm>
#include <sstream>
#include <string>
#ifdef _MSC_VER
#pragma warning(disable:4355)
#endif
using namespace soci;
using namespace soci::details;
using namespace sqlite_api;
sqlite3_statement_backend::sqlite3_statement_backend(
sqlite3_session_backend &session)
: session_(session), stmt_(0), dataCache_(), useData_(0),
databaseReady_(false), boundByName_(false), boundByPos_(false)
{
}
void sqlite3_statement_backend::alloc()
{
// ...
}
void sqlite3_statement_backend::clean_up()
{
if (stmt_)
{
sqlite3_finalize(stmt_);
stmt_ = 0;
databaseReady_ = false;
}
}
void sqlite3_statement_backend::prepare(std::string const & query,
statement_type /* eType */)
{
clean_up();
char const* tail = 0; // unused;
int res = sqlite3_prepare(session_.conn_,
query.c_str(),
static_cast<int>(query.size()),
&stmt_,
&tail);
if (res != SQLITE_OK)
{
char const* zErrMsg = sqlite3_errmsg(session_.conn_);
std::ostringstream ss;
ss << "sqlite3_statement_backend::prepare: "
<< zErrMsg;
throw soci_error(ss.str());
}
databaseReady_ = true;
}
// sqlite3_reset needs to be called before a prepared statment can
// be executed a second time.
void sqlite3_statement_backend::resetIfNeeded()
{
if (stmt_ && databaseReady_ == false)
{
int res = sqlite3_reset(stmt_);
if (SQLITE_OK == res)
{
databaseReady_ = true;
}
}
}
// This is used by bulk operations
statement_backend::exec_fetch_result
sqlite3_statement_backend::loadRS(int totalRows)
{
statement_backend::exec_fetch_result retVal = ef_success;
int numCols = -1;
int i = 0;
if (!databaseReady_)
{
retVal = ef_no_data;
}
else
{
// make the vector big enough to hold the data we need
dataCache_.resize(totalRows);
for (i = 0; i < totalRows && databaseReady_; ++i)
{
int res = sqlite3_step(stmt_);
if (SQLITE_DONE == res)
{
databaseReady_ = false;
retVal = ef_no_data;
break;
}
else if (SQLITE_ROW == res)
{
// only need to set the number of columns once
if (-1 == numCols)
{
numCols = sqlite3_column_count(stmt_);
for (sqlite3_recordset::iterator it = dataCache_.begin();
it != dataCache_.end(); ++it)
{
(*it).resize(numCols);
}
}
for (int c = 0; c < numCols; ++c)
{
char const* buf = reinterpret_cast<char const*>(
sqlite3_column_text(stmt_, c));
bool isNull = false;
if (0 == buf)
{
isNull = true;
buf = "";
}
dataCache_[i][c].data_ = buf;
dataCache_[i][c].isNull_ = isNull;
}
}
else
{
clean_up();
char const* zErrMsg = sqlite3_errmsg(session_.conn_);
std::ostringstream ss;
ss << "sqlite3_statement_backend::loadRS: "
<< zErrMsg;
throw soci_error(ss.str());
}
}
}
// if we read less than requested then shrink the vector
dataCache_.resize(i);
return retVal;
}
// This is used for non-bulk operations
statement_backend::exec_fetch_result
sqlite3_statement_backend::loadOne()
{
statement_backend::exec_fetch_result retVal = ef_success;
int res = sqlite3_step(stmt_);
if (SQLITE_DONE == res)
{
databaseReady_ = false;
retVal = ef_no_data;
}
else if (SQLITE_ROW == res)
{
}
else
{
clean_up();
char const* zErrMsg = sqlite3_errmsg(session_.conn_);
std::ostringstream ss;
ss << "sqlite3_statement_backend::loadOne: "
<< zErrMsg;
throw soci_error(ss.str());
}
return retVal;
}
// Execute statements once for every row of useData
statement_backend::exec_fetch_result
sqlite3_statement_backend::bindAndExecute(int number)
{
statement_backend::exec_fetch_result retVal = ef_no_data;
int rows = static_cast<int>(useData_.size());
for (int row = 0; row < rows; ++row)
{
sqlite3_reset(stmt_);
int totalPositions = static_cast<int>(useData_[0].size());
for (int pos = 1; pos <= totalPositions; ++pos)
{
int bindRes = SQLITE_OK;
const sqlite3_column& curCol = useData_[row][pos-1];
if (curCol.isNull_)
{
bindRes = sqlite3_bind_null(stmt_, pos);
}
else if (curCol.blobBuf_)
{
bindRes = sqlite3_bind_blob(stmt_, pos,
curCol.blobBuf_,
curCol.blobSize_,
SQLITE_STATIC);
}
else
{
bindRes = sqlite3_bind_text(stmt_, pos,
curCol.data_.c_str(),
static_cast<int>(curCol.data_.length()),
SQLITE_STATIC);
}
if (SQLITE_OK != bindRes)
{
throw soci_error("Failure to bind on bulk operations");
}
}
// Handle the case where there are both into and use elements
// in the same query and one of the into binds to a vector object.
if (1 == rows && number != rows)
{
return loadRS(number);
}
retVal = loadOne(); //execute each bound line
}
return retVal;
}
statement_backend::exec_fetch_result
sqlite3_statement_backend::execute(int number)
{
if (stmt_ == NULL)
{
throw soci_error("No sqlite statement created");
}
sqlite3_reset(stmt_);
databaseReady_ = true;
statement_backend::exec_fetch_result retVal = ef_no_data;
if (useData_.empty() == false)
{
retVal = bindAndExecute(number);
}
else
{
if (1 == number)
{
retVal = loadOne();
}
else
{
retVal = loadRS(number);
}
}
return retVal;
}
statement_backend::exec_fetch_result
sqlite3_statement_backend::fetch(int number)
{
return loadRS(number);
}
int sqlite3_statement_backend::get_number_of_rows()
{
return static_cast<int>(dataCache_.size());
}
std::string sqlite3_statement_backend::rewrite_for_procedure_call(
std::string const &query)
{
return query;
}
int sqlite3_statement_backend::prepare_for_describe()
{
return sqlite3_column_count(stmt_);
}
void sqlite3_statement_backend::describe_column(int colNum, data_type & type,
std::string & columnName)
{
columnName = sqlite3_column_name(stmt_, colNum-1);
// This is a hack, but the sqlite3 type system does not
// have a date or time field. Also it does not reliably
// id other data types. It has a tendency to see everything
// as text. sqlite3_column_decltype returns the text that is
// used in the create table statement
bool typeFound = false;
char const* declType = sqlite3_column_decltype(stmt_, colNum-1);
if ( declType == NULL )
{
static char const* s_char = "char";
declType = s_char;
}
std::string dt = declType;
// do all comparisons in lower case
std::transform(dt.begin(), dt.end(), dt.begin(), tolower);
if (dt.find("bigint", 0) != std::string::npos) // SME watch the order
of comparisons here! "int" is included in "bigint" !
{
type = dt_long_long;
typeFound = true;
}
else if (dt.find("int", 0) != std::string::npos)
{
type = dt_integer;
typeFound = true;
}
else if (dt.find("float", 0) != std::string::npos)
{
type = dt_double;
typeFound = true;
}
else if (dt.find("text", 0) != std::string::npos)
{
type = dt_string;
typeFound = true;
}
else if (dt.find("char", 0) != std::string::npos)
{
type = dt_string;
typeFound = true;
}
else if (dt.find("boolean", 0) != std::string::npos)
{
type = dt_integer;
typeFound = true;
}
else if (dt.find("time", 0) != std::string::npos)
{
type = dt_date;
typeFound = true;
}
else if (dt.find("date", 0) != std::string::npos)
{
type = dt_date;
typeFound = true;
}
if (typeFound)
{
return;
}
// try to get it from the weak ass type system
// total hack - execute the statment once to get the column types
// then clear so it can be executed again
sqlite3_step(stmt_);
int sqlite3_type = sqlite3_column_type(stmt_, colNum-1);
switch (sqlite3_type)
{
case SQLITE_INTEGER: type = dt_integer; break;
case SQLITE_FLOAT: type = dt_double; break;
case SQLITE_BLOB:
case SQLITE_TEXT: type = dt_string; break;
default: type = dt_string; break;
}
sqlite3_reset(stmt_);
}
sqlite3_standard_into_type_backend *
sqlite3_statement_backend::make_into_type_backend()
{
return new sqlite3_standard_into_type_backend(*this);
}
sqlite3_standard_use_type_backend *
sqlite3_statement_backend::make_use_type_backend()
{
return new sqlite3_standard_use_type_backend(*this);
}
sqlite3_vector_into_type_backend *
sqlite3_statement_backend::make_vector_into_type_backend()
{
return new sqlite3_vector_into_type_backend(*this);
}
sqlite3_vector_use_type_backend *
sqlite3_statement_backend::make_vector_use_type_backend()
{
return new sqlite3_vector_use_type_backend(*this);
}
------------------------------------------------------------------------------
Increase Visibility of Your 3D Game App & Earn a Chance To Win $500!
Tap into the largest installed PC base & get more eyes on your game by
optimizing for Intel(R) Graphics Technology. Get started today with the
Intel(R) Software Partner Program. Five $500 cash prizes are up for grabs.
http://p.sf.net/sfu/intelisp-dev2dev
_______________________________________________
Soci-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/soci-users