mirror of
https://github.com/pocoproject/poco.git
synced 2025-01-23 10:36:37 +01:00
wrong field size calculation in ODBC code #1659; other max size excession checks and testcase
This commit is contained in:
parent
f3d10e2764
commit
c0310b5c74
@ -959,7 +959,8 @@ private:
|
||||
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
|
||||
@ -967,6 +968,8 @@ private:
|
||||
/// 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.
|
||||
@ -990,12 +993,15 @@ private:
|
||||
/// 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();
|
||||
|
||||
@ -1036,7 +1042,7 @@ private:
|
||||
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;
|
||||
|
@ -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))
|
||||
{
|
||||
@ -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)
|
||||
@ -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))
|
||||
{
|
||||
@ -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)
|
||||
@ -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,
|
||||
@ -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.
|
||||
|
||||
@ -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)
|
||||
{
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
@ -67,6 +67,7 @@ void SessionImpl::init()
|
||||
setFeature("bulk", true);
|
||||
open();
|
||||
setProperty("handle", _db.handle());
|
||||
setProperty("handle", _db.handle());
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -1,28 +1,13 @@
|
||||
/*
|
||||
Boost Software License - Version 1.0 - August 17th, 2003
|
||||
//
|
||||
// ODBCSybaseTest.cpp
|
||||
//
|
||||
// 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.
|
||||
*/
|
||||
#include "ODBCSybaseTest.h"
|
||||
#include "Poco/CppUnit/TestCaller.h"
|
||||
#include "Poco/CppUnit/TestSuite.h"
|
||||
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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.");
|
||||
|
@ -58,6 +58,7 @@ public:
|
||||
virtual void testAutoPtrComplexTypeVector();
|
||||
virtual void testInsertVector();
|
||||
virtual void testInsertEmptyVector();
|
||||
virtual void testBigStringVector();
|
||||
|
||||
virtual void testSimpleAccessList();
|
||||
virtual void testComplexTypeList();
|
||||
|
@ -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;
|
||||
@ -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()";
|
||||
|
@ -211,6 +211,7 @@ public:
|
||||
void autoPtrComplexTypeVector();
|
||||
void insertVector();
|
||||
void insertEmptyVector();
|
||||
void bigStringVector();
|
||||
|
||||
void simpleAccessList();
|
||||
void complexTypeList();
|
||||
|
Loading…
x
Reference in New Issue
Block a user