connectivity/qa/connectivity/mysql/mysql.cxx | 41 ++ connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx | 172 +++++----- connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx | 7 connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx | 82 ++-- connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx | 22 + 5 files changed, 199 insertions(+), 125 deletions(-)
New commits: commit ea97f1e39015e36958374157e98b120bec47cb69 Author: Tamas Bunth <tamas.bu...@collabora.co.uk> AuthorDate: Mon Jul 29 13:27:38 2019 +0200 Commit: Tamás Bunth <btom...@gmail.com> CommitDate: Tue Aug 6 16:25:12 2019 +0200 mysqlc: Fix query of cursor position in result set Fix queries like "IsAfterLast" in result sets of prepared statements in the mysql driver. Cursor position is stored in the driver, since the mysql C driver does not support the query of the cursor position. The cursor position works the following way: - 0 means the cursor is on "BeforeFirst". In that state calling of getXXX() methods is user error. - 1 means the first row is already fetched. - n means the last fow is fetched, where n is the total number of rows in the result set. - Everything bigger than n is "AfterLast" Change-Id: I131f2042606897019cc0f868dbc4151faf4850ac Reviewed-on: https://gerrit.libreoffice.org/76549 Tested-by: Jenkins Reviewed-by: Tamás Bunth <btom...@gmail.com> Reviewed-on: https://gerrit.libreoffice.org/76583 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-on: https://gerrit.libreoffice.org/76870 diff --git a/connectivity/qa/connectivity/mysql/mysql.cxx b/connectivity/qa/connectivity/mysql/mysql.cxx index 546e916bd0a7..a3d88c065219 100644 --- a/connectivity/qa/connectivity/mysql/mysql.cxx +++ b/connectivity/qa/connectivity/mysql/mysql.cxx @@ -53,6 +53,7 @@ public: void testDBMetaData(); void testTimestampField(); void testNumericConversionPrepared(); + void testPreparedStmtIsAfterLast(); CPPUNIT_TEST_SUITE(MysqlTestDriver); CPPUNIT_TEST(testDBConnection); @@ -62,6 +63,7 @@ public: CPPUNIT_TEST(testDBMetaData); CPPUNIT_TEST(testTimestampField); CPPUNIT_TEST(testNumericConversionPrepared); + CPPUNIT_TEST(testPreparedStmtIsAfterLast); CPPUNIT_TEST_SUITE_END(); }; @@ -390,6 +392,45 @@ void MysqlTestDriver::testNumericConversionPrepared() xStatement->executeUpdate("DROP TABLE myTestTable"); } +/** + * Test cursor positioning method isAfterLast in case of using prepared + * statement. + */ +void MysqlTestDriver::testPreparedStmtIsAfterLast() +{ + Reference<XConnection> xConnection = m_xDriver->connect(m_sUrl, m_infos); + if (!xConnection.is()) + CPPUNIT_ASSERT_MESSAGE("cannot connect to data source!", xConnection.is()); + uno::Reference<XStatement> xStatement = xConnection->createStatement(); + CPPUNIT_ASSERT(xStatement.is()); + xStatement->executeUpdate("DROP TABLE IF EXISTS myTestTable"); + + // create test table + xStatement->executeUpdate("CREATE TABLE myTestTable (id INTEGER PRIMARY KEY)"); + Reference<XPreparedStatement> xPrepared + = xConnection->prepareStatement(OUString{ "INSERT INTO myTestTable VALUES (?)" }); + Reference<XParameters> xParams(xPrepared, UNO_QUERY); + constexpr int ROW_COUNT = 6; + for (int i = 0; i < ROW_COUNT; ++i) + { + xParams->setShort(1, i); + xPrepared->executeUpdate(); + } + + // query test table + xPrepared = xConnection->prepareStatement("SELECT id from myTestTable where id = 3"); + Reference<XResultSet> xResultSet = xPrepared->executeQuery(); + + // There should be exactly one row, therefore IsAfterLast is false at first. + xResultSet->next(); + CPPUNIT_ASSERT(!xResultSet->isAfterLast()); + + // attempt to fetch more data + bool hasData = xResultSet->next(); + CPPUNIT_ASSERT(!hasData); // now we are on "AfterLast" + CPPUNIT_ASSERT(xResultSet->isAfterLast()); +} + CPPUNIT_TEST_SUITE_REGISTRATION(MysqlTestDriver); CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx index ead866968ead..3d69eb5d2248 100644 --- a/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx +++ b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.cxx @@ -100,6 +100,62 @@ const std::type_index getTypeFromMysqlType(enum_field_types type) } } +bool OPreparedResultSet::fetchResult() +{ + // allocate array if it does not exist + if (m_aData == nullptr) + { + m_aData.reset(new MYSQL_BIND[m_nColumnCount]); + memset(m_aData.get(), 0, m_nColumnCount * sizeof(MYSQL_BIND)); + m_aMetaData.reset(new BindMetaData[m_nColumnCount]); + } + for (sal_Int32 i = 0; i < m_nColumnCount; ++i) + { + m_aMetaData[i].is_null = 0; + m_aMetaData[i].length = 0l; + m_aMetaData[i].error = 0; + + m_aData[i].is_null = &m_aMetaData[i].is_null; + m_aData[i].buffer_length = m_aFields[i].type == MYSQL_TYPE_BLOB ? 0 : m_aFields[i].length; + m_aData[i].length = &m_aMetaData[i].length; + m_aData[i].error = &m_aMetaData[i].error; + m_aData[i].buffer = nullptr; + m_aData[i].buffer_type = m_aFields[i].type; + + // allocates memory, if it is a fixed size type. If not then nullptr + mysqlc_sdbc_driver::allocateSqlVar(&m_aData[i].buffer, m_aData[i].buffer_type, + m_aFields[i].length); + } + mysql_stmt_bind_result(m_pStmt, m_aData.get()); + int failure = mysql_stmt_fetch(m_pStmt); + + for (sal_Int32 i = 0; i < m_nColumnCount; ++i) + { + if (*m_aData[i].error) + { + // expected if we have a BLOB, as buffer_length is set to 0. We want to + // fetch it piece by piece + // see https://bugs.mysql.com/file.php?id=12361&bug_id=33086 + if (m_aData[i].buffer == nullptr) + { + m_aData[i].buffer_length = *m_aData[i].length; + m_aData[i].buffer = malloc(*m_aData[i].length); + mysql_stmt_fetch_column(m_pStmt, &m_aData[i], i, 0); + } + } + } + + if (failure == 1) + { + MYSQL* pMysql = m_rConnection.getMysqlConnection(); + mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(pMysql), mysql_errno(pMysql), + *this, m_encoding); + } + else if (failure == MYSQL_NO_DATA) + return false; + return true; +} + OUString SAL_CALL OPreparedResultSet::getImplementationName() { return OUString("com.sun.star.sdbcx.mysqlc.ResultSet"); @@ -126,9 +182,12 @@ OPreparedResultSet::OPreparedResultSet(OConnection& rConn, OPreparedStatement* p , m_pStmt(pStmt) , m_encoding(rConn.getConnectionEncoding()) { - m_nFieldCount = mysql_stmt_field_count(pStmt); + m_nColumnCount = mysql_stmt_field_count(pStmt); m_pResult = mysql_stmt_result_metadata(m_pStmt); + if (m_pResult != nullptr) + mysql_stmt_store_result(m_pStmt); m_aFields = mysql_fetch_fields(m_pResult); + m_nRowCount = mysql_stmt_num_rows(pStmt); } void OPreparedResultSet::disposing() @@ -166,7 +225,7 @@ sal_Int32 SAL_CALL OPreparedResultSet::findColumn(const OUString& columnName) checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); MYSQL_FIELD* pFields = mysql_fetch_fields(m_pResult); - for (sal_Int32 i = 0; i < m_nFieldCount; ++i) + for (sal_Int32 i = 0; i < m_nColumnCount; ++i) { if (columnName.equalsIgnoreAsciiCaseAscii(pFields[i].name)) return i + 1; // sdbc indexes from 1 @@ -199,7 +258,10 @@ template <typename T> T OPreparedResultSet::retrieveValue(sal_Int32 nColumnIndex return getRowSetValue(nColumnIndex); } -namespace connectivity { namespace mysqlc { +namespace connectivity +{ +namespace mysqlc +{ template <> uno::Sequence<sal_Int8> OPreparedResultSet::retrieveValue(sal_Int32 column) { // TODO make conversion possible @@ -258,7 +320,8 @@ template <> OUString OPreparedResultSet::retrieveValue(sal_Int32 column) OUString sReturn = OUString(sStr, *m_aData[column - 1].length, m_encoding); return sReturn; } -}} +} +} ORowSetValue OPreparedResultSet::getRowSetValue(sal_Int32 nColumnIndex) { @@ -447,7 +510,7 @@ sal_Bool SAL_CALL OPreparedResultSet::isBeforeFirst() MutexGuard aGuard(m_aMutex); checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); - return m_nCurrentField == 0; + return m_nCurrentRow == 0; } sal_Bool SAL_CALL OPreparedResultSet::isAfterLast() @@ -455,7 +518,7 @@ sal_Bool SAL_CALL OPreparedResultSet::isAfterLast() MutexGuard aGuard(m_aMutex); checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); - return m_nCurrentField >= m_nFieldCount; + return m_nCurrentRow > m_nRowCount; } sal_Bool SAL_CALL OPreparedResultSet::isFirst() @@ -463,7 +526,7 @@ sal_Bool SAL_CALL OPreparedResultSet::isFirst() MutexGuard aGuard(m_aMutex); checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); - return m_nCurrentField == 1 && !isAfterLast(); + return m_nCurrentRow == 1 && !isAfterLast(); } sal_Bool SAL_CALL OPreparedResultSet::isLast() @@ -471,16 +534,17 @@ sal_Bool SAL_CALL OPreparedResultSet::isLast() MutexGuard aGuard(m_aMutex); checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); - return mysql_field_tell(m_pResult) == static_cast<unsigned>(m_nFieldCount); + return m_nCurrentRow == m_nRowCount; } void SAL_CALL OPreparedResultSet::beforeFirst() { MutexGuard aGuard(m_aMutex); checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); + mysql_stmt_data_seek(m_pStmt, 0); - mysqlc_sdbc_driver::throwFeatureNotImplementedException("OPreparedResultSet::beforeFirst", - *this); + m_nCurrentRow = 0; + m_aData.reset(); } void SAL_CALL OPreparedResultSet::afterLast() @@ -511,6 +575,7 @@ sal_Bool SAL_CALL OPreparedResultSet::first() checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); mysql_stmt_data_seek(m_pStmt, 0); + m_nCurrentRow = 0; next(); return true; @@ -521,7 +586,7 @@ sal_Bool SAL_CALL OPreparedResultSet::last() MutexGuard aGuard(m_aMutex); checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); - mysql_stmt_data_seek(m_pStmt, m_nFieldCount - 1); + mysql_stmt_data_seek(m_pStmt, m_nRowCount - 1); next(); return true; @@ -532,11 +597,10 @@ sal_Bool SAL_CALL OPreparedResultSet::absolute(sal_Int32 row) MutexGuard aGuard(m_aMutex); checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); - sal_Int32 nFields = m_nFieldCount; - sal_Int32 nToGo = row < 0 ? nFields - row : row - 1; + sal_Int32 nToGo = row < 0 ? m_nRowCount - row : row - 1; - if (nToGo >= nFields) - nToGo = nFields - 1; + if (nToGo >= m_nRowCount) + nToGo = m_nRowCount - 1; if (nToGo < 0) nToGo = 0; @@ -551,19 +615,18 @@ sal_Bool SAL_CALL OPreparedResultSet::relative(sal_Int32 row) MutexGuard aGuard(m_aMutex); checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); - sal_Int32 nFields = m_nFieldCount; if (row == 0) return true; - sal_Int32 nToGo = m_nCurrentField + row; - if (nToGo >= nFields) - nToGo = nFields - 1; + sal_Int32 nToGo = m_nCurrentRow + row; + if (nToGo >= m_nRowCount) + nToGo = m_nRowCount - 1; if (nToGo < 0) nToGo = 0; mysql_stmt_data_seek(m_pStmt, nToGo); next(); - m_nCurrentField += row; + m_nCurrentRow += row; return true; } @@ -573,12 +636,12 @@ sal_Bool SAL_CALL OPreparedResultSet::previous() MutexGuard aGuard(m_aMutex); checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); - if (m_nCurrentField <= 1) + if (m_nCurrentRow <= 1) return false; - mysql_stmt_data_seek(m_pStmt, m_nCurrentField - 2); + mysql_stmt_data_seek(m_pStmt, m_nCurrentRow - 2); next(); - --m_nFieldCount; + --m_nCurrentRow; return true; } @@ -618,68 +681,13 @@ sal_Bool SAL_CALL OPreparedResultSet::next() { MutexGuard aGuard(m_aMutex); checkDisposed(OPreparedResultSet_BASE::rBHelper.bDisposed); - - bool bFirstRun = false; - // allocate array if it does not exist - if (m_aData == nullptr) - { - bFirstRun = true; - m_aData.reset(new MYSQL_BIND[m_nFieldCount]); - memset(m_aData.get(), 0, m_nFieldCount * sizeof(MYSQL_BIND)); - m_aMetaData.reset(new BindMetaData[m_nFieldCount]); - } - for (sal_Int32 i = 0; i < m_nFieldCount; ++i) - { - m_aMetaData[i].is_null = 0; - m_aMetaData[i].length = 0l; - m_aMetaData[i].error = 0; - - m_aData[i].is_null = &m_aMetaData[i].is_null; - m_aData[i].buffer_length = m_aFields[i].type == MYSQL_TYPE_BLOB ? 0 : m_aFields[i].length; - m_aData[i].length = &m_aMetaData[i].length; - m_aData[i].error = &m_aMetaData[i].error; - m_aData[i].buffer = nullptr; - m_aData[i].buffer_type = m_aFields[i].type; - - // allocates memory, if it is a fixed size type. If not then nullptr - mysqlc_sdbc_driver::allocateSqlVar(&m_aData[i].buffer, m_aData[i].buffer_type, - m_aFields[i].length); - } - mysql_stmt_bind_result(m_pStmt, m_aData.get()); - if (bFirstRun) - mysql_stmt_store_result(m_pStmt); - int failure = mysql_stmt_fetch(m_pStmt); - - for (sal_Int32 i = 0; i < m_nFieldCount; ++i) - { - if (*m_aData[i].error) - { - // expected if we have a BLOB, as buffer_length is set to 0. We want to - // fetch it piece by piece - // see https://bugs.mysql.com/file.php?id=12361&bug_id=33086 - if (m_aData[i].buffer == nullptr) - { - m_aData[i].buffer_length = *m_aData[i].length; - m_aData[i].buffer = malloc(*m_aData[i].length); - mysql_stmt_fetch_column(m_pStmt, &m_aData[i], i, 0); - } - } - } - - if (failure == 1) - { - MYSQL* pMysql = m_rConnection.getMysqlConnection(); - mysqlc_sdbc_driver::throwSQLExceptionWithMsg(mysql_error(pMysql), mysql_errno(pMysql), - *this, m_encoding); - } - else if (failure == MYSQL_NO_DATA) - return false; + bool hasData = fetchResult(); // current field cannot be asked as a number. We have to keep track it // manually. - m_nCurrentField += 1; + m_nCurrentRow += 1; - return true; + return hasData; } sal_Bool SAL_CALL OPreparedResultSet::wasNull() @@ -1080,7 +1088,7 @@ void OPreparedResultSet::checkColumnIndex(sal_Int32 index) { if (!m_aData) throw SQLException("Cursor out of range", *this, OUString(), 1, Any()); - if (index < 1 || index > static_cast<int>(m_nFieldCount)) + if (index < 1 || index > static_cast<int>(m_nColumnCount)) { /* 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_prepared_resultset.hxx b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx index d10c8df5dacd..4a9c26fcfdd3 100644 --- a/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx +++ b/connectivity/source/drivers/mysqlc/mysqlc_prepared_resultset.hxx @@ -70,8 +70,9 @@ class OPreparedResultSet final : public OBase_Mutex, MYSQL_FIELD* m_aFields; rtl_TextEncoding m_encoding; - sal_Int32 m_nCurrentField = 0; - sal_Int32 m_nFieldCount; + sal_Int32 m_nCurrentRow = 0; + sal_Int32 m_nColumnCount; + sal_Int32 m_nRowCount; // Use c style arrays, because we have to work with pointers // on these. @@ -96,6 +97,8 @@ class OPreparedResultSet final : public OBase_Mutex, template <typename T> T retrieveValue(sal_Int32 nColumnIndex); connectivity::ORowSetValue getRowSetValue(sal_Int32 nColumnIndex); + bool fetchResult(); + // you can't delete objects of this type virtual ~OPreparedResultSet() override = default; commit c6f6b70450a86816a0d08b8c69b1f54830fa7c86 Author: Tamas Bunth <tamas.bu...@collabora.co.uk> AuthorDate: Tue Jan 15 17:53:51 2019 +0100 Commit: Tamás Bunth <btom...@gmail.com> CommitDate: Tue Aug 6 16:25:02 2019 +0200 mysqlc: fetch data exactly when it's needed It fixes the issue that one could not call getXXX on a result set on which next() method was never called before. Change-Id: I972bb9d475d192a14ba1534dcbdac81c20f211d0 Reviewed-on: https://gerrit.libreoffice.org/66431 Reviewed-by: Andras Timar <andras.ti...@collabora.com> Tested-by: Andras Timar <andras.ti...@collabora.com> Reviewed-on: https://gerrit.libreoffice.org/76728 Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoff...@gmail.com> Reviewed-by: Tamás Bunth <btom...@gmail.com> diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx b/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx index 6fb5f1e3ee61..05d5c1321604 100644 --- a/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx +++ b/connectivity/source/drivers/mysqlc/mysqlc_resultset.cxx @@ -136,6 +136,13 @@ void OResultSet::ensureResultFetched() void OResultSet::ensureFieldInfoFetched() { + if (m_bResultFetched) + return; // already fetched + + // it works only if result set is produced via mysql_store_result + // TODO ensure that + m_nRowCount = mysql_num_rows(m_pResult); + if (!m_aFields.empty()) return; unsigned nFieldCount = mysql_num_fields(m_pResult); @@ -150,11 +157,6 @@ 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(m_pResult); - ensureFieldInfoFetched(); // fetch all the data @@ -228,8 +230,7 @@ uno::Reference<XInputStream> SAL_CALL OResultSet::getBinaryStream(sal_Int32 colu { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - checkColumnIndex(column); - checkRowIndex(); + checkBordersAndEnsureFetched(column); if (checkNull(column)) return nullptr; @@ -242,8 +243,7 @@ uno::Reference<XInputStream> SAL_CALL OResultSet::getCharacterStream(sal_Int32 c { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - checkColumnIndex(column); - checkRowIndex(); + checkBordersAndEnsureFetched(column); mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getCharacterStream", *this); return nullptr; @@ -253,8 +253,7 @@ sal_Bool SAL_CALL OResultSet::getBoolean(sal_Int32 column) { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - checkColumnIndex(column); - checkRowIndex(); + checkBordersAndEnsureFetched(column); if (checkNull(column)) return false; @@ -266,8 +265,7 @@ sal_Int8 SAL_CALL OResultSet::getByte(sal_Int32 column) { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - checkColumnIndex(column); - checkRowIndex(); + checkBordersAndEnsureFetched(column); if (checkNull(column)) return 0; @@ -280,6 +278,7 @@ uno::Sequence<sal_Int8> SAL_CALL OResultSet::getBytes(sal_Int32 column) { checkDisposed(OResultSet_BASE::rBHelper.bDisposed); MutexGuard aGuard(m_aMutex); + checkBordersAndEnsureFetched(column); OString sVal = m_aRows[m_nRowPosition][column - 1]; if (checkNull(column)) return uno::Sequence<sal_Int8>(); @@ -292,8 +291,7 @@ Date SAL_CALL OResultSet::getDate(sal_Int32 column) { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - checkColumnIndex(column); - checkRowIndex(); + checkBordersAndEnsureFetched(column); Date d; @@ -330,8 +328,7 @@ double SAL_CALL OResultSet::getDouble(sal_Int32 column) { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - checkColumnIndex(column); - checkRowIndex(); + checkBordersAndEnsureFetched(column); if (checkNull(column)) return 0.0; @@ -344,8 +341,7 @@ float SAL_CALL OResultSet::getFloat(sal_Int32 column) { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - checkColumnIndex(column); - checkRowIndex(); + checkBordersAndEnsureFetched(column); if (checkNull(column)) return 0.0f; @@ -357,6 +353,7 @@ sal_Int32 SAL_CALL OResultSet::getInt(sal_Int32 column) { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + checkBordersAndEnsureFetched(column); if (checkNull(column)) return 0; @@ -376,8 +373,7 @@ sal_Int64 SAL_CALL OResultSet::getLong(sal_Int32 column) { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - checkColumnIndex(column); - checkRowIndex(); + checkBordersAndEnsureFetched(column); if (checkNull(column)) return 0LL; @@ -396,8 +392,7 @@ uno::Reference<XArray> SAL_CALL OResultSet::getArray(sal_Int32 column) { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - checkColumnIndex(column); - checkRowIndex(); + checkBordersAndEnsureFetched(column); mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getArray", *this); return nullptr; @@ -407,8 +402,7 @@ uno::Reference<XClob> SAL_CALL OResultSet::getClob(sal_Int32 column) { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - checkColumnIndex(column); - checkRowIndex(); + checkBordersAndEnsureFetched(column); mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getClob", *this); return nullptr; @@ -418,8 +412,7 @@ uno::Reference<XBlob> SAL_CALL OResultSet::getBlob(sal_Int32 column) { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - checkColumnIndex(column); - checkRowIndex(); + checkBordersAndEnsureFetched(column); mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getBlob", *this); return nullptr; @@ -429,8 +422,7 @@ uno::Reference<XRef> SAL_CALL OResultSet::getRef(sal_Int32 column) { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - checkColumnIndex(column); - checkRowIndex(); + checkBordersAndEnsureFetched(column); mysqlc_sdbc_driver::throwFeatureNotImplementedException("OResultSet::getRef", *this); return nullptr; @@ -441,8 +433,7 @@ Any SAL_CALL OResultSet::getObject(sal_Int32 column, { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - checkColumnIndex(column); - checkRowIndex(); + checkBordersAndEnsureFetched(column); Any aRet = Any(); @@ -454,8 +445,7 @@ sal_Int16 SAL_CALL OResultSet::getShort(sal_Int32 column) { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - checkColumnIndex(column); - checkRowIndex(); + checkBordersAndEnsureFetched(column); if (checkNull(column)) return 0; @@ -467,8 +457,7 @@ OUString SAL_CALL OResultSet::getString(sal_Int32 column) { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - checkColumnIndex(column); - checkRowIndex(); + checkBordersAndEnsureFetched(column); if (checkNull(column)) return rtl::OUString{}; @@ -480,9 +469,8 @@ Time SAL_CALL OResultSet::getTime(sal_Int32 column) { checkDisposed(OResultSet_BASE::rBHelper.bDisposed); MutexGuard aGuard(m_aMutex); + checkBordersAndEnsureFetched(column); - checkColumnIndex(column); - checkRowIndex(); Time t; if (checkNull(column)) return t; @@ -518,8 +506,7 @@ DateTime SAL_CALL OResultSet::getTimestamp(sal_Int32 column) { checkDisposed(OResultSet_BASE::rBHelper.bDisposed); MutexGuard aGuard(m_aMutex); - checkColumnIndex(column); - checkRowIndex(); + checkBordersAndEnsureFetched(column); if (checkNull(column)) return DateTime{}; @@ -559,6 +546,7 @@ sal_Bool SAL_CALL OResultSet::isAfterLast() { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); return m_nRowPosition >= m_nRowCount; } @@ -567,6 +555,7 @@ sal_Bool SAL_CALL OResultSet::isFirst() { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); return m_nRowPosition == 0 && !isAfterLast(); } @@ -575,6 +564,7 @@ sal_Bool SAL_CALL OResultSet::isLast() { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); return m_nRowPosition == m_nRowCount - 1; } @@ -590,6 +580,7 @@ void SAL_CALL OResultSet::afterLast() { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); m_nRowPosition = m_nRowCount; } @@ -615,7 +606,7 @@ sal_Bool SAL_CALL OResultSet::last() { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - ensureResultFetched(); + ensureFieldInfoFetched(); m_nRowPosition = m_nRowCount - 1; return true; @@ -625,6 +616,7 @@ sal_Bool SAL_CALL OResultSet::absolute(sal_Int32 row) { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); sal_Int32 nToGo = row < 0 ? (m_nRowCount - 1) - row : row - 1; @@ -642,6 +634,7 @@ sal_Bool SAL_CALL OResultSet::relative(sal_Int32 row) { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + ensureFieldInfoFetched(); if (row == 0) return true; @@ -712,7 +705,7 @@ sal_Bool SAL_CALL OResultSet::next() { MutexGuard aGuard(m_aMutex); checkDisposed(OResultSet_BASE::rBHelper.bDisposed); - ensureResultFetched(); + ensureFieldInfoFetched(); if (m_nRowPosition + 1 > m_nRowCount) // afterlast return false; if (m_nRowPosition + 1 == m_nRowCount) // last @@ -1121,4 +1114,11 @@ void OResultSet::checkColumnIndex(sal_Int32 index) } } +void OResultSet::checkBordersAndEnsureFetched(sal_Int32 index) +{ + ensureResultFetched(); + checkColumnIndex(index); + checkRowIndex(); +} + /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx b/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx index 34be3a2ca36c..6bc1feaec1b2 100644 --- a/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx +++ b/connectivity/source/drivers/mysqlc/mysqlc_resultset.hxx @@ -99,8 +99,30 @@ class OResultSet final : public OBase_Mutex, virtual ~OResultSet() override = default; + /** + * Ensures that the results of the query has already been fetched. + */ void ensureResultFetched(); + + /** + * Ensures that meta data of the corresponding result set has been already + * queried. It should be called before freeing the result set, unless the + * information is lost. + */ void ensureFieldInfoFetched(); + + /** + * Check the following things: + * - cursor is out of range. Throws expception if true. + * - column index is out of range. Throws exception if true. + * - result set is fetched. If no, then it fetches the result. + */ + void checkBordersAndEnsureFetched(sal_Int32 index); + + /** + * Fetches all the data from the MYSQL_RES object related to the class. It + * frees the MYSQL_RES object afterwards, so it cannot be used anymore. + */ void fetchResult(); public: _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits