connectivity/source/drivers/firebird/Connection.cxx | 65 ++++++++ connectivity/source/drivers/firebird/Connection.hxx | 8 + connectivity/source/drivers/firebird/DatabaseMetaData.cxx | 102 ++++++++++++-- 3 files changed, 166 insertions(+), 9 deletions(-)
New commits: commit 748bf45544a31b7bd6217d046009e272d11aa310 Author: Andrzej J.R. Hunt <andr...@ahunt.org> Date: Fri Sep 6 12:50:25 2013 +0100 Actually use table name in getIndexInfo. (firebird-sdbc) Otherwise dbaccess's indexcollection gets confused and can segfault when indexes not belonging to the desired table are returned. Change-Id: I4dfe62bf1053c65cac907bf490749ee2cc24e6ca diff --git a/connectivity/source/drivers/firebird/DatabaseMetaData.cxx b/connectivity/source/drivers/firebird/DatabaseMetaData.cxx index ddb9ea4..0f86ad5 100644 --- a/connectivity/source/drivers/firebird/DatabaseMetaData.cxx +++ b/connectivity/source/drivers/firebird/DatabaseMetaData.cxx @@ -1575,7 +1575,8 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getIndexInfo( "FROM RDB$INDICES indices " "JOIN RDB$INDEX_SEGMENTS index_segments " "on (indices.RDB$INDEX_NAME = index_segments.RDB$INDEX_NAME) " - "WHERE (indices.RDB$SYSTEM_FLAG = 0) "); + "WHERE indices.RDB$RELATION_NAME = '" + sTable + "' " + "AND (indices.RDB$SYSTEM_FLAG = 0) "); // Not sure whether we should exclude system indices, but otoh. we never // actually deal with system tables (system indices only apply to system // tables) within the GUI. commit 2e31c305a374f14d927ea700657a85aa705f21d9 Author: Andrzej J.R. Hunt <andr...@ahunt.org> Date: Fri Sep 6 11:47:49 2013 +0100 Actually rebuild indexes in rebuildIndexes. (firebird-sdbc) Change-Id: I76ac3b261bce830879f17e82ddd22a9f4d957f11 diff --git a/connectivity/source/drivers/firebird/Connection.cxx b/connectivity/source/drivers/firebird/Connection.cxx index 5cca811..cb935c9 100644 --- a/connectivity/source/drivers/firebird/Connection.cxx +++ b/connectivity/source/drivers/firebird/Connection.cxx @@ -792,12 +792,13 @@ uno::Reference< XTablesSupplier > OConnection::createCatalog() void OConnection::rebuildIndexes() throw(SQLException) { - SAL_INFO("connectivity.firebird", "rebuildIndexes()"); MutexGuard aGuard(m_aMutex); // We only need to do this for character based columns on user-created tables. + // Ideally we'd use a FOR SELECT ... INTO .... DO ..., but that seems to + // only be possible using PSQL, i.e. using a stored procedure. OUString sSql( // multiple columns possible per index, only select once "SELECT DISTINCT indices.RDB$INDEX_NAME " @@ -816,15 +817,35 @@ void OConnection::rebuildIndexes() throw(SQLException) "AND (indices.RDB$INDEX_INACTIVE IS NULL OR indices.RDB$INDEX_INACTIVE = 0) " ); + uno::Reference< XStatement > xCharIndicesStatement = createStatement(); + uno::Reference< XResultSet > xCharIndices = + xCharIndicesStatement->executeQuery(sSql); + uno::Reference< XRow > xRow(xCharIndices, UNO_QUERY_THROW); + + uno::Reference< XStatement > xAlterIndexStatement = createStatement(); - uno::Reference< XStatement > xStatement = createStatement(); - uno::Reference< XResultSet > xCharIndices = xStatement->executeQuery(sSql); - uno::Reference< XRow > xRow( xCharIndices, UNO_QUERY_THROW ); + // ALTER is a DDL statement, hence using Statement will cause a commit + // after every alter -- in this case this is inappropriate (xCharIndicesStatement + // and its ResultSet become invalidated) hence we use the native api. while (xCharIndices->next()) { + OUString sIndexName(xRow->getString(1)); + SAL_INFO("connectivity.firebird", "rebuilding index " + sIndexName); + OString sAlterIndex = "ALTER INDEX " + + OUStringToOString(sIndexName, RTL_TEXTENCODING_UTF8) + + " ACTIVE"; + + ISC_STATUS_ARRAY aStatusVector; + ISC_STATUS aErr = 0; + + aErr = isc_dsql_execute_immediate(aStatusVector, + &getDBHandle(), + &getTransaction(), + 0, // Length: 0 for null terminated + sAlterIndex.getStr(), + FIREBIRD_SQL_DIALECT, + NULL); } - - Reference< XCloseable> xClose(xCharIndices,UNO_QUERY); - xClose->close(); + commit(); } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ commit 4ef1215d6a380b05bb8bb8d6fca869ac7eca05ff Author: Andrzej J.R. Hunt <andr...@ahunt.org> Date: Fri Sep 6 10:55:40 2013 +0100 Retrieve all char indexes for rebuildIndexes. (firebird-sdbc) This provides the SQL SELECT statement necessary to retrieve all the indexes needing rebuilding. Change-Id: I07661277682f83dc3f2d33a398abd83593c9928d diff --git a/connectivity/source/drivers/firebird/Connection.cxx b/connectivity/source/drivers/firebird/Connection.cxx index de795eb..5cca811 100644 --- a/connectivity/source/drivers/firebird/Connection.cxx +++ b/connectivity/source/drivers/firebird/Connection.cxx @@ -274,6 +274,12 @@ void OConnection::construct(const ::rtl::OUString& url, const Sequence< Property if (m_bIsEmbedded) // Add DocumentEventListener to save the .fdb as needed { + // TODO: this is only needed when we change icu versions, so ideally + // we somehow keep track of which icu version we have. There might + // be something db internal that we can check, or we might have to store + // it in the .odb. + rebuildIndexes(); + uno::Reference< frame::XDesktop2 > xFramesSupplier = frame::Desktop::create(::comphelper::getProcessComponentContext()); uno::Reference< frame::XFrames > xFrames( xFramesSupplier->getFrames(), @@ -783,4 +789,42 @@ uno::Reference< XTablesSupplier > OConnection::createCatalog() } } + +void OConnection::rebuildIndexes() throw(SQLException) +{ + + SAL_INFO("connectivity.firebird", "rebuildIndexes()"); + MutexGuard aGuard(m_aMutex); + + // We only need to do this for character based columns on user-created tables. + + OUString sSql( + // multiple columns possible per index, only select once + "SELECT DISTINCT indices.RDB$INDEX_NAME " + "FROM RDB$INDICES indices " + "JOIN RDB$INDEX_SEGMENTS index_segments " + "ON (indices.RDB$INDEX_NAME = index_segments.RDB$INDEX_NAME) " + "JOIN RDB$RELATION_FIELDS relation_fields " + "ON (index_segments.RDB$FIELD_NAME = relation_fields.RDB$FIELD_NAME) " + "JOIN RDB$FIELDS fields " + "ON (relation_fields.RDB$FIELD_SOURCE = fields.RDB$FIELD_NAME) " + + "WHERE (indices.RDB$SYSTEM_FLAG = 0) " + // TODO: what about blr_text2 etc. ? + "AND ((fields.RDB$FIELD_TYPE = " + OUString::number((int) blr_text) + ") " + " OR (fields.RDB$FIELD_TYPE = " + OUString::number((int) blr_varying) + ")) " + "AND (indices.RDB$INDEX_INACTIVE IS NULL OR indices.RDB$INDEX_INACTIVE = 0) " + ); + + + uno::Reference< XStatement > xStatement = createStatement(); + uno::Reference< XResultSet > xCharIndices = xStatement->executeQuery(sSql); + uno::Reference< XRow > xRow( xCharIndices, UNO_QUERY_THROW ); + while (xCharIndices->next()) + { + } + + Reference< XCloseable> xClose(xCharIndices,UNO_QUERY); + xClose->close(); +} /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/firebird/Connection.hxx b/connectivity/source/drivers/firebird/Connection.hxx index 4d7658d..cdf6c44 100644 --- a/connectivity/source/drivers/firebird/Connection.hxx +++ b/connectivity/source/drivers/firebird/Connection.hxx @@ -112,6 +112,14 @@ namespace connectivity ::com::sun::star::uno::WeakReference< ::com::sun::star::sdbcx::XTablesSupplier> m_xCatalog; + + /** + * Firebird stores binary collations for indexes on Character based + * columns, these can be binary-incompatible between different icu + * version, hence we need to rebuild the indexes when switching icu + * versions. + */ + void rebuildIndexes() throw( ::com::sun::star::sdbc::SQLException); void buildTypeInfo() throw( ::com::sun::star::sdbc::SQLException); void setupTransaction() throw(::com::sun::star::sdbc::SQLException); commit 17a2a19ca23c0e3acf6dadc5ccdad054395738ef Author: Andrzej J.R. Hunt <andr...@ahunt.org> Date: Thu Sep 5 08:20:43 2013 +0100 Implement getIndexInfo. (firebird-sdbc) Change-Id: I8c3393fbc7c4fb418f31a80b23360c6c7bf21a25 diff --git a/connectivity/source/drivers/firebird/DatabaseMetaData.cxx b/connectivity/source/drivers/firebird/DatabaseMetaData.cxx index 2eabddf..ddb9ea4 100644 --- a/connectivity/source/drivers/firebird/DatabaseMetaData.cxx +++ b/connectivity/source/drivers/firebird/DatabaseMetaData.cxx @@ -26,6 +26,7 @@ #include <com/sun/star/sdbc/ColumnValue.hpp> #include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/IndexType.hpp> #include <com/sun/star/sdbc/ResultSetType.hpp> #include <com/sun/star/sdbc/ResultSetConcurrency.hpp> #include <com/sun/star/sdbc/TransactionIsolation.hpp> @@ -1548,17 +1549,99 @@ uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getPrimaryKeys( return xResultSet; } -// ------------------------------------------------------------------------- + uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getIndexInfo( - const Any& catalog, const OUString& schema, const OUString& table, - sal_Bool unique, sal_Bool approximate ) throw(SQLException, RuntimeException) + const Any& aCatalog, const OUString& sSchema, const OUString& sTable, + sal_Bool bIsUnique, sal_Bool bIsApproximate) + throw(SQLException, RuntimeException) { - (void) catalog; - (void) schema; - (void) table; - (void) unique; - (void) approximate; - return NULL; + (void) aCatalog; + (void) sSchema; + + // Apparently this method can also return a "tableIndexStatistic" + // However this is only mentioned in XDatabaseMetaData.idl (whose comments + // are duplicated in the postgresql driver), and is otherwise undocumented. + + SAL_INFO("connectivity.firebird", "getPrimaryKeys() with " + "Table: " << sTable); + + OUStringBuffer aQueryBuf("SELECT " + "indices.RDB$RELATION_NAME, " // 1. Table Name + "index_segments.RDB$FIELD_NAME, " // 2. Column Name + "index_segments.RDB$FIELD_POSITION, " // 3. Sequence Number + "indices.RDB$INDEX_NAME, " // 4. Index name + "indices.RDB$UNIQUE_FLAG, " // 5. Unique Flag + "indices.RDB$INDEX_TYPE " // 6. Index Type + "FROM RDB$INDICES indices " + "JOIN RDB$INDEX_SEGMENTS index_segments " + "on (indices.RDB$INDEX_NAME = index_segments.RDB$INDEX_NAME) " + "WHERE (indices.RDB$SYSTEM_FLAG = 0) "); + // Not sure whether we should exclude system indices, but otoh. we never + // actually deal with system tables (system indices only apply to system + // tables) within the GUI. + + // Only filter if true (according to the docs), i.e.: + // If false we return all indices, if true we return only unique indices + if (bIsUnique) + aQueryBuf.append("AND (indices.RDB$UNIQUE_FLAG = 1) "); + + // TODO: what is bIsApproximate? + (void) bIsApproximate; + + OUString sQuery = aQueryBuf.makeStringAndClear(); + + uno::Reference< XStatement > xStatement = m_pConnection->createStatement(); + uno::Reference< XResultSet > xRs = xStatement->executeQuery(sQuery); + uno::Reference< XRow > xRow( xRs, UNO_QUERY_THROW ); + + ODatabaseMetaDataResultSet::ORows aResults; + ODatabaseMetaDataResultSet::ORow aCurrentRow(14); + + aCurrentRow[0] = new ORowSetValueDecorator(); // Unused -- numbering starts from 0 + aCurrentRow[1] = new ORowSetValueDecorator(); // Catalog - can be null + aCurrentRow[2] = new ORowSetValueDecorator(); // Schema - can be null + aCurrentRow[5] = new ORowSetValueDecorator(); // Index Catalog -- can be null + // According to wikipedia firebird uses clustered indices. + // The documentation does not specifically seem to specify this. + aCurrentRow[7] = new ORowSetValueDecorator(IndexType::CLUSTERED); // 7. INDEX TYPE + aCurrentRow[13] = new ORowSetValueDecorator(); // Filter Condition -- can be null + + while(xRs->next()) + { + // 3. Table Name + if (xRs->getRow() == 1) // Table name doesn't change, so only retrieve once + { + aCurrentRow[3] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(1))); + } + + // 4. NON_UNIQUE -- i.e. specifically negate here. + aCurrentRow[4] = new ORowSetValueDecorator(!xRow->getBoolean(5)); + // 6. INDEX NAME + aCurrentRow[6] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(4))); + + // 8. ORDINAL POSITION + aCurrentRow[8] = new ORowSetValueDecorator(xRow->getShort(3)); + // 9. COLUMN NAME + aCurrentRow[9] = new ORowSetValueDecorator(sanitizeIdentifier(xRow->getString(2))); + // 10. ASC(ending)/DESC(ending) + if (xRow->getShort(6) == 1) + aCurrentRow[10] = new ORowSetValueDecorator(OUString("D")); + else + aCurrentRow[10] = new ORowSetValueDecorator(OUString("A")); + // TODO: double check this^^^, doesn't seem to be officially documented anywhere. + // 11. CARDINALITY + aCurrentRow[11] = new ORowSetValueDecorator((sal_Int32)0); // TODO: determine how to do this + // 12. PAGES + aCurrentRow[12] = new ORowSetValueDecorator((sal_Int32)0); // TODO: determine how to do this + + aResults.push_back(aCurrentRow); + } + ODatabaseMetaDataResultSet* pResultSet = new + ODatabaseMetaDataResultSet(ODatabaseMetaDataResultSet::ePrimaryKeys); + uno::Reference< XResultSet > xResultSet = pResultSet; + pResultSet->setRows( aResults ); + + return xResultSet; } // ------------------------------------------------------------------------- uno::Reference< XResultSet > SAL_CALL ODatabaseMetaData::getBestRowIdentifier( _______________________________________________ Libreoffice-commits mailing list libreoffice-comm...@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/libreoffice-commits