From 9a80f28ec1f5e188fa645b1d9264929d01cae38d Mon Sep 17 00:00:00 2001 From: Alex Fabijanic Date: Fri, 1 Nov 2024 01:34:54 -0500 Subject: [PATCH 01/20] fix(ODBC): Insert NULL using BULK #4001 resolve bound types and sizes at compile time --- .../include/Poco/Data/Test/SQLExecutor.h | 1 + Data/DataTest/src/SQLExecutor.cpp | 425 +++++++++++------- Data/ODBC/include/Poco/Data/ODBC/Binder.h | 94 +++- Data/ODBC/include/Poco/Data/ODBC/TypeInfo.h | 106 ++++- Data/ODBC/include/Poco/Data/ODBC/Utility.h | 25 ++ Data/ODBC/src/Binder.cpp | 22 +- Data/ODBC/src/TypeInfo.cpp | 4 +- Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp | 13 + Data/ODBC/testsuite/src/ODBCSQLServerTest.h | 1 + Data/ODBC/testsuite/src/SQLExecutor.h | 8 + Foundation/include/Poco/Nullable.h | 2 + 11 files changed, 509 insertions(+), 192 deletions(-) diff --git a/Data/DataTest/include/Poco/Data/Test/SQLExecutor.h b/Data/DataTest/include/Poco/Data/Test/SQLExecutor.h index 3977629c50..f339ded1e2 100644 --- a/Data/DataTest/include/Poco/Data/Test/SQLExecutor.h +++ b/Data/DataTest/include/Poco/Data/Test/SQLExecutor.h @@ -242,6 +242,7 @@ class DataTest_API SQLExecutor: public CppUnit::TestCase "SELECT * FROM Vectors ORDER BY int0 ASC", const std::string& intFldName = "int0"); + void nullBulk(const std::string& blobPlaceholder); void internalBulkExtraction(); void internalBulkExtractionUTF16(); void internalStorageType(); diff --git a/Data/DataTest/src/SQLExecutor.cpp b/Data/DataTest/src/SQLExecutor.cpp index 4ccb1b3508..705aca5379 100644 --- a/Data/DataTest/src/SQLExecutor.cpp +++ b/Data/DataTest/src/SQLExecutor.cpp @@ -569,7 +569,7 @@ void SQLExecutor::simpleAccess() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } count = 0; @@ -577,7 +577,7 @@ void SQLExecutor::simpleAccess() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 1); @@ -586,7 +586,7 @@ void SQLExecutor::simpleAccess() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (lastName == result); @@ -595,7 +595,7 @@ void SQLExecutor::simpleAccess() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == age); @@ -611,7 +611,7 @@ void SQLExecutor::complexType() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } @@ -619,7 +619,7 @@ void SQLExecutor::complexType() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } @@ -628,7 +628,7 @@ void SQLExecutor::complexType() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -638,7 +638,7 @@ void SQLExecutor::complexType() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (c1 == p1); @@ -655,7 +655,7 @@ void SQLExecutor::complexTypeTuple() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } @@ -665,7 +665,7 @@ void SQLExecutor::complexTypeTuple() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (ret == t); @@ -694,7 +694,7 @@ void SQLExecutor::simpleAccessVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } @@ -702,7 +702,7 @@ void SQLExecutor::simpleAccessVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -715,7 +715,7 @@ void SQLExecutor::simpleAccessVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (ages == agesR); @@ -735,7 +735,7 @@ void SQLExecutor::complexTypeVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } @@ -744,7 +744,7 @@ void SQLExecutor::complexTypeVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -754,7 +754,7 @@ void SQLExecutor::complexTypeVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (result == people); @@ -771,7 +771,7 @@ void SQLExecutor::sharedPtrComplexTypeVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } @@ -780,7 +780,7 @@ void SQLExecutor::sharedPtrComplexTypeVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -790,7 +790,7 @@ void SQLExecutor::sharedPtrComplexTypeVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (2 == result.size()); @@ -809,7 +809,7 @@ void SQLExecutor::autoPtrComplexTypeVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } @@ -818,7 +818,7 @@ void SQLExecutor::autoPtrComplexTypeVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -828,7 +828,7 @@ void SQLExecutor::autoPtrComplexTypeVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (2 == result.size()); @@ -858,7 +858,7 @@ void SQLExecutor::insertVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 0); @@ -867,7 +867,7 @@ void SQLExecutor::insertVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } @@ -875,7 +875,7 @@ void SQLExecutor::insertVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 4); @@ -885,7 +885,7 @@ void SQLExecutor::insertVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 4); @@ -928,7 +928,7 @@ void SQLExecutor::simpleAccessList() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } @@ -936,7 +936,7 @@ void SQLExecutor::simpleAccessList() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -949,7 +949,7 @@ void SQLExecutor::simpleAccessList() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (ages == agesR); @@ -969,7 +969,7 @@ void SQLExecutor::complexTypeList() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } @@ -978,7 +978,7 @@ void SQLExecutor::complexTypeList() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -988,7 +988,7 @@ void SQLExecutor::complexTypeList() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (result == people); @@ -1010,7 +1010,7 @@ void SQLExecutor::insertList() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 0); @@ -1019,14 +1019,14 @@ void SQLExecutor::insertList() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 4); @@ -1036,7 +1036,7 @@ void SQLExecutor::insertList() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 4); @@ -1079,14 +1079,14 @@ void SQLExecutor::simpleAccessDeque() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -1099,7 +1099,7 @@ void SQLExecutor::simpleAccessDeque() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (ages == agesR); @@ -1119,7 +1119,7 @@ void SQLExecutor::complexTypeDeque() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } @@ -1128,7 +1128,7 @@ void SQLExecutor::complexTypeDeque() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -1138,7 +1138,7 @@ void SQLExecutor::complexTypeDeque() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (result == people); @@ -1160,7 +1160,7 @@ void SQLExecutor::insertDeque() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 0); @@ -1169,14 +1169,14 @@ void SQLExecutor::insertDeque() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } try { session() << "SELECT COUNT(*) FROM Strings", into(count), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 4); @@ -1186,7 +1186,7 @@ void SQLExecutor::insertDeque() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 4); @@ -1251,7 +1251,7 @@ void SQLExecutor::insertSingleBulk() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 100); @@ -1260,7 +1260,7 @@ void SQLExecutor::insertSingleBulk() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == ((0+99)*100/2)); @@ -1276,7 +1276,7 @@ void SQLExecutor::floats() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } @@ -1285,7 +1285,7 @@ void SQLExecutor::floats() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 1); @@ -1294,7 +1294,7 @@ void SQLExecutor::floats() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (ret == data); @@ -1310,7 +1310,7 @@ void SQLExecutor::doubles() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } @@ -1319,7 +1319,7 @@ void SQLExecutor::doubles() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 1); @@ -1328,7 +1328,7 @@ void SQLExecutor::doubles() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (ret == data); @@ -1344,7 +1344,7 @@ void SQLExecutor::uuids() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } @@ -1353,7 +1353,7 @@ void SQLExecutor::uuids() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 1); @@ -1362,7 +1362,7 @@ void SQLExecutor::uuids() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (ret == data); @@ -1384,7 +1384,7 @@ void SQLExecutor::insertSingleBulkVec() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } @@ -1393,7 +1393,7 @@ void SQLExecutor::insertSingleBulkVec() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == ((0+99)*100/2)); @@ -1412,7 +1412,7 @@ void SQLExecutor::limits() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } std::vector retData; @@ -1420,7 +1420,7 @@ void SQLExecutor::limits() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (retData.size() == 50); @@ -1443,7 +1443,7 @@ void SQLExecutor::limitZero() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } std::vector retData; @@ -1451,7 +1451,7 @@ void SQLExecutor::limitZero() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (retData.size() == 0); @@ -1470,7 +1470,7 @@ void SQLExecutor::limitOnce() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } std::vector retData; @@ -1507,7 +1507,7 @@ void SQLExecutor::limitPrepare() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } std::vector retData; @@ -1519,7 +1519,7 @@ void SQLExecutor::limitPrepare() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (!stmt.done()); @@ -1529,7 +1529,7 @@ void SQLExecutor::limitPrepare() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (stmt.done()); @@ -1539,7 +1539,7 @@ void SQLExecutor::limitPrepare() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (!stmt.done()); @@ -1569,7 +1569,7 @@ void SQLExecutor::prepare() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 0); @@ -1596,7 +1596,7 @@ void SQLExecutor::doBulkPerformance(Poco::UInt32 size) } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } double time = sw.elapsed() / 1000.0; @@ -1604,7 +1604,7 @@ void SQLExecutor::doBulkPerformance(Poco::UInt32 size) try { session() << "DELETE FROM MiscTest", now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } try @@ -1619,7 +1619,7 @@ void SQLExecutor::doBulkPerformance(Poco::UInt32 size) } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } double bulkTime = sw.elapsed() / 1000.0; @@ -1657,7 +1657,7 @@ void SQLExecutor::doBulkPerformance(Poco::UInt32 size) } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } time = sw.elapsed() / 1000.0; @@ -1682,7 +1682,7 @@ void SQLExecutor::doBulkPerformance(Poco::UInt32 size) } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } bulkTime = sw.elapsed() / 1000.0; @@ -1726,13 +1726,13 @@ void SQLExecutor::setSimple() try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastNames), use(firstNames), use(addresses), use(ages), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -1744,7 +1744,7 @@ void SQLExecutor::setSimple() try { session() << "SELECT * FROM Person", into(lastNamesR), into(firstNamesR), into(addressesR), into(agesR), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (ages == agesR); @@ -1763,14 +1763,14 @@ void SQLExecutor::setComplex() try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } int count = 0; try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -1779,7 +1779,7 @@ void SQLExecutor::setComplex() try { session() << "SELECT * FROM Person", into(result), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (result == people); @@ -1800,7 +1800,7 @@ void SQLExecutor::setComplexUnique() try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(people), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } int count = 0; @@ -1808,7 +1808,7 @@ void SQLExecutor::setComplexUnique() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 5); @@ -1818,7 +1818,7 @@ void SQLExecutor::setComplexUnique() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (result.size() == 2); @@ -1848,14 +1848,14 @@ void SQLExecutor::multiSetSimple() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -1868,7 +1868,7 @@ void SQLExecutor::multiSetSimple() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (ages.size() == agesR.size()); @@ -1893,7 +1893,7 @@ void SQLExecutor::multiSetComplex() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } int count = 0; @@ -1901,7 +1901,7 @@ void SQLExecutor::multiSetComplex() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 5); @@ -1911,7 +1911,7 @@ void SQLExecutor::multiSetComplex() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (result.size() == people.size()); @@ -1930,7 +1930,7 @@ void SQLExecutor::mapComplex() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } int count = 0; @@ -1938,7 +1938,7 @@ void SQLExecutor::mapComplex() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -1948,7 +1948,7 @@ void SQLExecutor::mapComplex() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (result == people); @@ -1970,7 +1970,7 @@ void SQLExecutor::mapComplexUnique() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } int count = 0; @@ -1978,7 +1978,7 @@ void SQLExecutor::mapComplexUnique() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 5); @@ -1988,7 +1988,7 @@ void SQLExecutor::mapComplexUnique() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (result.size() == 2); @@ -2010,7 +2010,7 @@ void SQLExecutor::multiMapComplex() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } int count = 0; @@ -2018,7 +2018,7 @@ void SQLExecutor::multiMapComplex() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 5); @@ -2028,7 +2028,7 @@ void SQLExecutor::multiMapComplex() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (result.size() == people.size()); @@ -2047,7 +2047,7 @@ void SQLExecutor::selectIntoSingle() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } int count = 0; @@ -2055,7 +2055,7 @@ void SQLExecutor::selectIntoSingle() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -2064,7 +2064,7 @@ void SQLExecutor::selectIntoSingle() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (result == p1); @@ -2083,7 +2083,7 @@ void SQLExecutor::selectIntoSingleStep() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } @@ -2092,7 +2092,7 @@ void SQLExecutor::selectIntoSingleStep() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -2119,7 +2119,7 @@ void SQLExecutor::selectIntoSingleFail() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } int count = 0; @@ -2127,7 +2127,7 @@ void SQLExecutor::selectIntoSingleFail() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -2154,7 +2154,7 @@ void SQLExecutor::lowerLimitOk() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } int count = 0; @@ -2162,7 +2162,7 @@ void SQLExecutor::lowerLimitOk() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -2189,7 +2189,7 @@ void SQLExecutor::singleSelect() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } int count = 0; @@ -2197,7 +2197,7 @@ void SQLExecutor::singleSelect() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -2224,7 +2224,7 @@ void SQLExecutor::lowerLimitFail() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } int count = 0; @@ -2232,7 +2232,7 @@ void SQLExecutor::lowerLimitFail() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -2259,7 +2259,7 @@ void SQLExecutor::combinedLimits() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } int count = 0; @@ -2267,7 +2267,7 @@ void SQLExecutor::combinedLimits() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -2276,7 +2276,7 @@ void SQLExecutor::combinedLimits() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (result.size() == 2); @@ -2298,7 +2298,7 @@ void SQLExecutor::ranges() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } int count = 0; @@ -2306,7 +2306,7 @@ void SQLExecutor::ranges() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -2315,7 +2315,7 @@ void SQLExecutor::ranges() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (result.size() == 2); @@ -2336,7 +2336,7 @@ void SQLExecutor::combinedIllegalLimits() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } int count = 0; @@ -2344,7 +2344,7 @@ void SQLExecutor::combinedIllegalLimits() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -2371,7 +2371,7 @@ void SQLExecutor::illegalRange() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } int count = 0; @@ -2379,7 +2379,7 @@ void SQLExecutor::illegalRange() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 2); @@ -2401,7 +2401,7 @@ void SQLExecutor::emptyDB() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 0); @@ -2495,7 +2495,7 @@ void SQLExecutor::blobStmt() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 1); @@ -2507,7 +2507,7 @@ void SQLExecutor::blobStmt() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } poco_assert (res == blob); @@ -2606,7 +2606,7 @@ void SQLExecutor::recordSet() assertTrue (rset.rowCount() == 0); assertTrue (rset.affectedRowCount() == 2); } - } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; fail (__func__, __LINE__, __FILE__); } + } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; failmsg (__func__); } } @@ -2619,14 +2619,14 @@ void SQLExecutor::dateTime() DateTime born(1965, 6, 18, 5, 35, 1); int count = 0; - try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastName), use(firstName), use(address), use(born), now; } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; fail (__func__, __LINE__, __FILE__); } + try { session() << formatSQL("INSERT INTO Person VALUES (?,?,?,?)"), use(lastName), use(firstName), use(address), use(born), now; } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; failmsg (__func__); } - try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; fail (__func__, __LINE__, __FILE__); } + try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; failmsg (__func__); } assertTrue (count == 1); DateTime res; - try { session() << "SELECT Born FROM Person", into(res), now; } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; fail (__func__, __LINE__, __FILE__); } + try { session() << "SELECT Born FROM Person", into(res), now; } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; failmsg (__func__); } assertTrue (res == born); @@ -2655,14 +2655,14 @@ void SQLExecutor::date() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 1); @@ -2673,7 +2673,7 @@ void SQLExecutor::date() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (d == bornDate); @@ -2705,14 +2705,14 @@ void SQLExecutor::time() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } try { session() << "SELECT COUNT(*) FROM Person", into(count), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (count == 1); @@ -2723,7 +2723,7 @@ void SQLExecutor::time() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (t == bornTime); @@ -2746,7 +2746,7 @@ void SQLExecutor::tuples() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } @@ -2756,7 +2756,7 @@ void SQLExecutor::tuples() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (ret == t); @@ -2778,7 +2778,7 @@ void SQLExecutor::tupleVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } int count = 0; @@ -2786,7 +2786,7 @@ void SQLExecutor::tupleVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (v.size() == count); @@ -2796,7 +2796,7 @@ void SQLExecutor::tupleVector() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } assertTrue (ret == v); @@ -2815,7 +2815,7 @@ void SQLExecutor::internalExtraction() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } try @@ -2952,12 +2952,12 @@ void SQLExecutor::internalExtraction() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } catch(Exception& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } } @@ -2975,7 +2975,7 @@ void SQLExecutor::filter(const std::string& query, const std::string& intFldName catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } try @@ -3043,9 +3043,104 @@ void SQLExecutor::filter(const std::string& query, const std::string& intFldName catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); + } + +} + + +void SQLExecutor::nullBulk(const std::string& blobPlaceholder) +{ + { + std::vector lastName(10, null); + std::vector firstName(10, null); + std::vector address(10, null); + std::vector blob(10, null); + + try + { + session() << Poco::format("INSERT INTO Person VALUES (?,?,?,%s)", blobPlaceholder), + use(lastName, bulk), use(firstName, bulk), use(address, bulk), use(blob, bulk), now; + } + catch(DataException& ce) + { + std::cout << ce.displayText() << std::endl; + failmsg (__func__); + } + + lastName.clear(); + firstName.clear(); + address.clear(); + blob.clear(); + + assertEqual (0, lastName.size()); + assertEqual (0, firstName.size()); + assertEqual (0, address.size()); + assertEqual (0, blob.size()); + /*TODO + try + { + session() << "SELECT * Person", + into(lastName, bulk), into(firstName, bulk), into(address, bulk), into(blob, bulk), now; + } + catch(DataException& ce) + { + std::cout << ce.displayText() << std::endl; + failmsg (__func__); + } + + assertEqual (10, lastName.size()); + assertEqual (10, firstName.size()); + assertEqual (10, address.size()); + assertEqual (10, blob.size()); + */ } + { + /* TODO + std::vector> lastName(10, null); + std::vector> firstName(10, null); + std::vector> address(10, null); + std::vector> blob(10, null); + + try + { + session() << Poco::format("INSERT INTO Person VALUES (?,?,?,%s)", blobPlaceholder),//"INSERT INTO Person (LastName) VALUES (?)", + use(lastName, bulk), use(firstName, bulk), use(address, bulk), use(blob, bulk), now; + } + catch(DataException& ce) + { + std::cout << ce.displayText() << std::endl; + failmsg (__func__); + } + + lastName.clear(); + firstName.clear(); + address.clear(); + blob.clear(); + + assertEqual (0, lastName.size()); + assertEqual (0, firstName.size()); + assertEqual (0, address.size()); + assertEqual (0, blob.size()); + + try + { + session() << "SELECT * Person", + into(lastName, bulk), into(firstName, bulk), into(address, bulk), into(blob, bulk), now; + } + catch(DataException& ce) + { + std::cout << ce.displayText() << std::endl; + failmsg (__func__); + } + + assertEqual (10, lastName.size()); + assertEqual (10, firstName.size()); + assertEqual (10, address.size()); + assertEqual (10, blob.size()); + */ + } } @@ -3077,7 +3172,7 @@ void SQLExecutor::internalBulkExtraction() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } try @@ -3097,7 +3192,7 @@ void SQLExecutor::internalBulkExtraction() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } try @@ -3114,7 +3209,7 @@ void SQLExecutor::internalBulkExtraction() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } } @@ -3143,7 +3238,7 @@ void SQLExecutor::internalBulkExtractionUTF16() use(address, bulk), use(age, bulk), now; - } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; fail (__func__, __LINE__, __FILE__); } + } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; failmsg (__func__); } try { @@ -3158,7 +3253,7 @@ void SQLExecutor::internalBulkExtractionUTF16() rset.moveLast(); assertTrue (std::string("LN") + NumberFormatter::format(size - 1) == rset["LastName"]); assertTrue (size - 1 == rset["Age"]); - } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; fail (__func__, __LINE__, __FILE__); } + } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; failmsg (__func__); } try { @@ -3170,7 +3265,7 @@ void SQLExecutor::internalBulkExtractionUTF16() rset.moveLast(); assertTrue (std::string("LN") + NumberFormatter::format(size - 1) == rset["LastName"]); assertTrue (size - 1 == rset["Age"]); - } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; fail (__func__, __LINE__, __FILE__); } + } catch (ConnectionFailedException& ce){ std::cout << ce.displayText() << std::endl; failmsg (__func__); } } @@ -3192,7 +3287,7 @@ void SQLExecutor::internalStorageType() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } try @@ -3245,7 +3340,7 @@ void SQLExecutor::internalStorageType() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } } @@ -3257,7 +3352,7 @@ void SQLExecutor::nulls() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } RecordSet rs(session(), "SELECT * FROM NullTest"); @@ -3278,7 +3373,7 @@ void SQLExecutor::nulls() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } int i = 1; @@ -3289,7 +3384,7 @@ void SQLExecutor::nulls() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } rs = (session() << "SELECT * FROM NullTest", now); @@ -3310,7 +3405,7 @@ void SQLExecutor::nulls() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } i = 2; @@ -3319,7 +3414,7 @@ void SQLExecutor::nulls() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } rs = (session() << "SELECT i, r, v FROM NullTest ORDER BY i ASC", now); @@ -3342,14 +3437,14 @@ void SQLExecutor::nulls() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } try { session() << formatSQL("INSERT INTO NullTest (v) VALUES (?)"), bind(""), now; } catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } bool esin = session().getFeature("emptyStringIsNull"); @@ -3401,7 +3496,7 @@ void SQLExecutor::rowIterator() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } RecordSet rset0(session(), "SELECT * FROM Vectors"); @@ -3411,7 +3506,7 @@ void SQLExecutor::rowIterator() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } RecordSet rset(session(), "SELECT * FROM Vectors"); @@ -3451,7 +3546,7 @@ void SQLExecutor::stdVectorBool() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } b = true; @@ -3464,7 +3559,7 @@ void SQLExecutor::stdVectorBool() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } b = false; @@ -3482,7 +3577,7 @@ void SQLExecutor::stdVectorBool() catch(DataException& ce) { std::cout << ce.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } v.clear(); @@ -4297,7 +4392,7 @@ void SQLExecutor::transactor() catch (Poco::Exception& ex) { std::cerr << __func__ << ':' << ex.displayText() << std::endl; - fail (__func__, __LINE__, __FILE__); + failmsg (__func__); } } diff --git a/Data/ODBC/include/Poco/Data/ODBC/Binder.h b/Data/ODBC/include/Poco/Data/ODBC/Binder.h index 6274d7cff7..22439b8459 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/Binder.h +++ b/Data/ODBC/include/Poco/Data/ODBC/Binder.h @@ -339,6 +339,27 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder void bind(std::size_t pos, const std::list& val, Direction dir); /// Binds a null list. + template + void bind(std::size_t pos, const std::vector>& val, Direction dir) + /// Binds a nullable vector. + { + bindImplNullableContainer(pos, val, dir); + } + + template + void bind(std::size_t pos, const std::deque>& val, Direction dir) + /// Binds a nullable deque. + { + bindImplNullableContainer(pos, val, dir); + } + + template + void bind(std::size_t pos, const std::list>& val, Direction dir) + /// Binds a nullable list. + { + bindImplNullableContainer(pos, val, dir); + } + void setDataBinding(ParameterBinding binding); /// Set data binding type. @@ -437,7 +458,7 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder (SQLUSMALLINT) pos + 1, SQL_PARAM_INPUT, SQL_C_BINARY, - Utility::sqlDataType(SQL_C_BINARY), + TypeInfo::sqlDataType(), columnSize, 0, pVal, @@ -615,7 +636,7 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder (SQLUSMALLINT) pos + 1, toODBCDirection(dir), SQL_C_CHAR, - Utility::sqlDataType(SQL_C_CHAR), + TypeInfo::sqlDataType(), getStringColSize(size), 0, _charPtrs[pos], @@ -682,7 +703,7 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder (SQLUSMALLINT)pos + 1, toODBCDirection(dir), SQL_C_WCHAR, - Utility::sqlDataType(SQL_C_WCHAR), + TypeInfo::sqlDataType(), getStringColSize(size), 0, _utf16CharPtrs[pos], @@ -752,7 +773,7 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder (SQLUSMALLINT) pos + 1, SQL_PARAM_INPUT, SQL_C_BINARY, - Utility::sqlDataType(SQL_C_BINARY), + TypeInfo::sqlDataType(), (SQLUINTEGER) size, 0, _charPtrs[pos], @@ -801,7 +822,7 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder (SQLUSMALLINT) pos + 1, toODBCDirection(dir), SQL_C_TYPE_DATE, - Utility::sqlDataType(SQL_C_TYPE_DATE), + TypeInfo::sqlDataType(), colSize, decDigits, (SQLPOINTER) &(*_dateVecVec[pos])[0], @@ -849,7 +870,7 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder (SQLUSMALLINT) pos + 1, toODBCDirection(dir), SQL_C_TYPE_TIME, - Utility::sqlDataType(SQL_C_TYPE_TIME), + TypeInfo::sqlDataType(), colSize, decDigits, (SQLPOINTER) &(*_timeVecVec[pos])[0], @@ -898,7 +919,7 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder (SQLUSMALLINT) pos + 1, toODBCDirection(dir), SQL_C_TYPE_TIMESTAMP, - Utility::sqlDataType(SQL_C_TYPE_TIMESTAMP), + TypeInfo::sqlDataType(), colSize, decDigits, (SQLPOINTER) &(*_dateTimeVecVec[pos])[0], @@ -919,6 +940,7 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder throw InvalidAccessException("ODBC::Binder::bindImplNullContainer():Container can only be bound immediately."); std::size_t length = val.size(); + poco_assert (length); if (0 == length) throw InvalidArgumentException("ODBC::Binder::bindImplNullContainer():Empty container not allowed."); @@ -928,18 +950,68 @@ class ODBC_API Binder: public Poco::Data::AbstractBinder if (_vecLengthIndicator.size() <= pos) { _vecLengthIndicator.resize(pos + 1, 0); - _vecLengthIndicator[pos] = new LengthVec(length ? length : 1); + _vecLengthIndicator[pos] = new LengthVec(length, SQL_NULL_DATA); + } + + SQLINTEGER colSize = 0; + SQLSMALLINT decDigits = 0; + getColSizeAndPrecision(pos, SQL_C_CHAR, colSize, decDigits); + + if (Utility::isError(SQLBindParameter(_rStmt, + (SQLUSMALLINT) pos + 1, + SQL_PARAM_INPUT, + SQL_C_CHAR, + TypeInfo::sqlDataType(), + colSize, + decDigits, + 0, + 0, + &(*_vecLengthIndicator[pos])[0]))) + { + throw StatementException(_rStmt, "ODBC::Binder::bindImplNullContainer():SQLBindParameter()"); + } + } + + template + void bindImplNullableContainer(std::size_t pos, const C& val, Direction dir) + { + if (isOutBound(dir) || !isInBound(dir)) + throw NotImplementedException("ODBC::Binder::bindImplNullContainer():Null container parameter type can only be inbound."); + + if (PB_IMMEDIATE != _paramBinding) + throw InvalidAccessException("ODBC::Binder::bindImplNullContainer():Container can only be bound immediately."); + + std::size_t length = val.size(); + poco_assert (length); + + if (0 == length) + throw InvalidArgumentException("ODBC::Binder::bindImplNullContainer():Empty container not allowed."); + + setParamSetSize(length); + + if (_vecLengthIndicator.size() <= pos) + { + _vecLengthIndicator.resize(pos + 1, 0); + _vecLengthIndicator[pos] = new LengthVec(length, SQL_NULL_DATA); + auto valIt = val.begin(), valEnd = val.end(); + auto lenIt = _vecLengthIndicator[pos]->begin(), lenEnd = _vecLengthIndicator[pos]->end(); + for (; valIt != valEnd && lenIt != lenEnd; ++valIt, ++lenIt) + { + if (valIt->isNull()) *lenIt = SQL_NULL_DATA; + else *lenIt = Utility::sizeOf(); + } + } SQLINTEGER colSize = 0; SQLSMALLINT decDigits = 0; - getColSizeAndPrecision(pos, SQL_C_STINYINT, colSize, decDigits); + getColSizeAndPrecision(pos, SQL_C_CHAR, colSize, decDigits); if (Utility::isError(SQLBindParameter(_rStmt, (SQLUSMALLINT) pos + 1, SQL_PARAM_INPUT, - SQL_C_STINYINT, - Utility::sqlDataType(SQL_C_STINYINT), + SQL_C_CHAR, + TypeInfo::sqlDataType(), colSize, decDigits, 0, diff --git a/Data/ODBC/include/Poco/Data/ODBC/TypeInfo.h b/Data/ODBC/include/Poco/Data/ODBC/TypeInfo.h index b852ec1cac..80805a9d36 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/TypeInfo.h +++ b/Data/ODBC/include/Poco/Data/ODBC/TypeInfo.h @@ -76,11 +76,111 @@ class ODBC_API TypeInfo ~TypeInfo(); /// Destroys the TypeInfo. - int cDataType(int sqlDataType) const; + SQLSMALLINT cDataType(SQLSMALLINT sqlDataType) const; /// Returns C data type corresponding to supplied SQL data type. - int sqlDataType(int cDataType) const; + template + static constexpr SQLSMALLINT cDataType() + /// Returns C data type corresponding to supplied SQL data type. + { + static_assert ( + (T == SQL_CHAR ) || + (T == SQL_CHAR ) || + (T == SQL_VARCHAR ) || + (T == SQL_LONGVARCHAR ) || + (T == SQL_DECIMAL ) || + (T == SQL_NUMERIC ) || + (T == SQL_BIT ) || + (T == SQL_TINYINT ) || + (T == SQL_SMALLINT ) || + (T == SQL_INTEGER ) || + (T == SQL_BIGINT ) || + (T == SQL_REAL ) || + (T == SQL_FLOAT ) || + (T == SQL_DOUBLE ) || + (T == SQL_BINARY ) || + (T == SQL_VARBINARY ) || + (T == SQL_LONGVARBINARY ) || + (T == SQL_TYPE_DATE ) || + (T == SQL_TYPE_TIME ) || + (T == SQL_TYPE_TIMESTAMP), "TypeInfo::cDataType(): Unknown SQL type."s + ); + + if constexpr(T == SQL_CHAR ) return SQL_C_CHAR; + if constexpr(T == SQL_CHAR ) return SQL_C_CHAR; + if constexpr(T == SQL_VARCHAR ) return SQL_C_CHAR; + if constexpr(T == SQL_LONGVARCHAR ) return SQL_C_CHAR; + if constexpr(T == SQL_DECIMAL ) return SQL_C_DOUBLE; + if constexpr(T == SQL_NUMERIC ) return SQL_C_DOUBLE; + if constexpr(T == SQL_BIT ) return SQL_C_BIT; + if constexpr(T == SQL_TINYINT ) return SQL_C_STINYINT; + if constexpr(T == SQL_SMALLINT ) return SQL_C_SSHORT; + if constexpr(T == SQL_INTEGER ) return SQL_C_SLONG; + if constexpr(T == SQL_BIGINT ) return SQL_C_SBIGINT; + if constexpr(T == SQL_REAL ) return SQL_C_FLOAT; + if constexpr(T == SQL_FLOAT ) return SQL_C_DOUBLE; + if constexpr(T == SQL_DOUBLE ) return SQL_C_DOUBLE; + if constexpr(T == SQL_BINARY ) return SQL_C_BINARY; + if constexpr(T == SQL_VARBINARY ) return SQL_C_BINARY; + if constexpr(T == SQL_LONGVARBINARY ) return SQL_C_BINARY; + if constexpr(T == SQL_TYPE_DATE ) return SQL_C_TYPE_DATE; + if constexpr(T == SQL_TYPE_TIME ) return SQL_C_TYPE_TIME; + if constexpr(T == SQL_TYPE_TIMESTAMP) return SQL_C_TYPE_TIMESTAMP; + return 0; + } + + SQLSMALLINT sqlDataType(SQLSMALLINT cDataType) const; + /// Returns SQL data type corresponding to supplied C data type. + + template + static constexpr SQLSMALLINT sqlDataType() /// Returns SQL data type corresponding to supplied C data type. + { + static_assert ( + (T == SQL_C_CHAR ) || + (T == SQL_C_WCHAR ) || + (T == SQL_C_BIT ) || + (T == SQL_C_TINYINT ) || + (T == SQL_C_STINYINT ) || + (T == SQL_C_UTINYINT ) || + (T == SQL_C_SHORT ) || + (T == SQL_C_SSHORT ) || + (T == SQL_C_USHORT ) || + (T == SQL_C_LONG ) || + (T == SQL_C_SLONG ) || + (T == SQL_C_ULONG ) || + (T == SQL_C_SBIGINT ) || + (T == SQL_C_UBIGINT ) || + (T == SQL_C_FLOAT ) || + (T == SQL_C_DOUBLE ) || + (T == SQL_C_BINARY ) || + (T == SQL_C_TYPE_DATE ) || + (T == SQL_C_TYPE_TIME ) || + (T == SQL_C_TYPE_TIMESTAMP), "TypeInfo::sqlDataType(): Unknown C type."s + ); + + if constexpr(T == SQL_C_CHAR ) return SQL_VARCHAR; + if constexpr(T == SQL_C_WCHAR ) return SQL_WVARCHAR; + if constexpr(T == SQL_C_BIT ) return SQL_BIT; + if constexpr(T == SQL_C_TINYINT ) return SQL_TINYINT; + if constexpr(T == SQL_C_STINYINT ) return SQL_TINYINT; + if constexpr(T == SQL_C_UTINYINT ) return SQL_TINYINT; + if constexpr(T == SQL_C_SHORT ) return SQL_SMALLINT; + if constexpr(T == SQL_C_SSHORT ) return SQL_SMALLINT; + if constexpr(T == SQL_C_USHORT ) return SQL_SMALLINT; + if constexpr(T == SQL_C_LONG ) return SQL_INTEGER; + if constexpr(T == SQL_C_SLONG ) return SQL_INTEGER; + if constexpr(T == SQL_C_ULONG ) return SQL_INTEGER; + if constexpr(T == SQL_C_SBIGINT ) return SQL_BIGINT; + if constexpr(T == SQL_C_UBIGINT ) return SQL_BIGINT; + if constexpr(T == SQL_C_FLOAT ) return SQL_REAL; + if constexpr(T == SQL_C_DOUBLE ) return SQL_DOUBLE; + if constexpr(T == SQL_C_BINARY ) return SQL_LONGVARBINARY; + if constexpr(T == SQL_C_TYPE_DATE ) return SQL_TYPE_DATE; + if constexpr(T == SQL_C_TYPE_TIME ) return SQL_TYPE_TIME; + if constexpr(T == SQL_C_TYPE_TIMESTAMP) return SQL_TYPE_TIMESTAMP; + return 0; + } void fillTypeInfo(const SQLHDBC* pHDBC); /// Fills the data type info structure for the database. @@ -107,7 +207,7 @@ class ODBC_API TypeInfo DataTypeMap _cDataTypes; DataTypeMap _sqlDataTypes; TypeInfoVec _typeInfo; - const SQLHDBC* _pHDBC; + const SQLHDBC* _pHDBC; }; diff --git a/Data/ODBC/include/Poco/Data/ODBC/Utility.h b/Data/ODBC/include/Poco/Data/ODBC/Utility.h index 1cb1825239..3fe79e1c5e 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/Utility.h +++ b/Data/ODBC/include/Poco/Data/ODBC/Utility.h @@ -171,6 +171,31 @@ class ODBC_API Utility /// Returns the back end DBMS name. /// On error, returns "unknown". + template + static constexpr SQLINTEGER sizeOf() + /// Returns size of the data type. + { + static_assert ( + (std::is_same_v) || + (std::is_same_v) || + (std::is_same_v) || + (std::is_same_v), "Utility::sizeOf(): Unsupported type"s + ); + + if constexpr(std::is_same_v) return sizeof(SQL_DATE_STRUCT); + if constexpr(std::is_same_v) return sizeof(SQL_TIME_STRUCT); + if constexpr(std::is_same_v) return sizeof(SQL_TIMESTAMP_STRUCT); + if constexpr(std::is_same_v) return 16; + return 0; + } + + template + static constexpr SQLINTEGER sizeOf(const T&) + /// Returns size of the data type. + { + return sizeOf>>(); + } + private: static const TypeInfo _dataTypes; /// C <==> SQL data type mapping diff --git a/Data/ODBC/src/Binder.cpp b/Data/ODBC/src/Binder.cpp index 1f282eb039..94eb5dc3f2 100644 --- a/Data/ODBC/src/Binder.cpp +++ b/Data/ODBC/src/Binder.cpp @@ -165,7 +165,7 @@ void Binder::bind(std::size_t pos, const std::string& val, Direction dir) (SQLUSMALLINT)pos + 1, toODBCDirection(dir), SQL_C_CHAR, - Utility::sqlDataType(SQL_C_CHAR), + TypeInfo::sqlDataType(), getStringColSize(colSize), 0, pVal, @@ -218,7 +218,7 @@ void Binder::bind(std::size_t pos, const UTF16String& val, Direction dir) (SQLUSMALLINT)pos + 1, toODBCDirection(dir), SQL_C_WCHAR, - Utility::sqlDataType(SQL_C_WCHAR), + TypeInfo::sqlDataType(), getStringColSize(colSize), 0, pVal, @@ -232,7 +232,7 @@ void Binder::bind(std::size_t pos, const UTF16String& val, Direction dir) void Binder::bind(std::size_t pos, const Date& val, Direction dir) { - SQLINTEGER size = (SQLINTEGER) sizeof(SQL_DATE_STRUCT); + SQLINTEGER size = Utility::sizeOf(val); SQLLEN* pLenIn = new SQLLEN; *pLenIn = size; @@ -251,7 +251,7 @@ void Binder::bind(std::size_t pos, const Date& val, Direction dir) (SQLUSMALLINT) pos + 1, toODBCDirection(dir), SQL_C_TYPE_DATE, - Utility::sqlDataType(SQL_C_TYPE_DATE), + TypeInfo::sqlDataType(), colSize, decDigits, (SQLPOINTER) pDS, @@ -265,7 +265,7 @@ void Binder::bind(std::size_t pos, const Date& val, Direction dir) void Binder::bind(std::size_t pos, const Time& val, Direction dir) { - SQLINTEGER size = (SQLINTEGER) sizeof(SQL_TIME_STRUCT); + SQLINTEGER size = Utility::sizeOf(val); SQLLEN* pLenIn = new SQLLEN; *pLenIn = size; @@ -284,7 +284,7 @@ void Binder::bind(std::size_t pos, const Time& val, Direction dir) (SQLUSMALLINT) pos + 1, toODBCDirection(dir), SQL_C_TYPE_TIME, - Utility::sqlDataType(SQL_C_TYPE_TIME), + TypeInfo::sqlDataType(), colSize, decDigits, (SQLPOINTER) pTS, @@ -298,7 +298,7 @@ void Binder::bind(std::size_t pos, const Time& val, Direction dir) void Binder::bind(std::size_t pos, const Poco::DateTime& val, Direction dir) { - SQLINTEGER size = (SQLINTEGER) sizeof(SQL_TIMESTAMP_STRUCT); + SQLINTEGER size = Utility::sizeOf(val); SQLLEN* pLenIn = new SQLLEN; *pLenIn = size; @@ -317,7 +317,7 @@ void Binder::bind(std::size_t pos, const Poco::DateTime& val, Direction dir) (SQLUSMALLINT) pos + 1, toODBCDirection(dir), SQL_C_TYPE_TIMESTAMP, - Utility::sqlDataType(SQL_C_TYPE_TIMESTAMP), + TypeInfo::sqlDataType(), colSize, decDigits, (SQLPOINTER) pTS, @@ -331,7 +331,7 @@ 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; + SQLINTEGER size = Utility::sizeOf(val); SQLLEN* pLenIn = new SQLLEN; *pLenIn = size; @@ -375,13 +375,13 @@ void Binder::bind(std::size_t pos, const NullData& val, Direction dir) SQLINTEGER colSize = 0; SQLSMALLINT decDigits = 0; - getColSizeAndPrecision(pos, SQL_C_STINYINT, colSize, decDigits); + getColSizeAndPrecision(pos, SQL_C_CHAR, colSize, decDigits); if (Utility::isError(SQLBindParameter(_rStmt, (SQLUSMALLINT) pos + 1, SQL_PARAM_INPUT, SQL_C_CHAR, - Utility::sqlDataType(SQL_C_CHAR), + TypeInfo::sqlDataType(), colSize, decDigits, 0, diff --git a/Data/ODBC/src/TypeInfo.cpp b/Data/ODBC/src/TypeInfo.cpp index 615471a960..162a4d1b02 100644 --- a/Data/ODBC/src/TypeInfo.cpp +++ b/Data/ODBC/src/TypeInfo.cpp @@ -198,7 +198,7 @@ bool TypeInfo::tryGetInfo(SQLSMALLINT type, const std::string& param, Dynamic::V } -int TypeInfo::cDataType(int sqlDataType) const +SQLSMALLINT TypeInfo::cDataType(SQLSMALLINT sqlDataType) const { DataTypeMap::const_iterator it = _cDataTypes.find(sqlDataType); @@ -209,7 +209,7 @@ int TypeInfo::cDataType(int sqlDataType) const } -int TypeInfo::sqlDataType(int cDataType) const +SQLSMALLINT TypeInfo::sqlDataType(SQLSMALLINT cDataType) const { DataTypeMap::const_iterator it = _sqlDataTypes.find(cDataType); diff --git a/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp b/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp index d9ce9e581d..0ef3cddf83 100644 --- a/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp +++ b/Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp @@ -399,6 +399,18 @@ void ODBCSQLServerTest::testNull() } +void ODBCSQLServerTest::testNullBulk() +{ + if (!_pSession) fail ("Test not available."); + + _pSession->setFeature("autoBind", true); + _pSession->setFeature("autoExtract", true); + + recreatePersonBLOBTable(); + _pExecutor->nullBulk("CONVERT(VARBINARY(30),?)"); +} + + void ODBCSQLServerTest::testBulk() { if (!_pSession) fail ("Test not available."); @@ -1086,6 +1098,7 @@ CppUnit::Test* ODBCSQLServerTest::suite() CppUnit_addTest(pSuite, ODBCSQLServerTest, testLimitZero); CppUnit_addTest(pSuite, ODBCSQLServerTest, testPrepare); CppUnit_addTest(pSuite, ODBCSQLServerTest, testBulk); + CppUnit_addTest(pSuite, ODBCSQLServerTest, testNullBulk); CppUnit_addTest(pSuite, ODBCSQLServerTest, testBulkPerformance); CppUnit_addTest(pSuite, ODBCSQLServerTest, testSetSimple); CppUnit_addTest(pSuite, ODBCSQLServerTest, testSetComplex); diff --git a/Data/ODBC/testsuite/src/ODBCSQLServerTest.h b/Data/ODBC/testsuite/src/ODBCSQLServerTest.h index d1557a1711..56ee318139 100644 --- a/Data/ODBC/testsuite/src/ODBCSQLServerTest.h +++ b/Data/ODBC/testsuite/src/ODBCSQLServerTest.h @@ -51,6 +51,7 @@ class ODBCSQLServerTest: public ODBCTest void testBigStringVector(); void testBigBatch(); void testNull() override; + void testNullBulk(); void testBulk() override; void testStoredProcedure() override; diff --git a/Data/ODBC/testsuite/src/SQLExecutor.h b/Data/ODBC/testsuite/src/SQLExecutor.h index 2353d29317..dbff3853a1 100644 --- a/Data/ODBC/testsuite/src/SQLExecutor.h +++ b/Data/ODBC/testsuite/src/SQLExecutor.h @@ -158,6 +158,8 @@ class SQLExecutor: public CppUnit::TestCase void limitZero(); void prepare(); + void nullBulk(const std::string& blobPlaceholder); + template void doBulkWithBool(Poco::UInt32 size, const std::string& blobPlaceholder="?") { @@ -719,6 +721,12 @@ inline void SQLExecutor::prepare() } +inline void SQLExecutor::nullBulk(const std::string& blobPlaceholder) +{ + _dataExecutor.nullBulk(blobPlaceholder); +} + + inline void SQLExecutor::doBulkPerformance(Poco::UInt32 size) { _dataExecutor.doBulkPerformance(size); diff --git a/Foundation/include/Poco/Nullable.h b/Foundation/include/Poco/Nullable.h index b385bdd70c..df3e82c278 100644 --- a/Foundation/include/Poco/Nullable.h +++ b/Foundation/include/Poco/Nullable.h @@ -53,6 +53,8 @@ class Nullable /// default construction. { public: + using Type = C; + Nullable() /// Creates an empty Nullable. { From a66450ae17f244272a862a07ef7d8fa8a57a849b Mon Sep 17 00:00:00 2001 From: Alex Fabijanic Date: Fri, 1 Nov 2024 09:07:27 -0500 Subject: [PATCH 02/20] fix: remove string suffix for static_assert --- Data/ODBC/include/Poco/Data/ODBC/TypeInfo.h | 4 ++-- Data/ODBC/include/Poco/Data/ODBC/Utility.h | 2 +- Foundation/include/Poco/Exception.h | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Data/ODBC/include/Poco/Data/ODBC/TypeInfo.h b/Data/ODBC/include/Poco/Data/ODBC/TypeInfo.h index 80805a9d36..8eff5070a1 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/TypeInfo.h +++ b/Data/ODBC/include/Poco/Data/ODBC/TypeInfo.h @@ -103,7 +103,7 @@ class ODBC_API TypeInfo (T == SQL_LONGVARBINARY ) || (T == SQL_TYPE_DATE ) || (T == SQL_TYPE_TIME ) || - (T == SQL_TYPE_TIMESTAMP), "TypeInfo::cDataType(): Unknown SQL type."s + (T == SQL_TYPE_TIMESTAMP), "TypeInfo::cDataType(): Unknown SQL type." ); if constexpr(T == SQL_CHAR ) return SQL_C_CHAR; @@ -156,7 +156,7 @@ class ODBC_API TypeInfo (T == SQL_C_BINARY ) || (T == SQL_C_TYPE_DATE ) || (T == SQL_C_TYPE_TIME ) || - (T == SQL_C_TYPE_TIMESTAMP), "TypeInfo::sqlDataType(): Unknown C type."s + (T == SQL_C_TYPE_TIMESTAMP), "TypeInfo::sqlDataType(): Unknown C type." ); if constexpr(T == SQL_C_CHAR ) return SQL_VARCHAR; diff --git a/Data/ODBC/include/Poco/Data/ODBC/Utility.h b/Data/ODBC/include/Poco/Data/ODBC/Utility.h index 3fe79e1c5e..32541ceac4 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/Utility.h +++ b/Data/ODBC/include/Poco/Data/ODBC/Utility.h @@ -179,7 +179,7 @@ class ODBC_API Utility (std::is_same_v) || (std::is_same_v) || (std::is_same_v) || - (std::is_same_v), "Utility::sizeOf(): Unsupported type"s + (std::is_same_v), "Utility::sizeOf(): Unsupported type" ); if constexpr(std::is_same_v) return sizeof(SQL_DATE_STRUCT); diff --git a/Foundation/include/Poco/Exception.h b/Foundation/include/Poco/Exception.h index f2cdd02d6e..30a2da05d8 100644 --- a/Foundation/include/Poco/Exception.h +++ b/Foundation/include/Poco/Exception.h @@ -100,14 +100,14 @@ class Foundation_API Exception: public std::exception private: std::string _msg; Exception* _pNested; - int _code; + int _code; }; #if defined(_HAS_EXCEPTIONS) - // Size of Poco::Exception depends on the exception settings (like _HAS_EXCEPTIONS) - // that might influence size of std::exception from which Poco::Exception is derived from. - // It is expected that Poco libraries and application using Poco have the same settings. - static_assert(_HAS_EXCEPTIONS != 0); + // Size of Poco::Exception depends on the exception settings (like _HAS_EXCEPTIONS) + // that might influence size of std::exception from which Poco::Exception is derived from. + // It is expected that Poco libraries and application using Poco have the same settings. + static_assert(_HAS_EXCEPTIONS != 0); #endif // From 11f9017cba3921e72fe72dc7fa8a248b206e1d2c Mon Sep 17 00:00:00 2001 From: Alex Fabijanic Date: Fri, 8 Nov 2024 07:46:38 +0100 Subject: [PATCH 03/20] Insert NULL using BULK #4001 --- .../include/Poco/Data/Test/SQLExecutor.h | 2 +- Data/DataTest/src/SQLExecutor.cpp | 108 ++- Data/ODBC/include/Poco/Data/ODBC/Extractor.h | 83 ++ Data/ODBC/include/Poco/Data/ODBC/Preparator.h | 2 +- Data/ODBC/src/Extractor.cpp | 146 ++++ Data/ODBC/src/ODBCStatementImpl.cpp | 1 + Data/ODBC/testsuite/src/ODBCOracleTest.cpp | 1 + Data/ODBC/testsuite/src/ODBCSQLServerTest.cpp | 14 +- Data/ODBC/testsuite/src/ODBCSQLServerTest.h | 2 +- Data/ODBC/testsuite/src/ODBCTest.cpp | 18 +- Data/ODBC/testsuite/src/ODBCTest.h | 1 + Data/ODBC/testsuite/src/ODBCTestSuite.cpp | 13 - Data/ODBC/testsuite/src/SQLExecutor.h | 2 +- .../include/Poco/Data/SQLite/Extractor.h | 328 +++++++- Data/SQLite/src/Extractor.cpp | 643 +++++++++++++++ Data/SQLite/testsuite/src/SQLiteTest.cpp | 155 +++- Data/SQLite/testsuite/src/SQLiteTest.h | 1 + Data/include/Poco/Data/AbstractBinder.h | 2 +- Data/include/Poco/Data/AbstractExtractor.h | 210 +++-- Data/include/Poco/Data/AbstractPreparator.h | 302 ++++++- Data/include/Poco/Data/TypeHandler.h | 12 +- Data/src/AbstractExtractor.cpp | 358 ++------- Data/src/AbstractPreparator.cpp | 743 ++++++++++++++++-- Data/testsuite/src/DataTest.cpp | 14 +- Data/testsuite/src/DataTest.h | 1 + Data/testsuite/src/Extractor.cpp | 626 +++++++++++++++ Data/testsuite/src/Extractor.h | 363 ++++++++- Foundation/include/Poco/Nullable.h | 4 +- Foundation/include/Poco/Types.h | 7 + 29 files changed, 3600 insertions(+), 562 deletions(-) diff --git a/Data/DataTest/include/Poco/Data/Test/SQLExecutor.h b/Data/DataTest/include/Poco/Data/Test/SQLExecutor.h index f339ded1e2..6df3e444f3 100644 --- a/Data/DataTest/include/Poco/Data/Test/SQLExecutor.h +++ b/Data/DataTest/include/Poco/Data/Test/SQLExecutor.h @@ -242,7 +242,7 @@ class DataTest_API SQLExecutor: public CppUnit::TestCase "SELECT * FROM Vectors ORDER BY int0 ASC", const std::string& intFldName = "int0"); - void nullBulk(const std::string& blobPlaceholder); + void nullBulk(const std::string& blobPlaceholder = "?"s); void internalBulkExtraction(); void internalBulkExtractionUTF16(); void internalStorageType(); diff --git a/Data/DataTest/src/SQLExecutor.cpp b/Data/DataTest/src/SQLExecutor.cpp index 705aca5379..8b29002e2b 100644 --- a/Data/DataTest/src/SQLExecutor.cpp +++ b/Data/DataTest/src/SQLExecutor.cpp @@ -3051,11 +3051,13 @@ void SQLExecutor::filter(const std::string& query, const std::string& intFldName void SQLExecutor::nullBulk(const std::string& blobPlaceholder) { + const int sz = 10; + { - std::vector lastName(10, null); - std::vector firstName(10, null); - std::vector address(10, null); - std::vector blob(10, null); + std::vector lastName(sz, null); + std::vector firstName(sz, null); + std::vector address(sz, null); + std::vector blob(sz, null); try { @@ -3067,21 +3069,18 @@ void SQLExecutor::nullBulk(const std::string& blobPlaceholder) std::cout << ce.displayText() << std::endl; failmsg (__func__); } + } - lastName.clear(); - firstName.clear(); - address.clear(); - blob.clear(); + { + std::vector> lastName(sz, null); + std::vector> firstName(sz, null); + std::vector> address(sz, null); + std::vector> blob(sz, null); - assertEqual (0, lastName.size()); - assertEqual (0, firstName.size()); - assertEqual (0, address.size()); - assertEqual (0, blob.size()); - /*TODO try { - session() << "SELECT * Person", - into(lastName, bulk), into(firstName, bulk), into(address, bulk), into(blob, bulk), now; + session() << "SELECT * FROM Person", + into(lastName), into(firstName), into(address), into(blob), now; } catch(DataException& ce) { @@ -3089,24 +3088,52 @@ void SQLExecutor::nullBulk(const std::string& blobPlaceholder) failmsg (__func__); } - assertEqual (10, lastName.size()); - assertEqual (10, firstName.size()); - assertEqual (10, address.size()); - assertEqual (10, blob.size()); - */ + assertEqual (sz, lastName.size()); + assertEqual (sz, firstName.size()); + assertEqual (sz, address.size()); + assertEqual (sz, blob.size()); + + for (int i = 0; i < sz; ++i) + { + assertTrue (lastName[i].isNull()); + assertTrue (firstName[i].isNull()); + assertTrue (address[i].isNull()); + assertTrue (blob[i].isNull()); + } } + session() << "DELETE FROM Person", now; + { - /* TODO std::vector> lastName(10, null); std::vector> firstName(10, null); std::vector> address(10, null); std::vector> blob(10, null); + for (int i = 0; i < sz; ++i) + { + std::ostringstream ostr; + ostr << "abc" << i; + lastName[i] = ostr.str(); + + if (i % 2) + { + ostr.str(""s); + ostr << "def" << i; + firstName[i] = ostr.str(); + ostr.str(""s); + ostr << "ghi" << i; + address[i] = ostr.str(); + ostr.str(""s); + ostr << "jkl" << i; + blob[i] = BLOB((unsigned char*)ostr.str().data(), ostr.str().length()); + } + } + try { - session() << Poco::format("INSERT INTO Person VALUES (?,?,?,%s)", blobPlaceholder),//"INSERT INTO Person (LastName) VALUES (?)", - use(lastName, bulk), use(firstName, bulk), use(address, bulk), use(blob, bulk), now; + session() << Poco::format("INSERT INTO Person VALUES (?,?,?,%s)", blobPlaceholder), + use(lastName), use(firstName), use(address), use(blob), now; } catch(DataException& ce) { @@ -3126,8 +3153,8 @@ void SQLExecutor::nullBulk(const std::string& blobPlaceholder) try { - session() << "SELECT * Person", - into(lastName, bulk), into(firstName, bulk), into(address, bulk), into(blob, bulk), now; + session() << "SELECT * FROM Person ORDER BY lastName", + into(lastName), into(firstName), into(address), into(blob), now; } catch(DataException& ce) { @@ -3139,7 +3166,36 @@ void SQLExecutor::nullBulk(const std::string& blobPlaceholder) assertEqual (10, firstName.size()); assertEqual (10, address.size()); assertEqual (10, blob.size()); - */ + + for (int i = 0; i < sz; ++i) + { + assertFalse(lastName[i].isNull()); + std::ostringstream ostr; + ostr << "abc" << i; + assertEqual(ostr.str(), lastName[i].value()); + + if (i % 2) + { + assertFalse(firstName[i].isNull()); + ostr.str(""s); + ostr << "def" << i; + assertEqual(ostr.str(), firstName[i].value()); + assertFalse(address[i].isNull()); + ostr.str(""s); + ostr << "ghi" << i; + assertEqual(ostr.str(), address[i].value()); + assertFalse(blob[i].isNull()); + ostr.str(""s); + ostr << "jkl" << i; + assertTrue(BLOB((unsigned char*)ostr.str().data(), ostr.str().length()) == blob[i].value()); + } + else + { + assertTrue(firstName[i].isNull()); + assertTrue(address[i].isNull()); + assertTrue(blob[i].isNull()); + } + } } } diff --git a/Data/ODBC/include/Poco/Data/ODBC/Extractor.h b/Data/ODBC/include/Poco/Data/ODBC/Extractor.h index 655e14eb22..f36b4fa122 100644 --- a/Data/ODBC/include/Poco/Data/ODBC/Extractor.h +++ b/Data/ODBC/include/Poco/Data/ODBC/Extractor.h @@ -335,6 +335,80 @@ class ODBC_API Extractor: public Poco::Data::AbstractExtractor bool extract(std::size_t pos, std::list& val); /// Extracts a Dynamic::Var list. + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable Int8. + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable UInt8. + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable Int16. + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable UInt16. + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable Int32. + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable UInt32. + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable Int64. + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable UInt64. + +#ifndef POCO_INT64_IS_LONG + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable long. + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable unsigned long. +#endif + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable bool. + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable float. + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable double. + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable char. + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable string. + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable UTF16String. + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable BLOB. + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable CLOB. + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable DateTime. + + bool extract(std::size_t pos, Poco::Nullable& val); + /// Extracts a Nullable Date. + + bool extract(std::size_t pos, Poco::Nullable