mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-25 02:06:04 +02:00
internal bulk extraction; some fixes for recently added features
This commit is contained in:
@@ -428,8 +428,8 @@ private:
|
||||
|
||||
template <typename C>
|
||||
void bindImplContainer(std::size_t pos, const C& val, SQLSMALLINT cDataType, Direction dir)
|
||||
/// Utility function.
|
||||
/// Creates, fills and stores the reference to the replacement (std::vector) container
|
||||
/// Utility function - a "stand-in" for non-vector containers.
|
||||
/// Creates, fills and stores the reference to the replacement std::vector container
|
||||
/// for std::deque and std::list. Calls std::vector binding.
|
||||
{
|
||||
typedef typename C::value_type Type;
|
||||
@@ -507,7 +507,11 @@ private:
|
||||
poco_assert (size > 0);
|
||||
|
||||
if (size == _maxFieldSize)
|
||||
{
|
||||
getMinValueSize(val, size);
|
||||
// accomodate for terminating zero
|
||||
if (size != _maxFieldSize) ++size;
|
||||
}
|
||||
|
||||
if (_vecLengthIndicator.size() <= pos)
|
||||
{
|
||||
@@ -563,16 +567,19 @@ private:
|
||||
setParamSetSize(pos, val.size());
|
||||
|
||||
SQLINTEGER size = 0;
|
||||
getColumnOrParameterSize(pos, size);
|
||||
poco_assert (size > 0);
|
||||
|
||||
if (size == _maxFieldSize)
|
||||
getMinValueSize(val, size);
|
||||
|
||||
if (_vecLengthIndicator.size() <= pos)
|
||||
{
|
||||
_vecLengthIndicator.resize(pos + 1);
|
||||
_vecLengthIndicator[pos].resize(val.size(), SQL_NTS);
|
||||
|
||||
_vecLengthIndicator[pos].resize(val.size());
|
||||
std::vector<SQLLEN>::iterator lIt = _vecLengthIndicator[pos].begin();
|
||||
std::vector<SQLLEN>::iterator lEnd = _vecLengthIndicator[pos].end();
|
||||
typename C::const_iterator cIt = val.begin();
|
||||
for (; lIt != lEnd; ++lIt, ++cIt)
|
||||
{
|
||||
SQLLEN sz = static_cast<SQLLEN>(cIt->size());
|
||||
if (sz > size) size = sz;
|
||||
*lIt = sz;
|
||||
}
|
||||
|
||||
if (_charPtrs.size() <= pos)
|
||||
@@ -583,14 +590,14 @@ private:
|
||||
|
||||
std::size_t blobSize;
|
||||
std::size_t offset = 0;
|
||||
typename C::const_iterator it = val.begin();
|
||||
typename C::const_iterator end = val.end();
|
||||
for (; it != end; ++it)
|
||||
cIt = val.begin();
|
||||
typename C::const_iterator cEnd = val.end();
|
||||
for (; cIt != cEnd; ++cIt)
|
||||
{
|
||||
blobSize = it->size();
|
||||
blobSize = cIt->size();
|
||||
if (blobSize > size)
|
||||
throw LengthExceededException("SQLBindParameter(std::vector<BLOB>)");
|
||||
std::memcpy(_charPtrs[pos] + offset, it->rawContent(), blobSize);
|
||||
std::memcpy(_charPtrs[pos] + offset, cIt->rawContent(), blobSize);
|
||||
offset += size;
|
||||
}
|
||||
|
||||
|
||||
@@ -504,7 +504,10 @@ inline bool Extractor::isNullLengthIndicator(SQLLEN val) const
|
||||
|
||||
inline SQLINTEGER Extractor::columnSize(std::size_t pos) const
|
||||
{
|
||||
return (SQLINTEGER) ODBCColumn(_rStmt, pos).length();
|
||||
std::size_t size = ODBCColumn(_rStmt, pos).length();
|
||||
std::size_t maxSize = _rPreparation.maxDataSize(pos);
|
||||
if (size > maxSize) size = maxSize;
|
||||
return (SQLINTEGER) size;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1111,15 +1111,6 @@ inline void Preparation::prepare(std::size_t pos, const std::list<Poco::DynamicA
|
||||
}
|
||||
|
||||
|
||||
inline std::size_t Preparation::actualDataSize(std::size_t col, std::size_t row) const
|
||||
{
|
||||
poco_assert (col < _values.size());
|
||||
|
||||
if (INVALID_ROW == row) return _lengths[col];
|
||||
else return _lenLengths[col].at(row);
|
||||
}
|
||||
|
||||
|
||||
inline std::size_t Preparation::bulkSize(std::size_t col) const
|
||||
{
|
||||
poco_assert (col < _lenLengths.size());
|
||||
@@ -1154,9 +1145,7 @@ inline Preparation::DataExtraction Preparation::getDataExtraction() const
|
||||
|
||||
inline Poco::Any& Preparation::operator [] (std::size_t pos)
|
||||
{
|
||||
poco_assert (pos < _values.size());
|
||||
|
||||
return _values[pos];
|
||||
return _values.at(pos);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -101,11 +101,17 @@ void Binder::freeMemory()
|
||||
|
||||
StringMap::iterator itStr = _strings.begin();
|
||||
StringMap::iterator itStrEnd = _strings.end();
|
||||
for(; itStr != itStrEnd; ++itStr) std::free(itStr->first);
|
||||
for(; itStr != itStrEnd; ++itStr)
|
||||
{
|
||||
if (itStr->first) std::free(itStr->first);
|
||||
}
|
||||
|
||||
CharPtrVec::iterator itChr = _charPtrs.begin();
|
||||
CharPtrVec::iterator endChr = _charPtrs.end();
|
||||
for (; itChr != endChr; ++itChr) std::free(*itChr);
|
||||
for (; itChr != endChr; ++itChr)
|
||||
{
|
||||
if (*itChr) std::free(*itChr);
|
||||
}
|
||||
|
||||
BoolPtrVec::iterator itBool = _boolPtrs.begin();
|
||||
BoolPtrVec::iterator endBool = _boolPtrs.end();
|
||||
@@ -406,6 +412,8 @@ void Binder::reset()
|
||||
_dateTimeVec.clear();
|
||||
_charPtrs.clear();
|
||||
_boolPtrs.clear();
|
||||
_containers.clear();
|
||||
_paramSetSize = 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -504,12 +512,8 @@ void Binder::setParamSetSize(std::size_t pos, std::size_t length)
|
||||
Utility::isError(SQLSetStmtAttr(_rStmt, SQL_ATTR_PARAMSET_SIZE, (SQLPOINTER) length, SQL_IS_UINTEGER)))
|
||||
throw StatementException(_rStmt, "SQLSetStmtAttr()");
|
||||
|
||||
if (Utility::isError(SQLGetStmtAttr(_rStmt, SQL_ATTR_PARAMSET_SIZE, &_paramSetSize, 0, 0)))
|
||||
throw StatementException(_rStmt, "SQLGetStmtAttr()");
|
||||
_paramSetSize = static_cast<SQLINTEGER>(length);
|
||||
}
|
||||
|
||||
if (_paramSetSize != length)
|
||||
throw InvalidArgumentException("Invalid parameter array length.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ bool Extractor::extractBoundImplContainer<std::vector<Poco::Data::BLOB> >(std::s
|
||||
char** pc = AnyCast<char*>(&_rPreparation[pos]);
|
||||
poco_assert_dbg (pc);
|
||||
poco_assert_dbg (_rPreparation.bulkSize() == values.size());
|
||||
std::size_t colWidth = columnSize(pos);
|
||||
std::size_t colWidth = _rPreparation.maxDataSize(pos);
|
||||
std::vector<Poco::Data::BLOB>::iterator it = values.begin();
|
||||
std::vector<Poco::Data::BLOB>::iterator end = values.end();
|
||||
for (int row = 0; it != end; ++it, ++row)
|
||||
@@ -172,7 +172,7 @@ bool Extractor::extractBoundImplContainer<std::deque<Poco::Data::BLOB> >(std::si
|
||||
char** pc = AnyCast<char*>(&_rPreparation[pos]);
|
||||
poco_assert_dbg (pc);
|
||||
poco_assert_dbg (_rPreparation.bulkSize() == values.size());
|
||||
std::size_t colWidth = columnSize(pos);
|
||||
std::size_t colWidth = _rPreparation.maxDataSize(pos);
|
||||
std::deque<Poco::Data::BLOB>::iterator it = values.begin();
|
||||
std::deque<Poco::Data::BLOB>::iterator end = values.end();
|
||||
for (int row = 0; it != end; ++it, ++row)
|
||||
@@ -189,7 +189,7 @@ bool Extractor::extractBoundImplContainer<std::list<Poco::Data::BLOB> >(std::siz
|
||||
char** pc = AnyCast<char*>(&_rPreparation[pos]);
|
||||
poco_assert_dbg (pc);
|
||||
poco_assert_dbg (_rPreparation.bulkSize() == values.size());
|
||||
std::size_t colWidth = columnSize(pos);
|
||||
std::size_t colWidth = _rPreparation.maxDataSize(pos);
|
||||
std::list<Poco::Data::BLOB>::iterator it = values.begin();
|
||||
std::list<Poco::Data::BLOB>::iterator end = values.end();
|
||||
for (int row = 0; it != end; ++it, ++row)
|
||||
|
||||
@@ -45,7 +45,7 @@ namespace ODBC {
|
||||
|
||||
POCO_IMPLEMENT_EXCEPTION(ODBCException, Poco::Data::DataException, "Generic ODBC error")
|
||||
POCO_IMPLEMENT_EXCEPTION(InsufficientStorageException, ODBCException, "Insufficient storage error")
|
||||
POCO_IMPLEMENT_EXCEPTION(UnknownDataLengthException, ODBCException, "Unknown length of remaining data error")
|
||||
POCO_IMPLEMENT_EXCEPTION(UnknownDataLengthException, ODBCException, "Unknown length of remaining data")
|
||||
POCO_IMPLEMENT_EXCEPTION(DataTruncatedException, ODBCException, "Variable length character or binary data truncated")
|
||||
|
||||
|
||||
|
||||
@@ -92,12 +92,18 @@ void Preparation::freeMemory() const
|
||||
break;
|
||||
|
||||
case DT_CHAR_ARRAY:
|
||||
std::free(AnyCast<char>(&_values[it->first]));
|
||||
{
|
||||
char* pc = AnyCast<char>(&_values[it->first]);
|
||||
if (pc) std::free(pc);
|
||||
break;
|
||||
}
|
||||
|
||||
case DT_BOOL_ARRAY:
|
||||
std::free(AnyCast<bool>(&_values[it->first]));
|
||||
{
|
||||
bool* pb = AnyCast<bool>(&_values[it->first]);
|
||||
if (pb) std::free(pb);
|
||||
break;
|
||||
}
|
||||
|
||||
case DT_DATE:
|
||||
deleteCachedArray<SQL_DATE_STRUCT>(it->first);
|
||||
@@ -157,6 +163,18 @@ std::size_t Preparation::maxDataSize(std::size_t pos) const
|
||||
}
|
||||
|
||||
|
||||
std::size_t Preparation::actualDataSize(std::size_t col, std::size_t row) const
|
||||
{
|
||||
SQLLEN size = (INVALID_ROW == row) ? _lengths.at(col) :
|
||||
_lenLengths.at(col).at(row);
|
||||
|
||||
// workaround for drivers returning negative length
|
||||
if (size < 0 && SQL_NULL_DATA != size) size *= -1;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
void Preparation::prepareCharArray(std::size_t pos, SQLSMALLINT valueType, std::size_t size, std::size_t length)
|
||||
{
|
||||
poco_assert_dbg (DE_BOUND == _dataExtraction);
|
||||
|
||||
@@ -165,19 +165,6 @@ void ODBCDB2Test::testBLOB()
|
||||
}
|
||||
|
||||
|
||||
void ODBCDB2Test::testBulk()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
_pSession->setFeature("autoBind", true);
|
||||
_pSession->setFeature("autoExtract", true);
|
||||
recreateMiscTable();
|
||||
_pExecutor->doBulkStringIntFloat(100);
|
||||
recreateMiscTable();
|
||||
_pExecutor->doBulkPerformance(1000);
|
||||
}
|
||||
|
||||
|
||||
void ODBCDB2Test::testStoredProcedure()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
@@ -557,10 +544,9 @@ void ODBCDB2Test::recreateMiscTable()
|
||||
dropObject("TABLE", "MiscTest");
|
||||
try
|
||||
{
|
||||
// DB2 fails with BLOB
|
||||
session() << "CREATE TABLE MiscTest "
|
||||
"(First VARCHAR(30),"
|
||||
//"Second BLOB,"
|
||||
"Second BLOB,"
|
||||
"Third INTEGER,"
|
||||
"Fourth FLOAT,"
|
||||
"Fifth TIMESTAMP)", now;
|
||||
@@ -622,6 +608,7 @@ CppUnit::Test* ODBCDB2Test::suite()
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testSingleSelect);
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testEmptyDB);
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testBLOB);
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testBLOBContainer);
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testBLOBStmt);
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testDate);
|
||||
CppUnit_addTest(pSuite, ODBCDB2Test, testTime);
|
||||
|
||||
@@ -55,7 +55,6 @@ public:
|
||||
void testBareboneODBC();
|
||||
|
||||
void testBLOB();
|
||||
void testBulk();
|
||||
|
||||
void testStoredProcedure();
|
||||
void testStoredProcedureAny();
|
||||
|
||||
@@ -359,6 +359,20 @@ void ODBCMySQLTest::recreateNullsTable(const std::string& notNull)
|
||||
}
|
||||
|
||||
|
||||
void ODBCMySQLTest::recreateMiscTable()
|
||||
{
|
||||
dropObject("TABLE", "MiscTest");
|
||||
try { *_pSession << "CREATE TABLE MiscTest "
|
||||
"(First VARCHAR(30),"
|
||||
"Second VARBINARY(30),"
|
||||
"Third INTEGER,"
|
||||
"Fourth FLOAT,"
|
||||
"Fifth DATETIME)", now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail ("recreateNullsTable()"); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail ("recreateNullsTable()"); }
|
||||
}
|
||||
|
||||
|
||||
CppUnit::Test* ODBCMySQLTest::suite()
|
||||
{
|
||||
if (_pSession = init(_driver, _dsn, _uid, _pwd, _connectString))
|
||||
@@ -391,7 +405,7 @@ CppUnit::Test* ODBCMySQLTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testLimitPrepare);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testLimitZero);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testPrepare);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testBulk);
|
||||
//CppUnit_addTest(pSuite, ODBCMySQLTest, testBulk);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testSetSimple);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testSetComplex);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testSetComplexUnique);
|
||||
@@ -412,6 +426,7 @@ CppUnit::Test* ODBCMySQLTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testSingleSelect);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testEmptyDB);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testBLOB);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testBLOBContainer);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testBLOBStmt);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testDate);
|
||||
CppUnit_addTest(pSuite, ODBCMySQLTest, testTime);
|
||||
|
||||
@@ -82,6 +82,7 @@ private:
|
||||
void recreateVectorsTable();
|
||||
void recreateAnysTable();
|
||||
void recreateNullsTable(const std::string& notNull = "");
|
||||
void recreateMiscTable();
|
||||
|
||||
static ODBCTest::SessionPtr _pSession;
|
||||
static ODBCTest::ExecPtr _pExecutor;
|
||||
|
||||
@@ -224,19 +224,6 @@ void ODBCOracleTest::testBLOB()
|
||||
}
|
||||
|
||||
|
||||
void ODBCOracleTest::testBulk()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
_pSession->setFeature("autoBind", true);
|
||||
_pSession->setFeature("autoExtract", true);
|
||||
recreateMiscTable();
|
||||
_pExecutor->doBulkNoBool(100);
|
||||
recreateMiscTable();
|
||||
_pExecutor->doBulkPerformance(1000);
|
||||
}
|
||||
|
||||
|
||||
void ODBCOracleTest::testNull()
|
||||
{
|
||||
// test for NOT NULL violation exception
|
||||
@@ -821,6 +808,7 @@ CppUnit::Test* ODBCOracleTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testSingleSelect);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testEmptyDB);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testBLOB);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testBLOBContainer);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testBLOBStmt);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testDate);
|
||||
CppUnit_addTest(pSuite, ODBCOracleTest, testDateTime);
|
||||
|
||||
@@ -56,7 +56,6 @@ public:
|
||||
void testBareboneODBC();
|
||||
|
||||
void testBLOB();
|
||||
void testBulk();
|
||||
|
||||
void testMultipleResults();
|
||||
|
||||
|
||||
@@ -175,7 +175,6 @@ void ODBCPostgreSQLTest::testBareboneODBC()
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ODBCPostgreSQLTest::testBLOB()
|
||||
{
|
||||
const std::size_t maxFldSize = 1000000;
|
||||
@@ -346,19 +345,6 @@ void ODBCPostgreSQLTest::testStoredFunctionDynamicAny()
|
||||
}
|
||||
|
||||
|
||||
void ODBCPostgreSQLTest::testBulk()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
_pSession->setFeature("autoBind", true);
|
||||
_pSession->setFeature("autoExtract", true);
|
||||
recreateMiscTable();
|
||||
_pExecutor->doBulkStringIntFloat(100);
|
||||
recreateMiscTable();
|
||||
_pExecutor->doBulkPerformance(1000);
|
||||
}
|
||||
|
||||
|
||||
void ODBCPostgreSQLTest::configurePLPgSQL()
|
||||
{
|
||||
try
|
||||
@@ -540,7 +526,7 @@ void ODBCPostgreSQLTest::recreateMiscTable()
|
||||
// Mammoth does not bind columns properly
|
||||
session() << "CREATE TABLE MiscTest "
|
||||
"(First VARCHAR(30),"
|
||||
//"Second BYTEA,"
|
||||
"Second BYTEA,"
|
||||
"Third INTEGER,"
|
||||
"Fourth FLOAT,"
|
||||
"Fifth TIMESTAMP)", now;
|
||||
@@ -602,6 +588,7 @@ CppUnit::Test* ODBCPostgreSQLTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testSingleSelect);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testEmptyDB);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testBLOB);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testBLOBContainer);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testBLOBStmt);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testDate);
|
||||
CppUnit_addTest(pSuite, ODBCPostgreSQLTest, testTime);
|
||||
|
||||
@@ -64,7 +64,6 @@ public:
|
||||
void testBareboneODBC();
|
||||
|
||||
void testBLOB();
|
||||
void testBulk();
|
||||
|
||||
void testStoredFunction();
|
||||
void testStoredFunctionAny();
|
||||
|
||||
@@ -188,6 +188,42 @@ void ODBCSQLServerTest::testNull()
|
||||
}
|
||||
|
||||
|
||||
void ODBCSQLServerTest::testBulk()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
_pSession->setFeature("autoBind", true);
|
||||
_pSession->setFeature("autoExtract", true);
|
||||
|
||||
recreateMiscTable();
|
||||
_pExecutor->doBulkWithBool<std::vector<int>,
|
||||
std::vector<std::string>,
|
||||
std::vector<BLOB>,
|
||||
std::vector<double>,
|
||||
std::vector<DateTime>,
|
||||
std::vector<bool> >(100);
|
||||
|
||||
recreateMiscTable();
|
||||
_pExecutor->doBulkWithBool<std::deque<int>,
|
||||
std::deque<std::string>,
|
||||
std::deque<BLOB>,
|
||||
std::deque<double>,
|
||||
std::deque<DateTime>,
|
||||
std::deque<bool> >(100);
|
||||
|
||||
recreateMiscTable();
|
||||
_pExecutor->doBulkWithBool<std::list<int>,
|
||||
std::list<std::string>,
|
||||
std::list<BLOB>,
|
||||
std::list<double>,
|
||||
std::list<DateTime>,
|
||||
std::list<bool> >(100);
|
||||
|
||||
recreateMiscTable();
|
||||
_pExecutor->doBulkPerformance(1000);
|
||||
}
|
||||
|
||||
|
||||
void ODBCSQLServerTest::testStoredProcedure()
|
||||
{
|
||||
for (int k = 0; k < 8;)
|
||||
@@ -680,6 +716,7 @@ CppUnit::Test* ODBCSQLServerTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testSingleSelect);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testEmptyDB);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testBLOB);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testBLOBContainer);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testBLOBStmt);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testDateTime);
|
||||
CppUnit_addTest(pSuite, ODBCSQLServerTest, testFloat);
|
||||
|
||||
@@ -63,6 +63,7 @@ public:
|
||||
|
||||
void testBLOB();
|
||||
void testNull();
|
||||
void testBulk();
|
||||
|
||||
void testStoredProcedure();
|
||||
void testCursorStoredProcedure();
|
||||
|
||||
@@ -141,19 +141,6 @@ void ODBCSQLiteTest::testNull()
|
||||
}
|
||||
|
||||
|
||||
void ODBCSQLiteTest::testBulk()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
_pSession->setFeature("autoBind", true);
|
||||
_pSession->setFeature("autoExtract", true);
|
||||
recreateMiscTable();
|
||||
_pExecutor->doBulkStringIntFloat(100);
|
||||
recreateMiscTable();
|
||||
_pExecutor->doBulkPerformance(1000);
|
||||
}
|
||||
|
||||
|
||||
void ODBCSQLiteTest::dropObject(const std::string& type, const std::string& name)
|
||||
{
|
||||
try
|
||||
@@ -324,7 +311,6 @@ CppUnit::Test* ODBCSQLiteTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testLimitPrepare);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testLimitZero);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testPrepare);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testBulk);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testSetSimple);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testSetComplex);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testSetComplexUnique);
|
||||
@@ -345,6 +331,7 @@ CppUnit::Test* ODBCSQLiteTest::suite()
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testSingleSelect);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testEmptyDB);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testBLOB);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testBLOBContainer);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testBLOBStmt);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testDateTime);
|
||||
CppUnit_addTest(pSuite, ODBCSQLiteTest, testFloat);
|
||||
|
||||
@@ -54,7 +54,6 @@ public:
|
||||
|
||||
void testBareboneODBC();
|
||||
void testNull();
|
||||
void testBulk();
|
||||
|
||||
static CppUnit::Test* suite();
|
||||
|
||||
|
||||
@@ -415,28 +415,26 @@ void ODBCTest::testBulk()
|
||||
_pSession->setFeature("autoExtract", true);
|
||||
|
||||
recreateMiscTable();
|
||||
|
||||
_pExecutor->doBulk<std::vector<int>,
|
||||
std::vector<std::string>,
|
||||
std::vector<BLOB>,
|
||||
std::vector<double>,
|
||||
std::vector<DateTime>,
|
||||
std::vector<bool> >(100);
|
||||
std::vector<DateTime> >(100);
|
||||
|
||||
recreateMiscTable();
|
||||
_pExecutor->doBulk<std::deque<int>,
|
||||
std::deque<std::string>,
|
||||
std::deque<BLOB>,
|
||||
std::deque<double>,
|
||||
std::deque<DateTime>,
|
||||
std::deque<bool> >(100);
|
||||
std::deque<DateTime> >(100);
|
||||
|
||||
recreateMiscTable();
|
||||
_pExecutor->doBulk<std::list<int>,
|
||||
std::list<std::string>,
|
||||
std::list<BLOB>,
|
||||
std::list<double>,
|
||||
std::list<DateTime>,
|
||||
std::list<bool> >(100);
|
||||
std::list<DateTime> >(100);
|
||||
|
||||
recreateMiscTable();
|
||||
_pExecutor->doBulkPerformance(1000);
|
||||
@@ -744,6 +742,23 @@ void ODBCTest::testBLOB()
|
||||
}
|
||||
|
||||
|
||||
void ODBCTest::testBLOBContainer()
|
||||
{
|
||||
for (int i = 0; i < 8;)
|
||||
{
|
||||
session().setFeature("autoBind", bindValue(i));
|
||||
session().setFeature("autoExtract", bindValue(i+1));
|
||||
recreatePersonBLOBTable();
|
||||
_pExecutor->blobContainer<std::vector<std::string>, std::vector<BLOB> >(10);
|
||||
recreatePersonBLOBTable();
|
||||
_pExecutor->blobContainer<std::deque<std::string>, std::deque<BLOB> >(10);
|
||||
recreatePersonBLOBTable();
|
||||
_pExecutor->blobContainer<std::list<std::string>, std::list<BLOB> >(10);
|
||||
i += 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ODBCTest::testBLOBStmt()
|
||||
{
|
||||
if (!_pSession) fail ("Test not available.");
|
||||
|
||||
@@ -114,6 +114,7 @@ public:
|
||||
virtual void testEmptyDB();
|
||||
|
||||
virtual void testBLOB();
|
||||
virtual void testBLOBContainer();
|
||||
virtual void testBLOBStmt();
|
||||
|
||||
virtual void testDateTime();
|
||||
|
||||
@@ -588,6 +588,7 @@ void SQLExecutor::bareboneODBCTest(const std::string& dbConnString,
|
||||
assert (5 == sixth.hour);
|
||||
assert (34 == sixth.minute);
|
||||
assert (59 == sixth.second);
|
||||
if (sixth.fraction)//MySQL does not support fraction
|
||||
assert (997000000 == sixth.fraction);
|
||||
}
|
||||
|
||||
@@ -1581,205 +1582,6 @@ void SQLExecutor::doBulkPerformance(Poco::UInt32 size)
|
||||
}
|
||||
|
||||
|
||||
void SQLExecutor::doBulkNoBool(Poco::UInt32 size)
|
||||
{
|
||||
std::string funct = "doBulk()";
|
||||
std::vector<int> ints(size, 1);
|
||||
std::vector<std::string> strings(size);
|
||||
std::vector<BLOB> blobs(size);
|
||||
std::vector<double> floats(size);
|
||||
std::vector<DateTime> dateTimes(size);
|
||||
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
ints[i] = i;
|
||||
strings[i] = "xyz" + NumberFormatter::format(i);
|
||||
blobs[i] = "abc" + NumberFormatter::format(i);
|
||||
floats[i] = i + .5;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
session() << "INSERT INTO MiscTest VALUES (?,?,?,?,?)",
|
||||
use(strings),
|
||||
use(blobs),
|
||||
use(ints),
|
||||
use(floats),
|
||||
use(dateTimes), now;
|
||||
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
try { session() << "DELETE FROM MiscTest", now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
try
|
||||
{
|
||||
session() << "INSERT INTO MiscTest VALUES (?,?,?,?,?)",
|
||||
use(strings, bulk),
|
||||
use(blobs, bulk),
|
||||
use(ints, bulk),
|
||||
use(floats, bulk),
|
||||
use(dateTimes, bulk), now;
|
||||
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
ints.clear();
|
||||
strings.clear();
|
||||
blobs.clear();
|
||||
floats.clear();
|
||||
|
||||
try
|
||||
{
|
||||
session() << "SELECT * FROM MiscTest ORDER BY First",
|
||||
into(strings),
|
||||
into(blobs),
|
||||
into(ints),
|
||||
into(floats),
|
||||
into(dateTimes),
|
||||
now;
|
||||
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
std::string number = NumberFormatter::format(size - 1);
|
||||
assert (size == ints.size());
|
||||
assert (0 == ints[0]);
|
||||
assert (ints.size() - 1 == ints[ints.size() - 1]);
|
||||
assert (std::string("xyz0") == strings[0]);
|
||||
assert (std::string("xyz") + number == strings[strings.size()-1]);
|
||||
assert (BLOB("abc0") == blobs[0]);
|
||||
BLOB blob("abc");
|
||||
blob.appendRaw(number.c_str(), number.size());
|
||||
assert (blob == blobs[blobs.size()-1]);
|
||||
assert (.5 == floats[0]);
|
||||
assert (floats.size() - 1 + .5 == floats[floats.size() - 1]);
|
||||
|
||||
ints.clear();
|
||||
|
||||
try
|
||||
{
|
||||
session() << "SELECT First FROM MiscTest", into(ints, bulk(size)), limit(size+1), now;
|
||||
fail ("must fail");
|
||||
}
|
||||
catch(InvalidArgumentException&){ }
|
||||
|
||||
try
|
||||
{
|
||||
session() << "SELECT First FROM MiscTest", into(ints), bulk(size), now;
|
||||
fail ("must fail");
|
||||
}
|
||||
catch(InvalidAccessException&){ }
|
||||
|
||||
ints.clear();
|
||||
strings.clear();
|
||||
blobs.clear();
|
||||
floats.clear();
|
||||
|
||||
try
|
||||
{
|
||||
session() << "SELECT * FROM MiscTest ORDER BY First",
|
||||
into(strings, bulk(size)),
|
||||
into(blobs, bulk(size)),
|
||||
into(ints, bulk(size)),
|
||||
into(floats, bulk(size)),
|
||||
into(dateTimes, bulk(size)),
|
||||
now;
|
||||
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
assert (size == ints.size());
|
||||
assert (0 == ints[0]);
|
||||
assert (ints.size() - 1 == ints[ints.size()-1]);
|
||||
assert (std::string("xyz0") == strings[0]);
|
||||
assert (std::string("xyz") + number == strings[strings.size()-1]);
|
||||
assert (BLOB("abc0") == blobs[0]);
|
||||
blob.assignRaw("abc", 3);
|
||||
blob.appendRaw(number.c_str(), number.size());
|
||||
assert (blob == blobs[blobs.size()-1]);
|
||||
assert (.5 == floats[0]);
|
||||
assert (floats.size() - 1 + .5 == floats[floats.size() - 1]);
|
||||
}
|
||||
|
||||
|
||||
void SQLExecutor::doBulkStringIntFloat(Poco::UInt32 size)
|
||||
{
|
||||
std::string funct = "doBulk()";
|
||||
std::vector<int> ints(size, 1);
|
||||
std::vector<double> floats(size, .5);
|
||||
std::vector<std::string> strings(size, "xwyz");
|
||||
std::vector<DateTime> dateTimes(size);
|
||||
|
||||
try
|
||||
{
|
||||
session() << "INSERT INTO MiscTest VALUES (?,?,?,?)",
|
||||
use(strings),
|
||||
use(ints),
|
||||
use(floats),
|
||||
use(dateTimes), now;
|
||||
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
try { session() << "DELETE FROM MiscTest", now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
try
|
||||
{
|
||||
session() << "INSERT INTO MiscTest VALUES (?,?,?,?)",
|
||||
use(strings, bulk),
|
||||
use(ints, bulk),
|
||||
use(floats, bulk),
|
||||
use(dateTimes, bulk), now;
|
||||
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
ints.clear();
|
||||
strings.clear();
|
||||
try
|
||||
{
|
||||
session() << "SELECT * FROM MiscTest",
|
||||
into(strings),
|
||||
into(ints),
|
||||
into(floats),
|
||||
into(dateTimes), now;
|
||||
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
assert (size == ints.size());
|
||||
assert (1 == ints[ints.size()-1]);
|
||||
|
||||
ints.clear();
|
||||
|
||||
try
|
||||
{
|
||||
session() << "SELECT * FROM MiscTest", into(ints, bulk(size)), limit(size+1), now;
|
||||
fail ("must fail");
|
||||
}
|
||||
catch(InvalidArgumentException&){ }
|
||||
|
||||
try
|
||||
{
|
||||
session() << "SELECT * FROM MiscTest", into(ints), bulk(size), now;
|
||||
fail ("must fail");
|
||||
}
|
||||
catch(InvalidAccessException&){ }
|
||||
|
||||
ints.clear();
|
||||
try
|
||||
{
|
||||
session() << "SELECT * FROM MiscTest",
|
||||
into(strings, bulk(size)),
|
||||
into(ints, bulk(size)),
|
||||
into(floats, bulk(size)),
|
||||
into(dateTimes, bulk(size)), now;
|
||||
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
assert (size == ints.size());
|
||||
assert (1 == ints[ints.size()-1]);
|
||||
}
|
||||
|
||||
|
||||
void SQLExecutor::setSimple()
|
||||
{
|
||||
std::string funct = "setSimple()";
|
||||
@@ -2750,7 +2552,7 @@ void SQLExecutor::notNulls(const std::string& sqlState)
|
||||
}catch (StatementException& se)
|
||||
{
|
||||
//make sure we're failing for the right reason
|
||||
//default sqlState value is "23502", but some drivers report "HY???" codes
|
||||
//default sqlState value is "23502"; some drivers report "HY???" codes
|
||||
assert (sqlState == se.diagnostics().sqlState(0));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,9 +146,9 @@ public:
|
||||
void prepare();
|
||||
|
||||
template <typename C1, typename C2, typename C3, typename C4, typename C5, typename C6>
|
||||
void doBulk(Poco::UInt32 size)
|
||||
void doBulkWithBool(Poco::UInt32 size)
|
||||
{
|
||||
std::string funct = "doBulk()";
|
||||
std::string funct = "doBulkWithBool()";
|
||||
C1 ints;
|
||||
C2 strings;
|
||||
C3 blobs;
|
||||
@@ -283,8 +283,128 @@ public:
|
||||
}
|
||||
|
||||
void doBulkPerformance(Poco::UInt32 size);
|
||||
void doBulkNoBool(Poco::UInt32 size);
|
||||
void doBulkStringIntFloat(Poco::UInt32 size);
|
||||
|
||||
template <typename C1, typename C2, typename C3, typename C4, typename C5>
|
||||
void doBulk(Poco::UInt32 size)
|
||||
{
|
||||
std::string funct = "doBulk()";
|
||||
C1 ints;
|
||||
C2 strings;
|
||||
C3 blobs;
|
||||
C4 floats;
|
||||
C5 dateTimes(size);
|
||||
|
||||
for (int i = 0; i < size; ++i)
|
||||
{
|
||||
ints.push_back(i);
|
||||
strings.push_back(std::string("xyz" + Poco::NumberFormatter::format(i)));
|
||||
blobs.push_back(std::string("abc") + Poco::NumberFormatter::format(i));
|
||||
floats.push_back(i + .5);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
session() << "INSERT INTO MiscTest VALUES (?,?,?,?,?)",
|
||||
use(strings),
|
||||
use(blobs),
|
||||
use(ints),
|
||||
use(floats),
|
||||
use(dateTimes), now;
|
||||
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
try { session() << "DELETE FROM MiscTest", now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
try
|
||||
{
|
||||
session() << "INSERT INTO MiscTest VALUES (?,?,?,?,?)",
|
||||
use(strings, bulk),
|
||||
use(blobs, bulk),
|
||||
use(ints, bulk),
|
||||
use(floats, bulk),
|
||||
use(dateTimes, bulk), now;
|
||||
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
ints.clear();
|
||||
strings.clear();
|
||||
blobs.clear();
|
||||
floats.clear();
|
||||
dateTimes.clear();
|
||||
|
||||
try
|
||||
{
|
||||
session() << "SELECT * FROM MiscTest ORDER BY First",
|
||||
into(strings),
|
||||
into(blobs),
|
||||
into(ints),
|
||||
into(floats),
|
||||
into(dateTimes),
|
||||
now;
|
||||
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
std::string number = Poco::NumberFormatter::format(size - 1);
|
||||
assert (size == ints.size());
|
||||
assert (0 == ints.front());
|
||||
assert (size - 1 == ints.back());
|
||||
assert (std::string("xyz0") == strings.front());
|
||||
assert (std::string("xyz") + number == strings.back());
|
||||
assert (BLOB("abc0") == blobs.front());
|
||||
BLOB blob("abc");
|
||||
blob.appendRaw(number.c_str(), number.size());
|
||||
assert (blob == blobs.back());
|
||||
assert (.5 == floats.front());
|
||||
assert (floats.size() - 1 + .5 == floats.back());
|
||||
|
||||
ints.clear();
|
||||
|
||||
try
|
||||
{
|
||||
session() << "SELECT First FROM MiscTest", into(ints, bulk(size)), limit(size+1), now;
|
||||
fail ("must fail");
|
||||
}
|
||||
catch(Poco::InvalidArgumentException&){ }
|
||||
|
||||
try
|
||||
{
|
||||
session() << "SELECT First FROM MiscTest", into(ints), bulk(size), now;
|
||||
fail ("must fail");
|
||||
}
|
||||
catch(Poco::InvalidAccessException&){ }
|
||||
|
||||
ints.clear();
|
||||
strings.clear();
|
||||
blobs.clear();
|
||||
floats.clear();
|
||||
dateTimes.clear();
|
||||
|
||||
try
|
||||
{
|
||||
session() << "SELECT * FROM MiscTest ORDER BY First",
|
||||
into(strings, bulk(size)),
|
||||
into(blobs, bulk(size)),
|
||||
into(ints, bulk(size)),
|
||||
into(floats, bulk(size)),
|
||||
into(dateTimes, bulk(size)),
|
||||
now;
|
||||
} catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
|
||||
assert (size == ints.size());
|
||||
assert (0 == ints.front());
|
||||
assert (size - 1 == ints.back());
|
||||
assert (std::string("xyz0") == strings.front());
|
||||
assert (std::string("xyz") + number == strings.back());
|
||||
assert (BLOB("abc0") == blobs.front());
|
||||
blob.assignRaw("abc", 3);
|
||||
blob.appendRaw(number.c_str(), number.size());
|
||||
assert (blob == blobs.back());
|
||||
assert (.5 == floats.front());
|
||||
assert (floats.size() - 1 + .5 == floats.back());
|
||||
}
|
||||
|
||||
void setSimple();
|
||||
void setComplex();
|
||||
@@ -307,6 +427,32 @@ public:
|
||||
void emptyDB();
|
||||
|
||||
void blob(int bigSize = 1024);
|
||||
|
||||
template <typename C1, typename C2>
|
||||
void blobContainer(int size)
|
||||
{
|
||||
std::string funct = "blobContainer()";
|
||||
C1 lastName(size, "lastname");
|
||||
C1 firstName(size, "firstname");
|
||||
C1 address(size, "Address");
|
||||
C2 img(size, BLOB("0123456789", 10));
|
||||
int count = 0;
|
||||
try { session() << "INSERT INTO PERSON VALUES (?,?,?,?)", use(lastName), use(firstName), use(address), use(img), now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
try { session() << "SELECT COUNT(*) FROM PERSON", 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 == size);
|
||||
|
||||
C2 res;
|
||||
try { session() << "SELECT Image FROM Person", into(res), now; }
|
||||
catch(ConnectionException& ce){ std::cout << ce.toString() << std::endl; fail (funct); }
|
||||
catch(StatementException& se){ std::cout << se.toString() << std::endl; fail (funct); }
|
||||
assert (res.size() == img.size());
|
||||
assert (res == img);
|
||||
}
|
||||
|
||||
void blobStmt();
|
||||
|
||||
void dateTime();
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace Poco {
|
||||
namespace Data {
|
||||
|
||||
|
||||
template <class T>
|
||||
template <class C>
|
||||
class BulkExtraction: public AbstractExtraction
|
||||
/// Specialization for bulk extraction of values from a query result set.
|
||||
/// Bulk extraction support is provided only for following STL containers:
|
||||
@@ -59,10 +59,19 @@ class BulkExtraction: public AbstractExtraction
|
||||
/// - std::list
|
||||
{
|
||||
public:
|
||||
BulkExtraction(T& result, Poco::UInt32 limit, Poco::UInt32 position = 0):
|
||||
AbstractExtraction(limit, position, true),
|
||||
BulkExtraction(C& result, Poco::UInt32 limit):
|
||||
AbstractExtraction(limit, 0, true),
|
||||
_rResult(result),
|
||||
_default()
|
||||
_default(1)
|
||||
{
|
||||
if (static_cast<Poco::UInt32>(result.size()) != limit)
|
||||
result.resize(limit);
|
||||
}
|
||||
|
||||
BulkExtraction(C& result, const C& def, Poco::UInt32 limit):
|
||||
AbstractExtraction(limit, 0, true),
|
||||
_rResult(result),
|
||||
_default(def)
|
||||
{
|
||||
if (static_cast<Poco::UInt32>(result.size()) != limit)
|
||||
result.resize(limit);
|
||||
@@ -74,7 +83,7 @@ public:
|
||||
|
||||
std::size_t numOfColumnsHandled() const
|
||||
{
|
||||
return TypeHandler<T>::size();
|
||||
return TypeHandler<C>::size();
|
||||
}
|
||||
|
||||
std::size_t numOfRowsHandled() const
|
||||
@@ -101,9 +110,9 @@ public:
|
||||
std::size_t extract(std::size_t col)
|
||||
{
|
||||
AbstractExtractor* pExt = getExtractor();
|
||||
TypeHandler<T>::extract(col, _rResult, _default, pExt);
|
||||
typename T::iterator it = _rResult.begin();
|
||||
typename T::iterator end = _rResult.end();
|
||||
TypeHandler<C>::extract(col, _rResult, _default, pExt);
|
||||
typename C::iterator it = _rResult.begin();
|
||||
typename C::iterator end = _rResult.end();
|
||||
for (int row = 0; it !=end; ++it, ++row)
|
||||
_nulls.push_back(pExt->isNull(col, row));
|
||||
|
||||
@@ -119,22 +128,87 @@ public:
|
||||
Poco::UInt32 limit = getLimit();
|
||||
if (limit != _rResult.size()) _rResult.resize(limit);
|
||||
pPrep->setLength(limit);
|
||||
return new Prepare<T>(pPrep, col, _rResult);
|
||||
return new Prepare<C>(pPrep, col, _rResult);
|
||||
}
|
||||
|
||||
protected:
|
||||
const T& result() const
|
||||
const C& result() const
|
||||
{
|
||||
return _rResult;
|
||||
}
|
||||
|
||||
private:
|
||||
T& _rResult;
|
||||
T _default; // copy the default
|
||||
C& _rResult;
|
||||
C _default;
|
||||
std::deque<bool> _nulls;
|
||||
};
|
||||
|
||||
|
||||
template <class C>
|
||||
class InternalBulkExtraction: public BulkExtraction<C>
|
||||
/// Container Data Type specialization extension for extraction of values from a query result set.
|
||||
///
|
||||
/// This class is intended for PocoData internal use - it is used by StatementImpl
|
||||
/// to automaticaly create internal BulkExtraction in cases when statement returns data and no external storage
|
||||
/// was supplied. It is later used by RecordSet to retrieve the fetched data after statement execution.
|
||||
/// It takes ownership of the Column pointer supplied as constructor argument. Column object, in turn
|
||||
/// owns the data vector pointer.
|
||||
///
|
||||
/// InternalBulkExtraction objects can not be copied or assigned.
|
||||
{
|
||||
public:
|
||||
typedef typename C::value_type T;
|
||||
|
||||
explicit InternalBulkExtraction(C& result, Column<T,C>* pColumn, Poco::UInt32 limit):
|
||||
BulkExtraction<C>(result, _default, limit),
|
||||
_pColumn(pColumn)
|
||||
/// Creates InternalBulkExtraction.
|
||||
{
|
||||
}
|
||||
|
||||
~InternalBulkExtraction()
|
||||
/// Destroys InternalBulkExtraction.
|
||||
{
|
||||
delete _pColumn;
|
||||
}
|
||||
|
||||
void reset()
|
||||
{
|
||||
_pColumn->reset();
|
||||
}
|
||||
|
||||
const T& value(int index) const
|
||||
{
|
||||
try
|
||||
{
|
||||
return BulkExtraction<C>::result().at(index);
|
||||
}
|
||||
catch (std::out_of_range& ex)
|
||||
{
|
||||
throw RangeException(ex.what());
|
||||
}
|
||||
}
|
||||
|
||||
bool isNull(std::size_t row) const
|
||||
{
|
||||
return BulkExtraction<C>::isNull(row);
|
||||
}
|
||||
|
||||
const Column<T,C>& column() const
|
||||
{
|
||||
return *_pColumn;
|
||||
}
|
||||
|
||||
private:
|
||||
InternalBulkExtraction();
|
||||
InternalBulkExtraction(const InternalBulkExtraction&);
|
||||
InternalBulkExtraction& operator = (const InternalBulkExtraction&);
|
||||
|
||||
Column<T,C>* _pColumn;
|
||||
C _default;
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
BulkExtraction<std::vector<T> >* into(std::vector<T>& t, const Bulk& bulk)
|
||||
/// Convenience function to allow for a more compact creation of an extraction object
|
||||
|
||||
@@ -472,7 +472,7 @@ private:
|
||||
};
|
||||
|
||||
|
||||
template <class T, class C = std::deque<T> >
|
||||
template <class C>
|
||||
class InternalExtraction: public Extraction<C>
|
||||
/// Container Data Type specialization extension for extraction of values from a query result set.
|
||||
///
|
||||
@@ -485,6 +485,8 @@ class InternalExtraction: public Extraction<C>
|
||||
/// InternalExtraction objects can not be copied or assigned.
|
||||
{
|
||||
public:
|
||||
typedef typename C::value_type T;
|
||||
|
||||
explicit InternalExtraction(C& result, Column<T,C>* pColumn, const Position& pos = Position(0)):
|
||||
Extraction<C>(result, T(), pos),
|
||||
_pColumn(pColumn)
|
||||
|
||||
@@ -113,6 +113,70 @@ private:
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
class Prepare<std::deque<T> >: public AbstractPrepare
|
||||
/// Prepare specialization for std::deque.
|
||||
/// This specialization is needed for bulk operations to enforce
|
||||
/// the whole deque preparation, rather than only individual contained values.
|
||||
{
|
||||
public:
|
||||
Prepare(AbstractPreparation* pPrepare, std::size_t pos, std::deque<T>& val = std::deque<T>()):
|
||||
AbstractPrepare(pPrepare),
|
||||
_pos(pos),
|
||||
_val(val)
|
||||
/// Creates the Prepare.
|
||||
{
|
||||
}
|
||||
|
||||
~Prepare()
|
||||
/// Destroys the Prepare.
|
||||
{
|
||||
}
|
||||
|
||||
void prepare()
|
||||
/// Prepares data.
|
||||
{
|
||||
TypeHandler<std::deque<T> >::prepare(_pos, _val, preparation());
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t _pos;
|
||||
std::deque<T>& _val;
|
||||
};
|
||||
|
||||
|
||||
template<typename T>
|
||||
class Prepare<std::list<T> >: public AbstractPrepare
|
||||
/// Prepare specialization for std::list.
|
||||
/// This specialization is needed for bulk operations to enforce
|
||||
/// the whole list preparation, rather than only individual contained values.
|
||||
{
|
||||
public:
|
||||
Prepare(AbstractPreparation* pPrepare, std::size_t pos, std::list<T>& val = std::list<T>()):
|
||||
AbstractPrepare(pPrepare),
|
||||
_pos(pos),
|
||||
_val(val)
|
||||
/// Creates the Prepare.
|
||||
{
|
||||
}
|
||||
|
||||
~Prepare()
|
||||
/// Destroys the Prepare.
|
||||
{
|
||||
}
|
||||
|
||||
void prepare()
|
||||
/// Prepares data.
|
||||
{
|
||||
TypeHandler<std::list<T> >::prepare(_pos, _val, preparation());
|
||||
}
|
||||
|
||||
private:
|
||||
std::size_t _pos;
|
||||
std::list<T>& _val;
|
||||
};
|
||||
|
||||
|
||||
} } // namespace Poco::Data
|
||||
|
||||
|
||||
|
||||
@@ -111,7 +111,7 @@ public:
|
||||
const Column<T,C>& column(std::size_t pos) const
|
||||
/// Returns the reference to column at specified location.
|
||||
{
|
||||
typedef const InternalExtraction<T,C>* ExtractionVecPtr;
|
||||
typedef const InternalExtraction<C>* ExtractionVecPtr;
|
||||
|
||||
const AbstractExtractionVec& rExtractions = extractions();
|
||||
|
||||
@@ -263,7 +263,7 @@ private:
|
||||
std::size_t columnPosition(const std::string& name) const
|
||||
/// Returns the position of the column with specified name.
|
||||
{
|
||||
typedef const InternalExtraction<T,C>* ExtractionVecPtr;
|
||||
typedef const InternalExtraction<C>* ExtractionVecPtr;
|
||||
|
||||
bool typeFound = false;
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@
|
||||
#include "Poco/Data/Bulk.h"
|
||||
#include "Poco/Data/Column.h"
|
||||
#include "Poco/Data/Extraction.h"
|
||||
#include "Poco/Data/BulkExtraction.h"
|
||||
#include "Poco/Data/SessionImpl.h"
|
||||
#include "Poco/RefCountedObject.h"
|
||||
#include "Poco/AutoPtr.h"
|
||||
@@ -291,12 +292,22 @@ private:
|
||||
void resetExtraction();
|
||||
/// Resets extraction so it can be reused again.
|
||||
|
||||
template <class T, class C>
|
||||
InternalExtraction<T,C>* createExtract(const MetaColumn& mc)
|
||||
template <class C>
|
||||
InternalExtraction<C>* createExtract(const MetaColumn& mc)
|
||||
{
|
||||
typedef typename C::value_type T;
|
||||
C* pData = new C;
|
||||
Column<T,C>* pCol = new Column<T,C>(mc, pData);
|
||||
return new InternalExtraction<T,C>(*pData, pCol);
|
||||
return new InternalExtraction<C>(*pData, pCol);
|
||||
}
|
||||
|
||||
template <class C>
|
||||
InternalBulkExtraction<C>* createBulkExtract(const MetaColumn& mc)
|
||||
{
|
||||
typedef typename C::value_type T;
|
||||
C* pData = new C;
|
||||
Column<T,C>* pCol = new Column<T,C>(mc, pData);
|
||||
return new InternalBulkExtraction<C>(*pData, pCol, getExtractionLimit());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -330,11 +341,26 @@ private:
|
||||
if (storage.empty()) storage = DEQUE;
|
||||
|
||||
if (0 == icompare(DEQUE, storage))
|
||||
addExtract(createExtract<T, std::deque<T> >(mc));
|
||||
{
|
||||
if (!isBulkExtraction())
|
||||
addExtract(createExtract<std::deque<T> >(mc));
|
||||
else
|
||||
addExtract(createBulkExtract<std::deque<T> >(mc));
|
||||
}
|
||||
else if (0 == icompare(VECTOR, storage))
|
||||
addExtract(createExtract<T, std::vector<T> >(mc));
|
||||
{
|
||||
if (!isBulkExtraction())
|
||||
addExtract(createExtract<std::vector<T> >(mc));
|
||||
else
|
||||
addExtract(createBulkExtract<std::vector<T> >(mc));
|
||||
}
|
||||
else if (0 == icompare(LIST, storage))
|
||||
addExtract(createExtract<T, std::list<T> >(mc));
|
||||
{
|
||||
if (!isBulkExtraction())
|
||||
addExtract(createExtract<std::list<T> >(mc));
|
||||
else
|
||||
addExtract(createBulkExtract<std::list<T> >(mc));
|
||||
}
|
||||
}
|
||||
|
||||
bool isNull(std::size_t col, std::size_t row) const;
|
||||
|
||||
@@ -160,6 +160,137 @@ private:
|
||||
};
|
||||
|
||||
|
||||
template <class C>
|
||||
class TypeHandler<std::deque<C> >: public AbstractTypeHandler
|
||||
/// Specialization of type handler for std::deque.
|
||||
/// Used by bulk extraction.
|
||||
{
|
||||
public:
|
||||
static void bind(std::size_t pos, const std::deque<C>& obj, AbstractBinder* pBinder, AbstractBinder::Direction dir)
|
||||
{
|
||||
poco_assert_dbg (pBinder != 0);
|
||||
pBinder->bind(pos, obj, dir);
|
||||
}
|
||||
|
||||
static std::size_t size()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void extract(std::size_t pos, std::deque<C>& obj, const std::deque<C>& defVal, AbstractExtractor* pExt)
|
||||
{
|
||||
poco_assert_dbg (pExt != 0);
|
||||
if (!pExt->extract(pos, obj))
|
||||
{
|
||||
if (defVal.size() == 1)
|
||||
obj.assign(obj.size(), defVal.front());
|
||||
else if (defVal.size() > 1)
|
||||
obj.assign(defVal.begin(), defVal.end());
|
||||
else
|
||||
throw InvalidArgumentException("Size of default value container must not be zero.");
|
||||
}
|
||||
}
|
||||
|
||||
static void prepare(std::size_t pos, std::deque<C>& obj, AbstractPreparation* pPrepare)
|
||||
{
|
||||
poco_assert_dbg (pPrepare != 0);
|
||||
pPrepare->prepare(pos, obj);
|
||||
}
|
||||
|
||||
private:
|
||||
TypeHandler(const TypeHandler&);
|
||||
TypeHandler& operator = (const TypeHandler&);
|
||||
};
|
||||
|
||||
|
||||
template <class C>
|
||||
class TypeHandler<std::vector<C> >: public AbstractTypeHandler
|
||||
/// Specialization of type handler for std::vector.
|
||||
/// Used by bulk extraction.
|
||||
{
|
||||
public:
|
||||
typedef typename std::vector<C>::value_type T;
|
||||
|
||||
static void bind(std::size_t pos, const std::vector<C>& obj, AbstractBinder* pBinder, AbstractBinder::Direction dir)
|
||||
{
|
||||
poco_assert_dbg (pBinder != 0);
|
||||
pBinder->bind(pos, obj, dir);
|
||||
}
|
||||
|
||||
static std::size_t size()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void extract(std::size_t pos, std::vector<C>& obj, const std::vector<C>& defVal, AbstractExtractor* pExt)
|
||||
{
|
||||
poco_assert_dbg (pExt != 0);
|
||||
if (!pExt->extract(pos, obj))
|
||||
{
|
||||
if (defVal.size() == 1)
|
||||
obj.assign(obj.size(), defVal.front());
|
||||
else if (defVal.size() > 1)
|
||||
obj.assign(defVal.begin(), defVal.end());
|
||||
else
|
||||
throw InvalidArgumentException("Size of default value container must not be zero.");
|
||||
}
|
||||
}
|
||||
|
||||
static void prepare(std::size_t pos, std::vector<C>& obj, AbstractPreparation* pPrepare)
|
||||
{
|
||||
poco_assert_dbg (pPrepare != 0);
|
||||
pPrepare->prepare(pos, obj);
|
||||
}
|
||||
|
||||
private:
|
||||
TypeHandler(const TypeHandler&);
|
||||
TypeHandler& operator = (const TypeHandler&);
|
||||
};
|
||||
|
||||
|
||||
template <class C>
|
||||
class TypeHandler<std::list<C> >: public AbstractTypeHandler
|
||||
/// Specialization of type handler for std::list.
|
||||
/// Used by bulk extraction.
|
||||
{
|
||||
public:
|
||||
static void bind(std::size_t pos, const std::list<C>& obj, AbstractBinder* pBinder, AbstractBinder::Direction dir)
|
||||
{
|
||||
poco_assert_dbg (pBinder != 0);
|
||||
pBinder->bind(pos, obj, dir);
|
||||
}
|
||||
|
||||
static std::size_t size()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void extract(std::size_t pos, std::list<C>& obj, const std::list<C>& defVal, AbstractExtractor* pExt)
|
||||
{
|
||||
poco_assert_dbg (pExt != 0);
|
||||
if (!pExt->extract(pos, obj))
|
||||
{
|
||||
if (defVal.size() == 1)
|
||||
obj.assign(obj.size(), defVal.front());
|
||||
else if (defVal.size() > 1)
|
||||
obj.assign(defVal.begin(), defVal.end());
|
||||
else
|
||||
throw InvalidArgumentException("Size of default value container must not be zero.");
|
||||
}
|
||||
}
|
||||
|
||||
static void prepare(std::size_t pos, std::list<C>& obj, AbstractPreparation* pPrepare)
|
||||
{
|
||||
poco_assert_dbg (pPrepare != 0);
|
||||
pPrepare->prepare(pos, obj);
|
||||
}
|
||||
|
||||
private:
|
||||
TypeHandler(const TypeHandler&);
|
||||
TypeHandler& operator = (const TypeHandler&);
|
||||
};
|
||||
|
||||
|
||||
/// Poco::Tuple TypeHandler specializations
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user