[Libreoffice-commits] core.git: connectivity/Library_mysqlc.mk connectivity/qa connectivity/source

Libreoffice Gerrit user logerrit at kemper.freedesktop.org
Mon Nov 5 09:06:58 UTC 2018


 connectivity/Library_mysqlc.mk                          |    1 
 connectivity/qa/connectivity/mysql/mysql.cxx            |   48 ++
 connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx |  283 +++++++---------
 connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx |   25 +
 4 files changed, 200 insertions(+), 157 deletions(-)

New commits:
commit 0c6da44c9249e7b9355c0efd9a60004701867275
Author:     Tamas Bunth <tamas.bunth at collabora.co.uk>
AuthorDate: Tue Oct 30 18:49:46 2018 +0100
Commit:     Tamás Bunth <btomi96 at gmail.com>
CommitDate: Mon Nov 5 10:06:03 2018 +0100

    mysqlc: allow multiple open statements
    
    Change-Id: I07e57ea7d9e6af1c7543483b1ab54a0b8c5be2d5
    Reviewed-on: https://gerrit.libreoffice.org/62640
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.grandin at collabora.co.uk>
    Reviewed-by: Tamás Bunth <btomi96 at gmail.com>

diff --git a/connectivity/Library_mysqlc.mk b/connectivity/Library_mysqlc.mk
index 42a10e40cdf8..9dba7769a9a2 100644
--- a/connectivity/Library_mysqlc.mk
+++ b/connectivity/Library_mysqlc.mk
@@ -33,6 +33,7 @@ $(eval $(call gb_Library_use_libraries,mysqlc,\
 	cppu \
 	sal \
 	salhelper \
+	comphelper \
 	cppuhelper \
 ))
 
diff --git a/connectivity/qa/connectivity/mysql/mysql.cxx b/connectivity/qa/connectivity/mysql/mysql.cxx
index f5057dce1519..f78ea2ea57e5 100644
--- a/connectivity/qa/connectivity/mysql/mysql.cxx
+++ b/connectivity/qa/connectivity/mysql/mysql.cxx
@@ -43,6 +43,7 @@ public:
     void testDBConnection();
     void testCreateAndDropTable();
     void testIntegerInsertAndQuery();
+    void testDBPositionChange();
 
     CPPUNIT_TEST_SUITE(MysqlTestDriver);
     CPPUNIT_TEST(testDBConnection);
@@ -175,6 +176,53 @@ void MysqlTestDriver::testIntegerInsertAndQuery()
     CPPUNIT_ASSERT_EQUAL(0, nUpdateCount); // it's a DDL statement
 }
 
+void MysqlTestDriver::testDBPositionChange()
+{
+    Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos);
+    if (!xConnection.is())
+    {
+        CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is());
+    }
+
+    Reference<XStatement> xStatement = xConnection->createStatement();
+    CPPUNIT_ASSERT(xStatement.is());
+
+    auto nUpdateCount
+        = xStatement->executeUpdate("CREATE TABLE myTestTable (id INTEGER PRIMARY KEY)");
+    CPPUNIT_ASSERT_EQUAL(0, nUpdateCount); // it's a DDL statement
+    Reference<XPreparedStatement> xPrepared
+        = xConnection->prepareStatement(OUString{ "INSERT INTO myTestTable VALUES (?)" });
+    Reference<XParameters> xParams(xPrepared, UNO_QUERY);
+    constexpr int ROW_COUNT = 3;
+    for (int i = 1; i <= ROW_COUNT; ++i)
+    {
+        xParams->setLong(1, i); // first and only column
+        nUpdateCount = xPrepared->executeUpdate();
+        CPPUNIT_ASSERT_EQUAL(1, nUpdateCount); // one row is inserted at a time
+    }
+    Reference<XResultSet> xResultSet = xStatement->executeQuery("SELECT id from myTestTable");
+    CPPUNIT_ASSERT_MESSAGE("result set cannot be instantiated after query", xResultSet.is());
+    Reference<XRow> xRow(xResultSet, UNO_QUERY);
+    CPPUNIT_ASSERT_MESSAGE("cannot extract row from result set!", xRow.is());
+
+    xResultSet->afterLast();
+    CPPUNIT_ASSERT_EQUAL(ROW_COUNT + 1, xResultSet->getRow());
+    xResultSet->last();
+    CPPUNIT_ASSERT_EQUAL(ROW_COUNT, nUpdateCount);
+    CPPUNIT_ASSERT_EQUAL(ROW_COUNT, xResultSet->getRow());
+    bool successPrevios = xResultSet->previous();
+    CPPUNIT_ASSERT(successPrevios);
+    CPPUNIT_ASSERT_EQUAL(ROW_COUNT - 1, nUpdateCount);
+    xResultSet->beforeFirst();
+    xResultSet->next();
+    CPPUNIT_ASSERT_EQUAL(1, xResultSet->getRow());
+    xResultSet->first();
+    CPPUNIT_ASSERT_EQUAL(1, xResultSet->getRow());
+
+    nUpdateCount = xStatement->executeUpdate("DROP TABLE myTestTable");
+    CPPUNIT_ASSERT_EQUAL(0, nUpdateCount); // it's a DDL statement
+}
+
 CPPUNIT_TEST_SUITE_REGISTRATION(MysqlTestDriver);
 
 CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx b/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx
