[Libreoffice-commits] core.git: 4 commits - connectivity/source

Andrzej J.R. Hunt andrzej at ahunt.org
Thu Sep 5 05:48:38 PDT 2013


 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 <andrzej at 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 <andrzej at 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 <andrzej at 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 <andrzej at 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(


More information about the Libreoffice-commits mailing list