summaryrefslogtreecommitdiffstats
path: root/connectivity/source/drivers/file
diff options
context:
space:
mode:
Diffstat (limited to 'connectivity/source/drivers/file')
-rw-r--r--connectivity/source/drivers/file/FCatalog.cxx103
-rw-r--r--connectivity/source/drivers/file/FColumns.cxx80
-rw-r--r--connectivity/source/drivers/file/FConnection.cxx432
-rw-r--r--connectivity/source/drivers/file/FDatabaseMetaData.cxx1055
-rw-r--r--connectivity/source/drivers/file/FDateFunctions.cxx278
-rw-r--r--connectivity/source/drivers/file/FDriver.cxx205
-rw-r--r--connectivity/source/drivers/file/FNoException.cxx102
-rw-r--r--connectivity/source/drivers/file/FNumericFunctions.cxx242
-rw-r--r--connectivity/source/drivers/file/FPreparedStatement.cxx555
-rw-r--r--connectivity/source/drivers/file/FResultSet.cxx1593
-rw-r--r--connectivity/source/drivers/file/FResultSetMetaData.cxx188
-rw-r--r--connectivity/source/drivers/file/FStatement.cxx711
-rw-r--r--connectivity/source/drivers/file/FStringFunctions.cxx233
-rw-r--r--connectivity/source/drivers/file/FTable.cxx185
-rw-r--r--connectivity/source/drivers/file/FTables.cxx54
-rw-r--r--connectivity/source/drivers/file/fanalyzer.cxx207
-rw-r--r--connectivity/source/drivers/file/fcode.cxx373
-rw-r--r--connectivity/source/drivers/file/fcomp.cxx886
-rw-r--r--connectivity/source/drivers/file/quotedstring.cxx146
19 files changed, 7628 insertions, 0 deletions
diff --git a/connectivity/source/drivers/file/FCatalog.cxx b/connectivity/source/drivers/file/FCatalog.cxx
new file mode 100644
index 000000000..eedda26ef
--- /dev/null
+++ b/connectivity/source/drivers/file/FCatalog.cxx
@@ -0,0 +1,103 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/FCatalog.hxx>
+#include <file/FConnection.hxx>
+#include <file/FTables.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+
+
+using namespace connectivity::file;
+
+OFileCatalog::OFileCatalog(OConnection* _pCon) : connectivity::sdbcx::OCatalog(_pCon)
+ ,m_pConnection(_pCon)
+{
+}
+
+void SAL_CALL OFileCatalog::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ typedef connectivity::sdbcx::OCatalog OFileCatalog_BASE;
+ m_xMetaData.clear();
+ OFileCatalog_BASE::disposing();
+}
+
+OUString OFileCatalog::buildName(const Reference< XRow >& _xRow)
+{
+ return _xRow->getString(3);
+}
+
+void OFileCatalog::refreshTables()
+{
+ ::std::vector< OUString> aVector;
+ Sequence< OUString > aTypes;
+ Reference< XResultSet > xResult = m_xMetaData->getTables(Any(),
+ "%", "%", aTypes);
+ fillNames(xResult,aVector);
+
+ if(m_pTables)
+ m_pTables->reFill(aVector);
+ else
+ m_pTables.reset( new OTables(m_xMetaData,*this,m_aMutex,aVector) );
+}
+
+
+Any SAL_CALL OFileCatalog::queryInterface( const Type & rType )
+{
+ if( rType == cppu::UnoType<XGroupsSupplier>::get()||
+ rType == cppu::UnoType<XUsersSupplier>::get()||
+ rType == cppu::UnoType<XViewsSupplier>::get())
+ return Any();
+
+
+ typedef sdbcx::OCatalog OFileCatalog_BASE;
+ return OFileCatalog_BASE::queryInterface(rType);
+}
+
+Sequence< Type > SAL_CALL OFileCatalog::getTypes( )
+{
+ typedef sdbcx::OCatalog OFileCatalog_BASE;
+
+ Sequence< Type > aTypes = OFileCatalog_BASE::getTypes();
+ std::vector<Type> aOwnTypes;
+ aOwnTypes.reserve(aTypes.getLength());
+ const Type* pBegin = aTypes.getConstArray();
+ const Type* pEnd = pBegin + aTypes.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ {
+ if(!(*pBegin == cppu::UnoType<XGroupsSupplier>::get()||
+ *pBegin == cppu::UnoType<XUsersSupplier>::get()||
+ *pBegin == cppu::UnoType<XViewsSupplier>::get()))
+ {
+ aOwnTypes.push_back(*pBegin);
+ }
+ }
+ return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size());
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FColumns.cxx b/connectivity/source/drivers/file/FColumns.cxx
new file mode 100644
index 000000000..1b90385bf
--- /dev/null
+++ b/connectivity/source/drivers/file/FColumns.cxx
@@ -0,0 +1,80 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/FColumns.hxx>
+#include <connectivity/sdbcx/VColumn.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <file/FTable.hxx>
+
+using namespace connectivity::file;
+using namespace connectivity;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+sdbcx::ObjectType OColumns::createObject(const OUString& _rName)
+{
+ const OUString sCatalogName;
+ const OUString sSchemaName(m_pTable->getSchema());
+ const OUString sTableName(m_pTable->getName());
+ Reference< XResultSet > xResult = m_pTable->getConnection()->getMetaData()->getColumns(Any(),
+ sSchemaName, sTableName, _rName);
+
+ sdbcx::ObjectType xRet;
+ if(xResult.is())
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while(xResult->next())
+ {
+ if(xRow->getString(4) == _rName)
+ {
+ xRet = new sdbcx::OColumn(_rName,
+ xRow->getString(6),
+ xRow->getString(13),
+ xRow->getString(12),
+ xRow->getInt(11),
+ xRow->getInt(7),
+ xRow->getInt(9),
+ xRow->getInt(5),
+ false,
+ false,
+ false,
+ m_pTable->getConnection()->getMetaData()->supportsMixedCaseQuotedIdentifiers(),
+ sCatalogName,
+ sSchemaName,
+ sTableName);
+ break;
+ }
+ }
+ }
+
+ return xRet;
+}
+
+void OColumns::impl_refresh()
+{
+ m_pTable->refreshColumns();
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FConnection.cxx b/connectivity/source/drivers/file/FConnection.cxx
new file mode 100644
index 000000000..90030abb5
--- /dev/null
+++ b/connectivity/source/drivers/file/FConnection.cxx
@@ -0,0 +1,432 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <comphelper/processfactory.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <file/FConnection.hxx>
+#include <file/FDatabaseMetaData.hxx>
+#include <file/FDriver.hxx>
+#include <file/FStatement.hxx>
+#include <file/FPreparedStatement.hxx>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/ucb/ContentCreationException.hpp>
+#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/ucb/XContentIdentifier.hpp>
+#include <tools/urlobj.hxx>
+#include <file/FCatalog.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/pathoptions.hxx>
+#include <ucbhelper/content.hxx>
+#include <connectivity/dbcharset.hxx>
+#include <connectivity/dbexception.hxx>
+#include <o3tl/any.hxx>
+#include <osl/thread.h>
+#include <strings.hrc>
+
+using namespace connectivity::file;
+using namespace dbtools;
+
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+using namespace com::sun::star::ucb;
+using namespace ::ucbhelper;
+typedef connectivity::OMetaConnection OConnection_BASE;
+
+OConnection::OConnection(OFileDriver* _pDriver)
+ : m_pDriver(_pDriver)
+ , m_bAutoCommit(false)
+ , m_bReadOnly(false)
+ , m_bShowDeleted(false)
+ , m_bCaseSensitiveExtension( true )
+ , m_bCheckSQL92(false)
+ , m_bDefaultTextEncoding(false)
+{
+ m_nTextEncoding = RTL_TEXTENCODING_DONTKNOW;
+}
+
+OConnection::~OConnection()
+{
+ if(!isClosed( ))
+ close();
+}
+
+bool OConnection::matchesExtension( const OUString& _rExt ) const
+{
+ if ( isCaseSensitiveExtension() )
+ return ( getExtension() == _rExt );
+
+ OUString sMyExtension( getExtension().toAsciiLowerCase() );
+ OUString sExt( _rExt.toAsciiLowerCase() );
+
+ return sMyExtension == sExt;
+}
+
+
+void OConnection::construct(const OUString& url,const Sequence< PropertyValue >& info)
+{
+ osl_atomic_increment( &m_refCount );
+
+ OUString aExt;
+ const PropertyValue *pIter = info.getConstArray();
+ const PropertyValue *pEnd = pIter + info.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if( pIter->Name == "Extension" )
+ OSL_VERIFY( pIter->Value >>= aExt );
+ else if( pIter->Name == "CharSet" )
+ {
+ if (auto const numeric = o3tl::tryAccess<sal_uInt16>(pIter->Value))
+ {
+ m_nTextEncoding = *numeric;
+ }
+ else
+ {
+ OUString sIanaName;
+ OSL_VERIFY( pIter->Value >>= sIanaName );
+
+ ::dbtools::OCharsetMap aLookupIanaName;
+ ::dbtools::OCharsetMap::const_iterator aLookup = aLookupIanaName.findIanaName(sIanaName);
+ if (aLookup != aLookupIanaName.end())
+ m_nTextEncoding = (*aLookup).getEncoding();
+ else
+ m_nTextEncoding = RTL_TEXTENCODING_DONTKNOW;
+ }
+ }
+ else if( pIter->Name == "ShowDeleted" )
+ {
+ OSL_VERIFY( pIter->Value >>= m_bShowDeleted );
+ }
+ else if( pIter->Name == "EnableSQL92Check" )
+ {
+ pIter->Value >>= m_bCheckSQL92;
+ }
+ } // for(;pIter != pEnd;++pIter)
+
+ {
+ sal_Int32 nLen = url.indexOf(':');
+ nLen = url.indexOf(':',nLen+1);
+ OUString aDSN(url.copy(nLen+1));
+
+ OUString aFileName = aDSN;
+ INetURLObject aURL;
+ aURL.SetSmartProtocol(INetProtocol::File);
+ if (!utl::ConfigManager::IsFuzzing())
+ {
+ SvtPathOptions aPathOptions;
+ aFileName = aPathOptions.SubstituteVariable(aFileName);
+ }
+
+ aURL.SetSmartURL(aFileName);
+
+ setURL(aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE));
+ }
+
+ if ( m_nTextEncoding == RTL_TEXTENCODING_DONTKNOW )
+ {
+ //m_nTextEncoding = osl_getTextEncodingFromLocale(NULL);
+ m_nTextEncoding = osl_getThreadTextEncoding();
+ m_bDefaultTextEncoding = true;
+ }
+
+ if ( !aExt.isEmpty() )
+ m_aFilenameExtension = aExt;
+
+ try
+ {
+ ::ucbhelper::Content aFile;
+ try
+ {
+ aFile = ::ucbhelper::Content(getURL(), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext());
+ }
+ catch(ContentCreationException& e)
+ {
+ throwUrlNotValid(getURL(),e.Message);
+ }
+
+ // set fields to fetch
+ Sequence< OUString > aProps { "Title" };
+
+ try
+ {
+ if (aFile.isFolder())
+ {
+ m_xDir = aFile.createDynamicCursor(aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY );
+ m_xContent = aFile.get();
+ }
+ else if (aFile.isDocument())
+ {
+ Reference<XContent> xParent(Reference<XChild>(aFile.get(),UNO_QUERY_THROW)->getParent(),UNO_QUERY_THROW);
+ Reference<XContentIdentifier> xIdent = xParent->getIdentifier();
+ m_xContent = xParent;
+
+ ::ucbhelper::Content aParent(xIdent->getContentIdentifier(), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext());
+ m_xDir = aParent.createDynamicCursor(aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY );
+ }
+ else
+ {
+ OSL_FAIL("OConnection::construct: ::ucbhelper::Content is neither a folder nor a document! How's that?!");
+ throw SQLException();
+ }
+ }
+ catch(Exception& e) // an exception is thrown when no file exists
+ {
+ throwUrlNotValid(getURL(),e.Message);
+ }
+ if(!m_xDir.is() || !m_xContent.is())
+ throwUrlNotValid(getURL(),OUString());
+
+ if (m_aFilenameExtension.indexOf('*') >= 0 || m_aFilenameExtension.indexOf('?') >= 0)
+ throw SQLException();
+ }
+ catch(const Exception&)
+ {
+ osl_atomic_decrement( &m_refCount );
+ throw;
+ }
+
+ osl_atomic_decrement( &m_refCount );
+}
+// XServiceInfo
+
+IMPLEMENT_SERVICE_INFO(OConnection, "com.sun.star.sdbc.drivers.file.Connection", "com.sun.star.sdbc.Connection")
+
+
+Reference< XStatement > SAL_CALL OConnection::createStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ Reference< XStatement > xReturn = new OStatement(this);
+ m_aStatements.push_back(WeakReferenceHelper(xReturn));
+ return xReturn;
+}
+
+Reference< XPreparedStatement > SAL_CALL OConnection::prepareStatement( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ rtl::Reference<OPreparedStatement> pStmt = new OPreparedStatement(this);
+ pStmt->construct(sql);
+ m_aStatements.push_back(WeakReferenceHelper(*pStmt));
+ return pStmt;
+}
+
+Reference< XPreparedStatement > SAL_CALL OConnection::prepareCall( const OUString& /*sql*/ )
+{
+ throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this );
+ return nullptr;
+}
+
+OUString SAL_CALL OConnection::nativeSQL( const OUString& sql )
+{
+ return sql;
+}
+
+void SAL_CALL OConnection::setAutoCommit( sal_Bool autoCommit )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ m_bAutoCommit = autoCommit;
+}
+
+sal_Bool SAL_CALL OConnection::getAutoCommit( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ return m_bAutoCommit;
+}
+
+void SAL_CALL OConnection::commit( )
+{
+}
+
+void SAL_CALL OConnection::rollback( )
+{
+}
+
+sal_Bool SAL_CALL OConnection::isClosed( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ return OConnection_BASE::rBHelper.bDisposed;
+}
+
+Reference< XDatabaseMetaData > SAL_CALL OConnection::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ Reference< XDatabaseMetaData > xMetaData = m_xMetaData;
+ if(!xMetaData.is())
+ {
+ xMetaData = new ODatabaseMetaData(this);
+ m_xMetaData = xMetaData;
+ }
+
+ return xMetaData;
+}
+
+void SAL_CALL OConnection::setReadOnly( sal_Bool readOnly )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ m_bReadOnly = readOnly;
+}
+
+sal_Bool SAL_CALL OConnection::isReadOnly( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+
+ return m_bReadOnly;
+}
+
+void SAL_CALL OConnection::setCatalog( const OUString& /*catalog*/ )
+{
+ throwFeatureNotImplementedSQLException( "XConnection::setCatalog", *this );
+}
+
+OUString SAL_CALL OConnection::getCatalog( )
+{
+ return OUString();
+}
+
+void SAL_CALL OConnection::setTransactionIsolation( sal_Int32 /*level*/ )
+{
+ throwFeatureNotImplementedSQLException( "XConnection::setTransactionIsolation", *this );
+}
+
+sal_Int32 SAL_CALL OConnection::getTransactionIsolation( )
+{
+ return 0;
+}
+
+Reference< XNameAccess > SAL_CALL OConnection::getTypeMap( )
+{
+ return nullptr;
+}
+
+void SAL_CALL OConnection::setTypeMap( const Reference< XNameAccess >& /*typeMap*/ )
+{
+}
+
+// XCloseable
+void SAL_CALL OConnection::close( )
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OConnection_BASE::rBHelper.bDisposed);
+
+ }
+ dispose();
+}
+
+// XWarningsSupplier
+Any SAL_CALL OConnection::getWarnings( )
+{
+ return Any();
+}
+
+void SAL_CALL OConnection::clearWarnings( )
+{
+}
+
+void OConnection::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ OConnection_BASE::disposing();
+
+ m_xDir.clear();
+ m_xContent.clear();
+ m_xCatalog = WeakReference< XTablesSupplier>();
+}
+
+Reference< XTablesSupplier > OConnection::createCatalog()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Reference< XTablesSupplier > xTab = m_xCatalog;
+ if(!xTab.is())
+ {
+ xTab = new OFileCatalog(this);
+ m_xCatalog = xTab;
+ }
+ return xTab;
+}
+
+Reference< XDynamicResultSet > OConnection::getDir() const
+{
+ Reference<XDynamicResultSet> xContent;
+ Sequence< OUString > aProps { "Title" };
+ try
+ {
+ Reference<XContentIdentifier> xIdent = getContent()->getIdentifier();
+ ::ucbhelper::Content aParent(xIdent->getContentIdentifier(), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext());
+ xContent = aParent.createDynamicCursor(aProps, ::ucbhelper::INCLUDE_DOCUMENTS_ONLY );
+ }
+ catch(Exception&)
+ {
+ }
+ return xContent;
+}
+
+sal_Int64 SAL_CALL OConnection::getSomething( const Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+const Sequence< sal_Int8 > & OConnection::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+void OConnection::throwUrlNotValid(const OUString & _rsUrl,const OUString & _rsMessage)
+{
+ SQLException aError;
+ aError.Message = getResources().getResourceStringWithSubstitution(
+ STR_NO_VALID_FILE_URL,
+ "$URL$", _rsUrl
+ );
+
+ aError.SQLState = "S1000";
+ aError.ErrorCode = 0;
+ aError.Context = static_cast< XConnection* >(this);
+ if (!_rsMessage.isEmpty())
+ aError.NextException <<= SQLException(_rsMessage, aError.Context, OUString(), 0, Any());
+
+ throw aError;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FDatabaseMetaData.cxx b/connectivity/source/drivers/file/FDatabaseMetaData.cxx
new file mode 100644
index 000000000..6d0a4f2fe
--- /dev/null
+++ b/connectivity/source/drivers/file/FDatabaseMetaData.cxx
@@ -0,0 +1,1055 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <config_fuzzers.h>
+
+#include <file/FDatabaseMetaData.hxx>
+#include <FDatabaseMetaDataResultSet.hxx>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/ucb/UniversalContentBroker.hpp>
+#include <com/sun/star/ucb/SortedDynamicResultSetFactory.hpp>
+#include <tools/urlobj.hxx>
+#include <sal/log.hxx>
+#include <file/FDriver.hxx>
+#include <file/FTable.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <ucbhelper/content.hxx>
+
+using namespace com::sun::star::ucb;
+using namespace connectivity::file;
+using namespace connectivity;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+
+ODatabaseMetaData::ODatabaseMetaData(OConnection* _pCon) : ::connectivity::ODatabaseMetaDataBase(_pCon,_pCon->getConnectionInfo())
+ ,m_pConnection(_pCon)
+{
+}
+
+ODatabaseMetaData::~ODatabaseMetaData()
+{
+}
+
+Reference< XResultSet > ODatabaseMetaData::impl_getTypeInfo_throw( )
+{
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTypeInfo );
+}
+
+OUString ODatabaseMetaData::impl_getCatalogSeparator_throw( )
+{
+ return OUString();
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getColumns(
+ const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& /*tableNamePattern*/,
+ const OUString& /*columnNamePattern*/ )
+{
+ SAL_WARN("connectivity.drivers", "ODatabaseMetaData::getColumns() should be overridden!");
+ return new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eColumns );
+}
+
+
+namespace
+{
+#if !ENABLE_FUZZERS
+ sal_Int16 isCaseSensitiveParentFolder( const OUString& _rFolderOrDoc, std::u16string_view _rDocName )
+ {
+ sal_Int16 nIsCS = 1;
+ try
+ {
+ // first get the real content for the URL
+ INetURLObject aContentURL( _rFolderOrDoc );
+ ::ucbhelper::Content aContent1;
+ {
+ ::ucbhelper::Content aFolderOrDoc( _rFolderOrDoc, Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+ if ( aFolderOrDoc.isDocument() )
+ aContent1 = aFolderOrDoc;
+ else
+ {
+ aContentURL = INetURLObject( _rFolderOrDoc, INetURLObject::EncodeMechanism::WasEncoded );
+ aContentURL.Append( _rDocName );
+ aContent1 = ::ucbhelper::Content( aContentURL.GetMainURL( INetURLObject::DecodeMechanism::NONE ), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+ }
+ }
+
+ // get two extensions which differ by case only
+ OUString sExtension1(aContentURL.getExtension());
+ OUString sExtension2(sExtension1.toAsciiLowerCase());
+ if (sExtension2 == sExtension1)
+ {
+ // the extension was already in lower case
+ sExtension2 = sExtension2.toAsciiUpperCase();
+ }
+
+ // the complete URL for the second extension
+ INetURLObject aURL2( aContentURL );
+ if (!sExtension2.isEmpty())
+ aURL2.SetExtension( sExtension2 );
+ if ( aURL2.GetMainURL(INetURLObject::DecodeMechanism::NONE) == aContentURL.GetMainURL(INetURLObject::DecodeMechanism::NONE) )
+ return -1;
+
+ // the second context
+ bool bCanAccess = false;
+ ::ucbhelper::Content aContent2;
+ try
+ {
+ aContent2 = ::ucbhelper::Content( aURL2.GetMainURL( INetURLObject::DecodeMechanism::NONE ), Reference< XCommandEnvironment >(), comphelper::getProcessComponentContext() );
+ bCanAccess = aContent2.isDocument();
+ }
+ catch( const Exception& )
+ {
+ }
+
+ if ( bCanAccess )
+ {
+ // here we have two contents whose URLs differ by case only.
+ // Now let's check if both really refer to the same object...
+ Reference< XContent > xContent1 = aContent1.get();
+ Reference< XContent > xContent2 = aContent2.get();
+ OSL_ENSURE( xContent1.is() && xContent2.is(), "isCaseSensitiveParentFolder: invalid content interfaces!" );
+ if ( xContent1.is() && xContent2.is() )
+ {
+ Reference< XContentIdentifier > xID1 = xContent1->getIdentifier();
+ Reference< XContentIdentifier > xID2 = xContent2->getIdentifier();
+ OSL_ENSURE( xID1.is() && xID2.is(), "isCaseSensitiveParentFolder: invalid ID interfaces!" );
+ if ( xID1.is() && xID2.is()
+ && ( UniversalContentBroker::create(
+ comphelper::getProcessComponentContext() )->
+ compareContentIds( xID1, xID2 ) == 0 ) )
+ {
+ // finally, we know that the folder is not case-sensitive...
+ nIsCS = 0;
+ }
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.drivers", "isCaseSensitiveParentFolder" );
+ }
+
+ return nIsCS;
+ }
+#endif
+}
+
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTables(
+ const Any& /*catalog*/, const OUString& /*schemaPattern*/,
+ const OUString& tableNamePattern, const Sequence< OUString >& types )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTables );
+
+ // check if any type is given
+ // when no types are given then we have to return all tables e.g. TABLE
+
+ static constexpr OUStringLiteral aTable = u"TABLE";
+
+ bool bTableFound = true;
+ sal_Int32 nLength = types.getLength();
+ if(nLength)
+ {
+ bTableFound = false;
+
+ const OUString* pBegin = types.getConstArray();
+ const OUString* pEnd = pBegin + nLength;
+ for(;pBegin != pEnd;++pBegin)
+ {
+ if(*pBegin == aTable)
+ {
+ bTableFound = true;
+ break;
+ }
+ }
+ }
+ if(!bTableFound)
+ return pResult;
+
+ Reference<XDynamicResultSet> xContent = m_pConnection->getDir();
+ Reference < XSortedDynamicResultSetFactory > xSRSFac =
+ SortedDynamicResultSetFactory::create( m_pConnection->getDriver()->getComponentContext() );
+
+ Sequence< NumberedSortingInfo > aSortInfo( 1 );
+ NumberedSortingInfo* pInfo = aSortInfo.getArray();
+ pInfo[ 0 ].ColumnIndex = 1;
+ pInfo[ 0 ].Ascending = true;
+
+ Reference < XAnyCompareFactory > xFactory;
+ Reference< XDynamicResultSet > xDynamicResultSet = xSRSFac->createSortedDynamicResultSet( xContent, aSortInfo, xFactory );
+ Reference<XResultSet> xResultSet = xDynamicResultSet->getStaticResultSet();
+
+ Reference<XRow> xRow(xResultSet,UNO_QUERY);
+
+ OUString aFilenameExtension = m_pConnection->getExtension();
+ OUString sThisContentExtension;
+ ODatabaseMetaDataResultSet::ORows aRows;
+ // scan the directory for tables
+ OUString aName;
+ INetURLObject aURL;
+ xResultSet->beforeFirst();
+
+ bool bKnowCaseSensitivity = false;
+ bool bCaseSensitiveDir = true;
+ bool bCheckEnabled = m_pConnection->isCheckEnabled();
+
+ while(xResultSet->next())
+ {
+ aName = xRow->getString(1);
+ aURL.SetSmartProtocol(INetProtocol::File);
+ OUString sUrl = m_pConnection->getURL() + "/" + aName;
+ aURL.SetSmartURL( sUrl );
+ sThisContentExtension = aURL.getExtension();
+
+ ODatabaseMetaDataResultSet::ORow aRow { nullptr, nullptr, nullptr };
+ aRow.reserve(6);
+ bool bNewRow = false;
+
+ if ( !bKnowCaseSensitivity )
+ {
+ bKnowCaseSensitivity = true;
+#if ENABLE_FUZZERS
+ sal_Int16 nCase = 1;
+#else
+ sal_Int16 nCase = isCaseSensitiveParentFolder( m_pConnection->getURL(), aURL.getName() );
+#endif
+ switch( nCase )
+ {
+ case 1:
+ bCaseSensitiveDir = true;
+ break;
+ case -1:
+ bKnowCaseSensitivity = false;
+ [[fallthrough]];
+ case 0:
+ bCaseSensitiveDir = false;
+ }
+ if ( bKnowCaseSensitivity )
+ {
+ m_pConnection->setCaseSensitiveExtension( bCaseSensitiveDir, OConnection::GrantAccess() );
+ if ( !bCaseSensitiveDir )
+ {
+ aFilenameExtension = aFilenameExtension.toAsciiLowerCase();
+ }
+ }
+ }
+
+ if (!aFilenameExtension.isEmpty())
+ {
+ if ( !bCaseSensitiveDir )
+ {
+ sThisContentExtension = sThisContentExtension.toAsciiLowerCase();
+ }
+
+ if ( sThisContentExtension == aFilenameExtension )
+ {
+ aName = aName.copy(0, (aName.getLength()-(aFilenameExtension.getLength()+1)));
+ sal_Unicode nChar = aName.toChar();
+ if ( match(tableNamePattern,aName,'\0') && ( !bCheckEnabled || (nChar < '0' || nChar > '9')) )
+ {
+ aRow.push_back(new ORowSetValueDecorator(aName));
+ bNewRow = true;
+ }
+ }
+ }
+ else // no extension, filter myself
+ {
+ for (;;)
+ {
+ if (aURL.getExtension().isEmpty())
+ {
+ sal_Unicode nChar = aURL.getBase()[0];
+ if( match(tableNamePattern,aURL.getBase(),'\0') && ( !bCheckEnabled || nChar < '0' || nChar > '9' ) )
+ {
+ aRow.push_back(new ORowSetValueDecorator(aURL.getBase()));
+ bNewRow = true;
+ }
+ break;
+ }
+ if ( !xResultSet->next() )
+ {
+ break;
+ }
+ aName = xRow->getString(1);
+ aURL.SetSmartURL(aName);
+ }
+ }
+ if(bNewRow)
+ {
+ aRow.push_back(new ORowSetValueDecorator(OUString(aTable)));
+ aRow.push_back(ODatabaseMetaDataResultSet::getEmptyValue());
+
+ aRows.push_back(aRow);
+ }
+ }
+
+ pResult->setRows(std::move(aRows));
+
+ return pResult;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxBinaryLiteralLength( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxRowSize( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCatalogNameLength( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCharLiteralLength( )
+{
+ return SAL_MAX_INT32;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnNameLength( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInIndex( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxCursorNameLength( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxConnections( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInTable( )
+{
+ return 0;
+}
+
+sal_Int32 ODatabaseMetaData::impl_getMaxStatements_throw( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxTableNameLength( )
+{
+ return 0;
+}
+
+sal_Int32 ODatabaseMetaData::impl_getMaxTablesInSelect_throw( )
+{
+ return 1;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTablePrivileges(
+ const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& tableNamePattern )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTablePrivileges );
+ ODatabaseMetaDataResultSet::ORows aRows;
+
+ Reference< XTablesSupplier > xTabSup = m_pConnection->createCatalog();
+ if( xTabSup.is())
+ {
+ Reference< XNameAccess> xNames = xTabSup->getTables();
+ Sequence< OUString > aNames = xNames->getElementNames();
+ const OUString* pBegin = aNames.getConstArray();
+ const OUString* pEnd = pBegin + aNames.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ {
+ if(match(tableNamePattern,*pBegin,'\0'))
+ {
+ ODatabaseMetaDataResultSet::ORow aRow(8);
+
+ aRow[2] = new ORowSetValueDecorator(*pBegin);
+ aRow[6] = ODatabaseMetaDataResultSet::getSelectValue();
+ aRow[7] = new ORowSetValueDecorator(OUString("NO"));
+ aRows.push_back(aRow);
+
+ Reference< XPropertySet> xTable(
+ xNames->getByName(*pBegin), css::uno::UNO_QUERY);
+ if(xTable.is())
+ {
+ auto pTable = comphelper::getFromUnoTunnel<OFileTable>(xTable);
+ if(pTable && !pTable->isReadOnly())
+ {
+ aRow[6] = ODatabaseMetaDataResultSet::getInsertValue();
+ aRows.push_back(aRow);
+ if(!m_pConnection->showDeleted())
+ {
+ aRow[6] = ODatabaseMetaDataResultSet::getDeleteValue();
+ aRows.push_back(aRow);
+ }
+ aRow[6] = ODatabaseMetaDataResultSet::getUpdateValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getCreateValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getReadValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getAlterValue();
+ aRows.push_back(aRow);
+ aRow[6] = ODatabaseMetaDataResultSet::getDropValue();
+ aRows.push_back(aRow);
+ }
+ }
+ }
+ }
+ }
+
+ pResult->setRows(std::move(aRows));
+ return pResult;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::doesMaxRowSizeIncludeBlobs( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseQuotedIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesLowerCaseIdentifiers( )
+{
+ return false;
+}
+
+bool ODatabaseMetaData::impl_storesMixedCaseQuotedIdentifiers_throw( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesMixedCaseIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseQuotedIdentifiers( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::storesUpperCaseIdentifiers( )
+{
+ return false;
+}
+
+bool ODatabaseMetaData::impl_supportsAlterTableWithAddColumn_throw( )
+{
+ return false;
+}
+
+bool ODatabaseMetaData::impl_supportsAlterTableWithDropColumn_throw( )
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxIndexLength( )
+{
+ return 0;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsNonNullableColumns( )
+{
+ return false;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getCatalogTerm( )
+{
+ return OUString();
+}
+
+OUString ODatabaseMetaData::impl_getIdentifierQuoteString_throw( )
+{
+ return "\"";
+}
+
+OUString SAL_CALL ODatabaseMetaData::getExtraNameCharacters( )
+{
+ return OUString();
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsDifferentTableCorrelationNames( )
+{
+ return true;
+}
+
+bool ODatabaseMetaData::impl_isCatalogAtStart_throw( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionIgnoredInTransactions( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::dataDefinitionCausesTransactionCommit( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsDataManipulationTransactionsOnly( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsDataDefinitionAndDataManipulationTransactions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedDelete( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsPositionedUpdate( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossRollback( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenStatementsAcrossCommit( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossCommit( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOpenCursorsAcrossRollback( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactionIsolationLevel( sal_Int32 /*level*/ )
+{
+ return false;
+}
+
+bool ODatabaseMetaData::impl_supportsSchemasInDataManipulation_throw( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92FullSQL( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92EntryLevelSQL( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsIntegrityEnhancementFacility( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInIndexDefinitions( )
+{
+ return false;
+}
+
+bool ODatabaseMetaData::impl_supportsSchemasInTableDefinitions_throw( )
+{
+ return false;
+}
+
+bool ODatabaseMetaData::impl_supportsCatalogsInTableDefinitions_throw( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInIndexDefinitions( )
+{
+ return false;
+}
+
+bool ODatabaseMetaData::impl_supportsCatalogsInDataManipulation_throw( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOuterJoins( )
+{
+ return false;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getTableTypes( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ rtl::Reference<ODatabaseMetaDataResultSet> pResult = new ODatabaseMetaDataResultSet( ODatabaseMetaDataResultSet::eTableTypes );
+ static ODatabaseMetaDataResultSet::ORows aRows;
+ if(aRows.empty())
+ {
+ aRows.push_back( { ODatabaseMetaDataResultSet::getEmptyValue(), new ORowSetValueDecorator(OUString("TABLE")) } );
+ }
+ pResult->setRows(std::move(aRows));
+ return pResult;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxStatementLength( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxProcedureNameLength( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxSchemaNameLength( )
+{
+ return 0;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTransactions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::allProceduresAreCallable( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsStoredProcedures( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSelectForUpdate( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::allTablesAreSelectable( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::isReadOnly( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFiles( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::usesLocalFilePerTable( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTypeConversion( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullPlusNonNullIsNull( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsColumnAliasing( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsTableCorrelationNames( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsConvert( sal_Int32 /*fromType*/, sal_Int32 /*toType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsExpressionsInOrderBy( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupBy( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByBeyondSelect( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsGroupByUnrelated( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleTransactions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMultipleResultSets( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsLikeEscapeClause( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsOrderByUnrelated( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsUnion( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsUnionAll( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMixedCaseIdentifiers( )
+{
+ return true;
+}
+
+bool ODatabaseMetaData::impl_supportsMixedCaseQuotedIdentifiers_throw( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtEnd( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedAtStart( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedHigh( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::nullsAreSortedLow( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInProcedureCalls( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSchemasInPrivilegeDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInProcedureCalls( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCatalogsInPrivilegeDefinitions( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCorrelatedSubqueries( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInComparisons( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInExists( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInIns( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsSubqueriesInQuantifieds( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsANSI92IntermediateSQL( )
+{
+ return false;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getURL( )
+{
+ return "sdbc:file:";
+}
+
+OUString SAL_CALL ODatabaseMetaData::getUserName( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDriverName( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDriverVersion( )
+{
+ return OUString::number(1);
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDatabaseProductVersion( )
+{
+ return OUString::number(0);
+}
+
+OUString SAL_CALL ODatabaseMetaData::getDatabaseProductName( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getProcedureTerm( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSchemaTerm( )
+{
+ return OUString();
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMajorVersion( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDefaultTransactionIsolation( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getDriverMinorVersion( )
+{
+ return 0;
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSQLKeywords( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSearchStringEscape( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getStringFunctions( )
+{
+ return "UCASE,LCASE,ASCII,LENGTH,OCTET_LENGTH,CHAR_LENGTH,CHARACTER_LENGTH,CHAR,CONCAT,LOCATE,SUBSTRING,LTRIM,RTRIM,SPACE,REPLACE,REPEAT,INSERT,LEFT,RIGHT";
+}
+
+OUString SAL_CALL ODatabaseMetaData::getTimeDateFunctions( )
+{
+ return "DAYOFWEEK,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,MONTHNAME,QUARTER,WEEK,YEAR,HOUR,MINUTE,SECOND,CURDATE,CURTIME,NOW";
+}
+
+OUString SAL_CALL ODatabaseMetaData::getSystemFunctions( )
+{
+ return OUString();
+}
+
+OUString SAL_CALL ODatabaseMetaData::getNumericFunctions( )
+{
+ return "ABS,SIGN,MOD,FLOOR,CEILING,ROUND,EXP,LN,LOG,LOG10,POWER,SQRT,PI,COS,SIN,TAN,ACOS,ASIN,ATAN,ATAN2,DEGREES,RADIANS";
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsExtendedSQLGrammar( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsCoreSQLGrammar( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsMinimumSQLGrammar( )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsFullOuterJoins( )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsLimitedOuterJoins( )
+{
+ return false;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInGroupBy( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInOrderBy( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxColumnsInSelect( )
+{
+ return 0;
+}
+
+sal_Int32 SAL_CALL ODatabaseMetaData::getMaxUserNameLength( )
+{
+ return 0;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetType( sal_Int32 setType )
+{
+ switch(setType)
+ {
+ case ResultSetType::FORWARD_ONLY:
+ return true;
+ case ResultSetType::SCROLL_INSENSITIVE:
+ case ResultSetType::SCROLL_SENSITIVE:
+ break;
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsResultSetConcurrency( sal_Int32 setType, sal_Int32 /*concurrency*/ )
+{
+ switch(setType)
+ {
+ case ResultSetType::FORWARD_ONLY:
+ return true;
+ case ResultSetType::SCROLL_INSENSITIVE:
+ case ResultSetType::SCROLL_SENSITIVE:
+ break;
+ }
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownUpdatesAreVisible( sal_Int32 /*setType*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownDeletesAreVisible( sal_Int32 /*setType*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::ownInsertsAreVisible( sal_Int32 /*setType*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersUpdatesAreVisible( sal_Int32 /*setType*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersDeletesAreVisible( sal_Int32 /*setType*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::othersInsertsAreVisible( sal_Int32 /*setType*/ )
+{
+ return true;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::updatesAreDetected( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::deletesAreDetected( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::insertsAreDetected( sal_Int32 /*setType*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL ODatabaseMetaData::supportsBatchUpdates( )
+{
+ return false;
+}
+
+Reference< XResultSet > SAL_CALL ODatabaseMetaData::getUDTs( const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& /*typeNamePattern*/, const Sequence< sal_Int32 >& /*types*/ )
+{
+ return nullptr;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FDateFunctions.cxx b/connectivity/source/drivers/file/FDateFunctions.cxx
new file mode 100644
index 000000000..1be992d4b
--- /dev/null
+++ b/connectivity/source/drivers/file/FDateFunctions.cxx
@@ -0,0 +1,278 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/FDateFunctions.hxx>
+#include <tools/date.hxx>
+#include <tools/time.hxx>
+#include <tools/datetime.hxx>
+#include <osl/diagnose.h>
+
+using namespace connectivity;
+using namespace connectivity::file;
+
+ORowSetValue OOp_DayOfWeek::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ sal_Int32 nRet = 0;
+ css::util::Date aD = lhs.getDate();
+ Date aDate(aD.Day, aD.Month, aD.Year);
+ DayOfWeek eDayOfWeek = aDate.GetDayOfWeek();
+ switch (eDayOfWeek)
+ {
+ case MONDAY:
+ nRet = 2;
+ break;
+ case TUESDAY:
+ nRet = 3;
+ break;
+ case WEDNESDAY:
+ nRet = 4;
+ break;
+ case THURSDAY:
+ nRet = 5;
+ break;
+ case FRIDAY:
+ nRet = 6;
+ break;
+ case SATURDAY:
+ nRet = 7;
+ break;
+ case SUNDAY:
+ nRet = 1;
+ break;
+ default:
+ OSL_FAIL("Error in enum values for date");
+ }
+ return nRet;
+}
+
+ORowSetValue OOp_DayOfMonth::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ css::util::Date aD = lhs.getDate();
+ return static_cast<sal_Int16>(aD.Day);
+}
+
+ORowSetValue OOp_DayOfYear::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ css::util::Date aD = lhs.getDate();
+ Date aDate(aD.Day, aD.Month, aD.Year);
+ return static_cast<sal_Int16>(aDate.GetDayOfYear());
+}
+
+ORowSetValue OOp_Month::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ css::util::Date aD = lhs.getDate();
+ return static_cast<sal_Int16>(aD.Month);
+}
+
+ORowSetValue OOp_DayName::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ OUString sRet;
+ css::util::Date aD = lhs.getDate();
+ Date aDate(aD.Day, aD.Month, aD.Year);
+ DayOfWeek eDayOfWeek = aDate.GetDayOfWeek();
+ switch (eDayOfWeek)
+ {
+ case MONDAY:
+ sRet = "Monday";
+ break;
+ case TUESDAY:
+ sRet = "Tuesday";
+ break;
+ case WEDNESDAY:
+ sRet = "Wednesday";
+ break;
+ case THURSDAY:
+ sRet = "Thursday";
+ break;
+ case FRIDAY:
+ sRet = "Friday";
+ break;
+ case SATURDAY:
+ sRet = "Saturday";
+ break;
+ case SUNDAY:
+ sRet = "Sunday";
+ break;
+ default:
+ OSL_FAIL("Error in enum values for date");
+ }
+ return sRet;
+}
+
+ORowSetValue OOp_MonthName::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ OUString sRet;
+ css::util::Date aD = lhs.getDate();
+ switch (aD.Month)
+ {
+ case 1:
+ sRet = "January";
+ break;
+ case 2:
+ sRet = "February";
+ break;
+ case 3:
+ sRet = "March";
+ break;
+ case 4:
+ sRet = "April";
+ break;
+ case 5:
+ sRet = "May";
+ break;
+ case 6:
+ sRet = "June";
+ break;
+ case 7:
+ sRet = "July";
+ break;
+ case 8:
+ sRet = "August";
+ break;
+ case 9:
+ sRet = "September";
+ break;
+ case 10:
+ sRet = "October";
+ break;
+ case 11:
+ sRet = "November";
+ break;
+ case 12:
+ sRet = "December";
+ break;
+ }
+ return sRet;
+}
+
+ORowSetValue OOp_Quarter::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ sal_Int32 nRet = 1;
+ css::util::Date aD = lhs.getDate();
+ if (aD.Month >= 4 && aD.Month < 7)
+ nRet = 2;
+ else if (aD.Month >= 7 && aD.Month < 10)
+ nRet = 3;
+ else if (aD.Month >= 10 && aD.Month <= 12)
+ nRet = 4;
+ return nRet;
+}
+
+ORowSetValue OOp_Week::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (lhs.empty() || lhs.size() > 2)
+ return ORowSetValue();
+
+ size_t nSize = lhs.size();
+
+ css::util::Date aD = lhs[nSize - 1].getDate();
+ Date aDate(aD.Day, aD.Month, aD.Year);
+
+ sal_Int16 nStartDay = SUNDAY;
+ if (nSize == 2 && !lhs[0].isNull())
+ nStartDay = lhs[0].getInt16();
+
+ return static_cast<sal_Int16>(aDate.GetWeekOfYear(static_cast<DayOfWeek>(nStartDay)));
+}
+
+ORowSetValue OOp_Year::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ css::util::Date aD = lhs.getDate();
+ return aD.Year;
+}
+
+ORowSetValue OOp_Hour::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ css::util::Time aT = lhs.getTime();
+ return static_cast<sal_Int16>(aT.Hours);
+}
+
+ORowSetValue OOp_Minute::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ css::util::Time aT = lhs.getTime();
+ return static_cast<sal_Int16>(aT.Minutes);
+}
+
+ORowSetValue OOp_Second::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ css::util::Time aT = lhs.getTime();
+ return static_cast<sal_Int16>(aT.Seconds);
+}
+
+ORowSetValue OOp_CurDate::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (!lhs.empty())
+ return ORowSetValue();
+
+ Date aCurDate(Date::SYSTEM);
+ return aCurDate.GetUNODate();
+}
+
+ORowSetValue OOp_CurTime::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (!lhs.empty())
+ return ORowSetValue();
+
+ tools::Time aCurTime(tools::Time::SYSTEM);
+ return aCurTime.GetUNOTime();
+}
+
+ORowSetValue OOp_Now::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (!lhs.empty())
+ return ORowSetValue();
+
+ DateTime aCurTime(DateTime::SYSTEM);
+ return aCurTime.GetUNODateTime();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FDriver.cxx b/connectivity/source/drivers/file/FDriver.cxx
new file mode 100644
index 000000000..4b6d45fe7
--- /dev/null
+++ b/connectivity/source/drivers/file/FDriver.cxx
@@ -0,0 +1,205 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/FDriver.hxx>
+#include <file/FConnection.hxx>
+#include <file/fcode.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+#include <resource/sharedresources.hxx>
+
+
+using namespace connectivity::file;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+
+OFileDriver::OFileDriver(const css::uno::Reference< css::uno::XComponentContext >& _rxContext)
+ : ODriver_BASE(m_aMutex)
+ ,m_xContext(_rxContext)
+{
+}
+
+void OFileDriver::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+
+ for (auto const& connection : m_xConnections)
+ {
+ Reference< XComponent > xComp(connection.get(), UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ }
+ m_xConnections.clear();
+
+ ODriver_BASE::disposing();
+}
+
+// XServiceInfo
+
+OUString SAL_CALL OFileDriver::getImplementationName( )
+{
+ return "com.sun.star.sdbc.driver.file.Driver";
+}
+
+sal_Bool SAL_CALL OFileDriver::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+
+Sequence< OUString > SAL_CALL OFileDriver::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdbc.Driver", "com.sun.star.sdbcx.Driver" };
+}
+
+
+Reference< XConnection > SAL_CALL OFileDriver::connect( const OUString& url, const Sequence< PropertyValue >& info )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODriver_BASE::rBHelper.bDisposed);
+
+ rtl::Reference<OConnection> pCon = new OConnection(this);
+ pCon->construct(url,info);
+ m_xConnections.push_back(WeakReferenceHelper(*pCon));
+
+ return pCon;
+}
+
+sal_Bool SAL_CALL OFileDriver::acceptsURL( const OUString& url )
+{
+ return url.startsWith("sdbc:file:");
+}
+
+Sequence< DriverPropertyInfo > SAL_CALL OFileDriver::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& /*info*/ )
+{
+ if ( acceptsURL(url) )
+ {
+
+ Sequence< OUString > aBoolean { "0", "1" };
+
+ return
+ {
+ {
+ "CharSet"
+ ,"CharSet of the database."
+ ,false
+ ,{}
+ ,{}
+ },
+ {
+ "Extension"
+ ,"Extension of the file format."
+ ,false
+ ,".*"
+ ,{}
+ },
+ {
+ "ShowDeleted"
+ ,"Display inactive records."
+ ,false
+ ,"0"
+ ,aBoolean
+ },
+ {
+ "EnableSQL92Check"
+ ,"Use SQL92 naming constraints."
+ ,false
+ ,"0"
+ ,aBoolean
+ },
+ {
+ "UseRelativePath"
+ ,"Handle the connection url as relative path."
+ ,false
+ ,"0"
+ ,aBoolean
+ },
+ {
+ "URL"
+ ,"The URL of the database document which is used to create an absolute path."
+ ,false
+ ,{}
+ ,{}
+ }
+ };
+ } // if ( acceptsURL(url) )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ } // if ( ! acceptsURL(url) )
+ return Sequence< DriverPropertyInfo >();
+}
+
+sal_Int32 SAL_CALL OFileDriver::getMajorVersion( )
+{
+ return 1;
+}
+
+sal_Int32 SAL_CALL OFileDriver::getMinorVersion( )
+{
+ return 0;
+}
+
+
+// XDataDefinitionSupplier
+Reference< XTablesSupplier > SAL_CALL OFileDriver::getDataDefinitionByConnection( const Reference< css::sdbc::XConnection >& connection )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(ODriver_BASE::rBHelper.bDisposed);
+
+ if (OConnection* pSearchConnection = comphelper::getFromUnoTunnel<OConnection>(connection))
+ {
+ for (auto const& elem : m_xConnections)
+ {
+ if (static_cast<OConnection*>( Reference< XConnection >::query(elem.get()).get() ) == pSearchConnection)
+ return pSearchConnection->createCatalog();
+ }
+ }
+ return {};
+}
+
+
+Reference< XTablesSupplier > SAL_CALL OFileDriver::getDataDefinitionByURL( const OUString& url, const Sequence< PropertyValue >& info )
+{
+ if ( ! acceptsURL(url) )
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR);
+ ::dbtools::throwGenericSQLException(sMessage ,*this);
+ }
+ return getDataDefinitionByConnection(connect(url,info));
+}
+
+
+OOperandAttr::OOperandAttr(sal_uInt16 _nPos,const Reference< XPropertySet>& _xColumn)
+ : OOperandRow(_nPos,::comphelper::getINT32(_xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))))
+{
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FNoException.cxx b/connectivity/source/drivers/file/FNoException.cxx
new file mode 100644
index 000000000..920bb3885
--- /dev/null
+++ b/connectivity/source/drivers/file/FNoException.cxx
@@ -0,0 +1,102 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/FCatalog.hxx>
+#include <file/fcomp.hxx>
+#include <file/fanalyzer.hxx>
+#include <file/FResultSet.hxx>
+#include <file/FPreparedStatement.hxx>
+#include <connectivity/FValue.hxx>
+#include <tools/debug.hxx>
+#include <TKeyValue.hxx>
+
+using namespace connectivity;
+using namespace connectivity::file;
+
+void OFileCatalog::refreshViews()
+{}
+void OFileCatalog::refreshGroups()
+{}
+void OFileCatalog::refreshUsers()
+{
+}
+
+OPredicateInterpreter::~OPredicateInterpreter()
+{
+ while(!m_aStack.empty())
+ {
+ delete m_aStack.top();
+ m_aStack.pop();
+ }
+ // m_aStack.clear();
+}
+
+void OPredicateCompiler::Clean()
+{
+ m_aCodeList.clear();
+}
+
+void OSQLAnalyzer::bindParameterRow(OValueRefRow const & _pRow)
+{
+ OCodeList& rCodeList = m_aCompiler->m_aCodeList;
+ for (auto const& code : rCodeList)
+ {
+ OOperandParam* pParam = dynamic_cast<OOperandParam*>(code.get());
+ if ( pParam )
+ pParam->bindValue(_pRow);
+ }
+}
+
+void OPreparedStatement::scanParameter(OSQLParseNode* pParseNode,std::vector< OSQLParseNode*>& _rParaNodes)
+{
+ DBG_ASSERT(pParseNode != nullptr,"OResultSet: internal error: invalid ParseNode");
+
+ // found parameter Name-Rule?
+ if (SQL_ISRULE(pParseNode,parameter))
+ {
+ DBG_ASSERT(pParseNode->count() >= 1,"OResultSet: faulty Parse Tree");
+ DBG_ASSERT(pParseNode->getChild(0)->getNodeType() == SQLNodeType::Punctuation,"OResultSet: faulty Parse Tree");
+
+ _rParaNodes.push_back(pParseNode);
+ // Further descend not necessary
+ return;
+ }
+
+ // Further descend in Parse Tree
+ for (size_t i = 0; i < pParseNode->count(); i++)
+ scanParameter(pParseNode->getChild(i),_rParaNodes);
+}
+
+std::unique_ptr<OKeyValue> OResultSet::GetOrderbyKeyValue(OValueRefRow const & _rRow)
+{
+ sal_uInt32 nBookmarkValue = std::abs((*_rRow)[0]->getValue().getInt32());
+
+ std::unique_ptr<OKeyValue> pKeyValue = OKeyValue::createKeyValue(nBookmarkValue);
+
+ for (auto const& elem : m_aOrderbyColumnNumber)
+ {
+ OSL_ENSURE(elem < static_cast<sal_Int32>(_rRow->size()),"Invalid index for orderkey values!");
+ pKeyValue->pushKey(new ORowSetValueDecorator((*_rRow)[elem]->getValue()));
+ }
+
+ return pKeyValue;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FNumericFunctions.cxx b/connectivity/source/drivers/file/FNumericFunctions.cxx
new file mode 100644
index 000000000..7c7fdc754
--- /dev/null
+++ b/connectivity/source/drivers/file/FNumericFunctions.cxx
@@ -0,0 +1,242 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <cmath>
+#include <basegfx/numeric/ftools.hxx>
+#include <file/FNumericFunctions.hxx>
+#include <rtl/math.hxx>
+
+using namespace connectivity;
+using namespace connectivity::file;
+
+ORowSetValue OOp_Abs::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ double nVal = lhs.getDouble();
+ if ( nVal < 0 )
+ nVal *= -1.0;
+ return fabs(nVal);
+}
+
+ORowSetValue OOp_Sign::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ sal_Int32 nRet = 0;
+ double nVal = lhs.getDouble();
+ if ( nVal < 0 )
+ nRet = -1;
+ else if ( nVal > 0 )
+ nRet = 1;
+
+ return nRet;
+}
+
+ORowSetValue OOp_Mod::operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const
+{
+ if ( lhs.isNull() || rhs.isNull() )
+ return ORowSetValue();
+
+ return fmod(lhs.getDouble(), rhs.getDouble());
+}
+
+ORowSetValue OOp_Floor::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ return floor(lhs.getDouble());
+}
+
+ORowSetValue OOp_Ceiling::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ double nVal = lhs.getDouble();
+ return ceil(nVal);
+}
+
+ORowSetValue OOp_Round::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if ( lhs.empty() || lhs.size() > 2 )
+ return ORowSetValue();
+
+ size_t nSize = lhs.size();
+ double nVal = lhs[nSize-1].getDouble();
+
+ sal_Int32 nDec = 0;
+ if ( nSize == 2 && !lhs[0].isNull() )
+ nDec = lhs[0].getDouble();
+ return ::rtl::math::round(nVal,nDec);
+}
+
+ORowSetValue OOp_Exp::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ double nVal = lhs.getDouble();
+ return exp(nVal);
+}
+
+ORowSetValue OOp_Ln::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() || lhs.getDouble() < 0.0 )
+ return lhs;
+
+ double nVal = lhs.getDouble();
+ nVal = log(nVal);
+ if ( std::isnan(nVal) )
+ return ORowSetValue();
+ return nVal;
+}
+
+ORowSetValue OOp_Log::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if ( lhs.empty() || lhs.size() > 2 )
+ return ORowSetValue();
+ size_t nSize = lhs.size();
+ double nVal = log( lhs[nSize-1].getDouble() );
+
+
+ if ( nSize == 2 && !lhs[0].isNull() )
+ nVal /= log(lhs[0].getDouble());
+
+ if ( std::isnan(nVal) )
+ return ORowSetValue();
+ return nVal;
+}
+
+ORowSetValue OOp_Log10::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() || lhs.getDouble() < 0.0 )
+ return lhs;
+
+ double nVal = log(lhs.getDouble());
+ if ( std::isnan(nVal) )
+ return ORowSetValue();
+ nVal /= log(10.0);
+ return nVal;
+}
+
+ORowSetValue OOp_Pow::operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const
+{
+ if ( lhs.isNull() || rhs.isNull() )
+ return lhs;
+
+ return pow(lhs.getDouble(), rhs.getDouble());
+}
+
+ORowSetValue OOp_Sqrt::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ double nVal = sqrt(lhs.getDouble());
+ if ( std::isnan(nVal) )
+ return ORowSetValue();
+ return nVal;
+}
+
+ORowSetValue OOp_Pi::operate(const std::vector<ORowSetValue>& /*lhs*/) const
+{
+ return M_PI;
+}
+
+ORowSetValue OOp_Cos::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ return cos(lhs.getDouble());
+}
+
+ORowSetValue OOp_Sin::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ return sin(lhs.getDouble());
+}
+
+ORowSetValue OOp_Tan::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ return tan(lhs.getDouble());
+}
+
+ORowSetValue OOp_ACos::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ return acos(lhs.getDouble());
+}
+
+ORowSetValue OOp_ASin::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ return asin(lhs.getDouble());
+}
+
+ORowSetValue OOp_ATan::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ return atan(lhs.getDouble());
+}
+
+ORowSetValue OOp_ATan2::operate(const ORowSetValue& lhs,const ORowSetValue& rhs) const
+{
+ if ( lhs.isNull() || rhs.isNull() )
+ return lhs;
+
+ return atan2(lhs.getDouble(), rhs.getDouble());
+}
+
+ORowSetValue OOp_Degrees::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ double nLhs = lhs.getDouble();
+ return basegfx::rad2deg(nLhs);
+}
+
+ORowSetValue OOp_Radians::operate(const ORowSetValue& lhs) const
+{
+ if ( lhs.isNull() )
+ return lhs;
+
+ double nLhs = lhs.getDouble();
+ return basegfx::deg2rad(nLhs);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FPreparedStatement.cxx b/connectivity/source/drivers/file/FPreparedStatement.cxx
new file mode 100644
index 000000000..f2a8571b6
--- /dev/null
+++ b/connectivity/source/drivers/file/FPreparedStatement.cxx
@@ -0,0 +1,555 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <file/FPreparedStatement.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <file/FResultSetMetaData.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <comphelper/sequence.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/PColumn.hxx>
+#include <comphelper/types.hxx>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <strings.hrc>
+
+using namespace connectivity;
+using namespace comphelper;
+using namespace ::dbtools;
+using namespace connectivity::file;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+using namespace com::sun::star;
+
+IMPLEMENT_SERVICE_INFO(OPreparedStatement,"com.sun.star.sdbc.driver.file.PreparedStatement","com.sun.star.sdbc.PreparedStatement");
+
+OPreparedStatement::OPreparedStatement( OConnection* _pConnection)
+ : OStatement_BASE2( _pConnection )
+{
+}
+
+
+OPreparedStatement::~OPreparedStatement()
+{
+}
+
+
+void OPreparedStatement::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ OStatement_BASE2::disposing();
+
+ m_xParamColumns = nullptr;
+ m_xMetaData.clear();
+ if(m_aParameterRow.is())
+ {
+ m_aParameterRow->clear();
+ m_aParameterRow = nullptr;
+ }
+}
+
+void OPreparedStatement::construct(const OUString& sql)
+{
+ OStatement_Base::construct(sql);
+
+ m_aParameterRow = new OValueRefVector();
+ m_aParameterRow->push_back(new ORowSetValueDecorator(sal_Int32(0)) );
+
+ Reference<XIndexAccess> xNames(m_xColNames,UNO_QUERY);
+
+ if ( m_aSQLIterator.getStatementType() == OSQLStatementType::Select )
+ m_xParamColumns = m_aSQLIterator.getParameters();
+ else
+ {
+ m_xParamColumns = new OSQLColumns();
+ // describe all parameters need for the resultset
+ describeParameter();
+ }
+
+ OValueRefRow aTemp;
+ OResultSet::setBoundedColumns(m_aEvaluateRow,aTemp,m_xParamColumns,xNames,false,m_xDBMetaData,m_aColMapping);
+}
+
+rtl::Reference<OResultSet> OPreparedStatement::makeResultSet()
+{
+ closeResultSet();
+
+ rtl::Reference<OResultSet> xResultSet(createResultSet());
+ m_xResultSet = uno::Reference<uno::XWeak>(xResultSet);
+ initializeResultSet(xResultSet.get());
+ initResultSet(xResultSet.get());
+ return xResultSet;
+}
+
+Any SAL_CALL OPreparedStatement::queryInterface( const Type & rType )
+{
+ Any aRet = OStatement_BASE2::queryInterface(rType);
+ return aRet.hasValue() ? aRet : ::cppu::queryInterface( rType,
+ static_cast< XPreparedStatement*>(this),
+ static_cast< XParameters*>(this),
+ static_cast< XResultSetMetaDataSupplier*>(this));
+}
+
+css::uno::Sequence< css::uno::Type > SAL_CALL OPreparedStatement::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<XPreparedStatement>::get(),
+ cppu::UnoType<XParameters>::get(),
+ cppu::UnoType<XResultSetMetaDataSupplier>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),OStatement_BASE2::getTypes());
+}
+
+
+Reference< XResultSetMetaData > SAL_CALL OPreparedStatement::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ if(!m_xMetaData.is())
+ m_xMetaData = new OResultSetMetaData(m_aSQLIterator.getSelectColumns(),m_aSQLIterator.getTables().begin()->first,m_pTable.get());
+ return m_xMetaData;
+}
+
+
+void SAL_CALL OPreparedStatement::close( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ closeResultSet();
+}
+
+
+sal_Bool SAL_CALL OPreparedStatement::execute( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ rtl::Reference<OResultSet> xRS(makeResultSet());
+ // since we don't support the XMultipleResults interface, nobody will ever get that ResultSet...
+ if(xRS.is())
+ xRS->dispose();
+
+ return m_aSQLIterator.getStatementType() == OSQLStatementType::Select;
+}
+
+
+sal_Int32 SAL_CALL OPreparedStatement::executeUpdate( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ rtl::Reference<OResultSet> xRS(makeResultSet());
+ if(xRS.is())
+ {
+ const sal_Int32 res(xRS->getRowCountResult());
+ // nobody will ever get that ResultSet...
+ xRS->dispose();
+ return res;
+ }
+ else
+ return 0;
+}
+
+
+void SAL_CALL OPreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x )
+{
+ setParameter(parameterIndex,x);
+}
+
+
+Reference< XConnection > SAL_CALL OPreparedStatement::getConnection( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ return m_pConnection;
+}
+
+
+Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ return makeResultSet();
+}
+
+
+void SAL_CALL OPreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x )
+{
+ setParameter(parameterIndex,static_cast<bool>(x));
+}
+
+void SAL_CALL OPreparedStatement::setByte( sal_Int32 parameterIndex, sal_Int8 x )
+{
+ setParameter(parameterIndex,x);
+}
+
+
+void SAL_CALL OPreparedStatement::setDate( sal_Int32 parameterIndex, const util::Date& aData )
+{
+ setParameter(parameterIndex,DBTypeConversion::toDouble(aData));
+}
+
+void SAL_CALL OPreparedStatement::setTime( sal_Int32 parameterIndex, const util::Time& aVal )
+{
+ setParameter(parameterIndex,DBTypeConversion::toDouble(aVal));
+}
+
+
+void SAL_CALL OPreparedStatement::setTimestamp( sal_Int32 parameterIndex, const util::DateTime& aVal )
+{
+ setParameter(parameterIndex,DBTypeConversion::toDouble(aVal));
+}
+
+
+void SAL_CALL OPreparedStatement::setDouble( sal_Int32 parameterIndex, double x )
+{
+ setParameter(parameterIndex,x);
+}
+
+
+void SAL_CALL OPreparedStatement::setFloat( sal_Int32 parameterIndex, float x )
+{
+ setParameter(parameterIndex,x);
+}
+
+
+void SAL_CALL OPreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x )
+{
+ setParameter(parameterIndex,x);
+}
+
+
+void SAL_CALL OPreparedStatement::setLong( sal_Int32 /*parameterIndex*/, sal_Int64 /*aVal*/ )
+{
+ throwFeatureNotImplementedSQLException( "XParameters::setLong", *this );
+}
+
+
+void SAL_CALL OPreparedStatement::setNull( sal_Int32 parameterIndex, sal_Int32 /*sqlType*/ )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkAndResizeParameters(parameterIndex);
+
+ if ( m_aAssignValues.is() )
+ (*m_aAssignValues)[m_aParameterIndexes[parameterIndex]]->setNull();
+ else
+ (*m_aParameterRow)[parameterIndex]->setNull();
+}
+
+
+void SAL_CALL OPreparedStatement::setClob( sal_Int32 /*parameterIndex*/, const Reference< XClob >& /*x*/ )
+{
+ throwFeatureNotImplementedSQLException( "XParameters::setClob", *this );
+}
+
+
+void SAL_CALL OPreparedStatement::setBlob( sal_Int32 /*parameterIndex*/, const Reference< XBlob >& /*x*/ )
+{
+ throwFeatureNotImplementedSQLException( "XParameters::setBlob", *this );
+}
+
+
+void SAL_CALL OPreparedStatement::setArray( sal_Int32 /*parameterIndex*/, const Reference< XArray >& /*x*/ )
+{
+ throwFeatureNotImplementedSQLException( "XParameters::setArray", *this );
+}
+
+
+void SAL_CALL OPreparedStatement::setRef( sal_Int32 /*parameterIndex*/, const Reference< XRef >& /*x*/ )
+{
+ throwFeatureNotImplementedSQLException( "XParameters::setRef", *this );
+}
+
+
+void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 sqlType, sal_Int32 scale )
+{
+ switch(sqlType)
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ setString(parameterIndex,::comphelper::getString(x));
+ break;
+ default:
+ ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale);
+ break;
+ }
+}
+
+
+void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& /*typeName*/ )
+{
+ setNull(parameterIndex,sqlType);
+}
+
+
+void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x )
+{
+ if(!::dbtools::implSetObject(this,parameterIndex,x))
+ {
+ const OUString sError( m_pConnection->getResources().getResourceStringWithSubstitution(
+ STR_UNKNOWN_PARA_TYPE,
+ "$position$", OUString::number(parameterIndex)
+ ) );
+ ::dbtools::throwGenericSQLException(sError,*this);
+ }
+ // setObject (parameterIndex, x, sqlType, 0);
+}
+
+
+void SAL_CALL OPreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x )
+{
+ setParameter(parameterIndex,x);
+}
+
+
+void SAL_CALL OPreparedStatement::setBytes( sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x )
+{
+ setParameter(parameterIndex,x);
+}
+
+
+void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ setBinaryStream(parameterIndex,x,length );
+}
+
+
+void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ if(!x.is())
+ ::dbtools::throwFunctionSequenceException(*this);
+
+ Sequence<sal_Int8> aSeq;
+ x->readBytes(aSeq,length);
+ setParameter(parameterIndex,aSeq);
+}
+
+
+void SAL_CALL OPreparedStatement::clearParameters( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ m_aParameterRow->clear();
+ m_aParameterRow->push_back(new ORowSetValueDecorator(sal_Int32(0)) );
+}
+
+rtl::Reference<OResultSet> OPreparedStatement::createResultSet()
+{
+ return new OResultSet(this,m_aSQLIterator);
+}
+
+void OPreparedStatement::initResultSet(OResultSet *pResultSet)
+{
+ // check if we got enough parameters
+ if ( (m_aParameterRow.is() && ( m_aParameterRow->size() -1 ) < m_xParamColumns->size()) ||
+ (m_xParamColumns.is() && !m_aParameterRow.is() && !m_aParameterRow->empty()) )
+ m_pConnection->throwGenericSQLException(STR_INVALID_PARA_COUNT,*this);
+
+ pResultSet->OpenImpl();
+ pResultSet->setMetaData(getMetaData());
+}
+
+void SAL_CALL OPreparedStatement::acquire() noexcept
+{
+ OStatement_BASE2::acquire();
+}
+
+void SAL_CALL OPreparedStatement::release() noexcept
+{
+ OStatement_BASE2::release();
+}
+
+void OPreparedStatement::checkAndResizeParameters(sal_Int32 parameterIndex)
+{
+ ::connectivity::checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+ if ( m_aAssignValues.is() && (parameterIndex < 1 || o3tl::make_unsigned(parameterIndex) >= m_aParameterIndexes.size()) )
+ throwInvalidIndexException(*this);
+ else if ( static_cast<sal_Int32>(m_aParameterRow->size()) <= parameterIndex )
+ {
+ sal_Int32 i = m_aParameterRow->size();
+ m_aParameterRow->resize(parameterIndex+1);
+ for ( ; i <= parameterIndex; ++i)
+ {
+ if ( !(*m_aParameterRow)[i].is() )
+ (*m_aParameterRow)[i] = new ORowSetValueDecorator;
+ }
+ }
+}
+
+void OPreparedStatement::setParameter(sal_Int32 parameterIndex, const ORowSetValue& x)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkAndResizeParameters(parameterIndex);
+
+ if(m_aAssignValues.is())
+ *(*m_aAssignValues)[m_aParameterIndexes[parameterIndex]] = x;
+ else
+ *((*m_aParameterRow)[parameterIndex]) = x;
+}
+
+sal_uInt32 OPreparedStatement::AddParameter(OSQLParseNode const * pParameter, const Reference<XPropertySet>& _xCol)
+{
+ OSL_ENSURE(SQL_ISRULE(pParameter,parameter),"OResultSet::AddParameter: Argument is not a parameter");
+ OSL_ENSURE(pParameter->count() > 0,"OResultSet: Error in Parse Tree");
+
+ OUString sParameterName;
+ // set up Parameter-Column:
+ sal_Int32 eType = DataType::VARCHAR;
+ sal_uInt32 nPrecision = 255;
+ sal_Int32 nScale = 0;
+ sal_Int32 nNullable = ColumnValue::NULLABLE;
+
+ if (_xCol.is())
+ {
+ // Use type, precision, scale ... from the given column,
+ // because this Column will get a value assigned or
+ // with this Column the value will be compared.
+ _xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)) >>= eType;
+ _xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)) >>= nPrecision;
+ _xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)) >>= nScale;
+ _xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)) >>= nNullable;
+ _xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)) >>= sParameterName;
+ }
+
+ Reference<XPropertySet> xParaColumn = new connectivity::parse::OParseColumn(sParameterName
+ ,OUString()
+ ,OUString()
+ ,OUString()
+ ,nNullable
+ ,nPrecision
+ ,nScale
+ ,eType
+ ,false
+ ,false
+ ,m_aSQLIterator.isCaseSensitive()
+ ,OUString()
+ ,OUString()
+ ,OUString());
+ m_xParamColumns->push_back(xParaColumn);
+ return m_xParamColumns->size();
+}
+
+void OPreparedStatement::describeColumn(OSQLParseNode const * _pParameter, OSQLParseNode const * _pNode,const OSQLTable& _xTable)
+{
+ Reference<XPropertySet> xProp;
+ if(SQL_ISRULE(_pNode,column_ref))
+ {
+ OUString sColumnName,sTableRange;
+ m_aSQLIterator.getColumnRange(_pNode,sColumnName,sTableRange);
+ if ( !sColumnName.isEmpty() )
+ {
+ Reference<XNameAccess> xNameAccess = _xTable->getColumns();
+ if(xNameAccess->hasByName(sColumnName))
+ xNameAccess->getByName(sColumnName) >>= xProp;
+ AddParameter(_pParameter,xProp);
+ }
+ }
+ // else
+ // AddParameter(_pParameter,xProp);
+}
+
+void OPreparedStatement::describeParameter()
+{
+ std::vector< OSQLParseNode*> aParseNodes;
+ scanParameter(m_pParseTree,aParseNodes);
+ if ( aParseNodes.empty() )
+ return;
+
+ // m_xParamColumns = new OSQLColumns();
+ const OSQLTables& rTabs = m_aSQLIterator.getTables();
+ if( !rTabs.empty() )
+ {
+ OSQLTable xTable = rTabs.begin()->second;
+ for (auto const& parseNode : aParseNodes)
+ {
+ describeColumn(parseNode,parseNode->getParent()->getChild(0),xTable);
+ }
+ }
+}
+void OPreparedStatement::initializeResultSet(OResultSet* pRS)
+{
+ OStatement_Base::initializeResultSet(pRS);
+
+ // Substitute parameter (AssignValues and criteria):
+ if (m_xParamColumns->empty())
+ return;
+
+ // begin with AssignValues
+ sal_uInt16 nParaCount=0; // gives the current number of previously set Parameters
+
+ // search for parameters to be substituted:
+ size_t nCount = m_aAssignValues.is() ? m_aAssignValues->size() : 1; // 1 is important for the Criteria
+ for (size_t j = 1; j < nCount; j++)
+ {
+ sal_uInt32 nParameter = (*m_aAssignValues).getParameterIndex(j);
+ if (nParameter == SQL_NO_PARAMETER)
+ continue; // this AssignValue is no Parameter
+
+ ++nParaCount; // now the Parameter is valid
+ }
+
+ if (m_aParameterRow.is() && (m_xParamColumns->size()+1) != m_aParameterRow->size() )
+ {
+ sal_Int32 i = m_aParameterRow->size();
+ sal_Int32 nParamColumns = m_xParamColumns->size()+1;
+ m_aParameterRow->resize(nParamColumns);
+ for ( ;i < nParamColumns; ++i )
+ {
+ if ( !(*m_aParameterRow)[i].is() )
+ (*m_aParameterRow)[i] = new ORowSetValueDecorator;
+ }
+ }
+ if (m_aParameterRow.is() && nParaCount < m_aParameterRow->size() )
+ m_pSQLAnalyzer->bindParameterRow(m_aParameterRow);
+}
+
+void OPreparedStatement::parseParamterElem(const OUString& _sColumnName, OSQLParseNode* pRow_Value_Constructor_Elem)
+{
+ Reference<XPropertySet> xCol;
+ m_xColNames->getByName(_sColumnName) >>= xCol;
+ sal_Int32 nParameter = -1;
+ if(m_xParamColumns.is())
+ {
+ OSQLColumns::const_iterator aIter = find(m_xParamColumns->begin(),m_xParamColumns->end(),_sColumnName,::comphelper::UStringMixEqual(m_pTable->isCaseSensitive()));
+ if(aIter != m_xParamColumns->end())
+ nParameter = m_xParamColumns->size() - (m_xParamColumns->end() - aIter) + 1;// +1 because the rows start at 1
+ }
+ if(nParameter == -1)
+ nParameter = AddParameter(pRow_Value_Constructor_Elem,xCol);
+ // Save number of parameter in the variable:
+ SetAssignValue(_sColumnName, OUString(), true, nParameter);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FResultSet.cxx b/connectivity/source/drivers/file/FResultSet.cxx
new file mode 100644
index 000000000..4d0e256b9
--- /dev/null
+++ b/connectivity/source/drivers/file/FResultSet.cxx
@@ -0,0 +1,1593 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <file/FResultSet.hxx>
+#include <sqlbison.hxx>
+#include <file/FResultSetMetaData.hxx>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <connectivity/dbtools.hxx>
+#include <cppuhelper/propshlp.hxx>
+#include <o3tl/safeint.hxx>
+#include <sal/log.hxx>
+#include <iterator>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
+
+#include <algorithm>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/types.hxx>
+#include <resource/sharedresources.hxx>
+#include <strings.hrc>
+#include <tools/diagnose_ex.h>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace connectivity::file;
+using namespace ::cppu;
+using namespace dbtools;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+
+namespace
+{
+ void lcl_throwError(TranslateId pErrorId, const css::uno::Reference< css::uno::XInterface>& _xContext)
+ {
+ ::connectivity::SharedResources aResources;
+ const OUString sMessage = aResources.getResourceString(pErrorId);
+ ::dbtools::throwGenericSQLException(sMessage ,_xContext);
+ }
+}
+
+IMPLEMENT_SERVICE_INFO(OResultSet,"com.sun.star.sdbcx.drivers.file.ResultSet","com.sun.star.sdbc.ResultSet");
+
+OResultSet::OResultSet(OStatement_Base* pStmt,OSQLParseTreeIterator& _aSQLIterator) : OResultSet_BASE(m_aMutex)
+ ,::comphelper::OPropertyContainer(OResultSet_BASE::rBHelper)
+ ,m_aSkipDeletedSet(this)
+ ,m_pParseTree(pStmt->getParseTree())
+ ,m_pSQLAnalyzer(nullptr)
+ ,m_aSQLIterator(_aSQLIterator)
+ ,m_nFetchSize(0)
+ ,m_nResultSetType(ResultSetType::SCROLL_INSENSITIVE)
+ ,m_nFetchDirection(FetchDirection::FORWARD)
+ ,m_nResultSetConcurrency(ResultSetConcurrency::UPDATABLE)
+ ,m_xStatement(*pStmt)
+ ,m_nRowPos(-1)
+ ,m_nFilePos(0)
+ ,m_nLastVisitedPos(-1)
+ ,m_nRowCountResult(-1)
+ ,m_nColumnCount(0)
+ ,m_bWasNull(false)
+ ,m_bInserted(false)
+ ,m_bRowUpdated(false)
+ ,m_bRowInserted(false)
+ ,m_bRowDeleted(false)
+ ,m_bShowDeleted(pStmt->getOwnConnection()->showDeleted())
+ ,m_bIsCount(false)
+{
+ osl_atomic_increment( &m_refCount );
+ m_bIsCount = (m_pParseTree &&
+ m_pParseTree->count() > 2 &&
+ SQL_ISRULE(m_pParseTree->getChild(2),scalar_exp_commalist) &&
+ SQL_ISRULE(m_pParseTree->getChild(2)->getChild(0),derived_column) &&
+ SQL_ISRULE(m_pParseTree->getChild(2)->getChild(0)->getChild(0),general_set_fct) &&
+ m_pParseTree->getChild(2)->getChild(0)->getChild(0)->count() == 4
+ );
+
+ m_nResultSetConcurrency = isCount() ? ResultSetConcurrency::READ_ONLY : ResultSetConcurrency::UPDATABLE;
+ construct();
+ m_aSkipDeletedSet.SetDeletedVisible(m_bShowDeleted);
+ osl_atomic_decrement( &m_refCount );
+}
+
+
+OResultSet::~OResultSet()
+{
+ osl_atomic_increment( &m_refCount );
+ disposing();
+}
+
+void OResultSet::construct()
+{
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), PROPERTY_ID_FETCHSIZE, 0,&m_nFetchSize, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), PROPERTY_ID_RESULTSETTYPE, PropertyAttribute::READONLY,&m_nResultSetType, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), PROPERTY_ID_FETCHDIRECTION, 0,&m_nFetchDirection, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), PROPERTY_ID_RESULTSETCONCURRENCY,PropertyAttribute::READONLY,&m_nResultSetConcurrency, ::cppu::UnoType<sal_Int32>::get());
+}
+
+void OResultSet::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_xStatement.clear();
+ m_xMetaData.clear();
+ m_pParseTree = nullptr;
+ m_xColNames.clear();
+ m_xColumns = nullptr;
+ m_xColsIdx.clear();
+
+ if ( m_pTable.is() )
+ m_pTable->removeEventListener(this);
+ m_pTable.clear();
+
+ m_pFileSet = nullptr;
+ m_pSortIndex.reset();
+
+ if(m_aInsertRow.is())
+ m_aInsertRow->clear();
+
+ m_aSkipDeletedSet.clear();
+}
+
+Any SAL_CALL OResultSet::queryInterface( const Type & rType )
+{
+ Any aRet = OPropertySetHelper::queryInterface(rType);
+ return aRet.hasValue() ? aRet : OResultSet_BASE::queryInterface(rType);
+}
+
+Sequence< Type > SAL_CALL OResultSet::getTypes( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ OTypeCollection aTypes( cppu::UnoType<css::beans::XMultiPropertySet>::get(),
+ cppu::UnoType<css::beans::XPropertySet>::get(),
+ cppu::UnoType<css::beans::XPropertySet>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),OResultSet_BASE::getTypes());
+}
+
+
+sal_Int32 SAL_CALL OResultSet::findColumn( const OUString& columnName )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ Reference< XResultSetMetaData > xMeta = getMetaData();
+ sal_Int32 nLen = xMeta->getColumnCount();
+ sal_Int32 i = 1;
+ for(;i<=nLen;++i)
+ {
+ if(xMeta->isCaseSensitive(i) ? columnName == xMeta->getColumnName(i) :
+ columnName.equalsIgnoreAsciiCase(xMeta->getColumnName(i)))
+ return i;
+ }
+
+ ::dbtools::throwInvalidColumnException( columnName, *this );
+ assert(false);
+ return 0; // Never reached
+}
+
+const ORowSetValue& OResultSet::getValue(sal_Int32 columnIndex)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ checkIndex(columnIndex );
+
+
+ m_bWasNull = (*m_aSelectRow)[columnIndex]->getValue().isNull();
+ return *(*m_aSelectRow)[columnIndex];
+}
+
+void OResultSet::checkIndex(sal_Int32 columnIndex )
+{
+ if ( columnIndex <= 0
+ || columnIndex >= m_nColumnCount )
+ ::dbtools::throwInvalidIndexException(*this);
+}
+
+Reference< css::io::XInputStream > SAL_CALL OResultSet::getBinaryStream( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+Reference< css::io::XInputStream > SAL_CALL OResultSet::getCharacterStream( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+
+sal_Bool SAL_CALL OResultSet::getBoolean( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getBool();
+}
+
+
+sal_Int8 SAL_CALL OResultSet::getByte( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getInt8();
+}
+
+
+Sequence< sal_Int8 > SAL_CALL OResultSet::getBytes( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getSequence();
+}
+
+
+css::util::Date SAL_CALL OResultSet::getDate( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDate();
+}
+
+
+double SAL_CALL OResultSet::getDouble( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDouble();
+}
+
+
+float SAL_CALL OResultSet::getFloat( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getFloat();
+}
+
+
+sal_Int32 SAL_CALL OResultSet::getInt( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getInt32();
+}
+
+
+sal_Int32 SAL_CALL OResultSet::getRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ OSL_ENSURE((m_bShowDeleted || !m_aRow->isDeleted()),"getRow called for deleted row");
+
+ return m_aSkipDeletedSet.getMappedPosition((*m_aRow)[0]->getValue().getInt32());
+}
+
+
+sal_Int64 SAL_CALL OResultSet::getLong( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getLong();
+}
+
+
+Reference< XResultSetMetaData > SAL_CALL OResultSet::getMetaData( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(!m_xMetaData.is())
+ m_xMetaData = new OResultSetMetaData(m_xColumns,m_aSQLIterator.getTables().begin()->first,m_pTable.get());
+ return m_xMetaData;
+}
+
+Reference< XArray > SAL_CALL OResultSet::getArray( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+
+Reference< XClob > SAL_CALL OResultSet::getClob( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+Reference< XBlob > SAL_CALL OResultSet::getBlob( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+
+Reference< XRef > SAL_CALL OResultSet::getRef( sal_Int32 /*columnIndex*/ )
+{
+ return nullptr;
+}
+
+
+Any SAL_CALL OResultSet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& /*typeMap*/ )
+{
+ return getValue(columnIndex).makeAny();
+}
+
+
+sal_Int16 SAL_CALL OResultSet::getShort( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getInt16();
+}
+
+OUString SAL_CALL OResultSet::getString( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getString();
+}
+
+css::util::Time SAL_CALL OResultSet::getTime( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getTime();
+}
+
+css::util::DateTime SAL_CALL OResultSet::getTimestamp( sal_Int32 columnIndex )
+{
+ return getValue(columnIndex).getDateTime();
+}
+
+
+sal_Bool SAL_CALL OResultSet::isAfterLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_nRowPos == sal_Int32(m_pFileSet->size());
+}
+
+sal_Bool SAL_CALL OResultSet::isFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_nRowPos == 0;
+}
+
+sal_Bool SAL_CALL OResultSet::isLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_nRowPos == sal_Int32(m_pFileSet->size() - 1);
+}
+
+void SAL_CALL OResultSet::beforeFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(first())
+ previous();
+}
+
+void SAL_CALL OResultSet::afterLast( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(last())
+ next();
+}
+
+
+void SAL_CALL OResultSet::close( )
+{
+ dispose();
+}
+
+
+sal_Bool SAL_CALL OResultSet::first( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::FIRST,1,true);
+}
+
+
+sal_Bool SAL_CALL OResultSet::last( )
+{
+ // here I know definitely that I stand on the last record
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::LAST,1,true);
+}
+
+sal_Bool SAL_CALL OResultSet::absolute( sal_Int32 row )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::ABSOLUTE1,row,true);
+}
+
+sal_Bool SAL_CALL OResultSet::relative( sal_Int32 row )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::RELATIVE1,row,true);
+}
+
+sal_Bool SAL_CALL OResultSet::previous( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+ return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::PRIOR,0,true);
+}
+
+Reference< XInterface > SAL_CALL OResultSet::getStatement( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_xStatement;
+}
+
+
+sal_Bool SAL_CALL OResultSet::rowDeleted( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_bRowDeleted;
+}
+
+sal_Bool SAL_CALL OResultSet::rowInserted( )
+{ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_bRowInserted;
+}
+
+sal_Bool SAL_CALL OResultSet::rowUpdated( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_bRowUpdated;
+}
+
+
+sal_Bool SAL_CALL OResultSet::isBeforeFirst( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ return m_nRowPos == -1;
+}
+
+sal_Bool SAL_CALL OResultSet::next( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_pTable.is() && m_aSkipDeletedSet.skipDeleted(IResultSetHelper::NEXT,1,true);
+}
+
+
+sal_Bool SAL_CALL OResultSet::wasNull( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ return m_bWasNull;
+}
+
+
+void SAL_CALL OResultSet::cancel( )
+{
+}
+
+void SAL_CALL OResultSet::clearWarnings( )
+{
+}
+
+Any SAL_CALL OResultSet::getWarnings( )
+{
+ return Any();
+}
+
+void SAL_CALL OResultSet::insertRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ if(!m_bInserted || !m_pTable.is())
+ throwFunctionSequenceException(*this);
+
+ // we know that we append new rows at the end
+ // so we have to know where the end is
+ (void)m_aSkipDeletedSet.skipDeleted(IResultSetHelper::LAST,1,false);
+ m_bRowInserted = m_pTable->InsertRow(*m_aInsertRow, m_xColsIdx);
+ if(m_bRowInserted && m_pFileSet.is())
+ {
+ sal_Int32 nPos = (*m_aInsertRow)[0]->getValue().getInt32();
+ m_pFileSet->push_back(nPos);
+ *(*m_aInsertRow)[0] = sal_Int32(m_pFileSet->size());
+ clearInsertRow();
+
+ m_aSkipDeletedSet.insertNewPosition((*m_aRow)[0]->getValue().getInt32());
+ }
+}
+
+void SAL_CALL OResultSet::updateRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if(!m_pTable.is() || m_pTable->isReadOnly())
+ lcl_throwError(STR_TABLE_READONLY,*this);
+
+ m_bRowUpdated = m_pTable->UpdateRow(*m_aInsertRow, m_aRow,m_xColsIdx);
+ *(*m_aInsertRow)[0] = (*m_aRow)[0]->getValue().getInt32();
+
+ clearInsertRow();
+}
+
+void SAL_CALL OResultSet::deleteRow()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if(!m_pTable.is() || m_pTable->isReadOnly())
+ lcl_throwError(STR_TABLE_READONLY,*this);
+ if (m_bShowDeleted)
+ lcl_throwError(STR_DELETE_ROW,*this);
+ if(m_aRow->isDeleted())
+ lcl_throwError(STR_ROW_ALREADY_DELETED,*this);
+
+ sal_Int32 nPos = (*m_aRow)[0]->getValue().getInt32();
+ m_bRowDeleted = m_pTable->DeleteRow(*m_xColumns);
+ if(m_bRowDeleted && m_pFileSet.is())
+ {
+ m_aRow->setDeleted(true);
+ // don't touch the m_pFileSet member here
+ m_aSkipDeletedSet.deletePosition(nPos);
+ }
+}
+
+void SAL_CALL OResultSet::cancelRowUpdates( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+
+ m_bInserted = false;
+ m_bRowUpdated = false;
+ m_bRowInserted = false;
+ m_bRowDeleted = false;
+
+ if(m_aInsertRow.is())
+ {
+ OValueRefVector::iterator aIter = m_aInsertRow->begin()+1;
+ for(;aIter != m_aInsertRow->end();++aIter)
+ {
+ (*aIter)->setBound(false);
+ (*aIter)->setNull();
+ }
+ }
+}
+
+
+void SAL_CALL OResultSet::moveToInsertRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if(!m_pTable.is() || m_pTable->isReadOnly())
+ lcl_throwError(STR_TABLE_READONLY,*this);
+
+ m_bInserted = true;
+
+ OValueRefVector::iterator aIter = m_aInsertRow->begin()+1;
+ for(;aIter != m_aInsertRow->end();++aIter)
+ {
+ (*aIter)->setBound(false);
+ (*aIter)->setNull();
+ }
+}
+
+
+void SAL_CALL OResultSet::moveToCurrentRow( )
+{
+}
+
+void OResultSet::updateValue(sal_Int32 columnIndex ,const ORowSetValue& x)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ checkIndex(columnIndex );
+ columnIndex = mapColumn(columnIndex);
+
+ (*m_aInsertRow)[columnIndex]->setBound(true);
+ *(*m_aInsertRow)[columnIndex] = x;
+}
+
+
+void SAL_CALL OResultSet::updateNull( sal_Int32 columnIndex )
+{
+ ORowSetValue aEmpty;
+ updateValue(columnIndex,aEmpty);
+}
+
+
+void SAL_CALL OResultSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x )
+{
+ updateValue(columnIndex, static_cast<bool>(x));
+}
+
+void SAL_CALL OResultSet::updateByte( sal_Int32 columnIndex, sal_Int8 x )
+{
+ updateValue(columnIndex,x);
+}
+
+
+void SAL_CALL OResultSet::updateShort( sal_Int32 columnIndex, sal_Int16 x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL OResultSet::updateInt( sal_Int32 columnIndex, sal_Int32 x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL OResultSet::updateLong( sal_Int32 /*columnIndex*/, sal_Int64 /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::updateLong", *this );
+}
+
+void SAL_CALL OResultSet::updateFloat( sal_Int32 columnIndex, float x )
+{
+ updateValue(columnIndex,x);
+}
+
+
+void SAL_CALL OResultSet::updateDouble( sal_Int32 columnIndex, double x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL OResultSet::updateString( sal_Int32 columnIndex, const OUString& x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL OResultSet::updateBytes( sal_Int32 columnIndex, const Sequence< sal_Int8 >& x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL OResultSet::updateDate( sal_Int32 columnIndex, const css::util::Date& x )
+{
+ updateValue(columnIndex,x);
+}
+
+
+void SAL_CALL OResultSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x )
+{
+ updateValue(columnIndex,x);
+}
+
+
+void SAL_CALL OResultSet::updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x )
+{
+ updateValue(columnIndex,x);
+}
+
+
+void SAL_CALL OResultSet::updateBinaryStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+
+ if(!x.is())
+ ::dbtools::throwFunctionSequenceException(*this);
+
+ Sequence<sal_Int8> aSeq;
+ x->readBytes(aSeq,length);
+ updateValue(columnIndex,aSeq);
+}
+
+void SAL_CALL OResultSet::updateCharacterStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ updateBinaryStream(columnIndex,x,length);
+}
+
+void SAL_CALL OResultSet::refreshRow( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OResultSet_BASE::rBHelper.bDisposed);
+}
+
+void SAL_CALL OResultSet::updateObject( sal_Int32 columnIndex, const Any& x )
+{
+ if (!::dbtools::implUpdateObject(this, columnIndex, x))
+ throw SQLException();
+}
+
+
+void SAL_CALL OResultSet::updateNumericObject( sal_Int32 columnIndex, const Any& x, sal_Int32 /*scale*/ )
+{
+ if (!::dbtools::implUpdateObject(this, columnIndex, x))
+ throw SQLException();
+}
+
+IPropertyArrayHelper* OResultSet::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+IPropertyArrayHelper & OResultSet::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+
+bool OResultSet::ExecuteRow(IResultSetHelper::Movement eFirstCursorPosition,
+ sal_Int32 nFirstOffset,
+ bool bEvaluate,
+ bool bRetrieveData)
+{
+ OSL_ENSURE(m_pSQLAnalyzer,"OResultSet::ExecuteRow: Analyzer isn't set!");
+
+ // For further Fetch-Operations this information may possibly be changed ...
+ IResultSetHelper::Movement eCursorPosition = eFirstCursorPosition;
+ sal_Int32 nOffset = nFirstOffset;
+
+ if (!m_pTable.is())
+ return false;
+
+ const OSQLColumns & rTableCols = *(m_pTable->getTableColumns());
+ bool bHasRestriction = m_pSQLAnalyzer->hasRestriction();
+again:
+
+ // protect from reading over the end when somebody is inserting while we are reading
+ // this method works only for dBase at the moment!!!
+ if (eCursorPosition == IResultSetHelper::NEXT && m_nFilePos == m_nLastVisitedPos)
+ {
+ return false;
+ }
+
+ if (!m_pTable.is() || !m_pTable->seekRow(eCursorPosition, nOffset, m_nFilePos))
+ {
+ return false;
+ }
+
+ if (!bEvaluate) // If no evaluation runs, then just fill the results-row
+ {
+ m_pTable->fetchRow(m_aRow,rTableCols, bRetrieveData);
+ }
+ else
+ {
+ m_pTable->fetchRow(m_aEvaluateRow, rTableCols, bRetrieveData || bHasRestriction);
+
+ if ( ( !m_bShowDeleted
+ && m_aEvaluateRow->isDeleted()
+ )
+ || ( bHasRestriction
+ && !m_pSQLAnalyzer->evaluateRestriction()
+ )
+ )
+ { // Evaluate the next record
+ // delete current row in Keyset
+ if (m_pFileSet.is())
+ {
+ OSL_ENSURE(eCursorPosition == IResultSetHelper::NEXT, "Wrong CursorPosition!");
+ eCursorPosition = IResultSetHelper::NEXT;
+ nOffset = 1;
+ }
+ else if (eCursorPosition == IResultSetHelper::FIRST ||
+ eCursorPosition == IResultSetHelper::NEXT ||
+ eCursorPosition == IResultSetHelper::ABSOLUTE1)
+ {
+ eCursorPosition = IResultSetHelper::NEXT;
+ nOffset = 1;
+ }
+ else if (eCursorPosition == IResultSetHelper::LAST ||
+ eCursorPosition == IResultSetHelper::PRIOR)
+ {
+ eCursorPosition = IResultSetHelper::PRIOR;
+ nOffset = 1;
+ }
+ else if (eCursorPosition == IResultSetHelper::RELATIVE1)
+ {
+ eCursorPosition = (nOffset >= 0) ? IResultSetHelper::NEXT : IResultSetHelper::PRIOR;
+ }
+ else
+ {
+ return false;
+ }
+ // Try again ...
+ goto again;
+ }
+ }
+
+ // Evaluate may only be set,
+ // if the Keyset will be constructed further
+ if ( ( m_aSQLIterator.getStatementType() == OSQLStatementType::Select )
+ && !isCount()
+ && bEvaluate
+ )
+ {
+ if (m_pSortIndex)
+ {
+ std::unique_ptr<OKeyValue> pKeyValue = GetOrderbyKeyValue( m_aSelectRow );
+ m_pSortIndex->AddKeyValue(std::move(pKeyValue));
+ }
+ else if (m_pFileSet.is())
+ {
+ sal_uInt32 nBookmarkValue = std::abs((*m_aEvaluateRow)[0]->getValue().getInt32());
+ m_pFileSet->push_back(nBookmarkValue);
+ }
+ }
+ else if (m_aSQLIterator.getStatementType() == OSQLStatementType::Update)
+ {
+ bool bOK = true;
+ if (bEvaluate)
+ {
+ // read the actual result-row
+ bOK = m_pTable->fetchRow(m_aEvaluateRow, *(m_pTable->getTableColumns()), true);
+ }
+
+ if (bOK)
+ {
+ // just give the values to be changed:
+ if(!m_pTable->UpdateRow(*m_aAssignValues,m_aEvaluateRow, m_xColsIdx))
+ return false;
+ }
+ }
+ else if (m_aSQLIterator.getStatementType() == OSQLStatementType::Delete)
+ {
+ bool bOK = true;
+ if (bEvaluate)
+ {
+ bOK = m_pTable->fetchRow(m_aEvaluateRow, *(m_pTable->getTableColumns()), true);
+ }
+ if (bOK)
+ {
+ if(!m_pTable->DeleteRow(*m_xColumns))
+ return false;
+ }
+ }
+ return true;
+}
+
+
+bool OResultSet::Move(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, bool bRetrieveData)
+{
+ sal_Int32 nTempPos = m_nRowPos;
+
+ if (m_aSQLIterator.getStatementType() == OSQLStatementType::Select &&
+ !isCount())
+ {
+ if (!m_pFileSet.is()) //no Index available
+ {
+ // Normal FETCH
+ ExecuteRow(eCursorPosition,nOffset,false,bRetrieveData);
+
+ // now set the bookmark for outside this is the logical pos and not the file pos
+ *(*m_aRow->begin()) = sal_Int32(m_nRowPos + 1);
+ }
+ else
+ {
+ switch(eCursorPosition)
+ {
+ case IResultSetHelper::NEXT:
+ ++m_nRowPos;
+ break;
+ case IResultSetHelper::PRIOR:
+ if (m_nRowPos >= 0)
+ --m_nRowPos;
+ break;
+ case IResultSetHelper::FIRST:
+ m_nRowPos = 0;
+ break;
+ case IResultSetHelper::LAST:
+ m_nRowPos = m_pFileSet->size() - 1;
+ break;
+ case IResultSetHelper::RELATIVE1:
+ m_nRowPos += nOffset;
+ break;
+ case IResultSetHelper::ABSOLUTE1:
+ case IResultSetHelper::BOOKMARK:
+ if ( m_nRowPos == (nOffset -1) )
+ return true;
+ m_nRowPos = nOffset -1;
+ break;
+ }
+
+ // OffRange?
+ // The FileCursor is outside of the valid range, if:
+ // a.) m_nRowPos < 1
+ // b.) a KeySet exists and m_nRowPos > m_pFileSet->size()
+ if (m_nRowPos < 0 || (m_pFileSet->isFrozen() && eCursorPosition != IResultSetHelper::BOOKMARK && o3tl::make_unsigned(m_nRowPos) >= m_pFileSet->size() )) // && m_pFileSet->IsFrozen()
+ {
+ goto Error;
+ }
+ else
+ {
+ if (m_nRowPos < static_cast<sal_Int32>(m_pFileSet->size()))
+ {
+ // Fetch via Index
+ bool bOK = ExecuteRow(IResultSetHelper::BOOKMARK,(*m_pFileSet)[m_nRowPos],false,bRetrieveData);
+ if (!bOK)
+ goto Error;
+
+ // now set the bookmark for outside
+ *(*m_aRow->begin()) = sal_Int32(m_nRowPos + 1);
+ if ( (bRetrieveData || m_pSQLAnalyzer->hasRestriction()) && m_pSQLAnalyzer->hasFunctions() )
+ {
+ m_pSQLAnalyzer->setSelectionEvaluationResult(m_aSelectRow,m_aColMapping);
+ }
+ }
+ else // Index must be further constructed
+ {
+ // set first on the last known row
+ if (m_pFileSet->empty())
+ {
+ m_pTable->seekRow(IResultSetHelper::ABSOLUTE1, 0, m_nFilePos);
+ }
+ else
+ {
+ m_aFileSetIter = m_pFileSet->end()-1;
+ m_pTable->seekRow(IResultSetHelper::BOOKMARK, *m_aFileSetIter, m_nFilePos);
+ }
+ bool bOK = true;
+ // Determine the number of further Fetches
+ while (bOK && m_nRowPos >= static_cast<sal_Int32>(m_pFileSet->size()))
+ {
+ bOK = ExecuteRow(IResultSetHelper::NEXT,1,true, false);//bRetrieveData);
+ }
+
+ if (bOK)
+ {
+ // read the results again
+ m_pTable->fetchRow(m_aRow, *(m_pTable->getTableColumns()), bRetrieveData);
+
+ // now set the bookmark for outside
+ *(*m_aRow->begin()) = sal_Int32(m_nRowPos + 1);
+
+ if ( (bRetrieveData || m_pSQLAnalyzer->hasRestriction()) && m_pSQLAnalyzer->hasFunctions() )
+ {
+ m_pSQLAnalyzer->setSelectionEvaluationResult(m_aSelectRow,m_aColMapping);
+ }
+ }
+ else if (!m_pFileSet->isFrozen()) // no valid record found
+ {
+ m_pFileSet->setFrozen();
+ goto Error;
+ }
+ }
+ }
+ }
+ }
+ else if (m_aSQLIterator.getStatementType() == OSQLStatementType::Select && isCount())
+ {
+ // Fetch the COUNT(*)
+ switch (eCursorPosition)
+ {
+ case IResultSetHelper::NEXT:
+ ++m_nRowPos;
+ break;
+ case IResultSetHelper::PRIOR:
+ --m_nRowPos;
+ break;
+ case IResultSetHelper::FIRST:
+ m_nRowPos = 0;
+ break;
+ case IResultSetHelper::LAST:
+ m_nRowPos = 0;
+ break;
+ case IResultSetHelper::RELATIVE1:
+ m_nRowPos += nOffset;
+ break;
+ case IResultSetHelper::ABSOLUTE1:
+ case IResultSetHelper::BOOKMARK:
+ m_nRowPos = nOffset - 1;
+ break;
+ }
+
+ if ( m_nRowPos < 0 )
+ goto Error;
+ else if (m_nRowPos == 0)
+ {
+ // put COUNT(*) in result-row
+ // (must be the first and only variable in the row)
+ if (m_aRow->size() >= 2)
+ {
+ *(*m_aRow)[1] = m_nRowCountResult;
+ *(*m_aRow)[0] = sal_Int32(1);
+ (*m_aRow)[1]->setBound(true);
+ (*m_aSelectRow)[1] = (*m_aRow)[1];
+ }
+ }
+ else
+ {
+ m_nRowPos = 1;
+ return false;
+ }
+ }
+ else
+ // Fetch only possible at SELECT!
+ return false;
+
+ return true;
+
+Error:
+ // is the Cursor positioned before the first row
+ // then the position will be maintained
+ if (nTempPos == -1)
+ m_nRowPos = nTempPos;
+ else
+ {
+ switch(eCursorPosition)
+ {
+ case IResultSetHelper::PRIOR:
+ case IResultSetHelper::FIRST:
+ m_nRowPos = -1;
+ break;
+ case IResultSetHelper::LAST:
+ case IResultSetHelper::NEXT:
+ case IResultSetHelper::ABSOLUTE1:
+ case IResultSetHelper::RELATIVE1:
+ if (nOffset > 0)
+ m_nRowPos = m_pFileSet.is() ? static_cast<sal_Int32>(m_pFileSet->size()) : -1;
+ else if (nOffset < 0)
+ m_nRowPos = -1;
+ break;
+ case IResultSetHelper::BOOKMARK:
+ m_nRowPos = nTempPos; // last Position
+ }
+ }
+ return false;
+}
+
+void OResultSet::sortRows()
+{
+ if (!m_pSQLAnalyzer->hasRestriction() && m_aOrderbyColumnNumber.size() == 1)
+ {
+ // is just one field given for sorting
+ // and this field is indexed, then the Index will be used
+ Reference<XIndexesSupplier> xIndexSup;
+ m_pTable->queryInterface(cppu::UnoType<XIndexesSupplier>::get()) >>= xIndexSup;
+
+ Reference<XIndexAccess> xIndexes;
+ if(xIndexSup.is())
+ {
+ xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY);
+ Reference<XPropertySet> xColProp;
+ if(m_aOrderbyColumnNumber[0] < xIndexes->getCount())
+ {
+ xColProp.set(xIndexes->getByIndex(m_aOrderbyColumnNumber[0]),UNO_QUERY);
+ // iterate through the indexes to find the matching column
+ const sal_Int32 nCount = xIndexes->getCount();
+ for(sal_Int32 i=0; i < nCount;++i)
+ {
+ Reference<XColumnsSupplier> xIndex(xIndexes->getByIndex(i),UNO_QUERY);
+ Reference<XNameAccess> xIndexCols = xIndex->getColumns();
+ if(xIndexCols->hasByName(comphelper::getString(xColProp->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)))))
+ {
+ m_pFileSet = new OKeySet();
+
+ if(fillIndexValues(xIndex))
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ OSortIndex::TKeyTypeVector eKeyType(m_aOrderbyColumnNumber.size());
+ size_t i = 0;
+ for (auto const& elem : m_aOrderbyColumnNumber)
+ {
+ OSL_ENSURE(static_cast<sal_Int32>(m_aSelectRow->size()) > elem,"Invalid Index");
+ switch ((*(m_aSelectRow->begin()+elem))->getValue().getTypeKind())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ eKeyType[i] = OKeyType::String;
+ break;
+
+ case DataType::OTHER:
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ case DataType::BIT:
+ eKeyType[i] = OKeyType::Double;
+ break;
+
+ // Other types aren't implemented (so they are always FALSE)
+ default:
+ eKeyType[i] = OKeyType::NONE;
+ SAL_WARN( "connectivity.drivers","OFILECursor::Execute: Data type not implemented");
+ break;
+ }
+ (*m_aSelectRow)[elem]->setBound(true);
+ ++i;
+ }
+
+ m_pSortIndex.reset(new OSortIndex(std::move(eKeyType), std::vector(m_aOrderbyAscending)));
+
+ while ( ExecuteRow( IResultSetHelper::NEXT, 1, false ) )
+ {
+ (*m_aSelectRow)[0]->setValue( (*m_aRow)[0]->getValue() );
+ if ( m_pSQLAnalyzer->hasFunctions() )
+ m_pSQLAnalyzer->setSelectionEvaluationResult( m_aSelectRow, m_aColMapping );
+ const sal_Int32 nBookmark = (*m_aRow->begin())->getValue().getInt32();
+ ExecuteRow( IResultSetHelper::BOOKMARK, nBookmark, true, false );
+ }
+
+ // create sorted Keyset
+ m_pFileSet = nullptr;
+ m_pFileSet = m_pSortIndex->CreateKeySet();
+ m_pSortIndex.reset();
+ // now access to a sorted set is possible via Index
+}
+
+
+void OResultSet::OpenImpl()
+{
+ OSL_ENSURE(m_pSQLAnalyzer,"No analyzer set with setSqlAnalyzer!");
+ if(!m_pTable.is())
+ {
+ const OSQLTables& rTabs = m_aSQLIterator.getTables();
+ if (rTabs.empty() || !rTabs.begin()->second.is())
+ lcl_throwError(STR_QUERY_TOO_COMPLEX,*this);
+
+ if ( rTabs.size() > 1 || m_aSQLIterator.hasErrors() )
+ lcl_throwError(STR_QUERY_MORE_TABLES,*this);
+
+ OSQLTable xTable = rTabs.begin()->second;
+ m_xColumns = m_aSQLIterator.getSelectColumns();
+
+ m_xColNames = xTable->getColumns();
+ m_xColsIdx.set(m_xColNames,UNO_QUERY);
+ doTableSpecials(xTable);
+ Reference<XComponent> xComp(xTable,UNO_QUERY);
+ if(xComp.is())
+ xComp->addEventListener(this);
+ }
+
+ m_pTable->refreshHeader();
+
+ sal_Int32 nColumnCount = m_xColsIdx->getCount();
+
+ initializeRow(m_aRow,nColumnCount);
+ initializeRow(m_aEvaluateRow,nColumnCount);
+ initializeRow(m_aInsertRow,nColumnCount);
+
+
+ m_nResultSetConcurrency = (m_pTable->isReadOnly() || isCount()) ? ResultSetConcurrency::READ_ONLY : ResultSetConcurrency::UPDATABLE;
+
+ // create new Index:
+ m_pFileSet = nullptr;
+
+ // position at the beginning
+ m_nRowPos = -1;
+ m_nFilePos = 0;
+ m_nRowCountResult = -1;
+ m_pTable->seekRow(IResultSetHelper::ABSOLUTE1, 0, m_nFilePos);
+
+ m_nLastVisitedPos = m_pTable->getCurrentLastPos();
+
+ switch(m_aSQLIterator.getStatementType())
+ {
+ case OSQLStatementType::Select:
+ {
+ if(isCount())
+ {
+ if(m_xColumns->size() > 1)
+ lcl_throwError(STR_QUERY_COMPLEX_COUNT,*this);
+
+ m_nRowCountResult = 0;
+ // for now simply iterate over all rows and
+ // do all actions (or just count)
+ {
+ bool bOK = true;
+ while (bOK)
+ {
+ bOK = ExecuteRow(IResultSetHelper::NEXT);
+
+ if (bOK)
+ {
+ m_nRowCountResult++;
+ }
+ }
+
+ // save result of COUNT(*) in m_nRowCountResult.
+ // nRowCount (number of Rows in the result) = 1 for this request!
+ }
+ }
+ else
+ {
+ bool bDistinct = false;
+ assert(m_pParseTree != nullptr);
+ OSQLParseNode *pDistinct = m_pParseTree->getChild(1);
+
+ assert(m_aOrderbyColumnNumber.size() ==
+ m_aOrderbyAscending.size());
+ if (pDistinct && pDistinct->getTokenID() == SQL_TOKEN_DISTINCT )
+ {
+ // To eliminate duplicates we need to sort on all columns.
+ // This is not a problem because the SQL spec says that the
+ // order of columns that are not specified in ORDER BY
+ // clause is undefined, so it doesn't hurt to sort on
+ // these; pad the vectors to include them.
+ for (size_t i = 1; // 0: bookmark (see setBoundedColumns)
+ i < m_aColMapping.size(); ++i)
+ {
+ if (std::find(m_aOrderbyColumnNumber.begin(),
+ m_aOrderbyColumnNumber.end(),
+ sal::static_int_cast<sal_Int32>(i))
+ == m_aOrderbyColumnNumber.end())
+ {
+ m_aOrderbyColumnNumber.push_back(i);
+ // ASC or DESC doesn't matter
+ m_aOrderbyAscending.push_back(TAscendingOrder::ASC);
+ }
+ }
+ bDistinct = true;
+ }
+
+ if (IsSorted())
+ sortRows();
+
+ if (!m_pFileSet.is())
+ {
+ m_pFileSet = new OKeySet();
+
+ if (!m_pSQLAnalyzer->hasRestriction())
+ // now the Keyset can be filled!
+ // But be careful: It is assumed, that the FilePositions will be stored as sequence 1..n
+ {
+ if ( m_nLastVisitedPos > 0)
+ m_pFileSet->reserve( m_nLastVisitedPos );
+ for (sal_Int32 i = 0; i < m_nLastVisitedPos; i++)
+ m_pFileSet->push_back(i + 1);
+ }
+ }
+ OSL_ENSURE(m_pFileSet.is(),"No KeySet existing! :-(");
+
+ if(bDistinct && m_pFileSet.is())
+ {
+ OValueRow aSearchRow = new OValueVector(m_aRow->size());
+ OValueRefVector::iterator aRowIter = m_aRow->begin();
+ OValueVector::iterator aSearchIter = aSearchRow->begin();
+ for ( ++aRowIter,++aSearchIter; // the first column is the bookmark column
+ aRowIter != m_aRow->end();
+ ++aRowIter,++aSearchIter)
+ aSearchIter->setBound((*aRowIter)->isBound());
+
+ size_t nMaxRow = m_pFileSet->size();
+
+ if (nMaxRow)
+ {
+ #if OSL_DEBUG_LEVEL > 1
+ sal_Int32 nFound=0;
+ #endif
+ sal_Int32 nPos;
+ sal_Int32 nKey;
+
+ for( size_t j = nMaxRow-1; j > 0; --j)
+ {
+ nPos = (*m_pFileSet)[j];
+ ExecuteRow(IResultSetHelper::BOOKMARK,nPos,false);
+ m_pSQLAnalyzer->setSelectionEvaluationResult(m_aSelectRow,m_aColMapping);
+ { // cop*y row values
+ OValueRefVector::iterator copyFrom = m_aSelectRow->begin();
+ OValueVector::iterator copyTo = aSearchRow->begin();
+ for ( ++copyFrom,++copyTo; // the first column is the bookmark column
+ copyFrom != m_aSelectRow->end();
+ ++copyFrom,++copyTo)
+ *copyTo = *(*copyFrom);
+ }
+
+ // compare with next row
+ nKey = (*m_pFileSet)[j-1];
+ ExecuteRow(IResultSetHelper::BOOKMARK,nKey,false);
+ m_pSQLAnalyzer->setSelectionEvaluationResult(m_aSelectRow,m_aColMapping);
+ auto rowsMismatchIters = std::mismatch(std::next(m_aSelectRow->begin()), m_aSelectRow->end(),
+ std::next(aSearchRow->begin()), // the first column is the bookmark column
+ [](const OValueRefVector::value_type& a, const OValueVector::value_type& b) {
+ return !a->isBound() || (*a == b); });
+
+ if(rowsMismatchIters.first == m_aSelectRow->end())
+ (*m_pFileSet)[j] = 0; // Rows match -- Mark for deletion by setting key to 0
+ #if OSL_DEBUG_LEVEL > 1
+ else
+ nFound++;
+ #endif
+ }
+
+ m_pFileSet->erase(std::remove(m_pFileSet->begin(),m_pFileSet->end(),0)
+ ,m_pFileSet->end());
+ }
+ }
+ }
+ } break;
+
+ case OSQLStatementType::Update:
+ case OSQLStatementType::Delete:
+ // during processing count the number of processed Rows
+ m_nRowCountResult = 0;
+ // for now simply iterate over all rows and
+ // run the actions (or simply count):
+ {
+
+ bool bOK = true;
+ while (bOK)
+ {
+ bOK = ExecuteRow(IResultSetHelper::NEXT);
+
+ if (bOK)
+ {
+ m_nRowCountResult++;
+ }
+ }
+
+ // save result of COUNT(*) in nRowCountResult.
+ // nRowCount (number of rows in the result-set) = 1 for this request!
+ }
+ break;
+ case OSQLStatementType::Insert:
+ m_nRowCountResult = 0;
+
+ OSL_ENSURE(m_aAssignValues.is(),"No assign values set!");
+ if(!m_pTable->InsertRow(*m_aAssignValues, m_xColsIdx))
+ {
+ m_nFilePos = 0;
+ return;
+ }
+
+ m_nRowCountResult = 1;
+ break;
+ default:
+ SAL_WARN( "connectivity.drivers", "OResultSet::OpenImpl: unsupported statement type!" );
+ break;
+ }
+
+ // reset FilePos
+ m_nFilePos = 0;
+}
+
+const Sequence< sal_Int8 > & OResultSet::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+// css::lang::XUnoTunnel
+
+sal_Int64 OResultSet::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+void OResultSet::setBoundedColumns(const OValueRefRow& _rRow,
+ const OValueRefRow& _rSelectRow,
+ const ::rtl::Reference<connectivity::OSQLColumns>& _rxColumns,
+ const Reference<XIndexAccess>& _xNames,
+ bool _bSetColumnMapping,
+ const Reference<XDatabaseMetaData>& _xMetaData,
+ std::vector<sal_Int32>& _rColMapping)
+{
+ ::comphelper::UStringMixEqual aCase(_xMetaData->supportsMixedCaseQuotedIdentifiers());
+
+ Reference<XPropertySet> xTableColumn;
+ OUString sTableColumnName, sSelectColumnRealName;
+
+ const OUString sName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME);
+ const OUString sRealName = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME);
+ const OUString sType = OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE);
+
+ std::map<OSQLColumns::iterator,bool> aSelectIters;
+ OValueRefVector::const_iterator aRowIter = _rRow->begin()+1;
+ for (sal_Int32 i=0; // the first column is the bookmark column
+ aRowIter != _rRow->end();
+ ++i, ++aRowIter
+ )
+ {
+ (*aRowIter)->setBound(false);
+ try
+ {
+ // get the table column and its name
+ _xNames->getByIndex(i) >>= xTableColumn;
+ OSL_ENSURE(xTableColumn.is(), "OResultSet::setBoundedColumns: invalid table column!");
+ if (xTableColumn.is())
+ xTableColumn->getPropertyValue(sName) >>= sTableColumnName;
+ else
+ sTableColumnName.clear();
+
+ // look if we have such a select column
+ // TODO: would like to have a O(log n) search here ...
+ for ( OSQLColumns::iterator aIter = _rxColumns->begin();
+ aIter != _rxColumns->end();
+ ++aIter
+ )
+ {
+ if((*aIter)->getPropertySetInfo()->hasPropertyByName(sRealName))
+ (*aIter)->getPropertyValue(sRealName) >>= sSelectColumnRealName;
+ else
+ (*aIter)->getPropertyValue(sName) >>= sSelectColumnRealName;
+
+ if ( aCase(sTableColumnName, sSelectColumnRealName) && !(*aRowIter)->isBound() && aSelectIters.end() == aSelectIters.find(aIter) )
+ {
+ aSelectIters.emplace(aIter,true);
+ if(_bSetColumnMapping)
+ {
+ sal_Int32 nSelectColumnPos = aIter - _rxColumns->begin() + 1;
+ // the getXXX methods are 1-based ...
+ sal_Int32 nTableColumnPos = i + 1;
+ // get first table column is the bookmark column ...
+ _rColMapping[nSelectColumnPos] = nTableColumnPos;
+ (*_rSelectRow)[nSelectColumnPos] = *aRowIter;
+ }
+
+ (*aRowIter)->setBound(true);
+ sal_Int32 nType = DataType::OTHER;
+ if (xTableColumn.is())
+ xTableColumn->getPropertyValue(sType) >>= nType;
+ (*aRowIter)->setTypeKind(nType);
+
+ break;
+ }
+ }
+ }
+ catch (Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.drivers","");
+ }
+ }
+ // in this case we got more select columns as columns exist in the table
+ if ( !(_bSetColumnMapping && aSelectIters.size() != _rColMapping.size()) )
+ return;
+
+ Reference<XNameAccess> xNameAccess(_xNames,UNO_QUERY);
+ Sequence< OUString > aSelectColumns = xNameAccess->getElementNames();
+
+ for ( OSQLColumns::iterator aIter = _rxColumns->begin();
+ aIter != _rxColumns->end();
+ ++aIter
+ )
+ {
+ if ( aSelectIters.end() == aSelectIters.find(aIter) )
+ {
+ if ( (*aIter)->getPropertySetInfo()->hasPropertyByName(sRealName) )
+ (*aIter)->getPropertyValue(sRealName) >>= sSelectColumnRealName;
+ else
+ (*aIter)->getPropertyValue(sName) >>= sSelectColumnRealName;
+
+ if ( xNameAccess->hasByName( sSelectColumnRealName ) )
+ {
+ aSelectIters.emplace(aIter,true);
+ sal_Int32 nSelectColumnPos = aIter - _rxColumns->begin() + 1;
+ const OUString* pBegin = aSelectColumns.getConstArray();
+ const OUString* pEnd = pBegin + aSelectColumns.getLength();
+ for(sal_Int32 i=0;pBegin != pEnd;++pBegin,++i)
+ {
+ if ( aCase(*pBegin, sSelectColumnRealName) )
+ {
+ // the getXXX methods are 1-based ...
+ sal_Int32 nTableColumnPos = i + 1;
+ // get first table column is the bookmark column ...
+ _rColMapping[nSelectColumnPos] = nTableColumnPos;
+ (*_rSelectRow)[nSelectColumnPos] = (*_rRow)[nTableColumnPos];
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
+void SAL_CALL OResultSet::acquire() noexcept
+{
+ OResultSet_BASE::acquire();
+}
+
+void SAL_CALL OResultSet::release() noexcept
+{
+ OResultSet_BASE::release();
+}
+
+Reference< css::beans::XPropertySetInfo > SAL_CALL OResultSet::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+void OResultSet::doTableSpecials(const OSQLTable& _xTable)
+{
+ Reference<css::lang::XUnoTunnel> xTunnel(_xTable, UNO_QUERY_THROW);
+ m_pTable = comphelper::getFromUnoTunnel<OFileTable>(xTunnel);
+ assert(m_pTable.is());
+}
+
+void OResultSet::clearInsertRow()
+{
+ m_aRow->setDeleted(false); // set to false here because this is the new row
+ sal_Int32 nPos = 0;
+ for(ORowSetValueDecoratorRef& rValue : *m_aInsertRow)
+ {
+ if ( rValue->isBound() )
+ {
+ (*m_aRow)[nPos]->setValue( rValue->getValue() );
+ }
+ rValue->setBound(nPos == 0);
+ rValue->setModified(false);
+ rValue->setNull();
+ ++nPos;
+ }
+}
+
+void OResultSet::initializeRow(OValueRefRow& _rRow,sal_Int32 _nColumnCount)
+{
+ if(!_rRow.is())
+ {
+ _rRow = new OValueRefVector(_nColumnCount);
+ (*_rRow)[0]->setBound(true);
+ std::for_each(_rRow->begin()+1,_rRow->end(),TSetRefBound(false));
+ }
+}
+
+bool OResultSet::fillIndexValues(const Reference< XColumnsSupplier> &/*_xIndex*/)
+{
+ return false;
+}
+
+bool OResultSet::move(IResultSetHelper::Movement _eCursorPosition, sal_Int32 _nOffset, bool _bRetrieveData)
+{
+ return Move(_eCursorPosition,_nOffset,_bRetrieveData);
+}
+
+sal_Int32 OResultSet::getDriverPos() const
+{
+ return (*m_aRow)[0]->getValue().getInt32();
+}
+
+bool OResultSet::isRowDeleted() const
+{
+ return m_aRow->isDeleted();
+}
+
+void SAL_CALL OResultSet::disposing( const EventObject& Source )
+{
+ Reference<XPropertySet> xProp = m_pTable;
+ if(m_pTable.is() && Source.Source == xProp)
+ {
+ m_pTable.clear();
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FResultSetMetaData.cxx b/connectivity/source/drivers/file/FResultSetMetaData.cxx
new file mode 100644
index 000000000..fdc944043
--- /dev/null
+++ b/connectivity/source/drivers/file/FResultSetMetaData.cxx
@@ -0,0 +1,188 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/FResultSetMetaData.hxx>
+#include <file/FTable.hxx>
+#include <comphelper/extract.hxx>
+#include <connectivity/dbexception.hxx>
+#include <comphelper/types.hxx>
+#include <o3tl/safeint.hxx>
+
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace dbtools;
+using namespace connectivity::file;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+
+
+OResultSetMetaData::OResultSetMetaData(const ::rtl::Reference<connectivity::OSQLColumns>& _rxColumns,const OUString& _aTableName,OFileTable* _pTable)
+ :m_aTableName(_aTableName)
+ ,m_xColumns(_rxColumns)
+ ,m_pTable(_pTable)
+{
+}
+
+
+OResultSetMetaData::~OResultSetMetaData()
+{
+ m_xColumns = nullptr;
+}
+
+void OResultSetMetaData::checkColumnIndex(sal_Int32 column)
+{
+ if(column <= 0 || o3tl::make_unsigned(column) > m_xColumns->size())
+ throwInvalidIndexException(*this);
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnDisplaySize( sal_Int32 column )
+{
+ return getPrecision(column);
+}
+
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnType( sal_Int32 column )
+{
+ checkColumnIndex(column);
+ return getINT32((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)));
+}
+
+
+sal_Int32 SAL_CALL OResultSetMetaData::getColumnCount( )
+{
+ return m_xColumns->size();
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isCaseSensitive( sal_Int32 /*column*/ )
+{
+ return false;
+}
+
+
+OUString SAL_CALL OResultSetMetaData::getSchemaName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+
+OUString SAL_CALL OResultSetMetaData::getColumnName( sal_Int32 column )
+{
+ checkColumnIndex(column);
+
+ Any aName((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)));
+ return aName.hasValue() ? getString(aName) : getString((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME)));
+}
+
+OUString SAL_CALL OResultSetMetaData::getTableName( sal_Int32 /*column*/ )
+{
+ return m_aTableName;
+}
+
+OUString SAL_CALL OResultSetMetaData::getCatalogName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnTypeName( sal_Int32 column )
+{
+ checkColumnIndex(column);
+ return getString((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)));
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnLabel( sal_Int32 column )
+{
+ return getColumnName(column);
+}
+
+OUString SAL_CALL OResultSetMetaData::getColumnServiceName( sal_Int32 /*column*/ )
+{
+ return OUString();
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isCurrency( sal_Int32 column )
+{
+ checkColumnIndex(column);
+ return getBOOL((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)));
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isAutoIncrement( sal_Int32 /*setCatalogcolumn*/ )
+{
+ return false;
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isSigned( sal_Int32 /*column*/ )
+{
+ return true;
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getPrecision( sal_Int32 column )
+{
+ checkColumnIndex(column);
+ return getINT32((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)));
+}
+
+sal_Int32 SAL_CALL OResultSetMetaData::getScale( sal_Int32 column )
+{
+ checkColumnIndex(column);
+ return getINT32((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)));
+}
+
+
+sal_Int32 SAL_CALL OResultSetMetaData::isNullable( sal_Int32 column )
+{
+ checkColumnIndex(column);
+ return getINT32((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)));
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isSearchable( sal_Int32 /*column*/ )
+{
+ return true;
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isReadOnly( sal_Int32 column )
+{
+ checkColumnIndex(column);
+ return m_pTable->isReadOnly() || (
+ (*m_xColumns)[column-1]->getPropertySetInfo()->hasPropertyByName(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FUNCTION)) &&
+ ::cppu::any2bool((*m_xColumns)[column-1]->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FUNCTION))));
+}
+
+
+sal_Bool SAL_CALL OResultSetMetaData::isDefinitelyWritable( sal_Int32 column )
+{
+ return !isReadOnly(column);
+}
+
+sal_Bool SAL_CALL OResultSetMetaData::isWritable( sal_Int32 column )
+{
+ return !isReadOnly(column);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FStatement.cxx b/connectivity/source/drivers/file/FStatement.cxx
new file mode 100644
index 000000000..d32ac0ed2
--- /dev/null
+++ b/connectivity/source/drivers/file/FStatement.cxx
@@ -0,0 +1,711 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <sal/config.h>
+
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <file/FStatement.hxx>
+#include <file/FConnection.hxx>
+#include <sqlbison.hxx>
+#include <file/FDriver.hxx>
+#include <file/FResultSet.hxx>
+#include <sal/log.hxx>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <strings.hrc>
+#include <algorithm>
+
+namespace connectivity::file
+{
+
+
+using namespace dbtools;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::lang;
+using namespace com::sun::star::beans;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdbcx;
+using namespace com::sun::star::container;
+
+OStatement_Base::OStatement_Base(OConnection* _pConnection )
+ :OStatement_BASE(m_aMutex)
+ ,::comphelper::OPropertyContainer(OStatement_BASE::rBHelper)
+ ,m_xDBMetaData(_pConnection->getMetaData())
+ ,m_aParser( _pConnection->getDriver()->getComponentContext() )
+ ,m_aSQLIterator( _pConnection, _pConnection->createCatalog()->getTables(), m_aParser )
+ ,m_pConnection(_pConnection)
+ ,m_pParseTree(nullptr)
+ ,m_nMaxFieldSize(0)
+ ,m_nMaxRows(0)
+ ,m_nQueryTimeOut(0)
+ ,m_nFetchSize(0)
+ ,m_nResultSetType(ResultSetType::FORWARD_ONLY)
+ ,m_nFetchDirection(FetchDirection::FORWARD)
+ ,m_nResultSetConcurrency(ResultSetConcurrency::UPDATABLE)
+ ,m_bEscapeProcessing(true)
+{
+ sal_Int32 nAttrib = 0;
+
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_CURSORNAME), PROPERTY_ID_CURSORNAME, nAttrib,&m_aCursorName, ::cppu::UnoType<OUString>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXFIELDSIZE), PROPERTY_ID_MAXFIELDSIZE, nAttrib,&m_nMaxFieldSize, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MAXROWS), PROPERTY_ID_MAXROWS, nAttrib,&m_nMaxRows, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_QUERYTIMEOUT), PROPERTY_ID_QUERYTIMEOUT, nAttrib,&m_nQueryTimeOut, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHSIZE), PROPERTY_ID_FETCHSIZE, nAttrib,&m_nFetchSize, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETTYPE), PROPERTY_ID_RESULTSETTYPE, nAttrib,&m_nResultSetType, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_FETCHDIRECTION), PROPERTY_ID_FETCHDIRECTION, nAttrib,&m_nFetchDirection, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ESCAPEPROCESSING),PROPERTY_ID_ESCAPEPROCESSING, nAttrib,&m_bEscapeProcessing,cppu::UnoType<bool>::get());
+
+ registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_RESULTSETCONCURRENCY), PROPERTY_ID_RESULTSETCONCURRENCY, nAttrib,&m_nResultSetConcurrency, ::cppu::UnoType<sal_Int32>::get());
+}
+
+OStatement_Base::~OStatement_Base()
+{
+ osl_atomic_increment( &m_refCount );
+ disposing();
+}
+
+void OStatement_Base::disposeResultSet()
+{
+ SAL_INFO( "connectivity.drivers", "file Ocke.Janssen@sun.com OStatement_Base::disposeResultSet" );
+ // free the cursor if alive
+ Reference< XComponent > xComp(m_xResultSet.get(), UNO_QUERY);
+ assert(xComp.is() || !m_xResultSet.get().is());
+ if (xComp.is())
+ xComp->dispose();
+ m_xResultSet.clear();
+}
+
+void OStatement_BASE2::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ disposeResultSet();
+
+ if(m_pSQLAnalyzer)
+ m_pSQLAnalyzer->dispose();
+
+ if(m_aRow.is())
+ {
+ m_aRow->clear();
+ m_aRow = nullptr;
+ }
+
+ m_aSQLIterator.dispose();
+
+ m_pTable.clear();
+
+ m_pConnection.clear();
+
+ if ( m_pParseTree )
+ {
+ delete m_pParseTree;
+ m_pParseTree = nullptr;
+ }
+
+ OStatement_Base::disposing();
+}
+
+void SAL_CALL OStatement_Base::acquire() noexcept
+{
+ OStatement_BASE::acquire();
+}
+
+void SAL_CALL OStatement_BASE2::release() noexcept
+{
+ OStatement_BASE::release();
+}
+
+Any SAL_CALL OStatement_Base::queryInterface( const Type & rType )
+{
+ const Any aRet = OStatement_BASE::queryInterface(rType);
+ return aRet.hasValue() ? aRet : OPropertySetHelper::queryInterface(rType);
+}
+
+Sequence< Type > SAL_CALL OStatement_Base::getTypes( )
+{
+ ::cppu::OTypeCollection aTypes( cppu::UnoType<css::beans::XMultiPropertySet>::get(),
+ cppu::UnoType<css::beans::XFastPropertySet>::get(),
+ cppu::UnoType<css::beans::XPropertySet>::get());
+
+ return ::comphelper::concatSequences(aTypes.getTypes(),OStatement_BASE::getTypes());
+}
+
+
+void SAL_CALL OStatement_Base::cancel( )
+{
+}
+
+void SAL_CALL OStatement_Base::close()
+{
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+ }
+ dispose();
+}
+
+void OStatement_Base::closeResultSet()
+{
+ SAL_INFO( "connectivity.drivers", "file Ocke.Janssen@sun.com OStatement_Base::clearMyResultSet " );
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ Reference< XCloseable > xCloseable(m_xResultSet.get(), UNO_QUERY);
+ assert(xCloseable.is() || !m_xResultSet.get().is());
+ if (xCloseable.is())
+ {
+ try
+ {
+ xCloseable->close();
+ }
+ catch( const DisposedException& ) { }
+ }
+
+ m_xResultSet.clear();
+}
+
+Any SAL_CALL OStatement_Base::getWarnings( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ return Any(m_aLastWarning);
+}
+
+void SAL_CALL OStatement_Base::clearWarnings( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ m_aLastWarning = SQLWarning();
+}
+
+::cppu::IPropertyArrayHelper* OStatement_Base::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+
+::cppu::IPropertyArrayHelper & OStatement_Base::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+rtl::Reference<OResultSet> OStatement::createResultSet()
+{
+ return new OResultSet(this,m_aSQLIterator);
+}
+
+IMPLEMENT_SERVICE_INFO(OStatement,"com.sun.star.sdbc.driver.file.Statement","com.sun.star.sdbc.Statement");
+
+void SAL_CALL OStatement::acquire() noexcept
+{
+ OStatement_BASE2::acquire();
+}
+
+void SAL_CALL OStatement::release() noexcept
+{
+ OStatement_BASE2::release();
+}
+
+
+sal_Bool SAL_CALL OStatement::execute( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ executeQuery(sql);
+
+ return m_aSQLIterator.getStatementType() == OSQLStatementType::Select;
+}
+
+
+Reference< XResultSet > SAL_CALL OStatement::executeQuery( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+ construct(sql);
+ Reference< XResultSet > xRS;
+ rtl::Reference<OResultSet> pResult = createResultSet();
+ xRS = pResult;
+ initializeResultSet(pResult.get());
+ m_xResultSet = xRS;
+
+ pResult->OpenImpl();
+
+ return xRS;
+}
+
+Reference< XConnection > SAL_CALL OStatement::getConnection( )
+{
+ return m_pConnection;
+}
+
+sal_Int32 SAL_CALL OStatement::executeUpdate( const OUString& sql )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ checkDisposed(OStatement_BASE::rBHelper.bDisposed);
+
+
+ construct(sql);
+ rtl::Reference<OResultSet> pResult = createResultSet();
+ initializeResultSet(pResult.get());
+ pResult->OpenImpl();
+
+ return pResult->getRowCountResult();
+}
+
+
+void SAL_CALL OStatement_Base::disposing()
+{
+ if(m_aEvaluateRow.is())
+ {
+ m_aEvaluateRow->clear();
+ m_aEvaluateRow = nullptr;
+ }
+ OStatement_BASE::disposing();
+}
+
+Reference< css::beans::XPropertySetInfo > SAL_CALL OStatement_Base::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+Any SAL_CALL OStatement::queryInterface( const Type & rType )
+{
+ Any aRet = OStatement_XStatement::queryInterface( rType);
+ return aRet.hasValue() ? aRet : OStatement_BASE2::queryInterface( rType);
+}
+
+void OStatement_Base::analyzeSQL()
+{
+ OSL_ENSURE(m_pSQLAnalyzer,"OResultSet::analyzeSQL: Analyzer isn't set!");
+ // start analysing the statement
+ m_pSQLAnalyzer->setOrigColumns(m_xColNames);
+ m_pSQLAnalyzer->start(m_pParseTree);
+
+ const OSQLParseNode* pOrderbyClause = m_aSQLIterator.getOrderTree();
+ if(!pOrderbyClause)
+ return;
+
+ OSQLParseNode * pOrderingSpecCommalist = pOrderbyClause->getChild(2);
+ OSL_ENSURE(SQL_ISRULE(pOrderingSpecCommalist,ordering_spec_commalist),"OResultSet: Error in Parse Tree");
+
+ for (size_t m = 0; m < pOrderingSpecCommalist->count(); m++)
+ {
+ OSQLParseNode * pOrderingSpec = pOrderingSpecCommalist->getChild(m);
+ OSL_ENSURE(SQL_ISRULE(pOrderingSpec,ordering_spec),"OResultSet: Error in Parse Tree");
+ OSL_ENSURE(pOrderingSpec->count() == 2,"OResultSet: Error in Parse Tree");
+
+ OSQLParseNode * pColumnRef = pOrderingSpec->getChild(0);
+ if(!SQL_ISRULE(pColumnRef,column_ref))
+ {
+ throw SQLException();
+ }
+ OSQLParseNode * pAscendingDescending = pOrderingSpec->getChild(1);
+ setOrderbyColumn(pColumnRef,pAscendingDescending);
+ }
+}
+
+void OStatement_Base::setOrderbyColumn( OSQLParseNode const * pColumnRef,
+ OSQLParseNode const * pAscendingDescending)
+{
+ OUString aColumnName;
+ if (pColumnRef->count() == 1)
+ aColumnName = pColumnRef->getChild(0)->getTokenValue();
+ else if (pColumnRef->count() == 3)
+ {
+ pColumnRef->getChild(2)->parseNodeToStr( aColumnName, getOwnConnection(), nullptr, false, false );
+ }
+ else
+ {
+ throw SQLException();
+ }
+
+ Reference<XColumnLocate> xColLocate(m_xColNames,UNO_QUERY);
+ if(!xColLocate.is())
+ return;
+ // Everything tested and we have the name of the Column.
+ // What number is the Column?
+ ::rtl::Reference<OSQLColumns> aSelectColumns = m_aSQLIterator.getSelectColumns();
+ ::comphelper::UStringMixEqual aCase;
+ OSQLColumns::const_iterator aFind = ::connectivity::find(aSelectColumns->begin(),aSelectColumns->end(),aColumnName,aCase);
+ if ( aFind == aSelectColumns->end() )
+ throw SQLException();
+ m_aOrderbyColumnNumber.push_back((aFind - aSelectColumns->begin()) + 1);
+
+ // Ascending or Descending?
+ m_aOrderbyAscending.push_back(SQL_ISTOKEN(pAscendingDescending,DESC) ? TAscendingOrder::DESC : TAscendingOrder::ASC);
+}
+
+void OStatement_Base::construct(const OUString& sql)
+{
+ OUString aErr;
+ m_pParseTree = m_aParser.parseTree(aErr,sql).release();
+ if(!m_pParseTree)
+ throw SQLException(aErr,*this,OUString(),0,Any());
+
+ m_aSQLIterator.setParseTree(m_pParseTree);
+ m_aSQLIterator.traverseAll();
+ const OSQLTables& rTabs = m_aSQLIterator.getTables();
+
+ // sanity checks
+ if ( rTabs.empty() )
+ // no tables -> nothing to operate on -> error
+ m_pConnection->throwGenericSQLException(STR_QUERY_NO_TABLE,*this);
+
+ if ( rTabs.size() > 1 || m_aSQLIterator.hasErrors() )
+ // more than one table -> can't operate on them -> error
+ m_pConnection->throwGenericSQLException(STR_QUERY_MORE_TABLES,*this);
+
+ if ( (m_aSQLIterator.getStatementType() == OSQLStatementType::Select) && m_aSQLIterator.getSelectColumns()->empty() )
+ // SELECT statement without columns -> error
+ m_pConnection->throwGenericSQLException(STR_QUERY_NO_COLUMN,*this);
+
+ switch(m_aSQLIterator.getStatementType())
+ {
+ case OSQLStatementType::CreateTable:
+ case OSQLStatementType::OdbcCall:
+ case OSQLStatementType::Unknown:
+ m_pConnection->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,*this);
+ break;
+ case OSQLStatementType::Select:
+ if(SQL_ISRULE(m_aSQLIterator.getParseTree(), union_statement))
+ {
+ m_pConnection->throwGenericSQLException(STR_QUERY_TOO_COMPLEX, *this);
+ }
+ assert(SQL_ISRULE(m_aSQLIterator.getParseTree(), select_statement));
+ break;
+ default:
+ break;
+ }
+
+ // at this moment we support only one table per select statement
+ m_pTable = comphelper::getFromUnoTunnel<OFileTable>(rTabs.begin()->second);
+ OSL_ENSURE(m_pTable.is(),"No table!");
+ if ( m_pTable.is() )
+ m_xColNames = m_pTable->getColumns();
+ Reference<XIndexAccess> xNames(m_xColNames,UNO_QUERY);
+ // set the binding of the resultrow
+ m_aRow = new OValueRefVector(xNames->getCount());
+ (*m_aRow)[0]->setBound(true);
+ std::for_each(m_aRow->begin()+1,m_aRow->end(),TSetRefBound(false));
+
+ // set the binding of the resultrow
+ m_aEvaluateRow = new OValueRefVector(xNames->getCount());
+
+ (*m_aEvaluateRow)[0]->setBound(true);
+ std::for_each(m_aEvaluateRow->begin()+1,m_aEvaluateRow->end(),TSetRefBound(false));
+
+ // set the select row
+ m_aSelectRow = new OValueRefVector(m_aSQLIterator.getSelectColumns()->size());
+ std::for_each(m_aSelectRow->begin(),m_aSelectRow->end(),TSetRefBound(true));
+
+ // create the column mapping
+ createColumnMapping();
+
+ m_pSQLAnalyzer.reset( new OSQLAnalyzer(m_pConnection.get()) );
+
+ analyzeSQL();
+}
+
+void OStatement_Base::createColumnMapping()
+{
+ // initialize the column index map (mapping select columns to table columns)
+ ::rtl::Reference<connectivity::OSQLColumns> xColumns = m_aSQLIterator.getSelectColumns();
+ m_aColMapping.resize(xColumns->size() + 1);
+ for (sal_Int32 i=0; i<static_cast<sal_Int32>(m_aColMapping.size()); ++i)
+ m_aColMapping[i] = i;
+
+ Reference<XIndexAccess> xNames(m_xColNames,UNO_QUERY);
+ // now check which columns are bound
+ OResultSet::setBoundedColumns(m_aRow,m_aSelectRow,xColumns,xNames,true,m_xDBMetaData,m_aColMapping);
+}
+
+void OStatement_Base::initializeResultSet(OResultSet* _pResult)
+{
+ GetAssignValues();
+
+ _pResult->setSqlAnalyzer(m_pSQLAnalyzer.get());
+ _pResult->setOrderByColumns(std::vector(m_aOrderbyColumnNumber));
+ _pResult->setOrderByAscending(std::vector(m_aOrderbyAscending));
+ _pResult->setBindingRow(m_aRow);
+ _pResult->setColumnMapping(std::vector(m_aColMapping));
+ _pResult->setEvaluationRow(m_aEvaluateRow);
+ _pResult->setAssignValues(m_aAssignValues);
+ _pResult->setSelectRow(m_aSelectRow);
+
+ m_pSQLAnalyzer->bindSelectRow(m_aRow);
+ m_pSQLAnalyzer->bindEvaluationRow(m_aEvaluateRow); // Set values in the code of the Compiler
+}
+
+void OStatement_Base::GetAssignValues()
+{
+ if (m_pParseTree == nullptr)
+ {
+ ::dbtools::throwFunctionSequenceException(*this);
+ return;
+ }
+
+ if (SQL_ISRULE(m_pParseTree,select_statement))
+ // no values have to be set for SELECT
+ return;
+ else if (SQL_ISRULE(m_pParseTree,insert_statement))
+ {
+ // Create Row for the values to be set (Reference through new)
+ if(m_aAssignValues.is())
+ m_aAssignValues->clear();
+ sal_Int32 nCount = Reference<XIndexAccess>(m_xColNames,UNO_QUERY_THROW)->getCount();
+ m_aAssignValues = new OAssignValues(nCount);
+ // unbound all
+ std::for_each(m_aAssignValues->begin()+1,m_aAssignValues->end(),TSetRefBound(false));
+
+ m_aParameterIndexes.resize(nCount+1,SQL_NO_PARAMETER);
+
+ // List of Column-Names, that exist in the column_commalist (separated by ;):
+ std::vector<OUString> aColumnNameList;
+
+ OSL_ENSURE(m_pParseTree->count() >= 4,"OResultSet: Error in Parse Tree");
+
+ OSQLParseNode * pOptColumnCommalist = m_pParseTree->getChild(3);
+ OSL_ENSURE(pOptColumnCommalist != nullptr,"OResultSet: Error in Parse Tree");
+ OSL_ENSURE(SQL_ISRULE(pOptColumnCommalist,opt_column_commalist),"OResultSet: Error in Parse Tree");
+ if (pOptColumnCommalist->count() == 0)
+ {
+ const Sequence< OUString>& aNames = m_xColNames->getElementNames();
+ aColumnNameList.insert(aColumnNameList.end(), aNames.begin(), aNames.end());
+ }
+ else
+ {
+ OSL_ENSURE(pOptColumnCommalist->count() == 3,"OResultSet: Error in Parse Tree");
+
+ OSQLParseNode * pColumnCommalist = pOptColumnCommalist->getChild(1);
+ OSL_ENSURE(pColumnCommalist != nullptr,"OResultSet: Error in Parse Tree");
+ OSL_ENSURE(SQL_ISRULE(pColumnCommalist,column_commalist),"OResultSet: Error in Parse Tree");
+ OSL_ENSURE(pColumnCommalist->count() > 0,"OResultSet: Error in Parse Tree");
+
+ // All Columns in the column_commalist ...
+ for (size_t i = 0; i < pColumnCommalist->count(); i++)
+ {
+ OSQLParseNode * pCol = pColumnCommalist->getChild(i);
+ OSL_ENSURE(pCol != nullptr,"OResultSet: Error in Parse Tree");
+ aColumnNameList.push_back(pCol->getTokenValue());
+ }
+ }
+ if ( aColumnNameList.empty() )
+ throwFunctionSequenceException(*this);
+
+ // Values ...
+ OSQLParseNode * pValuesOrQuerySpec = m_pParseTree->getChild(4);
+ OSL_ENSURE(pValuesOrQuerySpec != nullptr,"OResultSet: pValuesOrQuerySpec must not be NULL!");
+ OSL_ENSURE(SQL_ISRULE(pValuesOrQuerySpec,values_or_query_spec),"OResultSet: ! SQL_ISRULE(pValuesOrQuerySpec,values_or_query_spec)");
+ OSL_ENSURE(pValuesOrQuerySpec->count() > 0,"OResultSet: pValuesOrQuerySpec->count() <= 0");
+
+ // just "VALUES" is allowed ...
+ if (! SQL_ISTOKEN(pValuesOrQuerySpec->getChild(0),VALUES))
+ throwFunctionSequenceException(*this);
+
+ OSL_ENSURE(pValuesOrQuerySpec->count() == 4,"OResultSet: pValuesOrQuerySpec->count() != 4");
+
+ // List of values
+ OSQLParseNode * pInsertAtomCommalist = pValuesOrQuerySpec->getChild(2);
+ OSL_ENSURE(pInsertAtomCommalist != nullptr,"OResultSet: pInsertAtomCommalist must not be NULL!");
+ OSL_ENSURE(pInsertAtomCommalist->count() > 0,"OResultSet: pInsertAtomCommalist <= 0");
+
+ sal_Int32 nIndex=0;
+ for (size_t i = 0; i < pInsertAtomCommalist->count(); i++)
+ {
+ OSQLParseNode * pRow_Value_Const = pInsertAtomCommalist->getChild(i); // row_value_constructor
+ OSL_ENSURE(pRow_Value_Const != nullptr,"OResultSet: pRow_Value_Const must not be NULL!");
+ if(SQL_ISRULE(pRow_Value_Const,parameter))
+ {
+ ParseAssignValues(aColumnNameList,pRow_Value_Const,nIndex++); // only one Columnname allowed per loop
+ }
+ else if(pRow_Value_Const->isToken())
+ ParseAssignValues(aColumnNameList,pRow_Value_Const,i);
+ else
+ {
+ if(pRow_Value_Const->count() == aColumnNameList.size())
+ {
+ for (size_t j = 0; j < pRow_Value_Const->count(); ++j)
+ ParseAssignValues(aColumnNameList,pRow_Value_Const->getChild(j),nIndex++);
+ }
+ else
+ throwFunctionSequenceException(*this);
+ }
+ }
+ }
+ else if (SQL_ISRULE(m_pParseTree,update_statement_searched))
+ {
+ if(m_aAssignValues.is())
+ m_aAssignValues->clear();
+ sal_Int32 nCount = Reference<XIndexAccess>(m_xColNames,UNO_QUERY_THROW)->getCount();
+ m_aAssignValues = new OAssignValues(nCount);
+ // unbound all
+ std::for_each(m_aAssignValues->begin()+1,m_aAssignValues->end(),TSetRefBound(false));
+
+ m_aParameterIndexes.resize(nCount+1,SQL_NO_PARAMETER);
+
+ OSL_ENSURE(m_pParseTree->count() >= 4,"OResultSet: Error in Parse Tree");
+
+ OSQLParseNode * pAssignmentCommalist = m_pParseTree->getChild(3);
+ OSL_ENSURE(pAssignmentCommalist != nullptr,"OResultSet: pAssignmentCommalist == NULL");
+ OSL_ENSURE(SQL_ISRULE(pAssignmentCommalist,assignment_commalist),"OResultSet: Error in Parse Tree");
+ OSL_ENSURE(pAssignmentCommalist->count() > 0,"OResultSet: pAssignmentCommalist->count() <= 0");
+
+ // work on all assignments (commalist) ...
+ std::vector< OUString> aList(1);
+ for (size_t i = 0; i < pAssignmentCommalist->count(); i++)
+ {
+ OSQLParseNode * pAssignment = pAssignmentCommalist->getChild(i);
+ OSL_ENSURE(pAssignment != nullptr,"OResultSet: pAssignment == NULL");
+ OSL_ENSURE(SQL_ISRULE(pAssignment,assignment),"OResultSet: Error in Parse Tree");
+ OSL_ENSURE(pAssignment->count() == 3,"OResultSet: pAssignment->count() != 3");
+
+ OSQLParseNode * pCol = pAssignment->getChild(0);
+ OSL_ENSURE(pCol != nullptr,"OResultSet: pCol == NULL");
+
+ OSQLParseNode * pComp = pAssignment->getChild(1);
+ OSL_ENSURE(pComp != nullptr,"OResultSet: pComp == NULL");
+ OSL_ENSURE(pComp->getNodeType() == SQLNodeType::Equal,"OResultSet: pComp->getNodeType() != SQLNodeType::Comparison");
+ if (pComp->getTokenValue().toChar() != '=')
+ {
+ throwFunctionSequenceException(*this);
+ }
+
+ OSQLParseNode * pVal = pAssignment->getChild(2);
+ OSL_ENSURE(pVal != nullptr,"OResultSet: pVal == NULL");
+ aList[0] = pCol->getTokenValue();
+ ParseAssignValues(aList,pVal,0);
+ }
+
+ }
+}
+
+void OStatement_Base::ParseAssignValues(const std::vector< OUString>& aColumnNameList,OSQLParseNode* pRow_Value_Constructor_Elem, sal_Int32 nIndex)
+{
+ OSL_ENSURE(o3tl::make_unsigned(nIndex) <= aColumnNameList.size(),"SdbFileCursor::ParseAssignValues: nIndex > aColumnNameList.GetTokenCount()");
+ OUString aColumnName(aColumnNameList[nIndex]);
+ OSL_ENSURE(aColumnName.getLength() > 0,"OResultSet: Column-Name not found");
+ OSL_ENSURE(pRow_Value_Constructor_Elem != nullptr,"OResultSet: pRow_Value_Constructor_Elem must not be NULL!");
+
+ if (pRow_Value_Constructor_Elem->getNodeType() == SQLNodeType::String ||
+ pRow_Value_Constructor_Elem->getNodeType() == SQLNodeType::IntNum ||
+ pRow_Value_Constructor_Elem->getNodeType() == SQLNodeType::ApproxNum)
+ {
+ // set value:
+ SetAssignValue(aColumnName, pRow_Value_Constructor_Elem->getTokenValue());
+ }
+ else if (SQL_ISTOKEN(pRow_Value_Constructor_Elem,NULL))
+ {
+ // set NULL
+ SetAssignValue(aColumnName, OUString(), true);
+ }
+ else if (SQL_ISRULE(pRow_Value_Constructor_Elem,parameter))
+ parseParamterElem(aColumnName,pRow_Value_Constructor_Elem);
+ else
+ {
+ throwFunctionSequenceException(*this);
+ }
+}
+
+void OStatement_Base::SetAssignValue(const OUString& aColumnName,
+ const OUString& aValue,
+ bool bSetNull,
+ sal_uInt32 nParameter)
+{
+ Reference<XPropertySet> xCol;
+ m_xColNames->getByName(aColumnName) >>= xCol;
+ sal_Int32 nId = Reference<XColumnLocate>(m_xColNames,UNO_QUERY_THROW)->findColumn(aColumnName);
+ // does this column actually exist in the file?
+
+ if (!xCol.is())
+ {
+ // This Column doesn't exist!
+ throwFunctionSequenceException(*this);
+ }
+
+
+ // Everything tested and we have the names of the Column.
+ // Now allocate one Value, set the value and tie the value to the Row.
+ if (bSetNull)
+ (*m_aAssignValues)[nId]->setNull();
+ else
+ {
+ switch (::comphelper::getINT32(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE))))
+ {
+ // put criteria depending on the Type as String or double in the variable
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ *(*m_aAssignValues)[nId] = ORowSetValue(aValue);
+ //Characterset is already converted, since the entire statement was converted
+ break;
+
+ case DataType::BIT:
+ if (aValue.equalsIgnoreAsciiCase("TRUE") || aValue[0] == '1')
+ *(*m_aAssignValues)[nId] = true;
+ else if (aValue.equalsIgnoreAsciiCase("FALSE") || aValue[0] == '0')
+ *(*m_aAssignValues)[nId] = false;
+ else
+ throwFunctionSequenceException(*this);
+ break;
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ *(*m_aAssignValues)[nId] = ORowSetValue(aValue);
+ break;
+ default:
+ throwFunctionSequenceException(*this);
+ }
+ }
+
+ // save Parameter-No. (as User Data)
+ // SQL_NO_PARAMETER = no Parameter.
+ m_aAssignValues->setParameterIndex(nId,nParameter);
+ if(nParameter != SQL_NO_PARAMETER)
+ m_aParameterIndexes[nParameter] = nId;
+}
+
+void OStatement_Base::parseParamterElem(const OUString& /*_sColumnName*/,OSQLParseNode* /*pRow_Value_Constructor_Elem*/)
+{
+ // do nothing here
+}
+
+}// namespace
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FStringFunctions.cxx b/connectivity/source/drivers/file/FStringFunctions.cxx
new file mode 100644
index 000000000..94152bc5d
--- /dev/null
+++ b/connectivity/source/drivers/file/FStringFunctions.cxx
@@ -0,0 +1,233 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/FStringFunctions.hxx>
+
+#include <comphelper/string.hxx>
+#include <rtl/ustrbuf.hxx>
+
+using namespace connectivity;
+using namespace connectivity::file;
+
+ORowSetValue OOp_Upper::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ return lhs.getString().toAsciiUpperCase();
+}
+
+ORowSetValue OOp_Lower::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ return lhs.getString().toAsciiLowerCase();
+}
+
+ORowSetValue OOp_Ascii::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+ OString sStr(OUStringToOString(lhs.getString(), RTL_TEXTENCODING_ASCII_US));
+ sal_Int32 nAscii = sStr.toChar();
+ return nAscii;
+}
+
+ORowSetValue OOp_CharLength::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ return lhs.getString().getLength();
+}
+
+ORowSetValue OOp_Char::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (lhs.empty())
+ return ORowSetValue();
+
+ OUStringBuffer sRet(static_cast<sal_Int32>(lhs.size()));
+ std::vector<ORowSetValue>::const_reverse_iterator aIter = lhs.rbegin();
+ std::vector<ORowSetValue>::const_reverse_iterator aEnd = lhs.rend();
+ for (; aIter != aEnd; ++aIter)
+ {
+ if (!aIter->isNull())
+ {
+ char c = static_cast<char>(aIter->getInt32());
+
+ sRet.appendAscii(&c, 1);
+ }
+ }
+
+ return sRet.makeStringAndClear();
+}
+
+ORowSetValue OOp_Concat::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (lhs.empty())
+ return ORowSetValue();
+
+ OUStringBuffer sRet;
+ std::vector<ORowSetValue>::const_reverse_iterator aIter = lhs.rbegin();
+ std::vector<ORowSetValue>::const_reverse_iterator aEnd = lhs.rend();
+ for (; aIter != aEnd; ++aIter)
+ {
+ if (aIter->isNull())
+ return ORowSetValue();
+
+ sRet.append(aIter->getString());
+ }
+
+ return sRet.makeStringAndClear();
+}
+
+ORowSetValue OOp_Locate::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (std::any_of(lhs.begin(), lhs.end(),
+ [](const ORowSetValue& rValue) { return rValue.isNull(); }))
+ return ORowSetValue();
+
+ if (lhs.size() == 2)
+ return OUString(OUString::number(lhs[0].getString().indexOf(lhs[1].getString()) + 1));
+
+ else if (lhs.size() != 3)
+ return ORowSetValue();
+
+ return lhs[1].getString().indexOf(lhs[2].getString(), lhs[0].getInt32()) + 1;
+}
+
+ORowSetValue OOp_SubString::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (std::any_of(lhs.begin(), lhs.end(),
+ [](const ORowSetValue& rValue) { return rValue.isNull(); }))
+ return ORowSetValue();
+
+ if (lhs.size() == 2 && lhs[0].getInt32() >= sal_Int32(0))
+ return lhs[1].getString().copy(lhs[0].getInt32() - 1);
+
+ else if (lhs.size() != 3 || lhs[1].getInt32() < sal_Int32(0))
+ return ORowSetValue();
+
+ return lhs[2].getString().copy(lhs[1].getInt32() - 1, lhs[0].getInt32());
+}
+
+ORowSetValue OOp_LTrim::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ OUString sRet = lhs.getString();
+ OUString sNew = sRet.trim();
+ return sRet.copy(sRet.indexOf(sNew));
+}
+
+ORowSetValue OOp_RTrim::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ OUString sRet = lhs.getString();
+ OUString sNew = sRet.trim();
+ return sRet.copy(0, sRet.lastIndexOf(sNew[sNew.getLength() - 1]) + 1);
+}
+
+ORowSetValue OOp_Space::operate(const ORowSetValue& lhs) const
+{
+ if (lhs.isNull())
+ return lhs;
+
+ sal_Int32 nCount = std::max(lhs.getInt32(), sal_Int32(0));
+ OUStringBuffer sRet(nCount);
+ comphelper::string::padToLength(sRet, nCount, ' ');
+ return sRet.makeStringAndClear();
+}
+
+ORowSetValue OOp_Replace::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (lhs.size() != 3)
+ return ORowSetValue();
+
+ OUString sStr = lhs[2].getString();
+ OUString sFrom = lhs[1].getString();
+ OUString sTo = lhs[0].getString();
+ sal_Int32 nIndexOf = sStr.indexOf(sFrom);
+ while (nIndexOf != -1)
+ {
+ sStr = sStr.replaceAt(nIndexOf, sFrom.getLength(), sTo);
+ nIndexOf = sStr.indexOf(sFrom, nIndexOf + sTo.getLength());
+ }
+
+ return sStr;
+}
+
+ORowSetValue OOp_Repeat::operate(const ORowSetValue& lhs, const ORowSetValue& rhs) const
+{
+ if (lhs.isNull() || rhs.isNull())
+ return lhs;
+
+ const OUString s = lhs.getString();
+ const sal_Int32 nCount = std::max(rhs.getInt32(), sal_Int32(0));
+ OUStringBuffer sRet(s.getLength() * nCount);
+ for (sal_Int32 i = 0; i < nCount; ++i)
+ {
+ sRet.append(s);
+ }
+ return sRet.makeStringAndClear();
+}
+
+ORowSetValue OOp_Insert::operate(const std::vector<ORowSetValue>& lhs) const
+{
+ if (lhs.size() != 4)
+ return ORowSetValue();
+
+ OUString sStr = lhs[3].getString();
+
+ sal_Int32 nStart = lhs[2].getInt32();
+ if (nStart < 1)
+ nStart = 1;
+ return sStr.replaceAt(nStart - 1, lhs[1].getInt32(), lhs[0].getString());
+}
+
+ORowSetValue OOp_Left::operate(const ORowSetValue& lhs, const ORowSetValue& rhs) const
+{
+ if (lhs.isNull() || rhs.isNull())
+ return lhs;
+
+ OUString sRet = lhs.getString();
+ sal_Int32 nCount = rhs.getInt32();
+ if (nCount < 0)
+ return ORowSetValue();
+ return sRet.copy(0, nCount);
+}
+
+ORowSetValue OOp_Right::operate(const ORowSetValue& lhs, const ORowSetValue& rhs) const
+{
+ if (lhs.isNull() || rhs.isNull())
+ return lhs;
+
+ sal_Int32 nCount = rhs.getInt32();
+ OUString sRet = lhs.getString();
+ if (nCount < 0 || nCount >= sRet.getLength())
+ return ORowSetValue();
+
+ return sRet.copy(sRet.getLength() - nCount, nCount);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FTable.cxx b/connectivity/source/drivers/file/FTable.cxx
new file mode 100644
index 000000000..6ec776452
--- /dev/null
+++ b/connectivity/source/drivers/file/FTable.cxx
@@ -0,0 +1,185 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+
+#include <file/FTable.hxx>
+#include <file/FColumns.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <unotools/ucbstreamhelper.hxx>
+
+using namespace connectivity;
+using namespace connectivity::file;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+
+OFileTable::OFileTable(sdbcx::OCollection* _pTables,OConnection* _pConnection)
+: OTable_TYPEDEF(_pTables,_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers())
+ ,m_pConnection(_pConnection)
+ ,m_nFilePos(0)
+ ,m_nBufferSize(0)
+ ,m_bWriteable(false)
+{
+ construct();
+ m_aColumns = new OSQLColumns();
+}
+
+OFileTable::OFileTable( sdbcx::OCollection* _pTables,OConnection* _pConnection,
+ const OUString& Name,
+ const OUString& Type,
+ const OUString& Description ,
+ const OUString& SchemaName,
+ const OUString& CatalogName )
+ : OTable_TYPEDEF(_pTables,_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers(),
+ Name,
+ Type,
+ Description,
+ SchemaName,
+ CatalogName)
+ , m_pConnection(_pConnection)
+ , m_nFilePos(0)
+ , m_nBufferSize(0)
+ , m_bWriteable(false)
+{
+ m_aColumns = new OSQLColumns();
+ construct();
+ // refreshColumns();
+}
+
+OFileTable::~OFileTable( )
+{
+}
+
+void OFileTable::refreshColumns()
+{
+ ::std::vector< OUString> aVector;
+ Reference< XResultSet > xResult = m_pConnection->getMetaData()->getColumns(Any(),
+ m_SchemaName,m_Name, "%");
+
+ if(xResult.is())
+ {
+ Reference< XRow > xRow(xResult,UNO_QUERY);
+ while(xResult->next())
+ aVector.push_back(xRow->getString(4));
+ }
+
+ if(m_xColumns)
+ m_xColumns->reFill(aVector);
+ else
+ m_xColumns.reset(new OColumns(this,m_aMutex,aVector));
+}
+
+void OFileTable::refreshKeys()
+{
+}
+
+void OFileTable::refreshIndexes()
+{
+}
+
+Any SAL_CALL OFileTable::queryInterface( const Type & rType )
+{
+ if( rType == cppu::UnoType<XKeysSupplier>::get()||
+ rType == cppu::UnoType<XRename>::get()||
+ rType == cppu::UnoType<XAlterTable>::get()||
+ rType == cppu::UnoType<XIndexesSupplier>::get()||
+ rType == cppu::UnoType<XDataDescriptorFactory>::get())
+ return Any();
+
+ return OTable_TYPEDEF::queryInterface(rType);
+}
+
+void SAL_CALL OFileTable::disposing()
+{
+ OTable::disposing();
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ FileClose();
+}
+
+const Sequence< sal_Int8 > & OFileTable::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit s_Id;
+ return s_Id.getSeq();
+}
+
+// css::lang::XUnoTunnel
+
+sal_Int64 OFileTable::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<OTable_TYPEDEF>{});
+}
+
+void OFileTable::FileClose()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ m_pFileStream.reset();
+ m_pBuffer.reset();
+}
+
+bool OFileTable::InsertRow(OValueRefVector& /*rRow*/, const css::uno::Reference< css::container::XIndexAccess>& /*_xCols*/)
+{
+ return false;
+}
+
+bool OFileTable::DeleteRow(const OSQLColumns& /*_rCols*/)
+{
+ return false;
+}
+
+bool OFileTable::UpdateRow(OValueRefVector& /*rRow*/, OValueRefRow& /*pOrgRow*/,const css::uno::Reference< css::container::XIndexAccess>& /*_xCols*/)
+{
+ return false;
+}
+
+void OFileTable::addColumn(const css::uno::Reference< css::beans::XPropertySet>& /*descriptor*/)
+{
+ OSL_FAIL( "OFileTable::addColumn: not implemented!" );
+}
+
+void OFileTable::dropColumn(sal_Int32 /*_nPos*/)
+{
+ OSL_FAIL( "OFileTable::addColumn: not implemented!" );
+}
+
+
+std::unique_ptr<SvStream> OFileTable::createStream_simpleError( const OUString& _rFileName, StreamMode _eOpenMode)
+{
+ std::unique_ptr<SvStream> pReturn(::utl::UcbStreamHelper::CreateStream( _rFileName, _eOpenMode, bool(_eOpenMode & StreamMode::NOCREATE)));
+ if (pReturn && (ERRCODE_NONE != pReturn->GetErrorCode()))
+ {
+ pReturn.reset();
+ }
+ return pReturn;
+}
+
+
+void OFileTable::refreshHeader()
+{
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/FTables.cxx b/connectivity/source/drivers/file/FTables.cxx
new file mode 100644
index 000000000..c063f4a89
--- /dev/null
+++ b/connectivity/source/drivers/file/FTables.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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/FTables.hxx>
+#include <file/FCatalog.hxx>
+
+using namespace connectivity;
+using namespace connectivity::file;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+
+sdbcx::ObjectType OTables::createObject(const OUString& /*_rName*/)
+{
+ return sdbcx::ObjectType();
+}
+
+void OTables::impl_refresh( )
+{
+ static_cast<OFileCatalog&>(m_rParent).refreshTables();
+}
+
+Any SAL_CALL OTables::queryInterface( const Type & rType )
+{
+ if( rType == cppu::UnoType<XColumnLocate>::get()||
+ rType == cppu::UnoType<XDataDescriptorFactory>::get()||
+ rType == cppu::UnoType<XAppend>::get()||
+ rType == cppu::UnoType<XDrop>::get())
+ return Any();
+
+ typedef sdbcx::OCollection OTables_BASE;
+ return OTables_BASE::queryInterface(rType);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/fanalyzer.cxx b/connectivity/source/drivers/file/fanalyzer.cxx
new file mode 100644
index 000000000..a0d1305f6
--- /dev/null
+++ b/connectivity/source/drivers/file/fanalyzer.cxx
@@ -0,0 +1,207 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/fanalyzer.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <tools/debug.hxx>
+#include <connectivity/sqlnode.hxx>
+#include <file/FConnection.hxx>
+#include <strings.hrc>
+
+using namespace ::connectivity;
+using namespace ::connectivity::file;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+
+OSQLAnalyzer::OSQLAnalyzer(OConnection* _pConnection)
+ :m_pConnection(_pConnection)
+ ,m_bHasSelectionCode(false)
+ ,m_bSelectionFirstTime(true)
+{
+ m_aCompiler = new OPredicateCompiler(this);
+ m_aInterpreter = new OPredicateInterpreter(m_aCompiler);
+}
+
+
+OSQLAnalyzer::~OSQLAnalyzer()
+{
+}
+
+
+void OSQLAnalyzer::start(OSQLParseNode const * pSQLParseNode)
+{
+ if (SQL_ISRULE(pSQLParseNode,select_statement))
+ {
+ DBG_ASSERT(pSQLParseNode->count() >= 4,"OFILECursor: Error in Parse Tree");
+
+ // check that we don't use anything other than count(*) as function
+ OSQLParseNode* pSelection = pSQLParseNode->getChild(2);
+ if ( SQL_ISRULE(pSelection,scalar_exp_commalist) )
+ {
+ for (size_t i = 0; i < pSelection->count(); i++)
+ {
+ OSQLParseNode *pColumnRef = pSelection->getChild(i)->getChild(0);
+ if ( ( SQL_ISRULE(pColumnRef,set_fct_spec) && pColumnRef->count() == 4 )
+ || SQL_ISRULE(pColumnRef,char_value_fct)
+ || SQL_ISRULE(pColumnRef,char_substring_fct)
+ || SQL_ISRULE(pColumnRef,position_exp)
+ || SQL_ISRULE(pColumnRef,fold)
+ || SQL_ISRULE(pColumnRef,length_exp)
+ || SQL_ISRULE(pColumnRef,num_value_exp)
+ || SQL_ISRULE(pColumnRef,term)
+ || SQL_ISRULE(pColumnRef,factor)
+ || SQL_ISRULE(pColumnRef,set_fct_spec) )
+ {
+ ::rtl::Reference<OPredicateCompiler> pCompiler = new OPredicateCompiler(this);
+ pCompiler->setOrigColumns(m_aCompiler->getOrigColumns());
+ ::rtl::Reference<OPredicateInterpreter> pInterpreter = new OPredicateInterpreter(pCompiler);
+ pCompiler->execute( pColumnRef );
+ m_aSelectionEvaluations.push_back( TPredicates(pCompiler,pInterpreter) );
+ }
+ else if ( SQL_ISRULE(pColumnRef,general_set_fct) && pColumnRef->count() != 4 )
+ {
+ m_pConnection->throwGenericSQLException(STR_QUERY_COMPLEX_COUNT,nullptr);
+ }
+ else
+ {
+ if ( SQL_ISPUNCTUATION( pColumnRef, "*" )
+ || ( SQL_ISRULE( pColumnRef, column_ref )
+ && ( pColumnRef->count() == 3 )
+ && ( pColumnRef->getChild(0)->getNodeType() == SQLNodeType::Name )
+ && SQL_ISPUNCTUATION( pColumnRef->getChild(1), "." )
+ && SQL_ISRULE( pColumnRef->getChild(2), column_val )
+ && SQL_ISPUNCTUATION( pColumnRef->getChild(2)->getChild(0), "*" )
+ )
+ )
+ {
+ // push one element for each column of our table
+ const Reference< XNameAccess > xColumnNames( m_aCompiler->getOrigColumns() );
+ const Sequence< OUString > aColumnNames( xColumnNames->getElementNames() );
+ for ( sal_Int32 j=0; j<aColumnNames.getLength(); ++j )
+ m_aSelectionEvaluations.push_back( TPredicates() );
+ }
+ else
+ m_aSelectionEvaluations.push_back( TPredicates() );
+ }
+ }
+ }
+ }
+
+ m_aCompiler->start(pSQLParseNode);
+}
+
+
+void OSQLAnalyzer::bindRow(OCodeList& rCodeList,const OValueRefRow& _pRow)
+{
+ for (auto const& code : rCodeList)
+ {
+ OOperandAttr* pAttr = dynamic_cast<OOperandAttr*>(code.get());
+ if (pAttr)
+ {
+ pAttr->bindValue(_pRow);
+ }
+ }
+}
+
+void OSQLAnalyzer::bindSelectRow(const OValueRefRow& _pRow)
+{
+ // first the select part
+ for (auto const& selectionEval : m_aSelectionEvaluations)
+ {
+ if ( selectionEval.first.is() )
+ bindRow(selectionEval.first->m_aCodeList,_pRow);
+ }
+}
+
+void OSQLAnalyzer::bindEvaluationRow(OValueRefRow const & _pRow)
+{
+ bindRow(m_aCompiler->m_aCodeList,_pRow);
+}
+
+OOperandAttr* OSQLAnalyzer::createOperandAttr(sal_Int32 _nPos,
+ const Reference< XPropertySet>& _xCol)
+{
+ return new OOperandAttr(static_cast<sal_uInt16>(_nPos),_xCol);
+}
+
+bool OSQLAnalyzer::hasRestriction() const
+{
+ return m_aCompiler->hasCode();
+}
+
+bool OSQLAnalyzer::hasFunctions() const
+{
+ if ( m_bSelectionFirstTime )
+ {
+ m_bSelectionFirstTime = false;
+ for (auto const& selectionEval : m_aSelectionEvaluations)
+ {
+ if ( selectionEval.first.is() )
+ {
+ m_bHasSelectionCode = selectionEval.first->hasCode();
+ if (m_bHasSelectionCode)
+ break;
+ }
+ }
+ }
+ return m_bHasSelectionCode;
+}
+
+void OSQLAnalyzer::setSelectionEvaluationResult(OValueRefRow const & _pRow,const std::vector<sal_Int32>& _rColumnMapping)
+{
+ sal_Int32 nPos = 1;
+ for (auto const& selectionEval : m_aSelectionEvaluations)
+ {
+ if ( selectionEval.second.is() )
+ {
+ // the first column (index 0) is for convenience only. The first real select column is no 1.
+ sal_Int32 map = nPos;
+ if ( nPos < static_cast< sal_Int32 >( _rColumnMapping.size() ) )
+ map = _rColumnMapping[nPos];
+ if ( map > 0 )
+ selectionEval.second->startSelection( (*_pRow)[map] );
+ }
+ ++nPos;
+ }
+}
+
+void OSQLAnalyzer::dispose()
+{
+ m_aCompiler->dispose();
+ for (auto const& selectionEval : m_aSelectionEvaluations)
+ {
+ if ( selectionEval.first.is() )
+ selectionEval.first->dispose();
+ }
+}
+
+void OSQLAnalyzer::setOrigColumns(const css::uno::Reference< css::container::XNameAccess>& rCols)
+{
+ m_aCompiler->setOrigColumns(rCols);
+ for (auto const& selectionEval : m_aSelectionEvaluations)
+ {
+ if ( selectionEval.first.is() )
+ selectionEval.first->setOrigColumns(rCols);
+ }
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/fcode.cxx b/connectivity/source/drivers/file/fcode.cxx
new file mode 100644
index 000000000..d41d3e607
--- /dev/null
+++ b/connectivity/source/drivers/file/fcode.cxx
@@ -0,0 +1,373 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/fcode.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <connectivity/sqlnode.hxx>
+#include <sqlbison.hxx>
+#include <com/sun/star/sdb/SQLFilterOperator.hpp>
+
+using namespace ::comphelper;
+using namespace connectivity;
+using namespace connectivity::file;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+
+OCode::~OCode() = default;
+
+OOperandRow::OOperandRow(sal_uInt16 _nPos, sal_Int32 _rType)
+ : OOperand(_rType)
+ , m_nRowPos(_nPos)
+{}
+
+void OOperandRow::bindValue(const OValueRefRow& _pRow)
+{
+ OSL_ENSURE(_pRow.is(),"NO EMPTY row allowed!");
+ m_pRow = _pRow;
+ OSL_ENSURE(m_pRow.is() && m_nRowPos < m_pRow->size(),"Invalid RowPos is >= vector.size()");
+ (*m_pRow)[m_nRowPos]->setBound(true);
+}
+
+void OOperandRow::setValue(const ORowSetValue& _rVal)
+{
+ OSL_ENSURE(m_pRow.is() && m_nRowPos < m_pRow->size(),"Invalid RowPos is >= vector.size()");
+ (*(*m_pRow)[m_nRowPos]) = _rVal;
+}
+
+const ORowSetValue& OOperandRow::getValue() const
+{
+ OSL_ENSURE(m_pRow.is() && m_nRowPos < m_pRow->size(),"Invalid RowPos is >= vector.size()");
+ return (*m_pRow)[m_nRowPos]->getValue();
+}
+
+
+void OOperandValue::setValue(const ORowSetValue& _rVal)
+{
+ m_aValue = _rVal;
+}
+
+OOperandParam::OOperandParam(sal_Int32 _nPos)
+ : OOperandRow(static_cast<sal_uInt16>(_nPos), DataType::VARCHAR) // Standard-Type
+{
+ //TODO: Actually do something here (the current state of OOperandParam appears to be "the
+ // remains of the very beginnings of a never finished implementation of support for parameters
+ // in this code", as Lionel put it in the comments at <https://gerrit.libreoffice.org/c/core/+/
+ // 116839/1#message-7b2bbf3543f559a0b67dc35cd940e2ab8829c274> "-Werror,-Wunused-but-set-variable
+ // (Clang 13 trunk)").
+}
+
+
+const ORowSetValue& OOperandValue::getValue() const
+{
+ return m_aValue;
+}
+
+
+OOperandConst::OOperandConst(const OSQLParseNode& rColumnRef, const OUString& aStrValue)
+{
+ switch (rColumnRef.getNodeType())
+ {
+ case SQLNodeType::String:
+ m_aValue = aStrValue;
+ m_eDBType = DataType::VARCHAR;
+ m_aValue.setBound(true);
+ return;
+ case SQLNodeType::IntNum:
+ case SQLNodeType::ApproxNum:
+ m_aValue = aStrValue.toDouble();
+ m_eDBType = DataType::DOUBLE;
+ m_aValue.setBound(true);
+ return;
+ default:
+ break;
+ }
+
+ if (SQL_ISTOKEN(&rColumnRef, TRUE))
+ {
+ m_aValue = 1.0;
+ m_eDBType = DataType::BIT;
+ }
+ else if (SQL_ISTOKEN(&rColumnRef, FALSE))
+ {
+ m_aValue = 0.0;
+ m_eDBType = DataType::BIT;
+ }
+ else
+ {
+ SAL_WARN( "connectivity.drivers", "Parse Error");
+ }
+ m_aValue.setBound(true);
+}
+
+
+// Implementation of the operators
+
+
+bool OBoolOperator::operate(const OOperand*, const OOperand*) const
+{
+ return false;
+}
+
+
+void OBoolOperator::Exec(OCodeStack& rCodeStack)
+{
+ OOperand *pRight = rCodeStack.top();
+ rCodeStack.pop();
+ OOperand *pLeft = rCodeStack.top();
+ rCodeStack.pop();
+
+ rCodeStack.push(new OOperandResultBOOL(operate(pLeft, pRight)));
+ if( typeid(OOperandResult) == typeid(*pLeft))
+ delete pLeft;
+ if( typeid(OOperandResult) == typeid(*pRight))
+ delete pRight;
+}
+
+bool OOp_NOT::operate(const OOperand* pLeft, const OOperand* ) const
+{
+ return !pLeft->isValid();
+}
+
+void OOp_NOT::Exec(OCodeStack& rCodeStack)
+{
+ OOperand* pOperand = rCodeStack.top();
+ rCodeStack.pop();
+
+ rCodeStack.push(new OOperandResultBOOL(operate(pOperand, nullptr)));
+
+ if( typeid(OOperandResult) == typeid(*pOperand))
+ delete pOperand;
+}
+
+bool OOp_AND::operate(const OOperand* pLeft, const OOperand* pRight) const
+{
+ return pLeft->isValid() && pRight->isValid();
+}
+
+
+bool OOp_OR::operate(const OOperand* pLeft, const OOperand* pRight) const
+{
+ return pLeft->isValid() || pRight->isValid();
+}
+
+
+void OOp_ISNULL::Exec(OCodeStack& rCodeStack)
+{
+ OOperand* pOperand = rCodeStack.top();
+ rCodeStack.pop();
+
+ rCodeStack.push(new OOperandResultBOOL(operate(pOperand, nullptr)));
+ if( typeid(OOperandResult) == typeid(*pOperand))
+ delete pOperand;
+}
+
+
+bool OOp_ISNULL::operate(const OOperand* pOperand, const OOperand*) const
+{
+ return pOperand->getValue().isNull();
+}
+
+
+bool OOp_ISNOTNULL::operate(const OOperand* pOperand, const OOperand*) const
+{
+ return !OOp_ISNULL::operate(pOperand, nullptr);
+}
+
+
+bool OOp_LIKE::operate(const OOperand* pLeft, const OOperand* pRight) const
+{
+ bool bMatch;
+ const ORowSetValue& aLH(pLeft->getValue());
+ const ORowSetValue& aRH(pRight->getValue());
+
+ if (aLH.isNull() || aRH.isNull())
+ bMatch = false;
+ else
+ {
+ bMatch = match(aRH.getString(), aLH.getString(), cEscape);
+ }
+ return bMatch;
+}
+
+
+bool OOp_NOTLIKE::operate(const OOperand* pLeft, const OOperand* pRight) const
+{
+ return !OOp_LIKE::operate(pLeft, pRight);
+}
+
+
+bool OOp_COMPARE::operate(const OOperand* pLeft, const OOperand* pRight) const
+{
+ const ORowSetValue& aLH(pLeft->getValue());
+ const ORowSetValue& aRH(pRight->getValue());
+
+ if (aLH.isNull() || aRH.isNull()) // if (!aLH.getValue() || !aRH.getValue())
+ return false;
+
+ bool bResult = false;
+ sal_Int32 eDBType = pLeft->getDBType();
+
+ // Comparison (depending on Data-type):
+ switch (eDBType)
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ {
+ OUString sLH = aLH.getString(), sRH = aRH.getString();
+ sal_Int32 nRes = sLH.compareToIgnoreAsciiCase(sRH);
+ switch(aPredicateType)
+ {
+ case SQLFilterOperator::EQUAL: bResult = (nRes == 0); break;
+ case SQLFilterOperator::NOT_EQUAL: bResult = (nRes != 0); break;
+ case SQLFilterOperator::LESS: bResult = (nRes < 0); break;
+ case SQLFilterOperator::LESS_EQUAL: bResult = (nRes <= 0); break;
+ case SQLFilterOperator::GREATER: bResult = (nRes > 0); break;
+ case SQLFilterOperator::GREATER_EQUAL: bResult = (nRes >= 0); break;
+ default: bResult = false;
+ }
+ } break;
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ case DataType::REAL:
+ case DataType::DOUBLE:
+ case DataType::BIT:
+ case DataType::TIMESTAMP:
+ case DataType::DATE:
+ case DataType::TIME:
+ {
+ double n = aLH.getDouble(), m = aRH.getDouble();
+
+ switch (aPredicateType)
+ {
+ case SQLFilterOperator::EQUAL: bResult = (n == m); break;
+ case SQLFilterOperator::LIKE: bResult = (n == m); break;
+ case SQLFilterOperator::NOT_EQUAL: bResult = (n != m); break;
+ case SQLFilterOperator::NOT_LIKE: bResult = (n != m); break;
+ case SQLFilterOperator::LESS: bResult = (n < m); break;
+ case SQLFilterOperator::LESS_EQUAL: bResult = (n <= m); break;
+ case SQLFilterOperator::GREATER: bResult = (n > m); break;
+ case SQLFilterOperator::GREATER_EQUAL: bResult = (n >= m); break;
+ default: bResult = false;
+ }
+ } break;
+ default:
+ bResult = aLH == aRH;
+ }
+ return bResult;
+}
+
+
+void ONumOperator::Exec(OCodeStack& rCodeStack)
+{
+ OOperand *pRight = rCodeStack.top();
+ rCodeStack.pop();
+ OOperand *pLeft = rCodeStack.top();
+ rCodeStack.pop();
+
+ rCodeStack.push(new OOperandResultNUM(operate(pLeft->getValue().getDouble(), pRight->getValue().getDouble())));
+ if( typeid(OOperandResult) == typeid(*pLeft))
+ delete pLeft;
+ if( typeid(OOperandResult) == typeid(*pRight))
+ delete pRight;
+}
+
+double OOp_ADD::operate(const double& fLeft,const double& fRight) const
+{
+ return fLeft + fRight;
+}
+
+
+double OOp_SUB::operate(const double& fLeft,const double& fRight) const
+{
+ return fLeft - fRight;
+}
+
+
+double OOp_MUL::operate(const double& fLeft,const double& fRight) const
+{
+ return fLeft * fRight;
+}
+
+
+double OOp_DIV::operate(const double& fLeft,const double& fRight) const
+{
+ return fLeft / fRight;
+}
+
+void ONthOperator::Exec(OCodeStack& rCodeStack)
+{
+ std::vector<ORowSetValue> aValues;
+ std::vector<OOperand*> aOperands;
+ OOperand* pOperand;
+ do
+ {
+ OSL_ENSURE(!rCodeStack.empty(),"Stack must be none empty!");
+ pOperand = rCodeStack.top();
+ rCodeStack.pop();
+ assert(pOperand);
+ if (pOperand && typeid(OStopOperand) != typeid(*pOperand))
+ aValues.push_back( pOperand->getValue() );
+ aOperands.push_back( pOperand );
+ }
+ while (pOperand && typeid(OStopOperand) != typeid(*pOperand));
+
+ rCodeStack.push(new OOperandResult(operate(aValues)));
+
+ for (const auto& rpOperand : aOperands)
+ {
+ if (typeid(OOperandResult) == typeid(*rpOperand))
+ delete rpOperand;
+ }
+}
+
+void OBinaryOperator::Exec(OCodeStack& rCodeStack)
+{
+ OOperand *pRight = rCodeStack.top();
+ rCodeStack.pop();
+ OOperand *pLeft = rCodeStack.top();
+ rCodeStack.pop();
+
+ if ( !rCodeStack.empty() && typeid(OStopOperand) == typeid(*rCodeStack.top()) )
+ rCodeStack.pop();
+
+ rCodeStack.push(new OOperandResult(operate(pLeft->getValue(),pRight->getValue())));
+ if(typeid(OOperandResult) == typeid(*pRight))
+ delete pRight;
+ if(typeid(OOperandResult) == typeid(*pLeft))
+ delete pLeft;
+}
+
+void OUnaryOperator::Exec(OCodeStack& rCodeStack)
+{
+ OSL_ENSURE(!rCodeStack.empty(),"Stack is empty!");
+ OOperand* pOperand = rCodeStack.top();
+ rCodeStack.pop();
+
+ rCodeStack.push(new OOperandResult(operate(pOperand->getValue())));
+ if (typeid(OOperandResult) == typeid(*pOperand))
+ delete pOperand;
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/fcomp.cxx b/connectivity/source/drivers/file/fcomp.cxx
new file mode 100644
index 000000000..5a1646a20
--- /dev/null
+++ b/connectivity/source/drivers/file/fcomp.cxx
@@ -0,0 +1,886 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/fcomp.hxx>
+#include <tools/debug.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <file/fanalyzer.hxx>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <com/sun/star/sdb/SQLFilterOperator.hpp>
+#include <file/FStringFunctions.hxx>
+#include <file/FDateFunctions.hxx>
+#include <file/FNumericFunctions.hxx>
+#include <file/FConnection.hxx>
+#include <tools/diagnose_ex.h>
+#include <sqlbison.hxx>
+#include <strings.hrc>
+
+using namespace connectivity;
+using namespace connectivity::file;
+using namespace com::sun::star::uno;
+using namespace com::sun::star::sdbc;
+using namespace com::sun::star::sdb;
+using namespace ::com::sun::star::container;
+using namespace com::sun::star;
+
+OPredicateCompiler::OPredicateCompiler(OSQLAnalyzer* pAnalyzer)//,OCursor& rCurs)
+ : m_pAnalyzer(pAnalyzer)
+ , m_nParamCounter(0)
+{
+}
+
+
+OPredicateCompiler::~OPredicateCompiler()
+{
+ Clean();
+}
+
+void OPredicateCompiler::dispose()
+{
+ Clean();
+ m_orgColumns = nullptr;
+}
+
+void OPredicateCompiler::start(OSQLParseNode const * pSQLParseNode)
+{
+ if (!pSQLParseNode)
+ return;
+
+ m_nParamCounter = 0;
+ // analyse Parse Tree (depending on Statement-type)
+ // and set pointer on WHERE-clause:
+ OSQLParseNode * pWhereClause = nullptr;
+
+ if (SQL_ISRULE(pSQLParseNode,select_statement))
+ {
+ OSQLParseNode * pOrderbyClause = nullptr;
+ DBG_ASSERT(pSQLParseNode->count() >= 4,"OFILECursor: Error in Parse Tree");
+
+ OSQLParseNode * pTableExp = pSQLParseNode->getChild(3);
+ DBG_ASSERT(pTableExp != nullptr,"Error in Parse Tree");
+ DBG_ASSERT(SQL_ISRULE(pTableExp,table_exp)," Error in Parse Tree");
+ DBG_ASSERT(pTableExp->count() == TABLE_EXPRESSION_CHILD_COUNT,"Error in Parse Tree");
+
+ // check that we don't use anything other than count(*) as function
+ OSQLParseNode* pSelection = pSQLParseNode->getChild(2);
+ if ( SQL_ISRULE(pSelection,scalar_exp_commalist) )
+ {
+ for (size_t i = 0; i < pSelection->count(); i++)
+ {
+ OSQLParseNode *pColumnRef = pSelection->getChild(i)->getChild(0);
+ if ( SQL_ISRULE(pColumnRef,general_set_fct) && pColumnRef->count() != 4 )
+ {
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_COMPLEX_COUNT,nullptr);
+ }
+ }
+ }
+
+
+ pWhereClause = pTableExp->getChild(1);
+ pOrderbyClause = pTableExp->getChild(ORDER_BY_CHILD_POS);
+ (void)pOrderbyClause;
+ }
+ else if (SQL_ISRULE(pSQLParseNode,update_statement_searched))
+ {
+ DBG_ASSERT(pSQLParseNode->count() == 5,"OFILECursor: Error in Parse Tree");
+ pWhereClause = pSQLParseNode->getChild(4);
+ }
+ else if (SQL_ISRULE(pSQLParseNode,delete_statement_searched))
+ {
+ DBG_ASSERT(pSQLParseNode->count() == 4,"Error in Parse Tree");
+ pWhereClause = pSQLParseNode->getChild(3);
+ }
+ else
+ // Other Statement. no selection-criteria
+ return;
+
+ if (SQL_ISRULE(pWhereClause,where_clause))
+ {
+ // a where-clause is not allowed to be empty:
+ DBG_ASSERT(pWhereClause->count() == 2,"OFILECursor: Error in Parse Tree");
+
+ OSQLParseNode * pComparisonPredicate = pWhereClause->getChild(1);
+ DBG_ASSERT(pComparisonPredicate != nullptr,"OFILECursor: Error in Parse Tree");
+
+ execute( pComparisonPredicate );
+ }
+ else
+ {
+ // The where-clause is optionally in the majority of cases, i.e. it might be an "optional-where-clause".
+ DBG_ASSERT(SQL_ISRULE(pWhereClause,opt_where_clause),"OPredicateCompiler: Error in Parse Tree");
+ }
+}
+
+
+OOperand* OPredicateCompiler::execute(OSQLParseNode const * pPredicateNode)
+{
+ OOperand* pOperand = nullptr;
+ if (pPredicateNode->count() == 3 && // Expression is bracketed
+ SQL_ISPUNCTUATION(pPredicateNode->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pPredicateNode->getChild(2),")"))
+ {
+ execute(pPredicateNode->getChild(1));
+ }
+ else if ((SQL_ISRULE(pPredicateNode,search_condition) || SQL_ISRULE(pPredicateNode,boolean_term))
+ && // AND/OR-linkage:
+ pPredicateNode->count() == 3)
+ {
+ execute(pPredicateNode->getChild(0)); // process the left branch
+ execute(pPredicateNode->getChild(2)); // process the right branch
+
+ if (SQL_ISTOKEN(pPredicateNode->getChild(1),OR)) // OR-Operator
+ {
+ m_aCodeList.emplace_back(new OOp_OR);
+ }
+ else if (SQL_ISTOKEN(pPredicateNode->getChild(1),AND)) // AND-Operator
+ m_aCodeList.emplace_back(new OOp_AND);
+ else
+ {
+ OSL_FAIL("OPredicateCompiler: Error in Parse Tree");
+ }
+ }
+ else if (SQL_ISRULE(pPredicateNode,boolean_factor))
+ {
+ execute(pPredicateNode->getChild(1));
+ m_aCodeList.emplace_back(new OOp_NOT);
+ }
+ else if (SQL_ISRULE(pPredicateNode,comparison_predicate))
+ {
+ execute_COMPARE(pPredicateNode);
+ }
+ else if (SQL_ISRULE(pPredicateNode,like_predicate))
+ {
+ execute_LIKE(pPredicateNode);
+ }
+ else if (SQL_ISRULE(pPredicateNode,between_predicate))
+ {
+ execute_BETWEEN(pPredicateNode);
+ }
+ else if (SQL_ISRULE(pPredicateNode,test_for_null))
+ {
+ execute_ISNULL(pPredicateNode);
+ }
+ else if(SQL_ISRULE(pPredicateNode,num_value_exp))
+ {
+ execute(pPredicateNode->getChild(0)); // process the left branch
+ execute(pPredicateNode->getChild(2)); // process the right branch
+ if (SQL_ISPUNCTUATION(pPredicateNode->getChild(1),"+"))
+ {
+ m_aCodeList.emplace_back(new OOp_ADD);
+ }
+ else if (SQL_ISPUNCTUATION(pPredicateNode->getChild(1),"-"))
+ m_aCodeList.emplace_back(new OOp_SUB);
+ else
+ {
+ OSL_FAIL("OPredicateCompiler: Error in Parse Tree num_value_exp");
+ }
+ }
+ else if(SQL_ISRULE(pPredicateNode,term))
+ {
+ execute(pPredicateNode->getChild(0)); // process the left branch
+ execute(pPredicateNode->getChild(2)); // process the right branch
+ if (SQL_ISPUNCTUATION(pPredicateNode->getChild(1),"*"))
+ {
+ m_aCodeList.emplace_back(new OOp_MUL);
+ }
+ else if (SQL_ISPUNCTUATION(pPredicateNode->getChild(1),"/"))
+ m_aCodeList.emplace_back(new OOp_DIV);
+ else
+ {
+ OSL_FAIL("OPredicateCompiler: Error in Parse Tree num_value_exp");
+ }
+ }
+ else
+ pOperand = execute_Operand(pPredicateNode); // now only simple operands will be processed
+
+ return pOperand;
+}
+
+
+void OPredicateCompiler::execute_COMPARE(OSQLParseNode const * pPredicateNode)
+{
+ DBG_ASSERT(pPredicateNode->count() == 3,"OFILECursor: Error in Parse Tree");
+
+ if ( !(SQL_ISRULE(pPredicateNode->getChild(0),column_ref) ||
+ pPredicateNode->getChild(2)->getNodeType() == SQLNodeType::String ||
+ pPredicateNode->getChild(2)->getNodeType() == SQLNodeType::IntNum ||
+ pPredicateNode->getChild(2)->getNodeType() == SQLNodeType::ApproxNum ||
+ SQL_ISTOKEN(pPredicateNode->getChild(2),TRUE) ||
+ SQL_ISTOKEN(pPredicateNode->getChild(2),FALSE) ||
+ SQL_ISRULE(pPredicateNode->getChild(2),parameter) ||
+ // odbc date
+ SQL_ISRULE(pPredicateNode->getChild(2),set_fct_spec) ||
+ SQL_ISRULE(pPredicateNode->getChild(2),position_exp) ||
+ SQL_ISRULE(pPredicateNode->getChild(2),char_substring_fct) ||
+ // upper, lower etc.
+ SQL_ISRULE(pPredicateNode->getChild(2),fold)) )
+ {
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,nullptr);
+ return;
+ }
+
+ sal_Int32 ePredicateType( SQLFilterOperator::EQUAL );
+ OSQLParseNode *pPrec = pPredicateNode->getChild(1);
+
+ if (pPrec->getNodeType() == SQLNodeType::Equal)
+ ePredicateType = SQLFilterOperator::EQUAL;
+ else if (pPrec->getNodeType() == SQLNodeType::NotEqual)
+ ePredicateType = SQLFilterOperator::NOT_EQUAL;
+ else if (pPrec->getNodeType() == SQLNodeType::Less)
+ ePredicateType = SQLFilterOperator::LESS;
+ else if (pPrec->getNodeType() == SQLNodeType::LessEq)
+ ePredicateType = SQLFilterOperator::LESS_EQUAL;
+ else if (pPrec->getNodeType() == SQLNodeType::GreatEq)
+ ePredicateType = SQLFilterOperator::GREATER_EQUAL;
+ else if (pPrec->getNodeType() == SQLNodeType::Great)
+ ePredicateType = SQLFilterOperator::GREATER;
+ else
+ OSL_FAIL( "OPredicateCompiler::execute_COMPARE: unexpected node type!" );
+
+ execute(pPredicateNode->getChild(0));
+ execute(pPredicateNode->getChild(2));
+ m_aCodeList.emplace_back( new OOp_COMPARE(ePredicateType) );
+}
+
+
+void OPredicateCompiler::execute_LIKE(OSQLParseNode const * pPredicateNode)
+{
+ DBG_ASSERT(pPredicateNode->count() == 2,"OFILECursor: Error in Parse Tree");
+ const OSQLParseNode* pPart2 = pPredicateNode->getChild(1);
+
+ sal_Unicode cEscape = L'\0';
+ const bool bNotLike = pPart2->getChild(0)->isToken();
+
+ OSQLParseNode* pAtom = pPart2->getChild(pPart2->count()-2);
+ OSQLParseNode* pOptEscape = pPart2->getChild(pPart2->count()-1);
+
+ if (!(pAtom->getNodeType() == SQLNodeType::String ||
+ SQL_ISRULE(pAtom,parameter) ||
+ // odbc date
+ SQL_ISRULE(pAtom,set_fct_spec) ||
+ SQL_ISRULE(pAtom,position_exp) ||
+ SQL_ISRULE(pAtom,char_substring_fct) ||
+ // upper, lower etc.
+ SQL_ISRULE(pAtom,fold)) )
+ {
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,nullptr);
+ return;
+ }
+
+ if (pOptEscape->count() != 0)
+ {
+ if (pOptEscape->count() != 2)
+ {
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_INVALID_LIKE_STRING,nullptr);
+ }
+ OSQLParseNode *pEscNode = pOptEscape->getChild(1);
+ if (pEscNode->getNodeType() != SQLNodeType::String)
+ {
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_INVALID_LIKE_STRING,nullptr);
+ }
+ else
+ cEscape = pEscNode->getTokenValue().toChar();
+ }
+
+ execute(pPredicateNode->getChild(0));
+ execute(pAtom);
+
+ OBoolOperator* pOperator = bNotLike
+ ? new OOp_NOTLIKE(cEscape)
+ : new OOp_LIKE(cEscape);
+ m_aCodeList.emplace_back(pOperator);
+}
+
+void OPredicateCompiler::execute_BETWEEN(OSQLParseNode const * pPredicateNode)
+{
+ DBG_ASSERT(pPredicateNode->count() == 2,"OFILECursor: Error in Parse Tree");
+
+ OSQLParseNode* pColumn = pPredicateNode->getChild(0);
+ const OSQLParseNode* pPart2 = pPredicateNode->getChild(1);
+ OSQLParseNode* p1stValue = pPart2->getChild(2);
+ OSQLParseNode* p2ndtValue = pPart2->getChild(4);
+
+ if (
+ !(p1stValue->getNodeType() == SQLNodeType::String || SQL_ISRULE(p1stValue,parameter))
+ && !(p2ndtValue->getNodeType() == SQLNodeType::String || SQL_ISRULE(p2ndtValue,parameter))
+ )
+ {
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_INVALID_BETWEEN,nullptr);
+ }
+
+ bool bNot = SQL_ISTOKEN(pPart2->getChild(0),NOT);
+
+ OOperand* pColumnOp = execute(pColumn);
+ OOperand* pOb1 = execute(p1stValue);
+ OBoolOperator* pOperator = new OOp_COMPARE(bNot ? SQLFilterOperator::LESS_EQUAL : SQLFilterOperator::GREATER);
+ m_aCodeList.emplace_back(pOperator);
+
+ execute(pColumn);
+ OOperand* pOb2 = execute(p2ndtValue);
+ pOperator = new OOp_COMPARE(bNot ? SQLFilterOperator::GREATER_EQUAL : SQLFilterOperator::LESS);
+ m_aCodeList.emplace_back(pOperator);
+
+ if ( pColumnOp && pOb1 && pOb2 )
+ {
+ switch(pColumnOp->getDBType())
+ {
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ case DataType::LONGVARCHAR:
+ pOb1->setValue(pOb1->getValue().getString());
+ pOb2->setValue(pOb2->getValue().getString());
+ break;
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ pOb1->setValue(pOb1->getValue().getDouble());
+ pOb2->setValue(pOb2->getValue().getDouble());
+ break;
+ case DataType::FLOAT:
+ pOb1->setValue(pOb1->getValue().getFloat());
+ pOb2->setValue(pOb2->getValue().getFloat());
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ pOb1->setValue(pOb1->getValue().getDouble());
+ pOb2->setValue(pOb2->getValue().getDouble());
+ break;
+ case DataType::DATE:
+ pOb1->setValue(pOb1->getValue().getDate());
+ pOb2->setValue(pOb2->getValue().getDate());
+ break;
+ case DataType::TIME:
+ pOb1->setValue(pOb1->getValue().getTime());
+ pOb2->setValue(pOb2->getValue().getTime());
+ break;
+ case DataType::TIMESTAMP:
+ pOb1->setValue(pOb1->getValue().getDateTime());
+ pOb2->setValue(pOb2->getValue().getDateTime());
+ break;
+ }
+ }
+
+
+ OBoolOperator* pBoolOp = nullptr;
+ if ( bNot )
+ pBoolOp = new OOp_OR;
+ else
+ pBoolOp = new OOp_AND;
+ m_aCodeList.emplace_back(pBoolOp);
+}
+
+void OPredicateCompiler::execute_ISNULL(OSQLParseNode const * pPredicateNode)
+{
+ DBG_ASSERT(pPredicateNode->count() == 2,"OFILECursor: Error in Parse Tree");
+ const OSQLParseNode* pPart2 = pPredicateNode->getChild(1);
+ DBG_ASSERT(SQL_ISTOKEN(pPart2->getChild(0),IS),"OFILECursor: Error in Parse Tree");
+
+ sal_Int32 ePredicateType;
+ if (SQL_ISTOKEN(pPart2->getChild(1),NOT))
+ ePredicateType = SQLFilterOperator::NOT_SQLNULL;
+ else
+ ePredicateType = SQLFilterOperator::SQLNULL;
+
+ execute(pPredicateNode->getChild(0));
+ OBoolOperator* pOperator = (ePredicateType == SQLFilterOperator::SQLNULL) ?
+ new OOp_ISNULL : new OOp_ISNOTNULL;
+ m_aCodeList.emplace_back(pOperator);
+}
+
+OOperand* OPredicateCompiler::execute_Operand(OSQLParseNode const * pPredicateNode)
+{
+ OOperand* pOperand = nullptr;
+
+ if (SQL_ISRULE(pPredicateNode,column_ref))
+ {
+ OUString aColumnName;
+ if (pPredicateNode->count() == 1)
+ {
+ aColumnName = pPredicateNode->getChild(0)->getTokenValue();
+ }
+ else if (pPredicateNode->count() == 3)
+ {
+ if(SQL_ISRULE(pPredicateNode->getChild(2),column_val))
+ aColumnName = pPredicateNode->getChild(2)->getChild(0)->getTokenValue();
+ else
+ aColumnName = pPredicateNode->getChild(2)->getTokenValue();
+ }
+
+ if(!m_orgColumns->hasByName(aColumnName))
+ {
+ const OUString sError( m_pAnalyzer->getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_INVALID_COLUMNNAME,
+ "$columnname$", aColumnName
+ ) );
+ ::dbtools::throwGenericSQLException( sError, nullptr );
+ }
+ css::uno::Reference< css::beans::XPropertySet> xCol;
+ try
+ {
+ if (m_orgColumns->getByName(aColumnName) >>= xCol)
+ {
+ pOperand = OSQLAnalyzer::createOperandAttr(Reference< XColumnLocate>(m_orgColumns,UNO_QUERY_THROW)->findColumn(aColumnName),xCol);
+ }
+ else
+ {// Column doesn't exist in the Result-set
+ const OUString sError( m_pAnalyzer->getConnection()->getResources().getResourceStringWithSubstitution(
+ STR_INVALID_COLUMNNAME,
+ "$columnname$", aColumnName
+ ) );
+ ::dbtools::throwGenericSQLException( sError, nullptr );
+ }
+ }
+ catch(Exception &)
+ {
+ TOOLS_WARN_EXCEPTION( "connectivity.drivers", "OPredicateCompiler::execute_Operand Exception");
+ }
+ }
+ else if (SQL_ISRULE(pPredicateNode,parameter))
+ {
+ pOperand = new OOperandParam(++m_nParamCounter);
+ }
+ else if (pPredicateNode->getNodeType() == SQLNodeType::String ||
+ pPredicateNode->getNodeType() == SQLNodeType::IntNum ||
+ pPredicateNode->getNodeType() == SQLNodeType::ApproxNum ||
+ pPredicateNode->getNodeType() == SQLNodeType::Name ||
+ SQL_ISTOKEN(pPredicateNode,TRUE) ||
+ SQL_ISTOKEN(pPredicateNode,FALSE) ||
+ SQL_ISRULE(pPredicateNode,parameter))
+ {
+ pOperand = new OOperandConst(*pPredicateNode, pPredicateNode->getTokenValue());
+ }
+ else if((pPredicateNode->count() == 2) &&
+ (SQL_ISPUNCTUATION(pPredicateNode->getChild(0),"+") || SQL_ISPUNCTUATION(pPredicateNode->getChild(0),"-")) &&
+ pPredicateNode->getChild(1)->getNodeType() == SQLNodeType::IntNum)
+ { // if -1 or +1 is there
+ OUString aValue = pPredicateNode->getChild(0)->getTokenValue() + pPredicateNode->getChild(1)->getTokenValue();
+ pOperand = new OOperandConst(*pPredicateNode->getChild(1), aValue);
+ }
+ else if( SQL_ISRULE(pPredicateNode,set_fct_spec) && SQL_ISPUNCTUATION(pPredicateNode->getChild(0),"{") )
+ {
+ const OSQLParseNode* pODBCNode = pPredicateNode->getChild(1);
+ const OSQLParseNode* pODBCNodeChild = pODBCNode->getChild(0);
+
+ // Odbc Date or time
+ if (pODBCNodeChild->getNodeType() == SQLNodeType::Keyword && (
+ SQL_ISTOKEN(pODBCNodeChild,D) ||
+ SQL_ISTOKEN(pODBCNodeChild,T) ||
+ SQL_ISTOKEN(pODBCNodeChild,TS) ))
+ {
+ OUString sDateTime = pODBCNode->getChild(1)->getTokenValue();
+ pOperand = new OOperandConst(*pODBCNode->getChild(1), sDateTime);
+ if(SQL_ISTOKEN(pODBCNodeChild,D))
+ {
+ pOperand->setValue(::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDate(sDateTime)));
+ }
+ else if(SQL_ISTOKEN(pODBCNodeChild,T))
+ {
+ pOperand->setValue(::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toTime(sDateTime)));
+ }
+ else if(SQL_ISTOKEN(pODBCNodeChild,TS))
+ {
+ pOperand->setValue(::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDateTime(sDateTime)));
+ }
+ }
+ else
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,nullptr);
+
+ }
+ else if( SQL_ISRULE(pPredicateNode,fold) )
+ {
+ execute_Fold(pPredicateNode);
+ }
+ else if( SQL_ISRULE(pPredicateNode,set_fct_spec)
+ || SQL_ISRULE(pPredicateNode,position_exp)
+ || SQL_ISRULE(pPredicateNode,char_substring_fct)
+ )
+ {
+ executeFunction(pPredicateNode);
+ }
+ else if( SQL_ISRULE(pPredicateNode,length_exp) )
+ {
+ executeFunction(pPredicateNode->getChild(0));
+ }
+ else
+ {
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_TOO_COMPLEX,nullptr);
+ }
+ if (pOperand)
+ m_aCodeList.emplace_back(pOperand);
+ return pOperand;
+}
+
+
+bool OPredicateInterpreter::evaluate(OCodeList& rCodeList)
+{
+ if (!(rCodeList[0]))
+ return true; // no Predicate
+
+ for (auto const& code : rCodeList)
+ {
+ OOperand* pOperand = dynamic_cast<OOperand* >(code.get());
+ if (pOperand)
+ m_aStack.push(pOperand);
+ else
+ static_cast<OOperator *>(code.get())->Exec(m_aStack);
+ }
+
+ OOperand* pOperand = m_aStack.top();
+ m_aStack.pop();
+
+ DBG_ASSERT(m_aStack.empty(), "Stack error");
+ DBG_ASSERT(pOperand, "Stack error");
+
+ const bool bResult = pOperand->isValid();
+ if (typeid(OOperandResult) == typeid(*pOperand))
+ delete pOperand;
+ return bResult;
+}
+
+void OPredicateInterpreter::evaluateSelection(OCodeList& rCodeList, ORowSetValueDecoratorRef const & _rVal)
+{
+ if (!(rCodeList[0]))
+ return ; // no Predicate
+
+ for (auto const& code : rCodeList)
+ {
+ OOperand* pOperand = dynamic_cast<OOperand* >(code.get());
+ if (pOperand)
+ m_aStack.push(pOperand);
+ else
+ static_cast<OOperator *>(code.get())->Exec(m_aStack);
+ }
+
+ OOperand* pOperand = m_aStack.top();
+ m_aStack.pop();
+
+ DBG_ASSERT(m_aStack.empty(), "Stack error");
+ DBG_ASSERT(pOperand, "Stack error");
+
+ (*_rVal) = pOperand->getValue();
+ if (typeid(OOperandResult) == typeid(*pOperand))
+ delete pOperand;
+}
+
+void OPredicateCompiler::execute_Fold(OSQLParseNode const * pPredicateNode)
+{
+ DBG_ASSERT(pPredicateNode->count() >= 4,"OFILECursor: Error in Parse Tree");
+
+ bool bUpper = SQL_ISTOKEN(pPredicateNode->getChild(0),UPPER);
+
+ execute(pPredicateNode->getChild(2));
+ OOperator* pOperator = nullptr;
+ if ( bUpper )
+ pOperator = new OOp_Upper;
+ else
+ pOperator = new OOp_Lower;
+
+ m_aCodeList.emplace_back(pOperator);
+}
+
+void OPredicateCompiler::executeFunction(OSQLParseNode const * pPredicateNode)
+{
+ OOperator* pOperator = nullptr;
+
+ OSL_ENSURE(pPredicateNode->getChild(0)->isToken(),"The first one must be the name of the function!");
+ sal_Int32 nTokenId = pPredicateNode->getChild(0)->getTokenID();
+ switch ( nTokenId )
+ {
+ case SQL_TOKEN_CHAR_LENGTH:
+ case SQL_TOKEN_LENGTH:
+ case SQL_TOKEN_OCTET_LENGTH:
+ case SQL_TOKEN_ASCII:
+ case SQL_TOKEN_LCASE:
+ case SQL_TOKEN_LTRIM:
+ case SQL_TOKEN_RTRIM:
+ case SQL_TOKEN_SPACE:
+ case SQL_TOKEN_UCASE:
+ case SQL_TOKEN_ABS:
+ case SQL_TOKEN_ACOS:
+ case SQL_TOKEN_ASIN:
+ case SQL_TOKEN_ATAN:
+ case SQL_TOKEN_CEILING:
+ case SQL_TOKEN_COS:
+ case SQL_TOKEN_DEGREES:
+ case SQL_TOKEN_EXP:
+ case SQL_TOKEN_FLOOR:
+ case SQL_TOKEN_LOG10:
+ case SQL_TOKEN_LN:
+ case SQL_TOKEN_RADIANS:
+ case SQL_TOKEN_SIGN:
+ case SQL_TOKEN_SIN:
+ case SQL_TOKEN_SQRT:
+ case SQL_TOKEN_TAN:
+ case SQL_TOKEN_DAYNAME:
+ case SQL_TOKEN_DAYOFMONTH:
+ case SQL_TOKEN_DAYOFWEEK:
+ case SQL_TOKEN_DAYOFYEAR:
+ case SQL_TOKEN_HOUR:
+ case SQL_TOKEN_MINUTE:
+ case SQL_TOKEN_MONTH:
+ case SQL_TOKEN_MONTHNAME:
+ case SQL_TOKEN_QUARTER:
+ case SQL_TOKEN_SECOND:
+ case SQL_TOKEN_YEAR:
+
+ execute(pPredicateNode->getChild(2));
+
+ switch( nTokenId )
+ {
+ case SQL_TOKEN_CHAR_LENGTH:
+ case SQL_TOKEN_LENGTH:
+ case SQL_TOKEN_OCTET_LENGTH:
+ pOperator = new OOp_CharLength;
+ break;
+ case SQL_TOKEN_ASCII:
+ pOperator = new OOp_Ascii;
+ break;
+ case SQL_TOKEN_LCASE:
+ pOperator = new OOp_Lower;
+ break;
+
+ case SQL_TOKEN_LTRIM:
+ pOperator = new OOp_LTrim;
+ break;
+ case SQL_TOKEN_RTRIM:
+ pOperator = new OOp_RTrim;
+ break;
+ case SQL_TOKEN_SPACE:
+ pOperator = new OOp_Space;
+ break;
+ case SQL_TOKEN_UCASE:
+ pOperator = new OOp_Upper;
+ break;
+ case SQL_TOKEN_ABS:
+ pOperator = new OOp_Abs;
+ break;
+ case SQL_TOKEN_ACOS:
+ pOperator = new OOp_ACos;
+ break;
+ case SQL_TOKEN_ASIN:
+ pOperator = new OOp_ASin;
+ break;
+ case SQL_TOKEN_ATAN:
+ pOperator = new OOp_ATan;
+ break;
+ case SQL_TOKEN_CEILING:
+ pOperator = new OOp_Ceiling;
+ break;
+ case SQL_TOKEN_COS:
+ pOperator = new OOp_Cos;
+ break;
+ case SQL_TOKEN_DEGREES:
+ pOperator = new OOp_Degrees;
+ break;
+ case SQL_TOKEN_EXP:
+ pOperator = new OOp_Exp;
+ break;
+ case SQL_TOKEN_FLOOR:
+ pOperator = new OOp_Floor;
+ break;
+ case SQL_TOKEN_LOG10:
+ pOperator = new OOp_Log10;
+ break;
+ case SQL_TOKEN_LN:
+ pOperator = new OOp_Ln;
+ break;
+ case SQL_TOKEN_RADIANS:
+ pOperator = new OOp_Radians;
+ break;
+ case SQL_TOKEN_SIGN:
+ pOperator = new OOp_Sign;
+ break;
+ case SQL_TOKEN_SIN:
+ pOperator = new OOp_Sin;
+ break;
+ case SQL_TOKEN_SQRT:
+ pOperator = new OOp_Sqrt;
+ break;
+ case SQL_TOKEN_TAN:
+ pOperator = new OOp_Tan;
+ break;
+ case SQL_TOKEN_DAYOFWEEK:
+ pOperator = new OOp_DayOfWeek;
+ break;
+ case SQL_TOKEN_DAYOFMONTH:
+ pOperator = new OOp_DayOfMonth;
+ break;
+ case SQL_TOKEN_DAYOFYEAR:
+ pOperator = new OOp_DayOfYear;
+ break;
+ case SQL_TOKEN_MONTH:
+ pOperator = new OOp_Month;
+ break;
+ case SQL_TOKEN_DAYNAME:
+ pOperator = new OOp_DayName;
+ break;
+ case SQL_TOKEN_MONTHNAME:
+ pOperator = new OOp_MonthName;
+ break;
+ case SQL_TOKEN_QUARTER:
+ pOperator = new OOp_Quarter;
+ break;
+ case SQL_TOKEN_YEAR:
+ pOperator = new OOp_Year;
+ break;
+ case SQL_TOKEN_HOUR:
+ pOperator = new OOp_Hour;
+ break;
+ case SQL_TOKEN_MINUTE:
+ pOperator = new OOp_Minute;
+ break;
+ case SQL_TOKEN_SECOND:
+ pOperator = new OOp_Second;
+ break;
+ default:
+ OSL_FAIL("Error in switch!");
+ }
+ break;
+ case SQL_TOKEN_CHAR:
+ case SQL_TOKEN_CONCAT:
+ case SQL_TOKEN_INSERT:
+ case SQL_TOKEN_LEFT:
+ case SQL_TOKEN_LOCATE:
+ case SQL_TOKEN_LOCATE_2:
+ case SQL_TOKEN_REPEAT:
+ case SQL_TOKEN_REPLACE:
+ case SQL_TOKEN_RIGHT:
+ case SQL_TOKEN_MOD:
+ case SQL_TOKEN_ROUND:
+ case SQL_TOKEN_LOGF:
+ case SQL_TOKEN_LOG:
+ case SQL_TOKEN_POWER:
+ case SQL_TOKEN_ATAN2:
+ case SQL_TOKEN_PI:
+ case SQL_TOKEN_CURDATE:
+ case SQL_TOKEN_CURTIME:
+ case SQL_TOKEN_NOW:
+ case SQL_TOKEN_WEEK:
+ {
+ m_aCodeList.emplace_back(new OStopOperand);
+ OSQLParseNode* pList = pPredicateNode->getChild(2);
+ for (size_t i=0; i < pList->count(); ++i)
+ execute(pList->getChild(i));
+
+ switch( nTokenId )
+ {
+ case SQL_TOKEN_CHAR:
+ pOperator = new OOp_Char;
+ break;
+ case SQL_TOKEN_CONCAT:
+ pOperator = new OOp_Concat;
+ break;
+ case SQL_TOKEN_INSERT:
+ pOperator = new OOp_Insert;
+ break;
+ case SQL_TOKEN_LEFT:
+ pOperator = new OOp_Left;
+ break;
+ case SQL_TOKEN_LOCATE:
+ case SQL_TOKEN_LOCATE_2:
+ pOperator = new OOp_Locate;
+ break;
+ case SQL_TOKEN_REPEAT:
+ pOperator = new OOp_Repeat;
+ break;
+ case SQL_TOKEN_REPLACE:
+ pOperator = new OOp_Replace;
+ break;
+ case SQL_TOKEN_RIGHT:
+ pOperator = new OOp_Right;
+ break;
+ case SQL_TOKEN_MOD:
+ pOperator = new OOp_Mod;
+ break;
+ case SQL_TOKEN_ROUND:
+ pOperator = new OOp_Round;
+ break;
+ case SQL_TOKEN_LOGF:
+ case SQL_TOKEN_LOG:
+ pOperator = new OOp_Log;
+ break;
+ case SQL_TOKEN_POWER:
+ pOperator = new OOp_Pow;
+ break;
+ case SQL_TOKEN_ATAN2:
+ pOperator = new OOp_ATan2;
+ break;
+ case SQL_TOKEN_PI:
+ pOperator = new OOp_Pi;
+ break;
+ case SQL_TOKEN_CURDATE:
+ pOperator = new OOp_CurDate;
+ break;
+ case SQL_TOKEN_CURTIME:
+ pOperator = new OOp_CurTime;
+ break;
+ case SQL_TOKEN_NOW:
+ pOperator = new OOp_Now;
+ break;
+ case SQL_TOKEN_WEEK:
+ pOperator = new OOp_Week;
+ break;
+ default:
+ OSL_FAIL("Error in switch!");
+ }
+ }
+ break;
+
+ case SQL_TOKEN_SUBSTRING:
+ m_aCodeList.emplace_back(new OStopOperand);
+ if ( pPredicateNode->count() == 4 ) //char_substring_fct
+ {
+ OSQLParseNode* pList = pPredicateNode->getChild(2);
+ for (size_t i=0; i < pList->count(); ++i)
+ execute(pList->getChild(i));
+ }
+ else
+ {
+ execute(pPredicateNode->getChild(2));
+ execute(pPredicateNode->getChild(4));
+ execute(pPredicateNode->getChild(5)->getChild(1));
+ }
+ pOperator = new OOp_SubString;
+ break;
+
+ case SQL_TOKEN_POSITION:
+ m_aCodeList.emplace_back(new OStopOperand);
+ if ( pPredicateNode->count() == 4 ) //position_exp
+ {
+ OSQLParseNode* pList = pPredicateNode->getChild(2);
+ for (size_t i=0; i < pList->count(); ++i)
+ execute(pList->getChild(i));
+ }
+ else
+ {
+ execute(pPredicateNode->getChild(2));
+ execute(pPredicateNode->getChild(4));
+ }
+ pOperator = new OOp_Locate;
+ break;
+ default:
+ m_pAnalyzer->getConnection()->throwGenericSQLException(STR_QUERY_FUNCTION_NOT_SUPPORTED,nullptr);
+ }
+
+ m_aCodeList.emplace_back(pOperator);
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/connectivity/source/drivers/file/quotedstring.cxx b/connectivity/source/drivers/file/quotedstring.cxx
new file mode 100644
index 000000000..f654c709e
--- /dev/null
+++ b/connectivity/source/drivers/file/quotedstring.cxx
@@ -0,0 +1,146 @@
+/* -*- 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/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed
+ * with this work for additional information regarding copyright
+ * ownership. The ASF licenses this file to you under the Apache
+ * License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of
+ * the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <file/quotedstring.hxx>
+#include <rtl/ustrbuf.hxx>
+
+namespace connectivity
+{
+
+ sal_Int32 QuotedTokenizedString::GetTokenCount( sal_Unicode cTok, sal_Unicode cStrDel ) const
+ {
+ const sal_Int32 nLen = m_sString.getLength();
+ if ( !nLen )
+ return 0;
+
+ sal_Int32 nTokCount = 1;
+ bool bStart = true; // Are we on the first character in the Token?
+ bool bInString = false; // Are we WITHIN a (cStrDel delimited) String?
+
+ // Search for String-end after the first not matching character
+ for( sal_Int32 i = 0; i < nLen; ++i )
+ {
+ const sal_Unicode cChar = m_sString[i];
+ if (bStart)
+ {
+ bStart = false;
+ // First character a String-Delimiter?
+ if ( cChar == cStrDel )
+ {
+ bInString = true; // then we are now WITHIN the string!
+ continue; // skip this character!
+ }
+ }
+
+ if (bInString)
+ {
+ // when now the String-Delimiter-character occurs...
+ if ( cChar == cStrDel )
+ {
+ if ((i+1 < nLen) && (m_sString[i+1] == cStrDel))
+ {
+ // double String-Delimiter-character:
+ ++i; // no string-end, skip next character.
+ }
+ else
+ {
+ // String-End
+ bInString = false;
+ }
+ }
+ } // if (bInString)
+ else
+ {
+ // does the Token-character match, then raise TokCount
+ if ( cChar == cTok )
+ {
+ ++nTokCount;
+ bStart = true;
+ }
+ }
+ }
+
+ return nTokCount;
+ }
+
+
+ OUString QuotedTokenizedString::GetTokenSpecial(sal_Int32& nStartPos, sal_Unicode cTok, sal_Unicode cStrDel) const
+ {
+ const sal_Int32 nLen = m_sString.getLength();
+ if ( nLen )
+ {
+ bool bInString = (nStartPos < nLen) && (m_sString[nStartPos] == cStrDel); // are we WITHIN a (cStrDel delimited) String?
+
+ // First character a String-Delimiter?
+ if (bInString )
+ ++nStartPos; // skip this character!
+ if ( nStartPos >= nLen )
+ return OUString();
+
+ OUStringBuffer sBuff( nLen - nStartPos + 1 );
+
+ // Search until end of string for the first not matching character
+ for( sal_Int32 i = nStartPos; i < nLen; ++i )
+ {
+ const sal_Unicode cChar = m_sString[i];
+ if (bInString)
+ {
+ // when now the String-Delimiter-character occurs ...
+ if ( cChar == cStrDel )
+ {
+ if ((i+1 < nLen) && (m_sString[i+1] == cStrDel))
+ {
+ // double String Delimiter-character
+ // no end of string, skip next character.
+ ++i;
+ sBuff.append(m_sString[i]); // character belongs to Result-String
+ }
+ else
+ {
+ //end of String
+ bInString = false;
+ }
+ }
+ else
+ {
+ sBuff.append(cChar);
+ }
+ }
+ else
+ {
+ // does the Token-sign match, then raise nTok
+ if ( cChar == cTok )
+ {
+ // premature break of loop possible, because we found what we were looking for
+ nStartPos = i+1;
+ break;
+ }
+ else
+ {
+ sBuff.append(cChar);
+ }
+ }
+ } // for( sal_Int32 i = nStartPos; i < nLen; ++i )
+ return sBuff.makeStringAndClear();
+ }
+ return OUString();
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */