From e39d2b914ba81b5d73419076704f428fcd924d7e Mon Sep 17 00:00:00 2001 From: Jan Kukuczka Date: Thu, 3 Oct 2019 14:16:34 +0200 Subject: [PATCH 1/3] Fixed session reset - changed calling of mysql_reset_connection() to query FLUSH - previously used mysql_reset_connection() caused issues with encoding - see comment in Data/MySQL/src/SessionHandle.cpp:181 SessionHandle::reset() for more info --- Data/MySQL/src/SessionHandle.cpp | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/Data/MySQL/src/SessionHandle.cpp b/Data/MySQL/src/SessionHandle.cpp index f15020cf7c..288f837f2c 100644 --- a/Data/MySQL/src/SessionHandle.cpp +++ b/Data/MySQL/src/SessionHandle.cpp @@ -178,11 +178,21 @@ void SessionHandle::rollback() void SessionHandle::reset() { -#if ((defined (MYSQL_VERSION_ID)) && (MYSQL_VERSION_ID >= 50700)) || ((defined (MARIADB_PACKAGE_VERSION_ID)) && (MARIADB_PACKAGE_VERSION_ID >= 30000)) - if (mysql_reset_connection(_pHandle) != 0) -#else - if (mysql_refresh(_pHandle, REFRESH_TABLES | REFRESH_STATUS | REFRESH_THREADS | REFRESH_READ_LOCK) != 0) -#endif +/* + We have to somehow reset sessions before getting session from session pool, because sometimes + used session has some remains from previous usage. + + First, we tried call mysql_refresh() (now obsolete) and then mysql_reset_connection(). Both of + these functions caused unintended reseting of variables holding charset/encoding (internal variables + like "session.collation_connection" etc., was reseted to default value which is "latin1_swedish_ci"). + + Executing query FLUSH seems that it resets session and does not harm encoding. + I have tried few flush options (PRIVILEGES, USER_RESOURCES, QUERY CACHE, STATUS) and every of + these worked. Only option which did not work was FLUSH TABLES - it caused deadlocks. So I decided + call only FLUSH STATUS. +*/ + +if (mysql_query(_pHandle, "FLUSH STATUS;") != 0) throw TransactionException("Reset connection failed.", _pHandle); } From d821de100360b01c2166403526957da592a5eb2c Mon Sep 17 00:00:00 2001 From: Jan Kukuczka Date: Fri, 4 Oct 2019 12:34:44 +0200 Subject: [PATCH 2/3] Added test which should prove that session obtained from session pool does not harm encoding --- Data/MySQL/testsuite/src/MySQLTest.cpp | 11 +++++++++ Data/MySQL/testsuite/src/MySQLTest.h | 1 + Data/MySQL/testsuite/src/SQLExecutor.cpp | 29 ++++++++++++++++++++++++ Data/MySQL/testsuite/src/SQLExecutor.h | 2 ++ 4 files changed, 43 insertions(+) diff --git a/Data/MySQL/testsuite/src/MySQLTest.cpp b/Data/MySQL/testsuite/src/MySQLTest.cpp index d9baab6e3b..7f742c4388 100644 --- a/Data/MySQL/testsuite/src/MySQLTest.cpp +++ b/Data/MySQL/testsuite/src/MySQLTest.cpp @@ -23,6 +23,7 @@ #include "Poco/Data/MySQL/MySQLException.h" #include "Poco/Nullable.h" #include "Poco/Data/DataException.h" +#include "Poco/Data/SessionPool.h" #include using namespace Poco::Data; @@ -423,6 +424,15 @@ void MySQLTest::testDateTime() } +void MySQLTest::testSessionPoolAndUnicode() +{ + if (!_pSession) fail ("Test not available."); + + recreateStringsTable(); + _pExecutor->sessionPoolAndUnicode(_dbConnString); +} + + void MySQLTest::testBLOB() { if (!_pSession) fail ("Test not available."); @@ -897,6 +907,7 @@ CppUnit::Test* MySQLTest::suite() CppUnit_addTest(pSuite, MySQLTest, testSingleSelect); CppUnit_addTest(pSuite, MySQLTest, testEmptyDB); CppUnit_addTest(pSuite, MySQLTest, testDateTime); + CppUnit_addTest(pSuite, MySQLTest, testSessionPoolAndUnicode); //CppUnit_addTest(pSuite, MySQLTest, testBLOB); CppUnit_addTest(pSuite, MySQLTest, testBLOBStmt); CppUnit_addTest(pSuite, MySQLTest, testUnsignedInts); diff --git a/Data/MySQL/testsuite/src/MySQLTest.h b/Data/MySQL/testsuite/src/MySQLTest.h index 0589c7ed49..e6c169533f 100644 --- a/Data/MySQL/testsuite/src/MySQLTest.h +++ b/Data/MySQL/testsuite/src/MySQLTest.h @@ -77,6 +77,7 @@ class MySQLTest: public CppUnit::TestCase void testSingleSelect(); void testEmptyDB(); void testDateTime(); + void testSessionPoolAndUnicode(); void testBLOB(); void testBLOBStmt(); diff --git a/Data/MySQL/testsuite/src/SQLExecutor.cpp b/Data/MySQL/testsuite/src/SQLExecutor.cpp index a0484068b1..eb7d0ec803 100644 --- a/Data/MySQL/testsuite/src/SQLExecutor.cpp +++ b/Data/MySQL/testsuite/src/SQLExecutor.cpp @@ -24,6 +24,7 @@ #include "Poco/Data/Transaction.h" #include "Poco/Data/MySQL/Connector.h" #include "Poco/Data/MySQL/MySQLException.h" +#include "Poco/Data/SessionPool.h" #ifdef _WIN32 #include @@ -1462,6 +1463,34 @@ void SQLExecutor::tupleVector() } +void SQLExecutor::sessionPoolAndUnicode(const std::string& connString) +{ + std::string funct = "unicode()"; + std::string text = "ěščřžťďůň"; + std::string text2; + + // Test uses session from SessionPool instead of _pSession to prove session + // obtained and returned into pool is valid. + + // Min/Max 1 session - ensures that when get() is called, same session should be returned + Poco::SharedPtr sp = new Poco::Data::SessionPool(MySQL::Connector::KEY, connString, 1, 1); + + { + auto session = sp->get(); + try { session << "INSERT INTO Strings VALUES (?)", use(text), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + } // parentheses to ensure session is returned into pool + + auto session = sp->get(); + try { session << "SELECT str FROM Strings", into(text2), now; } + catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } + catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } + + assertTrue (text == text2); +} + + void SQLExecutor::internalExtraction() { /*std::string funct = "internalExtraction()"; diff --git a/Data/MySQL/testsuite/src/SQLExecutor.h b/Data/MySQL/testsuite/src/SQLExecutor.h index 00121d9da1..ded037a86d 100644 --- a/Data/MySQL/testsuite/src/SQLExecutor.h +++ b/Data/MySQL/testsuite/src/SQLExecutor.h @@ -89,6 +89,8 @@ class SQLExecutor: public CppUnit::TestCase void tuples(); void tupleVector(); + void sessionPoolAndUnicode(const std::string& connString); + void internalExtraction(); void doNull(); From ed89142ef37aec8810b03e8cc34e4744ec2c9dd1 Mon Sep 17 00:00:00 2001 From: Jan Kukuczka Date: Fri, 4 Oct 2019 16:12:23 +0200 Subject: [PATCH 3/3] Don't using `auto` --- Data/MySQL/testsuite/src/SQLExecutor.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Data/MySQL/testsuite/src/SQLExecutor.cpp b/Data/MySQL/testsuite/src/SQLExecutor.cpp index eb7d0ec803..d09aecda33 100644 --- a/Data/MySQL/testsuite/src/SQLExecutor.cpp +++ b/Data/MySQL/testsuite/src/SQLExecutor.cpp @@ -1476,14 +1476,14 @@ void SQLExecutor::sessionPoolAndUnicode(const std::string& connString) Poco::SharedPtr sp = new Poco::Data::SessionPool(MySQL::Connector::KEY, connString, 1, 1); { - auto session = sp->get(); + Poco::Data::Session session = sp->get(); try { session << "INSERT INTO Strings VALUES (?)", use(text), now; } catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); } } // parentheses to ensure session is returned into pool - auto session = sp->get(); - try { session << "SELECT str FROM Strings", into(text2), now; } + Poco::Data::Session session2 = sp->get(); + try { session2 << "SELECT str FROM Strings", into(text2), now; } catch(ConnectionException& ce){ std::cout << ce.displayText() << std::endl; fail (funct); } catch(StatementException& se){ std::cout << se.displayText() << std::endl; fail (funct); }