index ab018ef9a777..b3a172f0c2de 100644
--- a/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx
+++ b/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx
@@ -31,6 +31,7 @@
 #include <com/sun/star/sdbcx/CompareBookmark.hpp>
 #include <cppuhelper/supportsservice.hxx>
 #include <cppuhelper/typeprovider.hxx>
+#include <comphelper/seqstream.hxx>
 
 #include <sal/log.hxx>
 
@@ -48,6 +49,7 @@ using namespace com::sun::star::sdbc;
 using namespace com::sun::star::sdbcx;
 using namespace com::sun::star::container;
 using namespace com::sun::star::io;
+using namespace com::sun::star::uno;
 using namespace com::sun::star::util;
 using namespace ::comphelper;
 using ::osl::MutexGuard;
@@ -58,13 +60,13 @@ namespace
 {
 // copied from string misc, it should be replaced when library is not an
 // extension anymore
-std::vector<OUString> lcl_split(const OUString& rStr, sal_Unicode cSeparator)
+std::vector<OString> lcl_split(const OString& rStr, char cSeparator)
 {
-    std::vector<OUString> vec;
+    std::vector<OString> vec;
     sal_Int32 idx = 0;
     do
     {
-        OUString kw = rStr.getToken(0, cSeparator, idx);
+        OString kw = rStr.getToken(0, cSeparator, idx);
         kw = kw.trim();
         if (!kw.isEmpty())
         {
@@ -77,12 +79,23 @@ std::vector<OUString> lcl_split(const OUString& rStr, sal_Unicode cSeparator)
 
 void OResultSet::checkRowIndex()
 {
-    if (m_nRowPosition <= 0 || m_nRowPosition > m_nRowCount)
+    if (m_nRowPosition < 0 || m_nRowPosition >= m_nRowCount)
     {
         throw SQLException("Cursor position out of range", *this, OUString(), 1, Any());
     }
 }
 
+bool OResultSet::checkNull(sal_Int32 column)
+{
+    if (m_aRows[m_nRowPosition][column - 1].isEmpty())
+    {
+        m_bWasNull = true;
+        return true;
+    }
+    m_bWasNull = false;
+    return false;
+}
+
 OUString SAL_CALL OResultSet::getImplementationName()
 {
     return OUString("com.sun.star.sdbcx.mysqlc.ResultSet");
@@ -106,18 +119,55 @@ OResultSet::OResultSet(OConnection& rConn, OCommonStatement* pStmt, MYSQL_RES* p
     : OResultSet_BASE(m_aMutex)
     , OPropertySetHelper(OResultSet_BASE::rBHelper)
     , m_rConnection(rConn)
-    , m_aRow(nullptr)
     , m_pMysql(rConn.getMysqlConnection())
     , m_aStatement(static_cast<OWeakObject*>(pStmt))
     , m_pResult(pResult)
-    , fieldCount(0)
     , m_encoding(_encoding)
 {
-    fieldCount = mysql_num_fields(pResult);
+    m_xMetaData = new OResultSetMetaData(m_rConnection, m_pResult);
+}
+
+void OResultSet::ensureResultFetched()
+{
+    if (!m_bResultFetched)
+    {
+        fetchResult();
+    }
+}
+
+void OResultSet::fetchResult()
+{
+    // Mysql C API does not allow simultaneously opened result sets, but sdbc does.
+    // Because of that we need to fetch all of the data ASAP
 
     // it works only if result set is produced via mysql_store_result
     // TODO ensure that
-    m_nRowCount = mysql_num_rows(pResult);
+    m_nRowCount = mysql_num_rows(m_pResult);
+
+    // fetch all the data
+    m_aRows.reserve(m_nRowCount);
+
+    m_nFieldCount = mysql_num_fields(m_pResult);
+    MYSQL_FIELD* pFields = mysql_fetch_fields(m_pResult);
+    m_aFields.assign(pFields, pFields + m_nFieldCount);
+
+    for (sal_Int32 row = 0; row < m_nRowCount; ++row)
+    {
+        MYSQL_ROW data = mysql_fetch_row(m_pResult);
+        unsigned long* lengths = mysql_fetch_lengths(m_pResult);
+        m_aRows.push_back(DataFields{});
+        // MYSQL_ROW is char**, array of strings
+        for (unsigned col = 0; col < m_nFieldCount; ++col)
+        {
+            m_aRows.back().push_back(OString{ data[col], static_cast<sal_Int32>(lengths[col]) });
+        }
+    }
+    unsigned errorNum = mysql_errno(m_pMysql);
+    if (errorNum)
+        mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(m_pMysql), errorNum, *this,
+                                                     m_encoding);
+    m_bResultFetched = true;
+    mysql_free_result(m_pResult);
 }
 
 void OResultSet::disposing()
@@ -154,10 +204,9 @@ sal_Int32 SAL_CALL OResultSet::findColumn(const OUString& columnName)
     MutexGuard aGuard(m_aMutex);
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
 
-    MYSQL_FIELD* pFields = mysql_fetch_fields(m_pResult);
-    for (unsigned int i = 0; i < fieldCount; ++i)
+    for (unsigned int i = 0; i < m_nFieldCount; ++i)
     {
-        if (columnName.equalsIgnoreAsciiCaseAscii(pFields[i].name))
+        if (columnName.equalsIgnoreAsciiCaseAscii(m_aFields[i].name))
             return i + 1; // sdbc indexes from 1
     }
 
@@ -171,9 +220,12 @@ uno::Reference<XInputStream> SAL_CALL OResultSet::getBinaryStream(sal_Int32 colu
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
     checkColumnIndex(column);
     checkRowIndex();
+    if (checkNull(column))
+        return nullptr;
 
-    mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getBinaryStream", *this);
-    return nullptr;
+    OString sVal = m_aRows[m_nRowPosition][column - 1];
+    return new SequenceInputStream{ uno::Sequence<sal_Int8>(
+        reinterpret_cast<sal_Int8 const*>(sVal.getStr()), getDataLength(column - 1)) };
 }
 
 uno::Reference<XInputStream> SAL_CALL OResultSet::getCharacterStream(sal_Int32 column)
@@ -182,7 +234,6 @@ uno::Reference<XInputStream> SAL_CALL OResultSet::getCharacterStream(sal_Int32 c
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
     checkColumnIndex(column);
     checkRowIndex();
-
     mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getCharacterStream",
                                                             *this);
     return nullptr;
@@ -194,16 +245,11 @@ sal_Bool SAL_CALL OResultSet::getBoolean(sal_Int32 column)
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
     checkColumnIndex(column);
     checkRowIndex();
-
-    char* pValue = m_aRow[column - 1];
-    if (!pValue)
-    {
-        m_bWasNull = true;
+    if (checkNull(column))
         return false;
-    }
 
-    m_bWasNull = false;
-    return static_cast<bool>(std::atoi(pValue));
+    OString sVal = m_aRows[m_nRowPosition][column - 1];
+    return sVal.toInt32() != 0;
 }
 
 sal_Int8 SAL_CALL OResultSet::getByte(sal_Int32 column)
@@ -212,32 +258,24 @@ sal_Int8 SAL_CALL OResultSet::getByte(sal_Int32 column)
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
     checkColumnIndex(column);
     checkRowIndex();
-
-    char* pValue = m_aRow[column - 1];
-    if (!pValue)
-    {
-        m_bWasNull = true;
+    if (checkNull(column))
         return 0;
-    }
 
-    m_bWasNull = false;
-    return static_cast<sal_Int8>(std::atoi(pValue));
+    OString sVal = m_aRows[m_nRowPosition][column - 1];
+
+    return static_cast<sal_Int8>(sVal.toInt32());
 }
 
 uno::Sequence<sal_Int8> SAL_CALL OResultSet::getBytes(sal_Int32 column)
 {
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
     MutexGuard aGuard(m_aMutex);
-
-    char* pValue = m_aRow[column - 1];
-    if (!pValue)
-    {
-        m_bWasNull = true;
+    OString sVal = m_aRows[m_nRowPosition][column - 1];
+    if (checkNull(column))
         return uno::Sequence<sal_Int8>();
-    }
-    m_bWasNull = false;
-    return uno::Sequence<sal_Int8>(reinterpret_cast<sal_Int8 const*>(pValue),
-                                   m_aLengths[column - 1]);
+
+    return uno::Sequence<sal_Int8>(reinterpret_cast<sal_Int8 const*>(sVal.getStr()),
+                                   getDataLength(column - 1));
 }
 
 Date SAL_CALL OResultSet::getDate(sal_Int32 column)
@@ -247,13 +285,12 @@ Date SAL_CALL OResultSet::getDate(sal_Int32 column)
     checkColumnIndex(column);
     checkRowIndex();
 
-    Date d; // TODO initialize
-    char* dateStr = m_aRow[column - 1];
-    if (!dateStr)
-    {
-        m_bWasNull = true;
+    Date d;
+
+    if (checkNull(column))
         return d;
-    }
+
+    OString dateStr = m_aRows[m_nRowPosition][column - 1];
 
     OString dateString(dateStr);
     OString token;
@@ -276,7 +313,6 @@ Date SAL_CALL OResultSet::getDate(sal_Int32 column)
         }
         i++;
     } while (nIndex >= 0);
-    m_bWasNull = false;
     return d;
 }
 
