diff options
Diffstat (limited to 'connectivity/source/drivers')
16 files changed, 510 insertions, 14 deletions
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 |