Skip to content

Commit

Permalink
wrong field size calculation in ODBC code #1659; other max size exces…
Browse files Browse the repository at this point in the history
…sion checks and testcase
  • Loading branch information
aleks-f committed Oct 26, 2017
1 parent f3d10e2 commit c0310b5
Show file tree
Hide file tree
Showing 15 changed files with 125 additions and 62 deletions.
12 changes: 9 additions & 3 deletions Data/ODBC/include/Poco/Data/ODBC/Binder.h
Original file line number Diff line number Diff line change
Expand Up @@ -959,14 +959,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 unsuccessfully 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 @@ -990,12 +993,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 Expand Up @@ -1036,7 +1042,7 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder
const TypeInfo* _pTypeInfo;
SQLINTEGER _paramSetSize;
std::size_t _maxFieldSize;
AnyPtrVecVec _containers;
AnyPtrVecVec _containers;
std::size_t _maxCharColLength;
std::size_t _maxWCharColLength;
std::size_t _maxVarBinColSize;
Expand Down
41 changes: 31 additions & 10 deletions Data/ODBC/src/Binder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir, const
{
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 @@ -204,9 +207,7 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir, const
SQLLEN* pLenIn = new SQLLEN;
if (isOutBound(dir) && nullCb.defined())
_nullCbMap.insert(NullCbMap::value_type( pLenIn, nullCb) );
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;
getColSizeAndPrecision(pos, SQL_C_CHAR, colSize, decDigits);

*pLenIn = SQL_NTS;

if (PB_AT_EXEC == _paramBinding)
Expand Down Expand Up @@ -238,6 +239,9 @@ void Binder::bind(std::size_t pos, const UTF16String& val, Direction dir, const

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

if (isOutBound(dir))
{
Expand All @@ -261,9 +265,6 @@ void Binder::bind(std::size_t pos, const UTF16String& val, Direction dir, const
if (isOutBound(dir) && nullCb.defined())
_nullCbMap.insert(NullCbMap::value_type(pLenIn, nullCb));

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

if (PB_AT_EXEC == _paramBinding)
Expand Down Expand Up @@ -407,8 +408,12 @@ void Binder::bind(std::size_t pos, const NullData& val, Direction dir, const std
SQLINTEGER colSize = 0;
SQLSMALLINT decDigits = 0;

const SQLSMALLINT colType = (bindType == typeid(void) || bindType == typeid(NullData) || bindType == typeid(NullType)) ?
_pTypeInfo->nullDataType(val) : _pTypeInfo->tryTypeidToCType(bindType, SQL_C_TINYINT);
const SQLSMALLINT colType = (bindType == typeid(void) ||
bindType == typeid(NullData) ||
bindType == typeid(NullType)) ?
_pTypeInfo->nullDataType(val) :
_pTypeInfo->tryTypeidToCType(bindType, SQL_C_TINYINT);

getColSizeAndPrecision(pos, colType, colSize, decDigits);

if (Utility::isError(SQLBindParameter(_rStmt,
Expand Down Expand Up @@ -555,8 +560,11 @@ void Binder::reset()
void Binder::getColSizeAndPrecision(std::size_t pos,
SQLSMALLINT cDataType,
SQLINTEGER& colSize,
SQLSMALLINT& decDigits)
SQLSMALLINT& decDigits,
std::size_t actualSize)
{
colSize = 0;
decDigits = 0;
// Not all drivers are equally willing to cooperate in this matter.
// Hence the funky flow control.

Expand All @@ -565,6 +573,11 @@ void Binder::getColSizeAndPrecision(std::size_t pos,
DynamicAny tmp;
bool 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 @@ -599,7 +612,15 @@ void Binder::getColSizeAndPrecision(std::size_t pos,

// we may have no success, so use zeros and hope for the best
// (most drivers do not require these most of the times anyway)
colSize = _parameters[pos].colSize;
if (0 == colSize)
{
colSize = _parameters[pos].colSize;
if (actualSize > colSize)
{
throw LengthExceededException(Poco::format("Error binding column %z size=%z, max size=%ld)",
pos, actualSize, static_cast<long>(colSize)));
}
}
decDigits = _parameters[pos].decDigits;
}

Expand Down
1 change: 1 addition & 0 deletions Data/ODBC/src/SessionImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ void SessionImpl::init()
setFeature("bulk", true);
open();
setProperty("handle", _db.handle());
setProperty("handle", _db.handle());
}


Expand Down
1 change: 1 addition & 0 deletions Data/ODBC/testsuite/src/ODBCDB2Test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,7 @@ CppUnit::Test* ODBCDB2Test::suite()
CppUnit_addTest(pSuite, ODBCDB2Test, testAutoPtrComplexTypeVector);
CppUnit_addTest(pSuite, ODBCDB2Test, testInsertVector);
CppUnit_addTest(pSuite, ODBCDB2Test, testInsertEmptyVector);
CppUnit_addTest(pSuite, ODBCDB2Test, testBigStringVector);
CppUnit_addTest(pSuite, ODBCDB2Test, testSimpleAccessList);
CppUnit_addTest(pSuite, ODBCDB2Test, testComplexTypeList);
CppUnit_addTest(pSuite, ODBCDB2Test, testInsertList);
Expand Down
1 change: 1 addition & 0 deletions Data/ODBC/testsuite/src/ODBCMySQLTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ CppUnit::Test* ODBCMySQLTest::suite()
CppUnit_addTest(pSuite, ODBCMySQLTest, testAutoPtrComplexTypeVector);
CppUnit_addTest(pSuite, ODBCMySQLTest, testInsertVector);
CppUnit_addTest(pSuite, ODBCMySQLTest, testInsertEmptyVector);
CppUnit_addTest(pSuite, ODBCMySQLTest, testBigStringVector);
CppUnit_addTest(pSuite, ODBCMySQLTest, testSimpleAccessList);
CppUnit_addTest(pSuite, ODBCMySQLTest, testComplexTypeList);
CppUnit_addTest(pSuite, ODBCMySQLTest, testInsertList);
Expand Down
1 change: 1 addition & 0 deletions Data/ODBC/testsuite/src/ODBCOracleTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -910,6 +910,7 @@ CppUnit::Test* ODBCOracleTest::suite()
CppUnit_addTest(pSuite, ODBCOracleTest, testAutoPtrComplexTypeVector);
CppUnit_addTest(pSuite, ODBCOracleTest, testInsertVector);
CppUnit_addTest(pSuite, ODBCOracleTest, testInsertEmptyVector);
CppUnit_addTest(pSuite, ODBCOracleTest, testBigStringVector);
CppUnit_addTest(pSuite, ODBCOracleTest, testSimpleAccessList);
CppUnit_addTest(pSuite, ODBCOracleTest, testComplexTypeList);
CppUnit_addTest(pSuite, ODBCOracleTest, testInsertList);
Expand Down
1 change: 1 addition & 0 deletions Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -637,6 +637,7 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testAutoPtrComplexTypeVector);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testInsertVector);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testInsertEmptyVector);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testBigStringVector);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSimpleAccessList);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testComplexTypeList);
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testInsertList);
Expand Down
1 change: 1 addition & 0 deletions Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
CppUnit_addTest(pSuite, ODBCSQLServerTest, testAutoPtrComplexTypeVector);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInsertVector);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInsertEmptyVector);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testBigStringVector);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testSimpleAccessList);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testComplexTypeList);
CppUnit_addTest(pSuite, ODBCSQLServerTest, testInsertList);
Expand Down
1 change: 1 addition & 0 deletions Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,7 @@ CppUnit::Test* ODBCSQLiteTest::suite()
CppUnit_addTest(pSuite, ODBCSQLiteTest, testAutoPtrComplexTypeVector);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testInsertVector);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testInsertEmptyVector);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testBigStringVector);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testSimpleAccessList);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testComplexTypeList);
CppUnit_addTest(pSuite, ODBCSQLiteTest, testInsertList);
Expand Down
36 changes: 11 additions & 25 deletions Data/ODBC/testsuite/src/ODBCSybaseTest.cpp
Original file line number Diff line number Diff line change
@@ -1,28 +1,13 @@
/*
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/
//
// ODBCSybaseTest.cpp
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//


#include "ODBCSybaseTest.h"
#include "Poco/CppUnit/TestCaller.h"
#include "Poco/CppUnit/TestSuite.h"
Expand Down Expand Up @@ -583,6 +568,7 @@ CppUnit::Test* SybaseODBC::suite()
CppUnit_addTest(pSuite, SybaseODBC, testAutoPtrComplexTypeVector);
CppUnit_addTest(pSuite, SybaseODBC, testInsertVector);
CppUnit_addTest(pSuite, SybaseODBC, testInsertEmptyVector);
CppUnit_addTest(pSuite, SybaseODBC, testBigStringVector);
CppUnit_addTest(pSuite, SybaseODBC, testSimpleAccessList);
CppUnit_addTest(pSuite, SybaseODBC, testComplexTypeList);
CppUnit_addTest(pSuite, SybaseODBC, testInsertList);
Expand Down
32 changes: 8 additions & 24 deletions Data/ODBC/testsuite/src/ODBCSybaseTest.h
Original file line number Diff line number Diff line change
@@ -1,28 +1,12 @@
/*
Boost Software License - Version 1.0 - August 17th, 2003
//
// ODBCSybaseTest.h
//
// Copyright (c) 2006, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//

Permission is hereby granted, free of charge, to any person or organization
obtaining a copy of the software and accompanying documentation covered by
this license (the "Software") to use, reproduce, display, distribute,
execute, and transmit the Software, and to prepare derivative works of the
Software, and to permit third-parties to whom the Software is furnished to
do so, all subject to the following:
The copyright notices in the Software and this entire statement, including
the above license grant, this restriction and the following disclaimer,
must be included in all copies of the Software, in whole or in part, and
all derivative works of the Software, unless such copies or derivative
works are solely in the form of machine-executable object code generated by
a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
*/