@@ -287,15 +323,11 @@ double SAL_CALL OResultSet::getDouble(sal_Int32 column)
     checkColumnIndex(column);
     checkRowIndex();
 
-    char* pValue = m_aRow[column - 1];
-    if (!pValue)
-    {
-        m_bWasNull = true;
+    if (checkNull(column))
         return 0.0;
-    }
 
-    m_bWasNull = false;
-    return std::strtod(pValue, nullptr);
+    OString sVal = m_aRows[m_nRowPosition][column - 1];
+    return sVal.toDouble();
 }
 
 float SAL_CALL OResultSet::getFloat(sal_Int32 column)
@@ -304,31 +336,22 @@ float SAL_CALL OResultSet::getFloat(sal_Int32 column)
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
     checkColumnIndex(column);
     checkRowIndex();
-
-    char* pValue = m_aRow[column - 1];
-    if (!pValue)
-    {
-        m_bWasNull = true;
+    if (checkNull(column))
         return 0.0f;
-    }
 
-    m_bWasNull = false;
-    return std::strtod(pValue, nullptr);
+    OString sVal = m_aRows[m_nRowPosition][column - 1];
+    return sVal.toFloat();
 }
 
 sal_Int32 SAL_CALL OResultSet::getInt(sal_Int32 column)
 {
     MutexGuard aGuard(m_aMutex);
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
-    char* pValue = m_aRow[column - 1];
-    if (!pValue)
-    {
-        m_bWasNull = true;
+    if (checkNull(column))
         return 0;
-    }
 
-    m_bWasNull = false;
-    return std::atoi(pValue);
+    OString sVal = m_aRows[m_nRowPosition][column - 1];
+    return sVal.toInt32();
 }
 
 sal_Int32 SAL_CALL OResultSet::getRow()
