diff --git a/Data/ODBC/include/Poco/Data/ODBC/Binder.h b/Data/ODBC/include/Poco/Data/ODBC/Binder.h index 7cf97d84b0..bf04ad6561 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/Binder.h +++ b/Data/ODBC/include/Poco/Data/ODBC/Binder.h @@ -959,7 +959,8 @@ 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 @@ -967,6 +968,8 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder /// 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 @@ 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(); @@ -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; diff --git a/Data/ODBC/src/Binder.cpp b/Data/ODBC/src/Binder.cpp index c70e594064..543e69ceb9 100644 --- a/Data/ODBC/src/Binder.cpp +++ b/Data/ODBC/src/Binder.cpp @@ -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(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(colSize))); + } + } decDigits = _parameters[pos].decDigits; } diff --git a/Data/ODBC/src/SessionImpl.cpp b/Data/ODBC/src/SessionImpl.cpp index 603a8b57b4..e4a74bbc1b 100644 --- a/Data/ODBC/src/SessionImpl.cpp +++ b/Data/ODBC/src/SessionImpl.cpp @@ -67,6 +67,7 @@ void SessionImpl::init() setFeature("bulk", true); open(); setProperty("handle", _db.handle()); + setProperty("handle", _db.handle()); } diff --git a/Data/ODBC/testsuite/src/ODBCDB2Test.cpp b/Data/ODBC/testsuite/src/ODBCDB2Test.cpp index d1baaff857..ed53190e55 100644 --- a/Data/ODBC/testsuite/src/ODBCDB2Test.cpp +++ b/Data/ODBC/testsuite/src/ODBCDB2Test.cpp @@ -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); diff --git a/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp b/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp index eb96dda0cd..e75bd25e09 100644 --- a/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCMySQLTest.cpp @@ -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); diff --git a/Data/ODBC/testsuite/src/ODBCOracleTest.cpp b/Data/ODBC/testsuite/src/ODBCOracleTest.cpp index cc39f34aa5..904ace9377 100644 --- a/Data/ODBC/testsuite/src/ODBCOracleTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCOracleTest.cpp @@ -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); diff --git a/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp b/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp index 455fefd5c3..2d81113c67 100644 --- a/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCPostgreSQLTest.cpp @@ -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); diff --git a/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp b/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp index 22db36a9ea..1e31ea0272 100644 --- a/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp @@ -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); diff --git a/Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp b/Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp index 42f2617d19..441f3b9713 100644 --- a/Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCSQLiteTest.cpp @@ -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); diff --git a/Data/ODBC/testsuite/src/ODBCSybaseTest.cpp b/Data/ODBC/testsuite/src/ODBCSybaseTest.cpp index a9fcef9e5b..c695ac7f76 100644 --- a/Data/ODBC/testsuite/src/ODBCSybaseTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCSybaseTest.cpp @@ -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" @@ -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); diff --git a/Data/ODBC/testsuite/src/ODBCSybaseTest.h b/Data/ODBC/testsuite/src/ODBCSybaseTest.h index e8d070f056..20332e1918 100644 --- a/Data/ODBC/testsuite/src/ODBCSybaseTest.h +++ b/Data/ODBC/testsuite/src/ODBCSybaseTest.h @@ -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 diff --git a/Data/ODBC/testsuite/src/ODBCTest.cpp b/Data/ODBC/testsuite/src/ODBCTest.cpp index 0d63672ffc..17f29b2ca5 100644 --- a/Data/ODBC/testsuite/src/ODBCTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCTest.cpp @@ -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."); diff --git a/Data/ODBC/testsuite/src/ODBCTest.h b/Data/ODBC/testsuite/src/ODBCTest.h index fcb348e1f7..0e227310f4 100644 --- a/Data/ODBC/testsuite/src/ODBCTest.h +++ b/Data/ODBC/testsuite/src/ODBCTest.h @@ -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(); diff --git a/Data/ODBC/testsuite/src/SQLExecutor.cpp b/Data/ODBC/testsuite/src/SQLExecutor.cpp index bf534365e9..071548f5af 100644 --- a/Data/ODBC/testsuite/src/SQLExecutor.cpp +++ b/Data/ODBC/testsuite/src/SQLExecutor.cpp @@ -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 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()"; diff --git a/Data/ODBC/testsuite/src/SQLExecutor.h b/Data/ODBC/testsuite/src/SQLExecutor.h index 019e9931e2..8fc17d118c 100644 --- a/Data/ODBC/testsuite/src/SQLExecutor.h +++ b/Data/ODBC/testsuite/src/SQLExecutor.h @@ -211,6 +211,7 @@ class SQLExecutor: public CppUnit::TestCase void autoPtrComplexTypeVector(); void insertVector(); void insertEmptyVector(); + void bigStringVector(); void simpleAccessList(); void complexTypeList();