#ifndef ODBCSybaseTest_INCLUDED
#define ODBCSybaseTest_INCLUDED
Expand Down
15 changes: 15 additions & 0 deletions Data/ODBC/testsuite/src/ODBCTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,21 @@ void ODBCTest::testInsertEmptyVector()
}


void ODBCTest::testBigStringVector()
{
if (!_pSession) fail("Test not available.");

for (int i = 0; i < 8;)
{
recreateStringsTable();
_pSession->setFeature("autoBind", bindValue(i));
_pSession->setFeature("autoExtract", bindValue(i + 1));
_pExecutor->bigStringVector();
i += 2;
}
}


void ODBCTest::testSimpleAccessList()
{
if (!_pSession) fail ("Test not available.");
Expand Down
1 change: 1 addition & 0 deletions Data/ODBC/testsuite/src/ODBCTest.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class ODBCTest: public CppUnit::TestCase
virtual void testAutoPtrComplexTypeVector();
virtual void testInsertVector();
virtual void testInsertEmptyVector();
virtual void testBigStringVector();

virtual void testSimpleAccessList();
virtual void testComplexTypeList();
Expand Down
42 changes: 42 additions & 0 deletions Data/ODBC/testsuite/src/SQLExecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ using Poco::Data::RowIterator;
using Poco::Data::SQLChannel;
using Poco::Data::LimitException;
using Poco::Data::BindingException;
using Poco::Data::LengthExceededException;
using Poco::Data::CLOB;
using Poco::Data::Date;
using Poco::Data::Time;
Expand Down Expand Up @@ -1255,6 +1256,47 @@ void SQLExecutor::insertEmptyVector()
}


void SQLExecutor::bigStringVector()
{
std::string funct = "bigStringVector()";
std::vector<std::string> str;
str.push_back(std::string(10000, 'a'));

{
Statement stmt((session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (?)", use(str)));
try { stmt.execute(); fail("must throw"); }
catch (LengthExceededException&) { }
}

str.clear();
str.push_back(std::string(30, 'a'));
str.push_back(std::string(30, 'b'));
str.push_back(std::string(30, 'c'));
str.push_back(std::string(30, 'd'));
int count = 100;
{
Statement stmt((session() << "INSERT INTO " << ExecUtil::strings() << " VALUES (?)", use(str)));
try { session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; }
catch (ConnectionException& ce) { std::cout << ce.toString() << std::endl; fail(funct); }
catch (StatementException& se) { std::cout << se.toString() << std::endl; fail(funct); }
assert(count == 0);

try { stmt.execute(); }
catch (StatementException& se) { std::cout << se.toString() << std::endl; fail(funct); }

try { session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; }
catch (ConnectionException& ce) { std::cout << ce.toString() << std::endl; fail(funct); }
catch (StatementException& se) { std::cout << se.toString() << std::endl; fail(funct); }
assert(count == 4);
}
count = 0;
try { session() << "SELECT COUNT(*) FROM " << ExecUtil::strings(), into(count), now; }
catch (ConnectionException& ce) { std::cout << ce.toString() << std::endl; fail(funct); }
catch (StatementException& se) { std::cout << se.toString() << std::endl; fail(funct); }
assert(count == 4);
}


void SQLExecutor::simpleAccessList()
{
std::string funct = "simpleAccessList()";
Expand Down
1 change: 1 addition & 0 deletions Data/ODBC/testsuite/src/SQLExecutor.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ class SQLExecutor: public CppUnit::TestCase
void autoPtrComplexTypeVector();
void insertVector();
void insertEmptyVector();
void bigStringVector();

void simpleAccessList();
void complexTypeList();
Expand Down

0 comments on commit c0310b5

Please sign in to comment.