@@ -336,7 +359,7 @@ sal_Int32 SAL_CALL OResultSet::getRow()
     MutexGuard aGuard(m_aMutex);
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
 
-    return m_nRowPosition;
+    return m_nRowPosition + 1; // indexed from 1
 }
 
 sal_Int64 SAL_CALL OResultSet::getLong(sal_Int32 column)
@@ -345,26 +368,17 @@ sal_Int64 SAL_CALL OResultSet::getLong(sal_Int32 column)
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
     checkColumnIndex(column);
     checkRowIndex();
-
-    char* pValue = m_aRow[column - 1];
-    if (!pValue)
-    {
-        m_bWasNull = true;
+    if (checkNull(column))
         return 0LL;
-    }
 
-    m_bWasNull = false;
-    return std::atol(pValue);
+    OString sVal = m_aRows[m_nRowPosition][column - 1];
+    return sVal.toInt64();
 }
 
 uno::Reference<XResultSetMetaData> SAL_CALL OResultSet::getMetaData()
 {
     MutexGuard aGuard(m_aMutex);
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
-    if (!m_xMetaData.is())
-    {
-        m_xMetaData = new OResultSetMetaData(m_rConnection, m_pResult);
-    }
     return m_xMetaData;
 }
 
@@ -432,15 +446,11 @@ sal_Int16 SAL_CALL OResultSet::getShort(sal_Int32 column)
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
     checkColumnIndex(column);
     checkRowIndex();
