Skip to content

Commit

Permalink
FIX: ODBC data type precission, and NULL value bindings
Browse files Browse the repository at this point in the history
  • Loading branch information
Karol committed Nov 24, 2023
1 parent bcbb51b commit 105e658
Show file tree
Hide file tree
Showing 17 changed files with 137 additions and 55 deletions.
7 changes: 7 additions & 0 deletions ActiveRecord/include/Poco/ActiveRecord/ActiveRecord.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,13 @@ IDType ActiveRecord<IDType>::lastInsertID(Poco::Data::Session& session, const st
into(id),
now;
}
else if (session.connector() == "ODBC") {
// TODO: Works only with MS SQL, when no row creation trigger is associated with CREATE statement
session
<< "SELECT @@IDENTITY AS ID",
into(id),
now;
}
else
{
throw Poco::NotImplementedException("lastInsertID not implemented for connector", session.connector());
Expand Down
8 changes: 4 additions & 4 deletions Data/MySQL/include/Poco/Data/MySQL/Binder.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ class MySQL_API Binder: public Poco::Data::AbstractBinder
virtual void bind(std::size_t pos, const UUID& val, Direction dir);
/// Binds a UUID.

virtual void bind(std::size_t pos, const NullData& val, Direction dir);
virtual void bind(std::size_t pos, const NullData& val, const std::type_info &type, Direction dir);
/// Binds a null.

virtual void bind(std::size_t pos, const std::vector<Poco::Int8>& val, Direction dir = PD_IN);
Expand Down Expand Up @@ -212,11 +212,11 @@ class MySQL_API Binder: public Poco::Data::AbstractBinder

virtual void bind(std::size_t pos, const std::list<Time>& val, Direction dir = PD_IN);

virtual void bind(std::size_t pos, const std::vector<NullData>& val, Direction dir = PD_IN);
virtual void bind(std::size_t pos, const std::vector<NullData>& val, const std::type_info &type, Direction dir = PD_IN);

virtual void bind(std::size_t pos, const std::deque<NullData>& val, Direction dir = PD_IN);
virtual void bind(std::size_t pos, const std::deque<NullData>& val, const std::type_info &type, Direction dir = PD_IN);

virtual void bind(std::size_t pos, const std::list<NullData>& val, Direction dir = PD_IN);
virtual void bind(std::size_t pos, const std::list<NullData>& val, const std::type_info &type, Direction dir = PD_IN);

virtual void bind(std::size_t pos, const std::vector<std::string>& val, Direction dir = PD_IN);

Expand Down
8 changes: 4 additions & 4 deletions Data/MySQL/src/Binder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ void Binder::bind(std::size_t pos, const UUID& val, Direction dir)
}


void Binder::bind(std::size_t pos, const NullData&, Direction dir)
void Binder::bind(std::size_t pos, const NullData&, const std::type_info &type, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, MYSQL_TYPE_NULL, 0, 0);
Expand Down Expand Up @@ -603,19 +603,19 @@ void Binder::bind(std::size_t pos, const std::list<Poco::Data::Time>& val, Direc
}


void Binder::bind(std::size_t pos, const std::vector<Poco::Data::NullData>& val, Direction dir)
void Binder::bind(std::size_t pos, const std::vector<Poco::Data::NullData>& val, const std::type_info &type, Direction dir)
{
throw NotImplementedException();
}


void Binder::bind(std::size_t pos, const std::deque<Poco::Data::NullData>& val, Direction dir)
void Binder::bind(std::size_t pos, const std::deque<Poco::Data::NullData>& val, const std::type_info &type, Direction dir)
{
throw NotImplementedException();
}


void Binder::bind(std::size_t pos, const std::list<Poco::Data::NullData>& val, Direction dir)
void Binder::bind(std::size_t pos, const std::list<Poco::Data::NullData>& val, const std::type_info &type, Direction dir)
{
throw NotImplementedException();
}
Expand Down
31 changes: 17 additions & 14 deletions Data/ODBC/include/Poco/Data/ODBC/Binder.h
Original file line number Diff line number Diff line change
Expand Up @@ -327,16 +327,16 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder
void bind(std::size_t pos, const UUID& val, Direction dir);
/// Binds a UUID.

void bind(std::size_t pos, const NullData& val, Direction dir);
void bind(std::size_t pos, const NullData& val, const std::type_info &type, Direction dir);
/// Binds a null. In-bound only.

void bind(std::size_t pos, const std::vector<NullData>& val, Direction dir);
void bind(std::size_t pos, const std::vector<NullData>& val, const std::type_info &type, Direction dir);
/// Binds a null vector.

