diff options
Diffstat (limited to '')
-rw-r--r-- | connectivity/source/drivers/flat/ECatalog.cxx | 58 | ||||
-rw-r--r-- | connectivity/source/drivers/flat/EColumns.cxx | 44 | ||||
-rw-r--r-- | connectivity/source/drivers/flat/EConnection.cxx | 176 | ||||
-rw-r--r-- | connectivity/source/drivers/flat/EDatabaseMetaData.cxx | 244 | ||||
-rw-r--r-- | connectivity/source/drivers/flat/EDriver.cxx | 135 | ||||
-rw-r--r-- | connectivity/source/drivers/flat/EPreparedStatement.cxx | 35 | ||||
-rw-r--r-- | connectivity/source/drivers/flat/EResultSet.cxx | 169 | ||||
-rw-r--r-- | connectivity/source/drivers/flat/EStatement.cxx | 34 | ||||
-rw-r--r-- | connectivity/source/drivers/flat/ETable.cxx | 961 | ||||
-rw-r--r-- | connectivity/source/drivers/flat/ETables.cxx | 44 | ||||
-rw-r--r-- | connectivity/source/drivers/flat/flat.component | 27 |
11 files changed, 1927 insertions, 0 deletions
diff --git a/connectivity/source/drivers/flat/ECatalog.cxx b/connectivity/source/drivers/flat/ECatalog.cxx new file mode 100644 index 000000000..aed042fdd --- /dev/null +++ b/connectivity/source/drivers/flat/ECatalog.cxx @@ -0,0 +1,58 @@ +/* -*- 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 <flat/ECatalog.hxx> + +#include <flat/EConnection.hxx> +#include <flat/ETables.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::flat; + +OFlatCatalog::OFlatCatalog(OFlatConnection* _pCon) + : file::OFileCatalog(_pCon) +{ +} + +void OFlatCatalog::refreshTables() +{ + ::std::vector<OUString> aVector; + Sequence<OUString> aTypes; + Reference<XResultSet> xResult = m_xMetaData->getTables(Any(), "%", "%", aTypes); + + if (xResult.is()) + { + Reference<XRow> xRow(xResult, UNO_QUERY); + while (xResult->next()) + aVector.push_back(xRow->getString(3)); + } + if (m_pTables) + m_pTables->reFill(aVector); + else + m_pTables.reset(new OFlatTables(m_xMetaData, *this, m_aMutex, aVector)); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/EColumns.cxx b/connectivity/source/drivers/flat/EColumns.cxx new file mode 100644 index 000000000..a9e210321 --- /dev/null +++ b/connectivity/source/drivers/flat/EColumns.cxx @@ -0,0 +1,44 @@ +/* -*- 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 <flat/EColumns.hxx> +#include <flat/ETable.hxx> + +using namespace connectivity::flat; +using namespace connectivity; +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 OFlatColumns::createObject(const OUString& _rName) +{ + OFlatTable* pTable = static_cast<OFlatTable*>(m_pTable); + const ::rtl::Reference<OSQLColumns>& aCols = pTable->getTableColumns(); + OSQLColumns::const_iterator aIter = find(aCols->begin(),aCols->end(),_rName,::comphelper::UStringMixEqual(isCaseSensitive())); + sdbcx::ObjectType xRet; + if(aIter != aCols->end()) + xRet = sdbcx::ObjectType(*aIter,UNO_QUERY); + return xRet; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/EConnection.cxx b/connectivity/source/drivers/flat/EConnection.cxx new file mode 100644 index 000000000..288a53fa6 --- /dev/null +++ b/connectivity/source/drivers/flat/EConnection.cxx @@ -0,0 +1,176 @@ +/* -*- 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 <flat/EConnection.hxx> +#include <flat/EDatabaseMetaData.hxx> +#include <flat/ECatalog.hxx> +#include <flat/EDriver.hxx> +#include <flat/EPreparedStatement.hxx> +#include <flat/EStatement.hxx> +#include <connectivity/dbexception.hxx> +#include <sal/log.hxx> + +using namespace connectivity::flat; +using namespace connectivity::file; + +typedef connectivity::file::OConnection OConnection_B; + + +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::lang; + + +OFlatConnection::OFlatConnection(ODriver* _pDriver) : OConnection(_pDriver) + ,m_nMaxRowsToScan(50) + ,m_bHeaderLine(true) + ,m_cFieldDelimiter(';') + ,m_cStringDelimiter('"') + ,m_cDecimalDelimiter(',') + ,m_cThousandDelimiter('.') +{ +} + +OFlatConnection::~OFlatConnection() +{ +} + +// XServiceInfo + +IMPLEMENT_SERVICE_INFO(OFlatConnection, "com.sun.star.sdbc.drivers.flat.Connection", "com.sun.star.sdbc.Connection") + + +void OFlatConnection::construct(const OUString& url,const Sequence< PropertyValue >& info) +{ + osl_atomic_increment( &m_refCount ); + + const PropertyValue *pBegin = info.getConstArray(); + const PropertyValue *pEnd = pBegin + info.getLength(); + for(;pBegin != pEnd;++pBegin) + { + if(pBegin->Name == "HeaderLine") + { + if( ! (pBegin->Value >>= m_bHeaderLine) ) + SAL_WARN("connectivity.flat", "construct: unable to get property HeaderLine"); + } + else if(pBegin->Name == "FieldDelimiter") + { + OUString aVal; + if( ! (pBegin->Value >>= aVal) ) + SAL_WARN("connectivity.flat", "construct: unable to get property FieldDelimiter"); + + m_cFieldDelimiter = aVal.toChar(); + } + else if(pBegin->Name == "StringDelimiter") + { + OUString aVal; + if( ! (pBegin->Value >>= aVal) ) + SAL_WARN("connectivity.flat", "construct: unable to get property StringDelimiter"); + + m_cStringDelimiter = aVal.toChar(); + } + else if(pBegin->Name == "DecimalDelimiter") + { + OUString aVal; + if( ! (pBegin->Value >>= aVal) ) + SAL_WARN("connectivity.flat", "construct: unable to get property DecimalDelimiter"); + + m_cDecimalDelimiter = aVal.toChar(); + } + else if(pBegin->Name == "ThousandDelimiter") + { + OUString aVal; + if( ! (pBegin->Value >>= aVal) ) + SAL_WARN("connectivity.flat", "construct: unable to get property ThousandDelimiter"); + + m_cThousandDelimiter = aVal.toChar(); + } + else if ( pBegin->Name == "MaxRowScan" ) + { + pBegin->Value >>= m_nMaxRowsToScan; + } + } + + osl_atomic_decrement( &m_refCount ); + OConnection::construct(url,info); + m_bShowDeleted = true; // we do not supported rows for this type +} + +Reference< XDatabaseMetaData > SAL_CALL OFlatConnection::getMetaData( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_B::rBHelper.bDisposed); + + + Reference< XDatabaseMetaData > xMetaData = m_xMetaData; + if(!xMetaData.is()) + { + xMetaData = new OFlatDatabaseMetaData(this); + m_xMetaData = xMetaData; + } + + return xMetaData; +} + +css::uno::Reference< XTablesSupplier > OFlatConnection::createCatalog() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + Reference< XTablesSupplier > xTab = m_xCatalog; + if(!xTab.is()) + { + xTab = new OFlatCatalog(this); + m_xCatalog = xTab; + } + return xTab; +} + +Reference< XStatement > SAL_CALL OFlatConnection::createStatement( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_B::rBHelper.bDisposed); + + rtl::Reference<OFlatStatement> pStmt = new OFlatStatement(this); + m_aStatements.push_back(WeakReferenceHelper(*pStmt)); + return pStmt; +} + +Reference< XPreparedStatement > SAL_CALL OFlatConnection::prepareStatement( const OUString& sql ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_B::rBHelper.bDisposed); + + rtl::Reference<OFlatPreparedStatement> pStmt = new OFlatPreparedStatement(this); + pStmt->construct(sql); + m_aStatements.push_back(WeakReferenceHelper(*pStmt)); + return pStmt; +} + +Reference< XPreparedStatement > SAL_CALL OFlatConnection::prepareCall( const OUString& /*sql*/ ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OConnection_B::rBHelper.bDisposed); + + ::dbtools::throwFeatureNotImplementedSQLException( "XConnection::prepareCall", *this ); + return nullptr; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/EDatabaseMetaData.cxx b/connectivity/source/drivers/flat/EDatabaseMetaData.cxx new file mode 100644 index 000000000..b711645b5 --- /dev/null +++ b/connectivity/source/drivers/flat/EDatabaseMetaData.cxx @@ -0,0 +1,244 @@ +/* -*- 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 <flat/EDatabaseMetaData.hxx> +#include <com/sun/star/sdbc/ColumnSearch.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/SQLException.hpp> +#include <com/sun/star/sdbcx/XColumnsSupplier.hpp> +#include <FDatabaseMetaDataResultSet.hxx> +#include <comphelper/types.hxx> + +using namespace ::comphelper; + +using namespace connectivity; +using namespace connectivity::flat; +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; + + +OFlatDatabaseMetaData::OFlatDatabaseMetaData(::connectivity::file::OConnection* _pCon) :ODatabaseMetaData(_pCon) +{ +} + +OFlatDatabaseMetaData::~OFlatDatabaseMetaData() +{ +} + +Reference< XResultSet > OFlatDatabaseMetaData::impl_getTypeInfo_throw( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eTypeInfo); + + static ODatabaseMetaDataResultSet::ORows aRows = []() + { + ODatabaseMetaDataResultSet::ORows tmp; + ODatabaseMetaDataResultSet::ORow aRow + { + ODatabaseMetaDataResultSet::getEmptyValue() , + new ORowSetValueDecorator(OUString("CHAR")) , + new ORowSetValueDecorator(DataType::CHAR) , + new ORowSetValueDecorator(sal_Int32(254)) , + ODatabaseMetaDataResultSet::getQuoteValue() , + ODatabaseMetaDataResultSet::getQuoteValue() , + ODatabaseMetaDataResultSet::getEmptyValue() , + new ORowSetValueDecorator(sal_Int32(ColumnValue::NULLABLE)) , + ODatabaseMetaDataResultSet::get1Value() , + new ORowSetValueDecorator(sal_Int32(ColumnSearch::CHAR)) , + ODatabaseMetaDataResultSet::get1Value() , + ODatabaseMetaDataResultSet::get0Value() , + ODatabaseMetaDataResultSet::get0Value() , + ODatabaseMetaDataResultSet::getEmptyValue() , + ODatabaseMetaDataResultSet::get0Value() , + ODatabaseMetaDataResultSet::get0Value() , + ODatabaseMetaDataResultSet::getEmptyValue() , + ODatabaseMetaDataResultSet::getEmptyValue() , + new ORowSetValueDecorator(sal_Int32(10)) + }; + + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("VARCHAR")); + aRow[2] = new ORowSetValueDecorator(DataType::VARCHAR); + aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue(); + aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue(); + tmp.push_back(aRow); + + + aRow[1] = new ORowSetValueDecorator(OUString("LONGVARCHAR")); + aRow[2] = new ORowSetValueDecorator(DataType::LONGVARCHAR); + aRow[3] = new ORowSetValueDecorator(sal_Int32(65535)); + aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue(); + aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue(); + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("DATE")); + aRow[2] = new ORowSetValueDecorator(DataType::DATE); + aRow[3] = new ORowSetValueDecorator(sal_Int32(10)); + aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue(); + aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue(); + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("TIME")); + aRow[2] = new ORowSetValueDecorator(DataType::TIME); + aRow[3] = new ORowSetValueDecorator(sal_Int32(8)); + aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue(); + aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue(); + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("TIMESTAMP")); + aRow[2] = new ORowSetValueDecorator(DataType::TIMESTAMP); + aRow[3] = new ORowSetValueDecorator(sal_Int32(19)); + aRow[4] = ODatabaseMetaDataResultSet::getQuoteValue(); + aRow[5] = ODatabaseMetaDataResultSet::getQuoteValue(); + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("BOOL")); + aRow[2] = new ORowSetValueDecorator(DataType::BIT); + aRow[3] = ODatabaseMetaDataResultSet::get1Value(); + aRow[9] = ODatabaseMetaDataResultSet::getBasicValue(); + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("DECIMAL")); + aRow[2] = new ORowSetValueDecorator(DataType::DECIMAL); + aRow[3] = new ORowSetValueDecorator(sal_Int32(20)); + aRow[15] = new ORowSetValueDecorator(sal_Int32(15)); + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("DOUBLE")); + aRow[2] = new ORowSetValueDecorator(DataType::DOUBLE); + aRow[3] = new ORowSetValueDecorator(sal_Int32(20)); + aRow[15] = ODatabaseMetaDataResultSet::get0Value(); + tmp.push_back(aRow); + + aRow[1] = new ORowSetValueDecorator(OUString("NUMERIC")); + aRow[2] = new ORowSetValueDecorator(DataType::NUMERIC); + aRow[3] = new ORowSetValueDecorator(sal_Int32(20)); + aRow[15] = new ORowSetValueDecorator(sal_Int32(20)); + tmp.push_back(aRow); + + return tmp; + }(); + + pResult->setRows(std::move(aRows)); + return pResult; +} + +Reference< XResultSet > SAL_CALL OFlatDatabaseMetaData::getColumns( + const Any& /*catalog*/, const OUString& /*schemaPattern*/, const OUString& tableNamePattern, + const OUString& columnNamePattern ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + Reference< XTablesSupplier > xTables = m_pConnection->createCatalog(); + if(!xTables.is()) + throw SQLException(); + + Reference< XNameAccess> xNames = xTables->getTables(); + if(!xNames.is()) + throw SQLException(); + + ODatabaseMetaDataResultSet::ORows aRows; + ODatabaseMetaDataResultSet::ORow aRow(19); + aRow[10] = new ORowSetValueDecorator(sal_Int32(10)); + Sequence< OUString> aTabNames(xNames->getElementNames()); + const OUString* pTabBegin = aTabNames.getConstArray(); + const OUString* pTabEnd = pTabBegin + aTabNames.getLength(); + for(;pTabBegin != pTabEnd;++pTabBegin) + { + if(match(tableNamePattern,*pTabBegin,'\0')) + { + Reference< XColumnsSupplier> xTable( + xNames->getByName(*pTabBegin), css::uno::UNO_QUERY); + aRow[3] = new ORowSetValueDecorator(*pTabBegin); + + Reference< XNameAccess> xColumns = xTable->getColumns(); + if(!xColumns.is()) + throw SQLException(); + + Sequence< OUString> aColNames(xColumns->getElementNames()); + + const OUString* pBegin = aColNames.getConstArray(); + const OUString* pEnd = pBegin + aColNames.getLength(); + Reference< XPropertySet> xColumn; + for(sal_Int32 i=1;pBegin != pEnd;++pBegin,++i) + { + if(match(columnNamePattern,*pBegin,'\0')) + { + aRow[4] = new ORowSetValueDecorator(*pBegin); + + xColumn.set( + xColumns->getByName(*pBegin), css::uno::UNO_QUERY); + OSL_ENSURE(xColumn.is(),"Columns contains a column who isn't a fastpropertyset!"); + aRow[5] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE)))); + aRow[6] = new ORowSetValueDecorator(getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPENAME)))); + aRow[7] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_PRECISION)))); + aRow[9] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE)))); + aRow[11] = new ORowSetValueDecorator(getINT32(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISNULLABLE)))); + aRow[13] = new ORowSetValueDecorator(getString(xColumn->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DEFAULTVALUE)))); + + switch(aRow[5]->getValue().getInt32()) + { + case DataType::CHAR: + case DataType::VARCHAR: + aRow[16] = new ORowSetValueDecorator(sal_Int32(254)); + break; + case DataType::LONGVARCHAR: + aRow[16] = new ORowSetValueDecorator(sal_Int32(65535)); + break; + default: + aRow[16] = new ORowSetValueDecorator(sal_Int32(0)); + } + aRow[17] = new ORowSetValueDecorator(i); + switch(aRow[11]->getValue().getInt32()) + { + case ColumnValue::NO_NULLS: + aRow[18] = new ORowSetValueDecorator(OUString("NO")); + break; + case ColumnValue::NULLABLE: + aRow[18] = new ORowSetValueDecorator(OUString("YES")); + break; + default: + aRow[18] = new ORowSetValueDecorator(OUString()); + } + aRows.push_back(aRow); + } + } + } + } + + rtl::Reference<::connectivity::ODatabaseMetaDataResultSet> pResult = new ::connectivity::ODatabaseMetaDataResultSet(::connectivity::ODatabaseMetaDataResultSet::eColumns); + pResult->setRows(std::move(aRows)); + + return pResult; +} + +OUString SAL_CALL OFlatDatabaseMetaData::getURL( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + return "sdbc:flat:" + m_pConnection->getURL(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/EDriver.cxx b/connectivity/source/drivers/flat/EDriver.cxx new file mode 100644 index 000000000..294928955 --- /dev/null +++ b/connectivity/source/drivers/flat/EDriver.cxx @@ -0,0 +1,135 @@ +/* -*- 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 <flat/EDriver.hxx> +#include <flat/EConnection.hxx> +#include <com/sun/star/lang/DisposedException.hpp> +#include <connectivity/dbexception.hxx> +#include <comphelper/sequence.hxx> +#include <strings.hrc> +#include <resource/sharedresources.hxx> + + +using namespace connectivity::flat; +using namespace connectivity::file; +using namespace css::uno; +using namespace css::beans; +using namespace css::sdbcx; +using namespace css::sdbc; +using namespace css::lang; + + +// XServiceInfo + +OUString SAL_CALL ODriver::getImplementationName( ) +{ + return "com.sun.star.comp.sdbc.flat.ODriver"; +} + + +extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface* +connectivity_flat_ODriver( + css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const&) +{ + rtl::Reference<ODriver> ret; + try { + ret = new ODriver(context); + } catch (...) { + } + if (ret) + ret->acquire(); + return static_cast<cppu::OWeakObject*>(ret.get()); +} + +Reference< XConnection > SAL_CALL ODriver::connect( const OUString& url, const Sequence< PropertyValue >& info ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + if (ODriver_BASE::rBHelper.bDisposed) + throw DisposedException(); + + if ( ! acceptsURL(url) ) + return nullptr; + + rtl::Reference<OFlatConnection> pCon = new OFlatConnection(this); + pCon->construct(url,info); + m_xConnections.push_back(WeakReferenceHelper(*pCon)); + + return pCon; +} + +sal_Bool SAL_CALL ODriver::acceptsURL( const OUString& url ) +{ + return url.startsWith("sdbc:flat:"); +} + +Sequence< DriverPropertyInfo > SAL_CALL ODriver::getPropertyInfo( const OUString& url, const Sequence< PropertyValue >& info ) +{ + if ( acceptsURL(url) ) + { + Sequence< OUString > aBoolean { "0", "1" }; + + std::vector< DriverPropertyInfo > aDriverInfo + { + { + "FieldDelimiter" + ,"Field separator." + ,false + ,{} + ,{} + }, + { + "HeaderLine" + ,"Text contains headers." + ,false + ,"0" + ,aBoolean + }, + { + "StringDelimiter" + ,"Text separator." + ,false + ,"0" + ,aBoolean + }, + { + "DecimalDelimiter" + ,"Decimal separator." + ,false + ,"0" + ,aBoolean + }, + { + "ThousandDelimiter" + ,"Thousands separator." + ,false + ,"0" + ,aBoolean + } + }; + return ::comphelper::concatSequences(OFileDriver::getPropertyInfo(url,info ), + Sequence< DriverPropertyInfo >(aDriverInfo.data(),aDriverInfo.size())); + } + ::connectivity::SharedResources aResources; + const OUString sMessage = aResources.getResourceString(STR_URI_SYNTAX_ERROR); + ::dbtools::throwGenericSQLException(sMessage ,*this); + return Sequence< DriverPropertyInfo >(); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/EPreparedStatement.cxx b/connectivity/source/drivers/flat/EPreparedStatement.cxx new file mode 100644 index 000000000..f4095ac2c --- /dev/null +++ b/connectivity/source/drivers/flat/EPreparedStatement.cxx @@ -0,0 +1,35 @@ +/* -*- 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 <flat/EPreparedStatement.hxx> +#include <flat/EResultSet.hxx> + +using namespace connectivity::flat; +using namespace connectivity::file; +using namespace ::com::sun::star::uno; + +rtl::Reference<OResultSet> OFlatPreparedStatement::createResultSet() +{ + return new OFlatResultSet(this, m_aSQLIterator); +} + +IMPLEMENT_SERVICE_INFO(OFlatPreparedStatement, "com.sun.star.sdbc.driver.flat.PreparedStatement", + "com.sun.star.sdbc.PreparedStatement"); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/EResultSet.cxx b/connectivity/source/drivers/flat/EResultSet.cxx new file mode 100644 index 000000000..9d1975c77 --- /dev/null +++ b/connectivity/source/drivers/flat/EResultSet.cxx @@ -0,0 +1,169 @@ +/* -*- 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 <com/sun/star/sdbcx/CompareBookmark.hpp> +#include <com/sun/star/sdbcx/XDeleteRows.hpp> +#include <flat/EResultSet.hxx> +#include <com/sun/star/beans/PropertyAttribute.hpp> +#include <comphelper/sequence.hxx> +#include <comphelper/types.hxx> +#include <cppuhelper/supportsservice.hxx> + +using namespace ::comphelper; + +using namespace connectivity::flat; +using namespace connectivity::file; +using namespace ::cppu; +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; + + +OFlatResultSet::OFlatResultSet( OStatement_Base* pStmt,connectivity::OSQLParseTreeIterator& _aSQLIterator) + : file::OResultSet(pStmt,_aSQLIterator) + ,m_bBookmarkable(true) +{ + registerProperty(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISBOOKMARKABLE), PROPERTY_ID_ISBOOKMARKABLE, PropertyAttribute::READONLY,&m_bBookmarkable, cppu::UnoType<bool>::get()); +} + +OUString SAL_CALL OFlatResultSet::getImplementationName( ) +{ + return "com.sun.star.sdbcx.flat.ResultSet"; +} + +Sequence< OUString > SAL_CALL OFlatResultSet::getSupportedServiceNames( ) +{ + return { "com.sun.star.sdbc.ResultSet", "com.sun.star.sdbcx.ResultSet" }; +} + +sal_Bool SAL_CALL OFlatResultSet::supportsService( const OUString& _rServiceName ) +{ + return cppu::supportsService(this, _rServiceName); +} + +Any SAL_CALL OFlatResultSet::queryInterface( const Type & rType ) +{ + if(rType == cppu::UnoType<XDeleteRows>::get()|| rType == cppu::UnoType<XResultSetUpdate>::get() + || rType == cppu::UnoType<XRowUpdate>::get()) + return Any(); + + const Any aRet = OResultSet::queryInterface(rType); + return aRet.hasValue() ? aRet : OFlatResultSet_BASE::queryInterface(rType); +} + +Sequence< Type > SAL_CALL OFlatResultSet::getTypes( ) +{ + Sequence< Type > aTypes = OResultSet::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<XDeleteRows>::get()|| + *pBegin == cppu::UnoType<XResultSetUpdate>::get()|| + *pBegin == cppu::UnoType<XRowUpdate>::get())) + { + aOwnTypes.push_back(*pBegin); + } + } + Sequence< Type > aRet(aOwnTypes.data(), aOwnTypes.size()); + return ::comphelper::concatSequences(aRet,OFlatResultSet_BASE::getTypes()); +} + + +// XRowLocate +Any SAL_CALL OFlatResultSet::getBookmark( ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + return Any((*m_aRow)[0]->getValue().getInt32()); +} + +sal_Bool SAL_CALL OFlatResultSet::moveToBookmark( const Any& bookmark ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + + m_bRowDeleted = m_bRowInserted = m_bRowUpdated = false; + + return Move(IResultSetHelper::BOOKMARK,comphelper::getINT32(bookmark),true); +} + +sal_Bool SAL_CALL OFlatResultSet::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows ) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OResultSet_BASE::rBHelper.bDisposed); + + m_bRowDeleted = m_bRowInserted = m_bRowUpdated = false; + + Move(IResultSetHelper::BOOKMARK,comphelper::getINT32(bookmark),false); + + return relative(rows); +} + + +sal_Int32 SAL_CALL OFlatResultSet::compareBookmarks( const Any& lhs, const Any& rhs ) +{ + return (lhs == rhs) ? CompareBookmark::EQUAL : CompareBookmark::NOT_EQUAL; +} + +sal_Bool SAL_CALL OFlatResultSet::hasOrderedBookmarks( ) +{ + return true; +} + +sal_Int32 SAL_CALL OFlatResultSet::hashBookmark( const Any& bookmark ) +{ + return comphelper::getINT32(bookmark); +} + +IPropertyArrayHelper* OFlatResultSet::createArrayHelper( ) const +{ + Sequence< Property > aProps; + describeProperties(aProps); + return new ::cppu::OPropertyArrayHelper(aProps); +} + +IPropertyArrayHelper & OFlatResultSet::getInfoHelper() +{ + return *OFlatResultSet_BASE3::getArrayHelper(); +} + +void SAL_CALL OFlatResultSet::acquire() noexcept +{ + OFlatResultSet_BASE2::acquire(); +} + +void SAL_CALL OFlatResultSet::release() noexcept +{ + OFlatResultSet_BASE2::release(); +} + +css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OFlatResultSet::getPropertySetInfo( ) +{ + return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper()); +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/EStatement.cxx b/connectivity/source/drivers/flat/EStatement.cxx new file mode 100644 index 000000000..dc801ac48 --- /dev/null +++ b/connectivity/source/drivers/flat/EStatement.cxx @@ -0,0 +1,34 @@ +/* -*- 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 <flat/EStatement.hxx> +#include <flat/EResultSet.hxx> + +using namespace connectivity::flat; +using namespace connectivity::file; +using namespace css::uno; + +rtl::Reference<OResultSet> OFlatStatement::createResultSet() +{ + return new OFlatResultSet(this,m_aSQLIterator); +} + +IMPLEMENT_SERVICE_INFO(OFlatStatement,"com.sun.star.sdbc.driver.flat.Statement","com.sun.star.sdbc.Statement"); + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/ETable.cxx b/connectivity/source/drivers/flat/ETable.cxx new file mode 100644 index 000000000..bd6be38d7 --- /dev/null +++ b/connectivity/source/drivers/flat/ETable.cxx @@ -0,0 +1,961 @@ +/* -*- 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 <flat/ETable.hxx> +#include <com/sun/star/sdbc/ColumnValue.hpp> +#include <com/sun/star/sdbc/DataType.hpp> +#include <com/sun/star/sdbc/XRow.hpp> +#include <com/sun/star/ucb/XContentAccess.hpp> +#include <flat/EConnection.hxx> +#include <flat/EColumns.hxx> +#include <o3tl/safeint.hxx> +#include <rtl/math.hxx> +#include <sal/log.hxx> +#include <tools/urlobj.hxx> +#include <cppuhelper/queryinterface.hxx> +#include <comphelper/numbers.hxx> +#include <comphelper/servicehelper.hxx> +#include <com/sun/star/util/NumberFormat.hpp> +#include <com/sun/star/util/NumberFormatter.hpp> +#include <com/sun/star/util/NumberFormatsSupplier.hpp> +#include <i18nlangtag/languagetag.hxx> +#include <connectivity/dbconversion.hxx> +#include <connectivity/sdbcx/VColumn.hxx> +#include <file/quotedstring.hxx> +#include <file/FDriver.hxx> +#include <unotools/syslocale.hxx> +#include <unotools/charclass.hxx> + +using namespace ::comphelper; +using namespace connectivity; +using namespace connectivity::flat; +using namespace connectivity::file; +using namespace ::cppu; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::ucb; +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 ::com::sun::star::lang; +using namespace ::com::sun::star::util; +using std::vector; +using std::lower_bound; + + +void OFlatTable::fillColumns(const css::lang::Locale& _aLocale) +{ + m_bNeedToReadLine = true; // we overwrite m_aCurrentLine, seek the stream, ... + m_pFileStream->Seek(0); + // tdf#123055 - start to read unicode text in order to avoid the BOM + m_pFileStream->StartReadingUnicodeText(RTL_TEXTENCODING_DONTKNOW); + m_aCurrentLine = QuotedTokenizedString(); + bool bRead = true; + + const OFlatConnection* const pConnection = getFlatConnection(); + const bool bHasHeaderLine = pConnection->isHeaderLine(); + + QuotedTokenizedString aHeaderLine; + const sal_Int32 nPos = static_cast<sal_Int32>(m_pFileStream->Tell()); + TRowPositionInFile rowPos(nPos, nPos); + sal_Int32 rowNum(0); + if ( bHasHeaderLine ) + { + bRead = readLine(&rowPos.second, &rowPos.first, true); + if(bRead) + aHeaderLine = m_aCurrentLine; + } + setRowPos(rowNum++, rowPos); + + // read first row + if(bRead) + { + bRead = readLine(&rowPos.second, &rowPos.first); + if(bRead) + setRowPos(rowNum++, rowPos); + } + + if ( !bHasHeaderLine || !aHeaderLine.Len()) + { + // use first non-empty row as headerline because we need the number of columns + while(bRead && m_aCurrentLine.Len() == 0) + { + bRead = readLine(&rowPos.second, &rowPos.first); + if(bRead) + setRowPos(rowNum++, rowPos); + } + aHeaderLine = m_aCurrentLine; + } + // column count + const sal_Int32 nFieldCount = aHeaderLine.GetTokenCount(m_cFieldDelimiter,m_cStringDelimiter); + + if(!m_aColumns.is()) + m_aColumns = new OSQLColumns(); + else + m_aColumns->clear(); + + m_aTypes.clear(); + m_aPrecisions.clear(); + m_aScales.clear(); + // reserve some space + m_aColumns->reserve(nFieldCount+1); + m_aTypes.assign(nFieldCount+1,DataType::SQLNULL); + m_aPrecisions.assign(nFieldCount+1,-1); + m_aScales.assign(nFieldCount+1,-1); + + const bool bCase = m_pConnection->getMetaData()->supportsMixedCaseQuotedIdentifiers(); + CharClass aCharClass( pConnection->getDriver()->getComponentContext(), LanguageTag( _aLocale)); + // read description + const sal_Unicode cDecimalDelimiter = pConnection->getDecimalDelimiter(); + const sal_Unicode cThousandDelimiter = pConnection->getThousandDelimiter(); + ::comphelper::UStringMixEqual aCase(bCase); + vector<OUString> aColumnNames; + vector<OUString> aTypeNames; + aTypeNames.resize(nFieldCount); + const sal_Int32 nMaxRowsToScan = pConnection->getMaxRowsToScan(); + sal_Int32 nRowCount = 0; + + do + { + sal_Int32 nStartPosHeaderLine = 0; // use for efficient way to get the tokens + sal_Int32 nStartPosFirstLine = 0; // use for efficient way to get the tokens + sal_Int32 nStartPosFirstLine2 = 0; + for( sal_Int32 i = 0; i < nFieldCount; i++ ) + { + if ( nRowCount == 0) + { + OUString aColumnName; + if ( bHasHeaderLine ) + { + aColumnName = aHeaderLine.GetTokenSpecial(nStartPosHeaderLine,m_cFieldDelimiter,m_cStringDelimiter); + } + if ( aColumnName.isEmpty() ) + { + aColumnName = "C" + OUString::number(i+1); + } + aColumnNames.push_back(aColumnName); + } + if(bRead) + { + impl_fillColumnInfo_nothrow(m_aCurrentLine, nStartPosFirstLine, nStartPosFirstLine2, + m_aTypes[i], m_aPrecisions[i], m_aScales[i], aTypeNames[i], + cDecimalDelimiter, cThousandDelimiter, aCharClass); + } + } + ++nRowCount; + bRead = readLine(&rowPos.second, &rowPos.first); + if(bRead) + setRowPos(rowNum++, rowPos); + } + while(nRowCount < nMaxRowsToScan && bRead); + + for( sal_Int32 i = 0; i < nFieldCount; i++ ) + { + // check if the columname already exists + OUString aAlias(aColumnNames[i]); + OSQLColumns::const_iterator aFind = connectivity::find(m_aColumns->begin(),m_aColumns->end(),aAlias,aCase); + sal_Int32 nExprCnt = 0; + while(aFind != m_aColumns->end()) + { + aAlias = aColumnNames[i] + OUString::number(++nExprCnt); + aFind = connectivity::find(m_aColumns->begin(),m_aColumns->end(),aAlias,aCase); + } + + rtl::Reference<sdbcx::OColumn> pColumn = new sdbcx::OColumn(aAlias,aTypeNames[i],OUString(),OUString(), + ColumnValue::NULLABLE, + m_aPrecisions[i], + m_aScales[i], + m_aTypes[i], + false, + false, + false, + bCase, + m_CatalogName, getSchema(), getName()); + m_aColumns->push_back(pColumn); + } + + m_pFileStream->Seek(m_aRowPosToFilePos[0].second); +} + +void OFlatTable::impl_fillColumnInfo_nothrow(QuotedTokenizedString const & aFirstLine, sal_Int32& nStartPosFirstLine, sal_Int32& nStartPosFirstLine2, + sal_Int32& io_nType, sal_Int32& io_nPrecisions, sal_Int32& io_nScales, OUString& o_sTypeName, + const sal_Unicode cDecimalDelimiter, const sal_Unicode cThousandDelimiter, const CharClass& aCharClass) +{ + if ( io_nType != DataType::VARCHAR ) + { + bool bNumeric = io_nType == DataType::SQLNULL || io_nType == DataType::DOUBLE || io_nType == DataType::DECIMAL || io_nType == DataType::INTEGER; + sal_Int32 nIndex = 0; + + if ( bNumeric ) + { + // first without fielddelimiter + OUString aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine,m_cFieldDelimiter); + if (aField.isEmpty() || + (m_cStringDelimiter && m_cStringDelimiter == aField[0])) + { + bNumeric = false; + if ( m_cStringDelimiter != '\0' ) + aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); + else + nStartPosFirstLine2 = nStartPosFirstLine; + } + else + { + OUString aField2; + if ( m_cStringDelimiter != '\0' ) + aField2 = aFirstLine.GetTokenSpecial(nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); + else + aField2 = aField; + + if (aField2.isEmpty()) + { + bNumeric = false; + } + else + { + bNumeric = true; + sal_Int32 nDot = 0; + sal_Int32 nDecimalDelCount = 0; + sal_Int32 nSpaceCount = 0; + for( sal_Int32 j = 0; j < aField2.getLength(); j++ ) + { + const sal_Unicode c = aField2[j]; + if ( j == nSpaceCount && m_cFieldDelimiter != 32 && c == 32 ) + { + ++nSpaceCount; + continue; + } + // just digits, decimal- and thousands-delimiter? + if ( ( !cDecimalDelimiter || c != cDecimalDelimiter ) && + ( !cThousandDelimiter || c != cThousandDelimiter ) && + !aCharClass.isDigit(aField2,j) && + ( j != 0 || (c != '+' && c != '-' ) ) ) + { + bNumeric = false; + break; + } + if (cDecimalDelimiter && c == cDecimalDelimiter) + { + io_nPrecisions = 15; // we have a decimal value + io_nScales = 2; + ++nDecimalDelCount; + } // if (cDecimalDelimiter && c == cDecimalDelimiter) + if ( c == '.' ) + ++nDot; + } + + if (nDecimalDelCount > 1 || nDot > 1 ) // if there is more than one dot it isn't a number + bNumeric = false; + if (bNumeric && cThousandDelimiter) + { + // Is the delimiter correct? + const std::u16string_view aValue = o3tl::getToken(aField2, 0, cDecimalDelimiter); + for( sal_Int32 j = static_cast<sal_Int32>(aValue.size()) - 4; j >= 0; j -= 4) + { + const sal_Unicode c = aValue[j]; + // just digits, decimal- and thousands-delimiter? + if (c == cThousandDelimiter && j) + continue; + else + { + bNumeric = false; + break; + } + } + } + + // now also check for a date field + if (!bNumeric) + { + try + { + nIndex = m_xNumberFormatter->detectNumberFormat(css::util::NumberFormat::ALL,aField2); + } + catch(Exception&) + { + } + } + } + } + } + else if ( io_nType == DataType::DATE || io_nType == DataType::TIMESTAMP || io_nType == DataType::TIME) + { + OUString aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine,m_cFieldDelimiter); + if (aField.isEmpty() || + (m_cStringDelimiter && m_cStringDelimiter == aField[0])) + { + } + else + { + OUString aField2; + if ( m_cStringDelimiter != '\0' ) + aField2 = aFirstLine.GetTokenSpecial(nStartPosFirstLine2,m_cFieldDelimiter,m_cStringDelimiter); + else + aField2 = aField; + if (!aField2.isEmpty() ) + { + try + { + nIndex = m_xNumberFormatter->detectNumberFormat(css::util::NumberFormat::ALL,aField2); + } + catch(Exception&) + { + } + } + } + } + + if (bNumeric) + { + if (cDecimalDelimiter) + { + if(io_nPrecisions) + { + io_nType = DataType::DECIMAL; + o_sTypeName = "DECIMAL"; + } + else + { + io_nType = DataType::DOUBLE; + o_sTypeName = "DOUBLE"; + } + } + else + { + io_nType = DataType::INTEGER; + io_nPrecisions = 0; + io_nScales = 0; + } + } + else + { + switch (comphelper::getNumberFormatType(m_xNumberFormatter,nIndex)) + { + case css::util::NumberFormat::DATE: + io_nType = DataType::DATE; + o_sTypeName = "DATE"; + break; + case css::util::NumberFormat::DATETIME: + io_nType = DataType::TIMESTAMP; + o_sTypeName = "TIMESTAMP"; + break; + case css::util::NumberFormat::TIME: + io_nType = DataType::TIME; + o_sTypeName = "TIME"; + break; + default: + io_nType = DataType::VARCHAR; + io_nPrecisions = 0; // nyi: Data can be longer! + io_nScales = 0; + o_sTypeName = "VARCHAR"; + }; + } + } + else + { + OUString aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine,m_cFieldDelimiter); + if (aField.isEmpty() || + (m_cStringDelimiter && m_cStringDelimiter == aField[0])) + { + if ( m_cStringDelimiter != '\0' ) + aField = aFirstLine.GetTokenSpecial(nStartPosFirstLine2, m_cFieldDelimiter, m_cStringDelimiter); + else + nStartPosFirstLine2 = nStartPosFirstLine; + } + else + { + if ( m_cStringDelimiter != '\0' ) + aFirstLine.GetTokenSpecial(nStartPosFirstLine2, m_cFieldDelimiter, m_cStringDelimiter); + } + } +} + +OFlatTable::OFlatTable(sdbcx::OCollection* _pTables,OFlatConnection* _pConnection, + const OUString& Name, + const OUString& Type, + const OUString& Description , + const OUString& SchemaName, + const OUString& CatalogName + ) : OFlatTable_BASE(_pTables,_pConnection,Name, + Type, + Description, + SchemaName, + CatalogName) + ,m_nRowPos(0) + ,m_nMaxRowCount(0) + ,m_cStringDelimiter(_pConnection->getStringDelimiter()) + ,m_cFieldDelimiter(_pConnection->getFieldDelimiter()) + ,m_bNeedToReadLine(false) +{ + +} + +void OFlatTable::construct() +{ + SvtSysLocale aLocale; + css::lang::Locale aAppLocale(aLocale.GetLanguageTag().getLocale()); + + Reference< XNumberFormatsSupplier > xSupplier = NumberFormatsSupplier::createWithLocale( m_pConnection->getDriver()->getComponentContext(), aAppLocale ); + m_xNumberFormatter.set( NumberFormatter::create( m_pConnection->getDriver()->getComponentContext()), UNO_QUERY_THROW); + m_xNumberFormatter->attachNumberFormatsSupplier(xSupplier); + Reference<XPropertySet> xProp = xSupplier->getNumberFormatSettings(); + xProp->getPropertyValue("NullDate") >>= m_aNullDate; + + INetURLObject aURL; + aURL.SetURL(getEntry()); + + if(aURL.getExtension() != m_pConnection->getExtension()) + aURL.setExtension(m_pConnection->getExtension()); + + OUString aFileName = aURL.GetMainURL(INetURLObject::DecodeMechanism::NONE); + + m_pFileStream = createStream_simpleError( aFileName, StreamMode::READWRITE | StreamMode::NOCREATE | StreamMode::SHARE_DENYWRITE); + + if(!m_pFileStream) + m_pFileStream = createStream_simpleError( aFileName, StreamMode::READ | StreamMode::NOCREATE | StreamMode::SHARE_DENYNONE); + + if(!m_pFileStream) + return; + + sal_uInt64 const nSize = m_pFileStream->remainingSize(); + + // Buffersize is dependent on the file-size + m_pFileStream->SetBufferSize(nSize > 1000000 ? 32768 : + nSize > 100000 ? 16384 : + nSize > 10000 ? 4096 : 1024); + + fillColumns(aAppLocale); + + refreshColumns(); +} + +OUString OFlatTable::getEntry() const +{ + OUString sURL; + try + { + Reference< XResultSet > xDir = m_pConnection->getDir()->getStaticResultSet(); + Reference< XRow> xRow(xDir,UNO_QUERY); + OUString sName; + OUString sExt; + + INetURLObject aURL; + xDir->beforeFirst(); + while(xDir->next()) + { + sName = xRow->getString(1); + aURL.SetSmartProtocol(INetProtocol::File); + OUString sUrl = m_pConnection->getURL() + "/" + sName; + aURL.SetSmartURL( sUrl ); + + // cut the extension + sExt = aURL.getExtension(); + + // name and extension have to coincide + if ( m_pConnection->matchesExtension( sExt ) ) + { + if ( !sExt.isEmpty() ) + sName = sName.replaceAt(sName.getLength() - (sExt.getLength() + 1), sExt.getLength()+1, u""); + if ( sName == m_Name ) + { + Reference< XContentAccess > xContentAccess( xDir, UNO_QUERY ); + sURL = xContentAccess->queryContentIdentifierString(); + break; + } + } + } + xDir->beforeFirst(); // move back to before first record + } + catch(const Exception&) + { + OSL_ASSERT(false); + } + return sURL; +} + +void OFlatTable::refreshColumns() +{ + ::osl::MutexGuard aGuard( m_aMutex ); + + ::std::vector< OUString> aVector; + aVector.reserve(m_aColumns->size()); + + for (auto const& column : *m_aColumns) + aVector.push_back(Reference< XNamed>(column,UNO_QUERY_THROW)->getName()); + + if(m_xColumns) + m_xColumns->reFill(aVector); + else + m_xColumns.reset(new OFlatColumns(this,m_aMutex,aVector)); +} + + +void SAL_CALL OFlatTable::disposing() +{ + OFileTable::disposing(); + ::osl::MutexGuard aGuard(m_aMutex); + m_aColumns = nullptr; +} + +Sequence< Type > SAL_CALL OFlatTable::getTypes( ) +{ + Sequence< Type > aTypes = OTable_TYPEDEF::getTypes(); + 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<XKeysSupplier>::get()|| + *pBegin == cppu::UnoType<XRename>::get()|| + *pBegin == cppu::UnoType<XIndexesSupplier>::get()|| + *pBegin == cppu::UnoType<XAlterTable>::get()|| + *pBegin == cppu::UnoType<XDataDescriptorFactory>::get())) + { + aOwnTypes.push_back(*pBegin); + } + } + return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size()); +} + + +Any SAL_CALL OFlatTable::queryInterface( const Type & rType ) +{ + if( rType == cppu::UnoType<XKeysSupplier>::get()|| + rType == cppu::UnoType<XIndexesSupplier>::get()|| + rType == cppu::UnoType<XRename>::get()|| + rType == cppu::UnoType<XAlterTable>::get()|| + rType == cppu::UnoType<XDataDescriptorFactory>::get()) + return Any(); + + Any aRet = OTable_TYPEDEF::queryInterface(rType); + return aRet.hasValue() ? aRet : ::cppu::queryInterface(rType,static_cast< css::lang::XUnoTunnel*> (this)); +} + + +const Sequence< sal_Int8 > & OFlatTable::getUnoTunnelId() +{ + static const comphelper::UnoIdInit implId; + return implId.getSeq(); +} + +// css::lang::XUnoTunnel + +sal_Int64 OFlatTable::getSomething( const Sequence< sal_Int8 > & rId ) +{ + return comphelper::getSomethingImpl(rId, this, + comphelper::FallbackToGetSomethingOf<OFlatTable_BASE>{}); +} + +bool OFlatTable::fetchRow(OValueRefRow& _rRow, const OSQLColumns & _rCols, bool bRetrieveData) +{ + *(*_rRow)[0] = m_nFilePos; + + if (!bRetrieveData) + return true; + + bool result = false; + if ( m_bNeedToReadLine ) + { + m_pFileStream->Seek(m_nFilePos); + TRowPositionInFile rowPos(0, 0); + if(readLine(&rowPos.second, &rowPos.first)) + { + setRowPos(m_nRowPos, rowPos); + m_bNeedToReadLine = false; + result = true; + } + // else let run through so that we set _rRow to all NULL + } + + const OFlatConnection * const pConnection = getFlatConnection(); + const sal_Unicode cDecimalDelimiter = pConnection->getDecimalDelimiter(); + const sal_Unicode cThousandDelimiter = pConnection->getThousandDelimiter(); + // Fields: + sal_Int32 nStartPos = 0; + OSQLColumns::const_iterator aIter = _rCols.begin(); + OSQLColumns::const_iterator aEnd = _rCols.end(); + const OValueRefVector::size_type nCount = _rRow->size(); + for (OValueRefVector::size_type i = 1; + aIter != aEnd && i < nCount; + ++aIter, i++) + { + OUString aStr = m_aCurrentLine.GetTokenSpecial(nStartPos,m_cFieldDelimiter,m_cStringDelimiter); + + if (aStr.isEmpty()) + { + (*_rRow)[i]->setNull(); + } + else + { + sal_Int32 nType = m_aTypes[i-1]; + switch(nType) + { + case DataType::TIMESTAMP: + case DataType::DATE: + case DataType::TIME: + { + try + { + double nRes = m_xNumberFormatter->convertStringToNumber(css::util::NumberFormat::ALL,aStr); + + switch(nType) + { + case DataType::DATE: + *(*_rRow)[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDate(nRes,m_aNullDate)); + break; + case DataType::TIMESTAMP: + *(*_rRow)[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toDateTime(nRes,m_aNullDate)); + break; + default: + *(*_rRow)[i] = ::dbtools::DBTypeConversion::toDouble(::dbtools::DBTypeConversion::toTime(nRes)); + } + } + catch(Exception&) + { + (*_rRow)[i]->setNull(); + } + } break; + case DataType::DOUBLE: + case DataType::INTEGER: + case DataType::DECIMAL: + case DataType::NUMERIC: + { + + OUString aStrConverted; + if ( DataType::INTEGER != nType ) + { + OSL_ENSURE((cDecimalDelimiter && nType != DataType::INTEGER) || + (!cDecimalDelimiter && nType == DataType::INTEGER), + "Wrong type"); + + OUStringBuffer aBuf(aStr.getLength()); + // convert to Standard-Notation (DecimalPOINT without thousands-comma): + for (sal_Int32 j = 0; j < aStr.getLength(); ++j) + { + const sal_Unicode cChar = aStr[j]; + if (cDecimalDelimiter && cChar == cDecimalDelimiter) + aBuf.append('.'); + else if ( cChar == '.' ) // special case, if decimal separator isn't '.' we have to put the string after it + continue; + else if (cThousandDelimiter && cChar == cThousandDelimiter) + { + // leave out + } + else + aBuf.append(cChar); + } // for (j = 0; j < aStr.(); ++j) + aStrConverted = aBuf.makeStringAndClear(); + } // if ( DataType::INTEGER != nType ) + else + { + if ( cThousandDelimiter ) + aStrConverted = aStr.replaceAll(OUStringChar(cThousandDelimiter), ""); + else + aStrConverted = aStr; + } + const double nVal = ::rtl::math::stringToDouble(aStrConverted,'.',','); + + // #99178# OJ + if ( DataType::DECIMAL == nType || DataType::NUMERIC == nType ) + *(*_rRow)[i] = OUString(OUString::number(nVal)); + else + *(*_rRow)[i] = nVal; + } break; + + default: + { + // Copy Value as String in Row-Variable + *(*_rRow)[i] = ORowSetValue(aStr); + } + break; + } // switch(nType) + (*_rRow)[i]->setTypeKind(nType); + } + } + return result; +} + + +void OFlatTable::refreshHeader() +{ + SAL_INFO( "connectivity.flat", "flat lionel@mamane.lu OFlatTable::refreshHeader" ); +} + + +namespace +{ + template< typename Tp, typename Te> struct RangeBefore + { + bool operator() (const Tp &p, const Te &e) + { + assert(p.first <= p.second); + return p.second <= e; + } + }; +} + +bool OFlatTable::seekRow(IResultSetHelper::Movement eCursorPosition, sal_Int32 nOffset, sal_Int32& nCurPos) +{ + OSL_ENSURE(m_pFileStream,"OFlatTable::seekRow: FileStream is NULL!"); + + + switch(eCursorPosition) + { + case IResultSetHelper::FIRST: + m_nRowPos = 0; + [[fallthrough]]; + case IResultSetHelper::NEXT: + { + assert(m_nRowPos >= 0); + if(m_nMaxRowCount != 0 && m_nRowPos > m_nMaxRowCount) + return false; + ++m_nRowPos; + if(m_aRowPosToFilePos.size() > o3tl::make_unsigned(m_nRowPos)) + { + m_bNeedToReadLine = true; + m_nFilePos = m_aRowPosToFilePos[m_nRowPos].first; + nCurPos = m_aRowPosToFilePos[m_nRowPos].second; + } + else + { + assert(m_aRowPosToFilePos.size() == static_cast< vector< TRowPositionInFile >::size_type >(m_nRowPos)); + const TRowPositionInFile &lastRowPos(m_aRowPosToFilePos.back()); + // Our ResultSet is allowed to disagree with us only + // on the position of the first line + // (because of the special case of the header...) + assert(m_nRowPos == 1 || nCurPos == lastRowPos.second); + + m_nFilePos = lastRowPos.second; + m_pFileStream->Seek(m_nFilePos); + + TRowPositionInFile newRowPos; + if(!readLine(&newRowPos.second, &newRowPos.first)) + { + m_nMaxRowCount = m_nRowPos - 1; + return false; + } + + nCurPos = newRowPos.second; + setRowPos(m_nRowPos, newRowPos); + } + } + + break; + case IResultSetHelper::PRIOR: + assert(m_nRowPos >= 0); + + if(m_nRowPos == 0) + return false; + + --m_nRowPos; + { + assert (m_nRowPos >= 0); + assert(m_aRowPosToFilePos.size() >= o3tl::make_unsigned(m_nRowPos)); + const TRowPositionInFile &aPositions(m_aRowPosToFilePos[m_nRowPos]); + m_nFilePos = aPositions.first; + nCurPos = aPositions.second; + m_bNeedToReadLine = true; + } + + break; + case IResultSetHelper::LAST: + if (m_nMaxRowCount == 0) + { + while(seekRow(IResultSetHelper::NEXT, 1, nCurPos)) ; // run through after last row + } + // m_nMaxRowCount can still be zero, but now it means there a genuinely zero rows in the table + return seekRow(IResultSetHelper::ABSOLUTE1, m_nMaxRowCount, nCurPos); + case IResultSetHelper::RELATIVE1: + { + const sal_Int32 nNewRowPos = m_nRowPos + nOffset; + if (nNewRowPos < 0) + return false; + // ABSOLUTE will take care of case nNewRowPos > nMaxRowCount + return seekRow(IResultSetHelper::ABSOLUTE1, nNewRowPos, nCurPos); + } + case IResultSetHelper::ABSOLUTE1: + { + if(nOffset < 0) + { + if (m_nMaxRowCount == 0) + { + if (!seekRow(IResultSetHelper::LAST, 0, nCurPos)) + return false; + } + // m_nMaxRowCount can still be zero, but now it means there a genuinely zero rows in the table + nOffset = m_nMaxRowCount + nOffset; + } + if(nOffset < 0) + { + seekRow(IResultSetHelper::ABSOLUTE1, 0, nCurPos); + return false; + } + if(m_nMaxRowCount && nOffset > m_nMaxRowCount) + { + m_nRowPos = m_nMaxRowCount + 1; + const TRowPositionInFile &lastRowPos(m_aRowPosToFilePos.back()); + m_nFilePos = lastRowPos.second; + nCurPos = lastRowPos.second; + return false; + } + + assert(m_nRowPos >=0); + assert(m_aRowPosToFilePos.size() > o3tl::make_unsigned(m_nRowPos)); + assert(nOffset >= 0); + if(m_aRowPosToFilePos.size() > o3tl::make_unsigned(nOffset)) + { + m_nFilePos = m_aRowPosToFilePos[nOffset].first; + nCurPos = m_aRowPosToFilePos[nOffset].second; + m_nRowPos = nOffset; + m_bNeedToReadLine = true; + } + else + { + assert(m_nRowPos < nOffset); + while(m_nRowPos < nOffset) + { + if(!seekRow(IResultSetHelper::NEXT, 1, nCurPos)) + return false; + } + assert(m_nRowPos == nOffset); + } + } + + break; + case IResultSetHelper::BOOKMARK: + { + vector< TRowPositionInFile >::const_iterator aFind = lower_bound(m_aRowPosToFilePos.begin(), + m_aRowPosToFilePos.end(), + nOffset, + RangeBefore< TRowPositionInFile, sal_Int32 >()); + + if(aFind == m_aRowPosToFilePos.end() || aFind->first != nOffset) + //invalid bookmark + return false; + + m_bNeedToReadLine = true; + m_nFilePos = aFind->first; + nCurPos = aFind->second; + m_nRowPos = aFind - m_aRowPosToFilePos.begin(); + break; + } + } + + return true; +} + + +bool OFlatTable::readLine(sal_Int32 * const pEndPos, sal_Int32 * const pStartPos, const bool nonEmpty) +{ + const rtl_TextEncoding nEncoding = m_pConnection->getTextEncoding(); + m_aCurrentLine = QuotedTokenizedString(); + do + { + if (pStartPos) + *pStartPos = static_cast<sal_Int32>(m_pFileStream->Tell()); + m_pFileStream->ReadByteStringLine(m_aCurrentLine, nEncoding); + if (m_pFileStream->eof()) + return false; + + QuotedTokenizedString sLine = m_aCurrentLine; // check if the string continues on next line + sal_Int32 nLastOffset = 0; + bool isQuoted = false; + bool isFieldStarting = true; + while (true) + { + bool wasQuote = false; + const sal_Unicode *p = sLine.GetString().getStr() + nLastOffset; + while (*p) + { + if (isQuoted) + { + if (*p == m_cStringDelimiter) + wasQuote = !wasQuote; + else + { + if (wasQuote) + { + wasQuote = false; + isQuoted = false; + if (*p == m_cFieldDelimiter) + isFieldStarting = true; + } + } + } + else + { + if (isFieldStarting) + { + isFieldStarting = false; + if (*p == m_cStringDelimiter) + isQuoted = true; + else if (*p == m_cFieldDelimiter) + isFieldStarting = true; + } + else if (*p == m_cFieldDelimiter) + isFieldStarting = true; + } + ++p; + } + + if (wasQuote) + isQuoted = false; + + if (isQuoted) + { + nLastOffset = sLine.Len(); + m_pFileStream->ReadByteStringLine(sLine,nEncoding); + if ( !m_pFileStream->eof() ) + { + OUString aStr = m_aCurrentLine.GetString() + "\n" + sLine.GetString(); + m_aCurrentLine.SetString(aStr); + sLine = m_aCurrentLine; + } + else + break; + } + else + break; + } + } + while(nonEmpty && m_aCurrentLine.Len() == 0); + + if(pEndPos) + *pEndPos = static_cast<sal_Int32>(m_pFileStream->Tell()); + return true; +} + + +void OFlatTable::setRowPos(const vector<TRowPositionInFile>::size_type rowNum, const TRowPositionInFile &rowPos) +{ + assert(m_aRowPosToFilePos.size() >= rowNum); + if(m_aRowPosToFilePos.size() == rowNum) + m_aRowPosToFilePos.push_back(rowPos); + else + { + SAL_WARN_IF(m_aRowPosToFilePos[rowNum] != rowPos, + "connectivity.flat", + "Setting position for row " << rowNum << " to (" << rowPos.first << ", " << rowPos.second << "), " + "but already had different position (" << m_aRowPosToFilePos[rowNum].first << ", " << m_aRowPosToFilePos[rowNum].second << ")"); + m_aRowPosToFilePos[rowNum] = rowPos; + } +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/ETables.cxx b/connectivity/source/drivers/flat/ETables.cxx new file mode 100644 index 000000000..2e4dd377e --- /dev/null +++ b/connectivity/source/drivers/flat/ETables.cxx @@ -0,0 +1,44 @@ +/* -*- 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 <flat/ETables.hxx> +#include <flat/ETable.hxx> +#include <file/FCatalog.hxx> + +using namespace connectivity; +using namespace ::comphelper; +using namespace connectivity::flat; +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::lang; +using namespace ::com::sun::star::container; + +sdbcx::ObjectType OFlatTables::createObject(const OUString& _rName) +{ + rtl::Reference<OFlatTable> pRet = new OFlatTable(this, static_cast<OFlatConnection*>(static_cast<OFileCatalog&>(m_rParent).getConnection()), + _rName,"TABLE"); + pRet->construct(); + return pRet; +} + + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ diff --git a/connectivity/source/drivers/flat/flat.component b/connectivity/source/drivers/flat/flat.component new file mode 100644 index 000000000..715fbecd8 --- /dev/null +++ b/connectivity/source/drivers/flat/flat.component @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + * 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 . + --> + +<component loader="com.sun.star.loader.SharedLibrary" environment="@CPPU_ENV@" + xmlns="http://openoffice.org/2010/uno-components"> + <implementation name="com.sun.star.comp.sdbc.flat.ODriver" + constructor="connectivity_flat_ODriver"> + <service name="com.sun.star.sdbc.Driver"/> + <service name="com.sun.star.sdbcx.Driver"/> + </implementation> +</component> |