Skip to content

Commit

Permalink
wrong field size calculation in ODBC code #1659 and other develop bac…
Browse files Browse the repository at this point in the history
…kports
  • Loading branch information
aleks-f committed Oct 30, 2017
1 parent 57bc179 commit 1b2bd22
Show file tree
Hide file tree
Showing 11 changed files with 89 additions and 52 deletions.
15 changes: 11 additions & 4 deletions Data/ODBC/include/Poco/Data/ODBC/Binder.h
Original file line number Diff line number Diff line change
Expand Up @@ -640,15 +640,16 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder

std::size_t strSize;
std::size_t offset = 0;
char* pBuf = (char*)_utf16CharPtrs[pos];
typename C::const_iterator it = val.begin();
typename C::const_iterator end = val.end();
for (; it != end; ++it)
{
strSize = it->size() * sizeof(UTF16Char);
if (strSize > size)
throw LengthExceededException("SQLBindParameter(std::vector<UTF16String>)");
std::memcpy(_utf16CharPtrs[pos] + offset, it->data(), strSize);
offset += (size / sizeof(UTF16Char));
std::memcpy(pBuf + offset, it->data(), strSize);
offset += size;
}

if (Utility::isError(SQLBindParameter(_rStmt,
Expand Down Expand Up @@ -934,14 +935,17 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder
void getColSizeAndPrecision(std::size_t pos,
SQLSMALLINT cDataType,
SQLINTEGER& colSize,
SQLSMALLINT& decDigits);
SQLSMALLINT& decDigits,
std::size_t actualSize = 0);
/// Used to retrieve column size and precision.
/// Not all drivers cooperate with this inquiry under all circumstances
/// This function runs for query and stored procedure parameters (in and
/// out-bound). Some drivers, however, do not care about knowing this
/// information to start with. For that reason, after all the attempts
/// to discover the required values are unsuccesfully exhausted, the values
/// are both set to zero and no exception is thrown.
/// However, if the colSize is succesfully retrieved and it is greater than
/// session-wide maximum allowed field size, LengthExceededException is thrown.

void setParamSetSize(std::size_t length);
/// Sets the parameter set size. Used for column-wise binding.
Expand All @@ -964,12 +968,15 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder
/// optimization, looking for the maximum length within supplied data container and
/// uses the smaller of maximum found and maximum predefined data length.
{
typedef typename T::value_type ContainedValType;
typedef typename ContainedValType::value_type BaseValType;
std::size_t typeSize = sizeof(BaseValType);
std::size_t maxSize = 0;
typename T::const_iterator it = val.begin();
typename T::const_iterator end = val.end();
for (; it != end; ++it)
{
std::size_t sz = it->size() * sizeof(T);
std::size_t sz = it->size() * typeSize;
if (sz > _maxFieldSize)
throw LengthExceededException();

Expand Down
33 changes: 22 additions & 11 deletions Data/ODBC/src/Binder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,9 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir)
{
SQLPOINTER pVal = 0;
SQLINTEGER size = (SQLINTEGER) val.size();
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_C_CHAR, colSize, decDigits, val.size());

if (isOutBound(dir))
{
Expand All @@ -118,11 +121,7 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir)
else
throw InvalidArgumentException("Parameter must be [in] OR [out] bound.");

SQLLEN* pLenIn = new SQLLEN;
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_C_CHAR, colSize, decDigits);
*pLenIn = SQL_NTS;
SQLLEN* pLenIn = new SQLLEN(SQL_NTS);

if (PB_AT_EXEC == _paramBinding)
*pLenIn = SQL_LEN_DATA_AT_EXEC(size);
Expand Down Expand Up @@ -151,6 +150,9 @@ void Binder::bind(std::size_t pos, const UTF16String& val, Direction dir)

SQLPOINTER pVal = 0;
SQLINTEGER size = (SQLINTEGER)(val.size() * sizeof(CharT));
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_C_WCHAR, colSize, decDigits);

if (isOutBound(dir))
{
Expand All @@ -168,11 +170,7 @@ void Binder::bind(std::size_t pos, const UTF16String& val, Direction dir)
else
throw InvalidArgumentException("Parameter must be [in] OR [out] bound.");

SQLLEN* pLenIn = new SQLLEN;
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_C_WCHAR, colSize, decDigits);
*pLenIn = SQL_NTS;
SQLLEN* pLenIn = new SQLLEN(SQL_NTS);

if (PB_AT_EXEC == _paramBinding)
{
Expand Down Expand Up @@ -419,7 +417,8 @@ void Binder::reset()
void Binder::getColSizeAndPrecision(std::size_t pos,
SQLSMALLINT cDataType,
SQLINTEGER& colSize,
SQLSMALLINT& decDigits)
SQLSMALLINT& decDigits,
std::size_t actualSize)
{
// Not all drivers are equally willing to cooperate in this matter.
// Hence the funky flow control.
Expand All @@ -429,6 +428,11 @@ void Binder::getColSizeAndPrecision(std::size_t pos,
{
found = _pTypeInfo->tryGetInfo(cDataType, "COLUMN_SIZE", tmp);
if (found) colSize = tmp;
if (actualSize > colSize)
{
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);
if (found)
{
Expand Down Expand Up @@ -459,6 +463,13 @@ void Binder::getColSizeAndPrecision(std::size_t pos,
{
}

// last check, just in case
if ((0 != colSize) && (actualSize > colSize))
{
throw LengthExceededException(Poco::format("Error binding column %z size=%z, max size=%ld)",
pos, actualSize, static_cast<long>(colSize)));
}

// no success, set to zero and hope for the best
// (most drivers do not require these most of the times anyway)
colSize = 0;
Expand Down
16 changes: 5 additions & 11 deletions Data/ODBC/src/ODBCMetaColumn.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,17 +134,11 @@ void ODBCMetaColumn::init()

case SQL_NUMERIC:
case SQL_DECIMAL:
if (0 == _columnDesc.decimalDigits)
{
if (_columnDesc.size > 9)
setType(MetaColumn::FDT_INT64);
else
setType(MetaColumn::FDT_INT32);
}
else
{
setType(MetaColumn::FDT_DOUBLE);
}
// Oracle has no INTEGER type - it's essentially NUMBER with 38 whole and
// 0 fractional digits. It also does not recognize SQL_BIGINT type,
// so the workaround here is to hardcode it to 32 bit integer
if (0 == _columnDesc.decimalDigits) setType(MetaColumn::FDT_INT32);
else setType(MetaColumn::FDT_DOUBLE);
break;

case SQL_REAL:
Expand Down
2 changes: 1 addition & 1 deletion Data/ODBC/src/ODBCStatementImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@ int ODBCStatementImpl::affectedRowCount() const
_affectedRowCount = static_cast<std::size_t>(rows);
}

return _affectedRowCount;
return static_cast<int>(_affectedRowCount);
}


Expand Down
10 changes: 6 additions & 4 deletions Data/ODBC/testsuite/src/ODBCMySQLTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,13 @@ using Poco::Tuple;
using Poco::NotFoundException;


#define MYSQL_ODBC_DRIVER "MySQL ODBC 5.2 Driver"
#define MYSQL_ODBC_DRIVER "MySQL ODBC 5.3 Unicode Driver"
#define MYSQL_DSN "PocoDataMySQLTest"
#define MYSQL_SERVER POCO_ODBC_TEST_DATABASE_SERVER
#define MYSQL_DB "test"
#define MYSQL_UID "root"
#define MYSQL_PWD "poco"
#define MYSQL_DB "test"


ODBCTest::SessionPtr ODBCMySQLTest::_pSession;
Expand All @@ -52,6 +53,7 @@ std::string ODBCMySQLTest::_driver = MYSQL_ODBC_DRIVER;
std::string ODBCMySQLTest::_dsn = MYSQL_DSN;
std::string ODBCMySQLTest::_uid = MYSQL_UID;
std::string ODBCMySQLTest::_pwd = MYSQL_PWD;
std::string ODBCMySQLTest::_db = MYSQL_DB;
std::string ODBCMySQLTest::_connectString = "DRIVER={" MYSQL_ODBC_DRIVER "};"
"DATABASE=" MYSQL_DB ";"
"SERVER=" MYSQL_SERVER ";"
Expand Down Expand Up @@ -162,7 +164,7 @@ void ODBCMySQLTest::testNull()
recreateNullsTable("NOT NULL");
_pSession->setFeature("autoBind", bindValue(i));
_pSession->setFeature("autoExtract", bindValue(i+1));
_pExecutor->notNulls("HYT00");
_pExecutor->notNulls("HY000");
i += 2;
}

Expand Down Expand Up @@ -410,7 +412,7 @@ void ODBCMySQLTest::recreateLogTable()

CppUnit::Test* ODBCMySQLTest::suite()
{
if ((_pSession = init(_driver, _dsn, _uid, _pwd, _connectString)))
if ((_pSession = init(_driver, _dsn, _uid, _pwd, _connectString, _db)))
{
std::cout << "*** Connected to [" << _driver << "] test database." << std::endl;

Expand Down Expand Up @@ -444,7 +446,7 @@ CppUnit::Test* ODBCMySQLTest::suite()
CppUnit_addTest(pSuite, ODBCMySQLTest, testLimitPrepare);
CppUnit_addTest(pSuite, ODBCMySQLTest, testLimitZero);
CppUnit_addTest(pSuite, ODBCMySQLTest, testPrepare);
//CppUnit_addTest(pSuite, ODBCMySQLTest, testBulk);
CppUnit_addTest(pSuite, ODBCMySQLTest, testBulk);
CppUnit_addTest(pSuite, ODBCMySQLTest, testBulkPerformance);
CppUnit_addTest(pSuite, ODBCMySQLTest, testSetSimple);
CppUnit_addTest(pSuite, ODBCMySQLTest, testSetComplex);
Expand Down
1 change: 1 addition & 0 deletions Data/ODBC/testsuite/src/ODBCMySQLTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class ODBCMySQLTest: public ODBCTest
static std::string _dsn;
static std::string _uid;
static std::string _pwd;
static std::string _db;
static std::string _connectString;
};

Expand Down
4 changes: 2 additions & 2 deletions Data/ODBC/testsuite/src/ODBCOracleTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ using Poco::DynamicAny;
using Poco::DateTime;


#define ORACLE_ODBC_DRIVER "Oracle in XE"
#define ORACLE_ODBC_DRIVER "Oracle in OraDB12Home1"
#define ORACLE_DSN "PocoDataOracleTest"
#define ORACLE_SERVER POCO_ODBC_TEST_DATABASE_SERVER
#define ORACLE_PORT "1521"
#define ORACLE_SID "XE"
#define ORACLE_SID "ORCL"
#define ORACLE_UID "poco"
#define ORACLE_PWD "poco"

Expand Down
20 changes: 11 additions & 9 deletions Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,11 @@ using Poco::DateTime;
#define POSTGRESQL_PORT "5432"
#define POSTGRESQL_DB "postgres"
#define POSTGRESQL_UID "postgres"
#define POSTGRESQL_PWD "postgres"
#define POSTGRESQL_VERSION "9.3"
#define POSTGRESQL_PWD "poco"
#define POSTGRESQL_VERSION "10"

#ifdef POCO_OS_FAMILY_WINDOWS
const std::string ODBCPostgreSQLTest::_libDir = "C:\\\\Program Files\\\\PostgreSQL\\\\" POSTGRESQL_VERSION "\\\\lib\\\\";
const std::string ODBCPostgreSQLTest::_libDir = "C:\\\\Program Files\\\\PostgreSQL\\\\pg" POSTGRESQL_VERSION "\\\\lib\\\\";
#else
const std::string ODBCPostgreSQLTest::_libDir = "/usr/local/pgsql/lib/";
#endif
Expand Down Expand Up @@ -353,7 +353,7 @@ void ODBCPostgreSQLTest::configurePLPgSQL()

}catch(StatementException& ex)
{
if (7 != ex.diagnostics().nativeError(0))
if (1 != ex.diagnostics().nativeError(0))
throw;
}

Expand All @@ -374,7 +374,7 @@ void ODBCPostgreSQLTest::dropObject(const std::string& type, const std::string&
StatementDiagnostics::Iterator it = flds.begin();
for (; it != flds.end(); ++it)
{
if (7 == it->_nativeError)//(table does not exist)
if (1 == it->_nativeError)//(table does not exist)
{
ignoreError = true;
break;
Expand Down Expand Up @@ -665,13 +665,15 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testAsync);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testAny);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testDynamicAny);
//neither pSQL ODBC nor Mammoth drivers support multiple results properly
//CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testMultipleResults);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testMultipleResults);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSQLChannel);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSQLLogger);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSessionTransaction);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTransaction);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTransactor);
// (postgres bug?)
// local session claims to be capable of reading uncommitted changes,
// but fails to do so
//CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTransaction);
//CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTransactor);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testNullable);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testUnicode);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testReconnect);
Expand Down
14 changes: 10 additions & 4 deletions Data/ODBC/testsuite/src/SQLExecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -402,7 +402,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
sixth.day = 18;
sixth.hour = 5;
sixth.minute = 34;
sixth.second = 59;
sixth.second = 58;
// Fraction support is limited to milliseconds due to MS SQL Server limitation
// see http://support.microsoft.com/kb/263872
sixth.fraction = 997000000;
Expand Down Expand Up @@ -693,9 +693,15 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
{
assert (5 == sixth.hour);
assert (34 == sixth.minute);
assert (59 == sixth.second);
if (sixth.fraction)//MySQL does not support fraction
assert (997000000 == sixth.fraction);
if (sixth.fraction) // MySQL rounds fraction
{
assert(58 == sixth.second);
assert(997000000 == sixth.fraction);
}
else
{
assert(59 == sixth.second);
}
}

rc = SQLCloseCursor(hstmt);
Expand Down
13 changes: 11 additions & 2 deletions Data/include/Poco/Data/RowFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,15 @@ class Data_API RowFilter: public RefCountedObject
~RowFilter();
/// Destroys the RowFilter.

void addFilter(const Ptr& pFilter, LogicOperator comparison);
void addFilter(Ptr pFilter, LogicOperator comparison);
/// Appends another filter to this one.

void removeFilter(const Ptr& pFilter);
void removeFilter(Ptr pFilter);
/// Removes filter from this filter.

bool has(Ptr pFilter) const;
/// Returns true if this filter is parent of pFilter;

template <typename T>
void add(const std::string& name, Comparison comparison, const T& value, LogicOperator op = OP_OR)
/// Adds value to the filter.
Expand Down Expand Up @@ -183,6 +186,12 @@ class Data_API RowFilter: public RefCountedObject
///


inline bool RowFilter::has(Ptr pFilter) const
{
return _filterMap.find(pFilter) != _filterMap.end();
}


inline bool RowFilter::isEmpty() const
{
return _comparisonMap.size() == 0;
Expand Down
Loading

0 comments on commit 1b2bd22

Please sign in to comment.