-
-    char* pValue = m_aRow[column - 1];
-    if (!pValue)
-    {
-        m_bWasNull = true;
+    if (checkNull(column))
         return 0;
-    }
-    m_bWasNull = false;
-    return std::atoi(pValue);
+
+    OString sVal = m_aRows[m_nRowPosition][column - 1];
+    return sVal.toInt32();
 }
 
 OUString SAL_CALL OResultSet::getString(sal_Int32 column)
@@ -449,15 +459,11 @@ OUString SAL_CALL OResultSet::getString(sal_Int32 column)
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
     checkColumnIndex(column);
     checkRowIndex();
+    if (checkNull(column))
+        return rtl::OUString{};
 
-    char* pValue = m_aRow[column - 1];
-    if (!pValue)
-    {
-        m_bWasNull = true;
-        return OUString{};
-    }
-    m_bWasNull = false;
-    return OUString(pValue, static_cast<sal_Int32>(m_aLengths[column - 1]), m_encoding);
+    OString sVal = m_aRows[m_nRowPosition][column - 1];
+    return OStringToOUString(sVal, m_encoding);
 }
 
 Time SAL_CALL OResultSet::getTime(sal_Int32 column)
@@ -467,15 +473,13 @@ Time SAL_CALL OResultSet::getTime(sal_Int32 column)
 
     checkColumnIndex(column);
     checkRowIndex();
-    Time t; // initialize
-    char* pValue = m_aRow[column - 1];
-    if (!pValue)
-    {
-        m_bWasNull = true;
+    Time t;
+    if (checkNull(column))
         return t;
-    }
-    OUString timeString{ pValue, static_cast<sal_Int32>(m_aLengths[column - 1]), m_encoding };
-    OUString token;
+
+    OString sVal = m_aRows[m_nRowPosition][column - 1];
+    OString timeString{ sVal.getStr(), getDataLength(column - 1) };
+    OString token;
     sal_Int32 nIndex, i = 0;
 
     nIndex = timeString.indexOf(' ') + 1;
@@ -497,7 +501,6 @@ Time SAL_CALL OResultSet::getTime(sal_Int32 column)
         i++;
     } while (nIndex >= 0);
 
-    m_bWasNull = false;
     return t;
 }
 
@@ -508,19 +511,17 @@ DateTime SAL_CALL OResultSet::getTimestamp(sal_Int32 column)
     checkColumnIndex(column);
     checkRowIndex();
 
-    char* pValue = m_aRow[column - 1];
-    if (!pValue)
-    {
-        m_bWasNull = true;
-        return DateTime{}; // init
-    }
+    if (checkNull(column))
+        return DateTime{};
+
+    OString sVal = m_aRows[m_nRowPosition][column - 1];
 
     // YY-MM-DD HH:MM:SS
