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

Wastack btomi96 at gmail.com
Thu Aug 18 12:25:42 UTC 2016


 connectivity/Library_firebird_sdbc.mk                      |    1 
 connectivity/source/drivers/firebird/Column.cxx            |   54 +++
 connectivity/source/drivers/firebird/Column.hxx            |   37 ++
 connectivity/source/drivers/firebird/Columns.cxx           |    6 
 connectivity/source/drivers/firebird/Columns.hxx           |    3 
 connectivity/source/drivers/firebird/PreparedStatement.cxx |   13 
 connectivity/source/drivers/firebird/PreparedStatement.hxx |    1 
 connectivity/source/drivers/firebird/ResultSet.cxx         |    8 
 connectivity/source/drivers/firebird/ResultSet.hxx         |    5 
 connectivity/source/drivers/firebird/ResultSetMetaData.cxx |   37 +-
 connectivity/source/drivers/firebird/ResultSetMetaData.hxx |    5 
 connectivity/source/drivers/firebird/Statement.cxx         |    9 
 connectivity/source/drivers/firebird/Table.cxx             |    6 
 connectivity/source/drivers/firebird/Tables.cxx            |   93 +++++
 connectivity/source/drivers/firebird/Tables.hxx            |    2 
 connectivity/source/drivers/firebird/Util.cxx              |  234 +++++++++++++
 connectivity/source/drivers/firebird/Util.hxx              |   11 
 17 files changed, 511 insertions(+), 14 deletions(-)

New commits:
commit 0a9123152387f7a742481e9f35401270e29ed695
Author: Wastack <btomi96 at gmail.com>
Date:   Thu Aug 11 20:03:18 2016 +0200

    tdf#69949 GSoC Firebird implement autoincrement
    
    Change-Id: I6fe08b575f01b986f0a3c96b341f254279427b68
    Reviewed-on: https://gerrit.libreoffice.org/28062
    Reviewed-by: Lionel Elie Mamane <lionel at mamane.lu>
    Tested-by: Jenkins <ci at libreoffice.org>

diff --git a/connectivity/Library_firebird_sdbc.mk b/connectivity/Library_firebird_sdbc.mk
index 4c3dae1..43fa363 100644
--- a/connectivity/Library_firebird_sdbc.mk
+++ b/connectivity/Library_firebird_sdbc.mk
@@ -42,6 +42,7 @@ $(eval $(call gb_Library_set_componentfile,firebird_sdbc,connectivity/source/dri
 $(eval $(call gb_Library_add_exception_objects,firebird_sdbc,\
     connectivity/source/drivers/firebird/Blob \
     connectivity/source/drivers/firebird/Catalog \
+    connectivity/source/drivers/firebird/Column \
     connectivity/source/drivers/firebird/Columns \
     connectivity/source/drivers/firebird/Connection \
     connectivity/source/drivers/firebird/DatabaseMetaData \
diff --git a/connectivity/source/drivers/firebird/Column.cxx b/connectivity/source/drivers/firebird/Column.cxx
new file mode 100644
index 0000000..28ce9ac
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Column.cxx
@@ -0,0 +1,54 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "Columns.hxx"
+#include "Column.hxx"
+
+#include "TConnection.hxx"
+
+using namespace connectivity;
+using namespace connectivity::firebird;
+using namespace connectivity::sdbcx;
+
+Column::Column()
+    : OColumn( true ) // case sensitive
+{
+    construct();
+}
+
+void Column::construct()
+{
+    m_sAutoIncrement = "GENERATED BY DEFAULT AS IDENTITY";
+    registerProperty(OMetaConnection::getPropMap().getNameByIndex(
+                            PROPERTY_ID_AUTOINCREMENTCREATION),
+                     PROPERTY_ID_AUTOINCREMENTCREATION,
+                     0,
+                     &m_sAutoIncrement,
+                     cppu::UnoType<decltype(m_sAutoIncrement)>::get()
+                     );
+}
+
+::cppu::IPropertyArrayHelper* Column::createArrayHelper( sal_Int32 /*_nId*/ ) const
+{
+    return doCreateArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper & SAL_CALL Column::getInfoHelper()
+{
+    return *Column_PROP::getArrayHelper(isNew() ? 1 : 0);
+}
+
+css::uno::Sequence< OUString > SAL_CALL Column::getSupportedServiceNames(  ) throw(css::uno::RuntimeException, std::exception)
+{
+    css::uno::Sequence< OUString > aSupported { "com.sun.star.sdbc.Firebird" };
+
+    return aSupported;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/firebird/Column.hxx b/connectivity/source/drivers/firebird/Column.hxx
new file mode 100644
index 0000000..0b1ea67
--- /dev/null
+++ b/connectivity/source/drivers/firebird/Column.hxx
@@ -0,0 +1,37 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+#ifndef INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_HCOLUMN_HXX
+#define INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_HCOLUMN_HXX
+#include <connectivity/TColumnsHelper.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+
+namespace connectivity
+{
+    namespace firebird
+    {
+        class Column;
+        typedef sdbcx::OColumn Column_BASE;
+        typedef ::comphelper::OIdPropertyArrayUsageHelper<Column> Column_PROP;
+        class Column : public Column_BASE,
+                           public Column_PROP
+        {
+            OUString m_sAutoIncrement;
+        protected:
+            virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const override;
+            virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+        public:
+            Column();
+            virtual void construct() override;
+            virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames(  ) throw(css::uno::RuntimeException, std::exception) override;
+        };
+    }
+}
+#endif // INCLUDED_CONNECTIVITY_SOURCE_INC_HSQLDB_HCOLUMNS_HXX
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/firebird/Columns.cxx b/connectivity/source/drivers/firebird/Columns.cxx
index 6f41dca..d418026 100644
--- a/connectivity/source/drivers/firebird/Columns.cxx
+++ b/connectivity/source/drivers/firebird/Columns.cxx
@@ -8,6 +8,7 @@
  */
 
 #include "Columns.hxx"
+#include "Column.hxx"
 
 #include <com/sun/star/sdbc/XRow.hpp>
 
@@ -33,4 +34,9 @@ Columns::Columns(Table& rTable,
     OColumnsHelper::setParent(&rTable);
 }
 
+Reference< css::beans::XPropertySet > Columns::createDescriptor()
+{
+    return new Column;
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/firebird/Columns.hxx b/connectivity/source/drivers/firebird/Columns.hxx
index 87c81fb..58c1b33 100644
--- a/connectivity/source/drivers/firebird/Columns.hxx
+++ b/connectivity/source/drivers/firebird/Columns.hxx
@@ -20,11 +20,12 @@ namespace connectivity
     {
         class Columns: public ::connectivity::OColumnsHelper
         {
+        protected:
+            virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
         public:
             Columns(Table& rTable,
                     ::osl::Mutex& rMutex,
                     const ::connectivity::TStringVector &_rVector);
-
         };
 
     } // namespace firebird
diff --git a/connectivity/source/drivers/firebird/PreparedStatement.cxx b/connectivity/source/drivers/firebird/PreparedStatement.cxx
index 801acd8..13402b8 100644
--- a/connectivity/source/drivers/firebird/PreparedStatement.cxx
+++ b/connectivity/source/drivers/firebird/PreparedStatement.cxx
@@ -56,6 +56,7 @@ OPreparedStatement::OPreparedStatement( Connection* _pConnection,
     ,m_sSqlStatement(sql)
     ,m_pOutSqlda(nullptr)
     ,m_pInSqlda(nullptr)
+    ,m_sTableName()
 {
     SAL_INFO("connectivity.firebird", "OPreparedStatement(). "
              "sql: " << sql);
@@ -83,6 +84,11 @@ void OPreparedStatement::ensurePrepared()
                                m_pOutSqlda,
                                m_pInSqlda);
 
+    OStringVector vec;
+    tokenizeSQL( OUStringToOString(m_sSqlStatement, RTL_TEXTENCODING_UTF8), vec );
+    m_sTableName =
+            OStringToOUString(
+            extractSingleTableFromSelect( vec ), RTL_TEXTENCODING_UTF8);
 
     aErr = isc_dsql_describe_bind(m_statusVector,
                                   &m_aStatementHandle,
@@ -151,7 +157,9 @@ Reference< XResultSetMetaData > SAL_CALL OPreparedStatement::getMetaData()
     ensurePrepared();
 
     if(!m_xMetaData.is())
-        m_xMetaData = new OResultSetMetaData(m_pConnection.get(), m_pOutSqlda);
+        m_xMetaData = new OResultSetMetaData(m_pConnection.get()
+                                           , m_pOutSqlda
+                                           , m_sTableName);
 
     return m_xMetaData;
 }
@@ -285,7 +293,8 @@ sal_Bool SAL_CALL OPreparedStatement::execute()
                                   m_aMutex,
                                   uno::Reference< XInterface >(*this),
                                   m_aStatementHandle,
-                                  m_pOutSqlda);
+                                  m_pOutSqlda,
+                                  m_sTableName);
 
     if (getStatementChangeCount() > 0)
         m_pConnection->notifyDatabaseModified();
diff --git a/connectivity/source/drivers/firebird/PreparedStatement.hxx b/connectivity/source/drivers/firebird/PreparedStatement.hxx
index 72e90d5..33e1421 100644
--- a/connectivity/source/drivers/firebird/PreparedStatement.hxx
+++ b/connectivity/source/drivers/firebird/PreparedStatement.hxx
@@ -53,6 +53,7 @@ namespace connectivity
 
             XSQLDA*         m_pOutSqlda;
             XSQLDA*         m_pInSqlda;
+            ::rtl::OUString                                       m_sTableName;
             void checkParameterIndex(sal_Int32 nParameterIndex)
                 throw(css::sdbc::SQLException,
                       css::uno::RuntimeException);
diff --git a/connectivity/source/drivers/firebird/ResultSet.cxx b/connectivity/source/drivers/firebird/ResultSet.cxx
index 68517a8..299dafa 100644
--- a/connectivity/source/drivers/firebird/ResultSet.cxx
+++ b/connectivity/source/drivers/firebird/ResultSet.cxx
@@ -57,7 +57,8 @@ OResultSet::OResultSet(Connection* pConnection,
                        ::osl::Mutex& rMutex,
                        const uno::Reference< XInterface >& xStatement,
                        isc_stmt_handle& aStatementHandle,
-                       XSQLDA* pSqlda)
+                       XSQLDA* pSqlda,
+                       const OUString& rTableName)
     : OResultSet_BASE(rMutex)
     , OPropertyContainer(OResultSet_BASE::rBHelper)
     , m_bIsBookmarkable(false)
@@ -75,6 +76,7 @@ OResultSet::OResultSet(Connection* pConnection,
     , m_currentRow(0)
     , m_bIsAfterLastRow(false)
     , m_fieldCount(pSqlda? pSqlda->sqld : 0)
+    , m_sTableName(rTableName)
 {
     SAL_INFO("connectivity.firebird", "OResultSet().");
     registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE),
@@ -640,7 +642,9 @@ uno::Reference< XResultSetMetaData > SAL_CALL OResultSet::getMetaData(  ) throw(
     checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
 
     if(!m_xMetaData.is())
-        m_xMetaData = new OResultSetMetaData(m_pConnection, m_pSqlda);
+        m_xMetaData = new OResultSetMetaData(m_pConnection
+                                           , m_pSqlda
+                                           , m_sTableName);
     return m_xMetaData;
 }
 
diff --git a/connectivity/source/drivers/firebird/ResultSet.hxx b/connectivity/source/drivers/firebird/ResultSet.hxx
index e5ae03a..e0f3e46 100644
--- a/connectivity/source/drivers/firebird/ResultSet.hxx
+++ b/connectivity/source/drivers/firebird/ResultSet.hxx
@@ -97,6 +97,8 @@ namespace connectivity
             const sal_Int32                             m_fieldCount;
             ISC_STATUS_ARRAY                            m_statusVector;
 
+            OUString                                    m_sTableName;
+
             bool isNull(const sal_Int32 nColumnIndex);
 
             template <typename T> T     retrieveValue(const sal_Int32 nColumnIndex,
@@ -126,7 +128,8 @@ namespace connectivity
                        ::osl::Mutex& rMutex,
                        const css::uno::Reference< css::uno::XInterface >& xStatement,
                        isc_stmt_handle& aStatementHandle,
-                       XSQLDA* aSqlda);
+                       XSQLDA* aSqlda,
+                       const OUString & rTableName);
 
             // XInterface
             virtual css::uno::Any SAL_CALL queryInterface(
diff --git a/connectivity/source/drivers/firebird/ResultSetMetaData.cxx b/connectivity/source/drivers/firebird/ResultSetMetaData.cxx
index e76be24..9baadab 100644
--- a/connectivity/source/drivers/firebird/ResultSetMetaData.cxx
+++ b/connectivity/source/drivers/firebird/ResultSetMetaData.cxx
@@ -21,13 +21,19 @@
 #include "Util.hxx"
 
 #include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
 
 using namespace connectivity::firebird;
 
 using namespace com::sun::star::lang;
 using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
 using namespace com::sun::star::uno;
 
+using com::sun::star::beans::XPropertySet;
+using com::sun::star::container::XNameAccess;
+
 OResultSetMetaData::~OResultSetMetaData()
 {
 }
@@ -141,8 +147,35 @@ sal_Bool SAL_CALL OResultSetMetaData::isCurrency(sal_Int32 column)
 sal_Bool SAL_CALL OResultSetMetaData::isAutoIncrement(sal_Int32 column)
     throw(SQLException, RuntimeException, std::exception)
 {
-    // Supported internally but no way of determining this here.
-    (void) column;
+    if( !m_sTableName.isEmpty() )
+    {
+        OUString sColumnName = getColumnName( column );
+
+        OUString sSql = "SELECT RDB$IDENTITY_TYPE FROM RDB$RELATION_FIELDS "
+                   "WHERE RDB$RELATION_NAME = '"
+                   + escapeWith(m_sTableName, '\'', '\'') + "' AND "
+                   "RDB$FIELD_NAME = '"+ escapeWith(sColumnName, '\'', '\'') +"'";
+
+        Reference<XStatement> xStmt =m_pConnection ->createStatement();
+
+        Reference<XResultSet> xRes =
+                xStmt->executeQuery(sSql);
+        Reference<XRow> xRow ( xRes, UNO_QUERY);
+        if(xRes->next())
+        {
+            int iType = xRow->getShort(1);
+            if(iType == 1) // IDENTITY
+                return true;
+        }
+        else
+        {
+            SAL_WARN("connectivity.firebird","Column '"
+                    << sColumnName
+                    << "' not found in database");
+
+            return false;
+        }
+    }
     return false;
 }
 
diff --git a/connectivity/source/drivers/firebird/ResultSetMetaData.hxx b/connectivity/source/drivers/firebird/ResultSetMetaData.hxx
index 4df534a..cac8a01 100644
--- a/connectivity/source/drivers/firebird/ResultSetMetaData.hxx
+++ b/connectivity/source/drivers/firebird/ResultSetMetaData.hxx
@@ -40,6 +40,7 @@ namespace connectivity
         protected:
             ::rtl::Reference<Connection> m_pConnection;
             XSQLDA*         m_pSqlda;
+            OUString        m_sTableName;
 
             virtual ~OResultSetMetaData();
 
@@ -47,9 +48,11 @@ namespace connectivity
         public:
             // a constructor, which is required for returning objects:
             OResultSetMetaData(Connection* pConnection,
-                               XSQLDA* pSqlda)
+                               XSQLDA* pSqlda,
+                               const OUString & rTableName)
                 : m_pConnection(pConnection)
                 , m_pSqlda(pSqlda)
+                , m_sTableName(rTableName)
             {}
 
             virtual sal_Int32 SAL_CALL getColumnCount()
diff --git a/connectivity/source/drivers/firebird/Statement.cxx b/connectivity/source/drivers/firebird/Statement.cxx
index 29c195c..f69e3ef 100644
--- a/connectivity/source/drivers/firebird/Statement.cxx
+++ b/connectivity/source/drivers/firebird/Statement.cxx
@@ -125,11 +125,18 @@ uno::Reference< XResultSet > SAL_CALL OStatement::executeQuery(const OUString& s
     if (aErr)
         SAL_WARN("connectivity.firebird", "isc_dsql_execute failed");
 
+    OStringVector vec;
+    tokenizeSQL( OUStringToOString(sql, RTL_TEXTENCODING_UTF8), vec );
+    OUString sourceTable =
+            OStringToOUString(
+            extractSingleTableFromSelect( vec ), RTL_TEXTENCODING_UTF8);
+
     m_xResultSet = new OResultSet(m_pConnection.get(),
                                   m_aMutex,
                                   uno::Reference< XInterface >(*this),
                                   m_aStatementHandle,
-                                  m_pSqlda);
+                                  m_pSqlda,
+                                  sourceTable);
 
     // TODO: deal with cleanup
 
diff --git a/connectivity/source/drivers/firebird/Table.cxx b/connectivity/source/drivers/firebird/Table.cxx
index 8f189d7..fea9046 100644
--- a/connectivity/source/drivers/firebird/Table.cxx
+++ b/connectivity/source/drivers/firebird/Table.cxx
@@ -196,7 +196,11 @@ void SAL_CALL Table::alterColumnByName(const OUString& rColName,
 
     if (bIsAutoIncrementChanged)
     {
-        // TODO: changeType
+       ::dbtools::throwSQLException(
+            "Changing autoincrement property of existing column is not supported",
+            ::dbtools::StandardSQLState::FUNCTION_NOT_SUPPORTED,
+            *this);
+
     }
 
     if (bDefaultChanged)
diff --git a/connectivity/source/drivers/firebird/Tables.cxx b/connectivity/source/drivers/firebird/Tables.cxx
index df3edb7..bc15f90 100644
--- a/connectivity/source/drivers/firebird/Tables.cxx
+++ b/connectivity/source/drivers/firebird/Tables.cxx
@@ -11,9 +11,13 @@
 #include "Tables.hxx"
 #include "Catalog.hxx"
 
+#include "TConnection.hxx"
+
 #include <connectivity/dbtools.hxx>
 
 #include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
 
 using namespace ::connectivity;
 using namespace ::connectivity::firebird;
@@ -26,6 +30,7 @@ using namespace ::com::sun::star::beans;
 using namespace ::com::sun::star::container;
 using namespace ::com::sun::star::lang;
 using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
 using namespace ::com::sun::star::uno;
 
 
@@ -65,6 +70,42 @@ ObjectType Tables::createObject(const OUString& rName)
     return xRet;
 }
 
+OUString Tables::createStandardColumnPart(const Reference< XPropertySet >& xColProp,const Reference< XConnection>& _xConnection)
+{
+    Reference<XDatabaseMetaData> xMetaData = _xConnection->getMetaData();
+
+    ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+    bool bIsAutoIncrement = false;
+    xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISAUTOINCREMENT))    >>= bIsAutoIncrement;
+
+    const OUString sQuoteString = xMetaData->getIdentifierQuoteString();
+    OUStringBuffer aSql = ::dbtools::quoteName(sQuoteString,::comphelper::getString(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME))));
+
+    // check if the user enter a specific string to create autoincrement values
+    OUString sAutoIncrementValue;
+    Reference<XPropertySetInfo> xPropInfo = xColProp->getPropertySetInfo();
+
+    if ( xPropInfo.is() && xPropInfo->hasPropertyByName(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) )
+        xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_AUTOINCREMENTCREATION)) >>= sAutoIncrementValue;
+
+    aSql.append(" ");
+
+    aSql.append(dbtools::createStandardTypePart(xColProp, _xConnection));
+
+
+    if ( bIsAutoIncrement && !sAutoIncrementValue.isEmpty())
+    {
+        aSql.append(" ");
+        aSql.append(sAutoIncrementValue);
+    }
+    // AutoIncrementive "IDENTITY" is implizit "NOT NULL"
+    else if(::comphelper::getINT32(xColProp->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_ISNULLABLE))) == ColumnValue::NO_NULLS)
+        aSql.append(" NOT NULL");
+
+    return aSql.makeStringAndClear();
+}
+
 uno::Reference< XPropertySet > Tables::createDescriptor()
 {
     // There is some internal magic so that the same class can be used as either
@@ -77,8 +118,56 @@ uno::Reference< XPropertySet > Tables::createDescriptor()
 ObjectType Tables::appendObject(const OUString& rName,
                                 const uno::Reference< XPropertySet >& rDescriptor)
 {
-    OUString sSql(::dbtools::createSqlCreateTableStatement(rDescriptor,
-                                                            m_xMetaData->getConnection()));
+   /* OUString sSql(::dbtools::createSqlCreateTableStatement(rDescriptor,
+                                                            m_xMetaData->getConnection())); */
+    OUStringBuffer aSqlBuffer("CREATE TABLE ");
+    OUString sCatalog, sSchema, sComposedName, sTable;
+    const Reference< XConnection>& xConnection = m_xMetaData->getConnection();
+
+    ::dbtools::OPropertyMap& rPropMap = OMetaConnection::getPropMap();
+
+    rDescriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_CATALOGNAME))  >>= sCatalog;
+    rDescriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_SCHEMANAME))   >>= sSchema;
+    rDescriptor->getPropertyValue(rPropMap.getNameByIndex(PROPERTY_ID_NAME))         >>= sTable;
+
+    sComposedName = ::dbtools::composeTableName(m_xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InTableDefinitions );
+    if ( sComposedName.isEmpty() )
+        ::dbtools::throwFunctionSequenceException(xConnection);
+
+    aSqlBuffer.append(sComposedName);
+    aSqlBuffer.append(" (");
+
+    // columns
+    Reference<XColumnsSupplier> xColumnSup(rDescriptor,UNO_QUERY);
+    Reference<XIndexAccess> xColumns(xColumnSup->getColumns(),UNO_QUERY);
+    // check if there are columns
+    if(!xColumns.is() || !xColumns->getCount())
+        ::dbtools::throwFunctionSequenceException(xConnection);
+
+    Reference< XPropertySet > xColProp;
+
+    sal_Int32 nCount = xColumns->getCount();
+    for(sal_Int32 i=0;i<nCount;++i)
+    {
+        if ( (xColumns->getByIndex(i) >>= xColProp) && xColProp.is() )
+        {
+            aSqlBuffer.append(createStandardColumnPart(xColProp,xConnection));
+            aSqlBuffer.append(",");
+        }
+    }
+    OUString sSql = aSqlBuffer.makeStringAndClear();
+
+    const OUString sKeyStmt = ::dbtools::createStandardKeyStatement(rDescriptor,xConnection);
+    if ( !sKeyStmt.isEmpty() )
+        sSql += sKeyStmt;
+    else
+    {
+        if ( sSql.endsWith(",") )
+            sSql = sSql.replaceAt(aSqlBuffer.getLength()-1, 1, ")");
+        else
+            sSql += ")";
+    }
+
     m_xMetaData->getConnection()->createStatement()->execute(sSql);
 
     return createObject(rName);
diff --git a/connectivity/source/drivers/firebird/Tables.hxx b/connectivity/source/drivers/firebird/Tables.hxx
index 5fc5397..1a0a358 100644
--- a/connectivity/source/drivers/firebird/Tables.hxx
+++ b/connectivity/source/drivers/firebird/Tables.hxx
@@ -29,6 +29,8 @@ namespace connectivity
             css::uno::Reference< css::sdbc::XDatabaseMetaData >
                 m_xMetaData;
 
+            static OUString createStandardColumnPart(const css::uno::Reference< css::beans::XPropertySet >& xColProp,const css::uno::Reference< com::sun::star::sdbc::XConnection>& _xConnection);
+
             // OCollection
             virtual void impl_refresh()
                 throw(css::uno::RuntimeException) override;
diff --git a/connectivity/source/drivers/firebird/Util.cxx b/connectivity/source/drivers/firebird/Util.cxx
index 00eb4aa3..ee5a9bd 100644
--- a/connectivity/source/drivers/firebird/Util.cxx
+++ b/connectivity/source/drivers/firebird/Util.cxx
@@ -9,6 +9,7 @@
 
 #include "Util.hxx"
 #include <rtl/ustrbuf.hxx>
+#include <rtl/strbuf.hxx>
 
 using namespace ::connectivity;
 
@@ -306,4 +307,237 @@ void firebird::freeSQLVAR(XSQLDA* pSqlda)
         }
     }
 }
+
+static bool isWhitespace( sal_Unicode c )
+{
+    return ' ' == c || 9 == c || 10 == c || 13 == c;
+}
+
+static bool isOperator( char c )
+{
+    bool ret;
+    switch(c)
+    {
+    case '+':
+    case '-':
+    case '*':
+    case '/':
+    case '<':
+    case '>':
+    case '=':
+    case '~':
+    case '!':
+    case '@':
+    case '#':
+    case '%':
+    case '^':
+    case '&':
+    case '|':
+    case '`':
+    case '?':
+    case '$':
+        ret = true;
+        break;
+    default:
+        ret = false;
+    }
+    return ret;
+}
+
+void firebird::tokenizeSQL( const OString & sql, OStringVector &vec  )
+{
+    int length = sql.getLength();
+
+    int i = 0;
+    bool singleQuote = false;
+    bool doubleQuote = false;
+    int start = 0;
+    for( ; i < length ; i ++ )
+    {
+        char c = sql[i];
+        if( doubleQuote  )
+        {
+            if( '"' == c )
+            {
+                vec.push_back( OString( &sql.getStr()[start], i-start  ) );
+                start = i + 1;
+                doubleQuote = false;
+            }
+        }
+        else if( singleQuote )
+        {
+            if( '\'' == c )
+            {
+                vec.push_back( OString( &sql.getStr()[start], i - start +1 ) );
+                start = i + 1; // leave single quotes !
+                singleQuote = false;
+            }
+        }
+        else
+        {
+            if( '"' == c )
+            {
+                doubleQuote = true;
+                start = i +1; // skip double quotes !
+            }
+            else if( '\'' == c )
+            {
+                singleQuote = true;
+                start = i; // leave single quotes
+            }
+            else if( isWhitespace( c ) )
+            {
+                if( i == start )
+                    start ++;   // skip additional whitespace
+                else
+                {
+                    vec.push_back( OString( &sql.getStr()[start], i - start  ) );
+                    start = i +1;
+                }
+            }
+            else if( ',' == c || isOperator( c ) || '(' == c || ')' == c )
+            {
+                if( i - start )
+                    vec.push_back( OString( &sql.getStr()[start], i - start ) );
+                vec.push_back( OString( &sql.getStr()[i], 1 ) );
+                start = i + 1;
+            }
+            else if( '.' == c )
+            {
+                if( ( i > start && sql[start] >= '0' && sql[start] <= '9' ) ||
+                    ( i == start && i > 1 && isWhitespace( sql[i-1] ) ) )
+                {
+                    // ignore, is a literal
+                }
+                else
+                {
+                    if( i - start )
+                        vec.push_back( OString( &sql.getStr()[start], i - start ) );
+                    vec.push_back( OString( "." ) );
+                    start = i + 1;
+                }
+            }
+        }
+    }
+    if( start < i )
+        vec.push_back( OString( &sql.getStr()[start] , i - start ) );
+}
+
+OString firebird::extractSingleTableFromSelect( const OStringVector &vec )
+{
+    OString ret;
+
+    if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
+            vec[0].pData->buffer, vec[0].pData->length, "select" , 6 , 6 ) )
+    {
+        size_t token = 0;
+
+        for( token = 1; token < vec.size() ; token ++ )
+        {
+            if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
+                    vec[token].getStr(), vec[token].getLength(), "from" , 4 , 4 ) )
+            {
+                // found from
+                break;
+            }
+        }
+        token ++;
+
+        if( token < vec.size() && 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
+                vec[token].pData->buffer, vec[token].pData->length, "only " , 4 , 4 ) )
+        {
+            token ++;
+        }
+
+        if( token < vec.size() && vec[token] != "(" )
+        {
+            // it is a table or a function name
+            OStringBuffer buf(128);
+            if( '"' == vec[token][0] )
+                buf.append( &(vec[token].getStr()[1]) , vec[token].getLength() -2 );
+            else
+                buf.append( vec[token] );
+            token ++;
+
+            if( token < vec.size() )
+            {
+                if( vec[token] == "." )
+                {
+                    buf.append( vec[token] );
+                    token ++;
+                    if( token < vec.size() )
+                    {
+                        if( '"' == vec[token][0] )
+                            buf.append( &(vec[token].getStr()[1]) , vec[token].getLength() -2 );
+                        else
+                            buf.append( vec[token] );
+                        token ++;
+                    }
+                }
+            }
+
+            ret = buf.makeStringAndClear();
+            // now got my table candidate
+
+            if( token < vec.size() && vec[token] == "(" )
+            {
+                // whoops, it is a function
+                ret.clear();
+            }
+            else
+            {
+                if( token < vec.size() )
+                {
+                    if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
+                            vec[token].pData->buffer, vec[token].pData->length, "as" , 2, 2 ) )
+                    {
+                        token += 2; // skip alias
+                    }
+                }
+
+                if( token < vec.size() )
+                {
+                    if( vec[token] == "," )
+                    {
+                        // whoops, multiple tables are used
+                        ret.clear();
+                    }
+                    else
+                    {
+                        static const char * forbiddenKeywords[] =
+                            { "join", "natural", "outer", "inner", "left", "right", "full" , nullptr };
+                        for( int i = 0 ; forbiddenKeywords[i] ; i ++ )
+                        {
+                            size_t nKeywordLen = strlen(forbiddenKeywords[i]);
+                            if( 0 == rtl_str_shortenedCompareIgnoreAsciiCase_WithLength(
+                                 vec[token].pData->buffer, vec[token].pData->length,
+                                 forbiddenKeywords[i], nKeywordLen,
+                                 nKeywordLen ) )
+                            {
+                                // whoops, it is a join
+                                ret.clear();
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+    return ret;
+
+}
+
+OUString firebird::escapeWith( const OUString& sText, const char aKey, const char aEscapeChar)
+{
+    OUString sRet(sText);
+    sal_Int32 aIndex = 0;
+    while( (aIndex = sRet.indexOf(aKey, aIndex)) > 0 &&
+            aIndex < sRet.getLength())
+    {
+            sRet = sRet.replaceAt(aIndex, 1, OUString(aEscapeChar) + OUString(aKey)  );
+            aIndex+= 2;
+    }
+
+    return sRet;
+}
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/firebird/Util.hxx b/connectivity/source/drivers/firebird/Util.hxx
index 8e66aeb..b957c80 100644
--- a/connectivity/source/drivers/firebird/Util.hxx
+++ b/connectivity/source/drivers/firebird/Util.hxx
@@ -13,15 +13,18 @@
 #include <ibase.h>
 
 #include <rtl/ustring.hxx>
+#include <rtl/ustrbuf.hxx>
 
 #include <com/sun/star/sdbc/DataType.hpp>
 #include <com/sun/star/sdbc/SQLException.hpp>
 
+#include <vector>
+
 namespace connectivity
 {
     namespace firebird
     {
-
+        typedef ::std::vector< OString > OStringVector;
         /**
          * Make sure an identifier is safe to use within the databse. Currently
          * firebird seems to return identifiers with 93 character (instead of
@@ -64,6 +67,12 @@ namespace connectivity
         void mallocSQLVAR(XSQLDA* pSqlda);
 
         void freeSQLVAR(XSQLDA* pSqlda);
+
+        void tokenizeSQL( const OString & sql, OStringVector &vec  );
+
+        OString extractSingleTableFromSelect( const OStringVector &vec );
+
+        OUString escapeWith( const OUString& sText, const char aKey, const char aEscapeChar);
     }
 }
 #endif // INCLUDED_CONNECTIVITY_SOURCE_DRIVERS_FIREBIRD_UTIL_HXX


More information about the Libreoffice-commits mailing list