void bind(std::size_t pos, const std::deque<NullData>& val, Direction dir);
void bind(std::size_t pos, const std::deque<NullData>& val, const std::type_info &type, Direction dir);
/// Binds a null deque.

void bind(std::size_t pos, const std::list<NullData>& val, Direction dir);
void bind(std::size_t pos, const std::list<NullData>& val, const std::type_info &type, Direction dir);
/// Binds a null list.

void setDataBinding(ParameterBinding binding);
Expand Down Expand Up @@ -909,7 +909,7 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder
}

template<typename C>
void bindImplNullContainer(std::size_t pos, const C& val, Direction dir)
void bindImplNullContainer(std::size_t pos, const C& val, const std::type_info &type, Direction dir)
{
if (isOutBound(dir) || !isInBound(dir))
throw NotImplementedException("Null container parameter type can only be inbound.");
Expand All @@ -930,15 +930,18 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder
_vecLengthIndicator[pos] = new LengthVec(length ? length : 1);
}

const auto cDataType = Utility::cDataType(type);
const auto sqlDataType = Utility::sqlDataType(cDataType, type);

SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_C_STINYINT, colSize, decDigits);
getColSizeAndPrecision(pos, cDataType, colSize, decDigits);

if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
SQL_PARAM_INPUT,
SQL_C_STINYINT,
Utility::sqlDataType(SQL_C_STINYINT),
cDataType,
sqlDataType,
colSize,
decDigits,
0,
Expand Down Expand Up @@ -1498,21 +1501,21 @@ inline void Binder::bind(std::size_t pos, const std::list<DateTime>& val, Direct
}


inline void Binder::bind(std::size_t pos, const std::vector<NullData>& val, Direction dir)
inline void Binder::bind(std::size_t pos, const std::vector<NullData>& val, const std::type_info &type, Direction dir)
{
bindImplNullContainer(pos, val, dir);
bindImplNullContainer(pos, val, type, dir);
}


inline void Binder::bind(std::size_t pos, const std::deque<NullData>& val, Direction dir)
inline void Binder::bind(std::size_t pos, const std::deque<NullData>& val, const std::type_info &type, Direction dir)
{
bindImplNullContainer(pos, val, dir);
bindImplNullContainer(pos, val, type, dir);
}


inline void Binder::bind(std::size_t pos, const std::list<NullData>& val, Direction dir)
inline void Binder::bind(std::size_t pos, const std::list<NullData>& val, const std::type_info &type, Direction dir)
{
bindImplNullContainer(pos, val, dir);
bindImplNullContainer(pos, val, type, dir);
}


Expand Down
4 changes: 4 additions & 0 deletions Data/ODBC/include/Poco/Data/ODBC/Utility.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,10 @@ class ODBC_API Utility
for (; it != end; ++it, ++tIt) dateTimeSync(*tIt, *it);
}

static int cDataType(const std::type_info &type);

static int sqlDataType(int cDataType, const std::type_info &type);

private:
static const TypeInfo _dataTypes;
/// C <==> SQL data type mapping
Expand Down
17 changes: 9 additions & 8 deletions Data/ODBC/src/Binder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,6 @@ void Binder::bind(std::size_t pos, const Poco::DateTime& val, Direction dir)
}
}


void Binder::bind(std::size_t pos, const UUID& val, Direction dir)
{
SQLINTEGER size = (SQLINTEGER) 16;
Expand Down Expand Up @@ -358,8 +357,7 @@ void Binder::bind(std::size_t pos, const UUID& val, Direction dir)
}
}


void Binder::bind(std::size_t pos, const NullData& val, Direction dir)
void Binder::bind(std::size_t pos, const NullData& val, const std::type_info &type, Direction dir)
{
if (isOutBound(dir) || !isInBound(dir))
throw NotImplementedException("NULL parameter type can only be inbound.");
Expand All @@ -371,15 +369,18 @@ void Binder::bind(std::size_t pos, const NullData& val, Direction dir)

_lengthIndicator.push_back(pLenIn);

const auto cDataType = Utility::cDataType(type);
const auto sqlDataType = Utility::sqlDataType(cDataType, type);

SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_C_STINYINT, colSize, decDigits);

