diff --git a/Data/SQLite/testsuite/src/SQLiteTest.cpp b/Data/SQLite/testsuite/src/SQLiteTest.cpp index 1d8f3f20c..2268a10d1 100644 --- a/Data/SQLite/testsuite/src/SQLiteTest.cpp +++ b/Data/SQLite/testsuite/src/SQLiteTest.cpp @@ -2046,6 +2046,42 @@ void SQLiteTest::testDynamicAny() } + + +void SQLiteTest::testPair() +{ + Session tmp (Poco::Data::SQLite::Connector::KEY, "dummy.db"); + assert (tmp.isConnected()); + std::string tableName("Simpsons"); + std::pair junior = std::make_pair("Junior", 12); + std::pair senior = std::make_pair("Senior", 99); + + + int count = 0; + std::string result; + + tmp << "DROP TABLE IF EXISTS Simpsons", now; + tmp << "CREATE TABLE IF NOT EXISTS Simpsons (LastName VARCHAR(30), Age INTEGER(3))", now; + tmp << "SELECT name FROM sqlite_master WHERE tbl_name=?", use(tableName), into(result), now; + assert (result == tableName); + + + // these are fine + tmp << "INSERT INTO Simpsons VALUES(?, ?)", use(junior), now; + tmp << "INSERT INTO Simpsons VALUES(?, ?)", useRef(senior), now; + + tmp << "SELECT COUNT(*) FROM Simpsons", into(count), now; + assert (2 == count); + + std::vector > ret; + tmp << "SELECT * FROM Simpsons", into(ret), range(2,2), now; + assert (ret[0].second == 12 || ret[1].second == 12); + assert (ret[0].second == 99 || ret[1].second == 99); + assert (ret[0].first == "Junior" || ret[1].first == "Junior"); + assert (ret[0].first == "Senior" || ret[1].first == "Senior"); + +} + void SQLiteTest::testSQLChannel() { Session tmp (Poco::Data::SQLite::Connector::KEY, "dummy.db"); @@ -2344,6 +2380,7 @@ CppUnit::Test* SQLiteTest::suite() CppUnit_addTest(pSuite, SQLiteTest, testExternalBindingAndExtraction); CppUnit_addTest(pSuite, SQLiteTest, testBindingCount); CppUnit_addTest(pSuite, SQLiteTest, testMultipleResults); + CppUnit_addTest(pSuite, SQLiteTest, testPair); return pSuite; } diff --git a/Data/SQLite/testsuite/src/SQLiteTest.h b/Data/SQLite/testsuite/src/SQLiteTest.h index d668ecc49..f51c17b4e 100644 --- a/Data/SQLite/testsuite/src/SQLiteTest.h +++ b/Data/SQLite/testsuite/src/SQLiteTest.h @@ -119,6 +119,7 @@ public: void testAny(); void testDynamicAny(); + void testPair(); void testSQLChannel(); void testSQLLogger(); diff --git a/Data/include/Poco/Data/Binding.h b/Data/include/Poco/Data/Binding.h index 67121e842..6c672e06a 100644 --- a/Data/include/Poco/Data/Binding.h +++ b/Data/include/Poco/Data/Binding.h @@ -1350,6 +1350,120 @@ private: }; + +template +class Binding >: public AbstractBinding + /// Specialization for std::multimap. +{ +public: + explicit Binding(std::pair& val, + const std::string& name = "", + Direction direction = PD_IN): + AbstractBinding(name, direction), + _val(val), + _bound(false) + /// Creates the Binding. + { + reset(); + } + + ~Binding() + /// Destroys the Binding. + { + } + + std::size_t numOfColumnsHandled() const + { + return TypeHandler::size() + TypeHandler::size(); + } + + std::size_t numOfRowsHandled() const + { + return 1; + } + + bool canBind() const + { + return !_bound; + } + + void bind(std::size_t pos) + { + poco_assert_dbg(getBinder() != 0); + poco_assert_dbg(canBind()); + TypeHandler::bind(pos, _val.first, getBinder(), getDirection()); + TypeHandler::bind(pos+1, _val.second, getBinder(), getDirection()); + _bound = true; + } + + void reset() + { + _bound = false; + } + +private: + std::pair& _val; + bool _bound; +}; + + +template +class CopyBinding >: public AbstractBinding + /// Specialization for std::multimap. +{ +public: + explicit CopyBinding(std::pair& val, + const std::string& name = "", + Direction direction = PD_IN): + AbstractBinding(name, direction), + _pVal(new std::pair(val)), + _bound(false) + /// Creates the Binding. + { + reset(); + } + + ~CopyBinding() + /// Destroys the Binding. + { + } + + std::size_t numOfColumnsHandled() const + { + return TypeHandler::size() + TypeHandler::size(); + } + + std::size_t numOfRowsHandled() const + { + return 1; + } + + bool canBind() const + { + return !_bound; + } + + void bind(std::size_t pos) + { + poco_assert_dbg(getBinder() != 0); + poco_assert_dbg(canBind()); + TypeHandler::bind(pos, _pVal->first, getBinder(), getDirection()); + TypeHandler::bind(pos+1, _pVal->second, getBinder(), getDirection()); + _bound = true;; + } + + void reset() + { + _bound = false; + } + +private: + typedef typename TypeWrapper >::TYPE ValueType; + SharedPtr _pVal; + bool _bound; +}; + + namespace Keywords { diff --git a/Data/include/Poco/Data/Extraction.h b/Data/include/Poco/Data/Extraction.h index c26af7f53..aa4de9ad2 100644 --- a/Data/include/Poco/Data/Extraction.h +++ b/Data/include/Poco/Data/Extraction.h @@ -764,6 +764,61 @@ private: }; + +template +class Extraction >: public AbstractExtraction + /// Map Data Type specialization for extraction of values from a query result set. +{ +public: + Extraction(std::pair& result, const Position& pos = Position(0)): + AbstractExtraction(Limit::LIMIT_UNLIMITED, pos.value()), + _rResult(result), + _default() + { + } + + Extraction(std::pair& result, const std::pair& def, const Position& pos = Position(0)): + AbstractExtraction(Limit::LIMIT_UNLIMITED, pos.value()), + _rResult(result), + _default(def) + { + } + + ~Extraction() + { + } + + std::size_t numOfColumnsHandled() const + { + return TypeHandler::size() + TypeHandler::size(); + } + + std::size_t numOfRowsHandled() const + { + return 1; + } + + std::size_t numOfRowsAllowed() const + { + return getLimit(); + } + + std::size_t extract(std::size_t pos) + { + TypeHandler >::extract(pos, _rResult, _default, getExtractor()); + return 1u; + } + + AbstractPrepare* createPrepareObject(AbstractPreparation* pPrep, std::size_t pos) + { + return new Prepare(pPrep, pos, _default); + } + +private: + std::pair& _rResult; + std::pair _default; +}; + namespace Keywords { diff --git a/Data/include/Poco/Data/TypeHandler.h b/Data/include/Poco/Data/TypeHandler.h index 26ff95e0a..fd8d9a4ea 100644 --- a/Data/include/Poco/Data/TypeHandler.h +++ b/Data/include/Poco/Data/TypeHandler.h @@ -1763,6 +1763,44 @@ private: TypeHandler& operator=(const TypeHandler&); }; + + +template +class TypeHandler >: public AbstractTypeHandler +{ +public: + static void bind(std::size_t pos, const std::pair& obj, AbstractBinder* pBinder, AbstractBinder::Direction dir) + { + TypeHandler::bind(pos, obj.first, pBinder, dir); + pos += TypeHandler::size(); + TypeHandler::bind(pos, obj.second, pBinder, dir); + } + + static std::size_t size() + { + return TypeHandler::size() + TypeHandler::size(); + } + + static void extract(std::size_t pos, std::pair& obj, const std::pair& defVal, AbstractExtractor* pExt) + { + TypeHandler::extract(pos, obj.first, defVal.first, pExt); + pos += TypeHandler::size(); + TypeHandler::extract(pos, obj.second, defVal.second, pExt); + } + + static void prepare(std::size_t pos, std::pair& obj, AbstractPreparation* pPrepare) + { + TypeHandler::prepare(pos, obj.first, pPrepare); + pos += TypeHandler::size(); + TypeHandler::prepare(pos, obj.second, pPrepare); + } + +private: + TypeHandler(const TypeHandler&); + TypeHandler& operator = (const TypeHandler&); +}; + + } } // namespace Poco::Data