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>
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..f69e3ef5 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