getColSizeAndPrecision(pos, cDataType, colSize, decDigits);
if (Utility::isError(SQLBindParameter(_rStmt,
(SQLUSMALLINT) pos + 1,
SQL_PARAM_INPUT,
SQL_C_STINYINT,
Utility::sqlDataType(SQL_C_STINYINT),
cDataType,
sqlDataType,
colSize,
decDigits,
0,
Expand Down Expand Up @@ -523,7 +524,7 @@ void Binder::getColSizeAndPrecision(std::size_t pos,
throw LengthExceededException(Poco::format("Error binding column %z size=%z, max size=%ld)",
pos, actualSize, static_cast<long>(colSize)));
}
found = _pTypeInfo->tryGetInfo(cDataType, "MINIMUM_SCALE", tmp);
found = _pTypeInfo->tryGetInfo(cDataType, "MAXIMUM_SCALE", tmp);
if (found)
{
decDigits = tmp;
Expand Down
7 changes: 4 additions & 3 deletions Data/ODBC/src/ODBCStatementImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,6 @@ void ODBCStatementImpl::doBind()
Bindings::iterator it = binds.begin();
Bindings::iterator itEnd = binds.end();

if (it != itEnd && 0 == _affectedRowCount)
_affectedRowCount = static_cast<std::size_t>((*it)->numOfRowsHandled());

for (std::size_t pos = 0; it != itEnd && (*it)->canBind(); ++it)
{
(*it)->bind(pos);
Expand Down Expand Up @@ -350,6 +347,10 @@ std::size_t ODBCStatementImpl::next()
pos += (*it)->numOfColumnsHandled();
}
_stepCalled = false;

if (extracts.begin() != extracts.end() && 0 == _affectedRowCount) {
_affectedRowCount += static_cast<int>((*extracts.begin())->numOfRowsHandled());
}
}
else
{
Expand Down
66 changes: 66 additions & 0 deletions Data/ODBC/src/Utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@


#include "Poco/Data/ODBC/Utility.h"
#include "Poco/Data/ODBC/Connector.h"
#include "Poco/Data/ODBC/Handle.h"
#include "Poco/Data/ODBC/ODBCException.h"
#include "Poco/Data/LOB.h"
#include "Poco/NumberFormatter.h"
#include "Poco/DateTime.h"
#include <cmath>
Expand Down Expand Up @@ -155,5 +157,69 @@ void Utility::dateTimeSync(SQL_TIMESTAMP_STRUCT& ts, const Poco::DateTime& dt)
ts.fraction = (dt.millisecond() * 1000000);// + (dt.microsecond() * 1000);
}

int Utility::cDataType(const std::type_info &type)
{
if (type == typeid(std::string))
return SQL_C_CHAR;
else if (type == typeid(Poco::UTF16String))
return SQL_C_WCHAR;
else if (type == typeid(bool))
return SQL_C_BIT;
else if (type == typeid(char))
return SQL_C_STINYINT;
else if (type == typeid(Int8))
return SQL_C_STINYINT;
else if (type == typeid(UInt8))
return SQL_C_UTINYINT;
else if (type == typeid(Int16))
return SQL_C_SSHORT;
else if (type == typeid(UInt16))
return SQL_C_USHORT;
else if (type == typeid(Int32))
return SQL_C_SLONG;
else if (type == typeid(UInt32))
return SQL_C_ULONG;
else if (type == typeid(Int64))
return SQL_C_SBIGINT;
else if (type == typeid(UInt64))
return SQL_C_UBIGINT;
else if (type == typeid(float))
return SQL_C_FLOAT;
else if (type == typeid(double))
return SQL_C_DOUBLE;
else if (type == typeid(DateTime) || type == typeid(Timestamp))
return SQL_C_TYPE_TIMESTAMP;
else if (type == typeid(Date))
return SQL_C_TYPE_DATE;
else if (type == typeid(Time))
return SQL_C_TYPE_TIME;
else if (type == typeid(BLOB) || type == typeid(CLOB))
return SQL_C_BINARY;
else if (type == typeid(BLOB))
return SQL_C_BINARY;
else if (type == typeid(UUID))
return SQL_C_BINARY;
#ifndef POCO_INT64_IS_LONG
else if (type == typeid(long) || type == typeid(unsigned long))
return SQL_C_SLONG;
#endif

throw UnknownTypeException(std::string(type.name()));
}

int Utility::sqlDataType(int cDataType, const std::type_info &type)
{
switch (cDataType) {
case SQL_C_BINARY:
return type == typeid(UUID) ? SQL_GUID : SQL_LONGVARBINARY;
case SQL_C_CHAR:
return Connector::stringBoundToLongVarChar() ? SQL_LONGVARCHAR : SQL_VARCHAR;
case SQL_C_WCHAR:
return SQL_WLONGVARCHAR;
default:
return Utility::sqlDataType(cDataType);
}
}


} } } // namespace Poco::Data::ODBC
8 changes: 4 additions & 4 deletions Data/PostgreSQL/include/Poco/Data/PostgreSQL/Binder.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class PostgreSQL_API Binder: public Poco::Data::AbstractBinder
virtual void bind(std::size_t pos, const UUID& val, Direction dir = PD_IN);
/// Binds a UUID.