-    std::vector<OUString> dateAndTime = lcl_split(
-        OUString{ pValue, static_cast<sal_Int32>(m_aLengths[column - 1]), m_encoding }, u' ');
+    std::vector<OString> dateAndTime
+        = lcl_split(OString{ sVal.getStr(), getDataLength(column - 1) }, ' ');
 
-    auto dateParts = lcl_split(dateAndTime.at(0), u'-');
-    auto timeParts = lcl_split(dateAndTime.at(1), u':');
+    auto dateParts = lcl_split(dateAndTime.at(0), '-');
+    auto timeParts = lcl_split(dateAndTime.at(1), ':');
 
     DateTime dt;
 
@@ -530,7 +531,6 @@ DateTime SAL_CALL OResultSet::getTimestamp(sal_Int32 column)
     dt.Hours = timeParts.at(0).toUInt32();
     dt.Minutes = timeParts.at(1).toUInt32();
     dt.Seconds = timeParts.at(2).toUInt32();
-    m_bWasNull = false;
     return dt;
 }
 
@@ -539,7 +539,7 @@ sal_Bool SAL_CALL OResultSet::isBeforeFirst()
     MutexGuard aGuard(m_aMutex);
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
 
-    return m_nRowPosition == 0;
+    return m_nRowPosition < 0;
 }
 
 sal_Bool SAL_CALL OResultSet::isAfterLast()
@@ -547,7 +547,7 @@ sal_Bool SAL_CALL OResultSet::isAfterLast()
     MutexGuard aGuard(m_aMutex);
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
 
-    return m_nRowPosition > m_nRowCount;
+    return m_nRowPosition >= m_nRowCount;
 }
 
 sal_Bool SAL_CALL OResultSet::isFirst()
@@ -555,7 +555,7 @@ sal_Bool SAL_CALL OResultSet::isFirst()
     MutexGuard aGuard(m_aMutex);
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
 
-    return m_nRowPosition == 1 && !isAfterLast();
+    return m_nRowPosition == 0 && !isAfterLast();
 }
 
 sal_Bool SAL_CALL OResultSet::isLast()
@@ -563,23 +563,21 @@ sal_Bool SAL_CALL OResultSet::isLast()
     MutexGuard aGuard(m_aMutex);
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
 
-    return m_nRowPosition == m_nRowCount;
+    return m_nRowPosition == m_nRowCount - 1;
 }
 
 void SAL_CALL OResultSet::beforeFirst()
 {
     MutexGuard aGuard(m_aMutex);
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
-    mysql_data_seek(m_pResult, 0);
-    m_nRowPosition = 0;
+    m_nRowPosition = -1;
 }
 
 void SAL_CALL OResultSet::afterLast()
 {
     MutexGuard aGuard(m_aMutex);
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
-    mysql_data_seek(m_pResult, m_nRowCount + 1);
-    m_nRowPosition = m_nRowCount + 1;
+    m_nRowPosition = m_nRowCount;
 }
 
 void SAL_CALL OResultSet::close()
@@ -587,7 +585,6 @@ void SAL_CALL OResultSet::close()
     MutexGuard aGuard(m_aMutex);
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
 
-    mysql_free_result(m_pResult);
     m_pResult = nullptr;
     dispose();
 }
@@ -596,10 +593,7 @@ sal_Bool SAL_CALL OResultSet::first()
 {
     MutexGuard aGuard(m_aMutex);
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
-
-    mysql_data_seek(m_pResult, 0);
     m_nRowPosition = 0;
-    next();
 
     return true;
 }
@@ -608,10 +602,7 @@ sal_Bool SAL_CALL OResultSet::last()
 {
     MutexGuard aGuard(m_aMutex);
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
-
-    mysql_data_seek(m_pResult, m_nRowCount - 1);
     m_nRowPosition = m_nRowCount - 1;
-    next();
 
     return true;
 }
@@ -621,7 +612,7 @@ sal_Bool SAL_CALL OResultSet::absolute(sal_Int32 row)
     MutexGuard aGuard(m_aMutex);
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
 
-    sal_Int32 nToGo = row < 0 ? m_nRowCount - row : row - 1;
+    sal_Int32 nToGo = row < 0 ? (m_nRowCount - 1) - row : row - 1;
 
     if (nToGo >= m_nRowCount)
         nToGo = m_nRowCount - 1;
