summaryrefslogtreecommitdiff
path: root/connectivity
diff options
context:
space:
mode:
authorTamas Bunth <tamas.bunth@collabora.co.uk>2018-12-29 15:22:56 +0100
committerTamás Bunth <btomi96@gmail.com>2019-01-04 17:37:26 +0100
commitee33372f6406d7352bc7e19914ec5fb0059c4e01 (patch)
tree0ae19e7c40c58dcd925b5ed59241c121446561f7 /connectivity
parentf2ee532640fa200ada55ac51fbe47bad260aec7e (diff)
mysqlc: Fix result set metadata related issue
In order to allow fetching result of multiple result sets at time same time, all the data is fetched and copied on demand from the mysql result set. The mysql result set (MYSQL_RES) is freed afterwards. That means we need a copy of the meta information as well. Now all the meta data is stored in the driver for each result set, so it does not depend on the MYSQL_RES structure anymore. Also add test case for invoking some meta data queries before and after fetching the result set. Change-Id: Ie8bf993926ebe89cd362ab0b311d1f3d164b84df Reviewed-on: https://gerrit.libreoffice.org/65717 Tested-by: Jenkins Reviewed-by: Tamás Bunth <btomi96@gmail.com>
Diffstat (limited to 'connectivity')
-rw-r--r--connectivity/qa/connectivity/mysql/mysql.cxx42
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_general.cxx18
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_general.hxx4
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx99
-rw-r--r--connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx29
5 files changed, 124 insertions, 68 deletions
diff --git a/connectivity/qa/connectivity/mysql/mysql.cxx b/connectivity/qa/connectivity/mysql/mysql.cxx
index f93885fb34d9..0d1d9ef85145 100644
--- a/connectivity/qa/connectivity/mysql/mysql.cxx
+++ b/connectivity/qa/connectivity/mysql/mysql.cxx
@@ -13,7 +13,10 @@
#include <com/sun/star/sdbc/XColumnLocate.hpp>
#include <com/sun/star/sdbc/XConnection.hpp>
#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
#include <com/sun/star/sdbc/XParameters.hpp>
#include <com/sun/star/sdbc/XStatement.hpp>
#include <com/sun/star/sdbc/XDriver.hpp>
@@ -46,12 +49,14 @@ public:
void testIntegerInsertAndQuery();
void testDBPositionChange();
void testMultipleResultsets();
+ void testDBMetaData();
CPPUNIT_TEST_SUITE(MysqlTestDriver);
CPPUNIT_TEST(testDBConnection);
CPPUNIT_TEST(testCreateAndDropTable);
CPPUNIT_TEST(testIntegerInsertAndQuery);
CPPUNIT_TEST(testMultipleResultsets);
+ CPPUNIT_TEST(testDBMetaData);
CPPUNIT_TEST_SUITE_END();
};
@@ -289,6 +294,43 @@ void MysqlTestDriver::testMultipleResultsets()
xStatement->executeUpdate("DROP TABLE otherTable");
}
+void MysqlTestDriver::testDBMetaData()
+{
+ 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");
+
+ auto nUpdateCount = xStatement->executeUpdate(
+ "CREATE TABLE myTestTable (id INTEGER PRIMARY KEY, name VARCHAR(20))");
+ Reference<XPreparedStatement> xPrepared
+ = xConnection->prepareStatement(OUString{ "INSERT INTO myTestTable VALUES (?, ?)" });
+ Reference<XParameters> xParams(xPrepared, UNO_QUERY);
+ constexpr int ROW_COUNT = 3;
+ for (int i = 0; i < ROW_COUNT; ++i)
+ {
+ xParams->setLong(1, i);
+ xParams->setString(2, "lorem");
+ xPrepared->executeUpdate();
+ }
+
+ Reference<XResultSet> xResultSet = xStatement->executeQuery("SELECT * from myTestTable");
+ Reference<XResultSetMetaDataSupplier> xMetaDataSupplier(xResultSet, UNO_QUERY);
+ Reference<XResultSetMetaData> xMetaData = xMetaDataSupplier->getMetaData();
+ CPPUNIT_ASSERT_EQUAL(OUString{ "id" }, xMetaData->getColumnName(1));
+ CPPUNIT_ASSERT_EQUAL(OUString{ "name" }, xMetaData->getColumnName(2));
+ CPPUNIT_ASSERT(!xMetaData->isAutoIncrement(1));
+ CPPUNIT_ASSERT(!xMetaData->isCaseSensitive(2)); // default collation should be case insensitive
+ xResultSet->next(); // use it
+ // test that meta data is usable even after fetching result set
+ CPPUNIT_ASSERT_EQUAL(OUString{ "name" }, xMetaData->getColumnName(2));
+ CPPUNIT_ASSERT_THROW_MESSAGE("exception expected when indexing out of range",
+ xMetaData->getColumnName(3), sdbc::SQLException);
+ nUpdateCount = xStatement->executeUpdate("DROP TABLE myTestTable");
+}
+
CPPUNIT_TEST_SUITE_REGISTRATION(MysqlTestDriver);
CPPUNIT_PLUGIN_IMPLEMENT();
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_general.cxx b/connectivity/source/drivers/mysqlc/mysqlc_general.cxx
index aa0b0a9e4e5a..5827b4bd35b9 100644
--- a/connectivity/source/drivers/mysqlc/mysqlc_general.cxx
+++ b/connectivity/source/drivers/mysqlc/mysqlc_general.cxx
@@ -225,11 +225,13 @@ sal_Int32 mysqlStrToOOOType(const OUString& sType)
return css::sdbc::DataType::VARCHAR;
}
-OUString mysqlTypeToStr(MYSQL_FIELD* field)
+OUString mysqlTypeToStr(MYSQL_FIELD* field) { return mysqlTypeToStr(field->type, field->flags); }
+
+OUString mysqlTypeToStr(unsigned type, unsigned flags)
{
- bool isUnsigned = (field->flags & UNSIGNED_FLAG) != 0;
- bool isZerofill = (field->flags & ZEROFILL_FLAG) != 0;
- switch (field->type)
+ bool isUnsigned = (flags & UNSIGNED_FLAG) != 0;
+ bool isZerofill = (flags & ZEROFILL_FLAG) != 0;
+ switch (type)
{
case MYSQL_TYPE_BIT:
return OUString{ "BIT" };
@@ -294,21 +296,21 @@ OUString mysqlTypeToStr(MYSQL_FIELD* field)
}
case MYSQL_TYPE_VARCHAR:
case MYSQL_TYPE_VAR_STRING:
- if (field->flags & ENUM_FLAG)
+ if (flags & ENUM_FLAG)
{
return OUString{ "ENUM" };
}
- if (field->flags & SET_FLAG)
+ if (flags & SET_FLAG)
{
return OUString{ "SET" };
}
return OUString{ "VARCHAR" };
case MYSQL_TYPE_STRING:
- if (field->flags & ENUM_FLAG)
+ if (flags & ENUM_FLAG)
{
return OUString{ "ENUM" };
}
- if (field->flags & SET_FLAG)
+ if (flags & SET_FLAG)
{
return OUString{ "SET" };
}
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_general.hxx b/connectivity/source/drivers/mysqlc/mysqlc_general.hxx
index a7886c3015d2..f8d866964318 100644
--- a/connectivity/source/drivers/mysqlc/mysqlc_general.hxx
+++ b/connectivity/source/drivers/mysqlc/mysqlc_general.hxx
@@ -92,12 +92,10 @@ void resetSqlVar(void** target, T* pValue, enum_field_types type, sal_Int32 nSiz
void allocateSqlVar(void** mem, enum_field_types eType, unsigned nSize = 0);
-/// @throws css::sdbc::SQLException
void throwFeatureNotImplementedException(
const sal_Char* _pAsciiFeatureName,
const css::uno::Reference<css::uno::XInterface>& _rxContext);
-/// @throws css::sdbc::SQLException
void throwInvalidArgumentException(const sal_Char* _pAsciiFeatureName,
const css::uno::Reference<css::uno::XInterface>& _rxContext);
@@ -109,6 +107,8 @@ sal_Int32 mysqlToOOOType(int eType, int charsetnr) noexcept;
OUString mysqlTypeToStr(MYSQL_FIELD* pField);
+OUString mysqlTypeToStr(unsigned mysql_type, unsigned mysql_flags);
+
sal_Int32 mysqlStrToOOOType(const OUString& sType);
OUString convert(const ::std::string& _string, const rtl_TextEncoding encoding);
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx b/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx
index f5962a2a54ff..ba8c36da83ce 100644
--- a/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx
+++ b/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.cxx
@@ -23,41 +23,61 @@
#include <com/sun/star/sdbc/XRow.hpp>
#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
using namespace connectivity::mysqlc;
using namespace com::sun::star::uno;
using namespace com::sun::star::lang;
using namespace com::sun::star::sdbc;
-MYSQL_FIELD* OResultSetMetaData::getField(sal_Int32 column) const
+OResultSetMetaData::OResultSetMetaData(OConnection& rConn, MYSQL_RES* pResult)
+ : m_rConnection(rConn)
{
- return mysql_fetch_field_direct(m_pRes, column - 1);
+ MYSQL_FIELD* fields = mysql_fetch_field(pResult);
+ unsigned nFieldCount = mysql_num_fields(pResult);
+ for (unsigned i = 0; i < nFieldCount; ++i)
+ {
+ MySqlFieldInfo fieldInfo{
+ OUString{ fields[i].name, static_cast<sal_Int32>(fields[i].name_length),
+ m_rConnection.getConnectionEncoding() }, // column name
+ static_cast<sal_Int32>(fields[i].length), // length
+ mysqlc_sdbc_driver::mysqlToOOOType(fields[i].type, fields[i].charsetnr), // type
+ fields[i].type, // mysql_type
+ fields[i].charsetnr, // charset number
+ fields[i].flags,
+ OUString{ fields[i].db, static_cast<sal_Int32>(fields[i].db_length),
+ m_rConnection.getConnectionEncoding() }, // schema name
+ OUString{ fields[i].table, static_cast<sal_Int32>(fields[i].table_length),
+ m_rConnection.getConnectionEncoding() }, // table name
+ OUString{ fields[i].catalog, static_cast<sal_Int32>(fields[i].catalog_length),
+ m_rConnection.getConnectionEncoding() }, // catalog
+ static_cast<sal_Int32>(fields[i].decimals),
+ static_cast<sal_Int32>(fields[i].max_length)
+ };
+ m_fields.push_back(std::move(fieldInfo));
+ }
}
sal_Int32 SAL_CALL OResultSetMetaData::getColumnDisplaySize(sal_Int32 column)
{
- MYSQL_FIELD* pField = getField(column);
- return pField->length;
+ checkColumnIndex(column);
+ return m_fields.at(column - 1).length;
}
sal_Int32 SAL_CALL OResultSetMetaData::getColumnType(sal_Int32 column)
{
checkColumnIndex(column);
- MYSQL_FIELD* pField = getField(column);
-
- return mysqlc_sdbc_driver::mysqlToOOOType(pField->type, pField->charsetnr);
+ return m_fields.at(column - 1).type;
}
-sal_Int32 SAL_CALL OResultSetMetaData::getColumnCount() { return mysql_num_fields(m_pRes); }
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnCount() { return m_fields.size(); }
sal_Bool SAL_CALL OResultSetMetaData::isCaseSensitive(sal_Int32 column)
{
- checkColumnIndex(column);
// MYSQL_FIELD::charsetnr is the collation identifier
// _ci postfix means it's insensitive
- MYSQL_FIELD* pField = getField(column);
OUStringBuffer sql{ "SHOW COLLATION WHERE Id =" };
- sql.append(OUString::number(pField->charsetnr));
+ sql.append(OUString::number(m_fields.at(column - 1).charsetNumber));
Reference<XStatement> stmt = m_rConnection.createStatement();
Reference<XResultSet> rs = stmt->executeQuery(sql.makeStringAndClear());
@@ -74,54 +94,43 @@ sal_Bool SAL_CALL OResultSetMetaData::isCaseSensitive(sal_Int32 column)
OUString SAL_CALL OResultSetMetaData::getSchemaName(sal_Int32 column)
{
checkColumnIndex(column);
- MYSQL_FIELD* pField = getField(column);
-
- return OStringToOUString(pField->db, m_rConnection.getConnectionEncoding());
+ return m_fields.at(column - 1).schemaName;
}
OUString SAL_CALL OResultSetMetaData::getColumnName(sal_Int32 column)
{
checkColumnIndex(column);
-
- MYSQL_FIELD* pField = getField(column);
- return OStringToOUString(pField->name, m_rConnection.getConnectionEncoding());
+ return m_fields.at(column - 1).columnName;
}
OUString SAL_CALL OResultSetMetaData::getTableName(sal_Int32 column)
{
checkColumnIndex(column);
- MYSQL_FIELD* pField = getField(column);
- return OStringToOUString(pField->table, m_rConnection.getConnectionEncoding());
+ return m_fields.at(column - 1).tableName;
}
OUString SAL_CALL OResultSetMetaData::getCatalogName(sal_Int32 column)
{
checkColumnIndex(column);
- MYSQL_FIELD* pField = getField(column);
- return OStringToOUString(pField->catalog, m_rConnection.getConnectionEncoding());
+ return m_fields.at(column - 1).catalogName;
}
OUString SAL_CALL OResultSetMetaData::getColumnTypeName(sal_Int32 column)
{
checkColumnIndex(column);
- MYSQL_FIELD* pField = getField(column);
-
- return mysqlc_sdbc_driver::mysqlTypeToStr(pField);
+ return mysqlc_sdbc_driver::mysqlTypeToStr(m_fields.at(column - 1).mysql_type,
+ m_fields.at(column - 1).flags);
}
OUString SAL_CALL OResultSetMetaData::getColumnLabel(sal_Int32 column)
{
checkColumnIndex(column);
- MYSQL_FIELD* pField = getField(column);
- return OStringToOUString(pField->name, m_rConnection.getConnectionEncoding());
+ return getColumnName(column);
}
-OUString SAL_CALL OResultSetMetaData::getColumnServiceName(sal_Int32 column)
+OUString SAL_CALL OResultSetMetaData::getColumnServiceName(sal_Int32 /*column*/)
{
- checkColumnIndex(column);
-
- OUString aRet = OUString();
- return aRet;
+ return OUString{};
}
sal_Bool SAL_CALL OResultSetMetaData::isCurrency(sal_Int32 /*column*/)
@@ -132,47 +141,43 @@ sal_Bool SAL_CALL OResultSetMetaData::isCurrency(sal_Int32 /*column*/)
sal_Bool SAL_CALL OResultSetMetaData::isAutoIncrement(sal_Int32 column)
{
checkColumnIndex(column);
-
- MYSQL_FIELD* pField = getField(column);
- return (pField->flags & AUTO_INCREMENT_FLAG) != 0;
+ return (m_fields.at(column - 1).flags & AUTO_INCREMENT_FLAG) != 0;
}
sal_Bool SAL_CALL OResultSetMetaData::isSigned(sal_Int32 column)
{
checkColumnIndex(column);
-
- MYSQL_FIELD* pField = getField(column);
- return !(pField->flags & UNSIGNED_FLAG);
+ return !(m_fields.at(column - 1).flags & UNSIGNED_FLAG);
}
sal_Int32 SAL_CALL OResultSetMetaData::getPrecision(sal_Int32 column)
{
checkColumnIndex(column);
- MYSQL_FIELD* pField = getField(column);
- return pField->max_length - pField->decimals;
+ return m_fields.at(column - 1).max_length - m_fields.at(column - 1).decimals;
}
sal_Int32 SAL_CALL OResultSetMetaData::getScale(sal_Int32 column)
{
checkColumnIndex(column);
- MYSQL_FIELD* pField = getField(column);
- return pField->decimals;
+ return m_fields.at(column - 1).decimals;
}
sal_Int32 SAL_CALL OResultSetMetaData::isNullable(sal_Int32 column)
{
checkColumnIndex(column);
- MYSQL_FIELD* pField = getField(column);
- return (pField->flags & NOT_NULL_FLAG) ? 0 : 1;
+ return (m_fields.at(column - 1).flags & NOT_NULL_FLAG) ? 0 : 1;
}
-sal_Bool SAL_CALL OResultSetMetaData::isSearchable(sal_Int32 /*column*/) { return true; }
+sal_Bool SAL_CALL OResultSetMetaData::isSearchable(sal_Int32 column)
+{
+ checkColumnIndex(column);
+ return true;
+}
sal_Bool SAL_CALL OResultSetMetaData::isReadOnly(sal_Int32 column)
{
checkColumnIndex(column);
- MYSQL_FIELD* pField = getField(column);
- return !(pField->db && strlen(pField->db));
+ return m_fields.at(column - 1).schemaName.isEmpty();
}
sal_Bool SAL_CALL OResultSetMetaData::isDefinitelyWritable(sal_Int32 column)
@@ -189,7 +194,7 @@ sal_Bool SAL_CALL OResultSetMetaData::isWritable(sal_Int32 column)
void OResultSetMetaData::checkColumnIndex(sal_Int32 columnIndex)
{
- unsigned nColCount = mysql_num_fields(m_pRes);
+ auto nColCount = m_fields.size();
if (columnIndex < 1 || columnIndex > static_cast<sal_Int32>(nColCount))
{
OUStringBuffer buf;
diff --git a/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx b/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx
index 346695def388..a7de887bd78d 100644
--- a/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx
+++ b/connectivity/source/drivers/mysqlc/mysqlc_resultsetmetadata.hxx
@@ -37,6 +37,21 @@ using ::com::sun::star::sdbc::SQLException;
using ::com::sun::star::uno::RuntimeException;
using ::com::sun::star::uno::RuntimeException;
+struct MySqlFieldInfo
+{
+ OUString columnName;
+ sal_Int32 length = 0;
+ sal_Int32 type = 0;
+ unsigned mysql_type = 0;
+ unsigned charsetNumber = 0;
+ unsigned flags = 0;
+ OUString schemaName;
+ OUString tableName;
+ OUString catalogName;
+ sal_Int32 decimals;
+ sal_Int32 max_length;
+};
+
//************ Class: ResultSetMetaData
typedef ::cppu::WeakImplHelper1<css::sdbc::XResultSetMetaData> OResultSetMetaData_BASE;
@@ -45,17 +60,13 @@ class OResultSetMetaData final : public OResultSetMetaData_BASE
{
private:
OConnection& m_rConnection;
- MYSQL_RES* m_pRes;
+ std::vector<MySqlFieldInfo> m_fields;
+ void checkColumnIndex(sal_Int32 columnIndex);
virtual ~OResultSetMetaData() override = default;
- MYSQL_FIELD* getField(sal_Int32 column) const;
public:
- OResultSetMetaData(OConnection& rConn, MYSQL_RES* pResult)
- : m_rConnection(rConn)
- , m_pRes(pResult)
- {
- }
+ OResultSetMetaData(OConnection& rConn, MYSQL_RES* pResult);
sal_Int32 SAL_CALL getColumnCount() override;
@@ -89,10 +100,6 @@ public:
sal_Bool SAL_CALL isDefinitelyWritable(sal_Int32 column) override;
OUString SAL_CALL getColumnServiceName(sal_Int32 column) override;
-
- /// @throws SQLException
- /// @throws RuntimeException
- void checkColumnIndex(sal_Int32 columnIndex);
};
}
}