virtual void bind(std::size_t pos, const NullData& val, Direction dir = PD_IN);
virtual void bind(std::size_t pos, const NullData& val, const std::type_info &type, Direction dir = PD_IN);
/// Binds a null.

virtual void bind(std::size_t pos, const std::vector<Poco::Int8>& val, Direction dir = PD_IN);
Expand Down Expand Up @@ -216,11 +216,11 @@ class PostgreSQL_API Binder: public Poco::Data::AbstractBinder

virtual void bind(std::size_t pos, const std::list<Time>& val, Direction dir = PD_IN);

virtual void bind(std::size_t pos, const std::vector<NullData>& val, Direction dir = PD_IN);
virtual void bind(std::size_t pos, const std::vector<NullData>& val, const std::type_info &type, Direction dir = PD_IN);

virtual void bind(std::size_t pos, const std::deque<NullData>& val, Direction dir = PD_IN);
virtual void bind(std::size_t pos, const std::deque<NullData>& val, const std::type_info &type, Direction dir = PD_IN);

virtual void bind(std::size_t pos, const std::list<NullData>& val, Direction dir = PD_IN);
virtual void bind(std::size_t pos, const std::list<NullData>& val, const std::type_info &type, Direction dir = PD_IN);

virtual void bind(std::size_t pos, const std::vector<std::string>& val, Direction dir = PD_IN);

Expand Down
8 changes: 4 additions & 4 deletions Data/PostgreSQL/src/Binder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ void Binder::bind(std::size_t pos, const UUID& val, Direction dir)
}


void Binder::bind(std::size_t pos, const NullData&, Direction dir)
void Binder::bind(std::size_t pos, const NullData&, const std::type_info &type, Direction dir)
{
poco_assert(dir == PD_IN);
realBind(pos, Poco::Data::MetaColumn::FDT_UNKNOWN, 0, 0);
Expand Down Expand Up @@ -643,19 +643,19 @@ void Binder::bind(std::size_t /*pos*/, const std::list<Poco::Data::Time>& /*val*
}


void Binder::bind(std::size_t /*pos*/, const std::vector<Poco::Data::NullData>& /*val*/, Direction /*dir*/)
void Binder::bind(std::size_t /*pos*/, const std::vector<Poco::Data::NullData>& /*val*/, const std::type_info &type, Direction /*dir*/)
{
throw NotImplementedException();
}


void Binder::bind(std::size_t /*pos*/, const std::deque<Poco::Data::NullData>& /*val*/, Direction /*dir*/)
void Binder::bind(std::size_t /*pos*/, const std::deque<Poco::Data::NullData>& /*val*/, const std::type_info &type, Direction /*dir*/)
{
throw NotImplementedException();
}


void Binder::bind(std::size_t /*pos*/, const std::list<Poco::Data::NullData>& /*val*/, Direction /*dir*/)
void Binder::bind(std::size_t /*pos*/, const std::list<Poco::Data::NullData>& /*val*/, const std::type_info &type, Direction /*dir*/)
{
throw NotImplementedException();
}
Expand Down
2 changes: 1 addition & 1 deletion Data/SQLite/include/Poco/Data/SQLite/Binder.h
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ class SQLite_API Binder: public Poco::Data::AbstractBinder
void bind(std::size_t pos, const UUID& val, Direction dir);
/// Binds a UUID.

void bind(std::size_t pos, const NullData& val, Direction dir);
void bind(std::size_t pos, const NullData& val, const std::type_info &type, Direction dir);
/// Binds a null.

private:
Expand Down
2 changes: 1 addition & 1 deletion Data/SQLite/src/Binder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ void Binder::bind(std::size_t pos, const UUID& val, Direction dir)
}


void Binder::bind(std::size_t pos, const NullData&, Direction)
void Binder::bind(std::size_t pos, const NullData&, const std::type_info &type, Direction)
{
sqlite3_bind_null(_pStmt, static_cast<int>(pos));
}
Expand Down
Loading

0 comments on commit 105e658

Please sign in to comment.