@@ -629,8 +620,6 @@ sal_Bool SAL_CALL OResultSet::absolute(sal_Int32 row)
         nToGo = 0;
 
     m_nRowPosition = nToGo;
-    mysql_data_seek(m_pResult, nToGo);
-    next();
 
     return true;
 }
@@ -650,8 +639,6 @@ sal_Bool SAL_CALL OResultSet::relative(sal_Int32 row)
         nToGo = 0;
 
     m_nRowPosition = nToGo;
-    mysql_data_seek(m_pResult, nToGo);
-    next();
 
     return true;
 }
@@ -661,12 +648,10 @@ sal_Bool SAL_CALL OResultSet::previous()
     MutexGuard aGuard(m_aMutex);
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
 
-    if (m_nRowPosition <= 1)
+    if (m_nRowPosition <= 0)
         return false;
 
-    m_nRowPosition -= 2;
-    mysql_data_seek(m_pResult, m_nRowPosition);
-    next();
+    m_nRowPosition--;
     return true;
 }
 
@@ -706,17 +691,11 @@ sal_Bool SAL_CALL OResultSet::next()
 {
     MutexGuard aGuard(m_aMutex);
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
-
-    m_aRow = mysql_fetch_row(m_pResult);
-    m_aLengths = mysql_fetch_lengths(m_pResult);
-
-    unsigned errorNum = mysql_errno(m_pMysql);
-    if (errorNum)
-        mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(m_pMysql), errorNum, *this,
-                                                     m_encoding);
+    ensureResultFetched();
+    if (m_nRowPosition >= m_nRowCount)
+        return false;
     ++m_nRowPosition;
-
-    return m_aRow != nullptr;
+    return true;
 }
 
 sal_Bool SAL_CALL OResultSet::wasNull()
@@ -1108,7 +1087,7 @@ css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL OResultSet::getProper
 
 void OResultSet::checkColumnIndex(sal_Int32 index)
 {
-    if (index < 1 || index > static_cast<int>(fieldCount))
+    if (index < 1 || index > static_cast<int>(m_nFieldCount))
     {
         /* static object for efficiency or thread safety is a problem ? */
         throw SQLException("index out of range", *this, OUString(), 1, Any());
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx b/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx
index ce9f7bd61db8..3241420aa3f6 100644
--- a/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx
+++ b/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx
@@ -63,16 +63,29 @@ class OResultSet final : public OBase_Mutex,
                          public OPropertyArrayUsageHelper<OResultSet>
 {
     OConnection& m_rConnection;
-    MYSQL_ROW m_aRow;
-    unsigned long* m_aLengths = nullptr;
+
+    using DataFields = std::vector<OString>;
+    std::vector<DataFields> m_aRows;
+    std::vector<MYSQL_FIELD> m_aFields;
     MYSQL* m_pMysql = nullptr;
     css::uno::WeakReferenceHelper m_aStatement;
     css::uno::Reference<css::sdbc::XResultSetMetaData> m_xMetaData;
     MYSQL_RES* m_pResult;
-    unsigned int fieldCount;
+    unsigned int m_nFieldCount = 0;
     rtl_TextEncoding m_encoding;
     bool m_bWasNull = false; // did the last getXXX result null?
-    sal_Int32 m_nRowPosition = 0;
+    bool m_bResultFetched = false;
+
+    sal_Int32 getDataLength(sal_Int32 column)
+    {
+        return m_aRows[m_nRowCount][column - 1].getLength();
+    }
+    bool checkNull(sal_Int32 column);
+
+    /**
+     * Position of cursor indexed from 0
+     */
+    sal_Int32 m_nRowPosition = -1;
     sal_Int32 m_nRowCount = 0;
 
     // OPropertyArrayUsageHelper
@@ -87,9 +100,11 @@ class OResultSet final : public OBase_Mutex,
 
     void SAL_CALL getFastPropertyValue(Any& rValue, sal_Int32 nHandle) const override;
 
-    // you can't delete objects of this type
     virtual ~OResultSet() override = default;
 
+    void ensureResultFetched();
+    void fetchResult();
+
 public:
     virtual OUString SAL_CALL getImplementationName() override;
 


More information about the Libreoffice-commits mailing list