summaryrefslogtreecommitdiff
path: root/connectivity
diff options
context:
space:
mode:
authorWastack <btomi96@gmail.com>2016-08-11 20:03:18 +0200
committerLionel Elie Mamane <lionel@mamane.lu>2016-08-18 12:25:18 +0000
commit0a9123152387f7a742481e9f35401270e29ed695 (patch)
tree05b9059495d2217eefa629c8830a6964856e4a3b /connectivity
parentbfbd66f151002af6f65b9c062cc511797690e625 (diff)
tdf#69949 GSoC Firebird implement autoincrement
Change-Id: I6fe08b575f01b986f0a3c96b341f254279427b68 Reviewed-on: https://gerrit.libreoffice.org/28062 Reviewed-by: Lionel Elie Mamane <lionel@mamane.lu> Tested-by: Jenkins <ci@libreoffice.org>
Diffstat (limited to 'connectivity')
-rw-r--r--connectivity/Library_firebird_sdbc.mk1
-rw-r--r--connectivity/source/drivers/firebird/Column.cxx54
-rw-r--r--connectivity/source/drivers/firebird/Column.hxx37
-rw-r--r--connectivity/source/drivers/firebird/Columns.cxx6
-rw-r--r--connectivity/source/drivers/firebird/Columns.hxx3
-rw-r--r--connectivity/source/drivers/firebird/PreparedStatement.cxx13
-rw-r--r--connectivity/source/drivers/firebird/PreparedStatement.hxx1
-rw-r--r--connectivity/source/drivers/firebird/ResultSet.cxx8
-rw-r--r--connectivity/source/drivers/firebird/ResultSet.hxx5
-rw-r--r--connectivity/source/drivers/firebird/ResultSetMetaData.cxx37
-rw-r--r--connectivity/source/drivers/firebird/ResultSetMetaData.hxx5
-rw-r--r--connectivity/source/drivers/firebird/Statement.cxx9
-rw-r--r--connectivity/source/drivers/firebird/Table.cxx6
-rw-r--r--connectivity/source/drivers/firebird/Tables.cxx93
-rw-r--r--connectivity/source/drivers/firebird/Tables.hxx2
-rw-r--r--connectivity/source/drivers/firebird/Util.cxx234
-rw-r--r--connectivity/source/drivers/firebird/Util.hxx11
17 files changed, 511 insertions, 14 deletions
diff --git a/connectivity/Library_firebird_sdbc.mk b/connectivity/Library_firebird_sdbc.mk
index 4c3dae1a1eae..43fa363f7551 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 000000000000..28ce9ac0edb8
--- /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 000000000000..0b1ea67c1544
--- /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 6f41dcada0bc..d418026ce6c2 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 87c81fb802af..58c1b33029bd 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 801acd8ae29f..13402b86d1dd 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 72e90d59da07..33e1421e6f4a 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 68517a8a5c63..299dafad4502 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 e5ae03af98f2..e0f3e463415c 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 e76be244a9f8..9baadab8fcce 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 4df534ab39c4..cac8a013fcad 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 29c195cd67b4..f69e3ef52cf7 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 8f189d794e5c..fea904630ffb 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 df3edb7e6ea2..bc15f9040e46 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 5fc5397537f4..1a0a3580efd7 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 00eb4aa3f62e..ee5a9bd32481 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 8e66aebfe0c8..b957c808b37f 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