summaryrefslogtreecommitdiffstats
path: root/dbaccess/source/core
diff options
context:
space:
mode:
Diffstat (limited to 'dbaccess/source/core')
-rw-r--r--dbaccess/source/core/api/BookmarkSet.cxx204
-rw-r--r--dbaccess/source/core/api/BookmarkSet.hxx57
-rw-r--r--dbaccess/source/core/api/CIndexes.cxx87
-rw-r--r--dbaccess/source/core/api/CIndexes.hxx47
-rw-r--r--dbaccess/source/core/api/CRowSetColumn.cxx92
-rw-r--r--dbaccess/source/core/api/CRowSetColumn.hxx49
-rw-r--r--dbaccess/source/core/api/CRowSetDataColumn.cxx236
-rw-r--r--dbaccess/source/core/api/CRowSetDataColumn.hxx99
-rw-r--r--dbaccess/source/core/api/CacheSet.cxx580
-rw-r--r--dbaccess/source/core/api/CacheSet.hxx172
-rw-r--r--dbaccess/source/core/api/FilteredContainer.cxx459
-rw-r--r--dbaccess/source/core/api/HelperCollections.cxx106
-rw-r--r--dbaccess/source/core/api/HelperCollections.hxx106
-rw-r--r--dbaccess/source/core/api/KeySet.cxx1463
-rw-r--r--dbaccess/source/core/api/KeySet.hxx216
-rw-r--r--dbaccess/source/core/api/OptimisticSet.cxx586
-rw-r--r--dbaccess/source/core/api/OptimisticSet.hxx76
-rw-r--r--dbaccess/source/core/api/PrivateRow.cxx133
-rw-r--r--dbaccess/source/core/api/PrivateRow.hxx58
-rw-r--r--dbaccess/source/core/api/RowSet.cxx2965
-rw-r--r--dbaccess/source/core/api/RowSet.hxx527
-rw-r--r--dbaccess/source/core/api/RowSetBase.cxx1438
-rw-r--r--dbaccess/source/core/api/RowSetBase.hxx402
-rw-r--r--dbaccess/source/core/api/RowSetCache.cxx1713
-rw-r--r--dbaccess/source/core/api/RowSetCache.hxx190
-rw-r--r--dbaccess/source/core/api/RowSetCacheIterator.cxx91
-rw-r--r--dbaccess/source/core/api/RowSetCacheIterator.hxx72
-rw-r--r--dbaccess/source/core/api/RowSetRow.hxx52
-rw-r--r--dbaccess/source/core/api/SingleSelectQueryComposer.cxx1922
-rw-r--r--dbaccess/source/core/api/StaticSet.cxx280
-rw-r--r--dbaccess/source/core/api/StaticSet.hxx75
-rw-r--r--dbaccess/source/core/api/TableDeco.cxx634
-rw-r--r--dbaccess/source/core/api/View.cxx120
-rw-r--r--dbaccess/source/core/api/WrappedResultSet.cxx184
-rw-r--r--dbaccess/source/core/api/WrappedResultSet.hxx60
-rw-r--r--dbaccess/source/core/api/callablestatement.cxx250
-rw-r--r--dbaccess/source/core/api/column.cxx411
-rw-r--r--dbaccess/source/core/api/columnsettings.cxx150
-rw-r--r--dbaccess/source/core/api/datacolumn.cxx396
-rw-r--r--dbaccess/source/core/api/datacolumn.hxx107
-rw-r--r--dbaccess/source/core/api/datasettings.cxx191
-rw-r--r--dbaccess/source/core/api/definitioncolumn.cxx610
-rw-r--r--dbaccess/source/core/api/preparedstatement.cxx412
-rw-r--r--dbaccess/source/core/api/query.cxx383
-rw-r--r--dbaccess/source/core/api/query.hxx147
-rw-r--r--dbaccess/source/core/api/querycomposer.cxx265
-rw-r--r--dbaccess/source/core/api/querycontainer.cxx430
-rw-r--r--dbaccess/source/core/api/querydescriptor.cxx269
-rw-r--r--dbaccess/source/core/api/querydescriptor.hxx143
-rw-r--r--dbaccess/source/core/api/resultcolumn.cxx296
-rw-r--r--dbaccess/source/core/api/resultcolumn.hxx87
-rw-r--r--dbaccess/source/core/api/resultset.cxx994
-rw-r--r--dbaccess/source/core/api/resultset.hxx221
-rw-r--r--dbaccess/source/core/api/statement.cxx591
-rw-r--r--dbaccess/source/core/api/table.cxx352
-rw-r--r--dbaccess/source/core/api/tablecontainer.cxx456
-rw-r--r--dbaccess/source/core/api/viewcontainer.cxx254
-rw-r--r--dbaccess/source/core/dataaccess/ComponentDefinition.cxx285
-rw-r--r--dbaccess/source/core/dataaccess/ComponentDefinition.hxx159
-rw-r--r--dbaccess/source/core/dataaccess/ContentHelper.cxx615
-rw-r--r--dbaccess/source/core/dataaccess/ModelImpl.cxx1432
-rw-r--r--dbaccess/source/core/dataaccess/SharedConnection.cxx154
-rw-r--r--dbaccess/source/core/dataaccess/SharedConnection.hxx118
-rw-r--r--dbaccess/source/core/dataaccess/bookmarkcontainer.cxx301
-rw-r--r--dbaccess/source/core/dataaccess/commandcontainer.cxx100
-rw-r--r--dbaccess/source/core/dataaccess/commandcontainer.hxx72
-rw-r--r--dbaccess/source/core/dataaccess/commanddefinition.cxx153
-rw-r--r--dbaccess/source/core/dataaccess/commanddefinition.hxx125
-rw-r--r--dbaccess/source/core/dataaccess/connection.cxx808
-rw-r--r--dbaccess/source/core/dataaccess/connection.hxx229
-rw-r--r--dbaccess/source/core/dataaccess/dataaccessdescriptor.cxx229
-rw-r--r--dbaccess/source/core/dataaccess/databasecontext.cxx753
-rw-r--r--dbaccess/source/core/dataaccess/databasedocument.cxx2211
-rw-r--r--dbaccess/source/core/dataaccess/databasedocument.hxx753
-rw-r--r--dbaccess/source/core/dataaccess/databaseregistrations.cxx369
-rw-r--r--dbaccess/source/core/dataaccess/databaseregistrations.hxx32
-rw-r--r--dbaccess/source/core/dataaccess/datasource.cxx1437
-rw-r--r--dbaccess/source/core/dataaccess/datasource.hxx220
-rw-r--r--dbaccess/source/core/dataaccess/definitioncontainer.cxx679
-rw-r--r--dbaccess/source/core/dataaccess/documentcontainer.cxx770
-rw-r--r--dbaccess/source/core/dataaccess/documentcontainer.hxx137
-rw-r--r--dbaccess/source/core/dataaccess/documentdefinition.cxx2102
-rw-r--r--dbaccess/source/core/dataaccess/documentdefinition.hxx356
-rw-r--r--dbaccess/source/core/dataaccess/documenteventexecutor.cxx199
-rw-r--r--dbaccess/source/core/dataaccess/documenteventexecutor.hxx59
-rw-r--r--dbaccess/source/core/dataaccess/documenteventnotifier.cxx290
-rw-r--r--dbaccess/source/core/dataaccess/documenteventnotifier.hxx128
-rw-r--r--dbaccess/source/core/dataaccess/documentevents.cxx216
-rw-r--r--dbaccess/source/core/dataaccess/intercept.cxx363
-rw-r--r--dbaccess/source/core/dataaccess/intercept.hxx113
-rw-r--r--dbaccess/source/core/dataaccess/myucp_datasupplier.cxx330
-rw-r--r--dbaccess/source/core/dataaccess/myucp_datasupplier.hxx59
-rw-r--r--dbaccess/source/core/dataaccess/myucp_resultset.cxx74
-rw-r--r--dbaccess/source/core/dataaccess/myucp_resultset.hxx49
-rw-r--r--dbaccess/source/core/inc/ContainerMediator.hxx79
-rw-r--r--dbaccess/source/core/inc/ContentHelper.hxx183
-rw-r--r--dbaccess/source/core/inc/DatabaseDataProvider.hxx262
-rw-r--r--dbaccess/source/core/inc/FilteredContainer.hxx136
-rw-r--r--dbaccess/source/core/inc/ModelImpl.hxx542
-rw-r--r--dbaccess/source/core/inc/PropertyForward.hxx69
-rw-r--r--dbaccess/source/core/inc/RefreshListener.hxx42
-rw-r--r--dbaccess/source/core/inc/SingleSelectQueryComposer.hxx263
-rw-r--r--dbaccess/source/core/inc/TableDeco.hxx164
-rw-r--r--dbaccess/source/core/inc/View.hxx71
-rw-r--r--dbaccess/source/core/inc/bookmarkcontainer.hxx148
-rw-r--r--dbaccess/source/core/inc/callablestatement.hxx80
-rw-r--r--dbaccess/source/core/inc/column.hxx217
-rw-r--r--dbaccess/source/core/inc/columnsettings.hxx88
-rw-r--r--dbaccess/source/core/inc/commandbase.hxx50
-rw-r--r--dbaccess/source/core/inc/composertools.hxx121
-rw-r--r--dbaccess/source/core/inc/containerapprove.hxx57
-rw-r--r--dbaccess/source/core/inc/databasecontext.hxx180
-rw-r--r--dbaccess/source/core/inc/datasettings.hxx77
-rw-r--r--dbaccess/source/core/inc/definitioncolumn.hxx291
-rw-r--r--dbaccess/source/core/inc/definitioncontainer.hxx323
-rw-r--r--dbaccess/source/core/inc/documentevents.hxx75
-rw-r--r--dbaccess/source/core/inc/migrwarndlg.hxx24
-rw-r--r--dbaccess/source/core/inc/object.hxx30
-rw-r--r--dbaccess/source/core/inc/objectnameapproval.hxx75
-rw-r--r--dbaccess/source/core/inc/preparedstatement.hxx105
-rw-r--r--dbaccess/source/core/inc/querycomposer.hxx91
-rw-r--r--dbaccess/source/core/inc/querycontainer.hxx165
-rw-r--r--dbaccess/source/core/inc/recovery/dbdocrecovery.hxx71
-rw-r--r--dbaccess/source/core/inc/sdbcoretools.hxx55
-rw-r--r--dbaccess/source/core/inc/statement.hxx179
-rw-r--r--dbaccess/source/core/inc/table.hxx140
-rw-r--r--dbaccess/source/core/inc/tablecontainer.hxx96
-rw-r--r--dbaccess/source/core/inc/veto.hxx55
-rw-r--r--dbaccess/source/core/inc/viewcontainer.hxx94
-rw-r--r--dbaccess/source/core/misc/ContainerMediator.cxx231
-rw-r--r--dbaccess/source/core/misc/DatabaseDataProvider.cxx1066
-rw-r--r--dbaccess/source/core/misc/PropertyForward.cxx146
-rw-r--r--dbaccess/source/core/misc/apitools.cxx114
-rw-r--r--dbaccess/source/core/misc/dsntypes.cxx565
-rw-r--r--dbaccess/source/core/misc/migrwarndlg.cxx22
-rw-r--r--dbaccess/source/core/misc/objectnameapproval.cxx74
-rw-r--r--dbaccess/source/core/misc/sdbcoretools.cxx142
-rw-r--r--dbaccess/source/core/misc/veto.cxx49
-rw-r--r--dbaccess/source/core/recovery/dbdocrecovery.cxx347
-rw-r--r--dbaccess/source/core/recovery/settingsimport.cxx216
-rw-r--r--dbaccess/source/core/recovery/settingsimport.hxx163
-rw-r--r--dbaccess/source/core/recovery/storagestream.cxx55
-rw-r--r--dbaccess/source/core/recovery/storagestream.hxx51
-rw-r--r--dbaccess/source/core/recovery/storagetextstream.cxx71
-rw-r--r--dbaccess/source/core/recovery/storagetextstream.hxx52
-rw-r--r--dbaccess/source/core/recovery/storagexmlstream.cxx151
-rw-r--r--dbaccess/source/core/recovery/storagexmlstream.hxx88
-rw-r--r--dbaccess/source/core/recovery/subcomponentloader.cxx124
-rw-r--r--dbaccess/source/core/recovery/subcomponentloader.hxx71
-rw-r--r--dbaccess/source/core/recovery/subcomponentrecovery.cxx628
-rw-r--r--dbaccess/source/core/recovery/subcomponentrecovery.hxx114
-rw-r--r--dbaccess/source/core/recovery/subcomponents.hxx61
-rw-r--r--dbaccess/source/core/resource/core_resource.cxx41
153 files changed, 48785 insertions, 0 deletions
diff --git a/dbaccess/source/core/api/BookmarkSet.cxx b/dbaccess/source/core/api/BookmarkSet.cxx
new file mode 100644
index 000000000..75dfc24f5
--- /dev/null
+++ b/dbaccess/source/core/api/BookmarkSet.cxx
@@ -0,0 +1,204 @@
+/* -*- 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 "BookmarkSet.hxx"
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <connectivity/dbexception.hxx>
+
+using namespace dbaccess;
+using namespace ::connectivity;
+using namespace ::dbtools;
+using namespace ::com::sun::star::uno;
+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::lang;
+using namespace ::osl;
+
+void OBookmarkSet::construct(const Reference< XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter)
+{
+ OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
+ m_xRowLocate.set(_xDriverSet,UNO_QUERY);
+}
+
+void OBookmarkSet::reset(const Reference< XResultSet>& _xDriverSet)
+{
+ construct(_xDriverSet, m_sRowSetFilter);
+}
+
+Any OBookmarkSet::getBookmark()
+{
+ return m_xRowLocate->getBookmark();
+}
+
+bool OBookmarkSet::moveToBookmark( const Any& bookmark )
+{
+ return m_xRowLocate->moveToBookmark(bookmark);
+}
+
+sal_Int32 OBookmarkSet::compareBookmarks( const Any& _first, const Any& _second )
+{
+ return m_xRowLocate->compareBookmarks(_first,_second);
+}
+
+bool OBookmarkSet::hasOrderedBookmarks( )
+{
+ return m_xRowLocate->hasOrderedBookmarks();
+}
+
+sal_Int32 OBookmarkSet::hashBookmark( const Any& bookmark )
+{
+ return m_xRowLocate->hashBookmark(bookmark);
+}
+
+void OBookmarkSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ Reference<XRowUpdate> xUpdRow(m_xRowLocate,UNO_QUERY);
+ if(!xUpdRow.is())
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_XROWUPDATE ), StandardSQLState::GENERAL_ERROR, *this );
+
+ Reference<XResultSetUpdate> xUpd(m_xRowLocate,UNO_QUERY);
+ if(xUpd.is())
+ {
+ xUpd->moveToInsertRow();
+ sal_Int32 i = 1;
+ connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->end();
+ for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->begin()+1;aIter != aEnd;++aIter,++i)
+ {
+ aIter->setSigned(m_aSignedFlags[i-1]);
+ updateColumn(i,xUpdRow,*aIter);
+ }
+ xUpd->insertRow();
+ (*_rInsertRow->begin()) = m_xRowLocate->getBookmark();
+ }
+ else
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_XRESULTSETUPDATE ), StandardSQLState::GENERAL_ERROR, *this );
+}
+
+void OBookmarkSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ Reference<XRowUpdate> xUpdRow(m_xRowLocate,UNO_QUERY);
+ if(!xUpdRow.is())
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_XROWUPDATE ), StandardSQLState::GENERAL_ERROR, *this );
+
+ sal_Int32 i = 1;
+ connectivity::ORowVector< ORowSetValue > ::Vector::const_iterator aOrgIter = _rOriginalRow->begin()+1;
+ connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->end();
+ for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->begin()+1;aIter != aEnd;++aIter,++i,++aOrgIter)
+ {
+ aIter->setSigned(aOrgIter->isSigned());
+ updateColumn(i,xUpdRow,*aIter);
+ }
+
+
+ Reference<XResultSetUpdate> xUpd(m_xRowLocate,UNO_QUERY);
+ if(xUpd.is())
+ xUpd->updateRow();
+ else
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_XRESULTSETUPDATE ), StandardSQLState::GENERAL_ERROR, *this );
+}
+
+void OBookmarkSet::deleteRow(const ORowSetRow& /*_rDeleteRow*/ ,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ Reference<XResultSetUpdate> xUpd(m_xRowLocate,UNO_QUERY);
+
+ xUpd->deleteRow();
+}
+
+void OBookmarkSet::updateColumn(sal_Int32 nPos, const Reference< XRowUpdate >& _xParameter, const ORowSetValue& _rValue)
+{
+ if(!(_rValue.isBound() && _rValue.isModified()))
+ return;
+
+ if(_rValue.isNull())
+ _xParameter->updateNull(nPos);
+ else
+ {
+
+ switch(_rValue.getTypeKind())
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ _xParameter->updateNumericObject(nPos,_rValue.makeAny(),m_xSetMetaData->getScale(nPos));
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ _xParameter->updateString(nPos,_rValue.getString());
+ break;
+ case DataType::BIGINT:
+ if ( _rValue.isSigned() )
+ _xParameter->updateLong(nPos,_rValue.getLong());
+ else
+ _xParameter->updateString(nPos,_rValue.getString());
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ _xParameter->updateBoolean(nPos,_rValue.getBool());
+ break;
+ case DataType::TINYINT:
+ if ( _rValue.isSigned() )
+ _xParameter->updateByte(nPos,_rValue.getInt8());
+ else
+ _xParameter->updateShort(nPos,_rValue.getInt16());
+ break;
+ case DataType::SMALLINT:
+ if ( _rValue.isSigned() )
+ _xParameter->updateShort(nPos,_rValue.getInt16());
+ else
+ _xParameter->updateInt(nPos,_rValue.getInt32());
+ break;
+ case DataType::INTEGER:
+ if ( _rValue.isSigned() )
+ _xParameter->updateInt(nPos,_rValue.getInt32());
+ else
+ _xParameter->updateLong(nPos,_rValue.getLong());
+ break;
+ case DataType::FLOAT:
+ _xParameter->updateFloat(nPos,_rValue.getFloat());
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ _xParameter->updateDouble(nPos,_rValue.getDouble());
+ break;
+ case DataType::DATE:
+ _xParameter->updateDate(nPos,_rValue.getDate());
+ break;
+ case DataType::TIME:
+ _xParameter->updateTime(nPos,_rValue.getTime());
+ break;
+ case DataType::TIMESTAMP:
+ _xParameter->updateTimestamp(nPos,_rValue.getDateTime());
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ _xParameter->updateBytes(nPos,_rValue.getSequence());
+ break;
+ case DataType::BLOB:
+ case DataType::CLOB:
+ _xParameter->updateObject(nPos,_rValue.getAny());
+ break;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/BookmarkSet.hxx b/dbaccess/source/core/api/BookmarkSet.hxx
new file mode 100644
index 000000000..9863a80ec
--- /dev/null
+++ b/dbaccess/source/core/api/BookmarkSet.hxx
@@ -0,0 +1,57 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "CacheSet.hxx"
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+
+namespace dbaccess
+{
+ // this set is used when we have a bookmarkable set from the driver
+ class OBookmarkSet : public OCacheSet
+ {
+ css::uno::Reference< css::sdbcx::XRowLocate> m_xRowLocate;
+
+ void updateColumn(sal_Int32 nPos, const css::uno::Reference< css::sdbc::XRowUpdate >& _xParameter, const connectivity::ORowSetValue& _rValue);
+ public:
+ explicit OBookmarkSet(sal_Int32 i_nMaxRows) : OCacheSet(i_nMaxRows)
+ {}
+ virtual ~OBookmarkSet() override
+ {
+ m_xRowLocate = nullptr;
+ }
+
+ virtual void construct(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter) override;
+ virtual void reset(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet) override;
+ // css::sdbcx::XRowLocate
+ virtual css::uno::Any getBookmark() override;
+ virtual bool moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Int32 compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual bool hasOrderedBookmarks( ) override;
+ virtual sal_Int32 hashBookmark( const css::uno::Any& bookmark ) override;
+ // css::sdbc::XResultSetUpdate
+ virtual void insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void updateRow(const ORowSetRow& _rInsertRow,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void deleteRow(const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/CIndexes.cxx b/dbaccess/source/core/api/CIndexes.cxx
new file mode 100644
index 000000000..409d87728
--- /dev/null
+++ b/dbaccess/source/core/api/CIndexes.cxx
@@ -0,0 +1,87 @@
+/* -*- 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 "CIndexes.hxx"
+
+
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+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 ::com::sun::star::lang;
+using namespace dbaccess;
+using namespace cppu;
+
+
+ObjectType OIndexes::createObject(const OUString& _rName)
+{
+ ObjectType xRet;
+ if ( m_xIndexes.is() && m_xIndexes->hasByName(_rName) )
+ xRet.set(m_xIndexes->getByName(_rName),UNO_QUERY);
+ else
+ xRet = OIndexesHelper::createObject(_rName);
+
+ return xRet;
+}
+
+Reference< XPropertySet > OIndexes::createDescriptor()
+{
+ Reference<XDataDescriptorFactory> xData( m_xIndexes,UNO_QUERY);
+ if(xData.is())
+ return xData->createDataDescriptor();
+ else
+ return OIndexesHelper::createDescriptor();
+}
+
+// XAppend
+ObjectType OIndexes::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ Reference<XAppend> xData( m_xIndexes,UNO_QUERY);
+ if ( !xData.is() )
+ return OIndexesHelper::appendObject( _rForName, descriptor );
+
+ xData->appendByDescriptor(descriptor);
+ return createObject( _rForName );
+}
+
+// XDrop
+void OIndexes::dropObject(sal_Int32 _nPos, const OUString& _sElementName)
+{
+ if ( m_xIndexes.is() )
+ {
+ Reference<XDrop> xData( m_xIndexes,UNO_QUERY);
+ if ( xData.is() )
+ xData->dropByName(_sElementName);
+ }
+ else
+ OIndexesHelper::dropObject(_nPos,_sElementName);
+}
+
+void OIndexes::disposing()
+{
+ if ( m_xIndexes.is() )
+ clear_NoDispose();
+ else
+ OIndexesHelper::disposing();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/CIndexes.hxx b/dbaccess/source/core/api/CIndexes.hxx
new file mode 100644
index 000000000..f20da6cbe
--- /dev/null
+++ b/dbaccess/source/core/api/CIndexes.hxx
@@ -0,0 +1,47 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <connectivity/TIndexes.hxx>
+
+namespace dbaccess
+{
+ class OIndexes : public connectivity::OIndexesHelper
+ {
+ css::uno::Reference< css::container::XNameAccess > m_xIndexes;
+ protected:
+ virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual connectivity::sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+ public:
+ OIndexes(connectivity::OTableHelper* _pTable,
+ ::osl::Mutex& _rMutex,
+ const std::vector< OUString> &_rVector,
+ const css::uno::Reference< css::container::XNameAccess >& _rxIndexes
+ ) : connectivity::OIndexesHelper(_pTable,_rMutex,_rVector)
+ ,m_xIndexes(_rxIndexes)
+ {}
+
+ virtual void disposing() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/CRowSetColumn.cxx b/dbaccess/source/core/api/CRowSetColumn.cxx
new file mode 100644
index 000000000..98435b7c4
--- /dev/null
+++ b/dbaccess/source/core/api/CRowSetColumn.cxx
@@ -0,0 +1,92 @@
+/* -*- 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 <stringconstants.hxx>
+#include <strings.hxx>
+#include "CRowSetColumn.hxx"
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::beans;
+
+namespace dbaccess
+{
+
+ORowSetColumn::ORowSetColumn( const Reference < XResultSetMetaData >& _xMetaData,
+ const Reference < XRow >& _xRow, sal_Int32 _nPos,
+ const Reference< XDatabaseMetaData >& _rxDBMeta,
+ const OUString& _rDescription,
+ const OUString& i_sLabel,
+ const std::function<const ::connectivity::ORowSetValue& (sal_Int32)> &_getValue )
+ :ORowSetDataColumn( _xMetaData, _xRow, nullptr, _nPos, _rxDBMeta, _rDescription, i_sLabel, _getValue )
+{
+}
+
+::cppu::IPropertyArrayHelper* ORowSetColumn::createArrayHelper( ) const
+{
+ css::uno::Sequence< css::beans::Property> aDescriptor
+ {
+ { PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_DISPLAYSIZE, PROPERTY_ID_DISPLAYSIZE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISAUTOINCREMENT, PROPERTY_ID_ISAUTOINCREMENT, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISCASESENSITIVE, PROPERTY_ID_ISCASESENSITIVE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISCURRENCY, PROPERTY_ID_ISCURRENCY, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISDEFINITELYWRITABLE, PROPERTY_ID_ISDEFINITELYWRITABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISNULLABLE, PROPERTY_ID_ISNULLABLE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISREADONLY, PROPERTY_ID_ISREADONLY, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_ISROWVERSION, PROPERTY_ID_ISROWVERSION, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISSEARCHABLE, PROPERTY_ID_ISSEARCHABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISSIGNED, PROPERTY_ID_ISSIGNED, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISWRITABLE, PROPERTY_ID_ISWRITABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_LABEL, PROPERTY_ID_LABEL, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_PRECISION, PROPERTY_ID_PRECISION, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SCALE, PROPERTY_ID_SCALE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SERVICENAME, PROPERTY_ID_SERVICENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TABLENAME, PROPERTY_ID_TABLENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TYPE, PROPERTY_ID_TYPE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TYPENAME, PROPERTY_ID_TYPENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_VALUE, PROPERTY_ID_VALUE, cppu::UnoType<Any>::get(), css::beans::PropertyAttribute::READONLY | css::beans::PropertyAttribute::BOUND}
+ };
+
+ Sequence< Property > aRegisteredProperties;
+ describeProperties( aRegisteredProperties );
+
+ return new ::cppu::OPropertyArrayHelper( ::comphelper::concatSequences( aDescriptor, aRegisteredProperties ), false );
+}
+
+::cppu::IPropertyArrayHelper& ORowSetColumn::getInfoHelper()
+{
+ return *static_cast< ::comphelper::OPropertyArrayUsageHelper< ORowSetColumn >* >(this)->getArrayHelper();
+}
+
+void SAL_CALL ORowSetColumn::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue )
+{
+ OSL_ENSURE( nHandle != PROPERTY_ID_VALUE, "ORowSetColumn::setFastPropertyValue_NoBroadcast: hmm? This property is marked as READONLY!" );
+ if ( nHandle != PROPERTY_ID_VALUE )
+ ORowSetDataColumn::setFastPropertyValue_NoBroadcast( nHandle, rValue );
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/CRowSetColumn.hxx b/dbaccess/source/core/api/CRowSetColumn.hxx
new file mode 100644
index 000000000..bc0ae7eed
--- /dev/null
+++ b/dbaccess/source/core/api/CRowSetColumn.hxx
@@ -0,0 +1,49 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include "RowSetRow.hxx"
+#include <connectivity/CommonTools.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include "CRowSetDataColumn.hxx"
+
+namespace dbaccess
+{
+ class ORowSetColumn;
+ class ORowSetColumn :public ORowSetDataColumn
+ ,public ::comphelper::OPropertyArrayUsageHelper< ORowSetColumn >
+
+ {
+ public:
+ ORowSetColumn( const css::uno::Reference < css::sdbc::XResultSetMetaData >& _xMetaData,
+ const css::uno::Reference < css::sdbc::XRow >& _xRow,
+ sal_Int32 _nPos,
+ const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rxDBMeta,
+ const OUString& _rDescription,
+ const OUString& i_sLabel,
+ const std::function<const ::connectivity::ORowSetValue& (sal_Int32)> &_getValue);
+
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle,const css::uno::Any& rValue ) override;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/CRowSetDataColumn.cxx b/dbaccess/source/core/api/CRowSetDataColumn.cxx
new file mode 100644
index 000000000..0dce91848
--- /dev/null
+++ b/dbaccess/source/core/api/CRowSetDataColumn.cxx
@@ -0,0 +1,236 @@
+/* -*- 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 "CRowSetDataColumn.hxx"
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+using namespace dbaccess;
+using namespace comphelper;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+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 namespace cppu;
+using namespace osl;
+
+
+ORowSetDataColumn::ORowSetDataColumn( const Reference < XResultSetMetaData >& _xMetaData,
+ const Reference < XRow >& _xRow,
+ const Reference < XRowUpdate >& _xRowUpdate,
+ sal_Int32 _nPos,
+ const Reference< XDatabaseMetaData >& _rxDBMeta,
+ const OUString& _rDescription,
+ const OUString& i_sLabel,
+ const std::function<const ORowSetValue& (sal_Int32)> &_getValue)
+ :ODataColumn(_xMetaData,_xRow,_xRowUpdate,_nPos,_rxDBMeta)
+ ,m_pGetValue(_getValue)
+ ,m_sLabel(i_sLabel)
+ ,m_aDescription(_rDescription)
+{
+ OColumnSettings::registerProperties( *this );
+ registerProperty( PROPERTY_DESCRIPTION, PROPERTY_ID_DESCRIPTION, PropertyAttribute::READONLY, &m_aDescription, cppu::UnoType<decltype(m_aDescription)>::get() );
+}
+
+ORowSetDataColumn::~ORowSetDataColumn()
+{
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* ORowSetDataColumn::createArrayHelper( ) const
+{
+ css::uno::Sequence< css::beans::Property> aDescriptor
+ {
+ { PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_DISPLAYSIZE, PROPERTY_ID_DISPLAYSIZE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISAUTOINCREMENT, PROPERTY_ID_ISAUTOINCREMENT, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISCASESENSITIVE, PROPERTY_ID_ISCASESENSITIVE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISCURRENCY, PROPERTY_ID_ISCURRENCY, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISDEFINITELYWRITABLE, PROPERTY_ID_ISDEFINITELYWRITABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISNULLABLE, PROPERTY_ID_ISNULLABLE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISREADONLY, PROPERTY_ID_ISREADONLY, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_ISROWVERSION, PROPERTY_ID_ISROWVERSION, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISSEARCHABLE, PROPERTY_ID_ISSEARCHABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISSIGNED, PROPERTY_ID_ISSIGNED, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISWRITABLE, PROPERTY_ID_ISWRITABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_LABEL, PROPERTY_ID_LABEL, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_PRECISION, PROPERTY_ID_PRECISION, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SCALE, PROPERTY_ID_SCALE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SERVICENAME, PROPERTY_ID_SERVICENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TABLENAME, PROPERTY_ID_TABLENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TYPE, PROPERTY_ID_TYPE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TYPENAME, PROPERTY_ID_TYPENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_VALUE, PROPERTY_ID_VALUE, cppu::UnoType<Any>::get(), css::beans::PropertyAttribute::BOUND }
+ };
+
+ Sequence< Property > aRegisteredProperties;
+ describeProperties( aRegisteredProperties );
+
+ return new ::cppu::OPropertyArrayHelper( ::comphelper::concatSequences( aDescriptor, aRegisteredProperties ), false );
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& ORowSetDataColumn::getInfoHelper()
+{
+ return *static_cast< ::comphelper::OPropertyArrayUsageHelper< ORowSetDataColumn >* >(this)->getArrayHelper();
+}
+
+void SAL_CALL ORowSetDataColumn::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ if ( PROPERTY_ID_VALUE == nHandle )
+ {
+ try
+ {
+ rValue = m_pGetValue(m_nPos).makeAny();
+ }
+ catch(const SQLException &e)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw WrappedTargetRuntimeException("Could not retrieve column value: " + e.Message,
+ *const_cast<ORowSetDataColumn*>(this),
+ anyEx);
+ }
+ }
+ else if ( PROPERTY_ID_LABEL == nHandle && !m_sLabel.isEmpty() )
+ rValue <<= m_sLabel;
+ else
+ ODataColumn::getFastPropertyValue( rValue, nHandle );
+}
+
+void SAL_CALL ORowSetDataColumn::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue )
+{
+ switch( nHandle )
+ {
+ case PROPERTY_ID_VALUE:
+ updateObject(rValue);
+ break;
+ case PROPERTY_ID_ISREADONLY:
+ {
+ bool bVal = false;
+ rValue >>= bVal;
+ m_isReadOnly = bVal;
+ }
+ break;
+ default:
+ ODataColumn::setFastPropertyValue_NoBroadcast( nHandle,rValue );
+ break;
+ }
+}
+
+sal_Bool SAL_CALL ORowSetDataColumn::convertFastPropertyValue( Any & rConvertedValue,
+ Any & rOldValue,
+ sal_Int32 nHandle,
+ const Any& rValue )
+{
+ bool bModified = false;
+ switch( nHandle )
+ {
+ case PROPERTY_ID_VALUE:
+ {
+ rConvertedValue = rValue;
+ getFastPropertyValue(rOldValue, PROPERTY_ID_VALUE);
+ bModified = rConvertedValue != rOldValue;
+ }
+ break;
+ case PROPERTY_ID_ISREADONLY:
+ {
+ rConvertedValue = rValue;
+ getFastPropertyValue(rOldValue, PROPERTY_ID_ISREADONLY);
+ bModified = rConvertedValue != rOldValue;
+ }
+ break;
+ default:
+ bModified = ODataColumn::convertFastPropertyValue(rConvertedValue, rOldValue, nHandle, rValue);
+ break;
+ }
+
+ return bModified;
+}
+
+Sequence< sal_Int8 > ORowSetDataColumn::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void ORowSetDataColumn::fireValueChange(const ORowSetValue& _rOldValue)
+{
+ const ORowSetValue &value(m_pGetValue(m_nPos));
+ if ( value != _rOldValue)
+ {
+ sal_Int32 nHandle(PROPERTY_ID_VALUE);
+ m_aOldValue = _rOldValue.makeAny();
+ Any aNew = value.makeAny();
+
+ fire(&nHandle, &aNew, &m_aOldValue, 1, false );
+ }
+}
+
+ORowSetDataColumns::ORowSetDataColumns(
+ bool _bCase,
+ const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns,
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const std::vector< OUString> &_rVector
+ ) : connectivity::sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector)
+ ,m_aColumns(_rColumns)
+{
+}
+
+ORowSetDataColumns::~ORowSetDataColumns()
+{
+}
+
+sdbcx::ObjectType ORowSetDataColumns::createObject(const OUString& _rName)
+{
+ connectivity::sdbcx::ObjectType xNamed;
+
+ ::comphelper::UStringMixEqual aCase(isCaseSensitive());
+ ::connectivity::OSQLColumns::Vector::const_iterator first = ::connectivity::find(m_aColumns->begin(),m_aColumns->end(),_rName,aCase);
+ if(first != m_aColumns->end())
+ xNamed = *first;
+
+ return xNamed;
+}
+
+void ORowSetDataColumns::disposing()
+{
+ ORowSetDataColumns_BASE::disposing();
+ m_aColumns = nullptr;
+}
+
+void ORowSetDataColumns::assign(const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns,const std::vector< OUString> &_rVector)
+{
+ m_aColumns = _rColumns;
+ reFill(_rVector);
+}
+
+void ORowSetDataColumns::impl_refresh()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/CRowSetDataColumn.hxx b/dbaccess/source/core/api/CRowSetDataColumn.hxx
new file mode 100644
index 000000000..f0efcbf8d
--- /dev/null
+++ b/dbaccess/source/core/api/CRowSetDataColumn.hxx
@@ -0,0 +1,99 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include "datacolumn.hxx"
+#include "RowSetRow.hxx"
+#include <columnsettings.hxx>
+
+#include <connectivity/CommonTools.hxx>
+#include <comphelper/proparrhlp.hxx>
+
+#include <functional>
+
+namespace dbaccess
+{
+ class ORowSetDataColumn;
+ typedef ::comphelper::OPropertyArrayUsageHelper<ORowSetDataColumn> ORowSetDataColumn_PROP;
+
+ class ORowSetDataColumn : public ODataColumn,
+ public OColumnSettings,
+ public ORowSetDataColumn_PROP
+ {
+ protected:
+ const std::function<const ::connectivity::ORowSetValue& (sal_Int32)> m_pGetValue;
+ css::uno::Any m_aOldValue;
+ OUString m_sLabel;
+ OUString m_aDescription; // description
+
+ virtual ~ORowSetDataColumn() override;
+ public:
+ ORowSetDataColumn(const css::uno::Reference < css::sdbc::XResultSetMetaData >& _xMetaData,
+ const css::uno::Reference < css::sdbc::XRow >& _xRow,
+ const css::uno::Reference < css::sdbc::XRowUpdate >& _xRowUpdate,
+ sal_Int32 _nPos,
+ const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rxDBMeta,
+ const OUString& _rDescription,
+ const OUString& i_sLabel,
+ const std::function<const ::connectivity::ORowSetValue& (sal_Int32)> &_getValue);
+
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+ // comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue( css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue ) override;
+
+ void fireValueChange(const ::connectivity::ORowSetValue& _rOldValue);
+ protected:
+ using ODataColumn::getFastPropertyValue;
+ };
+
+ typedef connectivity::sdbcx::OCollection ORowSetDataColumns_BASE;
+ class ORowSetDataColumns : public ORowSetDataColumns_BASE
+ {
+ ::rtl::Reference< ::connectivity::OSQLColumns> m_aColumns;
+ protected:
+ virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override;
+ public:
+ ORowSetDataColumns(
+ bool _bCase,
+ const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns,
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const std::vector< OUString> &_rVector
+ );
+ virtual ~ORowSetDataColumns() override;
+ // only the name is identical to ::cppu::OComponentHelper
+ virtual void disposing() override;
+ void assign(const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns,const std::vector< OUString> &_rVector);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/CacheSet.cxx b/dbaccess/source/core/api/CacheSet.cxx
new file mode 100644
index 000000000..9774877e6
--- /dev/null
+++ b/dbaccess/source/core/api/CacheSet.cxx
@@ -0,0 +1,580 @@
+/* -*- 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 "CacheSet.hxx"
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
+
+#include <connectivity/dbtools.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <comphelper/types.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <osl/diagnose.h>
+#include <tools/diagnose_ex.h>
+
+using namespace comphelper;
+
+using namespace dbaccess;
+using namespace dbtools;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+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::lang;
+using namespace ::com::sun::star::io;
+using namespace ::osl;
+
+
+OCacheSet::OCacheSet(sal_Int32 i_nMaxRows)
+ :m_nMaxRows(i_nMaxRows)
+ ,m_bInserted(false)
+ ,m_bUpdated(false)
+ ,m_bDeleted(false)
+{
+
+}
+
+OUString OCacheSet::getIdentifierQuoteString() const
+{
+ OUString sQuote;
+ if ( m_xConnection.is() )
+ if (auto xMeta = m_xConnection->getMetaData())
+ sQuote = xMeta->getIdentifierQuoteString();
+ return sQuote;
+}
+
+void OCacheSet::construct( const Reference< XResultSet>& _xDriverSet,const OUString &i_sRowSetFilter)
+{
+ OSL_ENSURE(_xDriverSet.is(),"Invalid resultSet");
+
+ m_sRowSetFilter = i_sRowSetFilter;
+
+ if(!_xDriverSet.is())
+ return;
+
+ m_xDriverSet = _xDriverSet;
+ m_xDriverRow.set(_xDriverSet,UNO_QUERY);
+ m_xSetMetaData = Reference<XResultSetMetaDataSupplier>(_xDriverSet,UNO_QUERY_THROW)->getMetaData();
+ if ( m_xSetMetaData.is() )
+ {
+ const sal_Int32 nCount = m_xSetMetaData->getColumnCount();
+ m_aNullable.resize(nCount);
+ m_aSignedFlags.resize(nCount);
+ m_aColumnTypes.resize(nCount);
+ auto pNullableIter = m_aNullable.begin();
+ auto pSignedIter = m_aSignedFlags.begin();
+ auto pColumnIter = m_aColumnTypes.begin();
+ for (sal_Int32 i=1; i <= nCount; ++i,++pSignedIter,++pColumnIter,++pNullableIter)
+ {
+ *pNullableIter = m_xSetMetaData->isNullable(i) != ColumnValue::NO_NULLS;
+ *pSignedIter = m_xSetMetaData->isSigned(i);
+ *pColumnIter = m_xSetMetaData->getColumnType(i);
+ }
+ }
+ Reference< XStatement> xStmt(m_xDriverSet->getStatement(),UNO_QUERY);
+ if(xStmt.is())
+ m_xConnection = xStmt->getConnection();
+ else
+ {
+ Reference< XPreparedStatement> xPrepStmt(m_xDriverSet->getStatement(),UNO_QUERY);
+ if ( xPrepStmt.is() )
+ m_xConnection = xPrepStmt->getConnection();
+ }
+}
+
+OCacheSet::~OCacheSet()
+{
+ try
+ {
+ m_xDriverSet = nullptr;
+ m_xDriverRow = nullptr;
+ m_xSetMetaData = nullptr;
+ m_xConnection = nullptr;
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "");
+ }
+ catch(...)
+ {
+ SAL_WARN("dbaccess", "Unknown Exception occurred");
+ }
+
+}
+
+void OCacheSet::fillTableName(const Reference<XPropertySet>& _xTable)
+{
+ OSL_ENSURE(_xTable.is(),"OCacheSet::fillTableName: PropertySet is empty!");
+ if(m_aComposedTableName.isEmpty() && _xTable.is() )
+ {
+ Reference<XDatabaseMetaData> xMeta(m_xConnection->getMetaData());
+ m_aComposedTableName = composeTableName(xMeta
+ ,comphelper::getString(_xTable->getPropertyValue(PROPERTY_CATALOGNAME))
+ ,comphelper::getString(_xTable->getPropertyValue(PROPERTY_SCHEMANAME))
+ ,comphelper::getString(_xTable->getPropertyValue(PROPERTY_NAME))
+ ,true
+ ,::dbtools::EComposeRule::InDataManipulation);
+ }
+}
+
+void OCacheSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable )
+{
+ Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
+ fillTableName(xSet);
+
+ OUStringBuffer aSql("INSERT INTO " + m_aComposedTableName + " ( ");
+
+ // set values and column names
+ OUStringBuffer aValues(" VALUES ( ");
+ OUString aQuote = getIdentifierQuoteString();
+ sal_Int32 i = 1;
+ ORowVector< ORowSetValue >::Vector::const_iterator aIter = _rInsertRow->begin()+1;
+ connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->end();
+ for(; aIter != aEnd;++aIter)
+ {
+ aSql.append(::dbtools::quoteName( aQuote,m_xSetMetaData->getColumnName(i++)) + ",");
+ aValues.append("?,");
+ }
+
+ aSql[aSql.getLength() - 1] = ')';
+ aValues[aValues.getLength() - 1] = ')';
+
+ aSql.append(aValues);
+ // now create end execute the prepared statement
+ {
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(aSql.makeStringAndClear()));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+ i = 1;
+ for(aIter = _rInsertRow->begin()+1; aIter != aEnd;++aIter,++i)
+ {
+ if(aIter->isNull())
+ xParameter->setNull(i,aIter->getTypeKind());
+ else
+ setParameter(i,xParameter,*aIter,m_xSetMetaData->getColumnType(i),m_xSetMetaData->getScale(i));
+ }
+
+ m_bInserted = xPrep->executeUpdate() > 0;
+ }
+
+ // TODO set the bookmark in the insert row
+}
+
+void OCacheSet::fillParameters( const ORowSetRow& _rRow
+ ,const connectivity::OSQLTable& _xTable
+ ,OUStringBuffer& _sCondition
+ ,OUStringBuffer& _sParameter
+ ,std::vector< sal_Int32>& _rOrgValues)
+{
+ // use keys and indexes for exact positioning
+ // first the keys
+ Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
+ const Reference<XNameAccess> xPrimaryKeyColumns = getPrimaryKeyColumns_throw(xSet);
+ // second the indexes
+ Reference<XIndexesSupplier> xIndexSup(_xTable,UNO_QUERY);
+ Reference<XIndexAccess> xIndexes;
+ if(xIndexSup.is())
+ xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY);
+
+ Reference<XPropertySet> xIndexColsSup;
+ std::vector< Reference<XNameAccess> > aAllIndexColumns;
+ if(xIndexes.is())
+ {
+ for(sal_Int32 j=0;j<xIndexes->getCount();++j)
+ {
+ xIndexColsSup.set(xIndexes->getByIndex(j),UNO_QUERY);
+ if( xIndexColsSup.is()
+ && comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISUNIQUE))
+ && !comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISPRIMARYKEYINDEX))
+ )
+ aAllIndexColumns.push_back(Reference<XColumnsSupplier>(xIndexColsSup,UNO_QUERY_THROW)->getColumns());
+ }
+ }
+
+ OUString aColumnName;
+
+ static const char aAnd[] = " AND ";
+
+ OUString aQuote = getIdentifierQuoteString();
+
+ sal_Int32 nCheckCount = 1; // index for the original values
+ sal_Int32 i = 1;
+
+ OUString sIsNull(" IS NULL");
+ OUString sParam(" = ?");
+ ORowVector< ORowSetValue >::Vector::const_iterator aIter = _rRow->begin()+1;
+ ORowVector< ORowSetValue >::Vector::const_iterator aEnd = _rRow->end();
+ for(; aIter != aEnd;++aIter,++nCheckCount,++i)
+ {
+ aColumnName = m_xSetMetaData->getColumnName(i);
+ if(xPrimaryKeyColumns.is() && xPrimaryKeyColumns->hasByName(aColumnName))
+ {
+ _sCondition.append(::dbtools::quoteName( aQuote,aColumnName));
+ if(aIter->isNull())
+ _sCondition.append(sIsNull);
+ else
+ _sCondition.append(sParam);
+ _sCondition.append(aAnd);
+ _rOrgValues.push_back(nCheckCount);
+
+ }
+ for (auto const& indexColumn : aAllIndexColumns)
+ {
+ if(indexColumn->hasByName(aColumnName))
+ {
+ _sCondition.append(::dbtools::quoteName( aQuote,aColumnName));
+ if(aIter->isNull())
+ _sCondition.append(sIsNull);
+ else
+ _sCondition.append(sParam);
+ _sCondition.append(aAnd);
+ _rOrgValues.push_back(nCheckCount);
+ break;
+ }
+ }
+ if(aIter->isModified())
+ {
+ _sParameter.append(::dbtools::quoteName( aQuote,aColumnName) + "?,");
+ }
+ }
+}
+
+void OCacheSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& _xTable )
+{
+ Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
+ fillTableName(xSet);
+
+ OUStringBuffer aSql("UPDATE " + m_aComposedTableName + " SET ");
+ // list all columns that should be set
+
+ OUStringBuffer aCondition;
+ std::vector< sal_Int32> aOrgValues;
+ fillParameters(_rInsertRow,_xTable,aCondition,aSql,aOrgValues);
+ aSql[aSql.getLength() - 1] = ' ';
+ if ( !aCondition.isEmpty() )
+ {
+ aCondition.setLength(aCondition.getLength()-5);
+
+ aSql.append(" WHERE " + aCondition);
+ }
+ else
+ ::dbtools::throwSQLException(
+ DBA_RES( RID_STR_NO_UPDATE_MISSING_CONDITION ), StandardSQLState::GENERAL_ERROR, *this );
+
+ // now create end execute the prepared statement
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(aSql.makeStringAndClear()));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+ sal_Int32 i = 1;
+ connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->end();
+ for(ORowVector< ORowSetValue >::Vector::const_iterator aIter = _rInsertRow->begin()+1; aIter != aEnd;++aIter)
+ {
+ if(aIter->isModified())
+ {
+ setParameter(i,xParameter,*aIter,m_xSetMetaData->getColumnType(i),m_xSetMetaData->getScale(i));
+ ++i;
+ }
+ }
+ for (auto const& orgValue : aOrgValues)
+ {
+ setParameter(i,xParameter,(*_rOriginalRow)[orgValue],m_xSetMetaData->getColumnType(i),m_xSetMetaData->getScale(i));
+ ++i;
+ }
+
+ m_bUpdated = xPrep->executeUpdate() > 0;
+}
+
+void OCacheSet::deleteRow(const ORowSetRow& _rDeleteRow ,const connectivity::OSQLTable& _xTable )
+{
+ Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
+ fillTableName(xSet);
+
+ OUStringBuffer aSql("DELETE FROM " + m_aComposedTableName + " WHERE ");
+
+ // use keys and indexes for exact positioning
+ Reference<XIndexesSupplier> xIndexSup(_xTable,UNO_QUERY);
+ Reference<XIndexAccess> xIndexes;
+ if(xIndexSup.is())
+ xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY);
+
+ // Reference<XColumnsSupplier>
+ Reference<XPropertySet> xIndexColsSup;
+ std::vector< Reference<XNameAccess> > aAllIndexColumns;
+ if(xIndexes.is())
+ {
+ for(sal_Int32 j=0;j<xIndexes->getCount();++j)
+ {
+ xIndexColsSup.set(xIndexes->getByIndex(j),UNO_QUERY);
+ if( xIndexColsSup.is()
+ && comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISUNIQUE))
+ && !comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISPRIMARYKEYINDEX))
+ )
+ aAllIndexColumns.push_back(Reference<XColumnsSupplier>(xIndexColsSup,UNO_QUERY_THROW)->getColumns());
+ }
+ }
+
+ OUStringBuffer aColumnName;
+ std::vector< sal_Int32> aOrgValues;
+ fillParameters(_rDeleteRow,_xTable,aSql,aColumnName,aOrgValues);
+
+ aSql.setLength(aSql.getLength()-5);
+
+ // now create and execute the prepared statement
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(aSql.makeStringAndClear()));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+ sal_Int32 i = 1;
+ for (auto const& orgValue : aOrgValues)
+ {
+ setParameter(i,xParameter,(*_rDeleteRow)[orgValue],m_xSetMetaData->getColumnType(i),m_xSetMetaData->getScale(i));
+ ++i;
+ }
+
+ m_bDeleted = xPrep->executeUpdate() > 0;
+}
+
+void OCacheSet::setParameter(sal_Int32 nPos
+ ,const Reference< XParameters >& _xParameter
+ ,const ORowSetValue& _rValue
+ ,sal_Int32 _nType
+ ,sal_Int32 _nScale)
+{
+ sal_Int32 nType = ( _nType != DataType::OTHER ) ? _nType : _rValue.getTypeKind();
+ ::dbtools::setObjectWithInfo(_xParameter,nPos,_rValue,nType,_nScale);
+}
+
+void OCacheSet::fillValueRow(ORowSetRow& _rRow,sal_Int32 _nPosition)
+{
+ Any aBookmark = getBookmark();
+ if(!aBookmark.hasValue())
+ aBookmark <<= _nPosition;
+
+ connectivity::ORowVector< ORowSetValue >::Vector::iterator aIter = _rRow->begin();
+ connectivity::ORowVector< ORowSetValue >::Vector::iterator aEnd = _rRow->end();
+ (*aIter) = aBookmark;
+ ++aIter;
+ for(sal_Int32 i=1;aIter != aEnd;++aIter,++i)
+ {
+ aIter->setSigned(m_aSignedFlags[i-1]);
+ aIter->fill(i, m_aColumnTypes[i-1], this);
+ }
+}
+
+sal_Bool SAL_CALL OCacheSet::wasNull( )
+{
+ return m_xDriverRow->wasNull();
+}
+
+OUString SAL_CALL OCacheSet::getString( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getString(columnIndex);
+}
+
+sal_Bool SAL_CALL OCacheSet::getBoolean( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getBoolean(columnIndex);
+}
+
+sal_Int8 SAL_CALL OCacheSet::getByte( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getByte(columnIndex);
+}
+
+sal_Int16 SAL_CALL OCacheSet::getShort( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getShort(columnIndex);
+}
+
+sal_Int32 SAL_CALL OCacheSet::getInt( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getInt(columnIndex);
+}
+
+sal_Int64 SAL_CALL OCacheSet::getLong( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getLong(columnIndex);
+}
+
+float SAL_CALL OCacheSet::getFloat( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getFloat(columnIndex);
+}
+
+double SAL_CALL OCacheSet::getDouble( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getDouble(columnIndex);
+}
+
+Sequence< sal_Int8 > SAL_CALL OCacheSet::getBytes( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getBytes(columnIndex);
+}
+
+css::util::Date SAL_CALL OCacheSet::getDate( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getDate(columnIndex);
+}
+
+css::util::Time SAL_CALL OCacheSet::getTime( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getTime(columnIndex);
+}
+
+css::util::DateTime SAL_CALL OCacheSet::getTimestamp( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getTimestamp(columnIndex);
+}
+
+Reference< css::io::XInputStream > SAL_CALL OCacheSet::getBinaryStream( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getBinaryStream(columnIndex);
+}
+
+Reference< css::io::XInputStream > SAL_CALL OCacheSet::getCharacterStream( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getCharacterStream(columnIndex);
+}
+
+Any SAL_CALL OCacheSet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& typeMap )
+{
+ return m_xDriverRow->getObject(columnIndex,typeMap);
+}
+
+Reference< XRef > SAL_CALL OCacheSet::getRef( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getRef(columnIndex);
+}
+
+Reference< XBlob > SAL_CALL OCacheSet::getBlob( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getBlob(columnIndex);
+}
+
+Reference< XClob > SAL_CALL OCacheSet::getClob( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getClob(columnIndex);
+}
+
+Reference< XArray > SAL_CALL OCacheSet::getArray( sal_Int32 columnIndex )
+{
+ return m_xDriverRow->getArray(columnIndex);
+}
+
+// XResultSet
+bool OCacheSet::next()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ return m_xDriverSet->next();
+}
+
+void OCacheSet::beforeFirst( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ m_xDriverSet->beforeFirst();
+}
+
+void OCacheSet::afterLast( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ m_xDriverSet->afterLast();
+}
+
+bool OCacheSet::first()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ return m_xDriverSet->first();
+}
+
+bool OCacheSet::last()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ return m_xDriverSet->last();
+}
+
+sal_Int32 OCacheSet::getRow( )
+{
+ return m_xDriverSet->getRow();
+}
+
+bool OCacheSet::absolute( sal_Int32 row )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ return m_xDriverSet->absolute(row);
+}
+
+bool OCacheSet::previous( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ return m_xDriverSet->previous();
+}
+
+void OCacheSet::refreshRow( )
+{
+ m_xDriverSet->refreshRow();
+}
+
+bool OCacheSet::rowUpdated( )
+{
+ return m_xDriverSet->rowUpdated();
+}
+
+bool OCacheSet::rowInserted( )
+{
+ return m_xDriverSet->rowInserted();
+}
+
+bool OCacheSet::rowDeleted( )
+{
+ return m_xDriverSet->rowDeleted();
+}
+
+bool OCacheSet::isResultSetChanged() const
+{
+ return false;
+}
+
+void OCacheSet::mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& /*io_aInsertRow*/,ORowSetValueVector::Vector& /*io_aRow*/,std::vector<sal_Int32>& o_aChangedColumns)
+{
+ o_aChangedColumns.push_back(i_nColumnIndex);
+}
+
+bool OCacheSet::columnValuesUpdated(ORowSetValueVector::Vector& /*io_aCachedRow*/,const ORowSetValueVector::Vector& /*io_aRow*/)
+{
+ return false;
+}
+
+bool OCacheSet::updateColumnValues(const ORowSetValueVector::Vector& /*io_aCachedRow*/,ORowSetValueVector::Vector& /*io_aRow*/,const std::vector<sal_Int32>& /*i_aChangedColumns*/)
+{
+ return true;
+}
+
+void OCacheSet::fillMissingValues(ORowSetValueVector::Vector& /*io_aRow*/) const
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/CacheSet.hxx b/dbaccess/source/core/api/CacheSet.hxx
new file mode 100644
index 000000000..1006b9662
--- /dev/null
+++ b/dbaccess/source/core/api/CacheSet.hxx
@@ -0,0 +1,172 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include "RowSetRow.hxx"
+#include <cppuhelper/implbase.hxx>
+
+#include <vector>
+
+namespace com::sun::star::sdbc{ class XParameters; }
+
+namespace dbaccess
+{
+ class OCacheSet : public ::cppu::WeakImplHelper< css::sdbc::XRow>
+ {
+ protected:
+ css::uno::Reference< css::sdbc::XResultSet> m_xDriverSet;
+ css::uno::Reference< css::sdbc::XRow> m_xDriverRow;
+ css::uno::Reference< css::sdbc::XResultSetMetaData> m_xSetMetaData;
+ css::uno::Reference< css::sdbc::XConnection> m_xConnection;
+
+ std::vector<bool> m_aNullable;
+ std::vector<bool> m_aSignedFlags;
+ std::vector<sal_Int32> m_aColumnTypes;
+ OUString m_aComposedTableName;
+ sal_Int32 m_nMaxRows;
+ bool m_bInserted;
+ bool m_bUpdated;
+ bool m_bDeleted;
+ OUString m_sRowSetFilter;
+
+ explicit OCacheSet(sal_Int32 i_nMaxRows);
+ virtual ~OCacheSet() override;
+
+ static void setParameter(sal_Int32 nPos
+ ,const css::uno::Reference< css::sdbc::XParameters >& _xParameter
+ ,const connectivity::ORowSetValue& _rValue
+ ,sal_Int32 _nType
+ ,sal_Int32 _nScale
+ );
+ void fillParameters( const ORowSetRow& _rRow
+ ,const connectivity::OSQLTable& _xTable
+ ,OUStringBuffer& _sCondition
+ ,OUStringBuffer& _sParameter
+ ,std::vector< sal_Int32>& _rOrgValues);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void fillTableName(const css::uno::Reference< css::beans::XPropertySet>& _xTable);
+
+ OUString getIdentifierQuoteString() const;
+ public:
+
+ // late constructor
+ virtual void construct(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter);
+ virtual void fillValueRow(ORowSetRow& _rRow,sal_Int32 _nPosition);
+
+ // css::sdbc::XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ // css::sdbc::XResultSet
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool next();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual void beforeFirst( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual void afterLast( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool first();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool last();
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual sal_Int32 getRow( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool absolute( sal_Int32 row );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool previous( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual void refreshRow( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool rowUpdated( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool rowInserted( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool rowDeleted( );
+ // css::sdbcx::XRowLocate
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual css::uno::Any getBookmark() = 0;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool moveToBookmark( const css::uno::Any& bookmark ) = 0;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual sal_Int32 compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) = 0;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual bool hasOrderedBookmarks( ) = 0;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual sal_Int32 hashBookmark( const css::uno::Any& bookmark ) = 0;
+ // css::sdbc::XResultSetUpdate
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual void insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual void updateRow( const ORowSetRow& _rInsertRow,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& _xTable );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ virtual void deleteRow( const ORowSetRow& _rDeleteRow,const connectivity::OSQLTable& _xTable ) = 0;
+
+ virtual bool isResultSetChanged() const;
+ virtual void reset(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet) = 0;
+ virtual void mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,std::vector<sal_Int32>& o_aChangedColumns);
+ virtual bool columnValuesUpdated(ORowSetValueVector::Vector& o_aCachedRow,const ORowSetValueVector::Vector& i_aRow);
+ virtual bool updateColumnValues(const ORowSetValueVector::Vector& io_aCachedRow,ORowSetValueVector::Vector& io_aRow,const std::vector<sal_Int32>& i_aChangedColumns);
+ virtual void fillMissingValues(ORowSetValueVector::Vector& io_aRow) const;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/FilteredContainer.cxx b/dbaccess/source/core/api/FilteredContainer.cxx
new file mode 100644
index 000000000..a5cf0b156
--- /dev/null
+++ b/dbaccess/source/core/api/FilteredContainer.cxx
@@ -0,0 +1,459 @@
+/* -*- 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 <strings.hxx>
+#include <FilteredContainer.hxx>
+#include <RefreshListener.hxx>
+#include <sdbcoretools.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <tools/wldcrd.hxx>
+#include <tools/diagnose_ex.h>
+#include <optional>
+#include <sal/log.hxx>
+
+namespace dbaccess
+{
+ 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::sdb;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::container;
+ using namespace ::osl;
+ using namespace ::comphelper;
+ using namespace ::cppu;
+ using namespace ::connectivity::sdbcx;
+
+/** creates a vector of WildCards and reduce the _rTableFilter of the length of WildCards
+*/
+static sal_Int32 createWildCardVector(Sequence< OUString >& _rTableFilter, std::vector< WildCard >& _rOut)
+{
+ // for wildcard search : remove all table filters which are a wildcard expression and build a WildCard
+ // for them
+ OUString* pTableFilters = _rTableFilter.getArray();
+ OUString* pEnd = pTableFilters + _rTableFilter.getLength();
+ sal_Int32 nShiftPos = 0;
+ for (sal_Int32 i=0; pEnd != pTableFilters; ++pTableFilters,++i)
+ {
+ if (pTableFilters->indexOf('%') != -1)
+ {
+ _rOut.emplace_back(pTableFilters->replace('%', '*'));
+ }
+ else
+ {
+ if (nShiftPos != i)
+ {
+ _rTableFilter.getArray()[nShiftPos] = _rTableFilter.getArray()[i];
+ }
+ ++nShiftPos;
+ }
+ }
+ // now aTableFilter contains nShiftPos non-wc-strings and aWCSearch all wc-strings
+ _rTableFilter.realloc(nShiftPos);
+ return nShiftPos;
+}
+
+ static bool lcl_isElementAllowed( const OUString& _rName,
+ const Sequence< OUString >& _rTableFilter,
+ const std::vector< WildCard >& _rWCSearch )
+ {
+ sal_Int32 nTableFilterLen = _rTableFilter.getLength();
+
+ const OUString* tableFilter = _rTableFilter.getConstArray();
+ const OUString* tableFilterEnd = _rTableFilter.getConstArray() + nTableFilterLen;
+ bool bFilterMatch = std::find( tableFilter, tableFilterEnd, _rName ) != tableFilterEnd;
+ // the table is allowed to "pass" if we had no filters at all or any of the non-wildcard filters matches
+ if (!bFilterMatch && !_rWCSearch.empty())
+ { // or if one of the wildcard expression matches
+ for (auto const& elem : _rWCSearch)
+ {
+ bFilterMatch = elem.Matches( _rName );
+ if (bFilterMatch)
+ break;
+ }
+ }
+
+ return bFilterMatch;
+ }
+
+ typedef ::std::optional< OUString > OptionalString;
+
+ namespace {
+
+ struct TableInfo
+ {
+ OptionalString sComposedName;
+ OptionalString sType;
+ OptionalString sCatalog;
+ OptionalString sSchema;
+ OptionalString sName;
+
+ explicit TableInfo( const OUString& _composedName )
+ : sComposedName( _composedName )
+ {
+ }
+
+ TableInfo( const OUString& _catalog, const OUString& _schema, const OUString& _name,
+ const OUString& _type )
+ :sType( _type )
+ ,sCatalog( _catalog )
+ ,sSchema( _schema )
+ ,sName( _name )
+ {
+ }
+ };
+
+ }
+
+ typedef std::vector< TableInfo > TableInfos;
+
+ static void lcl_ensureComposedName( TableInfo& _io_tableInfo, const Reference< XDatabaseMetaData >& _metaData )
+ {
+ if ( !_metaData.is() )
+ throw RuntimeException("lcl_ensureComposedName: _metaData cannot be null!");
+
+ if ( !_io_tableInfo.sComposedName )
+ {
+ OSL_ENSURE( !!_io_tableInfo.sCatalog && !!_io_tableInfo.sSchema && !!_io_tableInfo.sName, "lcl_ensureComposedName: How should I composed the name from nothing!?" );
+
+ _io_tableInfo.sComposedName = OptionalString(
+ composeTableName( _metaData, *_io_tableInfo.sCatalog, *_io_tableInfo.sSchema, *_io_tableInfo.sName,
+ false, ::dbtools::EComposeRule::InDataManipulation )
+ );
+ }
+ }
+
+ static void lcl_ensureType( TableInfo& _io_tableInfo, const Reference< XDatabaseMetaData >& _metaData, const Reference< XNameAccess >& _masterContainer )
+ {
+ if ( !!_io_tableInfo.sType )
+ return;
+
+ lcl_ensureComposedName( _io_tableInfo, _metaData );
+
+ if ( !_masterContainer.is() )
+ throw RuntimeException("lcl_ensureType: _masterContainer cannot be null!");
+
+ OUString sTypeName;
+ try
+ {
+ Reference< XPropertySet > xTable( _masterContainer->getByName( *_io_tableInfo.sComposedName ), UNO_QUERY_THROW );
+ OSL_VERIFY( xTable->getPropertyValue( PROPERTY_TYPE ) >>= sTypeName );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ _io_tableInfo.sType = OptionalString( sTypeName );
+ }
+
+ static ::std::vector< OUString> lcl_filter( TableInfos&& _unfilteredTables,
+ const Sequence< OUString >& _tableFilter, const Sequence< OUString >& _tableTypeFilter,
+ const Reference< XDatabaseMetaData >& _metaData, const Reference< XNameAccess >& _masterContainer )
+ {
+ TableInfos aFilteredTables;
+
+ // first, filter for the table names
+ sal_Int32 nTableFilterCount = _tableFilter.getLength();
+ bool dontFilterTableNames = ( ( nTableFilterCount == 1 ) && _tableFilter[0] == "%" );
+ if( dontFilterTableNames )
+ {
+ aFilteredTables = std::move(_unfilteredTables);
+ }
+ else
+ {
+ // for wildcard search : remove all table filters which are a wildcard expression and build a WildCard
+ // for them
+ std::vector< WildCard > aWildCardTableFilter;
+ Sequence< OUString > aNonWildCardTableFilter = _tableFilter;
+ nTableFilterCount = createWildCardVector( aNonWildCardTableFilter, aWildCardTableFilter );
+
+ TableInfos aUnfilteredTables( std::move(_unfilteredTables) );
+ aUnfilteredTables.reserve( nTableFilterCount + ( aWildCardTableFilter.size() * 10 ) );
+
+ for (auto & unfilteredTable : aUnfilteredTables)
+ {
+ lcl_ensureComposedName(unfilteredTable, _metaData);
+
+ if ( lcl_isElementAllowed( *unfilteredTable.sComposedName, aNonWildCardTableFilter, aWildCardTableFilter ) )
+ aFilteredTables.push_back(unfilteredTable);
+ }
+ }
+
+ // second, filter for the table types
+ sal_Int32 nTableTypeFilterCount = _tableTypeFilter.getLength();
+ bool dontFilterTableTypes = ( ( nTableTypeFilterCount == 1 ) && _tableTypeFilter[0] == "%" );
+ dontFilterTableTypes = dontFilterTableTypes || ( nTableTypeFilterCount == 0 );
+ // (for TableTypeFilter, unlike TableFilter, "empty" means "do not filter at all")
+ if ( !dontFilterTableTypes )
+ {
+ TableInfos aUnfilteredTables;
+ aUnfilteredTables.swap( aFilteredTables );
+
+ const OUString* pTableTypeFilterBegin = _tableTypeFilter.getConstArray();
+ const OUString* pTableTypeFilterEnd = pTableTypeFilterBegin + _tableTypeFilter.getLength();
+
+ for (auto & unfilteredTable : aUnfilteredTables)
+ {
+ // ensure that we know the table type
+ lcl_ensureType( unfilteredTable, _metaData, _masterContainer );
+
+ if ( std::find( pTableTypeFilterBegin, pTableTypeFilterEnd, *unfilteredTable.sType ) != pTableTypeFilterEnd )
+ aFilteredTables.push_back(unfilteredTable);
+ }
+ }
+
+ ::std::vector< OUString> aReturn;
+ for (auto & filteredTable : aFilteredTables)
+ {
+ lcl_ensureComposedName(filteredTable, _metaData);
+ aReturn.push_back(*filteredTable.sComposedName);
+ }
+ return aReturn;
+ }
+
+ // OViewContainer
+ OFilteredContainer::OFilteredContainer(::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const Reference< XConnection >& _xCon,
+ bool _bCase,
+ IRefreshListener* _pRefreshListener,
+ std::atomic<std::size_t>& _nInAppend)
+ :OCollection(_rParent,_bCase,_rMutex,std::vector< OUString>())
+ ,m_bConstructed(false)
+ ,m_pRefreshListener(_pRefreshListener)
+ ,m_nInAppend(_nInAppend)
+ ,m_xConnection(_xCon)
+ {
+ }
+
+ void OFilteredContainer::construct(const Reference< XNameAccess >& _rxMasterContainer,
+ const Sequence< OUString >& _rTableFilter,
+ const Sequence< OUString >& _rTableTypeFilter)
+ {
+ try
+ {
+ Reference<XConnection> xCon = m_xConnection;
+ if ( xCon.is() )
+ m_xMetaData = xCon->getMetaData();
+ }
+ catch(SQLException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ m_xMasterContainer = _rxMasterContainer;
+
+ if ( m_xMasterContainer.is() )
+ {
+ addMasterContainerListener();
+
+ TableInfos aUnfilteredTables;
+
+ Sequence< OUString > aNames = m_xMasterContainer->getElementNames();
+ const OUString* name = aNames.getConstArray();
+ const OUString* nameEnd = name + aNames.getLength();
+ for ( ; name != nameEnd; ++name )
+ aUnfilteredTables.emplace_back( *name );
+
+ reFill( lcl_filter( std::move(aUnfilteredTables),
+ _rTableFilter, _rTableTypeFilter, m_xMetaData, m_xMasterContainer ) );
+
+ m_bConstructed = true;
+ }
+ else
+ {
+ construct( _rTableFilter, _rTableTypeFilter );
+ }
+ }
+
+ void OFilteredContainer::construct(const Sequence< OUString >& _rTableFilter, const Sequence< OUString >& _rTableTypeFilter)
+ {
+ // build sorted versions of the filter sequences, so the visibility decision is faster
+ Sequence< OUString > aTableFilter(_rTableFilter);
+
+ // for wildcard search : remove all table filters which are a wildcard expression and build a WildCard
+ // for them
+ std::vector< WildCard > aWCSearch;
+ createWildCardVector(aTableFilter,aWCSearch);
+
+ try
+ {
+ Reference< XConnection > xCon( m_xConnection, UNO_SET_THROW );
+ m_xMetaData.set( xCon->getMetaData(), UNO_SET_THROW );
+
+ // create a table filter suitable for the XDatabaseMetaData::getTables call,
+ // taking into account both the externally-provided table type filter, and any
+ // table type restriction which is inherent to the container
+ Sequence< OUString > aTableTypeFilter;
+ OUString sInherentTableTypeRestriction( getTableTypeRestriction() );
+ if ( !sInherentTableTypeRestriction.isEmpty() )
+ {
+ if ( _rTableTypeFilter.hasElements() )
+ {
+ const OUString* tableType = _rTableTypeFilter.getConstArray();
+ const OUString* tableTypeEnd = tableType + _rTableTypeFilter.getLength();
+ for ( ; tableType != tableTypeEnd; ++tableType )
+ {
+ if ( *tableType == sInherentTableTypeRestriction )
+ break;
+ }
+ if ( tableType == tableTypeEnd )
+ { // the only table type which can be part of this container is not allowed
+ // by the externally provided table type filter.
+ m_bConstructed = true;
+ return;
+ }
+ }
+ aTableTypeFilter = { sInherentTableTypeRestriction };
+ }
+ else
+ {
+ // no container-inherent restriction for the table types
+ if ( !_rTableTypeFilter.hasElements() )
+ { // no externally-provided table type filter => use the default filter
+ getAllTableTypeFilter( aTableTypeFilter );
+ }
+ else
+ {
+ aTableTypeFilter = _rTableTypeFilter;
+ }
+ }
+
+ static constexpr OUStringLiteral sAll = u"%";
+ Reference< XResultSet > xTables = m_xMetaData->getTables( Any(), sAll, sAll, aTableTypeFilter );
+ Reference< XRow > xCurrentRow( xTables, UNO_QUERY_THROW );
+
+ TableInfos aUnfilteredTables;
+
+ OUString sCatalog, sSchema, sName, sType;
+ while ( xTables->next() )
+ {
+ sCatalog = xCurrentRow->getString(1);
+ sSchema = xCurrentRow->getString(2);
+ sName = xCurrentRow->getString(3);
+ sType = xCurrentRow->getString(4);
+
+ aUnfilteredTables.emplace_back( sCatalog, sSchema, sName, sType );
+ }
+
+ reFill( lcl_filter( std::move(aUnfilteredTables),
+ _rTableFilter, aTableTypeFilter, m_xMetaData, nullptr ) );
+
+ disposeComponent( xTables );
+ }
+ catch (const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ disposing();
+ return;
+ }
+
+ m_bConstructed = true;
+ }
+
+ void OFilteredContainer::disposing()
+ {
+ OCollection::disposing();
+
+ if ( m_xMasterContainer.is() )
+ removeMasterContainerListener();
+
+ m_xMasterContainer = nullptr;
+ m_xMetaData = nullptr;
+ m_pRefreshListener = nullptr;
+ m_bConstructed = false;
+ }
+
+ void OFilteredContainer::impl_refresh()
+ {
+ if ( m_pRefreshListener )
+ {
+ m_bConstructed = false;
+ Reference<XRefreshable> xRefresh(m_xMasterContainer,UNO_QUERY);
+ if ( xRefresh.is() )
+ xRefresh->refresh();
+ m_pRefreshListener->refresh(this);
+ }
+ }
+
+ OUString OFilteredContainer::getNameForObject(const ObjectType& _xObject)
+ {
+ OSL_ENSURE( _xObject.is(), "OFilteredContainer::getNameForObject: Object is NULL!" );
+ return ::dbtools::composeTableName( m_xMetaData, _xObject, ::dbtools::EComposeRule::InDataManipulation, false );
+ }
+
+ // multiple to obtain all tables from XDatabaseMetaData::getTables, via passing a particular
+ // table type filter:
+ // adhere to the standard, which requests to pass a NULL table type filter, if
+ // you want to retrieve all tables
+ #define FILTER_MODE_STANDARD 0
+ // only pass %, which is not allowed by the standard, but understood by some drivers
+ #define FILTER_MODE_WILDCARD 1
+ // only pass TABLE and VIEW
+ #define FILTER_MODE_FIXED 2
+ // do the thing which showed to be the safest way, understood by nearly all
+ // drivers, even the ones which do not understand the standard
+ #define FILTER_MODE_MIX_ALL 3
+
+ void OFilteredContainer::getAllTableTypeFilter( Sequence< OUString >& /* [out] */ _rFilter ) const
+ {
+ sal_Int32 nFilterMode = FILTER_MODE_MIX_ALL;
+ // for compatibility reasons, this is the default: we used this way before we
+ // introduced the TableTypeFilterMode setting
+
+ // obtain the data source we belong to, and the TableTypeFilterMode setting
+ Any aFilterModeSetting;
+ if ( getDataSourceSetting( getDataSource( Reference< XInterface >(m_rParent) ), "TableTypeFilterMode", aFilterModeSetting ) )
+ {
+ OSL_VERIFY( aFilterModeSetting >>= nFilterMode );
+ }
+
+ static const OUStringLiteral sAll( u"%" );
+ static const OUStringLiteral sView( u"VIEW" );
+ static const OUStringLiteral sTable( u"TABLE" );
+
+ switch ( nFilterMode )
+ {
+ default:
+ SAL_WARN("dbaccess", "OTableContainer::getAllTableTypeFilter: unknown TableTypeFilterMode!" );
+ [[fallthrough]];
+ case FILTER_MODE_MIX_ALL:
+ _rFilter = { sView, sTable, sAll };
+ break;
+ case FILTER_MODE_FIXED:
+ _rFilter = { sView, sTable };
+ break;
+ case FILTER_MODE_WILDCARD:
+ _rFilter = { sAll };
+ break;
+ case FILTER_MODE_STANDARD:
+ _rFilter.realloc( 0 );
+ break;
+ }
+ }
+
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/HelperCollections.cxx b/dbaccess/source/core/api/HelperCollections.cxx
new file mode 100644
index 000000000..dfc18badc
--- /dev/null
+++ b/dbaccess/source/core/api/HelperCollections.cxx
@@ -0,0 +1,106 @@
+/* -*- 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 "HelperCollections.hxx"
+
+#include <strings.hxx>
+
+#include <osl/diagnose.h>
+
+namespace dbaccess
+{
+ using namespace dbtools;
+ using namespace comphelper;
+ using namespace connectivity;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::script;
+ using namespace ::cppu;
+ using namespace ::osl;
+
+ OPrivateColumns::OPrivateColumns(const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns,
+ bool _bCase,
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const std::vector< OUString> &_rVector,
+ bool _bUseAsIndex
+ ) : sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector,_bUseAsIndex)
+ ,m_aColumns(_rColumns)
+ {
+ }
+
+ std::unique_ptr<OPrivateColumns> OPrivateColumns::createWithIntrinsicNames( const ::rtl::Reference< ::connectivity::OSQLColumns >& _rColumns,
+ bool _bCase, ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex )
+ {
+ std::vector< OUString > aNames; aNames.reserve( _rColumns->size() );
+
+ OUString sColumName;
+ for (auto const& column : *_rColumns)
+ {
+ Reference< XPropertySet > xColumn(column, UNO_SET_THROW);
+ xColumn->getPropertyValue( PROPERTY_NAME ) >>= sColumName;
+ aNames.push_back( sColumName );
+ }
+ return std::unique_ptr<OPrivateColumns>(new OPrivateColumns( _rColumns, _bCase, _rParent, _rMutex, aNames, false ));
+ }
+
+ void OPrivateColumns::disposing()
+ {
+ m_aColumns = nullptr;
+ clear_NoDispose();
+ // we're not owner of the objects we're holding, instead the object we got in our ctor is
+ // So we're not allowed to dispose our elements.
+ OPrivateColumns_Base::disposing();
+ }
+
+ connectivity::sdbcx::ObjectType OPrivateColumns::createObject(const OUString& _rName)
+ {
+ if ( m_aColumns.is() )
+ {
+ ::connectivity::OSQLColumns::Vector::const_iterator aIter = find(m_aColumns->begin(),m_aColumns->end(),_rName,isCaseSensitive());
+ if(aIter == m_aColumns->end())
+ aIter = findRealName(m_aColumns->begin(),m_aColumns->end(),_rName,isCaseSensitive());
+
+ if(aIter != m_aColumns->end())
+ return connectivity::sdbcx::ObjectType(*aIter,UNO_QUERY);
+
+ OSL_FAIL("Column not found in collection!");
+ }
+ return nullptr;
+ }
+
+ connectivity::sdbcx::ObjectType OPrivateTables::createObject(const OUString& _rName)
+ {
+ if ( !m_aTables.empty() )
+ {
+ OSQLTables::iterator aIter = m_aTables.find(_rName);
+ OSL_ENSURE(aIter != m_aTables.end(),"Table not found!");
+ OSL_ENSURE(aIter->second.is(),"Table is null!");
+ return connectivity::sdbcx::ObjectType(m_aTables.find(_rName)->second,UNO_QUERY);
+ }
+ return nullptr;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/HelperCollections.hxx b/dbaccess/source/core/api/HelperCollections.hxx
new file mode 100644
index 000000000..ed89fc643
--- /dev/null
+++ b/dbaccess/source/core/api/HelperCollections.hxx
@@ -0,0 +1,106 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <connectivity/sdbcx/VCollection.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <rtl/ref.hxx>
+
+namespace dbaccess
+{
+ using namespace dbtools;
+ using namespace comphelper;
+ using namespace connectivity;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::script;
+ using namespace ::cppu;
+ using namespace ::osl;
+
+ typedef connectivity::sdbcx::OCollection OPrivateColumns_Base;
+ class OPrivateColumns : public OPrivateColumns_Base
+ {
+ ::rtl::Reference< ::connectivity::OSQLColumns> m_aColumns;
+ protected:
+ virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override {}
+ virtual Reference< XPropertySet > createDescriptor() override
+ {
+ return nullptr;
+ }
+ public:
+ OPrivateColumns(const ::rtl::Reference< ::connectivity::OSQLColumns>& _rColumns,
+ bool _bCase,
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const std::vector< OUString> &_rVector,
+ bool _bUseAsIndex = false
+ );
+
+ /** creates a columns instance as above, but taking the names from the columns itself
+ */
+ static std::unique_ptr<OPrivateColumns> createWithIntrinsicNames(
+ const ::rtl::Reference< ::connectivity::OSQLColumns >& _rColumns,
+ bool _bCase,
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex
+ );
+
+ virtual void disposing() override;
+ };
+ typedef connectivity::sdbcx::OCollection OPrivateTables_BASE;
+
+ // OPrivateTables
+ class OPrivateTables : public OPrivateTables_BASE
+ {
+ OSQLTables m_aTables;
+ protected:
+ virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual void impl_refresh() override {}
+ virtual Reference< XPropertySet > createDescriptor() override
+ {
+ return nullptr;
+ }
+ public:
+ OPrivateTables( const OSQLTables& _rTables,
+ bool _bCase,
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ std::vector< OUString> && _rVector
+ ) : sdbcx::OCollection(_rParent,_bCase,_rMutex,_rVector)
+ ,m_aTables(std::move(_rTables))
+ {
+ }
+ virtual void disposing() override
+ {
+ clear_NoDispose();
+ // we're not owner of the objects we're holding, instead the object we got in our ctor is
+ // So we're not allowed to dispose our elements.
+ m_aTables.clear();
+ OPrivateTables_BASE::disposing();
+ }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/KeySet.cxx b/dbaccess/source/core/api/KeySet.cxx
new file mode 100644
index 000000000..338d4d7f8
--- /dev/null
+++ b/dbaccess/source/core/api/KeySet.cxx
@@ -0,0 +1,1463 @@
+/* -*- 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 <memory>
+#include <string_view>
+
+#include "KeySet.hxx"
+#include <sal/log.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <algorithm>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <composertools.hxx>
+#include "PrivateRow.hxx"
+
+using namespace dbaccess;
+using namespace ::connectivity;
+using namespace ::dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star;
+using namespace ::cppu;
+using namespace ::osl;
+using std::vector;
+
+namespace
+{
+ void lcl_fillIndexColumns(const Reference<XIndexAccess>& _xIndexes, std::vector< Reference<XNameAccess> >& _rAllIndexColumns)
+ {
+ if ( !_xIndexes.is() )
+ return;
+
+ Reference<XPropertySet> xIndexColsSup;
+ sal_Int32 nCount = _xIndexes->getCount();
+ for(sal_Int32 j = 0 ; j < nCount ; ++j)
+ {
+ xIndexColsSup.set(_xIndexes->getByIndex(j),UNO_QUERY);
+ if( xIndexColsSup.is()
+ && comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISUNIQUE))
+ && !comphelper::getBOOL(xIndexColsSup->getPropertyValue(PROPERTY_ISPRIMARYKEYINDEX))
+ )
+ _rAllIndexColumns.push_back(Reference<XColumnsSupplier>(xIndexColsSup,UNO_QUERY_THROW)->getColumns());
+ }
+ }
+
+ template < typename T > void tryDispose( Reference<T> &r )
+ {
+ try
+ {
+ ::comphelper::disposeComponent(r);
+ }
+ catch(const Exception&)
+ {
+ r = nullptr;
+ }
+ catch(...)
+ {
+ SAL_WARN("dbaccess", "Unknown Exception occurred");
+ }
+ }
+}
+
+
+OKeySet::OKeySet(const connectivity::OSQLTable& _xTable,
+ const OUString& _rUpdateTableName, // this can be the alias or the full qualified name
+ const Reference< XSingleSelectQueryAnalyzer >& _xComposer,
+ const ORowSetValueVector& _aParameterValueForCache,
+ sal_Int32 i_nMaxRows,
+ sal_Int32& o_nRowCount)
+ :OCacheSet(i_nMaxRows)
+ ,m_aParameterValueForCache(new ORowSetValueVector(_aParameterValueForCache))
+ ,m_xTable(_xTable)
+ ,m_xComposer(_xComposer)
+ ,m_sUpdateTableName(_rUpdateTableName)
+ ,m_rRowCount(o_nRowCount)
+ ,m_bRowCountFinal(false)
+{
+}
+
+OKeySet::~OKeySet()
+{
+ tryDispose(m_xSet);
+ // m_xStatement is necessarily one of those
+ for (auto & statement : m_vStatements)
+ {
+ tryDispose(statement.second);
+ }
+
+ m_xComposer = nullptr;
+
+}
+
+void OKeySet::initColumns()
+{
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ bool bCase = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers();
+ m_pKeyColumnNames.reset( new SelectColumnsMetaData(bCase) );
+ m_pColumnNames.reset( new SelectColumnsMetaData(bCase) );
+ m_pParameterNames.reset( new SelectColumnsMetaData(bCase) );
+ m_pForeignColumnNames.reset( new SelectColumnsMetaData(bCase) );
+}
+
+void OKeySet::findTableColumnsMatching_throw( const Any& i_aTable,
+ const OUString& i_rUpdateTableName,
+ const Reference<XDatabaseMetaData>& i_xMeta,
+ const Reference<XNameAccess>& i_xQueryColumns,
+ std::unique_ptr<SelectColumnsMetaData> const & o_pKeyColumnNames)
+{
+ // first ask the database itself for the best columns which can be used
+ Sequence< OUString> aBestColumnNames;
+ Reference<XNameAccess> xKeyColumns = getPrimaryKeyColumns_throw(i_aTable);
+ if ( xKeyColumns.is() )
+ aBestColumnNames = xKeyColumns->getElementNames();
+
+ const Reference<XColumnsSupplier> xTblColSup(i_aTable,UNO_QUERY_THROW);
+ const Reference<XNameAccess> xTblColumns = xTblColSup->getColumns();
+ // locate parameter in select columns
+ Reference<XParametersSupplier> xParaSup(m_xComposer,UNO_QUERY);
+ Reference<XIndexAccess> xQueryParameters = xParaSup->getParameters();
+ const sal_Int32 nParaCount = xQueryParameters->getCount();
+ Sequence< OUString> aParameterColumns(nParaCount);
+ auto aParameterColumnsRange = asNonConstRange(aParameterColumns);
+ for(sal_Int32 i = 0; i< nParaCount;++i)
+ {
+ Reference<XPropertySet> xPara(xQueryParameters->getByIndex(i),UNO_QUERY_THROW);
+ xPara->getPropertyValue(PROPERTY_REALNAME) >>= aParameterColumnsRange[i];
+ }
+
+ OUString sUpdateTableName( i_rUpdateTableName );
+ if ( sUpdateTableName.isEmpty() )
+ {
+ SAL_WARN("dbaccess", "OKeySet::findTableColumnsMatching_throw: This is a fallback only - it won't work when the table has an alias name." );
+ // If i_aTable originates from a query composer, and is a table which appears with an alias in the SELECT statement,
+ // then the below code will not produce correct results.
+ // For instance, imagine a "SELECT alias.col FROM table AS alias". Now i_aTable would be the table named
+ // "table", so our sUpdateTableName would be "table" as well - not the information about the "alias" is
+ // already lost here.
+ // now getColumnPositions would traverse the columns, and check which of them belong to the table denoted
+ // by sUpdateTableName. Since the latter is "table", but the columns only know that they belong to a table
+ // named "alias", there will be no matching - so getColumnPositions wouldn't find anything.
+
+ OUString sCatalog, sSchema, sTable;
+ Reference<XPropertySet> xTableProp( i_aTable, UNO_QUERY_THROW );
+ xTableProp->getPropertyValue( PROPERTY_CATALOGNAME )>>= sCatalog;
+ xTableProp->getPropertyValue( PROPERTY_SCHEMANAME ) >>= sSchema;
+ xTableProp->getPropertyValue( PROPERTY_NAME ) >>= sTable;
+ sUpdateTableName = dbtools::composeTableName( i_xMeta, sCatalog, sSchema, sTable, false, ::dbtools::EComposeRule::InDataManipulation );
+ }
+
+ ::dbaccess::getColumnPositions(i_xQueryColumns,aBestColumnNames,sUpdateTableName,(*o_pKeyColumnNames),true);
+ ::dbaccess::getColumnPositions(i_xQueryColumns,xTblColumns->getElementNames(),sUpdateTableName,(*m_pColumnNames),true);
+ ::dbaccess::getColumnPositions(i_xQueryColumns,aParameterColumns,sUpdateTableName,(*m_pParameterNames),true);
+
+ if ( o_pKeyColumnNames->empty() )
+ {
+ ::dbtools::throwGenericSQLException("Could not find any key column.", *this );
+ }
+
+ for (auto const& keyColumn : *o_pKeyColumnNames)
+ {
+ if ( !xTblColumns->hasByName( keyColumn.second.sRealName ) )
+ continue;
+
+ Reference<XPropertySet> xProp( xTblColumns->getByName( keyColumn.second.sRealName ), UNO_QUERY );
+ bool bAuto = false;
+ if ( ( xProp->getPropertyValue( PROPERTY_ISAUTOINCREMENT ) >>= bAuto ) && bAuto )
+ m_aAutoColumns.push_back( keyColumn.first );
+ }
+}
+
+namespace
+{
+ void appendOneKeyColumnClause( std::u16string_view tblName, const OUString &colName, const connectivity::ORowSetValue &_rValue, OUStringBuffer &o_buf )
+ {
+ OUString fullName;
+ if (tblName.empty())
+ fullName = colName;
+ else
+ fullName = OUString::Concat(tblName) + "." + colName;
+ if ( _rValue.isNull() )
+ {
+ o_buf.append(fullName + " IS NULL ");
+ }
+ else
+ {
+ o_buf.append(fullName + " = ? ");
+ }
+ }
+}
+
+void OKeySet::setOneKeyColumnParameter( sal_Int32 &nPos, const Reference< XParameters > &_xParameter, const connectivity::ORowSetValue &_rValue, sal_Int32 _nType, sal_Int32 _nScale )
+{
+ if ( _rValue.isNull() )
+ {
+ // Nothing to do, appendOneKeyColumnClause took care of it,
+ // the "IS NULL" is hardcoded in the query
+ }
+ else
+ {
+ setParameter( nPos++, _xParameter, _rValue, _nType, _nScale );
+ }
+}
+
+OUStringBuffer OKeySet::createKeyFilter()
+{
+ connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aIter = m_aKeyIter->second.first->begin();
+
+ static const char aAnd[] = " AND ";
+ const OUString aQuote = getIdentifierQuoteString();
+ OUStringBuffer aFilter;
+ // create the where clause
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ {
+ if ( ! aFilter.isEmpty() )
+ aFilter.append(aAnd);
+ appendOneKeyColumnClause(::dbtools::quoteTableName(xMeta, keyColumnName.second.sTableName, ::dbtools::EComposeRule::InDataManipulation),
+ ::dbtools::quoteName(aQuote, keyColumnName.second.sRealName),
+ *aIter++,
+ aFilter);
+ }
+ for (auto const& foreignColumnName : * m_pForeignColumnNames)
+ {
+ if ( ! aFilter.isEmpty() )
+ aFilter.append(aAnd);
+ appendOneKeyColumnClause(::dbtools::quoteTableName(xMeta, foreignColumnName.second.sTableName, ::dbtools::EComposeRule::InDataManipulation),
+ ::dbtools::quoteName(aQuote, foreignColumnName.second.sRealName),
+ *aIter++,
+ aFilter);
+ }
+ return aFilter;
+}
+
+void OKeySet::construct(const Reference< XResultSet>& _xDriverSet, const OUString& i_sRowSetFilter)
+{
+ OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
+
+ initColumns();
+
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ Reference<XColumnsSupplier> xQueryColSup(m_xComposer, UNO_QUERY);
+ const Reference<XNameAccess> xQueryColumns = xQueryColSup->getColumns();
+ findTableColumnsMatching_throw( Any(m_xTable), m_sUpdateTableName, xMeta, xQueryColumns, m_pKeyColumnNames );
+
+ Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
+ Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
+ Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
+ xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
+ Reference<XTablesSupplier> xTabSup(xAnalyzer,uno::UNO_QUERY);
+ Reference<XNameAccess> xSelectTables = xTabSup->getTables();
+ const Sequence< OUString> aSeq = xSelectTables->getElementNames();
+ if ( aSeq.getLength() > 1 ) // special handling for join
+ {
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* const pEnd = pIter + aSeq.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( *pIter != m_sUpdateTableName )
+ {
+ connectivity::OSQLTable xSelColSup(xSelectTables->getByName(*pIter),uno::UNO_QUERY);
+ Reference<XPropertySet> xProp(xSelColSup,uno::UNO_QUERY);
+ OUString sSelectTableName = ::dbtools::composeTableName( xMeta, xProp, ::dbtools::EComposeRule::InDataManipulation, false );
+
+ ::dbaccess::getColumnPositions(xQueryColumns, xSelColSup->getColumns()->getElementNames(), sSelectTableName, (*m_pForeignColumnNames), true);
+
+ // LEM: there used to be a break here; however, I see no reason to stop
+ // at first non-updateTable, so I removed it. (think of multiple joins...)
+ }
+ }
+ }
+
+ // the first row is empty because it's now easier for us to distinguish when we are beforefirst or first
+ // without extra variable to be set
+ OKeySetValue keySetValue(nullptr,std::pair<sal_Int32,Reference<XRow> >(0,Reference<XRow>()));
+ m_aKeyMap.emplace(0, keySetValue);
+ m_aKeyIter = m_aKeyMap.begin();
+}
+
+void OKeySet::reset(const Reference< XResultSet>& _xDriverSet)
+{
+ OCacheSet::construct(_xDriverSet, m_sRowSetFilter);
+ m_bRowCountFinal = false;
+ m_aKeyMap.clear();
+ OKeySetValue keySetValue(nullptr,std::pair<sal_Int32,Reference<XRow> >(0,Reference<XRow>()));
+ m_aKeyMap.emplace(0,keySetValue);
+ m_aKeyIter = m_aKeyMap.begin();
+}
+
+void OKeySet::ensureStatement( )
+{
+ // do we already have a statement for the current combination of NULLness
+ // of key & foreign columns?
+ std::vector<bool> FilterColumnsNULL;
+ FilterColumnsNULL.reserve(m_aKeyIter->second.first->size());
+ for (auto const& elem : *m_aKeyIter->second.first)
+ FilterColumnsNULL.push_back(elem.isNull());
+ vStatements_t::const_iterator pNewStatement(m_vStatements.find(FilterColumnsNULL));
+ if(pNewStatement == m_vStatements.end())
+ {
+ // no: make a new one
+ makeNewStatement();
+ std::pair< vStatements_t::const_iterator, bool > insert_result
+ (m_vStatements.emplace( FilterColumnsNULL, m_xStatement));
+ (void) insert_result; // WaE: unused variable
+ assert(insert_result.second);
+ }
+ else
+ // yes: use it
+ m_xStatement = pNewStatement->second;
+}
+
+void OKeySet::makeNewStatement()
+{
+ Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
+ Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
+ Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
+ xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
+
+ OUStringBuffer aFilter(createKeyFilter());
+ executeStatement(aFilter, xAnalyzer);
+}
+
+void OKeySet::executeStatement(OUStringBuffer& io_aFilter, Reference<XSingleSelectQueryComposer>& io_xAnalyzer)
+{
+ bool bFilterSet = !m_sRowSetFilter.isEmpty();
+ if ( bFilterSet )
+ {
+ FilterCreator aFilterCreator;
+ aFilterCreator.append( m_sRowSetFilter );
+ aFilterCreator.append( io_aFilter.makeStringAndClear() );
+ io_aFilter = aFilterCreator.getComposedAndClear();
+ }
+ io_xAnalyzer->setFilter(io_aFilter.makeStringAndClear());
+ if ( bFilterSet )
+ {
+ Sequence< Sequence< PropertyValue > > aFilter2 = io_xAnalyzer->getStructuredFilter();
+ const Sequence< PropertyValue >* pOr = aFilter2.getConstArray();
+ const Sequence< PropertyValue >* pOrEnd = pOr + aFilter2.getLength();
+ for(;pOr != pOrEnd;++pOr)
+ {
+ const PropertyValue* pAnd = pOr->getConstArray();
+ const PropertyValue* pAndEnd = pAnd + pOr->getLength();
+ for(;pAnd != pAndEnd;++pAnd)
+ {
+ OUString sValue;
+ if ( !(pAnd->Value >>= sValue) || !( sValue == "?" || sValue.startsWith( ":" ) ) )
+ { // we have a criteria which has to be taken into account for updates
+ m_aFilterColumns.push_back(pAnd->Name);
+ }
+ }
+ }
+ }
+ m_xStatement = m_xConnection->prepareStatement(io_xAnalyzer->getQueryWithSubstitution());
+ ::comphelper::disposeComponent(io_xAnalyzer);
+}
+
+void OKeySet::invalidateRow()
+{
+ m_xRow = nullptr;
+ ::comphelper::disposeComponent(m_xSet);
+}
+
+Any OKeySet::getBookmark()
+{
+ OSL_ENSURE(m_aKeyIter != m_aKeyMap.end() && m_aKeyIter != m_aKeyMap.begin(),
+ "getBookmark is only possible when we stand on a valid row!");
+ return Any(m_aKeyIter->first);
+}
+
+bool OKeySet::moveToBookmark( const Any& bookmark )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ m_aKeyIter = m_aKeyMap.find(::comphelper::getINT32(bookmark));
+ invalidateRow();
+ return m_aKeyIter != m_aKeyMap.end();
+}
+
+sal_Int32 OKeySet::compareBookmarks( const Any& _first, const Any& _second )
+{
+ sal_Int32 nFirst = 0, nSecond = 0;
+ _first >>= nFirst;
+ _second >>= nSecond;
+
+ return (nFirst != nSecond) ? CompareBookmark::NOT_EQUAL : CompareBookmark::EQUAL;
+}
+
+bool OKeySet::hasOrderedBookmarks( )
+{
+ return true;
+}
+
+sal_Int32 OKeySet::hashBookmark( const Any& bookmark )
+{
+ return ::comphelper::getINT32(bookmark);
+}
+
+
+void OKeySet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& _xTable )
+{
+ Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
+ fillTableName(xSet);
+
+ OUStringBuffer aSql = "UPDATE " + m_aComposedTableName + " SET ";
+ // list all columns that should be set
+ constexpr OUStringLiteral aPara(u" = ?,");
+ OUString aQuote = getIdentifierQuoteString();
+ constexpr OUStringLiteral aAnd(u" AND ");
+ OUString sIsNull(" IS NULL");
+ OUString sParam(" = ?");
+
+ // use keys and indexes for exact positioning
+ Reference<XIndexesSupplier> xIndexSup(_xTable,UNO_QUERY);
+ Reference<XIndexAccess> xIndexes;
+ if ( xIndexSup.is() )
+ xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY);
+
+ std::vector< Reference<XNameAccess> > aAllIndexColumns;
+ lcl_fillIndexColumns(xIndexes,aAllIndexColumns);
+
+ OUStringBuffer sKeyCondition,sIndexCondition;
+ std::vector<sal_Int32> aIndexColumnPositions;
+
+ const sal_Int32 nOldLength = aSql.getLength();
+ // here we build the condition part for the update statement
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if ( m_pKeyColumnNames->find(columnName.first) != m_pKeyColumnNames->end() )
+ {
+ sKeyCondition.append(::dbtools::quoteName( aQuote,columnName.second.sRealName));
+ if((*_rOriginalRow)[columnName.second.nPosition].isNull())
+ sKeyCondition.append(sIsNull);
+ else
+ sKeyCondition.append(sParam);
+ sKeyCondition.append(aAnd);
+ }
+ else
+ {
+ for (auto const& indexColumn : aAllIndexColumns)
+ {
+ if(indexColumn->hasByName(columnName.first))
+ {
+ sIndexCondition.append(::dbtools::quoteName( aQuote,columnName.second.sRealName));
+ if((*_rOriginalRow)[columnName.second.nPosition].isNull())
+ sIndexCondition.append(sIsNull);
+ else
+ {
+ sIndexCondition.append(sParam);
+ aIndexColumnPositions.push_back(columnName.second.nPosition);
+ }
+ sIndexCondition.append(aAnd);
+ break;
+ }
+ }
+ }
+ if((*_rInsertRow)[columnName.second.nPosition].isModified())
+ {
+ aSql.append(::dbtools::quoteName( aQuote,columnName.second.sRealName) + aPara);
+ }
+ }
+
+ if( aSql.getLength() != nOldLength )
+ {
+ aSql.setLength(aSql.getLength()-1);
+ }
+ else
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED ), StandardSQLState::GENERAL_ERROR, m_xConnection );
+
+ if(!sKeyCondition.isEmpty() || !sIndexCondition.isEmpty())
+ {
+ aSql.append(" WHERE ");
+ if(!sKeyCondition.isEmpty() && !sIndexCondition.isEmpty())
+ {
+ aSql.append(sKeyCondition + sIndexCondition);
+ }
+ else if(!sKeyCondition.isEmpty())
+ {
+ aSql.append(sKeyCondition);
+ }
+ else if(!sIndexCondition.isEmpty())
+ {
+ aSql.append(sIndexCondition);
+ }
+ aSql.setLength(aSql.getLength()-5); // remove the last AND
+ }
+ else
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_CONDITION_FOR_PK ), StandardSQLState::GENERAL_ERROR, m_xConnection );
+
+ // now create end execute the prepared statement
+ executeUpdate(_rInsertRow ,_rOriginalRow,aSql.makeStringAndClear(),u"",aIndexColumnPositions);
+}
+
+void OKeySet::executeUpdate(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const OUString& i_sSQL,std::u16string_view i_sTableName,const std::vector<sal_Int32>& _aIndexColumnPositions)
+{
+ // now create end execute the prepared statement
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+
+ bool bRefetch = true;
+ Reference<XRow> xRow;
+ sal_Int32 i = 1;
+ // first the set values
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if ( i_sTableName.empty() || columnName.second.sTableName == i_sTableName )
+ {
+ sal_Int32 nPos = columnName.second.nPosition;
+ if((*_rInsertRow)[nPos].isModified())
+ {
+ if ( bRefetch )
+ {
+ bRefetch = std::find(m_aFilterColumns.begin(),m_aFilterColumns.end(),columnName.second.sRealName) == m_aFilterColumns.end();
+ }
+ impl_convertValue_throw(_rInsertRow,columnName.second);
+ (*_rInsertRow)[nPos].setSigned((*_rOriginalRow)[nPos].isSigned());
+ setParameter(i++,xParameter,(*_rInsertRow)[nPos],columnName.second.nType,columnName.second.nScale);
+ }
+ }
+ }
+ // and then the values of the where condition
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ {
+ if ( i_sTableName.empty() || keyColumnName.second.sTableName == i_sTableName )
+ {
+ setParameter(i++,xParameter,(*_rOriginalRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale);
+ }
+ }
+ if ( !_aIndexColumnPositions.empty() )
+ {
+ // now we have to set the index values
+ auto aIter = m_pColumnNames->begin();
+ for (auto const& indexColumnPosition : _aIndexColumnPositions)
+ {
+ setParameter(i++,xParameter,(*_rOriginalRow)[indexColumnPosition],(*_rOriginalRow)[indexColumnPosition].getTypeKind(),aIter->second.nScale);
+ ++aIter;
+ }
+ }
+ const sal_Int32 nRowsUpdated = xPrep->executeUpdate();
+ m_bUpdated = nRowsUpdated > 0;
+ if(m_bUpdated)
+ {
+ const sal_Int32 nBookmark = ::comphelper::getINT32((*_rInsertRow)[0].getAny());
+ m_aKeyIter = m_aKeyMap.find(nBookmark);
+ m_aKeyIter->second.second.first = 2;
+ m_aKeyIter->second.second.second = xRow;
+ copyRowValue(_rInsertRow,m_aKeyIter->second.first,nBookmark);
+ tryRefetch(_rInsertRow,bRefetch);
+ }
+}
+
+void OKeySet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable )
+{
+ Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
+ fillTableName(xSet);
+
+ OUStringBuffer aSql( "INSERT INTO " + m_aComposedTableName + " ( ");
+
+ // set values and column names
+ OUStringBuffer aValues(" VALUES ( ");
+ OUString aQuote = getIdentifierQuoteString();
+
+ bool bRefetch = true;
+ bool bModified = false;
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if((*_rInsertRow)[columnName.second.nPosition].isModified())
+ {
+ if ( bRefetch )
+ {
+ bRefetch = std::find(m_aFilterColumns.begin(),m_aFilterColumns.end(),columnName.second.sRealName) == m_aFilterColumns.end();
+ }
+ aSql.append(::dbtools::quoteName( aQuote,columnName.second.sRealName) + ",");
+ aValues.append("?,");
+ bModified = true;
+ }
+ }
+ if ( !bModified )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED ), StandardSQLState::GENERAL_ERROR, m_xConnection );
+
+ aSql[aSql.getLength() - 1] = ')';
+ aValues[aValues.getLength() - 1] = ')';
+ aSql.append(aValues);
+ // now create,fill and execute the prepared statement
+ executeInsert(_rInsertRow,aSql.makeStringAndClear(),u"",bRefetch);
+}
+
+void OKeySet::executeInsert( const ORowSetRow& _rInsertRow,const OUString& i_sSQL,std::u16string_view i_sTableName,bool bRefetch )
+{
+ // now create,fill and execute the prepared statement
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+
+ sal_Int32 i = 1;
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if ( i_sTableName.empty() || columnName.second.sTableName == i_sTableName )
+ {
+ const sal_Int32 nPos = columnName.second.nPosition;
+ if((*_rInsertRow)[nPos].isModified())
+ {
+ if((*_rInsertRow)[nPos].isNull())
+ xParameter->setNull(i++,(*_rInsertRow)[nPos].getTypeKind());
+ else
+ {
+ impl_convertValue_throw(_rInsertRow,columnName.second);
+ (*_rInsertRow)[nPos].setSigned(m_aSignedFlags[nPos-1]);
+ setParameter(i++,xParameter,(*_rInsertRow)[nPos],columnName.second.nType,columnName.second.nScale);
+ }
+ }
+ }
+ }
+
+ m_bInserted = xPrep->executeUpdate() > 0;
+ bool bAutoValuesFetched = false;
+ if ( m_bInserted )
+ {
+ // first insert the default values into the insertrow
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if ( !(*_rInsertRow)[columnName.second.nPosition].isModified() )
+ {
+ if(columnName.second.bNullable && columnName.second.sDefaultValue.isEmpty())
+ {
+ (*_rInsertRow)[columnName.second.nPosition].setTypeKind(columnName.second.nType);
+ (*_rInsertRow)[columnName.second.nPosition].setNull();
+ }
+ else
+ {
+ (*_rInsertRow)[columnName.second.nPosition] = columnName.second.sDefaultValue;
+ (*_rInsertRow)[columnName.second.nPosition].setTypeKind(columnName.second.nType);
+ }
+ }
+ }
+ try
+ {
+ Reference< XGeneratedResultSet > xGRes(xPrep, UNO_QUERY);
+ if ( xGRes.is() )
+ {
+ Reference< XResultSet > xRes = xGRes->getGeneratedValues();
+ Reference< XRow > xRow(xRes,UNO_QUERY);
+ if ( xRow.is() && xRes->next() )
+ {
+ Reference< XResultSetMetaDataSupplier > xMdSup(xRes,UNO_QUERY);
+ Reference< XResultSetMetaData > xMd = xMdSup->getMetaData();
+ sal_Int32 nColumnCount = xMd->getColumnCount();
+ std::vector< OUString >::const_iterator aAutoIter = m_aAutoColumns.begin();
+ std::vector< OUString >::const_iterator aAutoEnd = m_aAutoColumns.end();
+ for (sal_Int32 j = 1;aAutoIter != aAutoEnd && j <= nColumnCount; ++aAutoIter,++j)
+ {
+ SelectColumnsMetaData::const_iterator aFind = m_pKeyColumnNames->find(*aAutoIter);
+ if ( aFind != m_pKeyColumnNames->end() )
+ (*_rInsertRow)[aFind->second.nPosition].fill(j, aFind->second.nType, xRow);
+ }
+ bAutoValuesFetched = true;
+ }
+ }
+ }
+ catch(const Exception&)
+ {
+ SAL_WARN("dbaccess", "Could not execute GeneratedKeys() stmt");
+ }
+ }
+
+ ::comphelper::disposeComponent(xPrep);
+
+ if ( i_sTableName.empty() && !bAutoValuesFetched && m_bInserted )
+ {
+ // first check if all key column values were set
+ const OUString sQuote = getIdentifierQuoteString();
+ OUStringBuffer sMaxStmt;
+ auto aEnd = m_pKeyColumnNames->end();
+ for (auto const& autoColumn : m_aAutoColumns)
+ {
+ // we will only fetch values which are keycolumns
+ SelectColumnsMetaData::const_iterator aFind = m_pKeyColumnNames->find(autoColumn);
+ if ( aFind != aEnd )
+ {
+ sMaxStmt.append(" MAX(" + ::dbtools::quoteName( sQuote,aFind->second.sRealName) + "),");
+ }
+ }
+
+ if(!sMaxStmt.isEmpty())
+ {
+ sMaxStmt[sMaxStmt.getLength()-1] = ' ';
+ OUString sStmt = "SELECT " + sMaxStmt + "FROM ";
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(m_xConnection->getMetaData(),m_sUpdateTableName,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+ sStmt += ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
+ try
+ {
+ // now fetch the autoincrement values
+ Reference<XStatement> xStatement = m_xConnection->createStatement();
+ Reference<XResultSet> xRes = xStatement->executeQuery(sStmt);
+ Reference<XRow> xRow(xRes,UNO_QUERY);
+ if(xRow.is() && xRes->next())
+ {
+ sal_Int32 j=1;
+ for (auto const& autoColumn : m_aAutoColumns)
+ {
+ // we will only fetch values which are keycolumns
+ SelectColumnsMetaData::const_iterator aFind = m_pKeyColumnNames->find(autoColumn);
+ if ( aFind != aEnd )
+ (*_rInsertRow)[aFind->second.nPosition].fill(j++, aFind->second.nType, xRow);
+ }
+ }
+ ::comphelper::disposeComponent(xStatement);
+ }
+ catch(SQLException&)
+ {
+ SAL_WARN("dbaccess", "Could not fetch with MAX() ");
+ }
+ }
+ }
+ if ( m_bInserted )
+ {
+ OKeySetMatrix::const_iterator aKeyIter = m_aKeyMap.end();
+ --aKeyIter;
+ ORowSetRow aKeyRow = new connectivity::ORowVector< ORowSetValue >(m_pKeyColumnNames->size());
+ copyRowValue(_rInsertRow,aKeyRow,aKeyIter->first + 1);
+
+ m_aKeyIter = m_aKeyMap.emplace( aKeyIter->first + 1, OKeySetValue(aKeyRow,std::pair<sal_Int32,Reference<XRow> >(1,Reference<XRow>())) ).first;
+ // now we set the bookmark for this row
+ (*_rInsertRow)[0] = Any(static_cast<sal_Int32>(m_aKeyIter->first));
+ tryRefetch(_rInsertRow,bRefetch);
+ }
+}
+
+void OKeySet::tryRefetch(const ORowSetRow& _rInsertRow,bool bRefetch)
+{
+ if ( bRefetch )
+ {
+ try
+ {
+ bRefetch = doTryRefetch_throw();
+ }
+ catch(const Exception&)
+ {
+ bRefetch = false;
+ }
+ }
+ if ( !bRefetch )
+ {
+ m_aKeyIter->second.second.second = new OPrivateRow(std::vector(*_rInsertRow));
+ }
+}
+
+void OKeySet::copyRowValue(const ORowSetRow& _rInsertRow, ORowSetRow const & _rKeyRow, sal_Int32 i_nBookmark)
+{
+ connectivity::ORowVector< ORowSetValue >::Vector::iterator aIter = _rKeyRow->begin();
+
+ // check the if the parameter values have been changed
+ OSL_ENSURE((m_aParameterValueForCache->size()-1) == m_pParameterNames->size(),"OKeySet::copyRowValue: Parameter values and names differ!");
+ connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aParaValuesIter = m_aParameterValueForCache->begin() +1;
+
+ bool bChanged = false;
+ sal_Int32 i = 1;
+ for (auto const& parameterName : *m_pParameterNames)
+ {
+ ORowSetValue aValue(*aParaValuesIter);
+ aValue.setSigned(m_aSignedFlags[parameterName.second.nPosition-1]);
+ if ( (*_rInsertRow)[parameterName.second.nPosition] != aValue )
+ {
+ rtl::Reference aCopy(
+ new ORowSetValueVector(*m_aParameterValueForCache));
+ (*aCopy)[i] = (*_rInsertRow)[parameterName.second.nPosition];
+ m_aUpdatedParameter[i_nBookmark] = aCopy;
+ bChanged = true;
+ }
+ ++aParaValuesIter;
+ ++i;
+ }
+ if ( !bChanged )
+ {
+ m_aUpdatedParameter.erase(i_nBookmark);
+ }
+
+ // update the key values
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ {
+ impl_convertValue_throw(_rInsertRow,keyColumnName.second);
+ *aIter = (*_rInsertRow)[keyColumnName.second.nPosition];
+ aIter->setTypeKind(keyColumnName.second.nType);
+ ++aIter;
+ }
+}
+
+void OKeySet::deleteRow(const ORowSetRow& _rDeleteRow,const connectivity::OSQLTable& _xTable )
+{
+ Reference<XPropertySet> xSet(_xTable,UNO_QUERY);
+ fillTableName(xSet);
+
+ OUStringBuffer aSql("DELETE FROM " + m_aComposedTableName + " WHERE ");
+
+ // list all columns that should be set
+ OUString aQuote = getIdentifierQuoteString();
+ static const char aAnd[] = " AND ";
+
+ // use keys and indexes for exact positioning
+ Reference<XIndexesSupplier> xIndexSup(_xTable,UNO_QUERY);
+ Reference<XIndexAccess> xIndexes;
+ if ( xIndexSup.is() )
+ xIndexes.set(xIndexSup->getIndexes(),UNO_QUERY);
+
+ // Reference<XColumnsSupplier>
+ std::vector< Reference<XNameAccess> > aAllIndexColumns;
+ lcl_fillIndexColumns(xIndexes,aAllIndexColumns);
+
+ OUStringBuffer sIndexCondition;
+ std::vector<sal_Int32> aIndexColumnPositions;
+
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if ( m_pKeyColumnNames->find(columnName.first) != m_pKeyColumnNames->end() )
+ {
+ aSql.append(::dbtools::quoteName( aQuote,columnName.second.sRealName));
+ if((*_rDeleteRow)[columnName.second.nPosition].isNull())
+ {
+ SAL_WARN("dbaccess", "can a primary key be null");
+ aSql.append(" IS NULL");
+ }
+ else
+ aSql.append(" = ?");
+ aSql.append(aAnd);
+ }
+ else
+ {
+ for (auto const& indexColumn : aAllIndexColumns)
+ {
+ if(indexColumn->hasByName(columnName.first))
+ {
+ sIndexCondition.append(::dbtools::quoteName( aQuote,columnName.second.sRealName));
+ if((*_rDeleteRow)[columnName.second.nPosition].isNull())
+ sIndexCondition.append(" IS NULL");
+ else
+ {
+ sIndexCondition.append(" = ?");
+ aIndexColumnPositions.push_back(columnName.second.nPosition);
+ }
+ sIndexCondition.append(aAnd);
+
+ break;
+ }
+ }
+ }
+ }
+ aSql.append(sIndexCondition);
+ aSql.setLength(aSql.getLength()-5);
+
+ // now create end execute the prepared statement
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(aSql.makeStringAndClear()));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+
+ sal_Int32 i = 1;
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ {
+ setParameter(i++,xParameter,(*_rDeleteRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale);
+ }
+
+ // now we have to set the index values
+ auto aIter = m_pColumnNames->begin();
+ for (auto const& indexColumnPosition : aIndexColumnPositions)
+ {
+ setParameter(i++,xParameter,(*_rDeleteRow)[indexColumnPosition],(*_rDeleteRow)[indexColumnPosition].getTypeKind(),aIter->second.nScale);
+ ++aIter;
+ }
+
+ m_bDeleted = xPrep->executeUpdate() > 0;
+
+ if(m_bDeleted)
+ {
+ sal_Int32 nBookmark = ::comphelper::getINT32((*_rDeleteRow)[0].getAny());
+ if(m_aKeyIter == m_aKeyMap.find(nBookmark) && m_aKeyIter != m_aKeyMap.end())
+ ++m_aKeyIter;
+ m_aKeyMap.erase(nBookmark);
+ m_bDeleted = true;
+ }
+}
+
+bool OKeySet::next()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+
+ if(isAfterLast())
+ return false;
+ ++m_aKeyIter;
+ if(!m_bRowCountFinal && m_aKeyIter == m_aKeyMap.end())
+ {
+ // not yet all records fetched, but we reached the end of those we fetched
+ // try to fetch one more row
+ if (fetchRow())
+ {
+ OSL_ENSURE(!isAfterLast(), "fetchRow succeeded, but isAfterLast()");
+ return true;
+ }
+ else
+ {
+ // nope, we arrived at end of data
+ m_aKeyIter = m_aKeyMap.end();
+ OSL_ENSURE(isAfterLast(), "fetchRow failed, but not end of data");
+ }
+ }
+
+ invalidateRow();
+ return !isAfterLast();
+}
+
+bool OKeySet::isBeforeFirst( )
+{
+ return m_aKeyIter == m_aKeyMap.begin();
+}
+
+bool OKeySet::isAfterLast( )
+{
+ return m_bRowCountFinal && m_aKeyIter == m_aKeyMap.end();
+}
+
+void OKeySet::beforeFirst( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ m_aKeyIter = m_aKeyMap.begin();
+ invalidateRow();
+}
+
+void OKeySet::afterLast( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ fillAllRows();
+ m_aKeyIter = m_aKeyMap.end();
+ invalidateRow();
+}
+
+bool OKeySet::first()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ m_aKeyIter = m_aKeyMap.begin();
+ ++m_aKeyIter;
+ if(m_aKeyIter == m_aKeyMap.end())
+ {
+ if (!fetchRow())
+ {
+ m_aKeyIter = m_aKeyMap.end();
+ return false;
+ }
+ }
+ else
+ invalidateRow();
+ return m_aKeyIter != m_aKeyMap.end() && m_aKeyIter != m_aKeyMap.begin();
+}
+
+bool OKeySet::last( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ bool bFetchedRow = fillAllRows();
+
+ m_aKeyIter = m_aKeyMap.end();
+ --m_aKeyIter;
+ if ( !bFetchedRow )
+ {
+ invalidateRow();
+ }
+ return m_aKeyIter != m_aKeyMap.end() && m_aKeyIter != m_aKeyMap.begin();
+}
+
+sal_Int32 OKeySet::getRow( )
+{
+ OSL_ENSURE(!isAfterLast(),"getRow is not allowed when afterlast record!");
+ OSL_ENSURE(!isBeforeFirst(),"getRow is not allowed when beforefirst record!");
+
+ return std::distance(m_aKeyMap.begin(),m_aKeyIter);
+}
+
+bool OKeySet::absolute( sal_Int32 row )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ OSL_ENSURE(row,"absolute(0) isn't allowed!");
+ bool bFetchedRow = false;
+ if(row < 0)
+ {
+ if(!m_bRowCountFinal)
+ bFetchedRow = fillAllRows();
+
+ row = std::min(std::abs(row), static_cast<sal_Int32>(std::distance(m_aKeyMap.begin(), m_aKeyIter)));
+ m_aKeyIter = std::prev(m_aKeyIter, row);
+ }
+ else
+ {
+ if(row >= static_cast<sal_Int32>(m_aKeyMap.size()))
+ {
+ // we don't have this row
+ if(!m_bRowCountFinal)
+ {
+ // but there may still be rows to fetch.
+ bool bNext = true;
+ for(sal_Int32 i=m_aKeyMap.size()-1;i < row && bNext;++i)
+ bNext = fetchRow();
+ // it is guaranteed that the above loop has executed at least once,
+ // that is fetchRow called at least once.
+ if ( bNext )
+ {
+ bFetchedRow = true;
+ }
+ else
+ {
+ // reached end of data before desired row
+ m_aKeyIter = m_aKeyMap.end();
+ return false;
+ }
+ }
+ else
+ {
+ // no more rows to fetch -> fail
+ m_aKeyIter = m_aKeyMap.end();
+ return false;
+ }
+ }
+ else
+ {
+ m_aKeyIter = std::next(m_aKeyMap.begin(), row);
+ }
+ }
+ if ( !bFetchedRow )
+ {
+ invalidateRow();
+ }
+
+ return m_aKeyIter != m_aKeyMap.end() && m_aKeyIter != m_aKeyMap.begin();
+}
+
+bool OKeySet::previous()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ if(m_aKeyIter != m_aKeyMap.begin())
+ {
+ --m_aKeyIter;
+ invalidateRow();
+ }
+ return m_aKeyIter != m_aKeyMap.begin();
+}
+
+bool OKeySet::doTryRefetch_throw()
+{
+ ensureStatement( );
+ // we just reassign the base members
+ Reference< XParameters > xParameter(m_xStatement,UNO_QUERY);
+ OSL_ENSURE(xParameter.is(),"No Parameter interface!");
+ xParameter->clearParameters();
+
+ sal_Int32 nPos=1;
+ connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aParaIter;
+ connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aParaEnd;
+ OUpdatedParameter::const_iterator aUpdateFind = m_aUpdatedParameter.find(m_aKeyIter->first);
+ if ( aUpdateFind == m_aUpdatedParameter.end() )
+ {
+ aParaIter = m_aParameterValueForCache->begin();
+ aParaEnd = m_aParameterValueForCache->end();
+ }
+ else
+ {
+ aParaIter = aUpdateFind->second->begin();
+ aParaEnd = aUpdateFind->second->end();
+ }
+
+ for(++aParaIter;aParaIter != aParaEnd;++aParaIter,++nPos)
+ {
+ ::dbtools::setObjectWithInfo( xParameter, nPos, aParaIter->makeAny(), aParaIter->getTypeKind() );
+ }
+
+ // now set the primary key column values
+ connectivity::ORowVector< ORowSetValue >::Vector::const_iterator aIter = m_aKeyIter->second.first->begin();
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ setOneKeyColumnParameter(nPos,xParameter,*aIter++,keyColumnName.second.nType,keyColumnName.second.nScale);
+ for (auto const& foreignColumnName : *m_pForeignColumnNames)
+ setOneKeyColumnParameter(nPos,xParameter,*aIter++,foreignColumnName.second.nType,foreignColumnName.second.nScale);
+
+ m_xSet = m_xStatement->executeQuery();
+ OSL_ENSURE(m_xSet.is(),"No resultset from statement!");
+ return m_xSet->next();
+}
+
+void OKeySet::refreshRow()
+{
+ invalidateRow();
+
+ if(isBeforeFirst() || isAfterLast())
+ return;
+
+ if ( m_aKeyIter->second.second.second.is() )
+ {
+ m_xRow = m_aKeyIter->second.second.second;
+ return;
+ }
+
+ bool bOK = doTryRefetch_throw();
+ if ( !bOK )
+ {
+ // This row has disappeared; remove it.
+ OKeySetMatrix::const_iterator aTemp = m_aKeyIter;
+ // use *next* row
+ ++m_aKeyIter;
+ m_aKeyMap.erase(aTemp);
+
+ // adjust RowCount for the row we have removed
+ if (m_rRowCount > 0)
+ --m_rRowCount;
+ else
+ SAL_WARN("dbaccess", "m_rRowCount got out of sync: non-empty m_aKeyMap, but m_rRowCount <= 0");
+
+ if (m_aKeyIter == m_aKeyMap.end())
+ {
+ ::comphelper::disposeComponent(m_xSet);
+ if (!isAfterLast())
+ {
+ // it was the last fetched row,
+ // but there may be another one to fetch
+ if (!fetchRow())
+ {
+ // nope, that really was the last
+ m_aKeyIter = m_aKeyMap.end();
+ OSL_ENSURE(isAfterLast(), "fetchRow() failed but not isAfterLast()!");
+ }
+ }
+ // Now, either fetchRow has set m_xRow or isAfterLast()
+ }
+ else
+ {
+ refreshRow();
+ }
+ }
+ else
+ {
+ m_xRow.set(m_xSet,UNO_QUERY);
+ OSL_ENSURE(m_xRow.is(),"No row from statement!");
+ }
+}
+
+bool OKeySet::fetchRow()
+{
+ // fetch the next row and append on the keyset
+ bool bRet = false;
+ if ( !m_bRowCountFinal && (!m_nMaxRows || sal_Int32(m_aKeyMap.size()) < m_nMaxRows) )
+ bRet = m_xDriverSet->next();
+ if ( bRet )
+ {
+ ORowSetRow aKeyRow = new connectivity::ORowVector< ORowSetValue >((*m_pKeyColumnNames).size() + m_pForeignColumnNames->size());
+
+ ::comphelper::disposeComponent(m_xSet);
+ m_xRow.set(m_xDriverRow, UNO_SET_THROW);
+
+ connectivity::ORowVector< ORowSetValue >::Vector::iterator aIter = aKeyRow->begin();
+ // copy key columns
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ {
+ const SelectColumnDescription& rColDesc = keyColumnName.second;
+ aIter->fill(rColDesc.nPosition, rColDesc.nType, m_xRow);
+ ++aIter;
+ }
+ // copy missing columns from other tables
+ for (auto const& foreignColumnName : *m_pForeignColumnNames)
+ {
+ const SelectColumnDescription& rColDesc = foreignColumnName.second;
+ aIter->fill(rColDesc.nPosition, rColDesc.nType, m_xRow);
+ ++aIter;
+ }
+ m_aKeyIter = m_aKeyMap.emplace( m_aKeyMap.rbegin()->first+1,OKeySetValue(aKeyRow,std::pair<sal_Int32,Reference<XRow> >(0,Reference<XRow>())) ).first;
+ }
+ else
+ m_bRowCountFinal = true;
+ return bRet;
+}
+
+bool OKeySet::fillAllRows()
+{
+ if(m_bRowCountFinal)
+ {
+ return false;
+ }
+ else
+ {
+ while(fetchRow())
+ ;
+ return true;
+ }
+}
+
+// XRow
+sal_Bool SAL_CALL OKeySet::wasNull( )
+{
+ if ( ! m_xRow.is() )
+ throwGenericSQLException("Must call getFOO() for some FOO before wasNull()", *this);
+
+ OSL_ENSURE(m_xRow.is(),"m_xRow is null! I've thrown, but function execution continued?");
+ return m_xRow->wasNull();
+}
+
+inline void OKeySet::ensureRowForData( )
+{
+ if (! m_xRow.is() )
+ refreshRow();
+ if (! m_xRow.is() )
+ throwSQLException("Failed to refetch row", "02000", *this, -2);
+
+ OSL_ENSURE(m_xRow.is(),"m_xRow is null! I've called throwSQLException but execution continued?");
+}
+
+OUString SAL_CALL OKeySet::getString( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getString(columnIndex);
+}
+
+sal_Bool SAL_CALL OKeySet::getBoolean( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getBoolean(columnIndex);
+}
+
+sal_Int8 SAL_CALL OKeySet::getByte( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getByte(columnIndex);
+}
+
+sal_Int16 SAL_CALL OKeySet::getShort( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getShort(columnIndex);
+}
+
+sal_Int32 SAL_CALL OKeySet::getInt( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getInt(columnIndex);
+}
+
+sal_Int64 SAL_CALL OKeySet::getLong( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getLong(columnIndex);
+}
+
+float SAL_CALL OKeySet::getFloat( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getFloat(columnIndex);
+}
+
+double SAL_CALL OKeySet::getDouble( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getDouble(columnIndex);
+}
+
+Sequence< sal_Int8 > SAL_CALL OKeySet::getBytes( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getBytes(columnIndex);
+}
+
+css::util::Date SAL_CALL OKeySet::getDate( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getDate(columnIndex);
+}
+
+css::util::Time SAL_CALL OKeySet::getTime( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getTime(columnIndex);
+}
+
+css::util::DateTime SAL_CALL OKeySet::getTimestamp( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getTimestamp(columnIndex);
+}
+
+Reference< css::io::XInputStream > SAL_CALL OKeySet::getBinaryStream( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getBinaryStream(columnIndex);
+}
+
+Reference< css::io::XInputStream > SAL_CALL OKeySet::getCharacterStream( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getCharacterStream(columnIndex);
+}
+
+Any SAL_CALL OKeySet::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& typeMap )
+{
+ ensureRowForData();
+ return m_xRow->getObject(columnIndex,typeMap);
+}
+
+Reference< XRef > SAL_CALL OKeySet::getRef( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getRef(columnIndex);
+}
+
+Reference< XBlob > SAL_CALL OKeySet::getBlob( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getBlob(columnIndex);
+}
+
+Reference< XClob > SAL_CALL OKeySet::getClob( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getClob(columnIndex);
+}
+
+Reference< XArray > SAL_CALL OKeySet::getArray( sal_Int32 columnIndex )
+{
+ ensureRowForData();
+ return m_xRow->getArray(columnIndex);
+}
+
+bool OKeySet::rowUpdated( )
+{
+ return m_aKeyIter != m_aKeyMap.begin() && m_aKeyIter != m_aKeyMap.end() && m_aKeyIter->second.second.first == 2;
+}
+
+bool OKeySet::rowInserted( )
+{
+ return m_aKeyIter != m_aKeyMap.begin() && m_aKeyIter != m_aKeyMap.end() && m_aKeyIter->second.second.first == 1;
+}
+
+bool OKeySet::rowDeleted( )
+{
+ bool bDeleted = m_bDeleted;
+ m_bDeleted = false;
+ return bDeleted;
+}
+
+namespace dbaccess
+{
+
+void getColumnPositions(const Reference<XNameAccess>& _rxQueryColumns,
+ const css::uno::Sequence< OUString >& _aColumnNames,
+ std::u16string_view _rsUpdateTableName,
+ SelectColumnsMetaData& o_rColumnNames,
+ bool i_bAppendTableName)
+ {
+ // get the real name of the columns
+ Sequence< OUString> aSelNames(_rxQueryColumns->getElementNames());
+ const OUString* pSelIter = aSelNames.getConstArray();
+ const OUString* pSelEnd = pSelIter + aSelNames.getLength();
+
+ const OUString* pTblColumnIter = _aColumnNames.getConstArray();
+ const OUString* pTblColumnEnd = pTblColumnIter + _aColumnNames.getLength();
+
+ ::comphelper::UStringMixEqual bCase(o_rColumnNames.key_comp().isCaseSensitive());
+
+ for(sal_Int32 nPos = 1;pSelIter != pSelEnd;++pSelIter,++nPos)
+ {
+ Reference<XPropertySet> xQueryColumnProp(_rxQueryColumns->getByName(*pSelIter),UNO_QUERY_THROW);
+ OUString sRealName,sTableName;
+ OSL_ENSURE(xQueryColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME),"Property REALNAME not available!");
+ OSL_ENSURE(xQueryColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME),"Property TABLENAME not available!");
+ xQueryColumnProp->getPropertyValue(PROPERTY_REALNAME) >>= sRealName;
+ xQueryColumnProp->getPropertyValue(PROPERTY_TABLENAME) >>= sTableName;
+
+ for(;pTblColumnIter != pTblColumnEnd;++pTblColumnIter)
+ {
+ if(bCase(sRealName,*pTblColumnIter) && bCase(_rsUpdateTableName,sTableName) && o_rColumnNames.find(*pTblColumnIter) == o_rColumnNames.end())
+ {
+ sal_Int32 nType = 0;
+ xQueryColumnProp->getPropertyValue(PROPERTY_TYPE) >>= nType;
+ sal_Int32 nScale = 0;
+ xQueryColumnProp->getPropertyValue(PROPERTY_SCALE) >>= nScale;
+ OUString sColumnDefault;
+ if ( xQueryColumnProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_DEFAULTVALUE) )
+ xQueryColumnProp->getPropertyValue(PROPERTY_DEFAULTVALUE) >>= sColumnDefault;
+
+ sal_Int32 nNullable = ColumnValue::NULLABLE_UNKNOWN;
+ OSL_VERIFY( xQueryColumnProp->getPropertyValue( PROPERTY_ISNULLABLE ) >>= nNullable );
+
+ SelectColumnDescription aColDesc( nPos, nType, nScale, nNullable != sdbc::ColumnValue::NO_NULLS, sColumnDefault );
+ OUString sName;
+ if ( i_bAppendTableName )
+ {
+ sName = sTableName + "." + sRealName;
+ aColDesc.sRealName = sRealName;
+ aColDesc.sTableName = sTableName;
+ }
+ else
+ {
+ sName = sRealName;
+ }
+ o_rColumnNames[sName] = aColDesc;
+
+ break;
+ }
+ }
+ pTblColumnIter = _aColumnNames.getConstArray();
+ }
+ }
+}
+
+void OKeySet::impl_convertValue_throw(const ORowSetRow& _rInsertRow,const SelectColumnDescription& i_aMetaData)
+{
+ ORowSetValue& aValue((*_rInsertRow)[i_aMetaData.nPosition]);
+ switch(i_aMetaData.nType)
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ {
+ OUString sValue = aValue.getString();
+ sal_Int32 nIndex = sValue.indexOf('.');
+ if ( nIndex != -1 )
+ {
+ aValue = sValue.copy(0,std::min(sValue.getLength(),nIndex + (i_aMetaData.nScale > 0 ? i_aMetaData.nScale + 1 : 0)));
+ }
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/KeySet.hxx b/dbaccess/source/core/api/KeySet.hxx
new file mode 100644
index 000000000..57889c774
--- /dev/null
+++ b/dbaccess/source/core/api/KeySet.hxx
@@ -0,0 +1,216 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "CacheSet.hxx"
+
+#include <memory>
+#include <map>
+#include <vector>
+
+#include <com/sun/star/sdb/XSingleSelectQueryAnalyzer.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <comphelper/stl_types.hxx>
+
+namespace dbaccess
+{
+ struct SelectColumnDescription
+ {
+ OUString sRealName; // may be empty
+ OUString sTableName; // may be empty
+ OUString sDefaultValue;
+ sal_Int32 nPosition;
+ sal_Int32 nType;
+ sal_Int32 nScale;
+ bool bNullable;
+
+ SelectColumnDescription()
+ :nPosition( 0 )
+ ,nType( 0 )
+ ,nScale( 0 )
+ ,bNullable(false)
+ {
+ }
+
+ SelectColumnDescription( sal_Int32 _nPosition, sal_Int32 _nType, sal_Int32 _nScale,bool _bNullable, const OUString& _rDefaultValue )
+ :sDefaultValue( _rDefaultValue )
+ ,nPosition( _nPosition )
+ ,nType( _nType )
+ ,nScale( _nScale )
+ ,bNullable(_bNullable)
+ {
+ }
+ };
+ typedef std::map< OUString, SelectColumnDescription, ::comphelper::UStringMixLess > SelectColumnsMetaData;
+
+ // the elements of _rxQueryColumns must have the properties PROPERTY_REALNAME and PROPERTY_TABLENAME
+ void getColumnPositions(const css::uno::Reference< css::container::XNameAccess >& _rxQueryColumns,
+ const css::uno::Sequence< OUString >& _rColumnNames,
+ std::u16string_view _rsUpdateTableName,
+ SelectColumnsMetaData& o_rColumnNames /* out */,
+ bool i_bAppendTableName = false);
+
+ typedef std::pair<ORowSetRow,std::pair<sal_Int32,css::uno::Reference< css::sdbc::XRow> > > OKeySetValue;
+ typedef std::map<sal_Int32,OKeySetValue > OKeySetMatrix;
+ typedef std::map<sal_Int32, rtl::Reference<ORowSetValueVector> > OUpdatedParameter;
+ // is used when the source supports keys
+ class OKeySet : public OCacheSet
+ {
+ protected:
+ OKeySetMatrix m_aKeyMap;
+ OKeySetMatrix::iterator m_aKeyIter;
+
+ std::vector< OUString > m_aAutoColumns; // contains all columns which are autoincrement ones
+
+ OUpdatedParameter m_aUpdatedParameter; // contains all parameter which have been updated and are needed for refetching
+ rtl::Reference<ORowSetValueVector> m_aParameterValueForCache;
+ std::unique_ptr<SelectColumnsMetaData> m_pKeyColumnNames; // contains all key column names
+ std::unique_ptr<SelectColumnsMetaData> m_pColumnNames; // contains all column names
+ std::unique_ptr<SelectColumnsMetaData> m_pParameterNames; // contains all parameter names
+ std::unique_ptr<SelectColumnsMetaData> m_pForeignColumnNames; // contains all column names of the rest
+ connectivity::OSQLTable m_xTable; // reference to our table
+ // we need a different SQL (statement) for each different combination
+ // of NULLness of key & foreign columns;
+ // each subclause is either "colName = ?" or "colName IS NULL"
+ // (we avoid the standard "colName IS NOT DISTINCT FROM ?" because it is not widely supported)
+ typedef std::map< std::vector<bool>,
+ css::uno::Reference< css::sdbc::XPreparedStatement > >
+ vStatements_t;
+ vStatements_t m_vStatements;
+ css::uno::Reference< css::sdbc::XPreparedStatement> m_xStatement;
+ css::uno::Reference< css::sdbc::XResultSet> m_xSet;
+ css::uno::Reference< css::sdbc::XRow> m_xRow;
+ css::uno::Reference< css::sdb::XSingleSelectQueryAnalyzer > m_xComposer;
+ const OUString m_sUpdateTableName;
+ std::vector< OUString > m_aFilterColumns;
+ sal_Int32& m_rRowCount;
+
+ bool m_bRowCountFinal;
+
+ /** copies the values from the insert row into the key row
+ *
+ * \param _rInsertRow the row which was inserted
+ * \param _rKeyRow The current key row of the row set.
+ + \param i_nBookmark The bookmark is used to update the parameter
+ */
+ void copyRowValue(const ORowSetRow& _rInsertRow, ORowSetRow const & _rKeyRow, sal_Int32 i_nBookmark);
+
+ // returns true if it did any work
+ bool fillAllRows();
+ bool fetchRow();
+ void invalidateRow();
+
+ static void impl_convertValue_throw(const ORowSetRow& _rInsertRow,const SelectColumnDescription& i_aMetaData);
+ void initColumns();
+ void findTableColumnsMatching_throw( const css::uno::Any& i_aTable,
+ const OUString& i_rUpdateTableName,
+ const css::uno::Reference< css::sdbc::XDatabaseMetaData>& i_xMeta,
+ const css::uno::Reference< css::container::XNameAccess>& i_xQueryColumns,
+ std::unique_ptr<SelectColumnsMetaData> const & o_pKeyColumnNames);
+ void ensureStatement( );
+ virtual void makeNewStatement( );
+ static void setOneKeyColumnParameter( sal_Int32 &nPos,
+ const css::uno::Reference< css::sdbc::XParameters > &_xParameter,
+ const connectivity::ORowSetValue &_rValue,
+ sal_Int32 _nType,
+ sal_Int32 _nScale );
+ OUStringBuffer createKeyFilter( );
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ bool doTryRefetch_throw();
+ void tryRefetch(const ORowSetRow& _rInsertRow,bool bRefetch);
+ void executeUpdate(const ORowSetRow& _rInsertRow, const ORowSetRow& _rOriginalRow, const OUString& i_sSQL, std::u16string_view i_sTableName,const std::vector<sal_Int32>& _aIndexColumnPositions = std::vector<sal_Int32>());
+ void executeInsert( const ORowSetRow& _rInsertRow, const OUString& i_sSQL, std::u16string_view i_sTableName, bool bRefetch = false);
+ void executeStatement(OUStringBuffer& io_aFilter, css::uno::Reference< css::sdb::XSingleSelectQueryComposer>& io_xAnalyzer);
+
+ virtual ~OKeySet() override;
+ public:
+ OKeySet(const connectivity::OSQLTable& _xTable,
+ const OUString& _rUpdateTableName,
+ const css::uno::Reference< css::sdb::XSingleSelectQueryAnalyzer >& _xComposer,
+ const ORowSetValueVector& _aParameterValueForCache,
+ sal_Int32 i_nMaxRows,
+ sal_Int32& o_nRowCount);
+
+ // late ctor which can throw exceptions
+ virtual void construct(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter) override;
+ virtual void reset(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet) override;
+
+ // css::sdbc::XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+
+
+ virtual bool rowUpdated( ) override;
+ virtual bool rowInserted( ) override;
+ virtual bool rowDeleted( ) override;
+ bool isBeforeFirst( );
+ bool isAfterLast( );
+
+ // css::sdbc::XResultSet
+ virtual bool next() override;
+ virtual void beforeFirst( ) override;
+ virtual void afterLast( ) override;
+ virtual bool first() override;
+ virtual bool last( ) override;
+ virtual sal_Int32 getRow( ) override;
+ virtual bool absolute( sal_Int32 row ) override;
+ virtual bool previous( ) override;
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void ensureRowForData( );
+ virtual void refreshRow( ) override;
+ // css::sdbcx::XRowLocate
+ virtual css::uno::Any getBookmark() override;
+
+ virtual bool moveToBookmark( const css::uno::Any& bookmark ) override;
+
+ virtual sal_Int32 compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+
+ virtual bool hasOrderedBookmarks( ) override;
+
+ virtual sal_Int32 hashBookmark( const css::uno::Any& bookmark ) override;
+
+ // css::sdbc::XResultSetUpdate
+ virtual void updateRow(const ORowSetRow& _rInsertRow,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void deleteRow(const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/OptimisticSet.cxx b/dbaccess/source/core/api/OptimisticSet.cxx
new file mode 100644
index 000000000..d1d70955f
--- /dev/null
+++ b/dbaccess/source/core/api/OptimisticSet.cxx
@@ -0,0 +1,586 @@
+/* -*- 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 <memory>
+#include "OptimisticSet.hxx"
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <map>
+#include <algorithm>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <composertools.hxx>
+
+using namespace dbaccess;
+using namespace ::connectivity;
+using namespace ::dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star;
+using namespace ::cppu;
+using namespace ::osl;
+
+typedef std::map<OUString, OUStringBuffer> TSQLStatements;
+namespace
+{
+ void lcl_fillKeyCondition(const OUString& i_sTableName,std::u16string_view i_sQuotedColumnName,const ORowSetValue& i_aValue,TSQLStatements& io_aKeyConditions)
+ {
+ OUStringBuffer& rKeyCondition = io_aKeyConditions[i_sTableName];
+ if ( !rKeyCondition.isEmpty() )
+ rKeyCondition.append(" AND ");
+ rKeyCondition.append(i_sQuotedColumnName);
+ if ( i_aValue.isNull() )
+ rKeyCondition.append(" IS NULL");
+ else
+ rKeyCondition.append(" = ?");
+ }
+}
+
+
+OptimisticSet::OptimisticSet(const Reference<XComponentContext>& _rContext,
+ const Reference< XConnection>& i_xConnection,
+ const Reference< XSingleSelectQueryAnalyzer >& _xComposer,
+ const ORowSetValueVector& _aParameterValueForCache,
+ sal_Int32 i_nMaxRows,
+ sal_Int32& o_nRowCount)
+ :OKeySet(nullptr,OUString(),_xComposer,_aParameterValueForCache,i_nMaxRows,o_nRowCount)
+ ,m_aSqlParser( _rContext )
+ ,m_aSqlIterator( i_xConnection, Reference<XTablesSupplier>(_xComposer,UNO_QUERY_THROW)->getTables(), m_aSqlParser )
+ ,m_bResultSetChanged(false)
+{
+}
+
+OptimisticSet::~OptimisticSet()
+{
+}
+
+void OptimisticSet::construct(const Reference< XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter)
+{
+ OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
+
+ initColumns();
+ m_sRowSetFilter = i_sRowSetFilter;
+
+ Reference<XDatabaseMetaData> xMeta = m_xConnection->getMetaData();
+ bool bCase = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers();
+ Reference<XColumnsSupplier> xQueryColSup(m_xComposer,UNO_QUERY);
+ const Reference<XNameAccess> xQueryColumns = xQueryColSup->getColumns();
+ const Reference<XTablesSupplier> xTabSup(m_xComposer,UNO_QUERY);
+ const Reference<XNameAccess> xTables = xTabSup->getTables();
+ const Sequence< OUString> aTableNames = xTables->getElementNames();
+ const OUString* pTableNameIter = aTableNames.getConstArray();
+ const OUString* pTableNameEnd = pTableNameIter + aTableNames.getLength();
+ for( ; pTableNameIter != pTableNameEnd ; ++pTableNameIter)
+ {
+ std::unique_ptr<SelectColumnsMetaData> pKeyColumNames(new SelectColumnsMetaData(bCase));
+ findTableColumnsMatching_throw(xTables->getByName(*pTableNameIter),*pTableNameIter,xMeta,xQueryColumns,pKeyColumNames);
+ m_pKeyColumnNames->insert(pKeyColumNames->begin(),pKeyColumNames->end());
+ }
+
+ // the first row is empty because it's now easier for us to distinguish when we are beforefirst or first
+ // without extra variable to be set
+ OKeySetValue keySetValue(nullptr,std::pair<sal_Int32,Reference<XRow> >(0,Reference<XRow>()));
+ m_aKeyMap.emplace(0,keySetValue);
+ m_aKeyIter = m_aKeyMap.begin();
+
+ Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
+ Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
+ Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
+ OUString sQuery = xSourceComposer->getQuery();
+ xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
+ // check for joins
+ OUString aErrorMsg;
+ std::unique_ptr<OSQLParseNode> pStatementNode( m_aSqlParser.parseTree( aErrorMsg, sQuery ) );
+ m_aSqlIterator.setParseTree( pStatementNode.get() );
+ m_aSqlIterator.traverseAll();
+ fillJoinedColumns_throw(m_aSqlIterator.getJoinConditions());
+
+}
+
+void OptimisticSet::makeNewStatement( )
+{
+ OUStringBuffer aFilter = createKeyFilter();
+
+ Reference< XSingleSelectQueryComposer> xSourceComposer(m_xComposer,UNO_QUERY);
+ Reference< XMultiServiceFactory > xFactory(m_xConnection, UNO_QUERY_THROW);
+ Reference<XSingleSelectQueryComposer> xAnalyzer(xFactory->createInstance(SERVICE_NAME_SINGLESELECTQUERYCOMPOSER),UNO_QUERY);
+ xAnalyzer->setElementaryQuery(xSourceComposer->getElementaryQuery());
+
+ const OUString sComposerFilter = m_xComposer->getFilter();
+ if ( !m_sRowSetFilter.isEmpty() || !sComposerFilter.isEmpty() )
+ {
+ FilterCreator aFilterCreator;
+ if ( !sComposerFilter.isEmpty() && sComposerFilter != m_sRowSetFilter )
+ aFilterCreator.append( sComposerFilter );
+ aFilterCreator.append( m_sRowSetFilter );
+ aFilterCreator.append( aFilter.makeStringAndClear() );
+ aFilter = aFilterCreator.getComposedAndClear();
+ }
+ xAnalyzer->setFilter(aFilter.makeStringAndClear());
+ m_xStatement = m_xConnection->prepareStatement(xAnalyzer->getQueryWithSubstitution());
+ ::comphelper::disposeComponent(xAnalyzer);
+}
+
+void OptimisticSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ if ( m_aJoinedKeyColumns.empty() )
+ throw SQLException();
+ // list all columns that should be set
+ OUString aQuote = getIdentifierQuoteString();
+
+ std::map< OUString,bool > aResultSetChanged;
+ TSQLStatements aKeyConditions;
+ TSQLStatements aSql;
+
+ // here we build the condition part for the update statement
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ aResultSetChanged.try_emplace(columnName.second.sTableName, false);
+ const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
+ if ( m_pKeyColumnNames->find(columnName.first) != m_pKeyColumnNames->end() )
+ {
+ aResultSetChanged[columnName.second.sTableName] = m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end();
+ lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,(*_rOriginalRow)[columnName.second.nPosition],aKeyConditions);
+ }
+ if((*_rInsertRow)[columnName.second.nPosition].isModified())
+ {
+ if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end() )
+ throw SQLException();
+
+ std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(columnName.second.nPosition);
+ if ( aJoinIter != m_aJoinedColumns.end() )
+ {
+ (*_rInsertRow)[aJoinIter->second] = (*_rInsertRow)[columnName.second.nPosition];
+ }
+ OUStringBuffer& rPart = aSql[columnName.second.sTableName];
+ if ( !rPart.isEmpty() )
+ rPart.append(", ");
+ rPart.append(sQuotedColumnName + " = ?");
+ }
+ }
+
+ if( aSql.empty() )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED ), StandardSQLState::GENERAL_ERROR, m_xConnection );
+
+ if( aKeyConditions.empty() )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_CONDITION_FOR_PK ), StandardSQLState::GENERAL_ERROR, m_xConnection );
+
+ Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
+
+ for (auto const& elem : aSql)
+ {
+ if ( !elem.second.isEmpty() )
+ {
+ m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[elem.first];
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(xMetaData,elem.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+ OUStringBuffer sSql("UPDATE " + ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) +
+ " SET " + elem.second);
+ OUStringBuffer& rCondition = aKeyConditions[elem.first];
+ if ( !rCondition.isEmpty() )
+ sSql.append(" WHERE " + rCondition );
+
+ executeUpdate(_rInsertRow ,_rOriginalRow,sSql.makeStringAndClear(),elem.first);
+ }
+ }
+}
+
+void OptimisticSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ TSQLStatements aSql;
+ TSQLStatements aParameter;
+ TSQLStatements aKeyConditions;
+ std::map< OUString,bool > aResultSetChanged;
+ OUString aQuote = getIdentifierQuoteString();
+
+ // here we build the condition part for the update statement
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ aResultSetChanged.try_emplace(columnName.second.sTableName, false);
+
+ const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
+ if ( (*_rInsertRow)[columnName.second.nPosition].isModified() )
+ {
+ if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end() )
+ {
+ lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,(*_rInsertRow)[columnName.second.nPosition],aKeyConditions);
+ aResultSetChanged[columnName.second.sTableName] = true;
+ }
+ std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(columnName.second.nPosition);
+ if ( aJoinIter != m_aJoinedColumns.end() )
+ {
+ (*_rInsertRow)[aJoinIter->second] = (*_rInsertRow)[columnName.second.nPosition];
+ }
+ OUStringBuffer& rPart = aSql[columnName.second.sTableName];
+ if ( !rPart.isEmpty() )
+ rPart.append(", ");
+ rPart.append(sQuotedColumnName);
+ OUStringBuffer& rParam = aParameter[columnName.second.sTableName];
+ if ( !rParam.isEmpty() )
+ rParam.append(", ");
+ rParam.append("?");
+ }
+ }
+ if ( aParameter.empty() )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_VALUE_CHANGED ), StandardSQLState::GENERAL_ERROR, m_xConnection );
+
+ Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
+ for (auto const& elem : aSql)
+ {
+ if ( !elem.second.isEmpty() )
+ {
+ m_bResultSetChanged = m_bResultSetChanged || aResultSetChanged[elem.first];
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(xMetaData,elem.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+ OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
+ OUString sSql("INSERT INTO " + sComposedTableName + " ( " + elem.second +
+ ") VALUES ( " + aParameter[elem.first] + " )");
+
+ OUStringBuffer& rCondition = aKeyConditions[elem.first];
+ if ( !rCondition.isEmpty() )
+ {
+ OUString sQuery("SELECT " + elem.second + " FROM " + sComposedTableName +
+ " WHERE " + rCondition);
+
+ try
+ {
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+ // and then the values of the where condition
+ sal_Int32 i = 1;
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ {
+ if ( keyColumnName.second.sTableName == elem.first )
+ {
+ setParameter(i++,xParameter,(*_rInsertRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale);
+ }
+ }
+ Reference<XResultSet> xRes = xPrep->executeQuery();
+ Reference<XRow> xRow(xRes,UNO_QUERY);
+ if ( xRow.is() && xRes->next() )
+ {
+ m_bResultSetChanged = true;
+ continue;
+ }
+ }
+ catch(const SQLException&)
+ {
+ }
+ }
+
+ executeInsert(_rInsertRow,sSql,elem.first);
+ }
+ }
+}
+
+void OptimisticSet::deleteRow(const ORowSetRow& _rDeleteRow,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ OUString aQuote = getIdentifierQuoteString();
+ TSQLStatements aKeyConditions;
+
+ // here we build the condition part for the update statement
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) == m_aJoinedKeyColumns.end() && m_pKeyColumnNames->find(columnName.first) != m_pKeyColumnNames->end() )
+ {
+ // only delete rows which aren't the key in the join
+ const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
+ lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,(*_rDeleteRow)[columnName.second.nPosition],aKeyConditions);
+ }
+ }
+ Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
+ for (auto & keyCondition : aKeyConditions)
+ {
+ OUStringBuffer& rCondition = keyCondition.second;
+ if ( !rCondition.isEmpty() )
+ {
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(xMetaData,keyCondition.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+ OUString sSql("DELETE FROM " + ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable ) +
+ " WHERE " + rCondition );
+ executeDelete(_rDeleteRow, sSql, keyCondition.first);
+ }
+ }
+}
+
+void OptimisticSet::executeDelete(const ORowSetRow& _rDeleteRow,const OUString& i_sSQL,std::u16string_view i_sTableName)
+{
+ // now create and execute the prepared statement
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(i_sSQL));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+
+ sal_Int32 i = 1;
+ for (auto const& keyColumnName : *m_pKeyColumnNames)
+ {
+ if ( keyColumnName.second.sTableName == i_sTableName )
+ setParameter(i++,xParameter,(*_rDeleteRow)[keyColumnName.second.nPosition],keyColumnName.second.nType,keyColumnName.second.nScale);
+ }
+ m_bDeleted = xPrep->executeUpdate() > 0;
+
+ if(m_bDeleted)
+ {
+ sal_Int32 nBookmark = ::comphelper::getINT32((*_rDeleteRow)[0].getAny());
+ if(m_aKeyIter == m_aKeyMap.find(nBookmark) && m_aKeyIter != m_aKeyMap.end())
+ ++m_aKeyIter;
+ m_aKeyMap.erase(nBookmark);
+ m_bDeleted = true;
+ }
+}
+
+void OptimisticSet::fillJoinedColumns_throw(const std::vector< TNodePair >& i_aJoinColumns)
+{
+ for (auto const& joinColumn : i_aJoinColumns)
+ {
+ OUString sColumnName,sTableName;
+ m_aSqlIterator.getColumnRange(joinColumn.first,sColumnName,sTableName);
+ OUString sLeft(sTableName + "." + sColumnName);
+ m_aSqlIterator.getColumnRange(joinColumn.second,sColumnName,sTableName);
+ OUString sRight(sTableName + "." + sColumnName);
+ fillJoinedColumns_throw(sLeft, sRight);
+ }
+}
+
+void OptimisticSet::fillJoinedColumns_throw(const OUString& i_sLeftColumn,const OUString& i_sRightColumn)
+{
+ sal_Int32 nLeft = 0,nRight = 0;
+ SelectColumnsMetaData::const_iterator aLeftIter = m_pKeyColumnNames->find(i_sLeftColumn);
+ SelectColumnsMetaData::const_iterator aRightIter = m_pKeyColumnNames->find(i_sRightColumn);
+
+ bool bLeftKey = aLeftIter != m_pKeyColumnNames->end();
+ if ( bLeftKey )
+ {
+ nLeft = aLeftIter->second.nPosition;
+ }
+ else
+ {
+ aLeftIter = m_pColumnNames->find(i_sLeftColumn);
+ if ( aLeftIter != m_pColumnNames->end() )
+ nLeft = aLeftIter->second.nPosition;
+ }
+
+ bool bRightKey = aRightIter != m_pKeyColumnNames->end();
+ if ( bRightKey )
+ {
+ nRight = aRightIter->second.nPosition;
+ }
+ else
+ {
+ aRightIter = m_pColumnNames->find(i_sRightColumn);
+ if ( aRightIter != m_pColumnNames->end() )
+ nRight = aRightIter->second.nPosition;
+ }
+
+ if (bLeftKey)
+ m_aJoinedKeyColumns[nLeft] = nRight;
+ else
+ m_aJoinedColumns[nLeft] = nRight;
+ if (bRightKey)
+ m_aJoinedKeyColumns[nRight] = nLeft;
+ else
+ m_aJoinedColumns[nRight] = nLeft;
+}
+
+bool OptimisticSet::isResultSetChanged() const
+{
+ bool bOld = m_bResultSetChanged;
+ m_bResultSetChanged = false;
+ return bOld;
+}
+
+void OptimisticSet::mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,std::vector<sal_Int32>& o_aChangedColumns)
+{
+ o_aChangedColumns.push_back(i_nColumnIndex);
+ std::map<sal_Int32,sal_Int32>::const_iterator aJoinIter = m_aJoinedColumns.find(i_nColumnIndex);
+ if ( aJoinIter != m_aJoinedColumns.end() )
+ {
+ io_aRow[aJoinIter->second] = io_aRow[i_nColumnIndex];
+ io_aInsertRow[aJoinIter->second] = io_aInsertRow[i_nColumnIndex];
+ io_aRow[aJoinIter->second].setModified(true);
+ o_aChangedColumns.push_back(aJoinIter->second);
+ }
+}
+
+bool OptimisticSet::updateColumnValues(const ORowSetValueVector::Vector& io_aCachedRow,ORowSetValueVector::Vector& io_aRow,const std::vector<sal_Int32>& i_aChangedColumns)
+{
+ bool bRet = false;
+ for( const auto& aColIdx : i_aChangedColumns )
+ {
+ SelectColumnsMetaData::const_iterator aFind = std::find_if(
+ m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
+ [&aColIdx]( const SelectColumnsMetaData::value_type& aType )
+ { return aType.second.nPosition == aColIdx; } );
+ if ( aFind != m_pKeyColumnNames->end() )
+ {
+ const OUString sTableName = aFind->second.sTableName;
+ aFind = std::find_if( m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
+ [&sTableName]
+ ( const SelectColumnsMetaData::value_type& rCurr )
+ { return rCurr.second.sTableName == sTableName; } );
+ while( aFind != m_pKeyColumnNames->end() )
+ {
+ io_aRow[aFind->second.nPosition].setSigned(io_aCachedRow[aFind->second.nPosition].isSigned());
+ if ( io_aCachedRow[aFind->second.nPosition] != io_aRow[aFind->second.nPosition] )
+ break;
+ ++aFind;
+ }
+ if ( aFind == m_pKeyColumnNames->end() )
+ {
+ bRet = true;
+ for( const auto& aCol : *m_pColumnNames )
+ {
+ if ( aCol.second.sTableName == sTableName )
+ {
+ io_aRow[aCol.second.nPosition] = io_aCachedRow[aCol.second.nPosition];
+ io_aRow[aCol.second.nPosition].setModified(true);
+ }
+ }
+ }
+ }
+ }
+ return bRet;
+}
+
+bool OptimisticSet::columnValuesUpdated(ORowSetValueVector::Vector& o_aCachedRow,const ORowSetValueVector::Vector& i_aRow)
+{
+ bool bRet = false;
+ for( const auto& aCol : *m_pColumnNames )
+ {
+ sal_Int32 nPos = aCol.second.nPosition;
+ SelectColumnsMetaData::const_iterator aFind = std::find_if(
+ m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
+ [&nPos] ( const SelectColumnsMetaData::value_type& aType )
+ { return aType.second.nPosition == nPos; } );
+ if ( aFind != m_pKeyColumnNames->end() )
+ {
+ const OUString sTableName = aFind->second.sTableName;
+ aFind = std::find_if( m_pKeyColumnNames->begin(),m_pKeyColumnNames->end(),
+ [&sTableName]
+ ( const SelectColumnsMetaData::value_type& rCurr )
+ { return rCurr.second.sTableName == sTableName; } );
+ while( aFind != m_pKeyColumnNames->end() )
+ {
+ o_aCachedRow[aFind->second.nPosition].setSigned(i_aRow[aFind->second.nPosition].isSigned());
+ if ( o_aCachedRow[aFind->second.nPosition] != i_aRow[aFind->second.nPosition] )
+ break;
+ ++aFind;
+ }
+ if ( aFind == m_pKeyColumnNames->end() )
+ {
+ bRet = true;
+ for( const auto& aCol2 : *m_pColumnNames )
+ {
+ if ( aCol2.second.sTableName == sTableName )
+ {
+ o_aCachedRow[aCol2.second.nPosition] = i_aRow[aCol2.second.nPosition];
+ o_aCachedRow[aCol2.second.nPosition].setModified(true);
+ }
+ }
+ fillMissingValues(o_aCachedRow);
+ }
+ }
+ }
+ return bRet;
+}
+
+void OptimisticSet::fillMissingValues(ORowSetValueVector::Vector& io_aRow) const
+{
+ TSQLStatements aSql;
+ TSQLStatements aKeyConditions;
+ OUString aQuote = getIdentifierQuoteString();
+ // here we build the condition part for the update statement
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ const OUString sQuotedColumnName = ::dbtools::quoteName( aQuote,columnName.second.sRealName);
+ if ( m_aJoinedKeyColumns.find(columnName.second.nPosition) != m_aJoinedKeyColumns.end() )
+ {
+ lcl_fillKeyCondition(columnName.second.sTableName,sQuotedColumnName,io_aRow[columnName.second.nPosition],aKeyConditions);
+ }
+ OUStringBuffer& rPart = aSql[columnName.second.sTableName];
+ if ( !rPart.isEmpty() )
+ rPart.append(", ");
+ rPart.append(sQuotedColumnName);
+ }
+ Reference<XDatabaseMetaData> xMetaData = m_xConnection->getMetaData();
+ for (auto const& elem : aSql)
+ {
+ if ( !elem.second.isEmpty() )
+ {
+ OUStringBuffer& rCondition = aKeyConditions[elem.first];
+ if ( !rCondition.isEmpty() )
+ {
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(xMetaData,elem.first,sCatalog,sSchema,sTable,::dbtools::EComposeRule::InDataManipulation);
+ OUString sComposedTableName = ::dbtools::composeTableNameForSelect( m_xConnection, sCatalog, sSchema, sTable );
+ OUString sQuery("SELECT " + elem.second + " FROM " + sComposedTableName + " WHERE " + rCondition);
+ rCondition.setLength(0);
+
+ try
+ {
+ Reference< XPreparedStatement > xPrep(m_xConnection->prepareStatement(sQuery));
+ Reference< XParameters > xParameter(xPrep,UNO_QUERY);
+ // and then the values of the where condition
+ sal_Int32 i = 1;
+ for (auto const& keyColumn : *m_pKeyColumnNames)
+ {
+ if ( keyColumn.second.sTableName == elem.first )
+ {
+ setParameter(i++,xParameter,io_aRow[keyColumn.second.nPosition],keyColumn.second.nType,keyColumn.second.nScale);
+ }
+ }
+ Reference<XResultSet> xRes = xPrep->executeQuery();
+ Reference<XRow> xRow(xRes,UNO_QUERY);
+ if ( xRow.is() && xRes->next() )
+ {
+ i = 1;
+ for (auto const& columnName : *m_pColumnNames)
+ {
+ if ( columnName.second.sTableName == elem.first )
+ {
+ io_aRow[columnName.second.nPosition].fill(i++, columnName.second.nType, xRow);
+ io_aRow[columnName.second.nPosition].setModified(true);
+ }
+ }
+ }
+ }
+ catch(const SQLException&)
+ {
+ }
+ }
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/OptimisticSet.hxx b/dbaccess/source/core/api/OptimisticSet.hxx
new file mode 100644
index 000000000..bf5e3a803
--- /dev/null
+++ b/dbaccess/source/core/api/OptimisticSet.hxx
@@ -0,0 +1,76 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "KeySet.hxx"
+
+#include <connectivity/sqlparse.hxx>
+#include <connectivity/sqliterator.hxx>
+
+#include <com/sun/star/sdb/XSingleSelectQueryAnalyzer.hpp>
+
+namespace dbaccess
+{
+ // is used when the source supports keys
+ class OptimisticSet : public OKeySet
+ {
+ ::connectivity::OSQLParser m_aSqlParser;
+ ::connectivity::OSQLParseTreeIterator m_aSqlIterator;
+
+ std::map<sal_Int32,sal_Int32> m_aJoinedColumns;
+ std::map<sal_Int32,sal_Int32> m_aJoinedKeyColumns;
+
+ mutable bool m_bResultSetChanged;
+
+ void executeDelete(const ORowSetRow& _rDeleteRow,const OUString& i_sSQL,std::u16string_view i_sTableName);
+ void fillJoinedColumns_throw(const std::vector< ::connectivity::TNodePair>& i_aJoinColumns);
+ void fillJoinedColumns_throw(const OUString& i_sLeftColumn,const OUString& i_sRightColumn);
+ protected:
+ virtual void makeNewStatement( ) override;
+ virtual ~OptimisticSet() override;
+ public:
+ OptimisticSet(const css::uno::Reference< css::uno::XComponentContext>& _rContext,
+ const css::uno::Reference< css::sdbc::XConnection>& i_xConnection,
+ const css::uno::Reference< css::sdb::XSingleSelectQueryAnalyzer >& _xComposer,
+ const ORowSetValueVector& _aParameterValueForCache,
+ sal_Int32 i_nMaxRows,
+ sal_Int32& o_nRowCount);
+
+ // late ctor which can throw exceptions
+ virtual void construct(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter) override;
+
+ // css::sdbc::XResultSetUpdate
+ virtual void updateRow(const ORowSetRow& _rInsertRow,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void deleteRow(const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+
+ // CacheSet
+ virtual bool isResultSetChanged() const override;
+ virtual void mergeColumnValues(sal_Int32 i_nColumnIndex,ORowSetValueVector::Vector& io_aInsertRow,ORowSetValueVector::Vector& io_aRow,std::vector<sal_Int32>& o_aChangedColumns) override;
+ virtual bool columnValuesUpdated(ORowSetValueVector::Vector& o_aCachedRow,const ORowSetValueVector::Vector& i_aRow) override;
+ virtual bool updateColumnValues(const ORowSetValueVector::Vector& io_aCachedRow,ORowSetValueVector::Vector& io_aRow,const std::vector<sal_Int32>& i_aChangedColumns) override;
+ virtual void fillMissingValues(ORowSetValueVector::Vector& io_aRow) const override;
+
+ bool isReadOnly() const { return m_aJoinedKeyColumns.empty(); }
+ const std::map<sal_Int32,sal_Int32>& getJoinedKeyColumns() const { return m_aJoinedKeyColumns; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/PrivateRow.cxx b/dbaccess/source/core/api/PrivateRow.cxx
new file mode 100644
index 000000000..9bf270960
--- /dev/null
+++ b/dbaccess/source/core/api/PrivateRow.cxx
@@ -0,0 +1,133 @@
+/* -*- 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 "PrivateRow.hxx"
+
+using namespace dbaccess;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star;
+
+sal_Bool SAL_CALL OPrivateRow::wasNull( )
+ {
+ return m_aRow[m_nPos].isNull();
+ }
+ OUString SAL_CALL OPrivateRow::getString( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getString();
+ }
+ sal_Bool SAL_CALL OPrivateRow::getBoolean( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getBool();
+ }
+ ::sal_Int8 SAL_CALL OPrivateRow::getByte( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getInt8();
+ }
+ ::sal_Int16 SAL_CALL OPrivateRow::getShort( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getInt16();
+ }
+ ::sal_Int32 SAL_CALL OPrivateRow::getInt( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getInt32();
+ }
+ ::sal_Int64 SAL_CALL OPrivateRow::getLong( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getLong();
+ }
+ float SAL_CALL OPrivateRow::getFloat( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getFloat();
+ }
+ double SAL_CALL OPrivateRow::getDouble( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getDouble();
+ }
+ Sequence< ::sal_Int8 > SAL_CALL OPrivateRow::getBytes( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getSequence();
+ }
+ css::util::Date SAL_CALL OPrivateRow::getDate( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getDate();
+ }
+ css::util::Time SAL_CALL OPrivateRow::getTime( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getTime();
+ }
+ css::util::DateTime SAL_CALL OPrivateRow::getTimestamp( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].getDateTime();
+ }
+ Reference< css::io::XInputStream > SAL_CALL OPrivateRow::getBinaryStream( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return Reference< css::io::XInputStream >(m_aRow[m_nPos].makeAny(),UNO_QUERY);
+ }
+ Reference< css::io::XInputStream > SAL_CALL OPrivateRow::getCharacterStream( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return Reference< css::io::XInputStream >(m_aRow[m_nPos].makeAny(),UNO_QUERY);
+ }
+ Any SAL_CALL OPrivateRow::getObject( ::sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& )
+ {
+ m_nPos = columnIndex;
+ return m_aRow[m_nPos].makeAny();
+ }
+ Reference< XRef > SAL_CALL OPrivateRow::getRef( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return Reference< XRef >(m_aRow[m_nPos].makeAny(),UNO_QUERY);
+ }
+ Reference< XBlob > SAL_CALL OPrivateRow::getBlob( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return Reference< XBlob >(m_aRow[m_nPos].makeAny(),UNO_QUERY);
+ }
+ Reference< XClob > SAL_CALL OPrivateRow::getClob( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return Reference< XClob >(m_aRow[m_nPos].makeAny(),UNO_QUERY);
+ }
+ Reference< XArray > SAL_CALL OPrivateRow::getArray( ::sal_Int32 columnIndex )
+ {
+ m_nPos = columnIndex;
+ return Reference< XArray >(m_aRow[m_nPos].makeAny(),UNO_QUERY);
+ }
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/PrivateRow.hxx b/dbaccess/source/core/api/PrivateRow.hxx
new file mode 100644
index 000000000..c5ce74f15
--- /dev/null
+++ b/dbaccess/source/core/api/PrivateRow.hxx
@@ -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 .
+ */
+#pragma once
+
+#include <cppuhelper/implbase.hxx>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include "RowSetRow.hxx"
+
+namespace dbaccess
+{
+ class OPrivateRow : public ::cppu::WeakImplHelper< css::sdbc::XRow>
+ {
+ ORowSetValueVector::Vector m_aRow;
+ sal_Int32 m_nPos;
+ public:
+ explicit OPrivateRow(ORowSetValueVector::Vector&& i_aRow) : m_aRow(std::move(i_aRow)),m_nPos(0)
+ {
+ }
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( ::sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( ::sal_Int32 columnIndex ) override;
+ virtual ::sal_Int8 SAL_CALL getByte( ::sal_Int32 columnIndex ) override;
+ virtual ::sal_Int16 SAL_CALL getShort( ::sal_Int32 columnIndex ) override;
+ virtual ::sal_Int32 SAL_CALL getInt( ::sal_Int32 columnIndex ) override;
+ virtual ::sal_Int64 SAL_CALL getLong( ::sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( ::sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( ::sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< ::sal_Int8 > SAL_CALL getBytes( ::sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( ::sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( ::sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( ::sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( ::sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( ::sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( ::sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( ::sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( ::sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( ::sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( ::sal_Int32 columnIndex ) override;
+ };
+} // dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSet.cxx b/dbaccess/source/core/api/RowSet.cxx
new file mode 100644
index 000000000..28c392995
--- /dev/null
+++ b/dbaccess/source/core/api/RowSet.cxx
@@ -0,0 +1,2965 @@
+/* -*- 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 <sal/log.hxx>
+
+#include <map>
+#include <utility>
+
+#include "RowSet.hxx"
+#include <stringconstants.hxx>
+#include <sdbcoretools.hxx>
+#include <SingleSelectQueryComposer.hxx>
+#include "CRowSetColumn.hxx"
+#include "CRowSetDataColumn.hxx"
+#include "RowSetCache.hxx"
+#include <strings.hrc>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <tablecontainer.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#include <com/sun/star/sdb/RowChangeAction.hpp>
+#include <com/sun/star/sdb/RowSetVetoException.hpp>
+#include <com/sun/star/sdb/XCompletedConnection.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdbc/FetchDirection.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+
+#include <comphelper/extract.hxx>
+#include <comphelper/seqstream.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/uno3.hxx>
+#include <connectivity/BlobHelper.hxx>
+#include <connectivity/dbconversion.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/interfacecontainer.h>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <i18nlangtag/languagetag.hxx>
+#include <o3tl/safeint.hxx>
+#include <unotools/syslocale.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace utl;
+using namespace dbaccess;
+using namespace connectivity;
+using namespace comphelper;
+using namespace dbtools;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::util;
+using namespace ::cppu;
+using namespace ::osl;
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dba_ORowSet_get_implementation(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new ORowSet(context));
+}
+
+namespace dbaccess
+{
+ORowSet::ORowSet( const Reference< css::uno::XComponentContext >& _rxContext )
+ :ORowSet_BASE1(m_aMutex)
+ ,ORowSetBase( _rxContext, ORowSet_BASE1::rBHelper, &m_aMutex )
+ ,m_aPrematureParamValues(new ORowSetValueVector)
+ ,m_aParameterValueForCache(new ORowSetValueVector)
+ ,m_aRowsetListeners(*m_pMutex)
+ ,m_aApproveListeners(*m_pMutex)
+ ,m_aRowsChangeListener(*m_pMutex)
+ ,m_sErrorString(ResourceManager::loadString(RID_STR_COMMAND_LEADING_TO_ERROR))
+ ,m_nFetchDirection(FetchDirection::FORWARD)
+ ,m_nFetchSize(50)
+ ,m_nMaxFieldSize(0)
+ ,m_nMaxRows(0)
+ ,m_nQueryTimeOut(0)
+ ,m_nCommandType(CommandType::COMMAND)
+ ,m_nTransactionIsolation(0)
+ ,m_nPrivileges(0)
+ ,m_nLastKnownRowCount(0)
+ ,m_nInAppend(0)
+ ,m_bInsertingRow(false)
+ ,m_bLastKnownRowCountFinal(false)
+ ,m_bUseEscapeProcessing(true)
+ ,m_bApplyFilter(false)
+ ,m_bCommandFacetsDirty( true )
+ ,m_bParametersDirty( true )
+ ,m_bModified(false)
+ ,m_bRebuildConnOnExecute(false)
+ ,m_bIsBookmarkable(true)
+ ,m_bNew(false)
+ ,m_bCanUpdateInsertedRows(true)
+ ,m_bOwnConnection(false)
+ ,m_bPropChangeNotifyEnabled(true)
+{
+ m_nResultSetType = ResultSetType::SCROLL_SENSITIVE;
+ m_nResultSetConcurrency = ResultSetConcurrency::UPDATABLE;
+ m_pMySelf = this;
+ m_aActiveConnection <<= m_xActiveConnection;
+
+ sal_Int32 const nRBT = PropertyAttribute::READONLY | PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT;
+ sal_Int32 const nRT = PropertyAttribute::READONLY | PropertyAttribute::TRANSIENT;
+ sal_Int32 const nBT = PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT;
+
+ m_aPrematureParamValues->resize( 0 );
+
+ // sdb.RowSet Properties
+ registerMayBeVoidProperty(PROPERTY_ACTIVE_CONNECTION,PROPERTY_ID_ACTIVE_CONNECTION, PropertyAttribute::MAYBEVOID|PropertyAttribute::TRANSIENT|PropertyAttribute::BOUND, &m_aActiveConnection, cppu::UnoType<XConnection>::get());
+ registerProperty(PROPERTY_DATASOURCENAME, PROPERTY_ID_DATASOURCENAME, PropertyAttribute::BOUND, &m_aDataSourceName, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_COMMAND, PROPERTY_ID_COMMAND, PropertyAttribute::BOUND, &m_aCommand, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_COMMAND_TYPE, PROPERTY_ID_COMMAND_TYPE, PropertyAttribute::BOUND, &m_nCommandType, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_ACTIVECOMMAND, PROPERTY_ID_ACTIVECOMMAND, nRBT, &m_aActiveCommand, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_IGNORERESULT, PROPERTY_ID_IGNORERESULT, PropertyAttribute::BOUND, &m_bIgnoreResult, cppu::UnoType<bool>::get());
+ registerProperty(PROPERTY_FILTER, PROPERTY_ID_FILTER, PropertyAttribute::BOUND, &m_aFilter, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_HAVING_CLAUSE, PROPERTY_ID_HAVING_CLAUSE, PropertyAttribute::BOUND, &m_aHavingClause, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_GROUP_BY, PROPERTY_ID_GROUP_BY, PropertyAttribute::BOUND, &m_aGroupBy, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_APPLYFILTER, PROPERTY_ID_APPLYFILTER, PropertyAttribute::BOUND, &m_bApplyFilter, cppu::UnoType<bool>::get());
+ registerProperty(PROPERTY_ORDER, PROPERTY_ID_ORDER, PropertyAttribute::BOUND, &m_aOrder, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_PRIVILEGES, PROPERTY_ID_PRIVILEGES, nRT, &m_nPrivileges, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_ISMODIFIED, PROPERTY_ID_ISMODIFIED, nBT, &m_bModified, cppu::UnoType<bool>::get());
+ registerProperty(PROPERTY_ISNEW, PROPERTY_ID_ISNEW, nRBT, &m_bNew, cppu::UnoType<bool>::get());
+ registerProperty(PROPERTY_SINGLESELECTQUERYCOMPOSER,PROPERTY_ID_SINGLESELECTQUERYCOMPOSER, nRT, &m_xComposer, cppu::UnoType<XSingleSelectQueryComposer>::get());
+
+ // sdbcx.ResultSet Properties
+ registerProperty(PROPERTY_ISBOOKMARKABLE, PROPERTY_ID_ISBOOKMARKABLE, nRT, &m_bIsBookmarkable, cppu::UnoType<bool>::get());
+ registerProperty(PROPERTY_CANUPDATEINSERTEDROWS,PROPERTY_ID_CANUPDATEINSERTEDROWS, nRT, &m_bCanUpdateInsertedRows, cppu::UnoType<bool>::get());
+ // sdbc.ResultSet Properties
+ registerProperty(PROPERTY_RESULTSETCONCURRENCY, PROPERTY_ID_RESULTSETCONCURRENCY, PropertyAttribute::TRANSIENT, &m_nResultSetConcurrency,::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_RESULTSETTYPE, PROPERTY_ID_RESULTSETTYPE, PropertyAttribute::TRANSIENT, &m_nResultSetType, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_FETCHDIRECTION, PROPERTY_ID_FETCHDIRECTION, PropertyAttribute::TRANSIENT, &m_nFetchDirection, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_FETCHSIZE, PROPERTY_ID_FETCHSIZE, PropertyAttribute::TRANSIENT, &m_nFetchSize, ::cppu::UnoType<sal_Int32>::get());
+
+ // sdbc.RowSet Properties
+ registerProperty(PROPERTY_URL, PROPERTY_ID_URL, 0, &m_aURL, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_TRANSACTIONISOLATION, PROPERTY_ID_TRANSACTIONISOLATION, PropertyAttribute::TRANSIENT, &m_nTransactionIsolation,::cppu::UnoType<sal_Int32>::get());
+ registerMayBeVoidProperty(PROPERTY_TYPEMAP, PROPERTY_ID_TYPEMAP, PropertyAttribute::MAYBEVOID|PropertyAttribute::TRANSIENT, &m_aTypeMap, cppu::UnoType<XNameAccess>::get());
+ registerProperty(PROPERTY_ESCAPE_PROCESSING,PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::BOUND, &m_bUseEscapeProcessing,cppu::UnoType<bool>::get() );
+ registerProperty(PROPERTY_QUERYTIMEOUT, PROPERTY_ID_QUERYTIMEOUT, PropertyAttribute::TRANSIENT, &m_nQueryTimeOut, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_MAXFIELDSIZE, PROPERTY_ID_MAXFIELDSIZE, PropertyAttribute::TRANSIENT, &m_nMaxFieldSize, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_MAXROWS, PROPERTY_ID_MAXROWS, 0, &m_nMaxRows, ::cppu::UnoType<sal_Int32>::get() );
+ registerProperty(PROPERTY_USER, PROPERTY_ID_USER, PropertyAttribute::TRANSIENT, &m_aUser, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_PASSWORD, PROPERTY_ID_PASSWORD, PropertyAttribute::TRANSIENT, &m_aPassword, ::cppu::UnoType<OUString>::get());
+
+ registerProperty(PROPERTY_UPDATE_CATALOGNAME, PROPERTY_ID_UPDATE_CATALOGNAME, PropertyAttribute::BOUND, &m_aUpdateCatalogName, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_UPDATE_SCHEMANAME, PROPERTY_ID_UPDATE_SCHEMANAME, PropertyAttribute::BOUND, &m_aUpdateSchemaName, ::cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_UPDATE_TABLENAME, PROPERTY_ID_UPDATE_TABLENAME, PropertyAttribute::BOUND, &m_aUpdateTableName, ::cppu::UnoType<OUString>::get());
+
+ // ???
+ registerProperty(PROPERTY_CHANGE_NOTIFICATION_ENABLED, PROPERTY_ID_PROPCHANGE_NOTIFY, PropertyAttribute::BOUND, &m_bPropChangeNotifyEnabled, cppu::UnoType<bool>::get());
+}
+
+ORowSet::~ORowSet()
+{
+ if ( !m_rBHelper.bDisposed && !m_rBHelper.bInDispose )
+ {
+ SAL_WARN("dbaccess", "Please check who doesn't dispose this component!");
+ osl_atomic_increment( &m_refCount );
+ dispose();
+ }
+}
+
+void ORowSet::getPropertyDefaultByHandle( sal_Int32 _nHandle, Any& _rDefault ) const
+{
+ switch( _nHandle )
+ {
+ case PROPERTY_ID_COMMAND_TYPE:
+ _rDefault <<= CommandType::COMMAND;
+ break;
+ case PROPERTY_ID_IGNORERESULT:
+ _rDefault <<= false;
+ break;
+ case PROPERTY_ID_APPLYFILTER:
+ _rDefault <<= false;
+ break;
+ case PROPERTY_ID_ISMODIFIED:
+ _rDefault <<= false;
+ break;
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ _rDefault <<= true;
+ break;
+ case PROPERTY_ID_CANUPDATEINSERTEDROWS:
+ _rDefault <<= true;
+ break;
+ case PROPERTY_ID_RESULTSETTYPE:
+ _rDefault <<= ResultSetType::SCROLL_INSENSITIVE;
+ break;
+ case PROPERTY_ID_RESULTSETCONCURRENCY:
+ _rDefault <<= ResultSetConcurrency::UPDATABLE;
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ _rDefault <<= FetchDirection::FORWARD;
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ _rDefault <<= static_cast<sal_Int32>(1);
+ break;
+ case PROPERTY_ID_ESCAPE_PROCESSING:
+ _rDefault <<= true;
+ break;
+ case PROPERTY_ID_MAXROWS:
+ _rDefault <<= sal_Int32( 0 );
+ break;
+ case PROPERTY_ID_FILTER:
+ case PROPERTY_ID_HAVING_CLAUSE:
+ case PROPERTY_ID_GROUP_BY:
+ case PROPERTY_ID_ORDER:
+ case PROPERTY_ID_UPDATE_CATALOGNAME:
+ case PROPERTY_ID_UPDATE_SCHEMANAME:
+ case PROPERTY_ID_UPDATE_TABLENAME:
+ _rDefault <<= OUString();
+ break;
+ }
+}
+
+void SAL_CALL ORowSet::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ switch(nHandle)
+ {
+ case PROPERTY_ID_ISMODIFIED:
+ m_bModified = cppu::any2bool(rValue);
+ break;
+ case PROPERTY_ID_FETCHDIRECTION:
+ if( m_nResultSetType == ResultSetType::FORWARD_ONLY)
+ throw Exception("resultsettype is FORWARD_ONLY", nullptr);
+ [[fallthrough]];
+ default:
+ OPropertyStateContainer::setFastPropertyValue_NoBroadcast(nHandle,rValue);
+ }
+
+ if ( ( nHandle == PROPERTY_ID_ACTIVE_CONNECTION )
+ || ( nHandle == PROPERTY_ID_DATASOURCENAME )
+ || ( nHandle == PROPERTY_ID_COMMAND )
+ || ( nHandle == PROPERTY_ID_COMMAND_TYPE )
+ || ( nHandle == PROPERTY_ID_IGNORERESULT )
+ || ( nHandle == PROPERTY_ID_FILTER )
+ || ( nHandle == PROPERTY_ID_HAVING_CLAUSE )
+ || ( nHandle == PROPERTY_ID_GROUP_BY )
+ || ( nHandle == PROPERTY_ID_APPLYFILTER )
+ || ( nHandle == PROPERTY_ID_ORDER )
+ || ( nHandle == PROPERTY_ID_URL )
+ || ( nHandle == PROPERTY_ID_USER )
+ )
+ {
+ m_bCommandFacetsDirty = true;
+ }
+
+
+ switch(nHandle)
+ {
+ case PROPERTY_ID_ACTIVE_CONNECTION:
+ // the new connection
+ {
+ assert(m_aActiveConnection == rValue);
+ Reference< XConnection > xNewConnection(m_aActiveConnection,UNO_QUERY);
+ setActiveConnection(xNewConnection, false);
+ }
+
+ m_bOwnConnection = false;
+ m_bRebuildConnOnExecute = false;
+ break;
+
+ case PROPERTY_ID_DATASOURCENAME:
+ if(!m_xStatement.is())
+ {
+ Reference< XConnection > xNewConn;
+ Any aNewConn;
+ aNewConn <<= xNewConn;
+ setFastPropertyValue(PROPERTY_ID_ACTIVE_CONNECTION, aNewConn);
+ }
+ else
+ m_bRebuildConnOnExecute = true;
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ if(m_pCache)
+ {
+ m_pCache->setFetchSize(m_nFetchSize);
+ fireRowcount();
+ }
+ break;
+ case PROPERTY_ID_URL:
+ // is the connection-to-be-built determined by the url (which is the case if m_aDataSourceName is empty) ?
+ if (m_aDataSourceName.isEmpty())
+ {
+ // are we active at the moment ?
+ if (m_xStatement.is())
+ // yes -> the next execute needs to rebuild our connection because of this new property
+ m_bRebuildConnOnExecute = true;
+ else
+ { // no -> drop our active connection (if we have one) as it doesn't correspond to this new property value anymore
+ Reference< XConnection > xNewConn;
+ Any aNewConn;
+ aNewConn <<= xNewConn;
+ setFastPropertyValue(PROPERTY_ID_ACTIVE_CONNECTION, aNewConn);
+ }
+ }
+ m_bOwnConnection = true;
+ break;
+ case PROPERTY_ID_TYPEMAP:
+ m_xTypeMap.set(m_aTypeMap, css::uno::UNO_QUERY);
+ break;
+ case PROPERTY_ID_PROPCHANGE_NOTIFY:
+ m_bPropChangeNotifyEnabled = ::cppu::any2bool(rValue);
+ break;
+ default:
+ break;
+ }
+}
+
+void SAL_CALL ORowSet::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const
+{
+ if(m_pCache)
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_ISMODIFIED:
+ rValue <<= m_bModified;
+ break;
+ case PROPERTY_ID_ISNEW:
+ rValue <<= m_bNew;
+ break;
+ case PROPERTY_ID_PRIVILEGES:
+ rValue <<= m_pCache->m_nPrivileges;
+ break;
+ case PROPERTY_ID_ACTIVE_CONNECTION:
+ rValue <<= m_xActiveConnection;
+ break;
+ case PROPERTY_ID_TYPEMAP:
+ rValue <<= m_xTypeMap;
+ break;
+ default:
+ ORowSetBase::getFastPropertyValue(rValue,nHandle);
+ }
+ }
+ else
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_ACTIVE_CONNECTION:
+ rValue <<= m_xActiveConnection;
+ break;
+ case PROPERTY_ID_TYPEMAP:
+ rValue <<= m_xTypeMap;
+ break;
+ case PROPERTY_ID_PROPCHANGE_NOTIFY:
+ rValue <<= m_bPropChangeNotifyEnabled;
+ break;
+ default:
+ ORowSetBase::getFastPropertyValue(rValue,nHandle);
+ }
+ }
+}
+
+// css::XTypeProvider
+Sequence< Type > SAL_CALL ORowSet::getTypes()
+{
+ OTypeCollection aTypes(cppu::UnoType<XPropertySet>::get(),
+ cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XMultiPropertySet>::get(),
+ ::comphelper::concatSequences(ORowSet_BASE1::getTypes(),ORowSetBase::getTypes()));
+ return aTypes.getTypes();
+}
+
+Sequence< sal_Int8 > SAL_CALL ORowSet::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// css::XInterface
+Any SAL_CALL ORowSet::queryInterface( const Type & rType )
+{
+ return ORowSet_BASE1::queryInterface( rType);
+}
+
+void SAL_CALL ORowSet::acquire() noexcept
+{
+ ORowSet_BASE1::acquire();
+}
+
+void SAL_CALL ORowSet::release() noexcept
+{
+ ORowSet_BASE1::release();
+}
+
+// css::XUnoTunnel
+sal_Int64 SAL_CALL ORowSet::getSomething( const Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+const Sequence< sal_Int8 > & ORowSet::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit s_Id;
+ return s_Id.getSeq();
+}
+
+// css::XAggregation
+Any SAL_CALL ORowSet::queryAggregation( const Type& rType )
+{
+ Any aRet(ORowSetBase::queryInterface(rType));
+ if (!aRet.hasValue())
+ aRet = ORowSet_BASE1::queryAggregation(rType);
+ return aRet;
+}
+
+// css::XServiceInfo
+OUString SAL_CALL ORowSet::getImplementationName()
+{
+ return "com.sun.star.comp.dba.ORowSet";
+}
+
+sal_Bool SAL_CALL ORowSet::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > SAL_CALL ORowSet::getSupportedServiceNames()
+{
+ return { SERVICE_SDBC_RESULTSET, SERVICE_SDBC_ROWSET, SERVICE_SDBCX_RESULTSET,
+ SERVICE_SDB_RESULTSET, SERVICE_SDB_ROWSET };
+}
+
+// OComponentHelper
+void SAL_CALL ORowSet::disposing()
+{
+ OPropertyStateContainer::disposing();
+
+ MutexGuard aGuard(m_aMutex);
+ EventObject aDisposeEvent;
+ aDisposeEvent.Source = static_cast< XComponent* >(this);
+ m_aRowsetListeners.disposeAndClear( aDisposeEvent );
+ m_aApproveListeners.disposeAndClear( aDisposeEvent );
+ m_aRowsChangeListener.disposeAndClear( aDisposeEvent );
+
+ freeResources( true );
+
+ // remove myself as dispose listener
+ Reference< XComponent > xComponent(m_xActiveConnection, UNO_QUERY);
+ if (xComponent.is())
+ {
+ Reference<XEventListener> xEvt;
+ query_aggregation(this,xEvt);
+ xComponent->removeEventListener(xEvt);
+ }
+
+ m_aActiveConnection = Any(); // the any contains a reference too
+ if(m_bOwnConnection)
+ ::comphelper::disposeComponent(m_xActiveConnection);
+ m_xActiveConnection = nullptr;
+
+
+ ORowSetBase::disposing();
+}
+
+void ORowSet::freeResources( bool _bComplete )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ // free all clones
+ for (auto const& clone : m_aClones)
+ {
+ Reference< XComponent > xComp(clone.get(), UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ }
+ m_aClones.clear();
+
+ doCancelModification();
+
+ m_aBookmark = Any();
+ m_bBeforeFirst = true;
+ m_bAfterLast = false;
+ m_bNew = false;
+ m_bModified = false;
+ m_bIsInsertRow = false;
+ m_bLastKnownRowCountFinal = false;
+ m_nLastKnownRowCount = 0;
+
+ if ( !_bComplete )
+ return;
+
+ // the columns must be disposed before the querycomposer is disposed because
+ // their owner can be the composer
+ TDataColumns().swap(m_aDataColumns);// clear and resize capacity
+ std::vector<bool>().swap(m_aReadOnlyDataColumns);
+
+ m_xColumns = nullptr;
+ if ( m_pColumns )
+ m_pColumns->disposing();
+ // dispose the composer to avoid that everybody knows that the querycomposer is eol
+ try { ::comphelper::disposeComponent( m_xComposer ); }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ m_xComposer = nullptr;
+ }
+
+ // let our warnings container forget the reference to the (possibly disposed) old result set
+ m_aWarnings.setExternalWarnings( nullptr );
+
+ m_pCache.reset();
+
+ impl_resetTables_nothrow();
+
+ m_xStatement = nullptr;
+ m_xTypeMap = nullptr;
+
+ if ( m_aOldRow.is() )
+ m_aOldRow->clearRow();
+
+ impl_disposeParametersContainer_nothrow();
+
+ m_bCommandFacetsDirty = true;
+}
+
+void ORowSet::setActiveConnection( Reference< XConnection > const & _rxNewConn, bool _bFireEvent )
+{
+ if (_rxNewConn.get() == m_xActiveConnection.get())
+ // nothing to do
+ return;
+
+ // remove the event listener for the old connection
+ Reference< XComponent > xComponent(m_xActiveConnection, UNO_QUERY);
+ if (xComponent.is())
+ {
+ Reference<XEventListener> xListener;
+ query_aggregation(this, xListener);
+ xComponent->removeEventListener(xListener);
+ }
+
+ // if we owned the connection, remember it for later disposing
+ if(m_bOwnConnection)
+ m_xOldConnection = m_xActiveConnection;
+
+ // for firing the PropertyChangeEvent
+ sal_Int32 nHandle = PROPERTY_ID_ACTIVE_CONNECTION;
+ Any aOldConnection; aOldConnection <<= m_xActiveConnection;
+ Any aNewConnection; aNewConnection <<= _rxNewConn;
+
+ // set the new connection
+ m_xActiveConnection = _rxNewConn;
+ if (m_xActiveConnection.is())
+ m_aActiveConnection <<= m_xActiveConnection;
+ else
+ m_aActiveConnection.clear();
+
+ // fire the event
+ if (_bFireEvent)
+ fire(&nHandle, &aNewConnection, &aOldConnection, 1, false);
+
+ // register as event listener for the new connection
+ xComponent.set(m_xActiveConnection,UNO_QUERY);
+ if (xComponent.is())
+ {
+ Reference<XEventListener> xListener;
+ query_aggregation(this, xListener);
+ xComponent->addEventListener(xListener);
+ }
+}
+
+// css::XEventListener
+void SAL_CALL ORowSet::disposing( const css::lang::EventObject& Source )
+{
+ // close rowset because the connection is going to be deleted (someone told me :-)
+ Reference<XConnection> xCon(Source.Source,UNO_QUERY);
+ if(m_xActiveConnection == xCon)
+ {
+ close();
+ {
+ MutexGuard aGuard( m_aMutex );
+ Reference< XConnection > xXConnection;
+ setActiveConnection( xXConnection );
+ }
+ }
+}
+
+// XCloseable
+void SAL_CALL ORowSet::close( )
+{
+ {
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+ }
+ // additionals things to set
+ freeResources( true );
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* ORowSet::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& SAL_CALL ORowSet::getInfoHelper()
+{
+ return *::comphelper::OPropertyArrayUsageHelper<ORowSet>::getArrayHelper();
+}
+
+void ORowSet::updateValue(sal_Int32 columnIndex,const ORowSetValue& x)
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkUpdateConditions(columnIndex);
+ checkUpdateIterator();
+
+ ORowSetValueVector::Vector& rRow = **m_aCurrentRow;
+ ORowSetNotifier aNotify(this, std::vector(rRow));
+ m_pCache->updateValue(columnIndex,x,rRow,aNotify.getChangedColumns());
+ m_bModified = m_bModified || !aNotify.getChangedColumns().empty();
+ aNotify.firePropertyChange();
+}
+
+// XRowUpdate
+void SAL_CALL ORowSet::updateNull( sal_Int32 columnIndex )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkUpdateConditions(columnIndex);
+ checkUpdateIterator();
+
+ ORowSetValueVector::Vector& rRow = **m_aCurrentRow;
+ ORowSetNotifier aNotify(this, std::vector(rRow));
+ m_pCache->updateNull(columnIndex,rRow,aNotify.getChangedColumns());
+ m_bModified = m_bModified || !aNotify.getChangedColumns().empty();
+ aNotify.firePropertyChange();
+}
+
+void SAL_CALL ORowSet::updateBoolean( sal_Int32 columnIndex, sal_Bool x )
+{
+ updateValue(columnIndex, static_cast<bool>(x));
+}
+
+void SAL_CALL ORowSet::updateByte( sal_Int32 columnIndex, sal_Int8 x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateShort( sal_Int32 columnIndex, sal_Int16 x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateInt( sal_Int32 columnIndex, sal_Int32 x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateLong( sal_Int32 columnIndex, sal_Int64 x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateFloat( sal_Int32 columnIndex, float x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateDouble( sal_Int32 columnIndex, double x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateString( sal_Int32 columnIndex, const OUString& x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateBytes( sal_Int32 columnIndex, const Sequence< sal_Int8 >& x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateDate( sal_Int32 columnIndex, const css::util::Date& x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateTime( sal_Int32 columnIndex, const css::util::Time& x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x )
+{
+ updateValue(columnIndex,x);
+}
+
+void SAL_CALL ORowSet::updateBinaryStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkUpdateConditions(columnIndex);
+ checkUpdateIterator();
+
+ {
+ Sequence<sal_Int8> aSeq;
+ if(x.is())
+ x->readBytes(aSeq,length);
+ updateValue(columnIndex,aSeq);
+ }
+}
+
+void SAL_CALL ORowSet::updateCharacterStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkUpdateConditions(columnIndex);
+ checkUpdateIterator();
+ ORowSetValueVector::Vector& rRow = **m_aCurrentRow;
+ ORowSetNotifier aNotify(this, std::vector(rRow));
+ m_pCache->updateCharacterStream(columnIndex,x,length,rRow,aNotify.getChangedColumns());
+ m_bModified = m_bModified || !aNotify.getChangedColumns().empty();
+ aNotify.firePropertyChange();
+}
+
+void SAL_CALL ORowSet::updateObject( sal_Int32 columnIndex, const Any& x )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkUpdateConditions(columnIndex);
+ checkUpdateIterator();
+
+ Any aNewValue = x;
+
+ if ( m_pColumns )
+ {
+ Reference<XPropertySet> xColumn(m_pColumns->getByIndex(columnIndex-1),UNO_QUERY);
+ sal_Int32 nColType = 0;
+ xColumn->getPropertyValue(PROPERTY_TYPE) >>= nColType;
+ switch( nColType )
+ {
+ case DataType::DATE:
+ case DataType::TIME:
+ case DataType::TIMESTAMP:
+ {
+ double nValue = 0;
+ if ( x >>= nValue )
+ {
+ if ( DataType::TIMESTAMP == nColType )
+ aNewValue <<= dbtools::DBTypeConversion::toDateTime( nValue );
+ else if ( DataType::DATE == nColType )
+ aNewValue <<= dbtools::DBTypeConversion::toDate( nValue );
+ else
+ aNewValue <<= dbtools::DBTypeConversion::toTime( nValue );
+ }
+ break;
+ }
+ }
+ }
+
+ if (!::dbtools::implUpdateObject(this, columnIndex, aNewValue))
+ { // there is no other updateXXX call which can handle the value in x
+ ORowSetValueVector::Vector& rRow = **m_aCurrentRow;
+ ORowSetNotifier aNotify(this, std::vector(rRow));
+ m_pCache->updateObject(columnIndex,aNewValue,rRow,aNotify.getChangedColumns());
+ m_bModified = m_bModified || !aNotify.getChangedColumns().empty();
+ aNotify.firePropertyChange();
+ }
+}
+
+void SAL_CALL ORowSet::updateNumericObject( sal_Int32 columnIndex, const Any& x, sal_Int32 /*scale*/ )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkUpdateConditions(columnIndex);
+ checkUpdateIterator();
+ ORowSetValueVector::Vector& rRow = **m_aCurrentRow;
+ ORowSetNotifier aNotify(this, std::vector(rRow));
+ m_pCache->updateNumericObject(columnIndex,x,rRow,aNotify.getChangedColumns());
+ m_bModified = m_bModified || !aNotify.getChangedColumns().empty();
+ aNotify.firePropertyChange();
+}
+
+namespace
+{
+ class ProtectFlag
+ {
+ bool& m_rInsertingRow;
+ public:
+ explicit ProtectFlag(bool& rInsertingRow)
+ : m_rInsertingRow(rInsertingRow)
+ {
+ if (m_rInsertingRow)
+ {
+ throw std::runtime_error("recursion in insertRow");
+ }
+ m_rInsertingRow = true;
+ }
+ ~ProtectFlag()
+ {
+ m_rInsertingRow = false;
+ }
+ };
+}
+
+// XResultSetUpdate
+void SAL_CALL ORowSet::insertRow()
+{
+ ProtectFlag aFlagControl(m_bInsertingRow);
+
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+ // insertRow is not allowed when
+ // standing not on the insert row nor
+ // when the row isn't modified
+ // or the concurrency is read only
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+
+ if(!m_pCache || !m_bNew || !m_bModified || m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY)
+ throwFunctionSequenceException(*this);
+
+ // remember old value for fire
+ bool bOld = m_bNew;
+
+ ORowSetRow aOldValues;
+ if ( !m_aCurrentRow.isNull() )
+ aOldValues = new ORowSetValueVector( *(*m_aCurrentRow));
+ Sequence<Any> aChangedBookmarks;
+ RowsChangeEvent aEvt(*this,RowChangeAction::INSERT,1,aChangedBookmarks);
+ notifyAllListenersRowBeforeChange(aGuard,aEvt);
+
+ std::vector< Any > aBookmarks;
+ bool bInserted = m_pCache->insertRow(aBookmarks);
+
+ // make sure that our row is set to the new inserted row before clearing the insert flags in the cache
+ m_pCache->resetInsertRow(bInserted);
+
+ // notification order
+ // - column values
+ setCurrentRow( false, true, aOldValues, aGuard ); // we don't move here
+
+ // read-only flag restored
+ impl_restoreDataColumnsWriteable_throw();
+
+ // - rowChanged
+ notifyAllListenersRowChanged(aGuard,aEvt);
+
+ if ( !aBookmarks.empty() )
+ {
+ RowsChangeEvent aUpEvt(*this,RowChangeAction::UPDATE,aBookmarks.size(),comphelper::containerToSequence(aBookmarks));
+ notifyAllListenersRowChanged(aGuard,aUpEvt);
+ }
+
+ // - IsModified
+ if(!m_bModified)
+ fireProperty(PROPERTY_ID_ISMODIFIED,false,true);
+ OSL_ENSURE( !m_bModified, "ORowSet::insertRow: just updated, but _still_ modified?" );
+
+ // - IsNew
+ if(m_bNew != bOld)
+ fireProperty(PROPERTY_ID_ISNEW,m_bNew,bOld);
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+}
+
+void SAL_CALL ORowSet::updateRow( )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+ // not allowed when standing on insert row
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+ if ( !m_pCache || m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY || m_bNew || ((m_pCache->m_nPrivileges & Privilege::UPDATE ) != Privilege::UPDATE) )
+ throwFunctionSequenceException(*this);
+
+
+ if(!m_bModified)
+ return;
+
+ ORowSetRow aOldValues;
+ if ( !m_aCurrentRow.isNull() )
+ aOldValues = new ORowSetValueVector( *(*m_aCurrentRow) );
+
+ Sequence<Any> aChangedBookmarks;
+ RowsChangeEvent aEvt(*this,RowChangeAction::UPDATE,1,aChangedBookmarks);
+ notifyAllListenersRowBeforeChange(aGuard,aEvt);
+
+ std::vector< Any > aBookmarks;
+ m_pCache->updateRow(m_aCurrentRow.operator ->(),aBookmarks);
+ if ( !aBookmarks.empty() )
+ aEvt.Bookmarks = comphelper::containerToSequence(aBookmarks);
+ aEvt.Rows += aBookmarks.size();
+ m_aBookmark = m_pCache->getBookmark();
+ m_aCurrentRow = m_pCache->m_aMatrixIter;
+ m_bIsInsertRow = false;
+ if ( m_pCache->m_aMatrixIter != m_pCache->getEnd() && (*m_pCache->m_aMatrixIter).is() )
+ {
+ if ( m_pCache->isResultSetChanged() )
+ {
+ impl_rebuild_throw(aGuard);
+ }
+ else
+ {
+ m_aOldRow->setRow(new ORowSetValueVector(*(*m_aCurrentRow)));
+
+ // notification order
+ // - column values
+ ORowSetBase::firePropertyChange(aOldValues);
+ }
+ // - rowChanged
+ notifyAllListenersRowChanged(aGuard,aEvt);
+
+ // - IsModified
+ if(!m_bModified)
+ fireProperty(PROPERTY_ID_ISMODIFIED,false,true);
+ OSL_ENSURE( !m_bModified, "ORowSet::updateRow: just updated, but _still_ modified?" );
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+ else if ( !m_bAfterLast ) // the update went wrong
+ {
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_UPDATE_FAILED ), StandardSQLState::INVALID_CURSOR_POSITION, *this );
+ }
+}
+
+void SAL_CALL ORowSet::deleteRow( )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ if ( m_bBeforeFirst || m_bAfterLast )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_DELETE_BEFORE_AFTER ), StandardSQLState::INVALID_CURSOR_POSITION, *this );
+ if ( m_bNew )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_DELETE_INSERT_ROW ), StandardSQLState::INVALID_CURSOR_POSITION, *this );
+ if ( m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_RESULT_IS_READONLY ), StandardSQLState::FUNCTION_SEQUENCE_ERROR, *this );
+ if ( ( m_pCache->m_nPrivileges & Privilege::DELETE ) != Privilege::DELETE )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_DELETE_PRIVILEGE ), StandardSQLState::FUNCTION_SEQUENCE_ERROR, *this );
+ if ( rowDeleted() )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_ROW_ALREADY_DELETED ), StandardSQLState::FUNCTION_SEQUENCE_ERROR, *this );
+
+ // this call position the cache indirect
+ Any aBookmarkToDelete( m_aBookmark );
+ positionCache( MOVE_NONE );
+ sal_Int32 nDeletePosition = m_pCache->getRow();
+
+ notifyRowSetAndClonesRowDelete( aBookmarkToDelete );
+
+ ORowSetRow aOldValues;
+ if ( m_pCache->m_aMatrixIter != m_pCache->getEnd() && m_pCache->m_aMatrixIter->is() )
+ aOldValues = new ORowSetValueVector( *(*(m_pCache->m_aMatrixIter)) );
+
+ Sequence<Any> aChangedBookmarks;
+ RowsChangeEvent aEvt(*this,RowChangeAction::DELETE,1,aChangedBookmarks);
+ notifyAllListenersRowBeforeChange(aGuard,aEvt);
+
+ m_pCache->deleteRow();
+ notifyRowSetAndClonesRowDeleted( aBookmarkToDelete, nDeletePosition );
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ // notification order
+ // - rowChanged
+ notifyAllListenersRowChanged(aGuard,aEvt);
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire( );
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+}
+
+void ORowSet::implCancelRowUpdates( bool _bNotifyModified )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ if ( m_bBeforeFirst || m_bAfterLast || rowDeleted() )
+ return; // nothing to do so return
+
+ checkCache();
+ // cancelRowUpdates is not allowed when:
+ // - standing on the insert row
+ // - the concurrency is read only
+ // - the current row is deleted
+ if ( m_bNew || m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY )
+ throwFunctionSequenceException(*this);
+
+ positionCache( MOVE_NONE );
+
+ ORowSetRow aOldValues;
+ if ( !m_bModified && _bNotifyModified && !m_aCurrentRow.isNull() )
+ aOldValues = new ORowSetValueVector( *(*m_aCurrentRow) );
+
+ m_pCache->cancelRowUpdates();
+
+ m_aBookmark = m_pCache->getBookmark();
+ m_aCurrentRow = m_pCache->m_aMatrixIter;
+ m_bIsInsertRow = false;
+
+ // notification order
+ // IsModified
+ if( !m_bModified && _bNotifyModified )
+ {
+ // - column values
+ ORowSetBase::firePropertyChange(aOldValues);
+ fireProperty(PROPERTY_ID_ISMODIFIED,false,true);
+ }
+}
+
+void SAL_CALL ORowSet::cancelRowUpdates( )
+{
+ implCancelRowUpdates( true );
+}
+
+void SAL_CALL ORowSet::addRowSetListener( const Reference< XRowSetListener >& listener )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+ if(listener.is())
+ m_aRowsetListeners.addInterface(listener);
+}
+
+void SAL_CALL ORowSet::removeRowSetListener( const Reference< XRowSetListener >& listener )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+ if(listener.is())
+ m_aRowsetListeners.removeInterface(listener);
+}
+
+void ORowSet::notifyAllListeners(::osl::ResettableMutexGuard& _rGuard)
+{
+ EventObject aEvt(*m_pMySelf);
+ _rGuard.clear();
+ m_aRowsetListeners.notifyEach( &XRowSetListener::rowSetChanged, aEvt );
+ _rGuard.reset();
+}
+
+void ORowSet::notifyAllListenersCursorMoved(::osl::ResettableMutexGuard& _rGuard)
+{
+ EventObject aEvt(*m_pMySelf);
+ _rGuard.clear();
+ m_aRowsetListeners.notifyEach( &XRowSetListener::cursorMoved, aEvt );
+ _rGuard.reset();
+}
+
+void ORowSet::notifyAllListenersRowChanged(::osl::ResettableMutexGuard& _rGuard, const RowsChangeEvent& aEvt)
+{
+ _rGuard.clear();
+ m_aRowsetListeners.notifyEach( &XRowSetListener::rowChanged, static_cast<EventObject>(aEvt) );
+ m_aRowsChangeListener.notifyEach( &XRowsChangeListener::rowsChanged, aEvt );
+ _rGuard.reset();
+}
+
+bool ORowSet::notifyAllListenersCursorBeforeMove(::osl::ResettableMutexGuard& _rGuard)
+{
+ EventObject aEvt(*m_pMySelf);
+ std::vector< Reference< css::sdb::XRowSetApproveListener > > aListenerSeq = m_aApproveListeners.getElements();
+ _rGuard.clear();
+ bool bCheck = std::all_of(aListenerSeq.rbegin(), aListenerSeq.rend(),
+ [&aEvt](Reference<css::sdb::XRowSetApproveListener>& rxItem) {
+ try
+ {
+ return static_cast<bool>(rxItem->approveCursorMove(aEvt));
+ }
+ catch( RuntimeException& )
+ {
+ return true;
+ }
+ });
+ _rGuard.reset();
+ return bCheck;
+}
+
+void ORowSet::notifyAllListenersRowBeforeChange(::osl::ResettableMutexGuard& _rGuard,const RowChangeEvent &aEvt)
+{
+ std::vector< Reference< css::sdb::XRowSetApproveListener > > aListenerSeq = m_aApproveListeners.getElements();
+ _rGuard.clear();
+ bool bCheck = std::all_of(aListenerSeq.rbegin(), aListenerSeq.rend(),
+ [&aEvt](Reference<css::sdb::XRowSetApproveListener>& rxItem) {
+ try
+ {
+ return static_cast<bool>(rxItem->approveRowChange(aEvt));
+ }
+ catch( RuntimeException& )
+ {
+ return true;
+ }
+ });
+ _rGuard.reset();
+
+ if ( !bCheck )
+ m_aErrors.raiseTypedException( sdb::ErrorCondition::ROW_SET_OPERATION_VETOED, *this, ::cppu::UnoType< RowSetVetoException >::get() );
+}
+
+void ORowSet::fireRowcount()
+{
+ sal_Int32 nCurrentRowCount( impl_getRowCount() );
+ bool bCurrentRowCountFinal( m_pCache->m_bRowCountFinal );
+
+ if ( m_nLastKnownRowCount != nCurrentRowCount )
+ {
+ sal_Int32 nHandle = PROPERTY_ID_ROWCOUNT;
+ Any aNew,aOld;
+ aNew <<= nCurrentRowCount; aOld <<= m_nLastKnownRowCount;
+ fire(&nHandle,&aNew,&aOld,1,false);
+ m_nLastKnownRowCount = nCurrentRowCount;
+ }
+ if ( !m_bLastKnownRowCountFinal && ( m_bLastKnownRowCountFinal != bCurrentRowCountFinal ) )
+ {
+ sal_Int32 nHandle = PROPERTY_ID_ISROWCOUNTFINAL;
+ Any aNew,aOld;
+ aNew <<= bCurrentRowCountFinal;
+ aOld <<= m_bLastKnownRowCountFinal;
+ fire(&nHandle,&aNew,&aOld,1,false);
+ m_bLastKnownRowCountFinal = bCurrentRowCountFinal;
+ }
+}
+
+void SAL_CALL ORowSet::moveToInsertRow( )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+ checkPositioningAllowed();
+ if ( ( m_pCache->m_nPrivileges & Privilege::INSERT ) != Privilege::INSERT )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_INSERT_PRIVILEGE ), StandardSQLState::GENERAL_ERROR, *this );
+
+ if ( !notifyAllListenersCursorBeforeMove( aGuard ) )
+ return;
+
+ // remember old value for fire
+ ORowSetRow aOldValues;
+ if ( rowDeleted() )
+ {
+ positionCache( MOVE_FORWARD );
+ m_pCache->next();
+ setCurrentRow( true, false, aOldValues, aGuard);
+ }
+ else
+ positionCache( MOVE_NONE );
+
+ // check before because the resultset could be empty
+ if ( !m_bBeforeFirst
+ && !m_bAfterLast
+ && m_pCache->m_aMatrixIter != m_pCache->getEnd()
+ && m_pCache->m_aMatrixIter->is()
+ )
+ aOldValues = new ORowSetValueVector( *(*(m_pCache->m_aMatrixIter)) );
+
+ const bool bNewState = m_bNew;
+ const bool bModState = m_bModified;
+
+ m_pCache->moveToInsertRow();
+ m_aCurrentRow = m_pCache->m_aInsertRow;
+ m_bIsInsertRow = true;
+
+ // set read-only flag to false
+ impl_setDataColumnsWriteable_throw();
+
+ // notification order
+ // - column values
+ ORowSetBase::firePropertyChange(aOldValues);
+
+ // - cursorMoved
+ notifyAllListenersCursorMoved(aGuard);
+
+ // - IsModified
+ if ( bModState != m_bModified )
+ fireProperty( PROPERTY_ID_ISMODIFIED, m_bModified, bModState );
+
+ // - IsNew
+ if ( bNewState != m_bNew )
+ fireProperty( PROPERTY_ID_ISNEW, m_bNew, bNewState );
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+}
+
+void ORowSet::impl_setDataColumnsWriteable_throw()
+{
+ impl_restoreDataColumnsWriteable_throw();
+ m_aReadOnlyDataColumns.resize(m_aDataColumns.size(),false);
+ std::vector<bool, std::allocator<bool> >::iterator aReadIter = m_aReadOnlyDataColumns.begin();
+ for (auto const& dataColumn : m_aDataColumns)
+ {
+ bool bReadOnly = false;
+ dataColumn->getPropertyValue(PROPERTY_ISREADONLY) >>= bReadOnly;
+ *aReadIter = bReadOnly;
+
+ dataColumn->setPropertyValue(PROPERTY_ISREADONLY,Any(false));
+ ++aReadIter;
+ }
+}
+
+void ORowSet::impl_restoreDataColumnsWriteable_throw()
+{
+ assert(m_aDataColumns.size() == m_aReadOnlyDataColumns.size() || m_aReadOnlyDataColumns.size() == 0 );
+ TDataColumns::const_iterator aIter = m_aDataColumns.begin();
+ for (bool readOnlyDataColumn : m_aReadOnlyDataColumns)
+ {
+ (*aIter)->setPropertyValue(PROPERTY_ISREADONLY, Any(readOnlyDataColumn) );
+ ++aIter;
+ }
+ m_aReadOnlyDataColumns.clear();
+}
+
+void SAL_CALL ORowSet::moveToCurrentRow( )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+ checkPositioningAllowed();
+
+ if ( !m_pCache->m_bNew && !m_bModified )
+ // nothing to do if we're not on the insertion row, and not modified otherwise
+ return;
+
+ if ( rowDeleted() )
+ // this would perhaps even justify a RuntimeException...
+ // if the current row is deleted, then no write access to this row should be possible. So,
+ // m_bModified should be true. Also, as soon as somebody calls moveToInsertRow,
+ // our current row should not be deleted anymore. So, we should not have survived the above
+ // check "if ( !m_pCache->m_bNew && !m_bModified )"
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_ROW_ALREADY_DELETED ), StandardSQLState::FUNCTION_SEQUENCE_ERROR, *this );
+
+ if ( !notifyAllListenersCursorBeforeMove( aGuard ) )
+ return;
+
+ positionCache( MOVE_NONE_REFRESH );
+
+ ORowSetNotifier aNotifier( this );
+
+ // notification order
+ // - cursorMoved
+ notifyAllListenersCursorMoved(aGuard);
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire();
+}
+
+// XRow
+sal_Bool SAL_CALL ORowSet::wasNull( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ return ( m_pCache && isInsertRow() ) ? (**m_pCache->m_aInsertRow)[m_nLastColumnIndex].isNull() : ORowSetBase::wasNull();
+}
+
+const ORowSetValue& ORowSet::getInsertValue(sal_Int32 columnIndex)
+{
+ checkCache();
+
+ if ( m_pCache && isInsertRow() )
+ {
+ m_nLastColumnIndex = columnIndex;
+ return (**m_pCache->m_aInsertRow)[m_nLastColumnIndex];
+ }
+ return getValue(columnIndex);
+}
+
+OUString SAL_CALL ORowSet::getString( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getString();
+}
+
+sal_Bool SAL_CALL ORowSet::getBoolean( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getBool();
+}
+
+sal_Int8 SAL_CALL ORowSet::getByte( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getInt8();
+}
+
+sal_Int16 SAL_CALL ORowSet::getShort( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getInt16();
+}
+
+sal_Int32 SAL_CALL ORowSet::getInt( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getInt32();
+}
+
+sal_Int64 SAL_CALL ORowSet::getLong( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getLong();
+}
+
+float SAL_CALL ORowSet::getFloat( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getFloat();
+}
+
+double SAL_CALL ORowSet::getDouble( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getDouble();
+}
+
+Sequence< sal_Int8 > SAL_CALL ORowSet::getBytes( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getSequence();
+}
+
+css::util::Date SAL_CALL ORowSet::getDate( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getDate();
+}
+
+css::util::Time SAL_CALL ORowSet::getTime( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getTime();
+}
+
+css::util::DateTime SAL_CALL ORowSet::getTimestamp( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).getDateTime();
+}
+
+Reference< css::io::XInputStream > SAL_CALL ORowSet::getBinaryStream( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ if ( m_pCache && isInsertRow() )
+ {
+ checkCache();
+ m_nLastColumnIndex = columnIndex;
+ return new ::comphelper::SequenceInputStream((**m_pCache->m_aInsertRow)[m_nLastColumnIndex].getSequence());
+ }
+
+ return ORowSetBase::getBinaryStream(columnIndex);
+}
+
+Reference< css::io::XInputStream > SAL_CALL ORowSet::getCharacterStream( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ if(m_pCache && isInsertRow() )
+ {
+ checkCache();
+ m_nLastColumnIndex = columnIndex;
+ return new ::comphelper::SequenceInputStream((**m_pCache->m_aInsertRow)[m_nLastColumnIndex].getSequence());
+ }
+
+ return ORowSetBase::getCharacterStream(columnIndex);
+}
+
+Any SAL_CALL ORowSet::getObject( sal_Int32 columnIndex, const Reference< XNameAccess >& /*typeMap*/ )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getInsertValue(columnIndex).makeAny();
+}
+
+Reference< XRef > SAL_CALL ORowSet::getRef( sal_Int32 /*columnIndex*/ )
+{
+ return Reference< XRef >();
+}
+
+Reference< XBlob > SAL_CALL ORowSet::getBlob( sal_Int32 columnIndex )
+{
+ if ( m_pCache && isInsertRow() )
+ {
+ checkCache();
+ m_nLastColumnIndex = columnIndex;
+ return new ::connectivity::BlobHelper((**m_pCache->m_aInsertRow)[m_nLastColumnIndex].getSequence());
+ }
+ return ORowSetBase::getBlob(columnIndex);
+}
+
+Reference< XClob > SAL_CALL ORowSet::getClob( sal_Int32 columnIndex )
+{
+ return Reference< XClob >(getInsertValue(columnIndex).makeAny(),UNO_QUERY);
+}
+
+Reference< XArray > SAL_CALL ORowSet::getArray( sal_Int32 /*columnIndex*/ )
+{
+ return Reference< XArray >();
+}
+
+void SAL_CALL ORowSet::executeWithCompletion( const Reference< XInteractionHandler >& _rxHandler )
+{
+ if (!_rxHandler.is())
+ execute();
+
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ // tell everybody that we will change the result set
+ approveExecution();
+
+ ResettableMutexGuard aGuard( m_aMutex );
+
+ try
+ {
+ freeResources( m_bCommandFacetsDirty );
+
+ // calc the connection to be used
+ if (m_xActiveConnection.is() && m_bRebuildConnOnExecute)
+ {
+ // there was a setProperty(ActiveConnection), but a setProperty(DataSource) _after_ that, too
+ Reference< XConnection > xXConnection;
+ setActiveConnection( xXConnection );
+ }
+ calcConnection( _rxHandler );
+ m_bRebuildConnOnExecute = false;
+
+ Reference< XSingleSelectQueryComposer > xComposer = getCurrentSettingsComposer( this, m_aContext, nullptr );
+ Reference<XParametersSupplier> xParameters(xComposer, UNO_QUERY);
+
+ Reference<XIndexAccess> xParamsAsIndicies = xParameters.is() ? xParameters->getParameters() : Reference<XIndexAccess>();
+ const sal_Int32 nParamCount = xParamsAsIndicies.is() ? xParamsAsIndicies->getCount() : 0;
+ if ( m_aParametersSet.size() < o3tl::make_unsigned(nParamCount) )
+ m_aParametersSet.resize( nParamCount ,false);
+
+ ::dbtools::askForParameters( xComposer, this, m_xActiveConnection, _rxHandler,m_aParametersSet );
+ }
+ // ensure that only the allowed exceptions leave this block
+ catch(SQLException&)
+ {
+ throw;
+ }
+ catch(RuntimeException&)
+ {
+ throw;
+ }
+ catch(Exception const &)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "ORowSet::executeWithCompletion: caught an unexpected exception type while filling in the parameters");
+ }
+
+ // we're done with the parameters, now for the real execution
+
+ // do the real execute
+ execute_NoApprove_NoNewConn(aGuard);
+}
+
+Reference< XIndexAccess > SAL_CALL ORowSet::getParameters( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ if ( m_bCommandFacetsDirty )
+ // need to rebuild the parameters, since some property which contributes to the
+ // complete command, and thus the parameters, changed
+ impl_disposeParametersContainer_nothrow();
+
+ if ( !m_pParameters && !m_aCommand.isEmpty() )
+ {
+ try
+ {
+ OUString sNotInterestedIn;
+ impl_initComposer_throw( sNotInterestedIn );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ // our caller could change our parameters at any time
+ m_bParametersDirty = true;
+
+ return m_pParameters;
+}
+
+void ORowSet::approveExecution()
+{
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+ EventObject aEvt(*this);
+
+ OInterfaceIteratorHelper3 aApproveIter( m_aApproveListeners );
+ while ( aApproveIter.hasMoreElements() )
+ {
+ Reference< XRowSetApproveListener > xListener( aApproveIter.next() );
+ try
+ {
+ if ( !xListener->approveRowSetChange( aEvt ) )
+ throw RowSetVetoException();
+ }
+ catch ( const DisposedException& e )
+ {
+ if ( e.Context == xListener )
+ aApproveIter.remove();
+ }
+ catch ( const RuntimeException& ) { throw; }
+ catch ( const RowSetVetoException& ) { throw; }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+}
+
+// XRowSet
+void SAL_CALL ORowSet::execute( )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ // tell everybody that we will change the result set
+ approveExecution();
+
+ ResettableMutexGuard aGuard( m_aMutex );
+ freeResources( m_bCommandFacetsDirty );
+
+ // calc the connection to be used
+ if (m_xActiveConnection.is() && m_bRebuildConnOnExecute) {
+ // there was a setProperty(ActiveConnection), but a setProperty(DataSource) _after_ that, too
+ Reference< XConnection> xXConnection;
+ setActiveConnection( xXConnection );
+ }
+
+ calcConnection(nullptr);
+ m_bRebuildConnOnExecute = false;
+
+ // do the real execute
+ execute_NoApprove_NoNewConn(aGuard);
+}
+
+void ORowSet::setStatementResultSetType( const Reference< XPropertySet >& _rxStatement, sal_Int32 _nDesiredResultSetType, sal_Int32 _nDesiredResultSetConcurrency )
+{
+ OSL_ENSURE( _rxStatement.is(), "ORowSet::setStatementResultSetType: invalid statement - this will crash!" );
+
+ sal_Int32 nResultSetType( _nDesiredResultSetType );
+ sal_Int32 nResultSetConcurrency( _nDesiredResultSetConcurrency );
+
+ // there *might* be a data source setting which tells use to be more defensive with those settings
+ // #i15113#
+ bool bRespectDriverRST = false;
+ Any aSetting;
+ if ( getDataSourceSetting( ::dbaccess::getDataSource( m_xActiveConnection ), "RespectDriverResultSetType", aSetting ) )
+ {
+ OSL_VERIFY( aSetting >>= bRespectDriverRST );
+ }
+
+ if ( bRespectDriverRST )
+ {
+ // try type/concurrency settings with decreasing usefulness, and rely on what the connection claims
+ // to support
+ Reference< XDatabaseMetaData > xMeta( m_xActiveConnection->getMetaData() );
+
+ sal_Int32 nCharacteristics[5][2] =
+ { { ResultSetType::SCROLL_SENSITIVE, ResultSetConcurrency::UPDATABLE },
+ { ResultSetType::SCROLL_INSENSITIVE, ResultSetConcurrency::UPDATABLE },
+ { ResultSetType::SCROLL_SENSITIVE, ResultSetConcurrency::READ_ONLY },
+ { ResultSetType::SCROLL_INSENSITIVE, ResultSetConcurrency::READ_ONLY },
+ { ResultSetType::FORWARD_ONLY, ResultSetConcurrency::READ_ONLY }
+ };
+ sal_Int32 i=0;
+ if ( m_xActiveConnection->getMetaData()->isReadOnly() )
+ i = 2; // if the database is read-only we only should use read-only concurrency
+
+ for ( ; i<5; ++i )
+ {
+ nResultSetType = nCharacteristics[i][0];
+ nResultSetConcurrency = nCharacteristics[i][1];
+
+ // don't try type/concurrency pairs which are more featured than what our caller requested
+ if ( nResultSetType > _nDesiredResultSetType )
+ continue;
+ if ( nResultSetConcurrency > _nDesiredResultSetConcurrency )
+ continue;
+
+ if ( xMeta.is() && xMeta->supportsResultSetConcurrency( nResultSetType, nResultSetConcurrency ) )
+ break;
+ }
+ }
+
+ _rxStatement->setPropertyValue( PROPERTY_RESULTSETTYPE, Any( nResultSetType ) );
+ _rxStatement->setPropertyValue( PROPERTY_RESULTSETCONCURRENCY, Any( nResultSetConcurrency ) );
+}
+
+void ORowSet::impl_ensureStatement_throw()
+{
+ OUString sCommandToExecute;
+ if(m_bCommandFacetsDirty)
+ {
+ impl_initComposer_throw( sCommandToExecute );
+ }
+ else
+ {
+ sCommandToExecute = m_bUseEscapeProcessing ? m_xComposer->getQueryWithSubstitution() : m_aActiveCommand;
+ }
+
+ try
+ {
+ m_xStatement = m_xActiveConnection->prepareStatement( sCommandToExecute );
+ if ( !m_xStatement.is() )
+ {
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_INTERNAL_ERROR ), StandardSQLState::GENERAL_ERROR, *this );
+ }
+
+ Reference< XPropertySet > xStatementProps( m_xStatement, UNO_QUERY_THROW );
+ // set the result set type and concurrency
+ try
+ {
+ xStatementProps->setPropertyValue( PROPERTY_USEBOOKMARKS, Any( true ) );
+ xStatementProps->setPropertyValue( PROPERTY_MAXROWS, Any( m_nMaxRows ) );
+
+ setStatementResultSetType( xStatementProps, m_nResultSetType, m_nResultSetConcurrency );
+ }
+ catch ( const Exception& )
+ {
+ // this exception doesn't matter here because when we catch an exception
+ // then the driver doesn't support this feature
+ }
+ }
+ catch (SQLException& rException)
+ {
+ css::sdbc::SQLException* pLastExceptionInChain = SQLExceptionInfo::getLastException(&rException);
+ assert(pLastExceptionInChain && "will at least be &rException");
+
+ // append information about what we were actually going to execute
+ OUString sInfo(m_sErrorString.replaceFirst("$command$", sCommandToExecute));
+ css::uno::Any aAppend = SQLExceptionInfo::createException(SQLExceptionInfo::TYPE::SQLContext, sInfo, OUString(), 0);
+ pLastExceptionInChain->NextException = aAppend;
+
+ // propagate
+ throw;
+ }
+}
+
+Reference< XResultSet > ORowSet::impl_prepareAndExecute_throw()
+{
+ impl_ensureStatement_throw();
+
+ m_aParameterValueForCache->resize(1);
+ Reference< XParameters > xParam( m_xStatement, UNO_QUERY_THROW );
+ size_t nParamCount( m_pParameters.is() ? m_pParameters->size() : m_aPrematureParamValues->size() );
+ for ( size_t i=1; i<=nParamCount; ++i )
+ {
+ ORowSetValue& rParamValue( getParameterStorage( static_cast<sal_Int32>(i) ) );
+ ::dbtools::setObjectWithInfo( xParam, i, rParamValue.makeAny(), rParamValue.getTypeKind() );
+ m_aParameterValueForCache->push_back(rParamValue);
+ }
+ m_bParametersDirty = false;
+
+ Reference< XResultSet > xResultSet(m_xStatement->executeQuery());
+
+ OUString aComposedUpdateTableName;
+ if ( !m_aUpdateTableName.isEmpty() )
+ aComposedUpdateTableName = composeTableName( m_xActiveConnection->getMetaData(), m_aUpdateCatalogName, m_aUpdateSchemaName, m_aUpdateTableName, false, ::dbtools::EComposeRule::InDataManipulation );
+
+ SAL_INFO("dbaccess", "ORowSet::impl_prepareAndExecute_throw: creating cache" );
+ m_pCache =
+ std::make_shared<ORowSetCache>(xResultSet, m_xComposer.get(), m_aContext, aComposedUpdateTableName,
+ m_bModified, m_bNew, *m_aParameterValueForCache, m_aFilter, m_nMaxRows);
+ if ( m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY )
+ {
+ m_nPrivileges = Privilege::SELECT;
+ m_pCache->m_nPrivileges = Privilege::SELECT;
+ }
+ m_pCache->setFetchSize(m_nFetchSize);
+ m_aCurrentRow = m_pCache->createIterator(this);
+ m_bIsInsertRow = false;
+ m_aOldRow = m_pCache->registerOldRow();
+
+ return xResultSet;
+}
+
+void ORowSet::impl_initializeColumnSettings_nothrow( const Reference< XPropertySet >& _rxTemplateColumn, const Reference< XPropertySet >& _rxRowSetColumn )
+{
+ OSL_ENSURE( _rxTemplateColumn.is() && _rxRowSetColumn.is(),
+ "ORowSet::impl_initializeColumnSettings_nothrow: this will crash!" );
+
+ bool bHaveAnyColumnSetting = false;
+ try
+ {
+ Reference< XPropertySetInfo > xInfo( _rxTemplateColumn->getPropertySetInfo(), UNO_SET_THROW );
+
+ // a number of properties is plain copied
+ const OUString aPropertyNames[] = {
+ OUString(PROPERTY_ALIGN), OUString(PROPERTY_RELATIVEPOSITION), OUString(PROPERTY_WIDTH), OUString(PROPERTY_HIDDEN), OUString(PROPERTY_CONTROLMODEL),
+ OUString(PROPERTY_HELPTEXT), OUString(PROPERTY_CONTROLDEFAULT)
+ };
+ for (const auto & aPropertyName : aPropertyNames)
+ {
+ if ( xInfo->hasPropertyByName( aPropertyName ) )
+ {
+ _rxRowSetColumn->setPropertyValue( aPropertyName, _rxTemplateColumn->getPropertyValue( aPropertyName ) );
+ bHaveAnyColumnSetting = true;
+ }
+ }
+
+ // the format key is slightly more complex
+ sal_Int32 nFormatKey = 0;
+ if( xInfo->hasPropertyByName( PROPERTY_NUMBERFORMAT ) )
+ {
+ _rxTemplateColumn->getPropertyValue( PROPERTY_NUMBERFORMAT ) >>= nFormatKey;
+ bHaveAnyColumnSetting = true;
+ }
+ if ( !nFormatKey && m_xNumberFormatTypes.is() )
+ nFormatKey = ::dbtools::getDefaultNumberFormat( _rxTemplateColumn, m_xNumberFormatTypes, SvtSysLocale().GetLanguageTag().getLocale() );
+ _rxRowSetColumn->setPropertyValue( PROPERTY_NUMBERFORMAT, Any( nFormatKey ) );
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ return;
+ }
+
+ if ( bHaveAnyColumnSetting )
+ return;
+
+ // the template column could not provide *any* setting. Okay, probably it's a parser column, which
+ // does not offer those. However, perhaps the template column refers to a table column, which we
+ // can use as new template column
+ try
+ {
+ Reference< XPropertySetInfo > xInfo( _rxTemplateColumn->getPropertySetInfo(), UNO_SET_THROW );
+ if ( !xInfo->hasPropertyByName( PROPERTY_TABLENAME ) )
+ // no chance
+ return;
+
+ OUString sTableName;
+ OSL_VERIFY( _rxTemplateColumn->getPropertyValue( PROPERTY_TABLENAME ) >>= sTableName );
+
+ Reference< XNameAccess > xTables( impl_getTables_throw(), UNO_SET_THROW );
+ if ( !xTables->hasByName( sTableName ) )
+ // no chance
+ return;
+
+ Reference< XColumnsSupplier > xTableColSup( xTables->getByName( sTableName ), UNO_QUERY_THROW );
+ Reference< XNameAccess > xTableCols( xTableColSup->getColumns(), UNO_SET_THROW );
+
+ OUString sTableColumnName;
+
+ // get the "Name" or (preferred) "RealName" property of the column
+ OUString sNamePropertyName( PROPERTY_NAME );
+ if ( xInfo->hasPropertyByName( PROPERTY_REALNAME ) )
+ sNamePropertyName = PROPERTY_REALNAME;
+ OSL_VERIFY( _rxTemplateColumn->getPropertyValue( sNamePropertyName ) >>= sTableColumnName );
+
+ if ( !xTableCols->hasByName( sTableColumnName ) )
+ return;
+
+ Reference< XPropertySet > xTableColumn( xTableCols->getByName( sTableColumnName ), UNO_QUERY_THROW );
+ impl_initializeColumnSettings_nothrow( xTableColumn, _rxRowSetColumn );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void ORowSet::execute_NoApprove_NoNewConn(ResettableMutexGuard& _rClearForNotification)
+{
+ // now we can dispose our old connection
+ ::comphelper::disposeComponent(m_xOldConnection);
+ m_xOldConnection = nullptr;
+
+ // do we need a new statement
+ if ( m_bCommandFacetsDirty )
+ {
+ m_xStatement = nullptr;
+ m_xComposer = nullptr;
+
+ Reference< XResultSet > xResultSet( impl_prepareAndExecute_throw() );
+
+ // let our warnings container forget the reference to the (possibly disposed) old result set
+ m_aWarnings.setExternalWarnings( nullptr );
+ // clear all current warnings
+ m_aWarnings.clearWarnings();
+ // let the warnings container know about the new "external warnings"
+ m_aWarnings.setExternalWarnings( Reference< XWarningsSupplier >( xResultSet, UNO_QUERY ) );
+
+ // get the locale
+ Locale aLocale = SvtSysLocale().GetLanguageTag().getLocale();
+
+ // get the numberformatTypes
+ OSL_ENSURE(m_xActiveConnection.is(),"No ActiveConnection");
+ Reference< XNumberFormatsSupplier> xNumberFormat = ::dbtools::getNumberFormats(m_xActiveConnection);
+ if ( xNumberFormat.is() )
+ m_xNumberFormatTypes.set(xNumberFormat->getNumberFormats(),UNO_QUERY);
+
+ ::rtl::Reference< ::connectivity::OSQLColumns> aColumns = new ::connectivity::OSQLColumns();
+ std::vector< OUString> aNames;
+ OUString aDescription;
+
+ const std::map<sal_Int32,sal_Int32>& rKeyColumns = m_pCache->getKeyColumns();
+ if(!m_xColumns.is())
+ {
+ SAL_INFO("dbaccess", "ORowSet::execute_NoApprove_NoNewConn::creating columns" );
+ // use the meta data
+ Reference<XResultSetMetaDataSupplier> xMetaSup(m_xStatement,UNO_QUERY);
+ try
+ {
+ Reference<XResultSetMetaData> xMetaData = xMetaSup->getMetaData();
+ if ( xMetaData.is() )
+ {
+ sal_Int32 nCount = xMetaData->getColumnCount();
+ m_aDataColumns.reserve(nCount+1);
+ aColumns->reserve(nCount+1);
+ std::map< OUString, int > aColumnMap;
+ for (sal_Int32 i = 0 ; i < nCount; ++i)
+ {
+ // retrieve the name of the column
+ OUString sName = xMetaData->getColumnName(i + 1);
+ // check for duplicate entries
+ if(aColumnMap.find(sName) != aColumnMap.end())
+ {
+ OUString sAlias(sName);
+ sal_Int32 searchIndex=1;
+ while(aColumnMap.find(sAlias) != aColumnMap.end())
+ {
+ sAlias = sName + OUString::number(searchIndex++);
+ }
+ sName = sAlias;
+ }
+ rtl::Reference<ORowSetDataColumn> pColumn = new ORowSetDataColumn( getMetaData(),
+ this,
+ this,
+ i+1,
+ m_xActiveConnection->getMetaData(),
+ aDescription,
+ OUString(),
+ [this] (sal_Int32 const column) -> ORowSetValue const& {
+ return this->getInsertValue(column);
+ });
+ aColumnMap.insert(std::make_pair(sName,0));
+ aColumns->emplace_back(pColumn);
+ pColumn->setName(sName);
+ aNames.push_back(sName);
+ m_aDataColumns.push_back(pColumn.get());
+
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_ISREADONLY,Any(rKeyColumns.find(i+1) != rKeyColumns.end()));
+
+ try
+ {
+ sal_Int32 nFormatKey = 0;
+ if(m_xNumberFormatTypes.is())
+ nFormatKey = ::dbtools::getDefaultNumberFormat(pColumn,m_xNumberFormatTypes,aLocale);
+
+
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_NUMBERFORMAT,Any(nFormatKey));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_RELATIVEPOSITION,Any(sal_Int32(i+1)));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_WIDTH,Any(sal_Int32(227)));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_ALIGN,Any(sal_Int32(0)));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_HIDDEN, css::uno::Any(false));
+ }
+ catch(Exception&)
+ {
+ }
+ }
+ }
+ }
+ catch (SQLException&)
+ {
+ }
+ }
+ else
+ {
+ // create the rowset columns
+ Reference< XResultSetMetaData > xMeta( getMetaData(), UNO_SET_THROW );
+ sal_Int32 nCount = xMeta->getColumnCount();
+ m_aDataColumns.reserve(nCount+1);
+ aColumns->reserve(nCount+1);
+ std::set< Reference< XPropertySet > > aAllColumns;
+
+ for(sal_Int32 i=1; i <= nCount ;++i)
+ {
+ OUString sName = xMeta->getColumnName(i);
+ OUString sColumnLabel = xMeta->getColumnLabel(i);
+
+ // retrieve the column number |i|
+ Reference<XPropertySet> xColumn;
+ {
+ bool bReFetchName = false;
+ if (m_xColumns->hasByName(sColumnLabel))
+ m_xColumns->getByName(sColumnLabel) >>= xColumn;
+ if (!xColumn.is() && m_xColumns->hasByName(sName))
+ m_xColumns->getByName(sName) >>= xColumn;
+
+ // check if column already in the list we need another
+ if ( aAllColumns.find( xColumn ) != aAllColumns.end() )
+ {
+ xColumn = nullptr;
+ bReFetchName = true;
+ sColumnLabel.clear();
+ }
+ if(!xColumn.is())
+ {
+ // no column found so we could look at the position i
+ Reference<XIndexAccess> xIndexAccess(m_xColumns,UNO_QUERY);
+ if(xIndexAccess.is() && i <= xIndexAccess->getCount())
+ {
+ xIndexAccess->getByIndex(i-1) >>= xColumn;
+ }
+ else
+ {
+ Sequence< OUString> aSeq = m_xColumns->getElementNames();
+ if( i <= aSeq.getLength())
+ {
+ m_xColumns->getByName(aSeq.getConstArray()[i-1]) >>= xColumn;
+ }
+ }
+ }
+ if(bReFetchName && xColumn.is())
+ xColumn->getPropertyValue(PROPERTY_NAME) >>= sName;
+ aAllColumns.insert( xColumn );
+ }
+
+ // create a RowSetDataColumn
+ {
+ Reference<XPropertySetInfo> xInfo = xColumn.is() ? xColumn->getPropertySetInfo() : Reference<XPropertySetInfo>();
+ if(xInfo.is() && xInfo->hasPropertyByName(PROPERTY_DESCRIPTION))
+ aDescription = comphelper::getString(xColumn->getPropertyValue(PROPERTY_DESCRIPTION));
+
+ OUString sParseLabel;
+ if ( xColumn.is() )
+ {
+ xColumn->getPropertyValue(PROPERTY_LABEL) >>= sParseLabel;
+ }
+ rtl::Reference<ORowSetDataColumn> pColumn = new ORowSetDataColumn( getMetaData(),
+ this,
+ this,
+ i,
+ m_xActiveConnection->getMetaData(),
+ aDescription,
+ sParseLabel,
+ [this] (sal_Int32 const column) -> ORowSetValue const& {
+ return this->getInsertValue(column);
+ });
+ aColumns->emplace_back(pColumn);
+
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_ISREADONLY,Any(rKeyColumns.find(i) != rKeyColumns.end()));
+
+ if(sColumnLabel.isEmpty())
+ {
+ if(xColumn.is())
+ xColumn->getPropertyValue(PROPERTY_NAME) >>= sColumnLabel;
+ else
+ sColumnLabel = DBA_RES( RID_STR_EXPRESSION1 );
+ }
+ pColumn->setName(sColumnLabel);
+ aNames.push_back(sColumnLabel);
+ m_aDataColumns.push_back(pColumn.get());
+
+ if ( xColumn.is() )
+ impl_initializeColumnSettings_nothrow( xColumn, pColumn );
+ }
+ }
+ }
+ // now create the columns we need
+ if(m_pColumns)
+ m_pColumns->assign(aColumns,aNames);
+ else
+ {
+ Reference<XDatabaseMetaData> xMeta = m_xActiveConnection->getMetaData();
+ m_pColumns.reset( new ORowSetDataColumns(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(),
+ aColumns,*this,m_aColumnsMutex,aNames) );
+ }
+ }
+ else // !m_bCommandFacetsDirty
+ {
+ Reference< XResultSet > xResultSet;
+ if(m_bParametersDirty)
+ {
+ xResultSet = impl_prepareAndExecute_throw();
+ }
+ else
+ {
+ xResultSet = m_xStatement->executeQuery();
+ m_pCache->reset(xResultSet);
+ }
+ // let our warnings container forget the reference to the (possibly disposed) old result set
+ m_aWarnings.setExternalWarnings( nullptr );
+ // clear all current warnings
+ m_aWarnings.clearWarnings();
+ // let the warnings container know about the new "external warnings"
+ m_aWarnings.setExternalWarnings( Reference< XWarningsSupplier >( xResultSet, UNO_QUERY ) );
+ }
+ checkCache();
+ // notify the rowset listeners
+ notifyAllListeners(_rClearForNotification);
+}
+
+// XRowSetApproveBroadcaster
+void SAL_CALL ORowSet::addRowSetApproveListener( const Reference< XRowSetApproveListener >& listener )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+
+ m_aApproveListeners.addInterface(listener);
+}
+
+void SAL_CALL ORowSet::removeRowSetApproveListener( const Reference< XRowSetApproveListener >& listener )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+
+ m_aApproveListeners.removeInterface(listener);
+}
+
+// XRowsChangeBroadcaster
+void SAL_CALL ORowSet::addRowsChangeListener( const Reference< XRowsChangeListener >& listener )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+
+ m_aRowsChangeListener.addInterface(listener);
+}
+
+void SAL_CALL ORowSet::removeRowsChangeListener( const Reference< XRowsChangeListener >& listener )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+
+ m_aRowsChangeListener.removeInterface(listener);
+}
+
+// XResultSetAccess
+Reference< XResultSet > SAL_CALL ORowSet::createResultSet( )
+{
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+
+ if(m_xStatement.is())
+ {
+ rtl::Reference<ORowSetClone> pClone = new ORowSetClone( m_aContext, *this, m_pMutex );
+ m_aClones.emplace_back(css::uno::Reference< css::uno::XWeak >(pClone));
+ return pClone;
+ }
+ return Reference< XResultSet >();
+}
+
+// css::util::XCancellable
+void SAL_CALL ORowSet::cancel( )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+}
+
+// css::sdbcx::XDeleteRows
+Sequence< sal_Int32 > SAL_CALL ORowSet::deleteRows( const Sequence< Any >& rows )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ if(!m_pCache || m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY)
+ throwFunctionSequenceException(*this);
+
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+
+ Sequence<Any> aChangedBookmarks;
+ RowsChangeEvent aEvt(*this,RowChangeAction::DELETE,rows.getLength(),aChangedBookmarks);
+ // notify the rowset listeners
+ notifyAllListenersRowBeforeChange(aGuard,aEvt);
+
+ Sequence< sal_Int32 > aResults( rows.getLength() );
+ const Any* row = rows.getConstArray();
+ const Any* rowEnd = rows.getConstArray() + rows.getLength();
+ sal_Int32* result = aResults.getArray();
+ for ( ; row != rowEnd; ++row, ++result )
+ {
+ *result = 0;
+ if ( !m_pCache->moveToBookmark( *row ) )
+ continue;
+ sal_Int32 nDeletePosition = m_pCache->getRow();
+
+ // first notify the clones so that they can save their position
+ notifyRowSetAndClonesRowDelete( *row );
+
+ // now delete the row
+ if ( !m_pCache->deleteRow() )
+ continue;
+ *result = 1;
+ // now notify that we have deleted
+ notifyRowSetAndClonesRowDeleted( *row, nDeletePosition );
+ }
+ aEvt.Rows = aResults.getLength();
+
+ // we have to check if we stand on the insert row and if so we have to reset it
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+ // notification order
+ // - rowChanged
+ notifyAllListenersRowChanged(aGuard,aEvt);
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire();
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+
+ return aResults;
+}
+
+void ORowSet::notifyRowSetAndClonesRowDelete( const Any& _rBookmark )
+{
+ // notify ourself
+ onDeleteRow( _rBookmark );
+ // notify the clones
+ for (auto const& elem : m_aClones)
+ {
+ auto pClone = comphelper::getFromUnoTunnel<ORowSetClone>(elem.get());
+ if(pClone)
+ pClone->onDeleteRow( _rBookmark );
+ }
+}
+
+void ORowSet::notifyRowSetAndClonesRowDeleted( const Any& _rBookmark, sal_Int32 _nPos )
+{
+ // notify ourself
+ onDeletedRow( _rBookmark, _nPos );
+ // notify the clones
+ for (auto const& clone : m_aClones)
+ {
+ auto pClone = comphelper::getFromUnoTunnel<ORowSetClone>(clone.get());
+ if(pClone)
+ pClone->onDeletedRow( _rBookmark, _nPos );
+ }
+}
+
+Reference< XConnection > ORowSet::calcConnection(const Reference< XInteractionHandler >& _rxHandler)
+{
+ MutexGuard aGuard(m_aMutex);
+ if (!m_xActiveConnection.is())
+ {
+ Reference< XConnection > xNewConn;
+ if ( !m_aDataSourceName.isEmpty() )
+ {
+ Reference< XDatabaseContext > xDatabaseContext( DatabaseContext::create(m_aContext) );
+ try
+ {
+ Reference< XDataSource > xDataSource( xDatabaseContext->getByName( m_aDataSourceName ), UNO_QUERY_THROW );
+
+ // try connecting with the interaction handler
+ Reference< XCompletedConnection > xComplConn( xDataSource, UNO_QUERY );
+ if ( _rxHandler.is() && xComplConn.is() )
+ {
+ xNewConn = xComplConn->connectWithCompletion( _rxHandler );
+ }
+ else
+ {
+ xNewConn = xDataSource->getConnection( m_aUser, m_aPassword );
+ }
+ }
+ catch ( const SQLException& )
+ {
+ throw;
+ }
+ catch ( const Exception& )
+ {
+ Any aError = ::cppu::getCaughtException();
+ OUString sMessage = ResourceManager::loadString( RID_NO_SUCH_DATA_SOURCE,
+ "$name$", m_aDataSourceName, "$error$", extractExceptionMessage( m_aContext, aError ) );
+ ::dbtools::throwGenericSQLException( sMessage, *this, aError );
+ }
+ }
+ setActiveConnection(xNewConn);
+ m_bOwnConnection = true;
+ }
+ return m_xActiveConnection;
+}
+
+Reference< XNameAccess > ORowSet::impl_getTables_throw()
+{
+ Reference< XNameAccess > xTables;
+
+ Reference< XTablesSupplier > xTablesAccess( m_xActiveConnection, UNO_QUERY );
+ if ( xTablesAccess.is() )
+ {
+ xTables.set( xTablesAccess->getTables(), UNO_SET_THROW );
+ }
+ else if ( m_xTables )
+ {
+ xTables = m_xTables.get();
+ }
+ else
+ {
+ if ( !m_xActiveConnection.is() )
+ throw SQLException(DBA_RES(RID_STR_CONNECTION_INVALID),*this,SQLSTATE_GENERAL,1000,Any() );
+
+ bool bCase = true;
+ try
+ {
+ Reference<XDatabaseMetaData> xMeta = m_xActiveConnection->getMetaData();
+ bCase = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers();
+ }
+ catch(SQLException&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ m_xTables.reset(new OTableContainer(*this,m_aMutex,m_xActiveConnection,bCase,nullptr,nullptr,m_nInAppend));
+ xTables = m_xTables.get();
+ Sequence<OUString> aTableFilter { "%" };
+ m_xTables->construct(aTableFilter,Sequence< OUString>());
+ }
+
+ return xTables;
+}
+
+void ORowSet::impl_resetTables_nothrow()
+{
+ if ( !m_xTables )
+ return;
+
+ try
+ {
+ m_xTables->dispose();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ m_xTables.reset();
+}
+
+void ORowSet::impl_initComposer_throw( OUString& _out_rCommandToExecute )
+{
+ bool bUseEscapeProcessing = impl_buildActiveCommand_throw( );
+ _out_rCommandToExecute = m_aActiveCommand;
+ if ( !bUseEscapeProcessing )
+ return;
+
+ if (m_bCommandFacetsDirty)
+ m_xComposer = nullptr;
+
+ Reference< XMultiServiceFactory > xFactory( m_xActiveConnection, UNO_QUERY );
+ if ( !m_xComposer.is() && xFactory.is() )
+ {
+ try
+ {
+ m_xComposer.set( xFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW );
+ }
+ catch (const Exception& ) { m_xComposer = nullptr; }
+ }
+ if ( !m_xComposer.is() )
+ m_xComposer = new OSingleSelectQueryComposer( impl_getTables_throw(), m_xActiveConnection, m_aContext );
+
+ m_xComposer->setCommand( m_aCommand,m_nCommandType );
+ m_aActiveCommand = m_xComposer->getQuery();
+
+ m_xComposer->setFilter( m_bApplyFilter ? m_aFilter : OUString() );
+ m_xComposer->setHavingClause( m_bApplyFilter ? m_aHavingClause : OUString() );
+
+ if ( m_bIgnoreResult )
+ { // append a "0=1" filter
+ // don't simply overwrite an existent filter, this would lead to problems if this existent
+ // filter contains parameters (since a keyset may add parameters itself)
+ m_xComposer->setElementaryQuery( m_xComposer->getQuery( ) );
+ m_xComposer->setFilter( "0 = 1" );
+ }
+
+ m_xComposer->setOrder( m_aOrder );
+ m_xComposer->setGroup( m_aGroupBy );
+
+ if ( !m_xColumns.is() )
+ {
+ Reference< XColumnsSupplier > xCols( m_xComposer, UNO_QUERY_THROW );
+ m_xColumns = xCols->getColumns();
+ }
+
+ impl_initParametersContainer_nothrow();
+
+ _out_rCommandToExecute = m_xComposer->getQueryWithSubstitution();
+
+ m_bCommandFacetsDirty = false;
+}
+
+bool ORowSet::impl_buildActiveCommand_throw()
+{
+ // create the sql command
+ // from a table name or get the command out of a query (not a view)
+ // the last use the command as it is
+ bool bDoEscapeProcessing = m_bUseEscapeProcessing;
+
+ m_aActiveCommand.clear();
+ OUString sCommand;
+
+ if ( m_aCommand.isEmpty() )
+ return bDoEscapeProcessing;
+
+ switch (m_nCommandType)
+ {
+ case CommandType::TABLE:
+ {
+ impl_resetTables_nothrow();
+ if ( bDoEscapeProcessing )
+ {
+ Reference< XNameAccess > xTables( impl_getTables_throw() );
+ if ( xTables->hasByName(m_aCommand) )
+ {
+ }
+ else
+ {
+ OUString sMessage( DBA_RES( RID_STR_TABLE_DOES_NOT_EXIST ) );
+ throwGenericSQLException(sMessage.replaceAll( "$table$", m_aCommand ),*this);
+ }
+ }
+ else
+ {
+ sCommand = "SELECT * FROM ";
+ OUString sCatalog, sSchema, sTable;
+ ::dbtools::qualifiedNameComponents( m_xActiveConnection->getMetaData(), m_aCommand, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation );
+ sCommand += ::dbtools::composeTableNameForSelect( m_xActiveConnection, sCatalog, sSchema, sTable );
+ }
+ }
+ break;
+
+ case CommandType::QUERY:
+ {
+ Reference< XQueriesSupplier > xQueriesAccess(m_xActiveConnection, UNO_QUERY);
+ if (!xQueriesAccess.is())
+ throw SQLException(DBA_RES(RID_STR_NO_XQUERIESSUPPLIER),*this,OUString(),0,Any());
+ Reference< css::container::XNameAccess > xQueries(xQueriesAccess->getQueries());
+ if (xQueries->hasByName(m_aCommand))
+ {
+ Reference< XPropertySet > xQuery(xQueries->getByName(m_aCommand),UNO_QUERY);
+ OSL_ENSURE(xQuery.is(),"ORowSet::impl_buildActiveCommand_throw: Query is NULL!");
+ if ( xQuery.is() )
+ {
+ xQuery->getPropertyValue(PROPERTY_COMMAND) >>= sCommand;
+ xQuery->getPropertyValue(PROPERTY_ESCAPE_PROCESSING) >>= bDoEscapeProcessing;
+ if ( bDoEscapeProcessing != m_bUseEscapeProcessing )
+ {
+ bool bOldValue = m_bUseEscapeProcessing;
+ m_bUseEscapeProcessing = bDoEscapeProcessing;
+ fireProperty(PROPERTY_ID_ESCAPE_PROCESSING,bOldValue,bDoEscapeProcessing);
+ }
+
+ OUString aCatalog,aSchema,aTable;
+ xQuery->getPropertyValue(PROPERTY_UPDATE_CATALOGNAME) >>= aCatalog;
+ xQuery->getPropertyValue(PROPERTY_UPDATE_SCHEMANAME) >>= aSchema;
+ xQuery->getPropertyValue(PROPERTY_UPDATE_TABLENAME) >>= aTable;
+ if(!aTable.isEmpty())
+ m_aUpdateTableName = composeTableName( m_xActiveConnection->getMetaData(), aCatalog, aSchema, aTable, false, ::dbtools::EComposeRule::InDataManipulation );
+ }
+ }
+ else
+ {
+ OUString sMessage( DBA_RES( RID_STR_QUERY_DOES_NOT_EXIST ) );
+ throwGenericSQLException(sMessage.replaceAll( "$table$", m_aCommand ),*this);
+ }
+ }
+ break;
+
+ default:
+ sCommand = m_aCommand;
+ break;
+ }
+
+ m_aActiveCommand = sCommand;
+
+ if ( m_aActiveCommand.isEmpty() && !bDoEscapeProcessing )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_SQL_COMMAND ), StandardSQLState::FUNCTION_SEQUENCE_ERROR, *this );
+
+ return bDoEscapeProcessing;
+}
+
+void ORowSet::impl_initParametersContainer_nothrow()
+{
+ OSL_PRECOND( !m_pParameters.is(), "ORowSet::impl_initParametersContainer_nothrow: already initialized the parameters!" );
+
+ m_pParameters = new param::ParameterWrapperContainer( m_xComposer );
+ // copy the premature parameters into the final ones
+ size_t nParamCount( std::min( m_pParameters->size(), m_aPrematureParamValues->size() ) );
+ for ( size_t i=0; i<nParamCount; ++i )
+ {
+ (*m_pParameters)[i] = (*m_aPrematureParamValues)[i];
+ }
+}
+
+void ORowSet::impl_disposeParametersContainer_nothrow()
+{
+ if ( !m_pParameters.is() )
+ return;
+
+ // copy the actual values to our "premature" ones, to preserve them for later use
+ size_t nParamCount( m_pParameters->size() );
+ m_aPrematureParamValues->resize( nParamCount );
+ for ( size_t i=0; i<nParamCount; ++i )
+ {
+ (*m_aPrematureParamValues)[i] = (*m_pParameters)[i];
+ }
+
+ m_pParameters->dispose();
+ m_pParameters = nullptr;
+}
+
+ORowSetValue& ORowSet::getParameterStorage(sal_Int32 parameterIndex)
+{
+ ::connectivity::checkDisposed( ORowSet_BASE1::rBHelper.bDisposed );
+ if ( parameterIndex < 1 )
+ throwInvalidIndexException( *this );
+
+ if ( m_aParametersSet.size() < o3tl::make_unsigned(parameterIndex) )
+ m_aParametersSet.resize( parameterIndex ,false);
+ m_aParametersSet[parameterIndex - 1] = true;
+
+ if ( m_pParameters.is() )
+ {
+ if ( m_bCommandFacetsDirty )
+ // need to rebuild the parameters, since some property which contributes to the
+ // complete command, and thus the parameters, changed
+ impl_disposeParametersContainer_nothrow();
+ if ( m_pParameters.is() )
+ {
+ if ( o3tl::make_unsigned(parameterIndex) > m_pParameters->size() )
+ throwInvalidIndexException( *this );
+ return (*m_pParameters)[ parameterIndex - 1 ];
+ }
+ }
+
+ if ( m_aPrematureParamValues->size() < o3tl::make_unsigned(parameterIndex) )
+ m_aPrematureParamValues->resize( parameterIndex );
+ return (*m_aPrematureParamValues)[ parameterIndex - 1 ];
+}
+
+// XParameters
+void SAL_CALL ORowSet::setNull( sal_Int32 parameterIndex, sal_Int32 /*sqlType*/ )
+{
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+
+ getParameterStorage( parameterIndex ).setNull();
+ m_bParametersDirty = true;
+}
+
+void SAL_CALL ORowSet::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& /*typeName*/ )
+{
+ setNull( parameterIndex, sqlType );
+}
+
+void ORowSet::setParameter(sal_Int32 parameterIndex, const ORowSetValue& x)
+{
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+
+ getParameterStorage( parameterIndex ) = x;
+ m_bParametersDirty = true;
+}
+
+void SAL_CALL ORowSet::setBoolean( sal_Int32 parameterIndex, sal_Bool x )
+{
+ setParameter(parameterIndex, static_cast<bool>(x));
+}
+
+void SAL_CALL ORowSet::setByte( sal_Int32 parameterIndex, sal_Int8 x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setShort( sal_Int32 parameterIndex, sal_Int16 x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setInt( sal_Int32 parameterIndex, sal_Int32 x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setLong( sal_Int32 parameterIndex, sal_Int64 x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setFloat( sal_Int32 parameterIndex, float x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setDouble( sal_Int32 parameterIndex, double x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setString( sal_Int32 parameterIndex, const OUString& x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setBytes( sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setDate( sal_Int32 parameterIndex, const css::util::Date& x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setTime( sal_Int32 parameterIndex, const css::util::Time& x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x )
+{
+ setParameter(parameterIndex,x);
+}
+
+void SAL_CALL ORowSet::setBinaryStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+ ORowSetValue& rParamValue( getParameterStorage( parameterIndex ) );
+
+ try
+ {
+ Sequence <sal_Int8> aData;
+ x->readBytes(aData, length);
+ rParamValue = aData;
+ m_bParametersDirty = true;
+ x->closeInput();
+ }
+ catch( Exception const & )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw SQLException("ORowSet::setBinaryStream", *this, "S1000", 0,anyEx);
+ }
+}
+
+void SAL_CALL ORowSet::setCharacterStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+ ORowSetValue& rParamValue( getParameterStorage( parameterIndex ) );
+ try
+ {
+ Sequence <sal_Int8> aData;
+ OUString aDataStr;
+ // the data is given as character data and the length defines the character length
+ sal_Int32 nSize = x->readBytes(aData, length * sizeof(sal_Unicode));
+ if (nSize / sizeof(sal_Unicode))
+ aDataStr = OUString(reinterpret_cast<sal_Unicode const *>(aData.getConstArray()), nSize / sizeof(sal_Unicode));
+ m_bParametersDirty = true;
+ rParamValue = aDataStr;
+ rParamValue.setTypeKind( DataType::LONGVARCHAR );
+ x->closeInput();
+ }
+ catch( Exception const & )
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw SQLException("ORowSet::setCharacterStream", *this, "S1000", 0, anyEx);
+ }
+}
+
+void SAL_CALL ORowSet::setObject( sal_Int32 parameterIndex, const Any& x )
+{
+ if ( !::dbtools::implSetObject( this, parameterIndex, x ) )
+ { // there is no other setXXX call which can handle the value in x
+ throw SQLException();
+ }
+ m_bParametersDirty = true;
+}
+
+void SAL_CALL ORowSet::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 targetSqlType, sal_Int32 /*scale*/ )
+{
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+ ORowSetValue& rParamValue( getParameterStorage( parameterIndex ) );
+ setObject( parameterIndex, x );
+ rParamValue.setTypeKind( targetSqlType );
+}
+
+void SAL_CALL ORowSet::setRef( sal_Int32 /*parameterIndex*/, const Reference< XRef >& /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setRef", *this );
+}
+
+void SAL_CALL ORowSet::setBlob( sal_Int32 /*parameterIndex*/, const Reference< XBlob >& /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setBlob", *this );
+}
+
+void SAL_CALL ORowSet::setClob( sal_Int32 /*parameterIndex*/, const Reference< XClob >& /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setClob", *this );
+}
+
+void SAL_CALL ORowSet::setArray( sal_Int32 /*parameterIndex*/, const Reference< XArray >& /*x*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setArray", *this );
+}
+
+void SAL_CALL ORowSet::clearParameters( )
+{
+ ::connectivity::checkDisposed(ORowSet_BASE1::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+
+ size_t nParamCount( m_pParameters.is() ? m_pParameters->size() : m_aPrematureParamValues->size() );
+ for ( size_t i=1; i<=nParamCount; ++i )
+ getParameterStorage( static_cast<sal_Int32>(i) ).setNull();
+ m_aParametersSet.clear();
+}
+
+Any SAL_CALL ORowSet::getWarnings( )
+{
+ return m_aWarnings.getWarnings();
+}
+
+void SAL_CALL ORowSet::clearWarnings( )
+{
+ m_aWarnings.clearWarnings();
+}
+
+void ORowSet::doCancelModification( )
+{
+ if ( isModification() )
+ {
+ // read-only flag restored
+ impl_restoreDataColumnsWriteable_throw();
+ m_pCache->cancelRowModification();
+ }
+ m_bModified = false;
+ m_bIsInsertRow = false;
+}
+
+bool ORowSet::isModification( )
+{
+ return isNew();
+}
+
+bool ORowSet::isModified( )
+{
+ return m_bModified;
+}
+
+bool ORowSet::isNew( )
+{
+ return m_bNew;
+}
+
+bool ORowSet::isPropertyChangeNotificationEnabled() const
+{
+ return m_bPropChangeNotifyEnabled;
+}
+
+void ORowSet::checkUpdateIterator()
+{
+ if(!m_bIsInsertRow)
+ {
+ m_pCache->setUpdateIterator(m_aCurrentRow);
+ m_aCurrentRow = m_pCache->m_aInsertRow;
+ m_bIsInsertRow = true;
+ }
+}
+
+void ORowSet::checkUpdateConditions(sal_Int32 columnIndex)
+{
+ checkCache();
+ if ( m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY)
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_RESULT_IS_READONLY ), StandardSQLState::GENERAL_ERROR, *this );
+
+ if ( rowDeleted() )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_ROW_ALREADY_DELETED ), StandardSQLState::INVALID_CURSOR_POSITION, *this );
+
+ if ( m_aCurrentRow.isNull() )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_INVALID_CURSOR_STATE ), StandardSQLState::INVALID_CURSOR_STATE, *this );
+
+ if ( columnIndex <= 0 || (*m_aCurrentRow)->size() <= o3tl::make_unsigned(columnIndex) )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_INVALID_INDEX ), StandardSQLState::INVALID_DESCRIPTOR_INDEX, *this );
+}
+
+void SAL_CALL ORowSet::refreshRow( )
+{
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ // notification order:
+ if ( m_bModified && m_pCache )
+ implCancelRowUpdates( false ); // do _not_ notify the IsModify - will do this ourself below
+
+ // - column values
+ ORowSetBase::refreshRow();
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire( );
+}
+
+void ORowSet::impl_rebuild_throw(::osl::ResettableMutexGuard& _rGuard)
+{
+ Reference< XResultSet > xResultSet(m_xStatement->executeQuery());
+ m_pCache->reset(xResultSet);
+ m_aWarnings.setExternalWarnings( Reference< XWarningsSupplier >( xResultSet, UNO_QUERY ) );
+ notifyAllListeners(_rGuard);
+}
+
+// ***********************************************************
+// ORowSetClone
+// ***********************************************************
+
+ORowSetClone::ORowSetClone( const Reference<XComponentContext>& _rContext, ORowSet& rParent, ::osl::Mutex* _pMutex )
+ :OSubComponent(m_aMutex, rParent)
+ ,ORowSetBase( _rContext, OComponentHelper::rBHelper, _pMutex )
+ ,m_pParent(&rParent)
+ ,m_nFetchDirection(rParent.m_nFetchDirection)
+ ,m_nFetchSize(rParent.m_nFetchSize)
+ ,m_bIsBookmarkable(true)
+{
+
+ m_nResultSetType = rParent.m_nResultSetType;
+ m_nResultSetConcurrency = ResultSetConcurrency::READ_ONLY;
+ m_pMySelf = this;
+ m_bClone = true;
+ m_bBeforeFirst = rParent.m_bBeforeFirst;
+ m_bAfterLast = rParent.m_bAfterLast;
+ m_pCache = rParent.m_pCache;
+ m_aBookmark = rParent.m_aBookmark;
+ m_aCurrentRow = m_pCache->createIterator(this);
+ m_xNumberFormatTypes = rParent.m_xNumberFormatTypes;
+
+ m_aOldRow = m_pCache->registerOldRow();
+
+ ::rtl::Reference< ::connectivity::OSQLColumns> aColumns = new ::connectivity::OSQLColumns();
+ std::vector< OUString> aNames;
+
+ OUString aDescription;
+ Locale aLocale = SvtSysLocale().GetLanguageTag().getLocale();
+
+ if ( rParent.m_pColumns )
+ {
+ Sequence< OUString> aSeq = rParent.m_pColumns->getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ aColumns->reserve(aSeq.getLength()+1);
+ for(sal_Int32 i=1;pIter != pEnd ;++pIter,++i)
+ {
+ Reference<XPropertySet> xColumn;
+ rParent.m_pColumns->getByName(*pIter) >>= xColumn;
+ if(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_DESCRIPTION))
+ aDescription = comphelper::getString(xColumn->getPropertyValue(PROPERTY_DESCRIPTION));
+
+ OUString sParseLabel;
+ xColumn->getPropertyValue(PROPERTY_LABEL) >>= sParseLabel;
+ rtl::Reference<ORowSetColumn> pColumn = new ORowSetColumn( rParent.getMetaData(),
+ this,
+ i,
+ rParent.m_xActiveConnection->getMetaData(),
+ aDescription,
+ sParseLabel,
+ [this] (sal_Int32 const column) -> ORowSetValue const& {
+ return this->getValue(column);
+ });
+ aColumns->emplace_back(pColumn);
+ pColumn->setName(*pIter);
+ aNames.push_back(*pIter);
+ m_aDataColumns.push_back(pColumn.get());
+
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_ALIGN,xColumn->getPropertyValue(PROPERTY_ALIGN));
+ sal_Int32 nFormatKey = 0;
+ xColumn->getPropertyValue(PROPERTY_NUMBERFORMAT) >>= nFormatKey;
+ if(!nFormatKey && xColumn.is() && m_xNumberFormatTypes.is())
+ nFormatKey = ::dbtools::getDefaultNumberFormat(xColumn,m_xNumberFormatTypes,aLocale);
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_NUMBERFORMAT,Any(nFormatKey));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_RELATIVEPOSITION,xColumn->getPropertyValue(PROPERTY_RELATIVEPOSITION));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_WIDTH,xColumn->getPropertyValue(PROPERTY_WIDTH));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_HIDDEN,xColumn->getPropertyValue(PROPERTY_HIDDEN));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_CONTROLMODEL,xColumn->getPropertyValue(PROPERTY_CONTROLMODEL));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_HELPTEXT,xColumn->getPropertyValue(PROPERTY_HELPTEXT));
+ pColumn->setFastPropertyValue_NoBroadcast(PROPERTY_ID_CONTROLDEFAULT,xColumn->getPropertyValue(PROPERTY_CONTROLDEFAULT));
+
+ }
+ }
+ Reference<XDatabaseMetaData> xMeta = rParent.m_xActiveConnection->getMetaData();
+ m_pColumns.reset( new ORowSetDataColumns(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(),
+ aColumns,*this,m_aMutex,aNames) );
+
+ sal_Int32 const nRT = PropertyAttribute::READONLY | PropertyAttribute::TRANSIENT;
+
+ // sdb.RowSet Properties
+ registerMayBeVoidProperty(PROPERTY_ACTIVE_CONNECTION,PROPERTY_ID_ACTIVE_CONNECTION, PropertyAttribute::MAYBEVOID|PropertyAttribute::READONLY, &rParent.m_aActiveConnection, cppu::UnoType<XConnection>::get());
+ registerProperty(PROPERTY_RESULTSETCONCURRENCY, PROPERTY_ID_RESULTSETCONCURRENCY, PropertyAttribute::READONLY, &m_nResultSetConcurrency,::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_RESULTSETTYPE, PROPERTY_ID_RESULTSETTYPE, PropertyAttribute::READONLY, &m_nResultSetType, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_FETCHDIRECTION, PROPERTY_ID_FETCHDIRECTION, PropertyAttribute::TRANSIENT, &m_nFetchDirection, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_FETCHSIZE, PROPERTY_ID_FETCHSIZE, PropertyAttribute::TRANSIENT, &m_nFetchSize, ::cppu::UnoType<sal_Int32>::get());
+ registerProperty(PROPERTY_ISBOOKMARKABLE, PROPERTY_ID_ISBOOKMARKABLE, nRT, &m_bIsBookmarkable, cppu::UnoType<bool>::get());
+}
+
+ORowSetClone::~ORowSetClone()
+{
+}
+
+// css::XTypeProvider
+Sequence< Type > ORowSetClone::getTypes()
+{
+ return ::comphelper::concatSequences(OSubComponent::getTypes(),ORowSetBase::getTypes());
+}
+
+// css::XInterface
+Any ORowSetClone::queryInterface( const Type & rType )
+{
+ Any aRet = ORowSetBase::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = OSubComponent::queryInterface(rType);
+ return aRet;
+}
+
+void ORowSetClone::acquire() noexcept
+{
+ OSubComponent::acquire();
+}
+
+void ORowSetClone::release() noexcept
+{
+ OSubComponent::release();
+}
+
+// XServiceInfo
+OUString ORowSetClone::getImplementationName( )
+{
+ return "com.sun.star.sdb.ORowSetClone";
+}
+
+sal_Bool ORowSetClone::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > ORowSetClone::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBC_RESULTSET, SERVICE_SDB_RESULTSET };
+}
+
+// OComponentHelper
+void ORowSetClone::disposing()
+{
+ MutexGuard aGuard( m_aMutex );
+ ORowSetBase::disposing();
+
+ m_pParent = nullptr;
+ m_pMutex = &m_aMutex; // this must be done here because someone could hold a ref to us and try to do something
+ OSubComponent::disposing();
+}
+
+// XCloseable
+void ORowSetClone::close()
+{
+ {
+ MutexGuard aGuard( m_aMutex );
+ if (OComponentHelper::rBHelper.bDisposed)
+ throw DisposedException();
+ }
+ dispose();
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* ORowSetClone::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& SAL_CALL ORowSetClone::getInfoHelper()
+{
+ return *::comphelper::OPropertyArrayUsageHelper<ORowSetClone>::getArrayHelper();
+}
+
+const Sequence< sal_Int8 > & ORowSetClone::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+// css::XUnoTunnel
+sal_Int64 SAL_CALL ORowSetClone::getSomething( const Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+void SAL_CALL ORowSetClone::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ if ( nHandle == PROPERTY_ID_FETCHSIZE )
+ {
+ if ( m_pParent )
+ m_pParent->setFastPropertyValue_NoBroadcast( nHandle, rValue );
+ }
+
+ OPropertyStateContainer::setFastPropertyValue_NoBroadcast(nHandle,rValue);
+}
+
+void ORowSetClone::doCancelModification( )
+{
+}
+
+bool ORowSetClone::isModification( )
+{
+ return false;
+}
+
+bool ORowSetClone::isModified( )
+{
+ return false;
+}
+
+bool ORowSetClone::isNew( )
+{
+ return false;
+}
+
+void SAL_CALL ORowSetClone::execute( )
+{
+ throwFunctionNotSupportedSQLException( "RowSetClone::XRowSet::execute", *this );
+}
+
+void SAL_CALL ORowSetClone::addRowSetListener( const Reference< XRowSetListener >& )
+{
+ throwFunctionNotSupportedRuntimeException( "RowSetClone::XRowSet", *this );
+}
+
+void SAL_CALL ORowSetClone::removeRowSetListener( const Reference< XRowSetListener >& )
+{
+ throwFunctionNotSupportedRuntimeException( "RowSetClone::XRowSet", *this );
+}
+
+} // dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSet.hxx b/dbaccess/source/core/api/RowSet.hxx
new file mode 100644
index 000000000..afe49a923
--- /dev/null
+++ b/dbaccess/source/core/api/RowSet.hxx
@@ -0,0 +1,527 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <atomic>
+#include <cstddef>
+
+#include <apitools.hxx>
+#include "RowSetBase.hxx"
+
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdb/XResultSetAccess.hpp>
+#include <com/sun/star/sdbc/XRowSetListener.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdb/XRowSetApproveBroadcaster.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbcx/XDeleteRows.hpp>
+#include <com/sun/star/sdb/XCompletedExecution.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdb/XRowsChangeBroadcaster.hpp>
+
+#include <cppuhelper/compbase12.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <connectivity/paramwrapper.hxx>
+#include <connectivity/FValue.hxx>
+#include <connectivity/warningscontainer.hxx>
+
+namespace dbaccess
+{
+ typedef ::cppu::WeakAggComponentImplHelper12 < css::sdb::XResultSetAccess
+ , css::sdb::XRowSetApproveBroadcaster
+ , css::sdb::XRowsChangeBroadcaster
+ , css::sdbcx::XDeleteRows
+ , css::sdbc::XParameters
+ , css::lang::XEventListener
+ , css::sdbc::XResultSetUpdate
+ , css::sdbc::XRowUpdate
+ , css::util::XCancellable
+ , css::sdb::XCompletedExecution
+ , css::sdb::XParametersSupplier
+ , css::sdbc::XWarningsSupplier
+ > ORowSet_BASE1;
+
+ class OTableContainer;
+ class ORowSet final : public cppu::BaseMutex
+ , public ORowSet_BASE1
+ , public ORowSetBase
+ , public ::comphelper::OPropertyArrayUsageHelper<ORowSet>
+ {
+ friend class ORowSetClone;
+
+ css::uno::Reference< css::sdbc::XConnection > m_xOldConnection;
+ css::uno::Reference< css::sdbc::XConnection > m_xActiveConnection;
+ css::uno::Any m_aActiveConnection;
+ css::uno::Reference< css::container::XNameAccess > m_xTypeMap;
+ css::uno::Any m_aTypeMap;
+ css::uno::Reference< css::sdbc::XPreparedStatement > m_xStatement;
+ css::uno::Reference< css::sdb::XSingleSelectQueryComposer > m_xComposer;
+ css::uno::Reference< css::container::XNameAccess > m_xColumns; // the columns from a table or query
+
+ connectivity::OWeakRefArray m_aClones;
+ /** our parameters as XPropertySet instances and ORowSetValue instances
+ */
+ ::dbtools::param::ParametersContainerRef m_pParameters;
+ /** our parameters values, used when we do not yet have a parameters container
+ (since we have not been executed, yet)
+ */
+ rtl::Reference<ORowSetValueVector> m_aPrematureParamValues;
+ rtl::Reference<ORowSetValueVector> m_aParameterValueForCache;
+ std::vector<bool> m_aParametersSet;
+ std::vector<bool> m_aReadOnlyDataColumns;
+
+ ::comphelper::OInterfaceContainerHelper3<css::sdbc::XRowSetListener> m_aRowsetListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::sdb::XRowSetApproveListener> m_aApproveListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::sdb::XRowsChangeListener> m_aRowsChangeListener;
+
+ ::dbtools::WarningsContainer m_aWarnings;
+
+ // no Reference! see OCollection::acquire
+ std::unique_ptr<OTableContainer> m_xTables;
+
+ OUString m_aCommand;
+ OUString m_aDataSourceName;
+ OUString m_aURL;
+ OUString m_aUser;
+ OUString m_aPassword;
+ OUString m_aFilter;
+ OUString m_aHavingClause;
+ OUString m_aGroupBy;
+ OUString m_aOrder;
+ OUString m_aActiveCommand;
+ OUString m_aUpdateCatalogName; // is set by a query
+ OUString m_aUpdateSchemaName; // is set by a query
+ OUString m_aUpdateTableName; // is set by a query
+ OUString m_sErrorString;
+
+ sal_Int32 m_nFetchDirection;
+ sal_Int32 m_nFetchSize;
+ sal_Int32 m_nMaxFieldSize;
+ sal_Int32 m_nMaxRows;
+ sal_Int32 m_nQueryTimeOut;
+ sal_Int32 m_nCommandType;
+ sal_Int32 m_nTransactionIsolation;
+ sal_Int32 m_nPrivileges;
+ sal_Int32 m_nLastKnownRowCount;
+ std::atomic<std::size_t> m_nInAppend;
+ bool m_bInsertingRow;
+ bool m_bLastKnownRowCountFinal;
+ bool m_bUseEscapeProcessing ;
+ bool m_bApplyFilter ;
+ bool m_bCommandFacetsDirty; // any of the facets which define the active command is dirty
+ bool m_bParametersDirty; // parameters changed since execute
+ bool m_bModified ;
+ bool m_bRebuildConnOnExecute ;
+ bool m_bIsBookmarkable ;
+ bool m_bNew ;
+ bool m_bCanUpdateInsertedRows;
+ bool m_bOwnConnection;
+ bool m_bPropChangeNotifyEnabled;
+
+ /** builds m_aActiveCommand from our settings
+
+ @return
+ whether we should use escape processing before executing the actual command. This is determined
+ from our own EscapeProcessing property, and possibly overruled by the respective property
+ of a query we're based on.
+ */
+ bool impl_buildActiveCommand_throw();
+
+ /** initializes our query composer, and everything which has to do with it
+
+ If we don't use escape processing, then we don't have a composer, and everything
+ related to it. Nonetheless, _out_rCommandToExecute and the return value are properly
+ initialized.
+
+ @param _out_rCommandToExecute
+ The command which is to be executed, according to the current settings -
+ it is built from our active command plus our current filter/order criterions.
+
+ @precond
+ m_xActiveConnection points to a valid SDB-level connection
+
+ @throws css::sdb::SQLException
+ if a database-related error occurred
+
+ @throws css::uno::RuntimeException
+ if any of the components involved throws a css::uno::RuntimeException
+ */
+ void impl_initComposer_throw( OUString& _out_rCommandToExecute );
+
+ /** returns the table container of our active connection
+
+ If our connection is able to provide a tables container, this one is returned.
+ Else, if m_pTables is not <NULL/>, this one will returned.
+ Else, m_pTables will be constructed and returned.
+
+ @precond m_xActiveConnection is not <NULL/>
+ @throws css::sdbc::SQLException
+ if retrieving or constructing the tables container goes wrong
+
+ @see impl_resetTables_nothrow
+ */
+ css::uno::Reference< css::container::XNameAccess >
+ impl_getTables_throw();
+
+ /** cleans up m_pTables, and resets it to <NULL/>
+ */
+ void impl_resetTables_nothrow();
+
+ /** prepares and executes our command
+ */
+ css::uno::Reference< css::sdbc::XResultSet >
+ impl_prepareAndExecute_throw();
+ void impl_ensureStatement_throw();
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::sdbc::XConnection > calcConnection(const css::uno::Reference< css::task::XInteractionHandler >& _rxHandler);
+ // free clones and ParseTree. Plus, if _bComplete is <TRUE/>, *all* other associated resources
+ void freeResources( bool _bComplete );
+
+ /// informs the clones (and ourself) that we are going to delete a record with a given bookmark
+ void notifyRowSetAndClonesRowDelete( const css::uno::Any& _rBookmark );
+
+ /// inform the clones (and ourself) that we have deleted a record with a given bookmark
+ void notifyRowSetAndClonesRowDeleted( const css::uno::Any& _rBookmark, sal_Int32 _nPos );
+
+ void checkUpdateIterator();
+ const connectivity::ORowSetValue& getInsertValue(sal_Int32 columnIndex);
+ void setParameter(sal_Int32 parameterIndex, const connectivity::ORowSetValue& x);
+ // resizes the parameter vector if necessary
+ ::connectivity::ORowSetValue& getParameterStorage( sal_Int32 parameterIndex );
+
+ void updateValue(sal_Int32 columnIndex,const connectivity::ORowSetValue& x);
+ void checkUpdateConditions(sal_Int32 columnIndex);
+ void impl_rebuild_throw(::osl::ResettableMutexGuard& _rGuard);
+ // set all data columns to writeable
+ void impl_setDataColumnsWriteable_throw();
+ // restore the old state of the data column read-only state
+ void impl_restoreDataColumnsWriteable_throw();
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue) override;
+ virtual void SAL_CALL getFastPropertyValue(css::uno::Any& rValue,sal_Int32 nHandle) const override;
+ virtual void getPropertyDefaultByHandle( sal_Int32 _nHandle, css::uno::Any& _rDefault ) const override;
+
+ virtual void fireRowcount() override;
+ void notifyAllListenersRowBeforeChange(::osl::ResettableMutexGuard& _rGuard,const css::sdb::RowChangeEvent &rEvt);
+ void notifyAllListenersRowChanged(::osl::ResettableMutexGuard& _rGuard,const css::sdb::RowsChangeEvent& rEvt);
+ virtual bool notifyAllListenersCursorBeforeMove(::osl::ResettableMutexGuard& _rGuard) override;
+ virtual void notifyAllListenersCursorMoved(::osl::ResettableMutexGuard& _rGuard) override;
+ // notify all that rowset changed
+ void notifyAllListeners(::osl::ResettableMutexGuard& _rGuard);
+
+ virtual void doCancelModification( ) override;
+ virtual bool isModification( ) override;
+ virtual bool isModified( ) override;
+ virtual bool isNew( ) override;
+ virtual bool isPropertyChangeNotificationEnabled() const override;
+
+ virtual ~ORowSet() override;
+
+ public:
+ explicit ORowSet(const css::uno::Reference<css::uno::XComponentContext>&);
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ // css::uno::XAggregation
+ virtual css::uno::Any SAL_CALL queryAggregation( const css::uno::Type& aType ) override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // css::lang::XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // css::sdbc::XCloseable
+ virtual void SAL_CALL close( ) override;
+
+ // comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // css::sdbc::XResultSet
+ virtual void SAL_CALL refreshRow( ) override;
+
+ // XCompletedExecution
+ virtual void SAL_CALL executeWithCompletion( const css::uno::Reference< css::task::XInteractionHandler >& handler ) override;
+
+ // XParametersSupplier
+ virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getParameters( ) override;
+
+ // css::sdbc::XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+
+ // css::sdbc::XRowUpdate
+ virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override;
+ virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override;
+ virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override;
+ virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override;
+
+ // css::sdbc::XResultSetUpdate
+ virtual void SAL_CALL insertRow( ) override;
+ virtual void SAL_CALL updateRow( ) override;
+ virtual void SAL_CALL deleteRow( ) override;
+ virtual void SAL_CALL cancelRowUpdates( ) override;
+ virtual void SAL_CALL moveToInsertRow( ) override;
+ virtual void SAL_CALL moveToCurrentRow( ) override;
+
+ // css::sdbc::XRowSet
+ virtual void SAL_CALL execute( ) override;
+ virtual void SAL_CALL addRowSetListener( const css::uno::Reference< css::sdbc::XRowSetListener >& listener ) override;
+ virtual void SAL_CALL removeRowSetListener( const css::uno::Reference< css::sdbc::XRowSetListener >& listener ) override;
+
+ // css::sdb::XRowSetApproveBroadcaster
+ virtual void SAL_CALL addRowSetApproveListener( const css::uno::Reference< css::sdb::XRowSetApproveListener >& listener ) override;
+ virtual void SAL_CALL removeRowSetApproveListener( const css::uno::Reference< css::sdb::XRowSetApproveListener >& listener ) override;
+
+ // css::sdb::XRowsChangeBroadcaster
+ virtual void SAL_CALL addRowsChangeListener( const css::uno::Reference< css::sdb::XRowsChangeListener >& listener ) override;
+ virtual void SAL_CALL removeRowsChangeListener( const css::uno::Reference< css::sdb::XRowsChangeListener >& listener ) override;
+
+ // css::sdb::XResultSetAccess
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL createResultSet( ) override;
+
+ // css::util::XCancellable
+ virtual void SAL_CALL cancel( ) override;
+
+ // css::sdbcx::XDeleteRows
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL deleteRows( const css::uno::Sequence< css::uno::Any >& rows ) override;
+
+ // XParameters
+ virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override;
+ virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override;
+ virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override;
+ virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override;
+ virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override;
+ virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override;
+ virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override;
+ virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override;
+ virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override;
+ virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override;
+ virtual void SAL_CALL clearParameters( ) override;
+
+ // XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+ /** implement the <method>execute</method>, without calling the approve listeners and without building a new
+ connection
+ @param _rClearForNotification mutex to clear before doing the final notifications
+ */
+ void execute_NoApprove_NoNewConn(::osl::ResettableMutexGuard& _rClearForNotification);
+
+ /** call the RowSetApproveListeners<p/>
+ @throws css::sdb::RowSetVetoException if one of the listeners vetoed
+ @throws css::uno::RuntimeException
+ */
+ void approveExecution();
+
+ /// set m_xActiveConnection, fire a PropertyChangeEvent if necessary, do the event listener handling etc
+ void setActiveConnection( css::uno::Reference< css::sdbc::XConnection > const & _rxNewConn, bool _bFireEvent = true );
+
+ void implCancelRowUpdates( bool _bNotifyModified );
+
+ /** sets the given result set type/concurrency at the given statement, while respecting
+ possibly related data source settings
+ */
+ void setStatementResultSetType(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxStatement,
+ sal_Int32 _nDesiredResultSetType,
+ sal_Int32 _nDesiredResultSetConcurrency
+ );
+
+ /** initializes a given RowSet column with the ColumnSettings (width, format, hidden, etc.) from a
+ template column.
+
+ If the template column supports any of the known column settings, they're plain copied. If not,
+ the template column is examined for a TableName and Name property, and the table column described
+ by those is used to find and copy the column settings.
+ */
+ void impl_initializeColumnSettings_nothrow(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxTemplateColumn,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxRowSetColumn
+ );
+
+ /** initializes our parameters container (m_pParameters) according to the parameter columns as
+ obtained from our composer
+ */
+ void impl_initParametersContainer_nothrow();
+ /** disposes our parameters container
+ */
+ void impl_disposeParametersContainer_nothrow();
+
+ using ORowSetBase::getFastPropertyValue;
+ using ORowSetBase::firePropertyChange;
+ using ORowSetBase::doCancelModification;
+ using ORowSetBase::isModification;
+ using ORowSetBase::isModified;
+ using ORowSetBase::isNew;
+ };
+
+
+ // ORowSetClone
+
+ class ORowSetClone : public cppu::BaseMutex
+ ,public OSubComponent
+ ,public ORowSetBase
+ ,public ::comphelper::OPropertyArrayUsageHelper < ORowSetClone >
+ {
+ ORowSet* m_pParent;
+ sal_Int32 m_nFetchDirection;
+ sal_Int32 m_nFetchSize;
+ bool m_bIsBookmarkable;
+
+ protected:
+ // the clone can not insert anything
+ virtual void doCancelModification( ) override;
+ virtual bool isModification( ) override;
+ virtual bool isModified( ) override;
+ virtual bool isNew( ) override;
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const css::uno::Any& rValue) override;
+ public:
+ ORowSetClone( const css::uno::Reference<css::uno::XComponentContext>& _rContext, ORowSet& rParent, ::osl::Mutex* _pMutex );
+ virtual ~ORowSetClone() override;
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override
+ {
+ return css::uno::Sequence<sal_Int8>();
+ }
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // css::sdbc::XCloseable
+ virtual void SAL_CALL close( ) override;
+
+ // css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override
+ {
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+ }
+
+ // css::sdbc::XRowSet
+ virtual void SAL_CALL execute( ) override;
+ virtual void SAL_CALL addRowSetListener( const css::uno::Reference< css::sdbc::XRowSetListener >& listener ) override;
+ virtual void SAL_CALL removeRowSetListener( const css::uno::Reference< css::sdbc::XRowSetListener >& listener ) override;
+
+ // comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ protected:
+ using ORowSetBase::doCancelModification;
+ using ORowSetBase::isModification;
+ using ORowSetBase::isModified;
+ using ORowSetBase::isNew;
+ using ORowSetBase::rowDeleted;
+ };
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSetBase.cxx b/dbaccess/source/core/api/RowSetBase.cxx
new file mode 100644
index 000000000..46e612271
--- /dev/null
+++ b/dbaccess/source/core/api/RowSetBase.cxx
@@ -0,0 +1,1438 @@
+/* -*- 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 "RowSetBase.hxx"
+#include "CRowSetDataColumn.hxx"
+#include <connectivity/sdbcx/VCollection.hxx>
+#include "RowSetCache.hxx"
+#include <stringconstants.hxx>
+#include <sal/log.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <comphelper/sequence.hxx>
+#include <comphelper/seqstream.hxx>
+#include <connectivity/dbexception.hxx>
+#include <o3tl/safeint.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace dbaccess;
+using namespace connectivity;
+using namespace connectivity::sdbcx;
+using namespace comphelper;
+using namespace dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::cppu;
+using namespace ::osl;
+
+namespace dbaccess
+{
+
+// OEmptyCollection
+class OEmptyCollection : public sdbcx::OCollection
+{
+protected:
+ virtual void impl_refresh() override;
+ virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+public:
+ OEmptyCollection(::cppu::OWeakObject& _rParent,::osl::Mutex& _rMutex) : OCollection(_rParent, true, _rMutex, std::vector< OUString>()){}
+};
+
+void OEmptyCollection::impl_refresh()
+{
+}
+
+connectivity::sdbcx::ObjectType OEmptyCollection::createObject(const OUString& /*_rName*/)
+{
+ return connectivity::sdbcx::ObjectType();
+}
+
+// ORowSetBase
+
+ORowSetBase::ORowSetBase( const Reference<XComponentContext>& _rContext, ::cppu::OBroadcastHelper& _rBHelper, ::osl::Mutex* _pMutex )
+ :OPropertyStateContainer(_rBHelper)
+ ,m_pMutex(_pMutex)
+ ,m_pMySelf(nullptr)
+ ,m_rBHelper(_rBHelper)
+ ,m_aContext( _rContext )
+ ,m_nLastColumnIndex(-1)
+ ,m_nDeletedPosition(-1)
+ ,m_nResultSetType( ResultSetType::FORWARD_ONLY )
+ ,m_nResultSetConcurrency( ResultSetConcurrency::READ_ONLY )
+ ,m_bClone(false)
+ ,m_bIgnoreResult(false)
+ ,m_bBeforeFirst(true) // changed from sal_False
+ ,m_bAfterLast(false)
+ ,m_bIsInsertRow(false)
+{
+ sal_Int32 nRBT = PropertyAttribute::READONLY | PropertyAttribute::BOUND | PropertyAttribute::TRANSIENT;
+
+ registerPropertyNoMember( PROPERTY_ROWCOUNT, PROPERTY_ID_ROWCOUNT, nRBT, cppu::UnoType<sal_Int32>::get(), css::uno::Any(sal_Int32(0)) );
+ registerPropertyNoMember( PROPERTY_ISROWCOUNTFINAL, PROPERTY_ID_ISROWCOUNTFINAL, nRBT, cppu::UnoType<bool>::get(), css::uno::Any(false) );
+}
+
+ORowSetBase::~ORowSetBase()
+{
+ if(m_pColumns)
+ {
+ TDataColumns().swap(m_aDataColumns);
+ m_pColumns->acquire();
+ m_pColumns->disposing();
+ }
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > ORowSetBase::getTypes()
+{
+ return ::comphelper::concatSequences(ORowSetBase_BASE::getTypes(),OPropertyStateContainer::getTypes());
+}
+
+// css::uno::XInterface
+Any ORowSetBase::queryInterface( const Type & rType )
+{
+ Any aRet = ORowSetBase_BASE::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = OPropertyStateContainer::queryInterface(rType);
+ return aRet;
+}
+
+void SAL_CALL ORowSetBase::getFastPropertyValue(Any& rValue,sal_Int32 nHandle) const
+{
+ if(m_pCache)
+ {
+ switch(nHandle)
+ {
+ case PROPERTY_ID_ROWCOUNT:
+ rValue <<= impl_getRowCount();
+ break;
+ case PROPERTY_ID_ISROWCOUNTFINAL:
+ rValue <<= m_pCache->m_bRowCountFinal;
+ break;
+ default:
+ OPropertyStateContainer::getFastPropertyValue(rValue,nHandle);
+ }
+ }
+ else
+ OPropertyStateContainer::getFastPropertyValue(rValue,nHandle);
+}
+
+// OComponentHelper
+void SAL_CALL ORowSetBase::disposing()
+{
+ MutexGuard aGuard(*m_pMutex);
+
+ if ( m_pColumns )
+ {
+ TDataColumns().swap(m_aDataColumns);
+ m_pColumns->disposing();
+ }
+ if ( m_pCache )
+ {
+ m_pCache->deregisterOldRow(m_aOldRow);
+ m_pCache->deleteIterator(this);
+ }
+ m_pCache = nullptr;
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* ORowSetBase::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& SAL_CALL ORowSetBase::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+// XRow
+sal_Bool SAL_CALL ORowSetBase::wasNull( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+ return !((m_nLastColumnIndex != -1) && !m_aCurrentRow.isNull() && m_aCurrentRow != m_pCache->getEnd() && m_aCurrentRow->is())
+ || (**m_aCurrentRow)[m_nLastColumnIndex].isNull();
+}
+
+const ORowSetValue& ORowSetBase::getValue(sal_Int32 columnIndex)
+{
+ checkCache();
+ return impl_getValue(columnIndex);
+}
+
+const ORowSetValue& ORowSetBase::impl_getValue(sal_Int32 columnIndex)
+{
+ if ( m_bBeforeFirst || m_bAfterLast )
+ {
+ SAL_WARN("dbaccess", "ORowSetBase::getValue: Illegal call here (we're before first or after last)!");
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_CURSOR_BEFORE_OR_AFTER ), StandardSQLState::INVALID_CURSOR_POSITION, *m_pMySelf );
+ }
+
+ if ( impl_rowDeleted() )
+ {
+ return m_aEmptyValue;
+ }
+
+ bool bValidCurrentRow = ( !m_aCurrentRow.isNull() && m_aCurrentRow != m_pCache->getEnd() && m_aCurrentRow->is() );
+ if ( !bValidCurrentRow )
+ {
+ // currentrow is null when the clone moves the window
+ positionCache( MOVE_NONE );
+ m_aCurrentRow = m_pCache->m_aMatrixIter;
+ m_bIsInsertRow = false;
+ OSL_ENSURE(!m_aCurrentRow.isNull(),"ORowSetBase::getValue: we don't stand on a valid row! Row is null.");
+
+ bValidCurrentRow = ( !m_aCurrentRow.isNull() && m_aCurrentRow != m_pCache->getEnd() && m_aCurrentRow->is() );
+ }
+
+ if ( bValidCurrentRow )
+ {
+#if OSL_DEBUG_LEVEL > 0
+ ORowSetMatrix::const_iterator aCacheEnd;
+ ORowSetMatrix::iterator aCurrentRow;
+ aCacheEnd = m_pCache->getEnd();
+ aCurrentRow = m_aCurrentRow;
+ ORowSetCacheMap::const_iterator aCacheIter = m_aCurrentRow.getIter();
+ ORowSetCacheIterator_Helper aHelper = aCacheIter->second;
+ ORowSetMatrix::const_iterator k = aHelper.aIterator;
+ for (; k != m_pCache->getEnd(); ++k)
+ {
+ ORowSetValueVector* pTemp = k->get();
+ OSL_ENSURE( pTemp != reinterpret_cast<void*>(0xfeeefeee),"HALT!" );
+ }
+ OSL_ENSURE(!m_aCurrentRow.isNull() && m_aCurrentRow < m_pCache->getEnd() && aCacheIter != m_pCache->m_aCacheIterators.end(),"Invalid iterator set for currentrow!");
+#endif
+ ORowSetRow rRow = *m_aCurrentRow;
+ bool bValidPosition = rRow.is() && o3tl::make_unsigned(columnIndex) < rRow->size();
+ if (!bValidPosition)
+ {
+ SAL_WARN("dbaccess", "ORowSetBase::getValue: Invalid size of vector!");
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_CURSOR_BEFORE_OR_AFTER ), StandardSQLState::INVALID_CURSOR_POSITION, *m_pMySelf );
+ }
+ m_nLastColumnIndex = columnIndex;
+ return (*rRow)[m_nLastColumnIndex];
+ }
+
+ // we should normally never reach this
+ return m_aEmptyValue;
+}
+
+OUString SAL_CALL ORowSetBase::getString( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getString();
+}
+
+sal_Bool SAL_CALL ORowSetBase::getBoolean( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getBool();
+}
+
+sal_Int8 SAL_CALL ORowSetBase::getByte( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getInt8();
+}
+
+sal_Int16 SAL_CALL ORowSetBase::getShort( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getInt16();
+}
+
+sal_Int32 SAL_CALL ORowSetBase::getInt( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getInt32();
+}
+
+sal_Int64 SAL_CALL ORowSetBase::getLong( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getLong();
+}
+
+float SAL_CALL ORowSetBase::getFloat( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getFloat();
+}
+
+double SAL_CALL ORowSetBase::getDouble( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getDouble();
+}
+
+Sequence< sal_Int8 > SAL_CALL ORowSetBase::getBytes( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getSequence();
+}
+
+css::util::Date SAL_CALL ORowSetBase::getDate( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getDate();
+}
+
+css::util::Time SAL_CALL ORowSetBase::getTime( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getTime();
+}
+
+css::util::DateTime SAL_CALL ORowSetBase::getTimestamp( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ return getValue(columnIndex).getDateTime();
+}
+
+Reference< css::io::XInputStream > SAL_CALL ORowSetBase::getBinaryStream( sal_Int32 columnIndex )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ if ( m_bBeforeFirst || m_bAfterLast )
+ {
+ SAL_WARN("dbaccess", "ORowSetBase::getBinaryStream: Illegal call here (we're before first or after last)!");
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_CURSOR_BEFORE_OR_AFTER ), StandardSQLState::INVALID_CURSOR_POSITION, *m_pMySelf );
+ }
+
+ if ( impl_rowDeleted() )
+ {
+ return nullptr;
+ }
+
+ bool bValidCurrentRow = ( !m_aCurrentRow.isNull() && m_aCurrentRow != m_pCache->getEnd() && m_aCurrentRow->is() );
+ if ( !bValidCurrentRow )
+ {
+ positionCache( MOVE_NONE );
+ m_aCurrentRow = m_pCache->m_aMatrixIter;
+ m_bIsInsertRow = false;
+ OSL_ENSURE(!m_aCurrentRow.isNull(),"ORowSetBase::getBinaryStream: we don't stand on a valid row! Row is null.");
+
+ bValidCurrentRow = ( !m_aCurrentRow.isNull() && m_aCurrentRow != m_pCache->getEnd() && m_aCurrentRow->is() );
+ }
+
+ if ( bValidCurrentRow )
+ {
+ m_nLastColumnIndex = columnIndex;
+ return new ::comphelper::SequenceInputStream((**m_aCurrentRow)[m_nLastColumnIndex].getSequence());
+ }
+
+ // we should normally never reach this
+ return Reference< css::io::XInputStream >();
+}
+
+Reference< css::io::XInputStream > SAL_CALL ORowSetBase::getCharacterStream( sal_Int32 columnIndex )
+{
+ return getBinaryStream(columnIndex);
+}
+
+Any SAL_CALL ORowSetBase::getObject( sal_Int32 columnIndex, const Reference< XNameAccess >& /*typeMap*/ )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ return getValue(columnIndex).makeAny();
+}
+
+Reference< XRef > SAL_CALL ORowSetBase::getRef( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getRef", *m_pMySelf );
+ return nullptr;
+}
+
+Reference< XBlob > SAL_CALL ORowSetBase::getBlob( sal_Int32 columnIndex )
+{
+ return Reference< XBlob >(getValue(columnIndex).makeAny(),UNO_QUERY);
+}
+
+Reference< XClob > SAL_CALL ORowSetBase::getClob( sal_Int32 columnIndex )
+{
+ return Reference< XClob >(getValue(columnIndex).makeAny(),UNO_QUERY);
+}
+
+Reference< XArray > SAL_CALL ORowSetBase::getArray( sal_Int32 /*columnIndex*/ )
+{
+ ::dbtools::throwFeatureNotImplementedSQLException( "XRow::getArray", *m_pMySelf );
+ return nullptr;
+}
+
+// css::sdbcx::XRowLocate
+Any SAL_CALL ORowSetBase::getBookmark( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::getBookmark() Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ if ( m_bBeforeFirst || m_bAfterLast )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_BOOKMARK_BEFORE_OR_AFTER ), StandardSQLState::INVALID_CURSOR_POSITION, *m_pMySelf );
+
+ if ( impl_rowDeleted() )
+ ::dbtools::throwSQLException( DBA_RES( RID_STR_NO_BOOKMARK_DELETED ), StandardSQLState::INVALID_CURSOR_POSITION, *m_pMySelf );
+
+ OSL_ENSURE( m_aBookmark.hasValue(), "ORowSetBase::getBookmark: bookmark has no value!" );
+ return m_aBookmark;
+}
+
+sal_Bool SAL_CALL ORowSetBase::moveToBookmark( const Any& bookmark )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::moveToBookmark(Any) Clone = " << m_bClone);
+ OSL_ENSURE(bookmark.hasValue(),"ORowSetBase::moveToBookmark bookmark has no value!");
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+
+ if(!bookmark.hasValue() || m_nResultSetType == ResultSetType::FORWARD_ONLY)
+ {
+ if(bookmark.hasValue())
+ SAL_WARN("dbaccess", "MoveToBookmark is not possible when we are only forward");
+ else
+ SAL_WARN("dbaccess", "Bookmark is not valid");
+ throwFunctionSequenceException(*m_pMySelf);
+ }
+
+ checkCache();
+
+ bool bRet( notifyAllListenersCursorBeforeMove( aGuard ) );
+ if ( bRet )
+ {
+ // check if we are inserting a row
+ bool bWasNew = m_pCache->m_bNew || impl_rowDeleted();
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+
+ bRet = m_pCache->moveToBookmark(bookmark);
+ doCancelModification( );
+ if(bRet)
+ {
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( true, true, aOldValues, aGuard );
+ }
+ else
+ {
+ movementFailed();
+ }
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire( );
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::moveToBookmark(Any) = " << bRet << " Clone = " << m_bClone);
+ return bRet;
+}
+
+sal_Bool SAL_CALL ORowSetBase::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::moveRelativeToBookmark(Any," << rows << ") Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+
+ checkPositioningAllowed();
+
+ bool bRet( notifyAllListenersCursorBeforeMove( aGuard ) );
+ if ( bRet )
+ {
+ // check if we are inserting a row
+ bool bWasNew = m_pCache->m_bNew || rowDeleted();
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+
+ bRet = m_pCache->moveRelativeToBookmark(bookmark,rows);
+ doCancelModification( );
+ if(bRet)
+ {
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( true, true, aOldValues, aGuard );
+ }
+ else
+ movementFailed();
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire( );
+
+ // RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::moveRelativeToBookmark(Any," << rows << ") = " << bRet << " Clone = " << m_bClone);
+ return bRet;
+}
+
+sal_Int32 SAL_CALL ORowSetBase::compareBookmarks( const Any& _first, const Any& _second )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+ return m_pCache->compareBookmarks(_first,_second);
+}
+
+sal_Bool SAL_CALL ORowSetBase::hasOrderedBookmarks( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+ return m_pCache->hasOrderedBookmarks();
+}
+
+sal_Int32 SAL_CALL ORowSetBase::hashBookmark( const Any& bookmark )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+ return m_pCache->hashBookmark(bookmark);
+}
+
+// XResultSetMetaDataSupplier
+Reference< XResultSetMetaData > SAL_CALL ORowSetBase::getMetaData( )
+{
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+
+ Reference< XResultSetMetaData > xMeta;
+ if(m_pCache)
+ xMeta = m_pCache->getMetaData();
+
+ return xMeta;
+}
+
+// XColumnLocate
+sal_Int32 SAL_CALL ORowSetBase::findColumn( const OUString& columnName )
+{
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+ // it is possible to save some time here when we remember the names - position relation in a map
+ return m_pColumns ? m_pColumns->findColumn(columnName) : sal_Int32(0);
+}
+
+// css::sdbcx::XColumnsSupplier
+Reference< XNameAccess > SAL_CALL ORowSetBase::getColumns( )
+{
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aColumnsMutex );
+ if(!m_pColumns)
+ {
+ if (!m_pEmptyCollection)
+ m_pEmptyCollection.reset( new OEmptyCollection(*m_pMySelf,m_aColumnsMutex) );
+ return m_pEmptyCollection.get();
+ }
+
+ return m_pColumns.get();
+}
+
+// XResultSet
+sal_Bool SAL_CALL ORowSetBase::next( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::next() Clone = " << m_bClone);
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ bool bRet( notifyAllListenersCursorBeforeMove( aGuard ) );
+ if ( bRet )
+ {
+ // check if we are inserting a row
+ bool bWasNew = m_pCache->m_bNew || impl_rowDeleted();
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+
+ positionCache( MOVE_FORWARD );
+ bool bAfterLast = m_pCache->isAfterLast();
+ bRet = m_pCache->next();
+ doCancelModification( );
+
+ // if we were afterLast before next() then we still are,
+ // i.e. bAfterLast implies m_pCache->isAfterLast()
+ if (bAfterLast)
+ assert(m_pCache->isAfterLast());
+ // so the only way bAfterLast != m_pCache->isAfterLast()
+ // would be that we just arrived there,
+ if (bAfterLast != m_pCache->isAfterLast())
+ {
+ assert(!bAfterLast);
+ assert(m_pCache->isAfterLast());
+ }
+ // in which case we *did* move the cursor
+ if ( bRet || bAfterLast != m_pCache->isAfterLast() )
+ {
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( true, true, aOldValues, aGuard );
+ OSL_ENSURE(!m_bBeforeFirst,"BeforeFirst is true. I don't know why?");
+ }
+ else
+ {
+ // moved after the last row
+ movementFailed();
+ OSL_ENSURE(m_bAfterLast,"AfterLast is false. I don't know why?");
+ }
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire();
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::next() = " << bRet << " Clone = " << m_bClone);
+ return bRet;
+}
+
+sal_Bool SAL_CALL ORowSetBase::isBeforeFirst( )
+{
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ SAL_INFO("dbaccess", "ORowSetBase::isBeforeFirst() = " << m_bBeforeFirst << " Clone = " << m_bClone);
+
+ return m_bBeforeFirst;
+}
+
+sal_Bool SAL_CALL ORowSetBase::isAfterLast( )
+{
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+ SAL_INFO("dbaccess", "ORowSetBase::isAfterLast() = " << m_bAfterLast << " Clone = " << m_bClone);
+
+ return m_bAfterLast;
+}
+
+bool ORowSetBase::isOnFirst()
+{
+ return isFirst();
+}
+
+sal_Bool SAL_CALL ORowSetBase::isFirst( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::isFirst() Clone = " << m_bClone);
+
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ if ( m_bBeforeFirst || m_bAfterLast )
+ return false;
+
+ if ( impl_rowDeleted() )
+ return ( m_nDeletedPosition == 1 );
+
+ positionCache( MOVE_NONE );
+ bool bIsFirst = m_pCache->isFirst();
+
+ SAL_INFO("dbaccess", "ORowSetBase::isFirst() = " << bIsFirst << " Clone = " << m_bClone);
+ return bIsFirst;
+}
+
+bool ORowSetBase::isOnLast()
+{
+ return isLast();
+}
+
+sal_Bool SAL_CALL ORowSetBase::isLast( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::isLast() Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ if ( m_bBeforeFirst || m_bAfterLast )
+ return false;
+
+ if ( impl_rowDeleted() )
+ {
+ if ( !m_pCache->m_bRowCountFinal )
+ return false;
+ else
+ return ( m_nDeletedPosition == impl_getRowCount() );
+ }
+
+ positionCache( MOVE_NONE );
+ bool bIsLast = m_pCache->isLast();
+
+ SAL_INFO("dbaccess", "ORowSetBase::isLast() = " << bIsLast << " Clone = " << m_bClone);
+ return bIsLast;
+}
+
+void SAL_CALL ORowSetBase::beforeFirst( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::beforeFirst() Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+
+ checkPositioningAllowed();
+
+ // check if we are inserting a row
+ bool bWasNew = m_pCache->m_bNew || impl_rowDeleted();
+
+ if((bWasNew || !m_bBeforeFirst) && notifyAllListenersCursorBeforeMove(aGuard) )
+ {
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ if ( !m_bBeforeFirst )
+ {
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+ m_pCache->beforeFirst();
+ doCancelModification( );
+
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( true, true, aOldValues, aGuard );
+
+ // - IsModified
+ // - Isnew
+ aNotifier.fire();
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+
+ // to be done _after_ the notifications!
+ m_aOldRow->clearRow();
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::beforeFirst() Clone = " << m_bClone);
+}
+
+void SAL_CALL ORowSetBase::afterLast( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::afterLast() Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+ checkPositioningAllowed();
+
+ bool bWasNew = m_pCache->m_bNew || impl_rowDeleted();
+
+ if((bWasNew || !m_bAfterLast) && notifyAllListenersCursorBeforeMove(aGuard) )
+ {
+ // check if we are inserting a row
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ if(!m_bAfterLast)
+ {
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+
+ m_pCache->afterLast();
+ doCancelModification( );
+
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( true, true, aOldValues, aGuard );
+
+ // - IsModified
+ // - Isnew
+ aNotifier.fire();
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::afterLast() Clone = " << m_bClone);
+}
+
+bool SAL_CALL ORowSetBase::move(std::function<bool(ORowSetBase *)> const & _aCheckFunctor,
+ std::function<bool(ORowSetCache *)> const & _aMovementFunctor)
+{
+ SAL_INFO("dbaccess", "ORowSetBase::move() Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+ checkPositioningAllowed();
+
+ bool bRet( notifyAllListenersCursorBeforeMove( aGuard ) );
+ if( bRet )
+ {
+ // check if we are inserting a row
+ bool bWasNew = m_pCache->m_bNew || rowDeleted();
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+
+ bool bMoved = ( bWasNew || !_aCheckFunctor(this) );
+
+ bRet = _aMovementFunctor(m_pCache.get());
+ doCancelModification( );
+
+ if ( bRet )
+ {
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( bMoved, true, aOldValues, aGuard );
+ }
+ else
+ { // first goes wrong so there is no row
+ movementFailed();
+ }
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire();
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::move() = " << bRet << " Clone = " << m_bClone);
+ return bRet;
+}
+
+sal_Bool SAL_CALL ORowSetBase::first( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::first() Clone = " << m_bClone);
+ auto ioF_tmp = std::mem_fn(&ORowSetBase::isOnFirst);
+ auto F_tmp = std::mem_fn(&ORowSetCache::first);
+ return move(ioF_tmp,F_tmp);
+}
+
+sal_Bool SAL_CALL ORowSetBase::last( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::last() Clone = " << m_bClone);
+ auto ioL_tmp = std::mem_fn(&ORowSetBase::isOnLast);
+ auto L_tmp = std::mem_fn(&ORowSetCache::last);
+ return move(ioL_tmp,L_tmp);
+}
+
+sal_Int32 SAL_CALL ORowSetBase::getRow( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::getRow() Clone = " << m_bClone);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+
+ checkCache();
+ return impl_getRow();
+}
+
+sal_Int32 ORowSetBase::impl_getRow()
+{
+ sal_Int32 nPos = 0;
+ if ( m_bBeforeFirst )
+ nPos = 0;
+ else if ( m_bAfterLast )
+ nPos = impl_getRowCount() + 1;
+ else if ( impl_rowDeleted() )
+ nPos = m_nDeletedPosition;
+ else if ( !m_bClone && m_pCache->m_bNew )
+ nPos = 0;
+ else
+ {
+ positionCache( MOVE_NONE );
+ nPos = m_pCache->getRow();
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::impl_getRow() = " << nPos << " Clone = " << m_bClone);
+ return nPos;
+}
+
+sal_Bool SAL_CALL ORowSetBase::absolute( sal_Int32 row )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::absolute(" << row << ") Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+ checkPositioningAllowed();
+
+ bool bRet = ( row > 0 )
+ && notifyAllListenersCursorBeforeMove( aGuard );
+ if ( bRet )
+ {
+ // check if we are inserting a row
+ bool bWasNew = m_pCache->m_bNew || rowDeleted();
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+
+ bRet = m_pCache->absolute(row);
+ doCancelModification( );
+
+ if(bRet)
+ {
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( true, true, aOldValues, aGuard );
+ }
+ else
+ { // absolute movement goes wrong we stand left or right side of the rows
+ movementFailed();
+ }
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire();
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::absolute(" << row << ") = " << bRet << " Clone = " << m_bClone);
+ return bRet;
+}
+
+sal_Bool SAL_CALL ORowSetBase::relative( sal_Int32 rows )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::relative(" << rows << ") Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+
+ if(!rows)
+ return true; // in this case do nothing
+
+ checkPositioningAllowed();
+
+ bool bRet =
+ ( ( !m_bAfterLast || rows <= 0 )
+ && ( !m_bBeforeFirst || rows >= 0 )
+ && notifyAllListenersCursorBeforeMove( aGuard )
+ );
+
+ if ( bRet )
+ {
+ // check if we are inserting a row
+ bool bWasNew = m_pCache->m_bNew || rowDeleted();
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+
+ positionCache( rows > 0 ? MOVE_FORWARD : MOVE_BACKWARD );
+ bRet = m_pCache->relative(rows);
+ doCancelModification( );
+
+ if(bRet)
+ {
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( true, true, aOldValues, aGuard );
+ }
+ else
+ {
+ movementFailed();
+ }
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire();
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::relative(" << rows << ") = " << bRet << " Clone = " << m_bClone);
+ return bRet;
+}
+
+sal_Bool SAL_CALL ORowSetBase::previous( )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::previous() Clone = " << m_bClone);
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::ResettableMutexGuard aGuard( *m_pMutex );
+
+ checkPositioningAllowed();
+
+ bool bRet = !m_bBeforeFirst
+ && notifyAllListenersCursorBeforeMove(aGuard);
+
+ if ( bRet )
+ {
+ // check if we are inserting a row
+ bool bWasNew = m_pCache->m_bNew || rowDeleted();
+
+ ORowSetNotifier aNotifier( this );
+ // this will call cancelRowModification on the cache if necessary
+
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+
+ positionCache( MOVE_BACKWARD );
+ bRet = m_pCache->previous();
+ doCancelModification( );
+
+ // if m_bBeforeFirst is false and bRet is false then we stood on the first row
+ if(!m_bBeforeFirst || bRet)
+ {
+ // notification order
+ // - column values
+ // - cursorMoved
+ setCurrentRow( true, true, aOldValues, aGuard );
+ }
+ else
+ {
+ SAL_WARN("dbaccess", "ORowSetBase::previous: inconsistency!" );
+ // we should never reach this place, as we should not get into this whole branch if m_bBeforeFirst
+ // was |true| from the beginning
+ movementFailed();
+ }
+
+ // - IsModified
+ // - IsNew
+ aNotifier.fire();
+
+ // - RowCount/IsRowCountFinal
+ fireRowcount();
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::previous() = " << bRet << " Clone = " << m_bClone);
+ return bRet;
+}
+
+void ORowSetBase::setCurrentRow( bool _bMoved, bool _bDoNotify, const ORowSetRow& _rOldValues, ::osl::ResettableMutexGuard& _rGuard )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::setCurrentRow() Clone = " << m_bClone);
+ m_bBeforeFirst = m_pCache->isBeforeFirst();
+ m_bAfterLast = m_pCache->isAfterLast();
+
+ if(!(m_bBeforeFirst || m_bAfterLast))
+ {
+ m_aBookmark = m_pCache->getBookmark();
+ OSL_ENSURE(m_aBookmark.hasValue(),"Bookmark has no value!");
+ m_aCurrentRow = m_pCache->m_aMatrixIter;
+ m_bIsInsertRow = false;
+ OSL_ENSURE(!m_aCurrentRow.isNull(),"CurrentRow is null!");
+ OSL_ENSURE(!m_aCurrentRow.isNull() && m_aCurrentRow != m_pCache->getEnd(),"Position of matrix iterator isn't valid!");
+ OSL_ENSURE(m_aCurrentRow->is(),"Currentrow isn't valid");
+ OSL_ENSURE(m_aBookmark.hasValue(),"Bookmark has no value!");
+
+ m_aCurrentRow = m_pCache->m_aMatrixIter;
+ m_bIsInsertRow = false;
+ OSL_ENSURE(!m_aCurrentRow.isNull(),"CurrentRow is nul after positionCache!");
+#if OSL_DEBUG_LEVEL > 0
+ ORowSetRow rRow = *m_aCurrentRow;
+ OSL_ENSURE(rRow.is() ,"Invalid size of vector!");
+#endif
+
+ // notification order
+ // - column values
+ if ( _bDoNotify )
+ firePropertyChange(_rOldValues);
+
+ }
+ else
+ {
+ m_aOldRow->clearRow();
+ m_aCurrentRow = m_pCache->getEnd();
+ m_aBookmark = Any();
+ }
+
+ // TODO: can this be done before the notifications?
+ if(!(m_bBeforeFirst || m_bAfterLast) && !m_aCurrentRow.isNull() && m_aCurrentRow->is() && m_aCurrentRow != m_pCache->getEnd())
+ m_aOldRow->setRow(new ORowSetValueVector( *(*m_aCurrentRow) ));
+
+ if ( _bMoved && _bDoNotify )
+ // - cursorMoved
+ notifyAllListenersCursorMoved( _rGuard );
+
+ SAL_INFO("dbaccess", "ORowSetBase::setCurrentRow() Clone = " << m_bClone);
+}
+
+void ORowSetBase::checkPositioningAllowed()
+{
+ if(!m_pCache || m_nResultSetType == ResultSetType::FORWARD_ONLY)
+ throwFunctionSequenceException(*m_pMySelf);
+}
+
+Reference< XInterface > ORowSetBase::getStatement()
+{
+ return nullptr;
+}
+
+void SAL_CALL ORowSetBase::refreshRow( )
+{
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+ if ( impl_rowDeleted() )
+ throwSQLException( "The current row is deleted", StandardSQLState::INVALID_CURSOR_STATE, Reference< XRowSet >( this ) );
+
+ if(!(m_bBeforeFirst || m_bAfterLast))
+ {
+ bool bWasNew = m_pCache->m_bNew || impl_rowDeleted();
+ ORowSetRow aOldValues = getOldRow(bWasNew);
+ positionCache( MOVE_NONE );
+ m_pCache->refreshRow();
+ firePropertyChange(aOldValues);
+ }
+}
+
+sal_Bool SAL_CALL ORowSetBase::rowUpdated( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+
+ if ( impl_rowDeleted() )
+ return false;
+
+ return m_pCache->rowUpdated();
+}
+
+sal_Bool SAL_CALL ORowSetBase::rowInserted( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+
+ checkCache();
+
+ if ( impl_rowDeleted() )
+ return false;
+
+ return m_pCache->rowInserted();
+}
+
+sal_Bool SAL_CALL ORowSetBase::rowDeleted( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ checkCache();
+ return impl_rowDeleted();
+}
+
+bool ORowSetBase::impl_rowDeleted( )
+{
+ return !m_aBookmark.hasValue() && !m_bBeforeFirst && !m_bAfterLast;
+}
+
+// XWarningsSupplier
+Any SAL_CALL ORowSetBase::getWarnings( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+
+ if ( m_pCache )
+ {
+ Reference< XWarningsSupplier > xWarnings( m_pCache->m_xSet.get(), UNO_QUERY );
+ if ( xWarnings.is() )
+ return xWarnings->getWarnings();
+ }
+
+ return Any();
+}
+
+void SAL_CALL ORowSetBase::clearWarnings( )
+{
+ ::osl::MutexGuard aGuard( *m_pMutex );
+
+ if ( m_pCache )
+ {
+ Reference< XWarningsSupplier > xWarnings( m_pCache->m_xSet.get(), UNO_QUERY );
+ if ( xWarnings.is() )
+ xWarnings->clearWarnings();
+ }
+}
+
+void ORowSetBase::firePropertyChange(const ORowSetRow& _rOldRow)
+{
+ if (!isPropertyChangeNotificationEnabled())
+ return;
+
+ SAL_INFO("dbaccess", "ORowSetBase::firePropertyChange" );
+ SAL_INFO("dbaccess", "ORowSetBase::firePropertyChange() Clone = " << m_bClone);
+ OSL_ENSURE(m_pColumns,"Columns can not be NULL here!");
+ sal_Int32 i=0;
+ for (auto const& dataColumn : m_aDataColumns)
+ {
+ try
+ {
+ dataColumn->fireValueChange(_rOldRow.is() ? (*_rOldRow)[i+1] : ::connectivity::ORowSetValue());
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "firePropertyChange: Exception on column " << i);
+ }
+ ++i;
+ }
+ SAL_INFO("dbaccess", "ORowSetBase::firePropertyChange() Clone = " << m_bClone);
+}
+
+void ORowSetBase::firePropertyChange(sal_Int32 _nPos,const ::connectivity::ORowSetValue& _rOldValue)
+{
+ OSL_ENSURE(_nPos < static_cast<sal_Int32>(m_aDataColumns.size()),"nPos is invalid!");
+ m_aDataColumns[_nPos]->fireValueChange(_rOldValue);
+}
+
+void ORowSetBase::fireRowcount()
+{
+}
+
+bool ORowSetBase::notifyAllListenersCursorBeforeMove(::osl::ResettableMutexGuard& /*_rGuard*/)
+{
+ return true;
+}
+
+void ORowSetBase::notifyAllListenersCursorMoved(::osl::ResettableMutexGuard& /*_rGuard*/)
+{
+}
+
+bool ORowSetBase::isPropertyChangeNotificationEnabled() const
+{
+ return true;
+}
+
+void ORowSetBase::fireProperty( sal_Int32 _nProperty, bool _bNew, bool _bOld )
+{
+ Any aNew( _bNew );
+ Any aOld( _bOld );
+ fire( &_nProperty, &aNew, &aOld, 1, false );
+}
+
+void ORowSetBase::positionCache( CursorMoveDirection _ePrepareForDirection )
+{
+ SAL_INFO("dbaccess", "ORowSetBase::positionCache() Clone = " << m_bClone);
+
+ bool bSuccess = false;
+ if ( m_aBookmark.hasValue() )
+ {
+ if (_ePrepareForDirection == MOVE_NONE_REFRESH ||
+ (m_pCache->isAfterLast() != bool(isAfterLast())) || ( m_pCache->isBeforeFirst() != bool(isBeforeFirst()) ) ||
+ m_pCache->compareBookmarks( m_aBookmark, m_pCache->getBookmark() ) != CompareBookmark::EQUAL )
+ bSuccess = m_pCache->moveToBookmark( m_aBookmark );
+ else
+ bSuccess = true;
+ }
+ else
+ {
+ if ( m_bBeforeFirst )
+ {
+ m_pCache->beforeFirst();
+ bSuccess = true;
+ }
+ else if ( m_bAfterLast )
+ {
+ m_pCache->afterLast();
+ bSuccess = true;
+ }
+ else
+ {
+ OSL_ENSURE( m_nDeletedPosition >= 1, "ORowSetBase::positionCache: no bookmark, and no valid 'deleted position'!" );
+ switch ( _ePrepareForDirection )
+ {
+ case MOVE_FORWARD:
+ if ( m_nDeletedPosition > 1 )
+ bSuccess = m_pCache->absolute( m_nDeletedPosition - 1 );
+ else
+ {
+ m_pCache->beforeFirst();
+ bSuccess = true;
+ }
+ break;
+
+ case MOVE_BACKWARD:
+ if ( m_pCache->m_bRowCountFinal && ( m_nDeletedPosition == impl_getRowCount() ) )
+ {
+ m_pCache->afterLast();
+ bSuccess = true;
+ }
+ else
+ bSuccess = m_pCache->absolute( m_nDeletedPosition );
+ break;
+
+ case MOVE_NONE:
+ case MOVE_NONE_REFRESH:
+ bSuccess = false; // will be asserted below
+ break;
+ }
+ }
+ }
+ OSL_ENSURE( bSuccess, "ORowSetBase::positionCache: failed!" );
+
+ SAL_INFO("dbaccess", "ORowSetBase::positionCache() Clone = " << m_bClone);
+}
+
+void ORowSetBase::checkCache()
+{
+ ::connectivity::checkDisposed(m_rBHelper.bDisposed);
+ if(!m_pCache)
+ throwFunctionSequenceException(*m_pMySelf);
+}
+
+void ORowSetBase::movementFailed()
+{
+ SAL_INFO("dbaccess", "ORowSetBase::movementFailed() Clone = " << m_bClone);
+ m_aOldRow->clearRow();
+ m_aCurrentRow = m_pCache->getEnd();
+ m_bBeforeFirst = m_pCache->isBeforeFirst();
+ m_bAfterLast = m_pCache->isAfterLast();
+ m_aBookmark = Any();
+ OSL_ENSURE(m_bBeforeFirst || m_bAfterLast,"BeforeFirst or AfterLast is wrong!");
+ SAL_INFO("dbaccess", "ORowSetBase::movementFailed() Clone = " << m_bClone);
+}
+
+ORowSetRow ORowSetBase::getOldRow(bool _bWasNew)
+{
+ OSL_ENSURE(m_aOldRow.is(),"RowSetRowHElper isn't valid!");
+ ORowSetRow aOldValues;
+ if ( !_bWasNew && m_aOldRow->getRow().is() )
+ aOldValues = new ORowSetValueVector( *(m_aOldRow->getRow())); // remember the old values
+ return aOldValues;
+}
+
+void ORowSetBase::getPropertyDefaultByHandle( sal_Int32 /*_nHandle*/, Any& _rDefault ) const
+{
+ _rDefault.clear();
+}
+
+void ORowSetBase::onDeleteRow( const Any& _rBookmark )
+{
+ if ( rowDeleted() )
+ // not interested in
+ return;
+
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ //OSL_ENSURE( m_aBookmark.hasValue(), "ORowSetBase::onDeleteRow: Bookmark isn't valid!" );
+ if ( compareBookmarks( _rBookmark, m_aBookmark ) == CompareBookmark::EQUAL )
+ {
+ positionCache( MOVE_NONE );
+ m_nDeletedPosition = m_pCache->getRow();
+ }
+}
+
+void ORowSetBase::onDeletedRow( const Any& _rBookmark, sal_Int32 _nPos )
+{
+ if ( rowDeleted() )
+ {
+ // if we're a clone, and on a deleted row, and the main RowSet deleted another
+ // row (only the main RowSet can, clones can't), which is *before* our
+ // deleted position, then we have to adjust this position
+ if ( m_bClone && ( _nPos < m_nDeletedPosition ) )
+ --m_nDeletedPosition;
+ return;
+ }
+
+ ::osl::MutexGuard aGuard( *m_pMutex );
+ if ( compareBookmarks( _rBookmark, m_aBookmark ) == CompareBookmark::EQUAL )
+ {
+ m_aOldRow->clearRow();
+ m_aCurrentRow = m_pCache->getEnd();
+ m_aBookmark = Any();
+ }
+}
+
+sal_Int32 ORowSetBase::impl_getRowCount() const
+{
+ sal_Int32 nRowCount( m_pCache->m_nRowCount );
+ if ( const_cast< ORowSetBase* >( this )->rowDeleted() && !m_pCache->m_bNew )
+ ++nRowCount;
+ return nRowCount;
+}
+
+struct ORowSetNotifierImpl
+{
+ std::vector<sal_Int32> aChangedColumns;
+ ORowSetValueVector::Vector aRow;
+};
+
+
+ORowSetNotifier::ORowSetNotifier( ORowSetBase* _pRowSet )
+ :m_pRowSet( _pRowSet )
+ ,m_bWasNew( false )
+ ,m_bWasModified( false )
+{
+
+ OSL_ENSURE( m_pRowSet, "ORowSetNotifier::ORowSetNotifier: invalid row set. This will crash." );
+
+ // remember the "inserted" and "modified" state for later firing
+ m_bWasNew = m_pRowSet->isNew( ORowSetBase::GrantNotifierAccess() );
+ m_bWasModified = m_pRowSet->isModified( ORowSetBase::GrantNotifierAccess() );
+
+ // if the row set is on the insert row, then we need to cancel this
+ if ( m_pRowSet->isModification( ORowSetBase::GrantNotifierAccess() ) )
+ m_pRowSet->doCancelModification( ORowSetBase::GrantNotifierAccess() );
+}
+
+ORowSetNotifier::ORowSetNotifier( ORowSetBase* _pRowSet, ORowSetValueVector::Vector&& i_aRow )
+ :m_pImpl(new ORowSetNotifierImpl)
+ ,m_pRowSet( _pRowSet )
+ ,m_bWasNew( false )
+ ,m_bWasModified( false )
+{
+
+ OSL_ENSURE( m_pRowSet, "ORowSetNotifier::ORowSetNotifier: invalid row set. This will crash." );
+ m_pImpl->aRow = std::move(i_aRow); // yes, create a copy to store the old values
+}
+
+ORowSetNotifier::~ORowSetNotifier( )
+{
+}
+
+void ORowSetNotifier::fire()
+{
+ // we're not interested in firing changes FALSE->TRUE, only TRUE->FALSE.
+ // (the former would be quite pathological, e.g. after a failed movement)
+
+ if ( m_bWasModified
+ && ( m_bWasModified != m_pRowSet->isModified( ORowSetBase::GrantNotifierAccess() ) )
+ )
+ m_pRowSet->fireProperty( PROPERTY_ID_ISMODIFIED, false, true, ORowSetBase::GrantNotifierAccess() );
+
+ if ( m_bWasNew
+ && ( m_bWasNew != m_pRowSet->isNew( ORowSetBase::GrantNotifierAccess() ) )
+ )
+ m_pRowSet->fireProperty( PROPERTY_ID_ISNEW, false, true, ORowSetBase::GrantNotifierAccess() );
+}
+
+std::vector<sal_Int32>& ORowSetNotifier::getChangedColumns() const
+{
+ OSL_ENSURE(m_pImpl, "Illegal CTor call, use the other one!");
+ return m_pImpl->aChangedColumns;
+}
+
+void ORowSetNotifier::firePropertyChange()
+{
+ OSL_ENSURE(m_pImpl, "Illegal CTor call, use the other one!");
+ if (m_pImpl)
+ {
+ for (auto const& changedColumn : m_pImpl->aChangedColumns)
+ {
+ m_pRowSet->firePropertyChange(changedColumn-1 ,m_pImpl->aRow[changedColumn-1], ORowSetBase::GrantNotifierAccess());
+ }
+ if ( !m_pImpl->aChangedColumns.empty() )
+ m_pRowSet->fireProperty(PROPERTY_ID_ISMODIFIED,true,false, ORowSetBase::GrantNotifierAccess());
+ }
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSetBase.hxx b/dbaccess/source/core/api/RowSetBase.hxx
new file mode 100644
index 000000000..f5443a2af
--- /dev/null
+++ b/dbaccess/source/core/api/RowSetBase.hxx
@@ -0,0 +1,402 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <memory>
+#include <cppuhelper/implbase10.hxx>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <cppuhelper/interfacecontainer.h>
+#include <connectivity/sqlerror.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <comphelper/propertystatecontainer.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/util/XNumberFormatTypes.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include "RowSetRow.hxx"
+#include "RowSetCacheIterator.hxx"
+
+#include <functional>
+
+namespace com::sun::star {
+ namespace sdb { struct RowChangeEvent; }
+ namespace lang { struct Locale; }
+}
+
+namespace dbaccess
+{
+ class OEmptyCollection;
+
+ typedef ::cppu::ImplHelper10< css::sdbcx::XRowLocate,
+ css::sdbc::XRow,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::sdbc::XWarningsSupplier,
+ css::sdbc::XColumnLocate,
+ css::sdbcx::XColumnsSupplier,
+ css::lang::XServiceInfo,
+ css::sdbc::XRowSet,
+ css::sdbc::XCloseable,
+ css::lang::XUnoTunnel> ORowSetBase_BASE;
+
+ class ORowSetCache;
+ class ORowSetDataColumns;
+ class ORowSetCacheIterator;
+ class ORowSetDataColumn;
+ class ORowSetBase : public ORowSetBase_BASE,
+ public ::comphelper::OPropertyStateContainer,
+ public ::comphelper::OPropertyArrayUsageHelper<ORowSetBase> // this class hold the static property info
+ {
+ protected:
+ typedef std::vector<ORowSetDataColumn*> TDataColumns;
+ ::osl::Mutex* m_pMutex; // this is the mutex from the rowset itself
+ ::osl::Mutex // we need an extra mutex for columns to prevent deadlock when setting new values
+ // for a row
+ m_aColumnsMutex;
+
+ css::uno::Any m_aBookmark;
+ ORowSetCacheIterator m_aCurrentRow; // contains the actual fetched row
+ TORowSetOldRowHelperRef m_aOldRow;
+ TDataColumns m_aDataColumns; // holds the columns as m_pColumns but know the implementation class
+ connectivity::ORowSetValue m_aEmptyValue; // only for error case
+
+ ::cppu::OWeakObject* m_pMySelf; // set by derived classes
+ std::shared_ptr<ORowSetCache> m_pCache; // the cache is used by the rowset and his clone (shared)
+ std::unique_ptr<ORowSetDataColumns> m_pColumns; // represent the select columns
+ ::cppu::OBroadcastHelper& m_rBHelper; // must be set from the derived classes
+ // is used when the formatkey for database types is set
+ css::uno::Reference< css::util::XNumberFormatTypes> m_xNumberFormatTypes;
+ std::unique_ptr<OEmptyCollection> m_pEmptyCollection;
+
+ css::uno::Reference< css::uno::XComponentContext> m_aContext;
+ ::connectivity::SQLError m_aErrors;
+
+ sal_Int32 m_nLastColumnIndex; // the last column ask for, used for wasNull()
+ sal_Int32 m_nDeletedPosition; // is set only when a row was deleted
+ sal_Int32 m_nResultSetType; // fetch property
+ sal_Int32 m_nResultSetConcurrency;
+ bool m_bClone; // I'm clone or not
+ bool m_bIgnoreResult ;
+ bool m_bBeforeFirst : 1;
+ bool m_bAfterLast : 1;
+ bool m_bIsInsertRow : 1;
+
+ protected:
+ ORowSetBase(
+ const css::uno::Reference<css::uno::XComponentContext>& _rContext,
+ ::cppu::OBroadcastHelper& _rBHelper,
+ ::osl::Mutex* _pMutex
+ );
+
+ // fire a notification for all that are listening on column::VALUE property
+ void firePropertyChange(const ORowSetRow& _rOldRow);
+ // fire a change for one column
+ // _nPos starts at zero
+ void firePropertyChange(sal_Int32 _nPos,const ::connectivity::ORowSetValue& _rNewValue);
+
+ // fire if rowcount changed
+ virtual void fireRowcount();
+ // notify row changed
+ virtual bool notifyAllListenersCursorBeforeMove(::osl::ResettableMutexGuard& _rGuard);
+ // notify cursor moved
+ virtual void notifyAllListenersCursorMoved(::osl::ResettableMutexGuard& _rGuard);
+
+ // cancel the insertion, if necessary (means if we're on the insert row)
+ virtual void doCancelModification( ) = 0;
+ // return <TRUE/> if and only if we're using the insert row (means: we're updating _or_ inserting)
+ virtual bool isModification( ) = 0;
+ // return <TRUE/> if and only if the current row is modified
+ // TODO: isn't this the same as isModification?
+ virtual bool isModified( ) = 0;
+ // return <TRUE/> if and only if the current row is the insert row
+ virtual bool isNew( ) = 0;
+ // return <TRUE/> if the property change notification should be fired
+ // upon property change.
+ virtual bool isPropertyChangeNotificationEnabled() const;
+ // notify the change of a boolean property
+ void fireProperty( sal_Int32 _nProperty, bool _bNew, bool _bOld );
+
+ // OPropertyStateContainer
+ virtual void getPropertyDefaultByHandle( sal_Int32 _nHandle, css::uno::Any& _rDefault ) const override;
+ virtual void SAL_CALL getFastPropertyValue(css::uno::Any& rValue,sal_Int32 nHandle) const override;
+
+ enum CursorMoveDirection
+ {
+ /// denotes a cursor move forward
+ MOVE_FORWARD,
+ /// denotes a cursor move backwards
+ MOVE_BACKWARD,
+ /// denotes no cursor move at all, but move cache to current row (if it is not there already)
+ MOVE_NONE,
+ /// denotes no cursor move at all, but force the cache to move to current row (and refresh the row)
+ MOVE_NONE_REFRESH
+ };
+ /** positions the cache in preparation of a cursor move
+
+ Normally, the cache is simply moved to our bookmark (m_aBookmark). If however the current
+ row is deleted, then the cache is properly positioned for a following cursor movement in the
+ given direction.
+
+ @param _ePrepareForDirection
+ the direction into which the cursor should be moved after the call. If we're currently not on
+ a deleted row, this parameter is ignored, since in this case the cache is simply moved to
+ m_aBookmark.</br>
+ If, however, we're currently on a deleted row, this is used to properly position the cache
+ using <member>m_nDeletedPosition</member>.<br/>
+ In this case, MOVE_NONE(_REFRESH) is not supported. This is because the deleted row
+ (to which the RowSet currently points to) is not present in the cache. So, you cannot move the
+ cache to this row.
+ */
+ void positionCache( CursorMoveDirection _ePrepareForDirection );
+
+ // returns a value of a column of the current row
+ const connectivity::ORowSetValue& getValue(sal_Int32 columnIndex);
+ // the cache has to be checked before calling this method
+ const connectivity::ORowSetValue& impl_getValue(sal_Int32 columnIndex);
+ // sets the current and the bookmark
+ void setCurrentRow( bool _bMoved, bool _bDoNotify, const ORowSetRow& _rOldValues, ::osl::ResettableMutexGuard& _rGuard);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ void checkPositioningAllowed();
+ // checks if the cache is null
+ void checkCache();
+ // sets the bookmark to Any()
+ // m_aCurrentRow to end of matrix
+ // m_aOldRow to NULL
+ void movementFailed();
+
+ ORowSetRow getOldRow(bool _bWasNew);
+ /** move the cache the position defined by the member functor
+ @param _aCheckFunctor
+ Return <TRUE/> when we already stand on the row we want to.
+ @param _aMovementFunctor
+ The method used to move.
+ @return
+ <TRUE/> if movement was successful.
+ */
+ bool SAL_CALL move( std::function<bool(ORowSetBase *)> const & _aCheckFunctor,
+ std::function<bool(ORowSetCache *)> const & _aMovementFunctor);
+
+ /** same meaning as isFirst. Only need by mem_fun
+ @return
+ <TRUE/> if so.
+ */
+ bool isOnFirst();
+ /** same meaning as isLast. Only need by mem_fun
+ @return
+ <TRUE/> if so.
+ */
+ bool isOnLast();
+
+ /** returns the current row count
+
+ This function takes into account that we might actually be positioned on a
+ deleted row, so that m_pCache->m_nRowCount does not really reflect the actual
+ count.
+
+ @precond
+ Our mutex is locked.
+ */
+ sal_Int32 impl_getRowCount() const;
+
+ // the checkCache has to be called before calling this methods
+ sal_Int32 impl_getRow();
+ bool impl_rowDeleted();
+
+ public:
+ virtual ~ORowSetBase() override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing();
+
+ // css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override
+ {
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+ }
+
+ // comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+
+ // css::sdbc::XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+ // css::sdbc::XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+
+ // css::sdbc::XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+
+ // css::sdbcx::XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+
+ // css::sdbc::XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+
+ // css::sdbcx::XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark( ) override;
+ virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override;
+ virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override;
+ virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override;
+
+ // css::sdbc::XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+
+ // css::sdbc::XRowSet
+ virtual void SAL_CALL execute( ) override = 0;
+ virtual void SAL_CALL addRowSetListener( const css::uno::Reference< css::sdbc::XRowSetListener >& listener ) override = 0;
+ virtual void SAL_CALL removeRowSetListener( const css::uno::Reference< css::sdbc::XRowSetListener >& listener ) override = 0;
+
+ // is called when the rowset is going to delete this bookmark _rBookmark
+ void onDeleteRow( const css::uno::Any& _rBookmark );
+ // is called when the rowset has deleted this bookmark _rBookmark
+ void onDeletedRow( const css::uno::Any& _rBookmark, sal_Int32 _nPos );
+
+ // granular access control
+ struct GrantNotifierAccess { friend class ORowSetNotifier; private: GrantNotifierAccess () { } };
+
+ // cancel the insertion, if necessary (means if we're on the insert row)
+ void doCancelModification( const GrantNotifierAccess& ) { doCancelModification(); }
+ bool isModification( const GrantNotifierAccess& ) { return isModification(); }
+ bool isModified( const GrantNotifierAccess& ) { return isModified(); }
+ bool isNew( const GrantNotifierAccess& ) { return isNew(); }
+ bool isInsertRow() const { return m_bIsInsertRow; } // isNew() || isModified(); }
+ void fireProperty( sal_Int32 _nProperty, bool _bNew, bool _bOld, const GrantNotifierAccess& )
+ {
+ fireProperty( _nProperty, _bNew, _bOld );
+ }
+ void firePropertyChange(sal_Int32 _nPos,const ::connectivity::ORowSetValue& _rNewValue, const GrantNotifierAccess& )
+ {
+ firePropertyChange(_nPos,_rNewValue);
+ }
+ using ::comphelper::OPropertyStateContainer::getFastPropertyValue;
+ };
+
+ /** eases the handling of the doCancelModification and notifyCancelInsert methods
+
+ <p>The class can only be used on the stack, within a method of ORowSetBase (or derivees)</p>
+ */
+ struct ORowSetNotifierImpl;
+ class ORowSetNotifier
+ {
+ private:
+ std::unique_ptr<ORowSetNotifierImpl> m_pImpl;
+ ORowSetBase* m_pRowSet;
+ // not acquired! This is not necessary because this class here is to be used on the stack within
+ // a method of ORowSetBase (or derivees)
+ bool m_bWasNew;
+ bool m_bWasModified;
+
+ public:
+ /** constructs the object, and cancels the insertion
+
+ @see ORowSetBase::doCancelModification
+ */
+ explicit ORowSetNotifier( ORowSetBase* m_pRowSet );
+
+ /** use this one to construct a vector for change value notification
+ */
+ ORowSetNotifier( ORowSetBase* m_pRowSet, ORowSetValueVector::Vector&& i_aRow );
+
+ // destructs the object. <member>fire</member> has to be called before.
+ ~ORowSetNotifier( );
+
+ /** notifies the insertion
+
+ <p>This has <em>not</em> been put into the destructor by intention!<br/>
+
+ The destructor is called during stack unwinding in case of an exception, so if we would do
+ listener notification there, this would have the potential of another exception during stack
+ unwinding, which would terminate the application.</p>
+
+ @see ORowSetBase::notifyCancelInsert
+ */
+ void fire();
+
+ /** notifies value change events and notifies IsModified
+ @param i_aChangedColumns the index of the changed value columns
+ @param i_aRow the old values
+ @see ORowSetBase::notifyCancelInsert
+ */
+ void firePropertyChange();
+
+ /** use this one to store the inde of the changed column values
+ */
+ std::vector<sal_Int32>& getChangedColumns() const;
+
+ };
+
+} // end of namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSetCache.cxx b/dbaccess/source/core/api/RowSetCache.cxx
new file mode 100644
index 000000000..8a23d6624
--- /dev/null
+++ b/dbaccess/source/core/api/RowSetCache.cxx
@@ -0,0 +1,1713 @@
+/* -*- 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 <memory>
+#include "BookmarkSet.hxx"
+#include "KeySet.hxx"
+#include "OptimisticSet.hxx"
+#include "RowSetBase.hxx"
+#include "RowSetCache.hxx"
+#include "StaticSet.hxx"
+#include "WrappedResultSet.hxx"
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <com/sun/star/sdbcx/Privilege.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+
+#include <comphelper/extract.hxx>
+#include <comphelper/types.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/sqliterator.hxx>
+#include <connectivity/sqlnode.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <sqlbison.hxx>
+#include <tools/diagnose_ex.h>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+
+#include <algorithm>
+
+using namespace dbaccess;
+using namespace dbtools;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::cppu;
+using namespace ::osl;
+
+// This class calls m_pCacheSet->FOO_checked(..., sal_False)
+// (where FOO is absolute, last, previous)
+// when it does not immediately care about the values in the row's columns.
+// As a corollary, m_pCacheSet may be left in an inconsistent state,
+// and all ->fillFOO calls (and ->getFOO) may fail or give wrong results,
+// until m_pCacheSet is moved (or refreshed) again.
+// So always make sure m_pCacheSet is moved or refreshed before accessing column values.
+
+
+ORowSetCache::ORowSetCache(const Reference< XResultSet >& _xRs,
+ const Reference< XSingleSelectQueryAnalyzer >& _xAnalyzer,
+ const Reference<XComponentContext>& _rContext,
+ const OUString& _rUpdateTableName,
+ bool& _bModified,
+ bool& _bNew,
+ const ORowSetValueVector& _aParameterValueForCache,
+ const OUString& i_sRowSetFilter,
+ sal_Int32 i_nMaxRows)
+ :m_xSet(_xRs)
+ ,m_xMetaData(Reference< XResultSetMetaDataSupplier >(_xRs,UNO_QUERY_THROW)->getMetaData())
+ ,m_aContext( _rContext )
+ ,m_nFetchSize(0)
+ ,m_nRowCount(0)
+ ,m_nPrivileges( Privilege::SELECT )
+ ,m_nPosition(0)
+ ,m_nStartPos(0)
+ ,m_nEndPos(0)
+ ,m_bRowCountFinal(false)
+ ,m_bBeforeFirst(true)
+ ,m_bAfterLast( false )
+ ,m_bModified(_bModified)
+ ,m_bNew(_bNew)
+{
+
+ // first try if the result can be used to do inserts and updates
+ Reference< XPropertySet> xProp(_xRs,UNO_QUERY);
+ Reference< XPropertySetInfo > xPropInfo = xProp->getPropertySetInfo();
+ bool bBookmarkable = false;
+ try
+ {
+ Reference< XResultSetUpdate> xUp(_xRs,UNO_QUERY_THROW);
+ bBookmarkable = xPropInfo->hasPropertyByName(PROPERTY_ISBOOKMARKABLE) &&
+ any2bool(xProp->getPropertyValue(PROPERTY_ISBOOKMARKABLE)) && Reference< XRowLocate >(_xRs, UNO_QUERY).is();
+ if ( bBookmarkable )
+ {
+ xUp->moveToInsertRow();
+ xUp->cancelRowUpdates();
+ _xRs->beforeFirst();
+ m_nPrivileges = Privilege::SELECT|Privilege::DELETE|Privilege::INSERT|Privilege::UPDATE;
+ m_xCacheSet = new WrappedResultSet(i_nMaxRows);
+ m_xCacheSet->construct(_xRs,i_sRowSetFilter);
+ return;
+ }
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess.core");
+ }
+ try
+ {
+ if ( xPropInfo->hasPropertyByName(PROPERTY_RESULTSETTYPE) &&
+ ::comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETTYPE)) != ResultSetType::FORWARD_ONLY)
+ _xRs->beforeFirst();
+ }
+ catch(const SQLException&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess.core", "ORowSetCache");
+ }
+
+ // check if all keys of the updateable table are fetched
+ bool bAllKeysFound = false;
+ sal_Int32 nTablesCount = 0;
+
+ bool bNeedKeySet = !bBookmarkable || (xPropInfo->hasPropertyByName(PROPERTY_RESULTSETCONCURRENCY) &&
+ ::comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY)) == ResultSetConcurrency::READ_ONLY);
+
+ OUString aUpdateTableName = _rUpdateTableName;
+ Reference< XConnection> xConnection;
+ // first we need a connection
+ Reference< XStatement> xStmt(_xRs->getStatement(),UNO_QUERY);
+ if(xStmt.is())
+ xConnection = xStmt->getConnection();
+ else
+ {
+ Reference< XPreparedStatement> xPrepStmt(_xRs->getStatement(),UNO_QUERY);
+ xConnection = xPrepStmt->getConnection();
+ }
+ OSL_ENSURE(xConnection.is(),"No connection!");
+ if(_xAnalyzer.is())
+ {
+ try
+ {
+ Reference<XTablesSupplier> xTabSup(_xAnalyzer,UNO_QUERY);
+ OSL_ENSURE(xTabSup.is(),"ORowSet::execute composer isn't a tablesupplier!");
+ Reference<XNameAccess> xTables = xTabSup->getTables();
+ Sequence< OUString> aTableNames = xTables->getElementNames();
+ if ( aTableNames.getLength() > 1 && _rUpdateTableName.isEmpty() && bNeedKeySet )
+ {// here we have a join or union and nobody told us which table to update, so we update them all
+ m_nPrivileges = Privilege::SELECT|Privilege::DELETE|Privilege::INSERT|Privilege::UPDATE;
+ rtl::Reference<OptimisticSet> pCursor = new OptimisticSet(m_aContext,xConnection,_xAnalyzer,_aParameterValueForCache,i_nMaxRows,m_nRowCount);
+ m_xCacheSet = pCursor;
+ try
+ {
+ m_xCacheSet->construct(_xRs,i_sRowSetFilter);
+ if ( pCursor->isReadOnly() )
+ m_nPrivileges = Privilege::SELECT;
+ m_aKeyColumns = pCursor->getJoinedKeyColumns();
+ return;
+ }
+ catch (const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess.core", "ORowSetCache");
+ }
+ m_xCacheSet.clear();
+ }
+ else
+ {
+ if(!_rUpdateTableName.isEmpty() && xTables->hasByName(_rUpdateTableName))
+ xTables->getByName(_rUpdateTableName) >>= m_aUpdateTable;
+ else if(xTables->getElementNames().hasElements())
+ {
+ aUpdateTableName = xTables->getElementNames()[0];
+ xTables->getByName(aUpdateTableName) >>= m_aUpdateTable;
+ }
+ Reference<XIndexAccess> xIndexAccess(xTables,UNO_QUERY);
+ if(xIndexAccess.is())
+ nTablesCount = xIndexAccess->getCount();
+ else
+ nTablesCount = xTables->getElementNames().getLength();
+
+ if(m_aUpdateTable.is() && nTablesCount < 3) // for we can't handle more than 2 tables in our keyset
+ {
+ Reference<XPropertySet> xSet(m_aUpdateTable,UNO_QUERY);
+ const Reference<XNameAccess> xPrimaryKeyColumns = dbtools::getPrimaryKeyColumns_throw(xSet);
+ if ( xPrimaryKeyColumns.is() )
+ {
+ Reference<XColumnsSupplier> xColSup(_xAnalyzer,UNO_QUERY);
+ if ( xColSup.is() )
+ {
+ Reference<XNameAccess> xSelColumns = xColSup->getColumns();
+ Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
+ SelectColumnsMetaData aColumnNames(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers());
+ ::dbaccess::getColumnPositions(xSelColumns,xPrimaryKeyColumns->getElementNames(),aUpdateTableName,aColumnNames);
+ bAllKeysFound = !aColumnNames.empty() && aColumnNames.size() == o3tl::make_unsigned(xPrimaryKeyColumns->getElementNames().getLength());
+ }
+ }
+ }
+ }
+ }
+ catch (Exception const&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess.core", "ORowSetCache");
+ }
+ }
+
+ // first check if resultset is bookmarkable
+ if(!bNeedKeySet)
+ {
+ try
+ {
+ m_xCacheSet = new OBookmarkSet(i_nMaxRows);
+ m_xCacheSet->construct(_xRs,i_sRowSetFilter);
+
+ // check privileges
+ m_nPrivileges = Privilege::SELECT;
+ if(Reference<XResultSetUpdate>(_xRs,UNO_QUERY).is()) // this interface is optional so we have to check it
+ {
+ Reference<XPropertySet> xTable(m_aUpdateTable,UNO_QUERY);
+ if(xTable.is() && xTable->getPropertySetInfo()->hasPropertyByName(PROPERTY_PRIVILEGES))
+ {
+ m_nPrivileges = 0;
+ xTable->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges;
+ if(!m_nPrivileges)
+ m_nPrivileges = Privilege::SELECT;
+ }
+ }
+ }
+ catch (const SQLException&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess.core", "ORowSetCache");
+ bNeedKeySet = true;
+ }
+
+ }
+ if(bNeedKeySet)
+ {
+ // need to check if we could handle this select clause
+ bAllKeysFound = bAllKeysFound && (nTablesCount == 1 || checkJoin(xConnection,_xAnalyzer,aUpdateTableName));
+
+ if(!bAllKeysFound )
+ {
+ if ( bBookmarkable )
+ {
+ // here I know that we have a read only bookmarkable cursor
+ _xRs->beforeFirst();
+ m_nPrivileges = Privilege::SELECT;
+ m_xCacheSet = new WrappedResultSet(i_nMaxRows);
+ m_xCacheSet->construct(_xRs,i_sRowSetFilter);
+ return;
+ }
+ m_xCacheSet = new OStaticSet(i_nMaxRows);
+ m_xCacheSet->construct(_xRs,i_sRowSetFilter);
+ m_nPrivileges = Privilege::SELECT;
+ }
+ else
+ {
+ Reference<XDatabaseMetaData> xMeta = xConnection->getMetaData();
+ SelectColumnsMetaData aColumnNames(xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers());
+ Reference<XColumnsSupplier> xColSup(_xAnalyzer,UNO_QUERY);
+ Reference<XNameAccess> xSelColumns = xColSup->getColumns();
+ Reference<XNameAccess> xColumns = m_aUpdateTable->getColumns();
+ ::dbaccess::getColumnPositions(xSelColumns,xColumns->getElementNames(),aUpdateTableName,aColumnNames);
+
+ // check privileges
+ m_nPrivileges = Privilege::SELECT;
+ bool bNoInsert = false;
+
+ Sequence< OUString> aNames(xColumns->getElementNames());
+ const OUString* pIter = aNames.getConstArray();
+ const OUString* pEnd = pIter + aNames.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ Reference<XPropertySet> xColumn(xColumns->getByName(*pIter),UNO_QUERY);
+ OSL_ENSURE(xColumn.is(),"Column in table is null!");
+ if(xColumn.is())
+ {
+ sal_Int32 nNullable = 0;
+ xColumn->getPropertyValue(PROPERTY_ISNULLABLE) >>= nNullable;
+ if(nNullable == ColumnValue::NO_NULLS && aColumnNames.find(*pIter) == aColumnNames.end())
+ { // we found a column where null is not allowed so we can't insert new values
+ bNoInsert = true;
+ break; // one column is enough
+ }
+ }
+ }
+
+ rtl::Reference<OKeySet> pKeySet = new OKeySet(m_aUpdateTable, aUpdateTableName ,_xAnalyzer,_aParameterValueForCache,i_nMaxRows,m_nRowCount);
+ try
+ {
+ m_xCacheSet = pKeySet;
+ pKeySet->construct(_xRs,i_sRowSetFilter);
+
+ if(Reference<XResultSetUpdate>(_xRs,UNO_QUERY).is()) // this interface is optional so we have to check it
+ {
+ Reference<XPropertySet> xTable(m_aUpdateTable,UNO_QUERY);
+ if(xTable.is() && xTable->getPropertySetInfo()->hasPropertyByName(PROPERTY_PRIVILEGES))
+ {
+ m_nPrivileges = 0;
+ xTable->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges;
+ if(!m_nPrivileges)
+ m_nPrivileges = Privilege::SELECT;
+ }
+ }
+ if(bNoInsert)
+ m_nPrivileges |= ~Privilege::INSERT; // remove the insert privilege
+ }
+ catch (const SQLException&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess.core", "ORowSetCache");
+ // we couldn't create a keyset here so we have to create a static cache
+ m_xCacheSet = new OStaticSet(i_nMaxRows);
+ m_xCacheSet->construct(_xRs,i_sRowSetFilter);
+ m_nPrivileges = Privilege::SELECT;
+ }
+ }
+
+ }
+ // last check
+ if(!bAllKeysFound && xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_RESULTSETCONCURRENCY) &&
+ ::comphelper::getINT32(xProp->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY)) == ResultSetConcurrency::READ_ONLY)
+ m_nPrivileges = Privilege::SELECT;
+}
+
+ORowSetCache::~ORowSetCache()
+{
+ m_xCacheSet.clear();
+ if(m_pMatrix)
+ {
+ m_pMatrix->clear();
+ m_pMatrix.reset();
+ }
+
+ if(m_pInsertMatrix)
+ {
+ m_pInsertMatrix->clear();
+ m_pInsertMatrix.reset();
+ }
+ m_xSet = WeakReference< XResultSet>();
+ m_xMetaData = nullptr;
+ m_aUpdateTable = nullptr;
+}
+
+void ORowSetCache::setFetchSize(sal_Int32 _nSize)
+{
+ if(_nSize == m_nFetchSize)
+ return;
+
+ m_nFetchSize = _nSize;
+ if(!m_pMatrix)
+ {
+ m_pMatrix.reset( new ORowSetMatrix(_nSize) );
+ m_aMatrixIter = m_pMatrix->end();
+ m_aMatrixEnd = m_pMatrix->end();
+
+ m_pInsertMatrix.reset( new ORowSetMatrix(1) ); // a little bit overkill but ??? :-)
+ m_aInsertRow = m_pInsertMatrix->end();
+ }
+ else
+ {
+ // now correct the iterator in our iterator vector
+ std::vector<sal_Int32> aPositions;
+ std::map<sal_Int32,bool> aCacheIterToChange;
+ // first get the positions where they stand now
+ for(const auto& [rIndex, rHelper] : m_aCacheIterators)
+ {
+ aCacheIterToChange[rIndex] = false;
+ if ( !rHelper.pRowSet->isInsertRow()
+ /*&& rHelper.aIterator != m_pMatrix->end()*/ && !m_bModified )
+ {
+ ptrdiff_t nDist = rHelper.aIterator - m_pMatrix->begin();
+ aPositions.push_back(nDist);
+ aCacheIterToChange[rIndex] = true;
+ }
+ }
+ sal_Int32 nKeyPos = m_aMatrixIter - m_pMatrix->begin();
+ m_pMatrix->resize(_nSize);
+
+ if ( nKeyPos < _nSize )
+ m_aMatrixIter = m_pMatrix->begin() + nKeyPos;
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ m_aMatrixEnd = m_pMatrix->end();
+
+ // now adjust their positions because a resize invalidates all iterators
+ std::vector<sal_Int32>::const_iterator aIter = aPositions.begin();
+ ORowSetCacheMap::iterator aCacheIter = m_aCacheIterators.begin();
+ for(const auto& rPosChange : aCacheIterToChange)
+ {
+ if ( rPosChange.second )
+ {
+ OSL_ENSURE((*aIter >= static_cast<ORowSetMatrix::difference_type>(0)) && (*aIter < static_cast<sal_Int32>(m_pMatrix->size())),"Position is invalid!");
+ if ( *aIter < _nSize )
+ aCacheIter->second.aIterator = m_pMatrix->begin() + *aIter++;
+ else
+ aCacheIter->second.aIterator = m_pMatrix->end();
+ }
+ ++aCacheIter;
+ }
+ }
+ if(!m_nPosition)
+ {
+ sal_Int32 nNewSt = 0;
+ fillMatrix(nNewSt,_nSize);
+ OSL_ENSURE(nNewSt == 0, "fillMatrix set new start to unexpected value");
+ m_nStartPos = 0;
+ m_nEndPos = _nSize;
+ }
+ else if (m_nStartPos < m_nPosition && m_nPosition <= m_nEndPos)
+ {
+ sal_Int32 nNewSt = -1;
+ _nSize += m_nStartPos;
+ fillMatrix(nNewSt, _nSize);
+ if (nNewSt >= 0)
+ {
+ m_nStartPos = nNewSt;
+ m_nEndPos = _nSize;
+ m_aMatrixIter = calcPosition();
+ }
+ else
+ {
+ m_nEndPos = m_nStartPos + m_nFetchSize;
+ }
+ }
+ else
+ {
+ OSL_FAIL("m_nPosition not between m_nStartPos and m_nEndpos");
+ // try to repair
+ moveWindow();
+ m_aMatrixIter = calcPosition();
+ }
+}
+
+// XResultSetMetaDataSupplier
+
+static Any lcl_getBookmark(ORowSetValue& i_aValue,OCacheSet* i_pCacheSet)
+{
+ switch ( i_aValue.getTypeKind() )
+ {
+ case DataType::TINYINT:
+ case DataType::SMALLINT:
+ case DataType::INTEGER:
+ return Any(i_aValue.getInt32());
+ default:
+ if ( i_pCacheSet && i_aValue.isNull())
+ i_aValue = i_pCacheSet->getBookmark();
+ return i_aValue.getAny();
+ }
+}
+
+// css::sdbcx::XRowLocate
+Any ORowSetCache::getBookmark( )
+{
+ if(m_bAfterLast)
+ throwFunctionSequenceException(m_xSet.get());
+
+ if ( m_aMatrixIter >= m_pMatrix->end() || m_aMatrixIter < m_pMatrix->begin() || !(*m_aMatrixIter).is())
+ {
+ return Any(); // this is allowed here because the rowset knows what it is doing
+ }
+
+ return lcl_getBookmark((**m_aMatrixIter)[0],m_xCacheSet.get());
+}
+
+bool ORowSetCache::moveToBookmark( const Any& bookmark )
+{
+ if ( m_xCacheSet->moveToBookmark(bookmark) )
+ {
+ m_bBeforeFirst = false;
+ m_nPosition = m_xCacheSet->getRow();
+
+ checkPositionFlags();
+
+ if(!m_bAfterLast)
+ {
+ moveWindow();
+ checkPositionFlags();
+ if ( !m_bAfterLast )
+ {
+ m_aMatrixIter = calcPosition();
+ OSL_ENSURE(m_aMatrixIter->is(),"Iterator after moveToBookmark not valid");
+ }
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ return false;
+
+ return m_aMatrixIter != m_pMatrix->end() && (*m_aMatrixIter).is();
+}
+
+bool ORowSetCache::moveRelativeToBookmark( const Any& bookmark, sal_Int32 rows )
+{
+ bool bRet( moveToBookmark( bookmark ) );
+ if ( bRet )
+ {
+ m_nPosition = m_xCacheSet->getRow() + rows;
+ absolute(m_nPosition);
+
+ bRet = m_aMatrixIter != m_pMatrix->end() && (*m_aMatrixIter).is();
+ }
+
+ return bRet;
+}
+
+sal_Int32 ORowSetCache::compareBookmarks( const Any& _first, const Any& _second )
+{
+ return (!_first.hasValue() || !_second.hasValue()) ? CompareBookmark::NOT_COMPARABLE : m_xCacheSet->compareBookmarks(_first,_second);
+}
+
+bool ORowSetCache::hasOrderedBookmarks( )
+{
+ return m_xCacheSet->hasOrderedBookmarks();
+}
+
+sal_Int32 ORowSetCache::hashBookmark( const Any& bookmark )
+{
+ return m_xCacheSet->hashBookmark(bookmark);
+}
+
+// XRowUpdate
+void ORowSetCache::updateNull(sal_Int32 columnIndex,ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32>& o_ChangedColumns
+ )
+{
+ checkUpdateConditions(columnIndex);
+
+ ORowSetValueVector::Vector& rInsert = **m_aInsertRow;
+ if ( !rInsert[columnIndex].isNull() )
+ {
+ rInsert[columnIndex].setBound(true);
+ rInsert[columnIndex].setNull();
+ rInsert[columnIndex].setModified(true);
+ io_aRow[columnIndex].setNull();
+
+ m_xCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
+ impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
+ }
+}
+
+void ORowSetCache::updateValue(sal_Int32 columnIndex,const ORowSetValue& x
+ ,ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32>& o_ChangedColumns
+ )
+{
+ checkUpdateConditions(columnIndex);
+
+ ORowSetValueVector::Vector& rInsert = **m_aInsertRow;
+ if ( rInsert[columnIndex] != x )
+ {
+ rInsert[columnIndex].setBound(true);
+ rInsert[columnIndex] = x;
+ rInsert[columnIndex].setModified(true);
+ io_aRow[columnIndex] = rInsert[columnIndex];
+
+ m_xCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
+ impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
+ }
+}
+
+void ORowSetCache::updateCharacterStream( sal_Int32 columnIndex, const Reference< css::io::XInputStream >& x
+ , sal_Int32 length,ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32>& o_ChangedColumns
+ )
+{
+ checkUpdateConditions(columnIndex);
+
+ Sequence<sal_Int8> aSeq;
+ if(x.is())
+ x->readBytes(aSeq,length);
+
+ ORowSetValueVector::Vector& rInsert = **m_aInsertRow;
+ rInsert[columnIndex].setBound(true);
+ rInsert[columnIndex] = aSeq;
+ rInsert[columnIndex].setModified(true);
+ io_aRow[columnIndex] = Any(x);
+
+ m_xCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
+ impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
+}
+
+void ORowSetCache::updateObject( sal_Int32 columnIndex, const Any& x
+ ,ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32>& o_ChangedColumns
+ )
+{
+ checkUpdateConditions(columnIndex);
+
+ ORowSetValueVector::Vector& rInsert = **m_aInsertRow;
+ ORowSetValue aTemp;
+ aTemp.fill(x);
+ if ( rInsert[columnIndex] != aTemp )
+ {
+ rInsert[columnIndex].setBound(true);
+ rInsert[columnIndex] = aTemp;
+ rInsert[columnIndex].setModified(true);
+ io_aRow[columnIndex] = rInsert[columnIndex];
+
+ m_xCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
+ impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
+ }
+}
+
+void ORowSetCache::updateNumericObject( sal_Int32 columnIndex, const Any& x
+ ,ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32>& o_ChangedColumns
+ )
+{
+ checkUpdateConditions(columnIndex);
+
+ ORowSetValueVector::Vector& rInsert = **m_aInsertRow;
+ ORowSetValue aTemp;
+ aTemp.fill(x);
+ if ( rInsert[columnIndex] != aTemp )
+ {
+ rInsert[columnIndex].setBound(true);
+ rInsert[columnIndex] = aTemp;
+ rInsert[columnIndex].setModified(true);
+ io_aRow[columnIndex] = rInsert[columnIndex];
+
+ m_xCacheSet->mergeColumnValues(columnIndex,rInsert,io_aRow,o_ChangedColumns);
+ impl_updateRowFromCache_throw(io_aRow,o_ChangedColumns);
+ }
+}
+
+// XResultSet
+bool ORowSetCache::next( )
+{
+ if(!isAfterLast())
+ {
+ m_bBeforeFirst = false;
+ ++m_nPosition;
+
+ // after we increment the position we have to check if we are already after the last row
+ checkPositionFlags();
+ if(!m_bAfterLast)
+ {
+ moveWindow();
+
+ OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
+ m_aMatrixIter = calcPosition();
+ checkPositionFlags();
+ }
+ }
+
+ return !m_bAfterLast;
+}
+
+
+bool ORowSetCache::isFirst( ) const
+{
+ return m_nPosition == 1; // ask resultset for
+}
+
+bool ORowSetCache::isLast( ) const
+{
+ return m_nPosition == m_nRowCount;
+}
+
+void ORowSetCache::beforeFirst( )
+{
+ if(!m_bBeforeFirst)
+ {
+ m_bAfterLast = false;
+ m_nPosition = 0;
+ m_bBeforeFirst = true;
+ m_xCacheSet->beforeFirst();
+ moveWindow();
+ m_aMatrixIter = m_pMatrix->end();
+ }
+}
+
+void ORowSetCache::afterLast( )
+{
+ if(m_bAfterLast)
+ return;
+
+ m_bBeforeFirst = false;
+ m_bAfterLast = true;
+
+ if(!m_bRowCountFinal)
+ {
+ m_xCacheSet->last();
+ m_bRowCountFinal = true;
+ m_nRowCount = m_xCacheSet->getRow();// + 1 removed
+ }
+ m_xCacheSet->afterLast();
+
+ m_nPosition = 0;
+ m_aMatrixIter = m_pMatrix->end();
+}
+
+bool ORowSetCache::fillMatrix(sal_Int32& _nNewStartPos, sal_Int32 &_nNewEndPos)
+{
+ OSL_ENSURE((_nNewStartPos != _nNewEndPos) || (_nNewStartPos == 0 && _nNewEndPos == 0 && m_nRowCount == 0),
+ "ORowSetCache::fillMatrix: StartPos and EndPos can not be equal (unless the recordset is empty)!");
+ // If _nNewStartPos >= 0, then fill the whole window with new data
+ // Else if _nNewStartPos == -1, then fill only segment [m_nEndPos, _nNewEndPos)
+ // Else, undefined (invalid argument)
+ OSL_ENSURE( _nNewStartPos >= -1, "ORowSetCache::fillMatrix: invalid _nNewStartPos" );
+
+ ORowSetMatrix::iterator aIter;
+ sal_Int32 i;
+ bool bCheck;
+ sal_Int32 requestedStartPos;
+ if ( _nNewStartPos == -1 )
+ {
+ aIter = m_pMatrix->begin() + (m_nEndPos - m_nStartPos);
+ i = m_nEndPos + 1;
+ requestedStartPos = m_nStartPos;
+ }
+ else
+ {
+ aIter = m_pMatrix->begin();
+ i = _nNewStartPos + 1;
+ requestedStartPos = _nNewStartPos;
+ }
+ bCheck = m_xCacheSet->absolute(i);
+
+
+ for(; i <= _nNewEndPos; ++i,++aIter)
+ {
+ if(bCheck)
+ {
+ if(!aIter->is())
+ *aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
+ m_xCacheSet->fillValueRow(*aIter,i);
+ }
+ else
+ { // there are no more rows found so we can fetch some before start
+
+ if(!m_bRowCountFinal)
+ {
+ if(m_xCacheSet->previous()) // because we stand after the last row
+ m_nRowCount = m_xCacheSet->getRow(); // here we have the row count
+ if(!m_nRowCount)
+ m_nRowCount = i-1; // it can be that getRow return zero
+ m_bRowCountFinal = true;
+ }
+ const ORowSetMatrix::iterator aEnd = aIter;
+ ORowSetMatrix::const_iterator aRealEnd = m_pMatrix->end();
+ sal_Int32 nPos;
+ if (m_nRowCount >= m_nFetchSize)
+ {
+ nPos = m_nRowCount - m_nFetchSize;
+ }
+ else
+ {
+ nPos = 0;
+ }
+ _nNewStartPos = nPos;
+ _nNewEndPos = m_nRowCount;
+ ++nPos;
+ bCheck = m_xCacheSet->absolute(nPos);
+
+ for(;bCheck && nPos <= requestedStartPos && aIter != aRealEnd; ++aIter, ++nPos)
+ {
+ if(!aIter->is())
+ *aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
+ m_xCacheSet->fillValueRow(*aIter, nPos);
+ bCheck = m_xCacheSet->next();
+ }
+ if(aIter != aEnd)
+ std::rotate(m_pMatrix->begin(),aEnd,aIter);
+ break;
+ }
+ bCheck = m_xCacheSet->next();
+ }
+ // we have to read one row forward to ensure that we know when we are on last row
+ // but only when we don't know it already
+ if(!m_bRowCountFinal)
+ {
+ if(!m_xCacheSet->next())
+ {
+ if(m_xCacheSet->previous()) // because we stand after the last row
+ m_nRowCount = m_xCacheSet->getRow(); // here we have the row count
+ m_bRowCountFinal = true;
+ }
+ else
+ m_nRowCount = std::max(i,m_nRowCount);
+
+ }
+ return bCheck;
+}
+
+// If m_nPosition is out of the current window,
+// move it and update m_nStartPos and m_nEndPos
+// Caller is responsible for updating m_aMatrixIter
+void ORowSetCache::moveWindow()
+{
+ OSL_ENSURE(m_nStartPos >= 0,"ORowSetCache::moveWindow: m_nStartPos is less than 0!");
+ OSL_ENSURE(m_nEndPos >= m_nStartPos,"ORowSetCache::moveWindow: m_nStartPos not smaller than m_nEndPos");
+ OSL_ENSURE(m_nEndPos-m_nStartPos <= m_nFetchSize,"ORowSetCache::moveWindow: m_nStartPos and m_nEndPos too far apart");
+
+ if ( m_nStartPos < m_nPosition && m_nPosition <= m_nEndPos )
+ {
+ // just move inside the window
+ OSL_ENSURE((m_nPosition - m_nStartPos) <= static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
+ // make double plus sure that we have fetched that row
+ m_aMatrixIter = calcPosition();
+ OSL_ENSURE(m_aMatrixIter != m_pMatrix->end(), "New m_aMatrixIter is at end(), but should not.");
+ if(!m_aMatrixIter->is())
+ {
+ bool bOk( m_xCacheSet->absolute( m_nPosition ) );
+ if ( bOk )
+ {
+ *m_aMatrixIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
+ m_xCacheSet->fillValueRow(*m_aMatrixIter,m_nPosition);
+ // we have to read one row forward to ensure that we know when we are on last row
+ // but only when we don't know it already
+ if ( !m_bRowCountFinal )
+ {
+ bOk = m_xCacheSet->absolute( m_nPosition + 1 );
+ if ( bOk )
+ m_nRowCount = std::max(sal_Int32(m_nPosition+1),m_nRowCount);
+ }
+ }
+ if(!bOk && !m_bRowCountFinal)
+ {
+ // because we stand after the last row
+ m_nRowCount = m_xCacheSet->previous() ? m_xCacheSet->getRow() : 0;
+ m_bRowCountFinal = true;
+ }
+ }
+ return;
+ }
+
+ sal_Int32 nDiff = (m_nFetchSize - 1) / 2;
+ sal_Int32 nNewStartPos = (m_nPosition - nDiff) - 1; //m_nPosition is 1-based, but m_nStartPos is 0-based
+ sal_Int32 nNewEndPos = nNewStartPos + m_nFetchSize;
+
+ if ( nNewStartPos < 0 )
+ {
+ // The computed new window crashes through the floor (begins before first row);
+ // nNew*Pos has to be shifted by -nNewStartPos
+ nNewEndPos -= nNewStartPos;
+ nNewStartPos = 0;
+ }
+
+ if ( nNewStartPos < m_nStartPos )
+ { // need to fill data *before* m_nStartPos
+ if ( nNewEndPos > m_nStartPos )
+ { // The two regions are overlapping.
+ // We'll first rotate the contents of m_pMatrix so that the overlap area
+ // is positioned right; in the old window it is at the beginning,
+ // it has to go to the end.
+ // then we fill in the rows between new and old start pos.
+
+ bool bCheck;
+ bCheck = m_xCacheSet->absolute(nNewStartPos + 1);
+
+ // m_nEndPos < nNewEndPos when window not filled (e.g. there are fewer rows in total than window size)
+ m_nEndPos = std::min(nNewEndPos, m_nEndPos);
+ const sal_Int32 nOverlapSize = m_nEndPos - m_nStartPos;
+ const sal_Int32 nStartPosOffset = m_nStartPos - nNewStartPos; // by how much m_nStartPos moves
+ m_nStartPos = nNewStartPos;
+ OSL_ENSURE( o3tl::make_unsigned(nOverlapSize) <= m_pMatrix->size(), "new window end is after end of cache matrix!" );
+ // the first position in m_pMatrix whose data we don't keep;
+ // content will be moved to m_pMatrix.begin()
+ ORowSetMatrix::iterator aEnd (m_pMatrix->begin() + nOverlapSize);
+ // the first unused position after we are done; it == m_pMatrix.end() if and only if the window is full
+ ORowSetMatrix::iterator aNewEnd (aEnd + nStartPosOffset);
+ // *m_pMatrix now looks like:
+ // [0; nOverlapSize) i.e. [begin(); aEnd): data kept
+ // [nOverlapSize; nOverlapSize + nStartPosOffset) i.e. [aEnd, aNewEnd): new data of positions < old m_nStartPos
+ // [nOverlapSize + nStartPosOffset; size()) i.e. [aNewEnd, end()): unused
+ // Note that nOverlapSize + nStartPosOffset == m_nEndPos - m_nStartPos (new values)
+ // When we are finished:
+ // [0; nStartPosOffset) i.e. [begin(); aEnd): new data of positions < old m_nStartPos
+ // [nStartPosOffset; nOverlapSize + nStartPosOffset) i.e. [aEnd, aNewEnd): kept
+ // [nOverlapSize + nStartPosOffset; size()) i.e. [aNewEnd, end()): unused
+
+ if ( bCheck )
+ {
+ {
+ ORowSetMatrix::iterator aIter(aEnd);
+ sal_Int32 nPos = m_nStartPos + 1;
+ fill(aIter, aNewEnd, nPos, bCheck);
+ }
+
+ std::rotate(m_pMatrix->begin(), aEnd, aNewEnd);
+ if (!m_bModified)
+ {
+ // now correct the iterator in our iterator vector
+ // rotateCacheIterator(aEnd-m_pMatrix->begin()); //can't be used because they decrement and here we need to increment
+ for(auto& rCacheIter : m_aCacheIterators)
+ {
+ if ( !rCacheIter.second.pRowSet->isInsertRow()
+ && rCacheIter.second.aIterator != m_pMatrix->end() )
+ {
+ const ptrdiff_t nDist = rCacheIter.second.aIterator - m_pMatrix->begin();
+ if ( nDist >= nOverlapSize )
+ {
+ // That's from outside the overlap area; invalidate iterator.
+ rCacheIter.second.aIterator = m_pMatrix->end();
+ }
+ else
+ {
+ // Inside overlap area: move to correct position
+ OSL_ENSURE(((nDist + nStartPosOffset) >= static_cast<ORowSetMatrix::difference_type>(0)) &&
+ ((nDist + nStartPosOffset) < static_cast<sal_Int32>(m_pMatrix->size())),"Position is invalid!");
+ rCacheIter.second.aIterator += nStartPosOffset;
+ OSL_ENSURE(rCacheIter.second.aIterator >= m_pMatrix->begin()
+ && rCacheIter.second.aIterator < m_pMatrix->end(),"Iterator out of area!");
+ }
+ }
+ }
+ }
+ }
+ else
+ { // normally this should never happen
+ OSL_FAIL("What the hell is happen here!");
+ return;
+ }
+ }
+ else
+ {// no rows can be reused so fill again
+ reFillMatrix(nNewStartPos,nNewEndPos);
+ }
+ }
+
+ OSL_ENSURE(nNewStartPos >= m_nStartPos, "ORowSetCache::moveWindow internal error: new start pos before current start pos");
+ if ( m_nEndPos < nNewEndPos )
+ { // need to fill data *after* m_nEndPos
+ if( nNewStartPos < m_nEndPos )
+ { // The two regions are overlapping.
+ const sal_Int32 nRowsInCache = m_nEndPos - m_nStartPos;
+ if ( nRowsInCache < m_nFetchSize )
+ {
+ // There is some unused space in *m_pMatrix; fill it
+ OSL_ENSURE((nRowsInCache >= static_cast<ORowSetMatrix::difference_type>(0)) && (o3tl::make_unsigned(nRowsInCache) < m_pMatrix->size()),"Position is invalid!");
+ sal_Int32 nPos = m_nEndPos + 1;
+ bool bCheck = m_xCacheSet->absolute(nPos);
+ ORowSetMatrix::iterator aIter = m_pMatrix->begin() + nRowsInCache;
+ const sal_Int32 nRowsToFetch = std::min(nNewEndPos-m_nEndPos, m_nFetchSize-nRowsInCache);
+ const ORowSetMatrix::const_iterator aEnd = aIter + nRowsToFetch;
+ bCheck = fill(aIter, aEnd, nPos, bCheck);
+ m_nEndPos = nPos - 1;
+ OSL_ENSURE( (!bCheck && m_nEndPos <= nNewEndPos ) ||
+ ( bCheck && m_nEndPos == nNewEndPos ),
+ "ORowSetCache::moveWindow opportunistic fetch-after-current-end went badly");
+ }
+
+ // A priori, the rows from begin() [inclusive] to (begin() + nNewStartPos - m_nStartPos) [exclusive]
+ // have to be refilled with new to-be-fetched rows.
+ // The rows behind this can be reused
+ ORowSetMatrix::iterator aIter = m_pMatrix->begin();
+ const sal_Int32 nNewStartPosInMatrix = nNewStartPos - m_nStartPos;
+ OSL_ENSURE((nNewStartPosInMatrix >= static_cast<ORowSetMatrix::difference_type>(0)) && (o3tl::make_unsigned(nNewStartPosInMatrix) < m_pMatrix->size()),"Position is invalid!");
+ // first position we reuse
+ const ORowSetMatrix::const_iterator aEnd = m_pMatrix->begin() + nNewStartPosInMatrix;
+ // End of used portion of the matrix. Is < m_pMatrix->end() if less data than window size
+ ORowSetMatrix::iterator aDataEnd = m_pMatrix->begin() + (m_nEndPos - m_nStartPos);
+
+ sal_Int32 nPos = m_nEndPos + 1;
+ bool bCheck = m_xCacheSet->absolute(nPos);
+ bCheck = fill(aIter, aEnd, nPos, bCheck); // refill the region we don't need anymore
+ //aIter and nPos are now the position *after* last filled in one!
+
+ // bind end to front
+ if(bCheck)
+ {
+ OSL_ENSURE(aIter == aEnd, "fill() said went till end, but did not.");
+ // rotate the end to the front
+ std::rotate(m_pMatrix->begin(), aIter, aDataEnd);
+ // now correct the iterator in our iterator vector
+ rotateCacheIterator( nNewStartPosInMatrix );
+ m_nStartPos = nNewStartPos;
+ m_nEndPos = nNewEndPos;
+ // now I can say how many rows we have
+ // we have to read one row forward to ensure that we know when we are on last row
+ // but only when we don't know it already
+ bool bOk = true;
+ if(!m_bRowCountFinal)
+ bOk = m_xCacheSet->next();
+ if(!bOk)
+ {
+ m_xCacheSet->previous(); // because we stand after the last row
+ m_nRowCount = nPos; // here we have the row count
+ OSL_ENSURE(nPos == m_xCacheSet->getRow(),"nPos is not valid!");
+ m_bRowCountFinal = true;
+ }
+ else if(!m_bRowCountFinal)
+ m_nRowCount = std::max(nPos+1, m_nRowCount); //+1 because we successfully moved to row after nPos
+ else
+ OSL_ENSURE(m_nRowCount >= nPos, "Final m_nRowCount is smaller than row I moved to!");
+ }
+ else
+ { // the end was reached before or at end() so we can set the start before or at nNewStartPos
+ // and possibly keep more of m_pMatrix than planned.
+ const ORowSetMatrix::const_iterator::difference_type nFetchedRows = aIter - m_pMatrix->begin();
+ // *m_pMatrix now looks like:
+ // [0; nFetchedRows) i.e. [begin(); aIter): newly fetched data for positions m_nEndPos to m_nEndPos+nFetchedRows
+ // [nFetchedRows; ???) i.e. [aIter; aDataEnd]: data to be kept for positions m_nStartPos+nFetchedRows to ???
+
+ nPos -= 1;
+ m_nStartPos += nFetchedRows;
+ m_nEndPos = nPos;
+ std::rotate(m_pMatrix->begin(), aIter, aDataEnd);
+ // now correct the iterator in our iterator vector
+ rotateCacheIterator( nFetchedRows );
+
+ if ( !m_bRowCountFinal )
+ {
+ m_xCacheSet->previous(); // because we stand after the last row
+ m_nRowCount = std::max(m_nRowCount, nPos); // here we have the row count
+ OSL_ENSURE(nPos == m_xCacheSet->getRow(),"nPos isn't valid!");
+ m_bRowCountFinal = true;
+ }
+
+ }
+ // here we need only to check if the beginning row is valid. If not we have to fetch it.
+ if(!m_pMatrix->begin()->is())
+ {
+ aIter = m_pMatrix->begin();
+
+ nPos = m_nStartPos + 1;
+ bCheck = m_xCacheSet->absolute(nPos);
+ for(; !aIter->is() && bCheck;++aIter, ++nPos)
+ {
+ OSL_ENSURE(aIter != m_pMatrix->end(),"Invalid iterator");
+
+ *aIter = new ORowSetValueVector(m_xMetaData->getColumnCount());
+ m_xCacheSet->fillValueRow(*aIter, nPos);
+
+ bCheck = m_xCacheSet->next();
+ }
+ }
+ }
+ else // no rows can be reused so fill again
+ reFillMatrix(nNewStartPos,nNewEndPos);
+ }
+
+ if(!m_bRowCountFinal)
+ m_nRowCount = std::max(m_nPosition,m_nRowCount);
+ OSL_ENSURE(m_nStartPos >= 0,"ORowSetCache::moveWindow: m_nStartPos is less than 0!");
+ OSL_ENSURE(m_nEndPos > m_nStartPos,"ORowSetCache::moveWindow: m_nStartPos not smaller than m_nEndPos");
+ OSL_ENSURE(m_nEndPos-m_nStartPos <= m_nFetchSize,"ORowSetCache::moveWindow: m_nStartPos and m_nEndPos too far apart");
+}
+
+bool ORowSetCache::first( )
+{
+ // First move to the first row.
+ // Then check if the cache window is at the beginning.
+ // If not, then position the window and fill it with data.
+ // We move the window smartly, i.e. we clear only the rows that are out of range
+ bool bRet = m_xCacheSet->first();
+ if(bRet)
+ {
+ m_bBeforeFirst = m_bAfterLast = false;
+ m_nPosition = 1;
+ moveWindow();
+ m_aMatrixIter = m_pMatrix->begin();
+ }
+ else
+ {
+ m_bRowCountFinal = m_bBeforeFirst = m_bAfterLast = true;
+ m_nRowCount = m_nPosition = 0;
+
+ OSL_ENSURE(m_bBeforeFirst || m_bNew,"ORowSetCache::first return false and BeforeFirst isn't true");
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ return bRet;
+}
+
+bool ORowSetCache::last( )
+{
+ bool bRet = m_xCacheSet->last();
+ if(bRet)
+ {
+ m_bBeforeFirst = m_bAfterLast = false;
+ if(!m_bRowCountFinal)
+ {
+ m_bRowCountFinal = true;
+ m_nRowCount = m_xCacheSet->getRow(); // not + 1
+ }
+ m_nPosition = m_xCacheSet->getRow();
+ moveWindow();
+ // we have to repositioning because moveWindow can modify the cache
+ m_xCacheSet->last();
+ OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
+ m_aMatrixIter = calcPosition();
+ }
+ else
+ {
+ m_bRowCountFinal = m_bBeforeFirst = m_bAfterLast = true;
+ m_nRowCount = m_nPosition = 0;
+ OSL_ENSURE(m_bBeforeFirst,"ORowSetCache::last return false and BeforeFirst isn't true");
+ m_aMatrixIter = m_pMatrix->end();
+ }
+#if OSL_DEBUG_LEVEL > 0
+ if(bRet)
+ {
+ assert((*m_aMatrixIter).is() && "ORowSetCache::last: Row not valid!");
+ }
+#endif
+
+ return bRet;
+}
+
+sal_Int32 ORowSetCache::getRow( ) const
+{
+ return (isBeforeFirst() || isAfterLast()) ? 0 : m_nPosition;
+}
+
+bool ORowSetCache::absolute( sal_Int32 row )
+{
+ if(!row )
+ throw SQLException(DBA_RES(RID_STR_NO_ABS_ZERO),nullptr,SQLSTATE_GENERAL,1000,Any() );
+
+ if(row < 0)
+ {
+ // here we have to scroll from the last row to backward so we have to go to last row and
+ // and to the previous
+ if(m_bRowCountFinal || last())
+ {
+ m_nPosition = m_nRowCount + row + 1; // + row because row is negative and +1 because row==-1 means last row
+ if(m_nPosition < 1)
+ {
+ m_bBeforeFirst = true;
+ m_bAfterLast = false;
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ {
+ m_bBeforeFirst = false;
+ m_bAfterLast = m_nPosition > m_nRowCount;
+ moveWindow();
+ OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
+ m_aMatrixIter = calcPosition();
+ }
+ }
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ {
+ m_nPosition = row;
+ // the position flags
+ m_bBeforeFirst = false;
+ checkPositionFlags();
+
+ if(!m_bAfterLast)
+ {
+ moveWindow();
+ checkPositionFlags();
+ if(!m_bAfterLast)
+ m_aMatrixIter = calcPosition();
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ m_aMatrixIter = m_pMatrix->end();
+ }
+
+ return !(m_bAfterLast || m_bBeforeFirst);
+}
+
+bool ORowSetCache::relative( sal_Int32 rows )
+{
+ bool bErg = true;
+ if(rows)
+ {
+ sal_Int32 nNewPosition = m_nPosition + rows;
+
+ if ( m_bBeforeFirst && rows > 0 )
+ nNewPosition = rows;
+ else if ( m_bRowCountFinal && m_bAfterLast && rows < 0 )
+ nNewPosition = m_nRowCount + 1 + rows;
+ else
+ if ( m_bBeforeFirst || ( m_bRowCountFinal && m_bAfterLast ) )
+ throw SQLException( DBA_RES( RID_STR_NO_RELATIVE ), nullptr, SQLSTATE_GENERAL, 1000, Any() );
+ if ( nNewPosition )
+ {
+ bErg = absolute( nNewPosition );
+ bErg = bErg && !isAfterLast() && !isBeforeFirst();
+ }
+ else
+ {
+ m_bBeforeFirst = true;
+ bErg = false;
+ }
+ }
+ return bErg;
+}
+
+bool ORowSetCache::previous( )
+{
+ bool bRet = false;
+ if(!isBeforeFirst())
+ {
+ if(m_bAfterLast) // we stand after the last row so one before is the last row
+ bRet = last();
+ else
+ {
+ m_bAfterLast = false;
+ --m_nPosition;
+ moveWindow();
+ OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
+
+ checkPositionFlags();
+
+ if(!m_nPosition)
+ {
+ m_bBeforeFirst = true;
+ m_aMatrixIter = m_pMatrix->end();
+ }
+ else
+ {
+ m_aMatrixIter = calcPosition();
+ bRet = (*m_aMatrixIter).is();
+ }
+ }
+ }
+ return bRet;
+}
+
+void ORowSetCache::refreshRow( )
+{
+ if(isAfterLast())
+ throw SQLException(DBA_RES(RID_STR_NO_REFRESH_AFTERLAST),nullptr,SQLSTATE_GENERAL,1000,Any() );
+ OSL_ENSURE(m_aMatrixIter != m_pMatrix->end(),"refreshRow() called for invalid row!");
+ m_xCacheSet->refreshRow();
+ m_xCacheSet->fillValueRow(*m_aMatrixIter,m_nPosition);
+ if ( m_bNew )
+ {
+ cancelRowModification();
+ }
+}
+
+bool ORowSetCache::rowUpdated( )
+{
+ return m_xCacheSet->rowUpdated();
+}
+
+bool ORowSetCache::rowInserted( )
+{
+ return m_xCacheSet->rowInserted();
+}
+
+// XResultSetUpdate
+bool ORowSetCache::insertRow(std::vector< Any >& o_aBookmarks)
+{
+ if ( !m_bNew || !m_aInsertRow->is() )
+ throw SQLException(DBA_RES(RID_STR_NO_MOVETOINSERTROW_CALLED),nullptr,SQLSTATE_GENERAL,1000,Any() );
+
+ m_xCacheSet->insertRow(*m_aInsertRow,m_aUpdateTable);
+
+ bool bRet( rowInserted() );
+ if ( bRet )
+ {
+ ++m_nRowCount;
+ Any aBookmark = (**m_aInsertRow)[0].makeAny();
+ m_bAfterLast = m_bBeforeFirst = false;
+ if(aBookmark.hasValue())
+ {
+ moveToBookmark(aBookmark);
+ // update the cached values
+ ORowSetValueVector::Vector& rCurrentRow = **m_aMatrixIter;
+ ORowSetMatrix::const_iterator aIter = m_pMatrix->begin();
+ for(;aIter != m_pMatrix->end();++aIter)
+ {
+ if ( m_aMatrixIter != aIter && aIter->is() && m_xCacheSet->columnValuesUpdated(**aIter,rCurrentRow) )
+ {
+ o_aBookmarks.push_back(lcl_getBookmark((**aIter)[0], m_xCacheSet.get()));
+ }
+ }
+ }
+ else
+ {
+ OSL_FAIL("There must be a bookmark after the row was inserted!");
+ }
+ }
+ return bRet;
+}
+
+void ORowSetCache::resetInsertRow(bool _bClearInsertRow)
+{
+ if ( _bClearInsertRow )
+ clearInsertRow();
+ m_bNew = false;
+ m_bModified = false;
+}
+
+void ORowSetCache::cancelRowModification()
+{
+ // clear the insertrow references -> implies that the current row of the rowset changes as well
+ for(auto& rCacheIter : m_aCacheIterators)
+ {
+ if ( rCacheIter.second.pRowSet->isInsertRow() && rCacheIter.second.aIterator == m_aInsertRow )
+ rCacheIter.second.aIterator = m_pMatrix->end();
+ }
+ resetInsertRow(false);
+}
+
+void ORowSetCache::updateRow( ORowSetMatrix::iterator const & _rUpdateRow, std::vector< Any >& o_aBookmarks )
+{
+ if(isAfterLast() || isBeforeFirst())
+ throw SQLException(DBA_RES(RID_STR_NO_UPDATEROW),nullptr,SQLSTATE_GENERAL,1000,Any() );
+
+ Any aBookmark = (**_rUpdateRow)[0].makeAny();
+ OSL_ENSURE(aBookmark.hasValue(),"Bookmark must have a value!");
+ // here we don't have to reposition our CacheSet, when we try to update a row,
+ // the row was already fetched
+ moveToBookmark(aBookmark);
+ m_xCacheSet->updateRow(*_rUpdateRow,*m_aMatrixIter,m_aUpdateTable);
+ // refetch the whole row
+ (*m_aMatrixIter) = nullptr;
+
+ if ( moveToBookmark(aBookmark) )
+ {
+ // update the cached values
+ ORowSetValueVector::Vector& rCurrentRow = **m_aMatrixIter;
+ ORowSetMatrix::const_iterator aIter = m_pMatrix->begin();
+ for(;aIter != m_pMatrix->end();++aIter)
+ {
+ if ( m_aMatrixIter != aIter && aIter->is() && m_xCacheSet->columnValuesUpdated(**aIter,rCurrentRow) )
+ {
+ o_aBookmarks.push_back(lcl_getBookmark((**aIter)[0], m_xCacheSet.get()));
+ }
+ }
+ }
+
+ m_bModified = false;
+}
+
+bool ORowSetCache::deleteRow( )
+{
+ if(isAfterLast() || isBeforeFirst())
+ throw SQLException(DBA_RES(RID_STR_NO_DELETEROW),nullptr,SQLSTATE_GENERAL,1000,Any() );
+
+ m_xCacheSet->deleteRow(*m_aMatrixIter,m_aUpdateTable);
+ if ( !m_xCacheSet->rowDeleted() )
+ return false;
+
+ --m_nRowCount;
+ OSL_ENSURE(((m_nPosition - m_nStartPos) - 1) < static_cast<sal_Int32>(m_pMatrix->size()),"Position is behind end()!");
+ ORowSetMatrix::iterator aPos = calcPosition();
+ (*aPos) = nullptr;
+
+ ORowSetMatrix::const_iterator aEnd = m_pMatrix->end();
+ for(++aPos;aPos != aEnd && aPos->is();++aPos)
+ {
+ *(aPos-1) = *aPos;
+ (*aPos) = nullptr;
+ }
+ m_aMatrixIter = m_pMatrix->end();
+
+ --m_nPosition;
+ return true;
+}
+
+void ORowSetCache::cancelRowUpdates( )
+{
+ m_bNew = m_bModified = false;
+ if(!m_nPosition)
+ {
+ OSL_FAIL("cancelRowUpdates:Invalid positions pos == 0");
+ ::dbtools::throwFunctionSequenceException(nullptr);
+ }
+
+ if(m_xCacheSet->absolute(m_nPosition))
+ m_xCacheSet->fillValueRow(*m_aMatrixIter,m_nPosition);
+ else
+ {
+ OSL_FAIL("cancelRowUpdates couldn't position right with absolute");
+ ::dbtools::throwFunctionSequenceException(nullptr);
+ }
+}
+
+void ORowSetCache::moveToInsertRow( )
+{
+ m_bNew = true;
+ m_bAfterLast = false;
+
+ m_aInsertRow = m_pInsertMatrix->begin();
+ if(!m_aInsertRow->is())
+ *m_aInsertRow = new ORowSetValueVector(m_xMetaData->getColumnCount());
+
+ // we don't unbound the bookmark column
+ ORowSetValueVector::Vector::iterator aIter = (*m_aInsertRow)->begin()+1;
+ ORowSetValueVector::Vector::const_iterator aEnd = (*m_aInsertRow)->end();
+ for(sal_Int32 i = 1;aIter != aEnd;++aIter,++i)
+ {
+ aIter->setBound(false);
+ aIter->setModified(false);
+ aIter->setNull();
+ aIter->setTypeKind(m_xMetaData->getColumnType(i));
+ }
+}
+
+ORowSetCacheIterator ORowSetCache::createIterator(ORowSetBase* _pRowSet)
+{
+ ORowSetCacheIterator_Helper aHelper;
+ aHelper.aIterator = m_pMatrix->end();
+ aHelper.pRowSet = _pRowSet;
+ return ORowSetCacheIterator(m_aCacheIterators.insert(m_aCacheIterators.begin(),ORowSetCacheMap::value_type(m_aCacheIterators.size()+1,aHelper)),this,_pRowSet);
+}
+
+void ORowSetCache::deleteIterator(const ORowSetBase* _pRowSet)
+{
+ ORowSetCacheMap::const_iterator aCacheIter = m_aCacheIterators.begin();
+ for(;aCacheIter != m_aCacheIterators.end();)
+ {
+ if ( aCacheIter->second.pRowSet == _pRowSet )
+ {
+ aCacheIter = m_aCacheIterators.erase(aCacheIter);
+ }
+ else
+ ++aCacheIter;
+ }
+}
+
+void ORowSetCache::rotateCacheIterator(ORowSetMatrix::difference_type _nDist)
+{
+ if (m_bModified)
+ return;
+
+ if(!_nDist)
+ return;
+
+ // now correct the iterator in our iterator vector
+ for(auto& rCacheIter : m_aCacheIterators)
+ {
+ if ( !rCacheIter.second.pRowSet->isInsertRow()
+ && rCacheIter.second.aIterator != m_pMatrix->end())
+ {
+ ptrdiff_t nDist = rCacheIter.second.aIterator - m_pMatrix->begin();
+ if(nDist < _nDist)
+ {
+ rCacheIter.second.aIterator = m_pMatrix->end();
+ }
+ else
+ {
+ OSL_ENSURE((rCacheIter.second.aIterator - m_pMatrix->begin()) >= _nDist,"Invalid Dist value!");
+ rCacheIter.second.aIterator -= _nDist;
+ OSL_ENSURE(rCacheIter.second.aIterator >= m_pMatrix->begin()
+ && rCacheIter.second.aIterator < m_pMatrix->end(),"Iterator out of area!");
+ }
+ }
+ }
+}
+
+void ORowSetCache::rotateAllCacheIterators()
+{
+ if (m_bModified)
+ return;
+
+ // now correct the iterator in our iterator vector
+ for (auto& rCacheIter : m_aCacheIterators)
+ {
+ if (!rCacheIter.second.pRowSet->isInsertRow())
+ {
+ rCacheIter.second.aIterator = m_pMatrix->end();
+ }
+ }
+}
+
+void ORowSetCache::setUpdateIterator(const ORowSetMatrix::iterator& _rOriginalRow)
+{
+ m_aInsertRow = m_pInsertMatrix->begin();
+ if(!m_aInsertRow->is())
+ *m_aInsertRow = new ORowSetValueVector(m_xMetaData->getColumnCount());
+
+ (*(*m_aInsertRow)) = *(*_rOriginalRow);
+ // we don't unbound the bookmark column
+ for(auto& rItem : **m_aInsertRow)
+ rItem.setModified(false);
+}
+
+void ORowSetCache::checkPositionFlags()
+{
+ if(m_bRowCountFinal)
+ {
+ m_bAfterLast = m_nPosition > m_nRowCount;
+ if(m_bAfterLast)
+ m_nPosition = 0;//m_nRowCount;
+ }
+}
+
+void ORowSetCache::checkUpdateConditions(sal_Int32 columnIndex)
+{
+ if(m_bAfterLast || columnIndex >= static_cast<sal_Int32>((*m_aInsertRow)->size()))
+ throwFunctionSequenceException(m_xSet.get());
+}
+
+bool ORowSetCache::checkInnerJoin(const ::connectivity::OSQLParseNode *pNode,const Reference< XConnection>& _xConnection,const OUString& _sUpdateTableName)
+{
+ bool bOk = false;
+ if (pNode->count() == 3 && // expression in parentheses
+ SQL_ISPUNCTUATION(pNode->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pNode->getChild(2),")"))
+ {
+ bOk = checkInnerJoin(pNode->getChild(1),_xConnection,_sUpdateTableName);
+ }
+ else if ((SQL_ISRULE(pNode,search_condition) || SQL_ISRULE(pNode,boolean_term)) && // AND/OR link
+ pNode->count() == 3)
+ {
+ // only allow an AND link
+ if ( SQL_ISTOKEN(pNode->getChild(1),AND) )
+ bOk = checkInnerJoin(pNode->getChild(0),_xConnection,_sUpdateTableName)
+ && checkInnerJoin(pNode->getChild(2),_xConnection,_sUpdateTableName);
+ }
+ else if (SQL_ISRULE(pNode,comparison_predicate))
+ {
+ // only the comparison of columns is allowed
+ OSL_ENSURE(pNode->count() == 3,"checkInnerJoin: Error in Parse Tree");
+ if (!(SQL_ISRULE(pNode->getChild(0),column_ref) &&
+ SQL_ISRULE(pNode->getChild(2),column_ref) &&
+ pNode->getChild(1)->getNodeType() == SQLNodeType::Equal))
+ {
+ bOk = false;
+ }
+ else
+ {
+ OUString sColumnName,sTableRange;
+ OSQLParseTreeIterator::getColumnRange( pNode->getChild(0), _xConnection, sColumnName, sTableRange );
+ bOk = sTableRange == _sUpdateTableName;
+ if ( !bOk )
+ {
+ OSQLParseTreeIterator::getColumnRange( pNode->getChild(2), _xConnection, sColumnName, sTableRange );
+ bOk = sTableRange == _sUpdateTableName;
+ }
+ }
+ }
+ return bOk;
+}
+
+bool ORowSetCache::checkJoin(const Reference< XConnection>& _xConnection,
+ const Reference< XSingleSelectQueryAnalyzer >& _xAnalyzer,
+ const OUString& _sUpdateTableName )
+{
+ bool bOk = false;
+ OUString sSql = _xAnalyzer->getQuery();
+ OUString sErrorMsg;
+ ::connectivity::OSQLParser aSqlParser( m_aContext );
+ std::unique_ptr< ::connectivity::OSQLParseNode> pSqlParseNode( aSqlParser.parseTree(sErrorMsg,sSql));
+ if ( pSqlParseNode && SQL_ISRULE(pSqlParseNode, select_statement) )
+ {
+ OSQLParseNode* pTableRefCommalist = pSqlParseNode->getByRule(::connectivity::OSQLParseNode::table_ref_commalist);
+ OSL_ENSURE(pTableRefCommalist,"NO tables why!?");
+ if(pTableRefCommalist && pTableRefCommalist->count() == 1)
+ {
+ // we found only one element so it must some kind of join here
+ OSQLParseNode* pJoin = pTableRefCommalist->getByRule(::connectivity::OSQLParseNode::qualified_join);
+ if(pJoin)
+ { // we are only interested in qualified joins like RIGHT or LEFT
+ OSQLParseNode* pJoinType = pJoin->getChild(1);
+ OSQLParseNode* pOuterType = nullptr;
+ if(SQL_ISRULE(pJoinType,join_type) && pJoinType->count() == 2)
+ pOuterType = pJoinType->getChild(0);
+ else if(SQL_ISRULE(pJoinType,outer_join_type))
+ pOuterType = pJoinType;
+
+ bool bCheck = false;
+ bool bLeftSide = false;
+ if(pOuterType)
+ { // found outer join
+ bLeftSide = SQL_ISTOKEN(pOuterType->getChild(0),LEFT);
+ bCheck = bLeftSide || SQL_ISTOKEN(pOuterType->getChild(0),RIGHT);
+ }
+
+ if(bCheck)
+ { // here we know that we have to check on which side our table resides
+ const OSQLParseNode* pTableRef;
+ if(bLeftSide)
+ pTableRef = pJoin->getChild(0);
+ else
+ pTableRef = pJoin->getChild(3);
+ OSL_ENSURE(SQL_ISRULE(pTableRef,table_ref),"Must be a tableref here!");
+
+ OUString sTableRange = OSQLParseNode::getTableRange(pTableRef);
+ if(sTableRange.isEmpty())
+ pTableRef->getChild(0)->parseNodeToStr( sTableRange, _xConnection, nullptr, false, false );
+ bOk = sTableRange == _sUpdateTableName;
+ }
+ }
+ }
+ else
+ {
+ OSQLParseNode* pWhereOpt = pSqlParseNode->getChild(3)->getChild(1);
+ if ( pWhereOpt && !pWhereOpt->isLeaf() )
+ bOk = checkInnerJoin(pWhereOpt->getChild(1),_xConnection,_sUpdateTableName);
+ }
+ }
+ return bOk;
+}
+
+void ORowSetCache::clearInsertRow()
+{
+ // we don't unbound the bookmark column
+ if ( m_aInsertRow != m_pInsertMatrix->end() && m_aInsertRow->is() )
+ {
+ ORowSetValueVector::Vector::iterator aIter = (*m_aInsertRow)->begin()+1;
+ ORowSetValueVector::Vector::const_iterator aEnd = (*m_aInsertRow)->end();
+ for(;aIter != aEnd;++aIter)
+ {
+ aIter->setBound(false);
+ aIter->setModified(false);
+ aIter->setNull();
+ }
+ }
+}
+
+ORowSetMatrix::iterator ORowSetCache::calcPosition() const
+{
+ sal_Int32 nValue = (m_nPosition - m_nStartPos) - 1;
+ OSL_ENSURE((nValue >= static_cast<ORowSetMatrix::difference_type>(0)) && (o3tl::make_unsigned(nValue) < m_pMatrix->size()),"Position is invalid!");
+ return ( nValue < 0 || o3tl::make_unsigned(nValue) >= m_pMatrix->size() ) ? m_pMatrix->end() : (m_pMatrix->begin() + nValue);
+}
+
+TORowSetOldRowHelperRef ORowSetCache::registerOldRow()
+{
+ TORowSetOldRowHelperRef pRef = new ORowSetOldRowHelper(ORowSetRow());
+ m_aOldRows.push_back(pRef);
+ return pRef;
+}
+
+void ORowSetCache::deregisterOldRow(const TORowSetOldRowHelperRef& _rRow)
+{
+ TOldRowSetRows::iterator aOldRowIter = std::find_if(m_aOldRows.begin(), m_aOldRows.end(),
+ [&_rRow](const TORowSetOldRowHelperRef& rxOldRow) { return rxOldRow.get() == _rRow.get(); });
+ if (aOldRowIter != m_aOldRows.end())
+ m_aOldRows.erase(aOldRowIter);
+}
+
+bool ORowSetCache::reFillMatrix(sal_Int32 _nNewStartPos, sal_Int32 _nNewEndPos)
+{
+ for (const auto& rxOldRow : m_aOldRows)
+ {
+ if ( rxOldRow.is() && rxOldRow->getRow().is() )
+ rxOldRow->setRow(new ORowSetValueVector( *(rxOldRow->getRow()) ) );
+ }
+ sal_Int32 nNewSt = _nNewStartPos;
+ bool bRet = fillMatrix(nNewSt,_nNewEndPos);
+ m_nStartPos = nNewSt;
+ m_nEndPos = _nNewEndPos;
+ rotateAllCacheIterators(); // invalidate every iterator
+ return bRet;
+}
+
+bool ORowSetCache::fill(ORowSetMatrix::iterator& _aIter, const ORowSetMatrix::const_iterator& _aEnd, sal_Int32& _nPos, bool _bCheck)
+{
+ const sal_Int32 nColumnCount = m_xMetaData->getColumnCount();
+ for (; _bCheck && _aIter != _aEnd; ++_aIter, ++_nPos)
+ {
+ if ( !_aIter->is() )
+ *_aIter = new ORowSetValueVector(nColumnCount);
+ else
+ {
+ for (const auto& rxOldRow : m_aOldRows)
+ {
+ if ( rxOldRow->getRow() == *_aIter )
+ *_aIter = new ORowSetValueVector(nColumnCount);
+ }
+ }
+ m_xCacheSet->fillValueRow(*_aIter, _nPos);
+ _bCheck = m_xCacheSet->next();
+ }
+ return _bCheck;
+}
+
+bool ORowSetCache::isResultSetChanged() const
+{
+ return m_xCacheSet->isResultSetChanged();
+}
+
+void ORowSetCache::reset(const Reference< XResultSet>& _xDriverSet)
+{
+ m_xSet = _xDriverSet;
+ m_xMetaData.set(Reference< XResultSetMetaDataSupplier >(_xDriverSet,UNO_QUERY_THROW)->getMetaData());
+ m_xCacheSet->reset(_xDriverSet);
+
+ m_bRowCountFinal = false;
+ m_nRowCount = 0;
+ reFillMatrix(m_nStartPos,m_nEndPos);
+}
+
+void ORowSetCache::impl_updateRowFromCache_throw(ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32> const & o_ChangedColumns)
+{
+ if ( o_ChangedColumns.size() > 1 )
+ {
+ for (auto const& elem : *m_pMatrix)
+ {
+ if ( elem.is() && m_xCacheSet->updateColumnValues(*elem,io_aRow,o_ChangedColumns))
+ {
+ return;
+ }
+ }
+ m_xCacheSet->fillMissingValues(io_aRow);
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSetCache.hxx b/dbaccess/source/core/api/RowSetCache.hxx
new file mode 100644
index 000000000..01ed6394d
--- /dev/null
+++ b/dbaccess/source/core/api/RowSetCache.hxx
@@ -0,0 +1,190 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <connectivity/CommonTools.hxx>
+#include <com/sun/star/io/XInputStream.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryAnalyzer.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include "RowSetRow.hxx"
+#include "RowSetCacheIterator.hxx"
+
+namespace connectivity
+{
+ class OSQLParseNode;
+}
+namespace dbaccess
+{
+ class OCacheSet;
+
+ class ORowSetCache
+ {
+ friend class ORowSetBase;
+ friend class ORowSet;
+ friend class ORowSetClone;
+ friend class ORowSetCacheIterator;
+
+ typedef std::vector< TORowSetOldRowHelperRef > TOldRowSetRows;
+
+ std::map<sal_Int32,sal_Int32> m_aKeyColumns;
+ //the set can be static, bookmarkable or keyset
+ css::uno::WeakReference< css::sdbc::XResultSet> m_xSet;
+ css::uno::Reference< css::sdbc::XResultSetMetaData > m_xMetaData; // must be before m_aInsertRow
+ css::uno::Reference< css::uno::XComponentContext> m_aContext;
+
+ rtl::Reference<OCacheSet> m_xCacheSet; // is a bookmarkable, keyset or static resultset
+
+ std::unique_ptr<ORowSetMatrix> m_pMatrix; // represent the table struct
+ ORowSetMatrix::iterator m_aMatrixIter; // represent a row of the table
+ ORowSetMatrix::iterator m_aMatrixEnd; // present the row behind the last row of the table
+ ORowSetCacheMap m_aCacheIterators;
+ TOldRowSetRows m_aOldRows;
+
+ std::unique_ptr<ORowSetMatrix> m_pInsertMatrix; // represent the rows which should be inserted normally this is only one
+ ORowSetMatrix::iterator m_aInsertRow; // represent an insert row
+
+ connectivity::OSQLTable m_aUpdateTable; // used for updates/deletes and inserts
+
+ sal_Int32 m_nFetchSize;
+ sal_Int32 m_nRowCount;
+ sal_Int32 m_nPrivileges;
+ sal_Int32 m_nPosition; // 0 means before first (i.e. 1-based)
+
+ sal_Int32 m_nStartPos; // start pos of the window zero based (inclusive)
+ sal_Int32 m_nEndPos; // end pos of the window zero based (exclusive)
+
+ bool m_bRowCountFinal ;
+ bool m_bBeforeFirst ;
+ bool m_bAfterLast ;
+ bool& m_bModified ; // points to the rowset member m_bModified
+ bool& m_bNew ; // points to the rowset member m_bNew
+
+ bool fill(ORowSetMatrix::iterator& _aIter, const ORowSetMatrix::const_iterator& _aEnd, sal_Int32& _nPos, bool _bCheck);
+ bool reFillMatrix(sal_Int32 _nNewStartPos,sal_Int32 nNewEndPos);
+ bool fillMatrix(sal_Int32 &_nNewStartPos,sal_Int32 &_nNewEndPos);
+ void moveWindow();
+
+ void rotateCacheIterator(ORowSetMatrix::difference_type _nDist);
+ void rotateAllCacheIterators();
+ void updateValue(sal_Int32 columnIndex
+ ,const connectivity::ORowSetValue& x
+ ,ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32>& o_ChangedColumns
+ );
+
+ void impl_updateRowFromCache_throw(ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32> const & o_ChangedColumns
+ );
+ // checks and set the flags isAfterLast isLast and position when afterlast is true
+ void checkPositionFlags();
+ void checkUpdateConditions(sal_Int32 columnIndex);
+ bool checkJoin( const css::uno::Reference< css::sdbc::XConnection>& _xConnection,
+ const css::uno::Reference< css::sdb::XSingleSelectQueryAnalyzer >& _xComposer,
+ const OUString& _sUpdateTableName);
+ bool checkInnerJoin(const ::connectivity::OSQLParseNode *pNode
+ ,const css::uno::Reference< css::sdbc::XConnection>& _xConnection
+ ,const OUString& _sUpdateTableName);
+
+ // clears the insert row
+ void clearInsertRow();
+ ORowSetMatrix::iterator calcPosition() const;
+
+ protected:
+ const ORowSetMatrix::iterator& getEnd() const { return m_aMatrixEnd;}
+ // is called when after a moveToInsertRow a movement (next, etc) was called
+ void cancelRowModification();
+ public:
+ ORowSetCache(const css::uno::Reference< css::sdbc::XResultSet >& _xRs,
+ const css::uno::Reference< css::sdb::XSingleSelectQueryAnalyzer >& _xAnalyzer,
+ const css::uno::Reference< css::uno::XComponentContext >& _rContext,
+ const OUString& _rUpdateTableName,
+ bool& _bModified,
+ bool& _bNew,
+ const ORowSetValueVector& _aParameterValueForCache,
+ const OUString& i_sRowSetFilter,
+ sal_Int32 i_nMaxRows);
+ ~ORowSetCache();
+
+
+ // called from the rowset when an updateXXX was called for the first time
+ void setUpdateIterator(const ORowSetMatrix::iterator& _rOriginalRow);
+ ORowSetCacheIterator createIterator(ORowSetBase* _pRowSet);
+ void deleteIterator(const ORowSetBase* _pRowSet);
+ // sets the size of the matrix
+ void setFetchSize(sal_Int32 _nSize);
+
+ TORowSetOldRowHelperRef registerOldRow();
+ void deregisterOldRow(const TORowSetOldRowHelperRef& _rRow);
+
+ // css::sdbc::XResultSetMetaDataSupplier
+ const css::uno::Reference< css::sdbc::XResultSetMetaData >& getMetaData( ) const { return m_xMetaData;}
+
+ // css::sdbcx::XRowLocate
+ css::uno::Any getBookmark( );
+ bool moveToBookmark( const css::uno::Any& bookmark );
+ bool moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows );
+ sal_Int32 compareBookmarks( const css::uno::Any& first, const css::uno::Any& second );
+ bool hasOrderedBookmarks( );
+ sal_Int32 hashBookmark( const css::uno::Any& bookmark );
+
+ // css::sdbc::XRowUpdate
+ void updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length,ORowSetValueVector::Vector& io_aRow,std::vector<sal_Int32>& o_ChangedColumns
+ );
+ void updateObject( sal_Int32 columnIndex, const css::uno::Any& x,ORowSetValueVector::Vector& io_aRow ,std::vector<sal_Int32>& o_ChangedColumns);
+ void updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, ORowSetValueVector::Vector& io_aRow ,std::vector<sal_Int32>& o_ChangedColumns);
+ void updateNull(sal_Int32 columnIndex
+ ,ORowSetValueVector::Vector& io_aRow
+ ,std::vector<sal_Int32>& o_ChangedColumns
+ );
+
+ // css::sdbc::XResultSet
+ bool next( );
+ bool isBeforeFirst( ) const { return m_bBeforeFirst;}
+ bool isAfterLast( ) const { return m_bAfterLast;}
+ bool isFirst( ) const;
+ bool isLast( ) const;
+ void beforeFirst( );
+ void afterLast( );
+ bool first( );
+ bool last( );
+ sal_Int32 getRow( ) const;
+ bool absolute( sal_Int32 row );
+ bool relative( sal_Int32 rows );
+ bool previous( );
+ void refreshRow( );
+ bool rowUpdated( );
+ bool rowInserted( );
+
+ // css::sdbc::XResultSetUpdate
+ bool insertRow(std::vector< css::uno::Any >& o_aBookmarks);
+ void resetInsertRow(bool _bClearInsertRow);
+
+ void updateRow( ORowSetMatrix::iterator const & _rUpdateRow, std::vector< css::uno::Any >& o_aBookmarks );
+ bool deleteRow();
+ void cancelRowUpdates( );
+ void moveToInsertRow( );
+
+ const std::map<sal_Int32,sal_Int32>& getKeyColumns() const { return m_aKeyColumns; }
+ bool isResultSetChanged() const;
+ void reset(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet);
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSetCacheIterator.cxx b/dbaccess/source/core/api/RowSetCacheIterator.cxx
new file mode 100644
index 000000000..7df7bae6b
--- /dev/null
+++ b/dbaccess/source/core/api/RowSetCacheIterator.cxx
@@ -0,0 +1,91 @@
+/* -*- 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 "RowSetCacheIterator.hxx"
+#include "RowSetCache.hxx"
+#include "RowSetBase.hxx"
+
+using namespace dbaccess;
+
+ORowSetCacheIterator::ORowSetCacheIterator(const ORowSetCacheIterator& _rRH)
+: m_aIter(_rRH.m_aIter)
+, m_pCache(_rRH.m_pCache)
+,m_pRowSet(_rRH.m_pRowSet)
+{
+}
+
+ORowSetCacheIterator::operator ORowSetMatrix::iterator const &()
+{
+ return m_aIter->second.aIterator;
+}
+
+ORowSetCacheIterator& ORowSetCacheIterator::operator =(const ORowSetCacheIterator& _rRH)
+{
+ if(this == &_rRH)
+ return *this;
+
+ m_pCache = _rRH.m_pCache;
+ m_aIter = _rRH.m_aIter;
+ m_pRowSet = _rRH.m_pRowSet;
+
+ return *this;
+}
+
+ORowSetCacheIterator& ORowSetCacheIterator::operator =(const ORowSetMatrix::iterator& _rIter)
+{
+ m_aIter->second.aIterator = _rIter;
+ return *this;
+}
+
+ORowSetRow& ORowSetCacheIterator::operator *()
+{
+ return *m_aIter->second.aIterator;
+}
+
+ORowSetMatrix::iterator& ORowSetCacheIterator::operator ->()
+{
+ return m_aIter->second.aIterator;
+}
+
+bool ORowSetCacheIterator::operator <(const ORowSetMatrix::iterator& _rRH) const
+{
+ return m_aIter->second.aIterator < _rRH;
+}
+
+bool ORowSetCacheIterator::operator !=(const ORowSetMatrix::iterator& _rRH) const
+{
+ return m_aIter->second.aIterator != _rRH;
+}
+
+bool ORowSetCacheIterator::isNull() const
+{
+ bool bRet = !m_pCache || !m_pRowSet || m_aIter == m_pCache->m_aCacheIterators.end();
+ if ( !bRet )
+ {
+ bRet = ( m_pRowSet->isInsertRow()
+ ?
+ m_aIter->second.aIterator == m_pCache->m_pInsertMatrix->end()
+ :
+ m_aIter->second.aIterator == m_pCache->m_pMatrix->end()
+ );
+ }
+ return bRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSetCacheIterator.hxx b/dbaccess/source/core/api/RowSetCacheIterator.hxx
new file mode 100644
index 000000000..9c7a9afd4
--- /dev/null
+++ b/dbaccess/source/core/api/RowSetCacheIterator.hxx
@@ -0,0 +1,72 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+
+#include "RowSetRow.hxx"
+
+namespace dbaccess
+{
+ class ORowSetBase;
+ struct ORowSetCacheIterator_Helper
+ {
+ ORowSetMatrix::iterator aIterator;
+ ORowSetBase* pRowSet;
+ };
+
+ typedef std::map<sal_Int32, ORowSetCacheIterator_Helper> ORowSetCacheMap;
+
+ class ORowSetCache;
+ class ORowSetCacheIterator final
+ {
+ friend class ORowSetCache;
+ ORowSetCacheMap::iterator m_aIter;
+ ORowSetCache* m_pCache;
+ ORowSetBase* m_pRowSet;
+
+ ORowSetCacheIterator(const ORowSetCacheMap::iterator& _rIter,ORowSetCache* _pCache,ORowSetBase* _pRowSet)
+ : m_aIter(_rIter)
+ ,m_pCache(_pCache)
+ ,m_pRowSet(_pRowSet)
+ {
+ }
+ public:
+ ORowSetCacheIterator() :m_aIter(),m_pCache(nullptr),m_pRowSet(nullptr){}
+ ORowSetCacheIterator(const ORowSetCacheIterator& _rRH);
+ ORowSetCacheIterator& operator =(const ORowSetCacheIterator&);
+
+ bool isNull() const;
+ ORowSetCacheIterator& operator =(const ORowSetMatrix::iterator&);
+ operator ORowSetMatrix::iterator const &();
+
+ ORowSetRow& operator *();
+
+ ORowSetMatrix::iterator& operator ->();
+
+ bool operator <(const ORowSetMatrix::iterator& _rRH) const;
+ bool operator !=(const ORowSetMatrix::iterator& _rRH) const;
+
+ const ORowSetCacheMap::iterator& getIter() const { return m_aIter; }
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/RowSetRow.hxx b/dbaccess/source/core/api/RowSetRow.hxx
new file mode 100644
index 000000000..7f24267b7
--- /dev/null
+++ b/dbaccess/source/core/api/RowSetRow.hxx
@@ -0,0 +1,52 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <rtl/ref.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/FValue.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+
+namespace dbaccess
+{
+ typedef connectivity::ORowVector< connectivity::ORowSetValue > ORowSetValueVector;
+ typedef ::rtl::Reference< ORowSetValueVector > ORowSetRow;
+ typedef std::vector< ORowSetRow > ORowSetMatrix;
+
+ class ORowSetOldRowHelper : public salhelper::SimpleReferenceObject
+ {
+ ORowSetRow m_aRow;
+
+ ORowSetOldRowHelper& operator=(const ORowSetOldRowHelper& _rRH) = delete;
+ ORowSetOldRowHelper(const ORowSetOldRowHelper& _rRh) = delete;
+ public:
+ explicit ORowSetOldRowHelper(const ORowSetRow& _rRow)
+ : m_aRow(_rRow)
+ {}
+
+ const ORowSetRow& getRow() const { return m_aRow; }
+ void clearRow() { m_aRow = nullptr; }
+ void setRow(const ORowSetRow& _rRow) { m_aRow = _rRow; }
+ };
+
+ typedef ::rtl::Reference< ORowSetOldRowHelper > TORowSetOldRowHelperRef;
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/SingleSelectQueryComposer.cxx b/dbaccess/source/core/api/SingleSelectQueryComposer.cxx
new file mode 100644
index 000000000..3c6906893
--- /dev/null
+++ b/dbaccess/source/core/api/SingleSelectQueryComposer.cxx
@@ -0,0 +1,1922 @@
+/* -*- 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 <string.h>
+#include <sal/log.hxx>
+#include <composertools.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <stringconstants.hxx>
+#include "HelperCollections.hxx"
+#include <SingleSelectQueryComposer.hxx>
+#include <sqlbison.hxx>
+#include <sdbcoretools.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/i18n/LocaleData.hpp>
+#include <com/sun/star/script/Converter.hpp>
+#include <com/sun/star/sdb/BooleanComparisonMode.hpp>
+#include <com/sun/star/sdb/SQLFilterOperator.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/util/NumberFormatter.hpp>
+
+#include <comphelper/types.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/PColumn.hxx>
+#include <connectivity/predicateinput.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <unotools/sharedunocomponent.hxx>
+
+#include <memory>
+#include <string_view>
+
+using namespace ::dbaccess;
+using namespace ::dbtools;
+using namespace ::comphelper;
+using namespace ::connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::i18n;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::util;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace ::utl;
+
+namespace dbaccess {
+namespace BooleanComparisonMode = ::com::sun::star::sdb::BooleanComparisonMode;
+}
+
+constexpr OUStringLiteral STR_SELECT = u"SELECT ";
+constexpr OUStringLiteral STR_FROM = u" FROM ";
+constexpr OUStringLiteral STR_WHERE = u" WHERE ";
+constexpr OUStringLiteral STR_GROUP_BY = u" GROUP BY ";
+constexpr OUStringLiteral STR_HAVING = u" HAVING ";
+constexpr OUStringLiteral STR_ORDER_BY = u" ORDER BY ";
+constexpr OUStringLiteral STR_AND = u" AND ";
+constexpr OUStringLiteral STR_OR = u" OR ";
+constexpr OUStringLiteral STR_LIKE = u" LIKE ";
+constexpr OUStringLiteral L_BRACKET = u"(";
+constexpr OUStringLiteral R_BRACKET = u")";
+constexpr OUStringLiteral COMMA = u",";
+
+namespace
+{
+ /** parses the given statement, using the given parser, returns a parse node representing
+ the statement
+
+ If the statement cannot be parsed, an error is thrown.
+ */
+ std::unique_ptr<OSQLParseNode> parseStatement_throwError( OSQLParser& _rParser, const OUString& _rStatement, const Reference< XInterface >& _rxContext )
+ {
+ OUString aErrorMsg;
+ std::unique_ptr<OSQLParseNode> pNewSqlParseNode = _rParser.parseTree( aErrorMsg, _rStatement );
+ if ( !pNewSqlParseNode )
+ {
+ OUString sSQLStateGeneralError( getStandardSQLState( StandardSQLState::GENERAL_ERROR ) );
+ SQLException aError2( aErrorMsg, _rxContext, sSQLStateGeneralError, 1000, Any() );
+ SQLException aError1( _rStatement, _rxContext, sSQLStateGeneralError, 1000, Any( aError2 ) );
+ throw SQLException(_rParser.getContext().getErrorMessage(OParseContext::ErrorCode::General),_rxContext,sSQLStateGeneralError,1000,Any(aError1));
+ }
+ return pNewSqlParseNode;
+ }
+
+ /** checks whether the given parse node describes a valid single select statement, throws
+ an error if not
+ */
+ void checkForSingleSelect_throwError( const OSQLParseNode* pStatementNode, OSQLParseTreeIterator& _rIterator,
+ const Reference< XInterface >& _rxContext, const OUString& _rOriginatingCommand )
+ {
+ const OSQLParseNode* pOldNode = _rIterator.getParseTree();
+
+ // determine the statement type
+ _rIterator.setParseTree( pStatementNode );
+ _rIterator.traverseAll();
+ bool bIsSingleSelect = ( _rIterator.getStatementType() == OSQLStatementType::Select );
+
+ // throw the error, if necessary
+ if ( !bIsSingleSelect || SQL_ISRULE( pStatementNode, union_statement ) ) // #i4229# OJ
+ {
+ // restore the old node before throwing the exception
+ _rIterator.setParseTree( pOldNode );
+ // and now really ...
+ SQLException aError1( _rOriginatingCommand, _rxContext, getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 1000, Any() );
+ throw SQLException( DBA_RES( RID_STR_ONLY_QUERY ), _rxContext,
+ getStandardSQLState( StandardSQLState::GENERAL_ERROR ), 1000, Any( aError1 ) );
+ }
+
+ delete pOldNode;
+ }
+
+ /** combines parseStatement_throwError and checkForSingleSelect_throwError
+ */
+ void parseAndCheck_throwError( OSQLParser& _rParser, const OUString& _rStatement,
+ OSQLParseTreeIterator& _rIterator, const Reference< XInterface >& _rxContext )
+ {
+ std::unique_ptr<OSQLParseNode> pNode = parseStatement_throwError( _rParser, _rStatement, _rxContext );
+ checkForSingleSelect_throwError( pNode.release(), _rIterator, _rxContext, _rStatement );
+ }
+
+ /** transforms a parse node describing a complete statement into a pure select
+ statement, without any filter/order/groupby/having clauses
+ */
+ OUString getPureSelectStatement( const OSQLParseNode* _pRootNode, const Reference< XConnection >& _rxConnection )
+ {
+ OUString sSQL = STR_SELECT;
+ _pRootNode->getChild(1)->parseNodeToStr( sSQL, _rxConnection );
+ _pRootNode->getChild(2)->parseNodeToStr( sSQL, _rxConnection );
+ sSQL += STR_FROM;
+ _pRootNode->getChild(3)->getChild(0)->getChild(1)->parseNodeToStr( sSQL, _rxConnection );
+ return sSQL;
+ }
+
+ /** resets an SQL iterator, including deletion of the parse tree, and dispose
+ */
+ void resetIterator( OSQLParseTreeIterator& _rIterator )
+ {
+ const OSQLParseNode* pSqlParseNode = _rIterator.getParseTree();
+ _rIterator.setParseTree(nullptr);
+ delete pSqlParseNode;
+ _rIterator.dispose();
+ }
+ void lcl_addFilterCriteria_throw(sal_Int32 i_nFilterOperator,std::u16string_view i_sValue,OUStringBuffer& o_sRet)
+ {
+ switch( i_nFilterOperator )
+ {
+ case SQLFilterOperator::EQUAL:
+ o_sRet.append(OUString::Concat(" = ") + i_sValue);
+ break;
+ case SQLFilterOperator::NOT_EQUAL:
+ o_sRet.append(OUString::Concat(" <> ") + i_sValue);
+ break;
+ case SQLFilterOperator::LESS:
+ o_sRet.append(OUString::Concat(" < ") + i_sValue);
+ break;
+ case SQLFilterOperator::GREATER:
+ o_sRet.append(OUString::Concat(" > ") + i_sValue);
+ break;
+ case SQLFilterOperator::LESS_EQUAL:
+ o_sRet.append(OUString::Concat(" <= ") + i_sValue);
+ break;
+ case SQLFilterOperator::GREATER_EQUAL:
+ o_sRet.append(OUString::Concat(" >= ") + i_sValue);
+ break;
+ case SQLFilterOperator::LIKE:
+ o_sRet.append(OUString::Concat(" LIKE ") + i_sValue);
+ break;
+ case SQLFilterOperator::NOT_LIKE:
+ o_sRet.append(OUString::Concat(" NOT LIKE ") + i_sValue);
+ break;
+ case SQLFilterOperator::SQLNULL:
+ o_sRet.append(" IS NULL");
+ break;
+ case SQLFilterOperator::NOT_SQLNULL:
+ o_sRet.append(" IS NOT NULL");
+ break;
+ default:
+ throw SQLException();
+ }
+ }
+
+}
+
+
+OSingleSelectQueryComposer::OSingleSelectQueryComposer(const Reference< XNameAccess>& _rxTables,
+ const Reference< XConnection>& _xConnection,
+ const Reference<XComponentContext>& _rContext )
+ :OSubComponent(m_aMutex,_xConnection)
+ ,OPropertyContainer(m_aBHelper)
+ ,m_aSqlParser( _rContext, &m_aParseContext )
+ ,m_aSqlIterator( _xConnection, _rxTables, m_aSqlParser )
+ ,m_aAdditiveIterator( _xConnection, _rxTables, m_aSqlParser )
+ ,m_aElementaryParts( size_t(SQLPartCount) )
+ ,m_xConnection(_xConnection)
+ ,m_xMetaData(_xConnection->getMetaData())
+ ,m_xConnectionTables( _rxTables )
+ ,m_aContext( _rContext )
+ ,m_nBoolCompareMode( BooleanComparisonMode::EQUAL_INTEGER )
+ ,m_nCommandType(CommandType::COMMAND)
+{
+ if ( !m_aContext.is() || !m_xConnection.is() || !m_xConnectionTables.is() )
+ throw IllegalArgumentException();
+
+ registerProperty(PROPERTY_ORIGINAL,PROPERTY_ID_ORIGINAL,PropertyAttribute::BOUND|PropertyAttribute::READONLY,&m_sOriginal,cppu::UnoType<decltype(m_sOriginal)>::get());
+
+ m_aCurrentColumns.resize(4);
+
+ m_aLocale = m_aParseContext.getPreferredLocale();
+ m_xNumberFormatsSupplier = dbtools::getNumberFormats( m_xConnection, true, m_aContext );
+ Reference< XLocaleData4 > xLocaleData( LocaleData::create(m_aContext) );
+ LocaleDataItem aData = xLocaleData->getLocaleItem(m_aLocale);
+ m_sDecimalSep = aData.decimalSeparator;
+ OSL_ENSURE(m_sDecimalSep.getLength() == 1,"OSingleSelectQueryComposer::OSingleSelectQueryComposer decimal separator is not 1 length");
+ try
+ {
+ Any aValue;
+ Reference<XInterface> xDs = dbaccess::getDataSource(_xConnection);
+ if ( dbtools::getDataSourceSetting(xDs,static_cast <OUString> (PROPERTY_BOOLEANCOMPARISONMODE),aValue) )
+ {
+ OSL_VERIFY( aValue >>= m_nBoolCompareMode );
+ }
+ Reference< XQueriesSupplier > xQueriesAccess(m_xConnection, UNO_QUERY);
+ if (xQueriesAccess.is())
+ m_xConnectionQueries = xQueriesAccess->getQueries();
+ }
+ catch(Exception&)
+ {
+ }
+}
+
+OSingleSelectQueryComposer::~OSingleSelectQueryComposer()
+{
+}
+
+// OComponentHelper
+void SAL_CALL OSingleSelectQueryComposer::disposing()
+{
+ OSubComponent::disposing();
+
+ MutexGuard aGuard(m_aMutex);
+
+ resetIterator( m_aSqlIterator );
+ resetIterator( m_aAdditiveIterator );
+
+ m_xConnectionTables = nullptr;
+ m_xConnection = nullptr;
+
+ clearCurrentCollections();
+}
+
+IMPLEMENT_FORWARD_XINTERFACE3(OSingleSelectQueryComposer,OSubComponent,OSingleSelectQueryComposer_BASE,OPropertyContainer)
+OUString SAL_CALL OSingleSelectQueryComposer::getImplementationName()
+ {
+ return "org.openoffice.comp.dba.OSingleSelectQueryComposer";
+ }
+sal_Bool SAL_CALL OSingleSelectQueryComposer::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL OSingleSelectQueryComposer::getSupportedServiceNames()
+{
+ return { SERVICE_NAME_SINGLESELECTQUERYCOMPOSER };
+}
+
+css::uno::Sequence<sal_Int8> OSingleSelectQueryComposer::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+css::uno::Sequence< css::uno::Type > OSingleSelectQueryComposer::getTypes()
+{
+ return ::comphelper::concatSequences(
+ OSubComponent::getTypes( ),
+ OSingleSelectQueryComposer_BASE::getTypes( ),
+ OPropertyContainer::getTypes( )
+ );
+}
+
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OSingleSelectQueryComposer::getPropertySetInfo()
+{
+ Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+::cppu::IPropertyArrayHelper& OSingleSelectQueryComposer::getInfoHelper()
+{
+ return *OSingleSelectQueryComposer::getArrayHelper();
+}
+::cppu::IPropertyArrayHelper* OSingleSelectQueryComposer::createArrayHelper( ) const
+{
+ css::uno::Sequence< css::beans::Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+
+// XSingleSelectQueryAnalyzer
+OUString SAL_CALL OSingleSelectQueryComposer::getQuery( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ TGetParseNode F_tmp(&OSQLParseTreeIterator::getParseTree);
+ return getStatementPart(F_tmp,m_aSqlIterator);
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setQuery( const OUString& command )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_nCommandType = CommandType::COMMAND;
+ // first clear the tables and columns
+ clearCurrentCollections();
+ // now set the new one
+ setQuery_Impl(command);
+ m_sOriginal = command;
+
+ // reset the additive iterator to the same statement
+ parseAndCheck_throwError( m_aSqlParser, m_sOriginal, m_aAdditiveIterator, *this );
+
+ // we have no "elementary" parts anymore (means filter/groupby/having/order clauses)
+ for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
+ m_aElementaryParts[ eLoopParts ].clear();
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setCommand( const OUString& Command,sal_Int32 _nCommandType )
+{
+ OUStringBuffer sSQL;
+ switch(_nCommandType)
+ {
+ case CommandType::COMMAND:
+ setElementaryQuery(Command);
+ return;
+ case CommandType::TABLE:
+ if ( m_xConnectionTables->hasByName(Command) )
+ {
+ sSQL.append("SELECT * FROM ");
+ Reference< XPropertySet > xTable;
+ try
+ {
+ m_xConnectionTables->getByName( Command ) >>= xTable;
+ }
+ catch(const WrappedTargetException& e)
+ {
+ SQLException e2;
+ if ( e.TargetException >>= e2 )
+ throw e2;
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ sSQL.append(dbtools::composeTableNameForSelect(m_xConnection,xTable));
+ }
+ else
+ {
+ OUString sMessage( DBA_RES( RID_STR_TABLE_DOES_NOT_EXIST ) );
+ throwGenericSQLException(sMessage.replaceAll( "$table$", Command ),*this);
+ }
+ break;
+ case CommandType::QUERY:
+ if ( m_xConnectionQueries->hasByName(Command) )
+ {
+
+ Reference<XPropertySet> xQuery(m_xConnectionQueries->getByName(Command),UNO_QUERY);
+ OUString sCommand;
+ xQuery->getPropertyValue(PROPERTY_COMMAND) >>= sCommand;
+ sSQL.append(sCommand);
+ }
+ else
+ {
+ OUString sMessage( DBA_RES( RID_STR_QUERY_DOES_NOT_EXIST ) );
+ throwGenericSQLException(sMessage.replaceAll( "$table$", Command ),*this);
+ }
+
+ break;
+ default:
+ break;
+ }
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_nCommandType = _nCommandType;
+ m_sCommand = Command;
+ // first clear the tables and columns
+ clearCurrentCollections();
+ // now set the new one
+ OUString sCommand = sSQL.makeStringAndClear();
+ setElementaryQuery(sCommand);
+ m_sOriginal = sCommand;
+}
+
+void OSingleSelectQueryComposer::setQuery_Impl( const OUString& command )
+{
+ // parse this
+ parseAndCheck_throwError( m_aSqlParser, command, m_aSqlIterator, *this );
+
+ // strip it from all clauses, to have the pure SELECT statement
+ m_aPureSelectSQL = getPureSelectStatement( m_aSqlIterator.getParseTree(), m_xConnection );
+
+ // update tables
+ getTables();
+}
+
+Sequence< Sequence< PropertyValue > > SAL_CALL OSingleSelectQueryComposer::getStructuredHavingClause( )
+{
+ TGetParseNode F_tmp(&OSQLParseTreeIterator::getSimpleHavingTree);
+ return getStructuredCondition(F_tmp);
+}
+
+Sequence< Sequence< PropertyValue > > SAL_CALL OSingleSelectQueryComposer::getStructuredFilter( )
+{
+ TGetParseNode F_tmp(&OSQLParseTreeIterator::getSimpleWhereTree);
+ return getStructuredCondition(F_tmp);
+}
+
+void SAL_CALL OSingleSelectQueryComposer::appendHavingClauseByColumn( const Reference< XPropertySet >& column, sal_Bool andCriteria,sal_Int32 filterOperator )
+{
+ auto F_tmp = std::mem_fn(&OSingleSelectQueryComposer::implSetHavingClause);
+ setConditionByColumn(column,andCriteria,F_tmp,filterOperator);
+}
+
+void SAL_CALL OSingleSelectQueryComposer::appendFilterByColumn( const Reference< XPropertySet >& column, sal_Bool andCriteria,sal_Int32 filterOperator )
+{
+ auto F_tmp = std::mem_fn(&OSingleSelectQueryComposer::implSetFilter);
+ setConditionByColumn(column,andCriteria,F_tmp,filterOperator);
+}
+
+OUString OSingleSelectQueryComposer::impl_getColumnRealName_throw(const Reference< XPropertySet >& column, bool bGroupBy)
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ getColumns();
+ if ( !column.is()
+ || !m_aCurrentColumns[SelectColumns]
+ || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_NAME)
+ )
+ {
+ OUString sError(DBA_RES(RID_STR_COLUMN_UNKNOWN_PROP));
+ SQLException aErr(sError.replaceAll("%value", PROPERTY_NAME),*this,SQLSTATE_GENERAL,1000,Any() );
+ throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_VALID),*this,SQLSTATE_GENERAL,1000,Any(aErr) );
+ }
+
+ OUString aName, aNewName;
+ column->getPropertyValue(PROPERTY_NAME) >>= aName;
+
+ if ( bGroupBy &&
+ !m_xMetaData->supportsGroupByUnrelated() &&
+ m_aCurrentColumns[SelectColumns] &&
+ !m_aCurrentColumns[SelectColumns]->hasByName(aName) )
+ {
+ OUString sError(DBA_RES(RID_STR_COLUMN_MUST_VISIBLE));
+ throw SQLException(sError.replaceAll("%name", aName),*this,SQLSTATE_GENERAL,1000,Any() );
+ }
+
+ OUString aQuote = m_xMetaData->getIdentifierQuoteString();
+ if ( m_aCurrentColumns[SelectColumns]->hasByName(aName) )
+ {
+ Reference<XPropertySet> xColumn;
+ m_aCurrentColumns[SelectColumns]->getByName(aName) >>= xColumn;
+ OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME),"Property REALNAME not available!");
+ OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME),"Property TABLENAME not available!");
+ OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName("Function"),"Property FUNCTION not available!");
+
+ OUString sRealName, sTableName;
+ xColumn->getPropertyValue(PROPERTY_REALNAME) >>= sRealName;
+ xColumn->getPropertyValue(PROPERTY_TABLENAME) >>= sTableName;
+ bool bFunction = false;
+ xColumn->getPropertyValue("Function") >>= bFunction;
+ if ( sRealName == aName )
+ {
+ if ( bFunction )
+ aNewName = aName;
+ else
+ {
+ if(sTableName.indexOf('.') != -1)
+ {
+ OUString aCatlog,aSchema,aTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData,sTableName,aCatlog,aSchema,aTable,::dbtools::EComposeRule::InDataManipulation);
+ sTableName = ::dbtools::composeTableName( m_xMetaData, aCatlog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation );
+ }
+ else if (!sTableName.isEmpty())
+ sTableName = ::dbtools::quoteName(aQuote,sTableName);
+
+ if(sTableName.isEmpty())
+ aNewName = ::dbtools::quoteName(aQuote,sRealName);
+ else
+ aNewName = sTableName + "." + ::dbtools::quoteName(aQuote,sRealName);
+ }
+ }
+ else
+ aNewName = ::dbtools::quoteName(aQuote,aName);
+ }
+ else
+ aNewName = getTableAlias(column) + ::dbtools::quoteName(aQuote,aName);
+ return aNewName;
+}
+
+OUString OSingleSelectQueryComposer::impl_getColumnNameOrderBy_throw(const Reference< XPropertySet >& column)
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ getColumns();
+ if ( !column.is()
+ || !m_aCurrentColumns[SelectColumns]
+ || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_NAME)
+ )
+ {
+ OUString sError(DBA_RES(RID_STR_COLUMN_UNKNOWN_PROP));
+ SQLException aErr(sError.replaceAll("%value", PROPERTY_NAME),*this,SQLSTATE_GENERAL,1000,Any() );
+ throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_VALID),*this,SQLSTATE_GENERAL,1000,Any(aErr) );
+ }
+
+ OUString aName;
+ column->getPropertyValue(PROPERTY_NAME) >>= aName;
+
+ const OUString aQuote = m_xMetaData->getIdentifierQuoteString();
+
+ if ( m_aCurrentColumns[SelectColumns] &&
+ m_aCurrentColumns[SelectColumns]->hasByName(aName) )
+ {
+ // It is a column from the SELECT list, use it as such.
+ return ::dbtools::quoteName(aQuote,aName);
+ }
+
+ // Nope, it is an unrelated column.
+ // Is that supported?
+ if ( !m_xMetaData->supportsOrderByUnrelated() )
+ {
+ OUString sError(DBA_RES(RID_STR_COLUMN_MUST_VISIBLE));
+ throw SQLException(sError.replaceAll("%name", aName),*this,SQLSTATE_GENERAL,1000,Any() );
+ }
+
+ // We need to refer to it by its "real" name, that is by schemaName.tableName.columnNameInTable
+ return impl_getColumnRealName_throw(column, false);
+}
+
+void SAL_CALL OSingleSelectQueryComposer::appendOrderByColumn( const Reference< XPropertySet >& column, sal_Bool ascending )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ OUString sColumnName( impl_getColumnNameOrderBy_throw(column) );
+ OUString sOrder = getOrder();
+ if ( !(sOrder.isEmpty() || sColumnName.isEmpty()) )
+ sOrder += COMMA;
+ sOrder += sColumnName;
+ if ( !(ascending || sColumnName.isEmpty()) )
+ sOrder += " DESC ";
+
+ setOrder(sOrder);
+}
+
+void SAL_CALL OSingleSelectQueryComposer::appendGroupByColumn( const Reference< XPropertySet >& column)
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ OUString sColumnName( impl_getColumnRealName_throw(column, true) );
+ OrderCreator aComposer;
+ aComposer.append( getGroup() );
+ aComposer.append( sColumnName );
+ setGroup( aComposer.getComposedAndClear() );
+}
+
+OUString OSingleSelectQueryComposer::composeStatementFromParts( const std::vector< OUString >& _rParts )
+{
+ OSL_ENSURE( _rParts.size() == size_t(SQLPartCount), "OSingleSelectQueryComposer::composeStatementFromParts: invalid parts array!" );
+
+ OUStringBuffer aSql( m_aPureSelectSQL );
+ for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
+ if ( !_rParts[ eLoopParts ].isEmpty() )
+ {
+ aSql.append( getKeyword( eLoopParts ) );
+ aSql.append( _rParts[ eLoopParts ] );
+ }
+
+ return aSql.makeStringAndClear();
+}
+
+OUString SAL_CALL OSingleSelectQueryComposer::getElementaryQuery()
+{
+ return composeStatementFromParts( m_aElementaryParts );
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setElementaryQuery( const OUString& _rElementary )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // remember the 4 current "additive" clauses
+ std::vector< OUString > aAdditiveClauses( SQLPartCount );
+ for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
+ aAdditiveClauses[ eLoopParts ] = getSQLPart( eLoopParts, m_aAdditiveIterator, false );
+
+ // clear the tables and columns
+ clearCurrentCollections();
+ // set and parse the new query
+ setQuery_Impl( _rElementary );
+
+ // get the 4 elementary parts of the statement
+ for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
+ m_aElementaryParts[ eLoopParts ] = getSQLPart( eLoopParts, m_aSqlIterator, false );
+
+ // reset the AdditiveIterator: m_aPureSelectSQL may have changed
+ try
+ {
+ parseAndCheck_throwError( m_aSqlParser, composeStatementFromParts( aAdditiveClauses ), m_aAdditiveIterator, *this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setElementaryQuery: there should be no error anymore for the additive statement!" );
+ // every part of the additive statement should have passed other tests already, and should not
+ // be able to cause any errors ... me thinks
+ }
+}
+
+namespace
+{
+ OUString getComposedClause( const OUString& _rElementaryClause, const OUString& _rAdditionalClause,
+ TokenComposer& _rComposer, std::u16string_view _rKeyword )
+ {
+ _rComposer.clear();
+ _rComposer.append( _rElementaryClause );
+ _rComposer.append( _rAdditionalClause );
+ OUString sComposed = _rComposer.getComposedAndClear();
+ if ( !sComposed.isEmpty() )
+ sComposed = _rKeyword + sComposed;
+ return sComposed;
+ }
+}
+
+void OSingleSelectQueryComposer::setSingleAdditiveClause( SQLPart _ePart, const OUString& _rClause )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ // if nothing is changed, do nothing
+ if ( getSQLPart( _ePart, m_aAdditiveIterator, false ) == _rClause )
+ return;
+
+ // collect the 4 single parts as they're currently set
+ std::vector< OUString > aClauses;
+ aClauses.reserve( size_t(SQLPartCount) );
+ for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
+ aClauses.push_back( getSQLPart( eLoopParts, m_aSqlIterator, true ) );
+
+ // overwrite the one part in question here
+ std::unique_ptr< TokenComposer > pComposer;
+ if ( ( _ePart == Where ) || ( _ePart == Having ) )
+ pComposer.reset( new FilterCreator );
+ else
+ pComposer.reset( new OrderCreator );
+ aClauses[ _ePart ] = getComposedClause( m_aElementaryParts[ _ePart ], _rClause,
+ *pComposer, getKeyword( _ePart ) );
+
+ // construct the complete statement
+ OUStringBuffer aSql(m_aPureSelectSQL);
+ for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
+ aSql.append(aClauses[ eLoopParts ]);
+
+ // set the query
+ setQuery_Impl(aSql.makeStringAndClear());
+
+ // clear column collections which (might) have changed
+ clearColumns( ParameterColumns );
+ if ( _ePart == Order )
+ clearColumns( OrderColumns );
+ else if ( _ePart == Group )
+ clearColumns( GroupByColumns );
+
+ // also, since the "additive filter" change, we need to rebuild our "additive" statement
+ aSql = m_aPureSelectSQL;
+ // again, first get all the old additive parts
+ for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
+ aClauses[ eLoopParts ] = getSQLPart( eLoopParts, m_aAdditiveIterator, true );
+ // then overwrite the one in question
+ aClauses[ _ePart ] = getComposedClause( OUString(), _rClause, *pComposer, getKeyword( _ePart ) );
+ // and parse it, so that m_aAdditiveIterator is up to date
+ for ( SQLPart eLoopParts = Where; eLoopParts != SQLPartCount; incSQLPart( eLoopParts ) )
+ aSql.append(aClauses[ eLoopParts ]);
+ try
+ {
+ parseAndCheck_throwError( m_aSqlParser, aSql.makeStringAndClear(), m_aAdditiveIterator, *this );
+ }
+ catch( const Exception& )
+ {
+ SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setSingleAdditiveClause: there should be no error anymore for the additive statement!" );
+ // every part of the additive statement should have passed other tests already, and should not
+ // be able to cause any errors ... me thinks
+ }
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setFilter( const OUString& filter )
+{
+ setSingleAdditiveClause( Where, filter );
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setOrder( const OUString& order )
+{
+ setSingleAdditiveClause( Order, order );
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setGroup( const OUString& group )
+{
+ setSingleAdditiveClause( Group, group );
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setHavingClause( const OUString& filter )
+{
+ setSingleAdditiveClause( Having, filter );
+}
+
+// XTablesSupplier
+Reference< XNameAccess > SAL_CALL OSingleSelectQueryComposer::getTables( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !m_pTables )
+ {
+ const OSQLTables& aTables = m_aSqlIterator.getTables();
+ std::vector< OUString> aNames;
+ for (auto const& elem : aTables)
+ aNames.push_back(elem.first);
+
+ m_pTables.reset( new OPrivateTables(aTables,m_xMetaData->supportsMixedCaseQuotedIdentifiers(),*this,m_aMutex,std::move(aNames)) );
+ }
+
+ return m_pTables.get();
+}
+
+// XColumnsSupplier
+Reference< XNameAccess > SAL_CALL OSingleSelectQueryComposer::getColumns( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !!m_aCurrentColumns[SelectColumns] )
+ return m_aCurrentColumns[SelectColumns].get();
+
+ std::vector< OUString> aNames;
+ ::rtl::Reference< OSQLColumns> aSelectColumns;
+ bool bCase = true;
+ Reference< XNameAccess> xQueryColumns;
+ if ( m_nCommandType == CommandType::QUERY )
+ {
+ Reference<XColumnsSupplier> xSup(m_xConnectionQueries->getByName(m_sCommand),UNO_QUERY);
+ if(xSup.is())
+ xQueryColumns = xSup->getColumns();
+ }
+
+ do {
+
+ try
+ {
+ SharedUNOComponent< XStatement, DisposableComponent > xStatement;
+ SharedUNOComponent< XPreparedStatement, DisposableComponent > xPreparedStatement;
+
+ bCase = m_xMetaData->supportsMixedCaseQuotedIdentifiers();
+ aSelectColumns = m_aSqlIterator.getSelectColumns();
+
+ OUStringBuffer aSQL( m_aPureSelectSQL + STR_WHERE + " ( 0 = 1 )");
+
+ // preserve the original WHERE clause
+ // #i102234#
+ OUString sOriginalWhereClause = getSQLPart( Where, m_aSqlIterator, false );
+ if ( !sOriginalWhereClause.isEmpty() )
+ {
+ aSQL.append( " AND ( " + sOriginalWhereClause + " ) " );
+ }
+
+ OUString sGroupBy = getSQLPart( Group, m_aSqlIterator, true );
+ if ( !sGroupBy.isEmpty() )
+ aSQL.append( sGroupBy );
+
+ OUString sSQL( aSQL.makeStringAndClear() );
+ // normalize the statement so that it doesn't contain any application-level features anymore
+ OUString sError;
+ const std::unique_ptr< OSQLParseNode > pStatementTree( m_aSqlParser.parseTree( sError, sSQL ) );
+ OSL_ENSURE(pStatementTree, "OSingleSelectQueryComposer::getColumns: could not parse the "
+ "column retrieval statement!");
+ if (pStatementTree)
+ if ( !pStatementTree->parseNodeToExecutableStatement( sSQL, m_xConnection, m_aSqlParser, nullptr ) )
+ break;
+
+ Reference< XResultSetMetaData > xResultSetMeta;
+ Reference< XResultSetMetaDataSupplier > xResMetaDataSup;
+ try
+ {
+ xPreparedStatement.set( m_xConnection->prepareStatement( sSQL ), UNO_QUERY_THROW );
+ xResMetaDataSup.set( xPreparedStatement, UNO_QUERY_THROW );
+ xResultSetMeta.set( xResMetaDataSup->getMetaData(), UNO_SET_THROW );
+ }
+ catch( const Exception& ) { }
+
+ if ( !xResultSetMeta.is() && xPreparedStatement.is() )
+ {
+ try
+ {
+ //@see issue http://qa.openoffice.org/issues/show_bug.cgi?id=110111
+ // access returns a different order of column names when executing select * from
+ // and asking the columns from the metadata.
+ Reference< XParameters > xParameters( xPreparedStatement, UNO_QUERY_THROW );
+ Reference< XIndexAccess > xPara = getParameters();
+ for(sal_Int32 i = 1;i <= xPara->getCount();++i)
+ xParameters->setNull(i,DataType::VARCHAR);
+ xResMetaDataSup.set(xPreparedStatement->executeQuery(), UNO_QUERY_THROW );
+ xResultSetMeta.set( xResMetaDataSup->getMetaData(), UNO_SET_THROW );
+ }
+ catch( const Exception& ) { }
+ }
+
+ if ( !xResultSetMeta.is() )
+ {
+ xStatement.reset( Reference< XStatement >( m_xConnection->createStatement(), UNO_SET_THROW ) );
+ Reference< XPropertySet > xStatementProps( xStatement, UNO_QUERY_THROW );
+ try { xStatementProps->setPropertyValue( PROPERTY_ESCAPE_PROCESSING, Any( false ) ); }
+ catch ( const Exception& ) { DBG_UNHANDLED_EXCEPTION("dbaccess"); }
+ xResMetaDataSup.set( xStatement->executeQuery( sSQL ), UNO_QUERY_THROW );
+ xResultSetMeta.set( xResMetaDataSup->getMetaData(), UNO_SET_THROW );
+
+ if (xResultSetMeta.is())
+ {
+ SAL_WARN("dbaccess", "OSingleSelectQueryComposer::getColumns failed to get xResultSetMeta from executed PreparedStatement, but got it from 'no escape processing' statement. SQL command:\n\t" << sSQL );
+ }
+ }
+
+ if ( aSelectColumns->empty() )
+ {
+ // This is a valid case. If we can syntactically parse the query, but not semantically
+ // (e.g. because it is based on a table we do not know), then there will be no SelectColumns
+ aSelectColumns = ::connectivity::parse::OParseColumn::createColumnsForResultSet( xResultSetMeta, m_xMetaData ,xQueryColumns);
+ break;
+ }
+
+ const ::comphelper::UStringMixEqual aCaseCompare( bCase );
+ std::set< size_t > aUsedSelectColumns;
+ ::connectivity::parse::OParseColumn::StringMap aColumnNames;
+
+ sal_Int32 nCount = xResultSetMeta->getColumnCount();
+ OSL_ENSURE( static_cast<size_t>(nCount) == aSelectColumns->size(), "OSingleSelectQueryComposer::getColumns: inconsistent column counts, this might result in wrong columns!" );
+ for(sal_Int32 i=1;i<=nCount;++i)
+ {
+ OUString sColumnName = xResultSetMeta->getColumnName(i);
+ OUString sColumnLabel;
+ if ( xQueryColumns.is() && xQueryColumns->hasByName(sColumnName) )
+ {
+ Reference<XPropertySet> xQueryColumn(xQueryColumns->getByName(sColumnName),UNO_QUERY_THROW);
+ xQueryColumn->getPropertyValue(PROPERTY_LABEL) >>= sColumnLabel;
+ }
+ else
+ sColumnLabel = xResultSetMeta->getColumnLabel(i);
+ bool bFound = false;
+ OSQLColumns::Vector::const_iterator aFind = ::connectivity::find(aSelectColumns->begin(),aSelectColumns->end(),sColumnLabel,aCaseCompare);
+ size_t nFoundSelectColumnPos = aFind - aSelectColumns->begin();
+ if ( aFind != aSelectColumns->end() )
+ {
+ if ( aUsedSelectColumns.find( nFoundSelectColumnPos ) != aUsedSelectColumns.end() )
+ { // we found a column name which exists twice
+ // so we start after the first found
+ do
+ {
+ aFind = ::connectivity::findRealName(++aFind,aSelectColumns->end(),sColumnName,aCaseCompare);
+ nFoundSelectColumnPos = aFind - aSelectColumns->begin();
+ }
+ while ( ( aUsedSelectColumns.find( nFoundSelectColumnPos ) != aUsedSelectColumns.end() )
+ && ( aFind != aSelectColumns->end() )
+ );
+ }
+ if ( aFind != aSelectColumns->end() )
+ {
+ (*aFind)->getPropertyValue(PROPERTY_NAME) >>= sColumnName;
+ aUsedSelectColumns.insert( nFoundSelectColumnPos );
+ aNames.push_back(sColumnName);
+ bFound = true;
+ }
+ }
+
+ if ( bFound )
+ continue;
+
+ OSQLColumns::Vector::const_iterator aRealFind = ::connectivity::findRealName(
+ aSelectColumns->begin(), aSelectColumns->end(), sColumnName, aCaseCompare );
+
+ if ( i > static_cast< sal_Int32>( aSelectColumns->size() ) )
+ {
+ aSelectColumns->emplace_back(::connectivity::parse::OParseColumn::createColumnForResultSet( xResultSetMeta, m_xMetaData, i ,aColumnNames)
+ );
+ OSL_ENSURE( aSelectColumns->size() == static_cast<size_t>(i), "OSingleSelectQueryComposer::getColumns: inconsistency!" );
+ }
+ else if ( aRealFind == aSelectColumns->end() )
+ {
+ // we can now only look if we found it under the realname property
+ // here we have to make the assumption that the position is correct
+ OSQLColumns::Vector::const_iterator aFind2 = aSelectColumns->begin() + i-1;
+ Reference<XPropertySet> xProp = *aFind2;
+ if ( !xProp.is() || !xProp->getPropertySetInfo()->hasPropertyByName( PROPERTY_REALNAME ) )
+ continue;
+
+ rtl::Reference<::connectivity::parse::OParseColumn> pColumn = new ::connectivity::parse::OParseColumn(xProp,bCase);
+ pColumn->setFunction(::comphelper::getBOOL(xProp->getPropertyValue("Function")));
+ pColumn->setAggregateFunction(::comphelper::getBOOL(xProp->getPropertyValue("AggregateFunction")));
+
+ OUString sRealName;
+ xProp->getPropertyValue(PROPERTY_REALNAME) >>= sRealName;
+ if ( sColumnName.isEmpty() )
+ xProp->getPropertyValue(PROPERTY_NAME) >>= sColumnName;
+
+ sal_Int32 j = 0;
+ while ( std::any_of(aNames.begin(),aNames.end(),
+ [&aCaseCompare, &sColumnName](const OUString& lhs)
+ { return aCaseCompare(lhs, sColumnName); } ) )
+ {
+ sColumnName += OUString::number(++j);
+ }
+
+ pColumn->setName(sColumnName);
+ pColumn->setRealName(sRealName);
+ pColumn->setTableName(::comphelper::getString(xProp->getPropertyValue(PROPERTY_TABLENAME)));
+
+ (*aSelectColumns)[i-1] = pColumn;
+ }
+ else
+ continue;
+
+ aUsedSelectColumns.insert( static_cast<size_t>(i - 1) );
+ aNames.push_back( sColumnName );
+ }
+ }
+ catch(const Exception&)
+ {
+ }
+
+ } while ( false );
+
+ bool bMissingSomeColumnLabels = !aNames.empty() && aNames.size() != aSelectColumns->size();
+ SAL_WARN_IF(bMissingSomeColumnLabels, "dbaccess", "We have column labels for *some* columns but not all");
+ //^^this happens in the evolution address book where we have real column names of e.g.
+ //first_name, second_name and city. On parsing via
+ //OSQLParseTreeIterator::appendColumns it creates some labels using those real names
+ //but the evo address book gives them proper labels of First Name, Second Name and City
+ //the munge means that here we have e.g. just "City" as a label because it matches
+
+ //This is all a horrible mess
+ if (bMissingSomeColumnLabels)
+ aNames.clear();
+
+ if ( aNames.empty() )
+ m_aCurrentColumns[ SelectColumns ] = OPrivateColumns::createWithIntrinsicNames( aSelectColumns, bCase, *this, m_aMutex );
+ else
+ m_aCurrentColumns[ SelectColumns ].reset( new OPrivateColumns( aSelectColumns, bCase, *this, m_aMutex, aNames ) );
+
+ return m_aCurrentColumns[SelectColumns].get();
+}
+
+bool OSingleSelectQueryComposer::setORCriteria(OSQLParseNode const * pCondition, OSQLParseTreeIterator& _rIterator,
+ std::vector< std::vector < PropertyValue > >& rFilters, const Reference< css::util::XNumberFormatter > & xFormatter) const
+{
+ // Round brackets around the expression
+ if (pCondition->count() == 3 &&
+ SQL_ISPUNCTUATION(pCondition->getChild(0),"(") &&
+ SQL_ISPUNCTUATION(pCondition->getChild(2),")"))
+ {
+ return setORCriteria(pCondition->getChild(1), _rIterator, rFilters, xFormatter);
+ }
+ // OR logic expression
+ // a searchcondition can only look like this: search_condition SQL_TOKEN_OR boolean_term
+ else if (SQL_ISRULE(pCondition,search_condition))
+ {
+ bool bResult = true;
+ for (int i = 0; bResult && i < 3; i+=2)
+ {
+ // Is the first element a OR logic expression again?
+ // Then descend recursively ...
+ if (SQL_ISRULE(pCondition->getChild(i),search_condition))
+ bResult = setORCriteria(pCondition->getChild(i), _rIterator, rFilters, xFormatter);
+ else
+ {
+ rFilters.emplace_back();
+ bResult = setANDCriteria(pCondition->getChild(i), _rIterator, rFilters[rFilters.size() - 1], xFormatter);
+ }
+ }
+ return bResult;
+ }
+ else
+ {
+ rFilters.emplace_back();
+ return setANDCriteria(pCondition, _rIterator, rFilters[rFilters.size() - 1], xFormatter);
+ }
+}
+
+bool OSingleSelectQueryComposer::setANDCriteria( OSQLParseNode const * pCondition,
+ OSQLParseTreeIterator& _rIterator, std::vector < PropertyValue >& rFilter, const Reference< XNumberFormatter > & xFormatter) const
+{
+ // Round brackets
+ if (SQL_ISRULE(pCondition,boolean_primary))
+ {
+ // this should not occur
+ SAL_WARN("dbaccess","boolean_primary in And-Criteria");
+ return false;
+ }
+ // The first element is an AND logical expression again
+ else if ( SQL_ISRULE(pCondition,boolean_term) && pCondition->count() == 3 )
+ {
+ return setANDCriteria(pCondition->getChild(0), _rIterator, rFilter, xFormatter) &&
+ setANDCriteria(pCondition->getChild(2), _rIterator, rFilter, xFormatter);
+ }
+ else if (SQL_ISRULE(pCondition, comparison_predicate))
+ {
+ return setComparisonPredicate(pCondition,_rIterator,rFilter,xFormatter);
+ }
+ else if (SQL_ISRULE(pCondition,like_predicate))
+ {
+ return setLikePredicate(pCondition,_rIterator,rFilter,xFormatter);
+ }
+ else if (SQL_ISRULE(pCondition,test_for_null) ||
+ SQL_ISRULE(pCondition,in_predicate) ||
+ SQL_ISRULE(pCondition,all_or_any_predicate) ||
+ SQL_ISRULE(pCondition,between_predicate))
+ {
+ if (SQL_ISRULE(pCondition->getChild(0), column_ref))
+ {
+ PropertyValue aItem;
+ OUString aValue;
+ OUString aColumnName;
+
+ pCondition->parseNodeToStr( aValue, m_xConnection );
+ pCondition->getChild(0)->parseNodeToStr( aColumnName, m_xConnection );
+
+ // don't display the column name
+ aValue = aValue.copy(aColumnName.getLength());
+ aValue = aValue.trim();
+
+ aItem.Name = getColumnName(pCondition->getChild(0),_rIterator);
+ aItem.Value <<= aValue;
+ aItem.Handle = 0; // just to know that this is not one the known ones
+ if ( SQL_ISRULE(pCondition,like_predicate) )
+ {
+ if ( SQL_ISTOKEN(pCondition->getChild(1)->getChild(0),NOT) )
+ aItem.Handle = SQLFilterOperator::NOT_LIKE;
+ else
+ aItem.Handle = SQLFilterOperator::LIKE;
+ }
+ else if (SQL_ISRULE(pCondition,test_for_null))
+ {
+ if (SQL_ISTOKEN(pCondition->getChild(1)->getChild(1),NOT) )
+ aItem.Handle = SQLFilterOperator::NOT_SQLNULL;
+ else
+ aItem.Handle = SQLFilterOperator::SQLNULL;
+ }
+ else if (SQL_ISRULE(pCondition,in_predicate))
+ {
+ SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setANDCriteria: in_predicate not implemented!" );
+ }
+ else if (SQL_ISRULE(pCondition,all_or_any_predicate))
+ {
+ SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setANDCriteria: all_or_any_predicate not implemented!" );
+ }
+ else if (SQL_ISRULE(pCondition,between_predicate))
+ {
+ SAL_WARN("dbaccess", "OSingleSelectQueryComposer::setANDCriteria: between_predicate not implemented!" );
+ }
+
+ rFilter.push_back(aItem);
+ }
+ else
+ return false;
+ }
+ else if (SQL_ISRULE(pCondition,existence_test) ||
+ SQL_ISRULE(pCondition,unique_test))
+ {
+ // this couldn't be handled here, too complex
+ // as we need a field name
+ return false;
+ }
+ else
+ return false;
+
+ return true;
+}
+
+sal_Int32 OSingleSelectQueryComposer::getPredicateType(OSQLParseNode const * _pPredicate)
+{
+ sal_Int32 nPredicate = SQLFilterOperator::EQUAL;
+ switch (_pPredicate->getNodeType())
+ {
+ case SQLNodeType::Equal:
+ nPredicate = SQLFilterOperator::EQUAL;
+ break;
+ case SQLNodeType::NotEqual:
+ nPredicate = SQLFilterOperator::NOT_EQUAL;
+ break;
+ case SQLNodeType::Less:
+ nPredicate = SQLFilterOperator::LESS;
+ break;
+ case SQLNodeType::LessEq:
+ nPredicate = SQLFilterOperator::LESS_EQUAL;
+ break;
+ case SQLNodeType::Great:
+ nPredicate = SQLFilterOperator::GREATER;
+ break;
+ case SQLNodeType::GreatEq:
+ nPredicate = SQLFilterOperator::GREATER_EQUAL;
+ break;
+ default:
+ SAL_WARN("dbaccess","Wrong NodeType!");
+ }
+ return nPredicate;
+}
+
+bool OSingleSelectQueryComposer::setLikePredicate(OSQLParseNode const * pCondition, OSQLParseTreeIterator const & _rIterator,
+ std::vector < PropertyValue >& rFilter, const Reference< css::util::XNumberFormatter > & xFormatter) const
+{
+ OSL_ENSURE(SQL_ISRULE(pCondition, like_predicate),"setLikePredicate: pCondition is not a LikePredicate");
+
+ assert(pCondition->count() == 2);
+ OSQLParseNode const *pRowValue = pCondition->getChild(0);
+ OSQLParseNode const *pPart2 = pCondition->getChild(1);
+
+ PropertyValue aItem;
+ if ( SQL_ISTOKEN(pPart2->getChild(0),NOT) )
+ aItem.Handle = SQLFilterOperator::NOT_LIKE;
+ else
+ aItem.Handle = SQLFilterOperator::LIKE;
+
+ if (SQL_ISRULE(pRowValue, column_ref))
+ {
+ OUString aValue;
+
+ // skip (optional "NOT") and "LIKE"
+ for (size_t i=2; i < pPart2->count(); i++)
+ {
+ pPart2->getChild(i)->parseNodeToPredicateStr(
+ aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+ }
+
+ aItem.Name = getColumnName(pRowValue,_rIterator);
+ aItem.Value <<= aValue;
+ rFilter.push_back(aItem);
+ }
+ else if (SQL_ISRULE(pRowValue, set_fct_spec ) ||
+ SQL_ISRULE(pRowValue, general_set_fct))
+ {
+ OUString aValue;
+ OUString aColumnName;
+
+ pPart2->getChild(2)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+ pPart2->getChild(3)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+ pRowValue->parseNodeToPredicateStr( aColumnName, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+
+ aItem.Name = getColumnName(pRowValue,_rIterator);
+ aItem.Value <<= aValue;
+ rFilter.push_back(aItem);
+ }
+ else // Can only be an expression
+ {
+ OUString aName, aValue;
+
+ OSQLParseNode const *pValue = pPart2->getChild(2);
+
+ // Field names
+ for (size_t i=0;i< pRowValue->count();i++)
+ pRowValue->getChild(i)->parseNodeToPredicateStr( aName, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+
+ // Criterion
+ for(size_t i=0;i< pValue->count();i++)
+ pValue->getChild(i)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+ pPart2->getChild(3)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+
+ aItem.Name = aName;
+ aItem.Value <<= aValue;
+ rFilter.push_back(aItem);
+ }
+ return true;
+}
+
+bool OSingleSelectQueryComposer::setComparisonPredicate(OSQLParseNode const * pCondition, OSQLParseTreeIterator const & _rIterator,
+ std::vector < PropertyValue >& rFilter, const Reference< css::util::XNumberFormatter > & xFormatter) const
+{
+ OSL_ENSURE(SQL_ISRULE(pCondition, comparison_predicate),"setComparisonPredicate: pCondition is not a ComparisonPredicate");
+ if (SQL_ISRULE(pCondition->getChild(0), column_ref) ||
+ SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref))
+ {
+ PropertyValue aItem;
+ OUString aValue;
+ sal_uInt32 nPos;
+ if (SQL_ISRULE(pCondition->getChild(0), column_ref))
+ {
+ nPos = 0;
+ size_t i=1;
+
+ aItem.Handle = getPredicateType(pCondition->getChild(i));
+
+ // go forward - don't display the operator
+ for (i++;i < pCondition->count();i++)
+ pCondition->getChild(i)->parseNodeToPredicateStr(
+ aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+ }
+ else if (SQL_ISRULE(pCondition->getChild(pCondition->count()-1), column_ref))
+ {
+ nPos = pCondition->count()-1;
+
+ sal_Int32 i = pCondition->count() - 2;
+ switch (pCondition->getChild(i)->getNodeType())
+ {
+ case SQLNodeType::Equal:
+ aItem.Handle = SQLFilterOperator::EQUAL;
+ break;
+ case SQLNodeType::NotEqual:
+ aItem.Handle = SQLFilterOperator::NOT_EQUAL;
+ break;
+ case SQLNodeType::Less:
+ // take the opposite as we change the order
+ aItem.Handle = SQLFilterOperator::GREATER_EQUAL;
+ break;
+ case SQLNodeType::LessEq:
+ // take the opposite as we change the order
+ aItem.Handle = SQLFilterOperator::GREATER;
+ break;
+ case SQLNodeType::Great:
+ // take the opposite as we change the order
+ aItem.Handle = SQLFilterOperator::LESS_EQUAL;
+ break;
+ case SQLNodeType::GreatEq:
+ // take the opposite as we change the order
+ aItem.Handle = SQLFilterOperator::LESS;
+ break;
+ default:
+ break;
+ }
+
+ // go backward - don't display the operator
+ for (i--; i >= 0; i--)
+ pCondition->getChild(i)->parseNodeToPredicateStr(
+ aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+ }
+ else
+ return false;
+
+ aItem.Name = getColumnName(pCondition->getChild(nPos),_rIterator);
+ aItem.Value <<= aValue;
+ rFilter.push_back(aItem);
+ }
+ else if (SQL_ISRULE(pCondition->getChild(0), set_fct_spec ) ||
+ SQL_ISRULE(pCondition->getChild(0), general_set_fct))
+ {
+ PropertyValue aItem;
+ OUString aValue;
+ OUString aColumnName;
+
+ pCondition->getChild(2)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+ pCondition->getChild(0)->parseNodeToPredicateStr( aColumnName, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+
+ aItem.Name = getColumnName(pCondition->getChild(0),_rIterator);
+ aItem.Value <<= aValue;
+ aItem.Handle = getPredicateType(pCondition->getChild(1));
+ rFilter.push_back(aItem);
+ }
+ else // Can only be an expression
+ {
+ PropertyValue aItem;
+ OUString aName, aValue;
+
+ OSQLParseNode *pLhs = pCondition->getChild(0);
+ OSQLParseNode *pRhs = pCondition->getChild(2);
+
+ // Field names
+ for (size_t i=0;i< pLhs->count();i++)
+ pLhs->getChild(i)->parseNodeToPredicateStr( aName, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+
+ // Criterion
+ aItem.Handle = getPredicateType(pCondition->getChild(1));
+ for(size_t i=0;i< pRhs->count();i++)
+ pRhs->getChild(i)->parseNodeToPredicateStr(aValue, m_xConnection, xFormatter, m_aLocale, m_sDecimalSep );
+
+ aItem.Name = aName;
+ aItem.Value <<= aValue;
+ rFilter.push_back(aItem);
+ }
+ return true;
+}
+
+// Functions for analysing SQL
+OUString OSingleSelectQueryComposer::getColumnName( ::connectivity::OSQLParseNode const * pColumnRef, OSQLParseTreeIterator const & _rIterator )
+{
+ OUString aTableRange, aColumnName;
+ _rIterator.getColumnRange(pColumnRef,aColumnName,aTableRange);
+ return aColumnName;
+}
+
+OUString SAL_CALL OSingleSelectQueryComposer::getFilter( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return getSQLPart(Where,m_aAdditiveIterator,false);
+}
+
+OUString SAL_CALL OSingleSelectQueryComposer::getOrder( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return getSQLPart(Order,m_aAdditiveIterator,false);
+}
+
+OUString SAL_CALL OSingleSelectQueryComposer::getGroup( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return getSQLPart(Group,m_aAdditiveIterator,false);
+}
+
+OUString OSingleSelectQueryComposer::getHavingClause()
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return getSQLPart(Having,m_aAdditiveIterator,false);
+}
+
+OUString OSingleSelectQueryComposer::getTableAlias(const Reference< XPropertySet >& column) const
+{
+ OUString sReturn;
+ if(m_pTables && m_pTables->getCount() > 1)
+ {
+ OUString aCatalog,aSchema,aTable,aColumnName;
+ if(column->getPropertySetInfo()->hasPropertyByName(PROPERTY_CATALOGNAME))
+ column->getPropertyValue(PROPERTY_CATALOGNAME) >>= aCatalog;
+ if(column->getPropertySetInfo()->hasPropertyByName(PROPERTY_SCHEMANAME))
+ column->getPropertyValue(PROPERTY_SCHEMANAME) >>= aSchema;
+ if(column->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME))
+ column->getPropertyValue(PROPERTY_TABLENAME) >>= aTable;
+ column->getPropertyValue(PROPERTY_NAME) >>= aColumnName;
+
+ Sequence< OUString> aNames(m_pTables->getElementNames());
+ const OUString* pBegin = aNames.getConstArray();
+ const OUString* const pEnd = pBegin + aNames.getLength();
+
+ if(aTable.isEmpty())
+ { // we haven't found a table name, now we must search every table for this column
+ for(;pBegin != pEnd;++pBegin)
+ {
+ Reference<XColumnsSupplier> xColumnsSupp;
+ m_pTables->getByName(*pBegin) >>= xColumnsSupp;
+
+ if(xColumnsSupp.is() && xColumnsSupp->getColumns()->hasByName(aColumnName))
+ {
+ aTable = *pBegin;
+ break;
+ }
+ }
+ }
+ else
+ {
+ OUString aComposedName = ::dbtools::composeTableName( m_xMetaData, aCatalog, aSchema, aTable, false, ::dbtools::EComposeRule::InDataManipulation );
+
+ // Is this the right case for the table name?
+ // Else, look for it with different case, if applicable.
+
+ if(!m_pTables->hasByName(aComposedName))
+ {
+ ::comphelper::UStringMixLess aTmp(m_aAdditiveIterator.getTables().key_comp());
+ ::comphelper::UStringMixEqual aComp(aTmp.isCaseSensitive());
+ for(;pBegin != pEnd;++pBegin)
+ {
+ Reference<XPropertySet> xTableProp;
+ m_pTables->getByName(*pBegin) >>= xTableProp;
+ OSL_ENSURE(xTableProp.is(),"Table isn't a propertyset!");
+ if(xTableProp.is())
+ {
+ OUString aCatalog2,aSchema2,aTable2;
+ xTableProp->getPropertyValue(PROPERTY_CATALOGNAME) >>= aCatalog2;
+ xTableProp->getPropertyValue(PROPERTY_SCHEMANAME) >>= aSchema2;
+ xTableProp->getPropertyValue(PROPERTY_NAME) >>= aTable2;
+ if(aComp(aCatalog,aCatalog2) && aComp(aSchema,aSchema2) && aComp(aTable,aTable2))
+ {
+ aCatalog = aCatalog2;
+ aSchema = aSchema2;
+ aTable = aTable2;
+ break;
+ }
+ }
+ }
+ }
+ }
+ if(pBegin != pEnd)
+ {
+ sReturn = ::dbtools::composeTableName( m_xMetaData, aCatalog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation ) + ".";
+ }
+ }
+ return sReturn;
+}
+
+Reference< XIndexAccess > SAL_CALL OSingleSelectQueryComposer::getParameters( )
+{
+ // now set the Parameters
+ if ( !m_aCurrentColumns[ParameterColumns] )
+ {
+ ::rtl::Reference< OSQLColumns> aCols = m_aSqlIterator.getParameters();
+ std::vector< OUString> aNames;
+ for (auto const& elem : *aCols)
+ aNames.push_back(getString(elem->getPropertyValue(PROPERTY_NAME)));
+ m_aCurrentColumns[ParameterColumns].reset( new OPrivateColumns(aCols,m_xMetaData->supportsMixedCaseQuotedIdentifiers(),*this,m_aMutex,aNames,true) );
+ }
+
+ return m_aCurrentColumns[ParameterColumns].get();
+}
+
+void OSingleSelectQueryComposer::clearColumns( const EColumnType _eType )
+{
+ OPrivateColumns* pColumns = m_aCurrentColumns[ _eType ].get();
+ if ( pColumns != nullptr )
+ {
+ pColumns->disposing();
+ m_aColumnsCollection.push_back( std::move(m_aCurrentColumns[ _eType ]) );
+ }
+}
+
+void OSingleSelectQueryComposer::clearCurrentCollections()
+{
+ for (auto & currentColumn : m_aCurrentColumns)
+ {
+ if (currentColumn)
+ {
+ currentColumn->disposing();
+ m_aColumnsCollection.push_back(std::move(currentColumn));
+ }
+ }
+
+ if(m_pTables)
+ {
+ m_pTables->disposing();
+ m_aTablesCollection.push_back(std::move(m_pTables));
+ }
+}
+
+Reference< XIndexAccess > OSingleSelectQueryComposer::setCurrentColumns( EColumnType _eType,
+ const ::rtl::Reference< OSQLColumns >& _rCols )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ // now set the group columns
+ if ( !m_aCurrentColumns[_eType] )
+ {
+ std::vector< OUString> aNames;
+ for (auto const& elem : *_rCols)
+ aNames.push_back(getString(elem->getPropertyValue(PROPERTY_NAME)));
+ m_aCurrentColumns[_eType].reset( new OPrivateColumns(_rCols,m_xMetaData->supportsMixedCaseQuotedIdentifiers(),*this,m_aMutex,aNames,true) );
+ }
+
+ return m_aCurrentColumns[_eType].get();
+}
+
+Reference< XIndexAccess > SAL_CALL OSingleSelectQueryComposer::getGroupColumns( )
+{
+ return setCurrentColumns( GroupByColumns, m_aAdditiveIterator.getGroupColumns() );
+}
+
+Reference< XIndexAccess > SAL_CALL OSingleSelectQueryComposer::getOrderColumns( )
+{
+ return setCurrentColumns( OrderColumns, m_aAdditiveIterator.getOrderColumns() );
+}
+
+OUString SAL_CALL OSingleSelectQueryComposer::getQueryWithSubstitution( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ OUString sSqlStatement( getQuery() );
+
+ const OSQLParseNode* pStatementNode = m_aSqlIterator.getParseTree();
+ if ( pStatementNode )
+ {
+ SQLException aError;
+ if ( !pStatementNode->parseNodeToExecutableStatement( sSqlStatement, m_xConnection, m_aSqlParser, &aError ) )
+ throw aError;
+ }
+
+ return sSqlStatement;
+}
+
+OUString OSingleSelectQueryComposer::getStatementPart( TGetParseNode const & _aGetFunctor, OSQLParseTreeIterator& _rIterator )
+{
+ OUString sResult;
+
+ const OSQLParseNode* pNode = _aGetFunctor( &_rIterator );
+ if ( pNode )
+ pNode->parseNodeToStr( sResult, m_xConnection );
+
+ return sResult;
+}
+
+namespace
+{
+ OUString lcl_getDecomposedColumnName(const OUString& rComposedName, const OUString& rQuoteString)
+ {
+ const sal_Int32 nQuoteLength = rQuoteString.getLength();
+ OUString sName = rComposedName.trim();
+ OUString sColumnName;
+ sal_Int32 nPos, nRPos = 0;
+
+ for (;;)
+ {
+ nPos = sName.indexOf( rQuoteString, nRPos );
+ if ( nPos >= 0 )
+ {
+ nRPos = sName.indexOf( rQuoteString, nPos + nQuoteLength );
+ if ( nRPos > nPos )
+ {
+ if ( nRPos + nQuoteLength < sName.getLength() )
+ {
+ nRPos += nQuoteLength; // -1 + 1 skip dot
+ }
+ else
+ {
+ sColumnName = sName.copy( nPos + nQuoteLength, nRPos - nPos - nQuoteLength );
+ break;
+ }
+ }
+ else
+ break;
+ }
+ else
+ break;
+ }
+ return sColumnName.isEmpty() ? rComposedName : sColumnName;
+ }
+
+ OUString lcl_getCondition(const Sequence< Sequence< PropertyValue > >& filter,
+ const OPredicateInputController& i_aPredicateInputController,
+ const Reference< XNameAccess >& i_xSelectColumns,
+ const OUString& rQuoteString)
+ {
+ OUStringBuffer sRet;
+ const Sequence< PropertyValue >* pOrIter = filter.getConstArray();
+ const Sequence< PropertyValue >* pOrEnd = pOrIter + filter.getLength();
+ while ( pOrIter != pOrEnd )
+ {
+ if ( pOrIter->hasElements() )
+ {
+ sRet.append(L_BRACKET);
+ const PropertyValue* pAndIter = pOrIter->getConstArray();
+ const PropertyValue* pAndEnd = pAndIter + pOrIter->getLength();
+ while ( pAndIter != pAndEnd )
+ {
+ sRet.append(pAndIter->Name);
+ OUString sValue;
+ pAndIter->Value >>= sValue;
+ const OUString sColumnName = lcl_getDecomposedColumnName( pAndIter->Name, rQuoteString );
+ if ( i_xSelectColumns.is() && i_xSelectColumns->hasByName(sColumnName) )
+ {
+ Reference<XPropertySet> xColumn(i_xSelectColumns->getByName(sColumnName),UNO_QUERY);
+ sValue = i_aPredicateInputController.getPredicateValueStr(sValue,xColumn);
+ }
+ else
+ {
+ sValue = i_aPredicateInputController.getPredicateValueStr(pAndIter->Name,sValue);
+ }
+ lcl_addFilterCriteria_throw(pAndIter->Handle,sValue,sRet);
+ ++pAndIter;
+ if ( pAndIter != pAndEnd )
+ sRet.append(STR_AND);
+ }
+ sRet.append(R_BRACKET);
+ }
+ ++pOrIter;
+ if ( pOrIter != pOrEnd && !sRet.isEmpty() )
+ sRet.append(STR_OR);
+ }
+ return sRet.makeStringAndClear();
+ }
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setStructuredFilter( const Sequence< Sequence< PropertyValue > >& filter )
+{
+ OPredicateInputController aPredicateInput(m_aContext, m_xConnection, &m_aParseContext);
+ setFilter(lcl_getCondition(filter, aPredicateInput, getColumns(), m_xMetaData->getIdentifierQuoteString()));
+}
+
+void SAL_CALL OSingleSelectQueryComposer::setStructuredHavingClause( const Sequence< Sequence< PropertyValue > >& filter )
+{
+ OPredicateInputController aPredicateInput(m_aContext, m_xConnection);
+ setHavingClause(lcl_getCondition(filter, aPredicateInput, getColumns(), m_xMetaData->getIdentifierQuoteString()));
+}
+
+void OSingleSelectQueryComposer::setConditionByColumn( const Reference< XPropertySet >& column, bool andCriteria, std::function<bool(OSingleSelectQueryComposer *, const OUString&)> const & _aSetFunctor, sal_Int32 filterOperator)
+{
+ try
+ {
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ if ( !column.is()
+ || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_VALUE)
+ || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_NAME)
+ || !column->getPropertySetInfo()->hasPropertyByName(PROPERTY_TYPE))
+ throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_VALID),*this,SQLSTATE_GENERAL,1000,Any() );
+
+ sal_Int32 nType = 0;
+ column->getPropertyValue(PROPERTY_TYPE) >>= nType;
+ sal_Int32 nSearchable = dbtools::getSearchColumnFlag(m_xConnection,nType);
+ if(nSearchable == ColumnSearch::NONE)
+ throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_SEARCHABLE),*this,SQLSTATE_GENERAL,1000,Any() );
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ OUString aName;
+ column->getPropertyValue(PROPERTY_NAME) >>= aName;
+
+ const Any aValue = column->getPropertyValue(PROPERTY_VALUE);
+
+ OUStringBuffer aSQL;
+ const OUString aQuote = m_xMetaData->getIdentifierQuoteString();
+ getColumns();
+
+ // TODO: if this is called for HAVING, check that the column is a GROUP BY column
+ // or that it is an aggregate function
+
+ if ( m_aCurrentColumns[SelectColumns] && m_aCurrentColumns[SelectColumns]->hasByName(aName) )
+ {
+ Reference<XPropertySet> xColumn;
+ m_aCurrentColumns[SelectColumns]->getByName(aName) >>= xColumn;
+ OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_REALNAME),"Property REALNAME not available!");
+ OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName(PROPERTY_TABLENAME),"Property TABLENAME not available!");
+ OSL_ENSURE(xColumn->getPropertySetInfo()->hasPropertyByName("AggregateFunction"),"Property AggregateFunction not available!");
+
+ OUString sRealName,sTableName;
+ xColumn->getPropertyValue(PROPERTY_REALNAME) >>= sRealName;
+ xColumn->getPropertyValue(PROPERTY_TABLENAME) >>= sTableName;
+ if(sTableName.indexOf('.') != -1)
+ {
+ OUString aCatlog,aSchema,aTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData,sTableName,aCatlog,aSchema,aTable,::dbtools::EComposeRule::InDataManipulation);
+ sTableName = ::dbtools::composeTableName( m_xMetaData, aCatlog, aSchema, aTable, true, ::dbtools::EComposeRule::InDataManipulation );
+ }
+ else
+ sTableName = ::dbtools::quoteName(aQuote,sTableName);
+
+ if ( !::comphelper::getBOOL(xColumn->getPropertyValue("Function")) )
+ {
+ aSQL = sTableName + "." + ::dbtools::quoteName( aQuote, sRealName );
+ }
+ else
+ aSQL = sRealName;
+ }
+ else
+ {
+ aSQL = getTableAlias( column ) + ::dbtools::quoteName( aQuote, aName );
+ }
+
+ if ( aValue.hasValue() )
+ {
+ if( !m_xTypeConverter.is() )
+ m_xTypeConverter.set( Converter::create(m_aContext) );
+ OSL_ENSURE(m_xTypeConverter.is(),"NO typeconverter!");
+
+ if ( nType != DataType::BOOLEAN && DataType::BIT != nType )
+ {
+ lcl_addFilterCriteria_throw(filterOperator,u"",aSQL);
+ }
+
+ switch(nType)
+ {
+ case DataType::VARCHAR:
+ case DataType::CHAR:
+ case DataType::LONGVARCHAR:
+ aSQL.append( DBTypeConversion::toSQLString( nType, aValue, m_xTypeConverter ) );
+ break;
+ case DataType::CLOB:
+ {
+ Reference< XClob > xClob(aValue,UNO_QUERY);
+ if ( xClob.is() )
+ {
+ const ::sal_Int64 nLength = xClob->length();
+ if ( sal_Int64(nLength + aSQL.getLength() + STR_LIKE.getLength() ) < sal_Int64(SAL_MAX_INT32) )
+ {
+ aSQL.append("'" + xClob->getSubString(1,static_cast<sal_Int32>(nLength)) + "'");
+ }
+ }
+ else
+ {
+ aSQL.append( DBTypeConversion::toSQLString( nType, aValue, m_xTypeConverter ) );
+ }
+ }
+ break;
+ case DataType::VARBINARY:
+ case DataType::BINARY:
+ case DataType::LONGVARBINARY:
+ {
+ Sequence<sal_Int8> aSeq;
+ if(!(aValue >>= aSeq))
+ throw SQLException(DBA_RES(RID_STR_NOT_SEQUENCE_INT8),*this,SQLSTATE_GENERAL,1000,Any() );
+ if(nSearchable == ColumnSearch::CHAR)
+ {
+ aSQL.append( "\'" );
+ }
+ aSQL.append( "0x" );
+ const sal_Int8* pBegin = aSeq.getConstArray();
+ const sal_Int8* pEnd = pBegin + aSeq.getLength();
+ for(;pBegin != pEnd;++pBegin)
+ {
+ aSQL.append( static_cast<sal_Int32>(*pBegin), 16 );
+ }
+ if(nSearchable == ColumnSearch::CHAR)
+ aSQL.append( "\'" );
+ }
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ {
+ bool bValue = false;
+ m_xTypeConverter->convertToSimpleType(aValue, TypeClass_BOOLEAN) >>= bValue;
+
+ OUString sColumnExp = aSQL.makeStringAndClear();
+ getBooleanComparisonPredicate( sColumnExp, bValue, m_nBoolCompareMode, aSQL );
+ }
+ break;
+ default:
+ aSQL.append( DBTypeConversion::toSQLString( nType, aValue, m_xTypeConverter ) );
+ break;
+ }
+ }
+ else
+ {
+ sal_Int32 nFilterOp = filterOperator;
+ if ( filterOperator != SQLFilterOperator::SQLNULL && filterOperator != SQLFilterOperator::NOT_SQLNULL )
+ nFilterOp = SQLFilterOperator::SQLNULL;
+ lcl_addFilterCriteria_throw(nFilterOp,u"",aSQL);
+ }
+
+ // Attach filter
+ // Construct SELECT without WHERE and ORDER BY
+ OUString sFilter = getFilter();
+
+ if ( !sFilter.isEmpty() && !aSQL.isEmpty() )
+ {
+ sFilter = L_BRACKET + sFilter + R_BRACKET +
+ (andCriteria ? std::u16string_view(STR_AND) : std::u16string_view(STR_OR));
+ }
+ sFilter += aSQL;
+
+ // add the filter and the sort order
+ _aSetFunctor(this,sFilter);
+ }
+ catch (css::lang::WrappedTargetException & e)
+ {
+ if (e.TargetException.isExtractableTo(
+ cppu::UnoType<css::sdbc::SQLException>::get()))
+ {
+ cppu::throwException(e.TargetException);
+ }
+ else
+ {
+ throw;
+ }
+ }
+}
+
+Sequence< Sequence< PropertyValue > > OSingleSelectQueryComposer::getStructuredCondition( TGetParseNode const & _aGetFunctor )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ MutexGuard aGuard(m_aMutex);
+
+ Sequence< Sequence< PropertyValue > > aFilterSeq;
+ OUString sFilter = getStatementPart( _aGetFunctor, m_aAdditiveIterator );
+
+
+ if ( !sFilter.isEmpty() )
+ {
+ OUString aSql(m_aPureSelectSQL + STR_WHERE + sFilter);
+ // build a temporary parse node
+ const OSQLParseNode* pTempNode = m_aAdditiveIterator.getParseTree();
+
+ OUString aErrorMsg;
+ std::unique_ptr<OSQLParseNode> pSqlParseNode( m_aSqlParser.parseTree(aErrorMsg,aSql));
+ if (pSqlParseNode)
+ {
+ m_aAdditiveIterator.setParseTree(pSqlParseNode.get());
+ // normalize the filter
+ OSQLParseNode* pWhereNode = const_cast<OSQLParseNode*>(m_aAdditiveIterator.getWhereTree());
+
+ OSQLParseNode* pCondition = pWhereNode->getChild(1);
+ #if OSL_DEBUG_LEVEL > 0
+ OUString sCondition;
+ pCondition->parseNodeToStr( sCondition, m_xConnection );
+ #endif
+ OSQLParseNode::negateSearchCondition(pCondition);
+
+ pCondition = pWhereNode->getChild(1);
+ #if OSL_DEBUG_LEVEL > 0
+ sCondition.clear();
+ pCondition->parseNodeToStr( sCondition, m_xConnection );
+ #endif
+ OSQLParseNode::disjunctiveNormalForm(pCondition);
+
+ pCondition = pWhereNode->getChild(1);
+ #if OSL_DEBUG_LEVEL > 0
+ sCondition.clear();
+ pCondition->parseNodeToStr( sCondition, m_xConnection );
+ #endif
+ OSQLParseNode::absorptions(pCondition);
+
+ pCondition = pWhereNode->getChild(1);
+ #if OSL_DEBUG_LEVEL > 0
+ sCondition.clear();
+ pCondition->parseNodeToStr( sCondition, m_xConnection );
+ #endif
+ if ( pCondition )
+ {
+ std::vector< std::vector < PropertyValue > > aFilters;
+ Reference< XNumberFormatter > xFormatter( NumberFormatter::create(m_aContext), UNO_QUERY_THROW );
+ xFormatter->attachNumberFormatsSupplier( m_xNumberFormatsSupplier );
+
+ if (setORCriteria(pCondition, m_aAdditiveIterator, aFilters, xFormatter))
+ {
+ aFilterSeq.realloc(aFilters.size());
+ Sequence<PropertyValue>* pFilters = aFilterSeq.getArray();
+ for (auto const& filter : aFilters)
+ {
+ pFilters->realloc(filter.size());
+ PropertyValue* pFilter = pFilters->getArray();
+ for (auto const& elem : filter)
+ {
+ *pFilter = elem;
+ ++pFilter;
+ }
+ ++pFilters;
+ }
+ }
+ }
+ // restore
+ m_aAdditiveIterator.setParseTree(pTempNode);
+ }
+ }
+ return aFilterSeq;
+}
+
+OUString OSingleSelectQueryComposer::getKeyword( SQLPart _ePart )
+{
+ OUString sKeyword;
+ switch(_ePart)
+ {
+ default:
+ SAL_WARN("dbaccess", "OSingleSelectQueryComposer::getKeyWord: Invalid enum value!" );
+ [[fallthrough]]; // fallback to WHERE
+ case Where:
+ sKeyword = STR_WHERE;
+ break;
+ case Group:
+ sKeyword = STR_GROUP_BY;
+ break;
+ case Having:
+ sKeyword = STR_HAVING;
+ break;
+ case Order:
+ sKeyword = STR_ORDER_BY;
+ break;
+ }
+ return sKeyword;
+}
+
+OUString OSingleSelectQueryComposer::getSQLPart( SQLPart _ePart, OSQLParseTreeIterator& _rIterator, bool _bWithKeyword )
+{
+ TGetParseNode F_tmp(&OSQLParseTreeIterator::getSimpleWhereTree);
+ OUString sKeyword( getKeyword( _ePart ) );
+ switch(_ePart)
+ {
+ case Where:
+ F_tmp = TGetParseNode(&OSQLParseTreeIterator::getSimpleWhereTree);
+ break;
+ case Group:
+ F_tmp = TGetParseNode (&OSQLParseTreeIterator::getSimpleGroupByTree);
+ break;
+ case Having:
+ F_tmp = TGetParseNode(&OSQLParseTreeIterator::getSimpleHavingTree);
+ break;
+ case Order:
+ F_tmp = TGetParseNode(&OSQLParseTreeIterator::getSimpleOrderTree);
+ break;
+ default:
+ SAL_WARN("dbaccess","Invalid enum value!");
+ }
+
+ OUString sRet = getStatementPart( F_tmp, _rIterator );
+ if ( _bWithKeyword && !sRet.isEmpty() )
+ sRet = sKeyword + sRet;
+ return sRet;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/StaticSet.cxx b/dbaccess/source/core/api/StaticSet.cxx
new file mode 100644
index 000000000..97226b466
--- /dev/null
+++ b/dbaccess/source/core/api/StaticSet.cxx
@@ -0,0 +1,280 @@
+/* -*- 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 "StaticSet.hxx"
+#include <com/sun/star/sdbcx/CompareBookmark.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <connectivity/CommonTools.hxx>
+#include <comphelper/types.hxx>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+
+using namespace dbaccess;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+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::lang;
+using namespace ::osl;
+
+void OStaticSet::fillValueRow(ORowSetRow& _rRow,sal_Int32 /*_nPosition*/)
+{
+ _rRow = *m_aSetIter;
+}
+
+// css::sdbcx::XRowLocate
+Any OStaticSet::getBookmark()
+{
+ return Any(getRow());
+}
+
+bool OStaticSet::moveToBookmark( const Any& bookmark )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ return absolute(::comphelper::getINT32(bookmark));
+}
+
+sal_Int32 OStaticSet::compareBookmarks( const Any& _first, const Any& _second )
+{
+ sal_Int32 nFirst = 0, nSecond = 0;
+ _first >>= nFirst;
+ _second >>= nSecond;
+ return (nFirst < nSecond) ? CompareBookmark::LESS : ((nFirst > nSecond) ? CompareBookmark::GREATER : CompareBookmark::EQUAL);
+}
+
+bool OStaticSet::hasOrderedBookmarks( )
+{
+ return true;
+}
+
+sal_Int32 OStaticSet::hashBookmark( const Any& bookmark )
+{
+ return ::comphelper::getINT32(bookmark);
+}
+
+bool OStaticSet::fetchRow()
+{
+ bool bRet = false;
+ if ( !m_bEnd && (!m_nMaxRows || sal_Int32(m_aSet.size()) < m_nMaxRows) )
+ bRet = m_xDriverSet->next();
+ if ( bRet )
+ {
+ m_aSet.push_back(new connectivity::ORowVector< connectivity::ORowSetValue >(m_xSetMetaData->getColumnCount()));
+ m_aSetIter = m_aSet.end() - 1;
+ (**m_aSetIter)[0] = getRow();
+ OCacheSet::fillValueRow(*m_aSetIter,(**m_aSetIter)[0].getInt32());
+ }
+ else
+ m_bEnd = true;
+ return bRet;
+}
+
+void OStaticSet::fillAllRows()
+{
+ if(m_bEnd)
+ return;
+
+ sal_Int32 nColumnCount = m_xSetMetaData->getColumnCount();
+ while(m_xDriverSet->next())
+ {
+ ORowSetRow pRow = new connectivity::ORowVector< connectivity::ORowSetValue >(nColumnCount);
+ m_aSet.push_back(pRow);
+ m_aSetIter = m_aSet.end() - 1;
+ (*pRow)[0] = getRow();
+ OCacheSet::fillValueRow(pRow,(*pRow)[0].getInt32());
+ }
+ m_bEnd = true;
+}
+
+// XResultSet
+bool OStaticSet::next()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+
+ if(isAfterLast())
+ return false;
+ if(!m_bEnd) // not yet all records fetched
+ {
+ ++m_aSetIter;
+ if(m_aSetIter == m_aSet.end() && !fetchRow())
+ m_aSetIter = m_aSet.end();
+ }
+ else if(!isAfterLast())
+ ++m_aSetIter;
+ return !isAfterLast();
+}
+
+bool OStaticSet::isBeforeFirst( )
+{
+ return m_aSetIter == m_aSet.begin();
+}
+
+bool OStaticSet::isAfterLast( )
+{
+ return m_aSetIter == m_aSet.end() && m_bEnd;
+}
+
+void OStaticSet::beforeFirst( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ m_aSetIter = m_aSet.begin();
+}
+
+void OStaticSet::afterLast( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ fillAllRows();
+ m_aSetIter = m_aSet.end();
+}
+
+bool OStaticSet::first()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ m_aSetIter = m_aSet.begin()+1;
+ if(m_aSetIter == m_aSet.end() && !fetchRow())
+ m_aSetIter = m_aSet.end();
+
+ return m_aSetIter != m_aSet.end();
+}
+
+bool OStaticSet::last()
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ fillAllRows();
+ m_aSetIter = m_aSet.end()-1;
+
+ return !isBeforeFirst() && !isAfterLast();
+}
+
+sal_Int32 OStaticSet::getRow( )
+{
+ OSL_ENSURE(!isAfterLast(),"getRow is not allowed when afterlast record!");
+ OSL_ENSURE(!isBeforeFirst(),"getRow is not allowed when beforefirst record!");
+
+ sal_Int32 nPos = m_aSet.size() - (m_aSet.end() - m_aSetIter);
+ OSL_ENSURE(nPos > 0,"RowPos is < 0");
+ return nPos;
+}
+
+bool OStaticSet::absolute( sal_Int32 row )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+ OSL_ENSURE(row,"OStaticSet::absolute: INVALID row number!");
+ // if row greater 0 than count from end - row means last
+ if(row < 0)
+ {
+ if(!m_bEnd)
+ fillAllRows();
+
+ sal_Int32 nRow = getRow();
+ nRow += row;
+ if(nRow <= static_cast<sal_Int32>(m_aSet.size()))
+ m_aSetIter = m_aSet.begin() + nRow;
+ else
+ m_aSetIter = m_aSet.begin();
+ }
+ else if(row > 0)
+ {
+ if(o3tl::make_unsigned(row) >= m_aSet.size())
+ {
+ if(!m_bEnd)
+ {
+ bool bNext = true;
+ for(sal_Int32 i=m_aSet.size()-1;i < row && bNext;++i)
+ bNext = fetchRow();
+ }
+
+ if(o3tl::make_unsigned(row) > m_aSet.size())
+ m_aSetIter = m_aSet.end(); // check again
+ else
+ m_aSetIter = m_aSet.begin() + row;
+ }
+ else
+ m_aSetIter = m_aSet.begin() + row;
+ }
+
+ return m_aSetIter != m_aSet.end() && m_aSetIter != m_aSet.begin();
+}
+
+bool OStaticSet::previous( )
+{
+ m_bInserted = m_bUpdated = m_bDeleted = false;
+
+ if(m_aSetIter != m_aSet.begin())
+ --m_aSetIter;
+
+ return m_aSetIter != m_aSet.begin();
+}
+
+void OStaticSet::refreshRow( )
+{
+}
+
+bool OStaticSet::rowUpdated( )
+{
+ return m_bUpdated;
+}
+
+bool OStaticSet::rowInserted( )
+{
+ return m_bInserted;
+}
+
+bool OStaticSet::rowDeleted( )
+{
+ return m_bDeleted;
+}
+
+void OStaticSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable )
+{
+ OCacheSet::insertRow( _rInsertRow,_xTable);
+ if(m_bInserted)
+ {
+ m_aSet.push_back(new ORowVector< ORowSetValue >(*_rInsertRow)); // we don't know where the new row is so we append it to the current rows
+ m_aSetIter = m_aSet.end() - 1;
+ (**m_aSetIter)[0] = (*_rInsertRow)[0] = getBookmark();
+ m_bEnd = false;
+ }
+}
+
+void OStaticSet::deleteRow(const ORowSetRow& _rDeleteRow ,const connectivity::OSQLTable& _xTable )
+{
+ OCacheSet::deleteRow(_rDeleteRow,_xTable);
+ if(m_bDeleted)
+ {
+ ORowSetMatrix::iterator aPos = m_aSet.begin()+(*_rDeleteRow)[0].getInt32();
+ if(aPos == (m_aSet.end()-1))
+ m_aSetIter = m_aSet.end();
+ m_aSet.erase(aPos);
+ }
+}
+
+void OStaticSet::reset(const Reference< XResultSet> &_xDriverSet)
+{
+ OCacheSet::construct(_xDriverSet, m_sRowSetFilter);
+ ORowSetMatrix().swap(m_aSet);
+ m_aSetIter = m_aSet.end();
+ m_bEnd = false;
+ m_aSet.emplace_back(nullptr); // this is the beforefirst record
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/StaticSet.hxx b/dbaccess/source/core/api/StaticSet.hxx
new file mode 100644
index 000000000..9f765996b
--- /dev/null
+++ b/dbaccess/source/core/api/StaticSet.hxx
@@ -0,0 +1,75 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "CacheSet.hxx"
+
+namespace dbaccess
+{
+ // is used when nothing is supported by the driver
+ // we use a snapshot
+ class OStaticSet : public OCacheSet
+ {
+ ORowSetMatrix m_aSet;
+ ORowSetMatrix::iterator m_aSetIter;
+ bool m_bEnd;
+ bool fetchRow();
+ void fillAllRows();
+ public:
+ explicit OStaticSet(sal_Int32 i_nMaxRows) : OCacheSet(i_nMaxRows)
+ , m_aSetIter(m_aSet.end())
+ , m_bEnd(false)
+ {
+ m_aSet.push_back(nullptr); // this is the beforefirst record
+ }
+
+ virtual void reset(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet) override;
+
+ virtual void fillValueRow(ORowSetRow& _rRow,sal_Int32 _nPosition) override;
+ // css::sdbcx::XRowLocate
+ virtual css::uno::Any getBookmark() override;
+ virtual bool moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Int32 compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual bool hasOrderedBookmarks( ) override;
+ virtual sal_Int32 hashBookmark( const css::uno::Any& bookmark ) override;
+
+ bool isBeforeFirst( );
+ bool isAfterLast( );
+
+ // css::sdbc::XResultSet
+ virtual bool next() override;
+ virtual void beforeFirst( ) override;
+ virtual void afterLast( ) override;
+ virtual bool first() override;
+ virtual bool last() override;
+ virtual sal_Int32 getRow( ) override;
+ virtual bool absolute( sal_Int32 row ) override;
+ virtual bool previous( ) override;
+ virtual void refreshRow( ) override;
+ virtual bool rowUpdated( ) override;
+ virtual bool rowInserted( ) override;
+ virtual bool rowDeleted( ) override;
+ // css::sdbc::XResultSetUpdate
+ virtual void insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void deleteRow(const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/TableDeco.cxx b/dbaccess/source/core/api/TableDeco.cxx
new file mode 100644
index 000000000..92821750f
--- /dev/null
+++ b/dbaccess/source/core/api/TableDeco.cxx
@@ -0,0 +1,634 @@
+/* -*- 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 <TableDeco.hxx>
+#include <definitioncolumn.hxx>
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+
+#include <comphelper/property.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <ContainerMediator.hxx>
+
+using namespace dbaccess;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+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 ::osl;
+using namespace ::comphelper;
+using namespace ::dbtools;
+using namespace ::cppu;
+
+// ODBTableDecorator
+
+ODBTableDecorator::ODBTableDecorator( const Reference< XConnection >& _rxConnection, const Reference< XColumnsSupplier >& _rxNewTable,
+ const Reference< XNumberFormatsSupplier >& _rxNumberFormats, const Reference< XNameAccess >& _xColumnDefinitions )
+ :OTableDescriptor_BASE(m_aMutex)
+ ,ODataSettings(OTableDescriptor_BASE::rBHelper)
+ ,m_xTable(_rxNewTable)
+ ,m_xColumnDefinitions(_xColumnDefinitions)
+ ,m_xConnection( _rxConnection )
+ ,m_xMetaData( _rxConnection.is() ? _rxConnection->getMetaData() : Reference< XDatabaseMetaData >() )
+ ,m_xNumberFormats( _rxNumberFormats )
+ ,m_nPrivileges(-1)
+{
+ ODataSettings::registerPropertiesFor(this);
+}
+
+ODBTableDecorator::~ODBTableDecorator()
+{
+}
+
+Sequence< sal_Int8 > ODBTableDecorator::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// OComponentHelper
+void SAL_CALL ODBTableDecorator::disposing()
+{
+ OPropertySetHelper::disposing();
+ OTableDescriptor_BASE::disposing();
+
+ MutexGuard aGuard(m_aMutex);
+ m_xTable = nullptr;
+ m_xMetaData = nullptr;
+ m_xColumnDefinitions = nullptr;
+ m_xNumberFormats = nullptr;
+ if ( m_pColumns )
+ m_pColumns->disposing();
+ m_xColumnMediator = nullptr;
+}
+
+sal_Bool SAL_CALL ODBTableDecorator::convertFastPropertyValue(
+ Any & rConvertedValue,
+ Any & rOldValue,
+ sal_Int32 nHandle,
+ const Any& rValue )
+{
+ bool bRet = true;
+ switch(nHandle)
+ {
+ case PROPERTY_ID_PRIVILEGES:
+ case PROPERTY_ID_FILTER:
+ case PROPERTY_ID_ORDER:
+ case PROPERTY_ID_APPLYFILTER:
+ case PROPERTY_ID_FONT:
+ case PROPERTY_ID_ROW_HEIGHT:
+ case PROPERTY_ID_AUTOGROW:
+ case PROPERTY_ID_TEXTCOLOR:
+ case PROPERTY_ID_TEXTLINECOLOR:
+ case PROPERTY_ID_TEXTEMPHASIS:
+ case PROPERTY_ID_TEXTRELIEF:
+ case PROPERTY_ID_FONTCHARWIDTH:
+ case PROPERTY_ID_FONTCHARSET:
+ case PROPERTY_ID_FONTFAMILY:
+ case PROPERTY_ID_FONTHEIGHT:
+ case PROPERTY_ID_FONTKERNING:
+ case PROPERTY_ID_FONTNAME:
+ case PROPERTY_ID_FONTORIENTATION:
+ case PROPERTY_ID_FONTPITCH:
+ case PROPERTY_ID_FONTSLANT:
+ case PROPERTY_ID_FONTSTRIKEOUT:
+ case PROPERTY_ID_FONTSTYLENAME:
+ case PROPERTY_ID_FONTUNDERLINE:
+ case PROPERTY_ID_FONTWEIGHT:
+ case PROPERTY_ID_FONTWIDTH:
+ case PROPERTY_ID_FONTWORDLINEMODE:
+ case PROPERTY_ID_FONTTYPE:
+ bRet = ODataSettings::convertFastPropertyValue(rConvertedValue, rOldValue,nHandle,rValue);
+ break;
+
+ default:
+ {
+ Any aValue;
+ getFastPropertyValue(aValue,nHandle);
+ bRet = ::comphelper::tryPropertyValue(rConvertedValue,rOldValue,rValue,aValue,::cppu::UnoType<OUString>::get());
+ }
+ break; // we assume that it works
+ }
+ return bRet;
+}
+
+void ODBTableDecorator::setFastPropertyValue_NoBroadcast(sal_Int32 _nHandle, const Any& _rValue)
+{
+ switch(_nHandle)
+ {
+ case PROPERTY_ID_PRIVILEGES:
+ SAL_WARN("dbaccess", "Property is readonly!");
+ [[fallthrough]];
+ case PROPERTY_ID_FILTER:
+ case PROPERTY_ID_ORDER:
+ case PROPERTY_ID_APPLYFILTER:
+ case PROPERTY_ID_FONT:
+ case PROPERTY_ID_ROW_HEIGHT:
+ case PROPERTY_ID_AUTOGROW:
+ case PROPERTY_ID_TEXTCOLOR:
+ case PROPERTY_ID_TEXTLINECOLOR:
+ case PROPERTY_ID_TEXTEMPHASIS:
+ case PROPERTY_ID_TEXTRELIEF:
+ case PROPERTY_ID_FONTCHARWIDTH:
+ case PROPERTY_ID_FONTCHARSET:
+ case PROPERTY_ID_FONTFAMILY:
+ case PROPERTY_ID_FONTHEIGHT:
+ case PROPERTY_ID_FONTKERNING:
+ case PROPERTY_ID_FONTNAME:
+ case PROPERTY_ID_FONTORIENTATION:
+ case PROPERTY_ID_FONTPITCH:
+ case PROPERTY_ID_FONTSLANT:
+ case PROPERTY_ID_FONTSTRIKEOUT:
+ case PROPERTY_ID_FONTSTYLENAME:
+ case PROPERTY_ID_FONTUNDERLINE:
+ case PROPERTY_ID_FONTWEIGHT:
+ case PROPERTY_ID_FONTWIDTH:
+ case PROPERTY_ID_FONTWORDLINEMODE:
+ case PROPERTY_ID_FONTTYPE:
+
+ ODataSettings::setFastPropertyValue_NoBroadcast(_nHandle, _rValue);
+ break;
+ case PROPERTY_ID_CATALOGNAME:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ xProp->setPropertyValue(PROPERTY_CATALOGNAME,_rValue);
+ }
+ break;
+ case PROPERTY_ID_SCHEMANAME:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ xProp->setPropertyValue(PROPERTY_SCHEMANAME,_rValue);
+ }
+ break;
+ case PROPERTY_ID_NAME:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ xProp->setPropertyValue(PROPERTY_NAME,_rValue);
+ }
+ break;
+ case PROPERTY_ID_DESCRIPTION:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ xProp->setPropertyValue(PROPERTY_DESCRIPTION,_rValue);
+ }
+ break;
+ case PROPERTY_ID_TYPE:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ xProp->setPropertyValue(PROPERTY_TYPE,_rValue);
+ }
+ break;
+ }
+}
+
+void ODBTableDecorator::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const
+{
+
+ switch(_nHandle)
+ {
+ case PROPERTY_ID_PRIVILEGES:
+ {
+ if ( -1 == m_nPrivileges )
+ fillPrivileges();
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ Reference<XPropertySetInfo> xInfo = xProp->getPropertySetInfo();
+ if ( xInfo->hasPropertyByName(PROPERTY_PRIVILEGES) )
+ {
+ _rValue <<= m_nPrivileges;
+ break;
+ }
+ }
+ [[fallthrough]];
+
+ case PROPERTY_ID_FILTER:
+ case PROPERTY_ID_ORDER:
+ case PROPERTY_ID_APPLYFILTER:
+ case PROPERTY_ID_FONT:
+ case PROPERTY_ID_ROW_HEIGHT:
+ case PROPERTY_ID_AUTOGROW:
+ case PROPERTY_ID_TEXTCOLOR:
+ case PROPERTY_ID_TEXTLINECOLOR:
+ case PROPERTY_ID_TEXTEMPHASIS:
+ case PROPERTY_ID_TEXTRELIEF:
+ case PROPERTY_ID_FONTCHARWIDTH:
+ case PROPERTY_ID_FONTCHARSET:
+ case PROPERTY_ID_FONTFAMILY:
+ case PROPERTY_ID_FONTHEIGHT:
+ case PROPERTY_ID_FONTKERNING:
+ case PROPERTY_ID_FONTNAME:
+ case PROPERTY_ID_FONTORIENTATION:
+ case PROPERTY_ID_FONTPITCH:
+ case PROPERTY_ID_FONTSLANT:
+ case PROPERTY_ID_FONTSTRIKEOUT:
+ case PROPERTY_ID_FONTSTYLENAME:
+ case PROPERTY_ID_FONTUNDERLINE:
+ case PROPERTY_ID_FONTWEIGHT:
+ case PROPERTY_ID_FONTWIDTH:
+ case PROPERTY_ID_FONTWORDLINEMODE:
+ case PROPERTY_ID_FONTTYPE:
+ ODataSettings::getFastPropertyValue(_rValue, _nHandle);
+ break;
+ case PROPERTY_ID_CATALOGNAME:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ _rValue = xProp->getPropertyValue(PROPERTY_CATALOGNAME);
+ }
+ break;
+ case PROPERTY_ID_SCHEMANAME:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ _rValue = xProp->getPropertyValue(PROPERTY_SCHEMANAME);
+ }
+ break;
+ case PROPERTY_ID_NAME:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ _rValue = xProp->getPropertyValue(PROPERTY_NAME);
+ }
+ break;
+ case PROPERTY_ID_DESCRIPTION:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ _rValue = xProp->getPropertyValue(PROPERTY_DESCRIPTION);
+ }
+ break;
+ case PROPERTY_ID_TYPE:
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ _rValue = xProp->getPropertyValue(PROPERTY_TYPE);
+ }
+ break;
+ default:
+ SAL_WARN("dbaccess", "Invalid Handle for table");
+ }
+}
+
+void ODBTableDecorator::construct()
+{
+ bool bNotFound = true;
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ if ( xProp.is() )
+ {
+ Reference<XPropertySetInfo> xInfo = xProp->getPropertySetInfo();
+ bNotFound = !xInfo->hasPropertyByName(PROPERTY_PRIVILEGES);
+ }
+ if ( bNotFound )
+ registerProperty(PROPERTY_PRIVILEGES, PROPERTY_ID_PRIVILEGES, PropertyAttribute::BOUND | PropertyAttribute::READONLY,
+ &m_nPrivileges, ::cppu::UnoType<sal_Int32>::get());
+}
+
+::cppu::IPropertyArrayHelper* ODBTableDecorator::createArrayHelper(sal_Int32 /*_nId*/) const
+{
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ Reference<XPropertySetInfo> xInfo = xProp->getPropertySetInfo();
+
+ Sequence< Property > aTableProps = xInfo->getProperties();
+ for (Property & prop : asNonConstRange(aTableProps))
+ {
+ if (prop.Name == PROPERTY_CATALOGNAME)
+ prop.Handle = PROPERTY_ID_CATALOGNAME;
+ else if (prop.Name == PROPERTY_SCHEMANAME)
+ prop.Handle = PROPERTY_ID_SCHEMANAME;
+ else if (prop.Name == PROPERTY_NAME)
+ prop.Handle = PROPERTY_ID_NAME;
+ else if (prop.Name == PROPERTY_DESCRIPTION)
+ prop.Handle = PROPERTY_ID_DESCRIPTION;
+ else if (prop.Name == PROPERTY_TYPE)
+ prop.Handle = PROPERTY_ID_TYPE;
+ else if (prop.Name == PROPERTY_PRIVILEGES)
+ prop.Handle = PROPERTY_ID_PRIVILEGES;
+ }
+
+ describeProperties(aTableProps);
+
+ return new ::cppu::OPropertyArrayHelper(aTableProps);
+}
+
+::cppu::IPropertyArrayHelper & SAL_CALL ODBTableDecorator::getInfoHelper()
+{
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+
+ Reference<XPropertySetInfo> xInfo = xProp->getPropertySetInfo();
+ bool bIsDescriptor = (xInfo->getPropertyByName(PROPERTY_NAME).Attributes & PropertyAttribute::READONLY) == 0;
+
+ return *ODBTableDecorator_PROP::getArrayHelper( bIsDescriptor ? 0 : 1 );
+
+ // TODO: this is a HACK, and prone to errors
+ // The OIdPropertyArrayUsageHelper is intended for classes where there exists a known, limited
+ // number of different property set infos (distinguished by the ID), all implemented by this very
+ // same class.
+ // However, in this case here we have an unknown, potentially unlimited number of different
+ // property set infos: Depending on the table for which we act as decorator, different property
+ // sets might exist.
+}
+
+// XServiceInfo
+OUString SAL_CALL ODBTableDecorator::getImplementationName()
+ {
+ return "com.sun.star.sdb.dbaccess.ODBTableDecorator";
+ }
+sal_Bool SAL_CALL ODBTableDecorator::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL ODBTableDecorator::getSupportedServiceNames()
+{
+ return { SERVICE_SDBCX_TABLE };
+}
+
+
+Any SAL_CALL ODBTableDecorator::queryInterface( const Type & rType )
+{
+ Any aRet;
+ if(m_xTable.is())
+ {
+ aRet = m_xTable->queryInterface(rType);
+ if(aRet.hasValue())
+ { // now we know that our table supports this type so we return ourself
+ aRet = OTableDescriptor_BASE::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = ODataSettings::queryInterface(rType);
+ }
+ }
+
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL ODBTableDecorator::getTypes( )
+{
+ Reference<XTypeProvider> xTypes(m_xTable,UNO_QUERY);
+ OSL_ENSURE(xTypes.is(),"Table must be a TypeProvider!");
+ return xTypes->getTypes();
+}
+
+// XRename,
+void SAL_CALL ODBTableDecorator::rename( const OUString& _rNewName )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+ Reference<XRename> xRename(m_xTable,UNO_QUERY);
+ if(!xRename.is())
+ throw SQLException(DBA_RES(RID_STR_NO_TABLE_RENAME),*this,SQLSTATE_GENERAL,1000,Any() );
+ // not supported
+ xRename->rename(_rNewName);
+}
+
+// XAlterTable,
+void SAL_CALL ODBTableDecorator::alterColumnByName( const OUString& _rName, const Reference< XPropertySet >& _rxDescriptor )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+ Reference<XAlterTable> xAlter(m_xTable,UNO_QUERY);
+ if(!xAlter.is())
+ throw SQLException(DBA_RES(RID_STR_COLUMN_ALTER_BY_NAME),*this,SQLSTATE_GENERAL,1000,Any() );
+ xAlter->alterColumnByName(_rName,_rxDescriptor);
+ if(m_pColumns)
+ m_pColumns->refresh();
+}
+
+void SAL_CALL ODBTableDecorator::alterColumnByIndex( sal_Int32 _nIndex, const Reference< XPropertySet >& _rxDescriptor )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+ Reference<XAlterTable> xAlter(m_xTable,UNO_QUERY);
+ if(!xAlter.is())
+ throw SQLException(DBA_RES(RID_STR_COLUMN_ALTER_BY_INDEX),*this,SQLSTATE_GENERAL,1000,Any() );
+ // not supported
+ xAlter->alterColumnByIndex(_nIndex,_rxDescriptor);
+ if(m_pColumns)
+ m_pColumns->refresh();
+}
+
+Reference< XNameAccess> ODBTableDecorator::getIndexes()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+ return Reference< XIndexesSupplier>(m_xTable,UNO_QUERY_THROW)->getIndexes();
+}
+
+Reference< XIndexAccess> ODBTableDecorator::getKeys()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+ return Reference< XKeysSupplier>(m_xTable,UNO_QUERY_THROW)->getKeys();
+}
+
+Reference< XNameAccess> ODBTableDecorator::getColumns()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+ if(!m_pColumns)
+ refreshColumns();
+
+ return m_pColumns.get();
+}
+
+OUString SAL_CALL ODBTableDecorator::getName()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+ Reference<XNamed> xName(m_xTable,UNO_QUERY);
+ OSL_ENSURE(xName.is(),"Table should support the XNamed interface");
+ return xName->getName();
+}
+
+sal_Int64 SAL_CALL ODBTableDecorator::getSomething( const Sequence< sal_Int8 >& rId )
+{
+ if (comphelper::isUnoTunnelId<ODBTableDecorator>(rId))
+ return comphelper::getSomething_cast(this);
+
+ sal_Int64 nRet = 0;
+ Reference<XUnoTunnel> xTunnel(m_xTable,UNO_QUERY);
+ if(xTunnel.is())
+ nRet = xTunnel->getSomething(rId);
+ return nRet;
+}
+
+const Sequence< sal_Int8 > & ODBTableDecorator::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+void ODBTableDecorator::fillPrivileges() const
+{
+ // somebody is asking for the privileges and we do not know them, yet
+ m_nPrivileges = 0;
+ try
+ {
+ Reference<XPropertySet> xProp(m_xTable,UNO_QUERY);
+ if ( xProp.is() )
+ {
+ if ( xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_PRIVILEGES) )
+ {
+ xProp->getPropertyValue(PROPERTY_PRIVILEGES) >>= m_nPrivileges;
+ }
+ if ( m_nPrivileges == 0 ) // second chance
+ {
+ OUString sCatalog,sSchema,sName;
+ xProp->getPropertyValue(PROPERTY_CATALOGNAME) >>= sCatalog;
+ xProp->getPropertyValue(PROPERTY_SCHEMANAME) >>= sSchema;
+ xProp->getPropertyValue(PROPERTY_NAME) >>= sName;
+ m_nPrivileges = ::dbtools::getTablePrivileges(m_xMetaData, sCatalog,sSchema, sName);
+ }
+ }
+ }
+ catch(const SQLException&)
+ {
+ SAL_WARN("dbaccess", "ODBTableDecorator::ODBTableDecorator : could not collect the privileges !");
+ }
+}
+
+Reference< XPropertySet > SAL_CALL ODBTableDecorator::createDataDescriptor( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+ Reference< XDataDescriptorFactory > xFactory( m_xTable, UNO_QUERY );
+ OSL_ENSURE( xFactory.is(), "ODBTableDecorator::createDataDescriptor: invalid table!" );
+ Reference< XColumnsSupplier > xColsSupp;
+ if ( xFactory.is() )
+ xColsSupp.set(xFactory->createDataDescriptor(), css::uno::UNO_QUERY);
+
+ return new ODBTableDecorator(
+ m_xConnection,
+ xColsSupp,
+ m_xNumberFormats,
+ nullptr
+ );
+}
+
+Reference< css::beans::XPropertySetInfo > SAL_CALL ODBTableDecorator::getPropertySetInfo( )
+{
+ return ::cppu::OPropertySetHelper::createPropertySetInfo(getInfoHelper());
+}
+
+void ODBTableDecorator::refreshColumns()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OTableDescriptor_BASE::rBHelper.bDisposed);
+
+ std::vector< OUString> aVector;
+
+ Reference<XNameAccess> xNames;
+ if(m_xTable.is())
+ {
+ xNames = m_xTable->getColumns();
+ if(xNames.is())
+ {
+ const Sequence< OUString> aNames = xNames->getElementNames();
+ aVector.insert(aVector.end(), aNames.begin(), aNames.end());
+ }
+ }
+ if(!m_pColumns)
+ {
+ OColumns* pCol = new OColumns(*this,m_aMutex,xNames,m_xMetaData.is() && m_xMetaData->supportsMixedCaseQuotedIdentifiers(),aVector,
+ this,this,
+ m_xMetaData.is() && m_xMetaData->supportsAlterTableWithAddColumn(),
+ m_xMetaData.is() && m_xMetaData->supportsAlterTableWithDropColumn());
+
+ pCol->setParent(*this);
+ rtl::Reference<OContainerMediator> pMediator = new OContainerMediator( pCol, m_xColumnDefinitions );
+ m_xColumnMediator = pMediator;
+ pCol->setMediator( pMediator.get() );
+ m_pColumns.reset(pCol);
+ }
+ else
+ m_pColumns->reFill(aVector);
+}
+
+rtl::Reference<OColumn> ODBTableDecorator::createColumn(const OUString& _rName) const
+{
+ rtl::Reference<OColumn> pReturn;
+
+ Reference<XNameAccess> xNames;
+ if ( m_xTable.is() )
+ {
+ xNames = m_xTable->getColumns();
+
+ if ( xNames.is() && xNames->hasByName(_rName) )
+ {
+ Reference<XPropertySet> xProp(xNames->getByName(_rName),UNO_QUERY);
+
+ Reference<XPropertySet> xColumnDefinition;
+ if ( m_xColumnDefinitions.is() && m_xColumnDefinitions->hasByName(_rName))
+ xColumnDefinition.set(m_xColumnDefinitions->getByName(_rName),UNO_QUERY);
+
+ pReturn = new OTableColumnWrapper( xProp, xColumnDefinition, false );
+ }
+ }
+ return pReturn;
+}
+
+void ODBTableDecorator::columnAppended( const Reference< XPropertySet >& /*_rxSourceDescriptor*/ )
+{
+ // not interested in
+}
+
+void ODBTableDecorator::columnDropped(const OUString& _sName)
+{
+ Reference<XDrop> xDrop(m_xColumnDefinitions,UNO_QUERY);
+ if ( xDrop.is() && m_xColumnDefinitions->hasByName(_sName) )
+ xDrop->dropByName(_sName);
+}
+
+Reference< XPropertySet > ODBTableDecorator::createColumnDescriptor()
+{
+ Reference<XDataDescriptorFactory> xNames;
+ if(m_xTable.is())
+ xNames.set(m_xTable->getColumns(),UNO_QUERY);
+ Reference< XPropertySet > xRet;
+ if ( xNames.is() )
+ xRet = new OTableColumnDescriptorWrapper( xNames->createDataDescriptor(), false, true );
+ return xRet;
+}
+
+void SAL_CALL ODBTableDecorator::acquire() noexcept
+{
+ OTableDescriptor_BASE::acquire();
+}
+
+void SAL_CALL ODBTableDecorator::release() noexcept
+{
+ OTableDescriptor_BASE::release();
+}
+
+void SAL_CALL ODBTableDecorator::setName( const OUString& /*aName*/ )
+{
+ throwFunctionNotSupportedRuntimeException( "XNamed::setName", *this );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/View.cxx b/dbaccess/source/core/api/View.cxx
new file mode 100644
index 000000000..c52c4885c
--- /dev/null
+++ b/dbaccess/source/core/api/View.cxx
@@ -0,0 +1,120 @@
+/* -*- 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 <View.hxx>
+#include <strings.hxx>
+
+#include <connectivity/dbtools.hxx>
+
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+
+#include <tools/diagnose_ex.h>
+
+namespace dbaccess
+{
+
+ using namespace ::com::sun::star::uno;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::lang::XMultiServiceFactory;
+
+ static OUString lcl_getServiceNameForSetting(const Reference< css::sdbc::XConnection >& _xConnection,const OUString& i_sSetting)
+ {
+ OUString sSupportService;
+ Any aValue;
+ if ( dbtools::getDataSourceSetting(_xConnection,i_sSetting,aValue) )
+ {
+ aValue >>= sSupportService;
+ }
+ return sSupportService;
+ }
+ // View
+ View::View( const Reference< XConnection >& _rxConnection, bool _bCaseSensitive,
+ const OUString& _rCatalogName,const OUString& _rSchemaName, const OUString& _rName )
+ :View_Base( _bCaseSensitive, _rName, _rxConnection->getMetaData(), OUString(), _rSchemaName, _rCatalogName )
+ {
+ m_nCommandHandle = getProperty(PROPERTY_COMMAND).Handle;
+ try
+ {
+ Reference<XMultiServiceFactory> xFac(_rxConnection,UNO_QUERY_THROW);
+ m_xViewAccess.set(xFac->createInstance(lcl_getServiceNameForSetting(_rxConnection,"ViewAccessServiceName")),UNO_QUERY);
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ View::~View()
+ {
+ }
+
+ IMPLEMENT_FORWARD_REFCOUNT( View, View_Base )
+ IMPLEMENT_GET_IMPLEMENTATION_ID( View )
+
+ Any SAL_CALL View::queryInterface( const Type & _rType )
+ {
+ if(_rType == cppu::UnoType<XAlterView>::get()&& !m_xViewAccess.is() )
+ return Any();
+ Any aReturn = View_Base::queryInterface( _rType );
+ if ( !aReturn.hasValue() )
+ aReturn = View_IBASE::queryInterface( _rType );
+ return aReturn;
+ }
+
+ Sequence< Type > SAL_CALL View::getTypes( )
+ {
+ Type aAlterType = cppu::UnoType<XAlterView>::get();
+
+ Sequence< Type > aTypes( ::comphelper::concatSequences(View_Base::getTypes(),View_IBASE::getTypes()) );
+ std::vector<Type> aOwnTypes;
+ aOwnTypes.reserve(aTypes.getLength());
+
+ const Type* pIter = aTypes.getConstArray();
+ const Type* pEnd = pIter + aTypes.getLength();
+ for(;pIter != pEnd ;++pIter)
+ {
+ if( *pIter != aAlterType || m_xViewAccess.is() )
+ aOwnTypes.push_back(*pIter);
+ }
+
+ return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size());
+ }
+
+ void SAL_CALL View::alterCommand( const OUString& _rNewCommand )
+ {
+ OSL_ENSURE(m_xViewAccess.is(),"Illegal call to AlterView!");
+ m_xViewAccess->alterCommand(this,_rNewCommand);
+ }
+
+ void SAL_CALL View::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
+ {
+ if ( _nHandle == m_nCommandHandle && m_xViewAccess.is() )
+ {
+ // retrieve the very current command, don't rely on the base classes cached value
+ // (which we initialized empty, anyway)
+ _rValue <<= m_xViewAccess->getCommand(const_cast<View*>(this));
+ return;
+ }
+
+ View_Base::getFastPropertyValue( _rValue, _nHandle );
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/WrappedResultSet.cxx b/dbaccess/source/core/api/WrappedResultSet.cxx
new file mode 100644
index 000000000..09d70826b
--- /dev/null
+++ b/dbaccess/source/core/api/WrappedResultSet.cxx
@@ -0,0 +1,184 @@
+/* -*- 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 "WrappedResultSet.hxx"
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+
+using namespace dbaccess;
+using namespace ::connectivity;
+using namespace ::com::sun::star::uno;
+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::lang;
+using namespace ::osl;
+
+void WrappedResultSet::construct(const Reference< XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter)
+{
+ OCacheSet::construct(_xDriverSet,i_sRowSetFilter);
+ m_xUpd.set(_xDriverSet,UNO_QUERY_THROW);
+ m_xRowLocate.set(_xDriverSet,UNO_QUERY_THROW);
+ m_xUpdRow.set(_xDriverSet,UNO_QUERY_THROW);
+}
+
+void WrappedResultSet::reset(const Reference< XResultSet>& _xDriverSet)
+{
+ construct(_xDriverSet, m_sRowSetFilter);
+}
+
+Any WrappedResultSet::getBookmark()
+{
+ if ( m_xRowLocate.is() )
+ {
+ return m_xRowLocate->getBookmark( );
+ }
+ return Any(m_xDriverSet->getRow());
+}
+
+bool WrappedResultSet::moveToBookmark( const Any& bookmark )
+{
+ return m_xRowLocate->moveToBookmark( bookmark );
+}
+
+sal_Int32 WrappedResultSet::compareBookmarks( const Any& _first, const Any& _second )
+{
+ return m_xRowLocate->compareBookmarks( _first,_second );
+}
+
+bool WrappedResultSet::hasOrderedBookmarks( )
+{
+ return m_xRowLocate->hasOrderedBookmarks();
+}
+
+sal_Int32 WrappedResultSet::hashBookmark( const Any& bookmark )
+{
+ return m_xRowLocate->hashBookmark(bookmark);
+}
+
+void WrappedResultSet::insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ m_xUpd->moveToInsertRow();
+ sal_Int32 i = 1;
+ connectivity::ORowVector< ORowSetValue > ::Vector::const_iterator aEnd = _rInsertRow->end();
+ for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->begin()+1;aIter != aEnd;++aIter,++i)
+ {
+ aIter->setSigned(m_aSignedFlags[i-1]);
+ updateColumn(i,m_xUpdRow,*aIter);
+ }
+ m_xUpd->insertRow();
+ (*_rInsertRow->begin()) = getBookmark();
+}
+
+void WrappedResultSet::updateRow(const ORowSetRow& _rInsertRow ,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ sal_Int32 i = 1;
+ connectivity::ORowVector< ORowSetValue > ::Vector::const_iterator aOrgIter = _rOriginalRow->begin()+1;
+ connectivity::ORowVector< ORowSetValue > ::Vector::iterator aEnd = _rInsertRow->end();
+ for(connectivity::ORowVector< ORowSetValue > ::Vector::iterator aIter = _rInsertRow->begin()+1;aIter != aEnd;++aIter,++i,++aOrgIter)
+ {
+ aIter->setSigned(aOrgIter->isSigned());
+ updateColumn(i,m_xUpdRow,*aIter);
+ }
+ m_xUpd->updateRow();
+}
+
+void WrappedResultSet::deleteRow(const ORowSetRow& /*_rDeleteRow*/ ,const connectivity::OSQLTable& /*_xTable*/ )
+{
+ m_xUpd->deleteRow();
+}
+
+void WrappedResultSet::updateColumn(sal_Int32 nPos, const Reference< XRowUpdate >& _xParameter, const ORowSetValue& _rValue)
+{
+ if(!(_rValue.isBound() && _rValue.isModified()))
+ return;
+
+ if(_rValue.isNull())
+ _xParameter->updateNull(nPos);
+ else
+ {
+
+ switch(_rValue.getTypeKind())
+ {
+ case DataType::DECIMAL:
+ case DataType::NUMERIC:
+ _xParameter->updateNumericObject(nPos,_rValue.makeAny(),m_xSetMetaData->getScale(nPos));
+ break;
+ case DataType::CHAR:
+ case DataType::VARCHAR:
+ _xParameter->updateString(nPos,_rValue.getString());
+ break;
+ case DataType::BIGINT:
+ if ( _rValue.isSigned() )
+ _xParameter->updateLong(nPos,_rValue.getLong());
+ else
+ _xParameter->updateString(nPos,_rValue.getString());
+ break;
+ case DataType::BIT:
+ case DataType::BOOLEAN:
+ _xParameter->updateBoolean(nPos,_rValue.getBool());
+ break;
+ case DataType::TINYINT:
+ if ( _rValue.isSigned() )
+ _xParameter->updateByte(nPos,_rValue.getInt8());
+ else
+ _xParameter->updateShort(nPos,_rValue.getInt16());
+ break;
+ case DataType::SMALLINT:
+ if ( _rValue.isSigned() )
+ _xParameter->updateShort(nPos,_rValue.getInt16());
+ else
+ _xParameter->updateInt(nPos,_rValue.getInt32());
+ break;
+ case DataType::INTEGER:
+ if ( _rValue.isSigned() )
+ _xParameter->updateInt(nPos,_rValue.getInt32());
+ else
+ _xParameter->updateLong(nPos,_rValue.getLong());
+ break;
+ case DataType::FLOAT:
+ _xParameter->updateFloat(nPos,_rValue.getFloat());
+ break;
+ case DataType::DOUBLE:
+ case DataType::REAL:
+ _xParameter->updateDouble(nPos,_rValue.getDouble());
+ break;
+ case DataType::DATE:
+ _xParameter->updateDate(nPos,_rValue.getDate());
+ break;
+ case DataType::TIME:
+ _xParameter->updateTime(nPos,_rValue.getTime());
+ break;
+ case DataType::TIMESTAMP:
+ _xParameter->updateTimestamp(nPos,_rValue.getDateTime());
+ break;
+ case DataType::BINARY:
+ case DataType::VARBINARY:
+ case DataType::LONGVARBINARY:
+ _xParameter->updateBytes(nPos,_rValue.getSequence());
+ break;
+ case DataType::BLOB:
+ case DataType::CLOB:
+ _xParameter->updateObject(nPos,_rValue.getAny());
+ break;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/WrappedResultSet.hxx b/dbaccess/source/core/api/WrappedResultSet.hxx
new file mode 100644
index 000000000..58b2d7041
--- /dev/null
+++ b/dbaccess/source/core/api/WrappedResultSet.hxx
@@ -0,0 +1,60 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "CacheSet.hxx"
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+
+namespace dbaccess
+{
+ // this set is used when we have a bookmarkable set from the driver
+ class WrappedResultSet : public OCacheSet
+ {
+ css::uno::Reference< css::sdbcx::XRowLocate> m_xRowLocate;
+ css::uno::Reference< css::sdbc::XResultSetUpdate> m_xUpd;
+ css::uno::Reference< css::sdbc::XRowUpdate> m_xUpdRow;
+
+ void updateColumn(sal_Int32 nPos, const css::uno::Reference< css::sdbc::XRowUpdate >& _xParameter, const connectivity::ORowSetValue& _rValue);
+ public:
+ explicit WrappedResultSet(sal_Int32 i_nMaxRows) : OCacheSet(i_nMaxRows)
+ {}
+ virtual ~WrappedResultSet() override
+ {
+ m_xRowLocate = nullptr;
+ }
+
+ virtual void construct(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet,const OUString& i_sRowSetFilter) override;
+ virtual void reset(const css::uno::Reference< css::sdbc::XResultSet>& _xDriverSet) override;
+ // css::sdbcx::XRowLocate
+ virtual css::uno::Any getBookmark() override;
+ virtual bool moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Int32 compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual bool hasOrderedBookmarks( ) override;
+ virtual sal_Int32 hashBookmark( const css::uno::Any& bookmark ) override;
+ // css::sdbc::XResultSetUpdate
+ virtual void insertRow( const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void updateRow(const ORowSetRow& _rInsertRow,const ORowSetRow& _rOriginalRow,const connectivity::OSQLTable& _xTable ) override;
+ virtual void deleteRow(const ORowSetRow& _rInsertRow,const connectivity::OSQLTable& _xTable ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/callablestatement.cxx b/dbaccess/source/core/api/callablestatement.cxx
new file mode 100644
index 000000000..8f864fbe0
--- /dev/null
+++ b/dbaccess/source/core/api/callablestatement.cxx
@@ -0,0 +1,250 @@
+/* -*- 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 <callablestatement.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <strings.hxx>
+
+using namespace dbaccess;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::cppu;
+using namespace ::osl;
+
+// css::lang::XTypeProvider
+Sequence< Type > OCallableStatement::getTypes()
+{
+ OTypeCollection aTypes(cppu::UnoType<XRow>::get(),
+ cppu::UnoType<XOutParameters>::get(),
+ OPreparedStatement::getTypes() );
+
+ return aTypes.getTypes();
+}
+
+Sequence< sal_Int8 > OCallableStatement::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// css::uno::XInterface
+Any OCallableStatement::queryInterface( const Type & rType )
+{
+ Any aIface = OPreparedStatement::queryInterface( rType );
+ if (!aIface.hasValue())
+ aIface = ::cppu::queryInterface(
+ rType,
+ static_cast< XRow * >( this ),
+ static_cast< XOutParameters * >( this ));
+ return aIface;
+}
+
+void OCallableStatement::acquire() noexcept
+{
+ OPreparedStatement::acquire();
+}
+
+void OCallableStatement::release() noexcept
+{
+ OPreparedStatement::release();
+}
+
+// XServiceInfo
+OUString OCallableStatement::getImplementationName( )
+{
+ return "com.sun.star.sdb.OCallableStatement";
+}
+
+Sequence< OUString > OCallableStatement::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBC_CALLABLESTATEMENT, SERVICE_SDB_CALLABLESTATEMENT };
+}
+
+// XOutParameters
+void SAL_CALL OCallableStatement::registerOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ Reference< XOutParameters >(m_xAggregateAsSet, UNO_QUERY_THROW)->registerOutParameter( parameterIndex, sqlType, typeName );
+}
+
+void SAL_CALL OCallableStatement::registerNumericOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, sal_Int32 scale )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ Reference< XOutParameters >(m_xAggregateAsSet, UNO_QUERY_THROW)->registerNumericOutParameter( parameterIndex, sqlType, scale );
+}
+
+// XRow
+sal_Bool SAL_CALL OCallableStatement::wasNull( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->wasNull();
+}
+
+OUString SAL_CALL OCallableStatement::getString( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getString( columnIndex );
+}
+
+sal_Bool SAL_CALL OCallableStatement::getBoolean( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getBoolean( columnIndex );
+}
+
+sal_Int8 SAL_CALL OCallableStatement::getByte( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getByte( columnIndex );
+}
+
+sal_Int16 SAL_CALL OCallableStatement::getShort( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getShort( columnIndex );
+}
+
+sal_Int32 SAL_CALL OCallableStatement::getInt( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getInt( columnIndex );
+}
+
+sal_Int64 SAL_CALL OCallableStatement::getLong( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getLong( columnIndex );
+}
+
+float SAL_CALL OCallableStatement::getFloat( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getFloat( columnIndex );
+}
+
+double SAL_CALL OCallableStatement::getDouble( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getDouble( columnIndex );
+}
+
+Sequence< sal_Int8 > SAL_CALL OCallableStatement::getBytes( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getBytes( columnIndex );
+}
+
+css::util::Date SAL_CALL OCallableStatement::getDate( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getDate( columnIndex );
+}
+
+css::util::Time SAL_CALL OCallableStatement::getTime( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getTime( columnIndex );
+}
+
+css::util::DateTime SAL_CALL OCallableStatement::getTimestamp( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getTimestamp( columnIndex );
+}
+
+Reference< css::io::XInputStream > SAL_CALL OCallableStatement::getBinaryStream( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getBinaryStream( columnIndex );
+}
+
+Reference< css::io::XInputStream > SAL_CALL OCallableStatement::getCharacterStream( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getCharacterStream( columnIndex );
+}
+
+Any SAL_CALL OCallableStatement::getObject( sal_Int32 columnIndex, const Reference< css::container::XNameAccess >& typeMap )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getObject( columnIndex, typeMap );
+}
+
+Reference< XRef > SAL_CALL OCallableStatement::getRef( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getRef( columnIndex );
+}
+
+Reference< XBlob > SAL_CALL OCallableStatement::getBlob( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getBlob( columnIndex );
+}
+
+Reference< XClob > SAL_CALL OCallableStatement::getClob( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getClob( columnIndex );
+}
+
+Reference< XArray > SAL_CALL OCallableStatement::getArray( sal_Int32 columnIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XRow >(m_xAggregateAsSet, UNO_QUERY_THROW)->getArray( columnIndex );
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/column.cxx b/dbaccess/source/core/api/column.cxx
new file mode 100644
index 000000000..5bc70affb
--- /dev/null
+++ b/dbaccess/source/core/api/column.cxx
@@ -0,0 +1,411 @@
+/* -*- 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 <ContainerMediator.hxx>
+#include <column.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <stringconstants.hxx>
+#include <sdbcoretools.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdb/tools/XTableAlteration.hpp>
+
+#include <comphelper/sequence.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/uno3.hxx>
+#include <connectivity/TTableHelper.hxx>
+#include <connectivity/dbexception.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <osl/diagnose.h>
+
+using namespace dbaccess;
+using namespace connectivity;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+
+// OColumn
+OColumn::OColumn( const bool _bNameIsReadOnly )
+ :OColumnBase( m_aMutex )
+ ,::comphelper::OPropertyContainer( OColumnBase::rBHelper )
+{
+
+ registerProperty( PROPERTY_NAME, PROPERTY_ID_NAME, _bNameIsReadOnly ? PropertyAttribute::READONLY : 0,
+ &m_sName, cppu::UnoType<decltype(m_sName)>::get() );
+}
+
+OColumn::~OColumn()
+{
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > OColumn::getTypes()
+{
+ return ::comphelper::concatSequences(
+ OColumnBase::getTypes(),
+ getBaseTypes()
+ );
+}
+
+// css::uno::XInterface
+IMPLEMENT_FORWARD_XINTERFACE2( OColumn, OColumnBase, ::comphelper::OPropertyContainer )
+
+// css::lang::XServiceInfo
+OUString OColumn::getImplementationName( )
+{
+ return "com.sun.star.sdb.OColumn";
+}
+
+sal_Bool OColumn::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > OColumn::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBCX_COLUMN };
+}
+
+// OComponentHelper
+void OColumn::disposing()
+{
+ OPropertyContainer::disposing();
+}
+
+// css::beans::XPropertySet
+Reference< XPropertySetInfo > OColumn::getPropertySetInfo()
+{
+ return createPropertySetInfo( getInfoHelper() ) ;
+}
+
+OUString SAL_CALL OColumn::getName( )
+{
+ return m_sName;
+}
+
+void SAL_CALL OColumn::setName( const OUString& _rName )
+{
+ m_sName = _rName;
+}
+
+void OColumn::registerProperty( const OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes, void* _pPointerToMember, const Type& _rMemberType )
+{
+ ::comphelper::OPropertyContainer::registerProperty( _rName, _nHandle, _nAttributes, _pPointerToMember, _rMemberType );
+}
+
+void OColumn::registerMayBeVoidProperty( const OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes, Any* _pPointerToMember, const Type& _rExpectedType )
+{
+ ::comphelper::OPropertyContainer::registerMayBeVoidProperty( _rName, _nHandle, _nAttributes, _pPointerToMember, _rExpectedType );
+}
+
+// OColumns
+
+OColumns::OColumns(::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ bool _bCaseSensitive,const std::vector< OUString> &_rVector,
+ IColumnFactory* _pColFactory,
+ ::connectivity::sdbcx::IRefreshableColumns* _pRefresh,
+ bool _bAddColumn,
+ bool _bDropColumn,
+ bool _bUseHardRef)
+ : OColumns_BASE(_rParent,_bCaseSensitive,_rMutex,_rVector,_bUseHardRef)
+ ,m_pMediator(nullptr)
+ ,m_pColFactoryImpl(_pColFactory)
+ ,m_pRefreshColumns(_pRefresh)
+ ,m_bInitialized(false)
+ ,m_bAddColumn(_bAddColumn)
+ ,m_bDropColumn(_bDropColumn)
+{
+}
+
+OColumns::OColumns(::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex,
+ const css::uno::Reference< css::container::XNameAccess >& _rxDrvColumns,
+ bool _bCaseSensitive,const std::vector< OUString> &_rVector,
+ IColumnFactory* _pColFactory,
+ ::connectivity::sdbcx::IRefreshableColumns* _pRefresh,
+ bool _bAddColumn,
+ bool _bDropColumn,
+ bool _bUseHardRef)
+ : OColumns_BASE(_rParent,_bCaseSensitive,_rMutex,_rVector,_bUseHardRef)
+ ,m_pMediator(nullptr)
+ ,m_xDrvColumns(_rxDrvColumns)
+ ,m_pColFactoryImpl(_pColFactory)
+ ,m_pRefreshColumns(_pRefresh)
+ ,m_bInitialized(false)
+ ,m_bAddColumn(_bAddColumn)
+ ,m_bDropColumn(_bDropColumn)
+{
+}
+
+OColumns::~OColumns()
+{
+}
+
+// XServiceInfo
+OUString OColumns::getImplementationName( )
+{
+ return "com.sun.star.sdb.OColumns";
+}
+
+sal_Bool OColumns::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > OColumns::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBCX_CONTAINER };
+}
+
+void OColumns::append( const OUString& _rName, OColumn* _pColumn )
+{
+ MutexGuard aGuard(m_rMutex);
+
+ OSL_ENSURE( _pColumn, "OColumns::append: invalid column!" );
+ OSL_ENSURE( !m_pElements->exists( _rName ),"OColumns::append: Column already exists");
+
+ _pColumn->m_sName = _rName;
+
+ // now really insert the column
+ insertElement( _rName, _pColumn );
+}
+
+void OColumns::clearColumns()
+{
+ MutexGuard aGuard(m_rMutex);
+ disposing();
+}
+
+void OColumns::disposing()
+{
+ MutexGuard aGuard(m_rMutex);
+ m_xDrvColumns = nullptr;
+ m_pMediator = nullptr;
+ m_pColFactoryImpl = nullptr;
+ OColumns_BASE::disposing();
+}
+
+void OColumns::impl_refresh()
+{
+ if (m_pRefreshColumns)
+ m_pRefreshColumns->refreshColumns();
+}
+
+connectivity::sdbcx::ObjectType OColumns::createObject(const OUString& _rName)
+{
+ OSL_ENSURE(m_pColFactoryImpl, "OColumns::createObject: no column factory!");
+
+ connectivity::sdbcx::ObjectType xRet;
+ if ( m_pColFactoryImpl )
+ {
+ xRet = m_pColFactoryImpl->createColumn(_rName);
+ Reference<XChild> xChild(xRet,UNO_QUERY);
+ if ( xChild.is() )
+ xChild->setParent(static_cast<XChild*>(static_cast<TXChild*>(this)));
+ }
+
+ Reference<XPropertySet> xDest(xRet,UNO_QUERY);
+ if ( m_pMediator && xDest.is() )
+ m_pMediator->notifyElementCreated(_rName,xDest);
+
+ return xRet;
+}
+
+Reference< XPropertySet > OColumns::createDescriptor()
+{
+ if ( m_pColFactoryImpl )
+ {
+ Reference<XPropertySet> xRet = m_pColFactoryImpl->createColumnDescriptor();
+ Reference<XChild> xChild(xRet,UNO_QUERY);
+ if ( xChild.is() )
+ xChild->setParent(static_cast<XChild*>(static_cast<TXChild*>(this)));
+ return xRet;
+ }
+ else
+ return Reference< XPropertySet >();
+}
+
+Any SAL_CALL OColumns::queryInterface( const Type & rType )
+{
+ Any aRet;
+ if(m_xDrvColumns.is())
+ {
+ aRet = m_xDrvColumns->queryInterface(rType);
+ if ( aRet.hasValue() )
+ aRet = OColumns_BASE::queryInterface( rType);
+ if ( !aRet.hasValue() )
+ aRet = TXChild::queryInterface( rType);
+ return aRet;
+ }
+ else if(!m_pTable || !m_pTable->isNew())
+ {
+ if(!m_bAddColumn && rType == cppu::UnoType<XAppend>::get())
+ return Any();
+ if(!m_bDropColumn && rType == cppu::UnoType<XDrop>::get())
+ return Any();
+ }
+
+ aRet = OColumns_BASE::queryInterface( rType);
+ if ( !aRet.hasValue() )
+ aRet = TXChild::queryInterface( rType);
+ return aRet;
+}
+
+Sequence< Type > SAL_CALL OColumns::getTypes( )
+{
+ bool bAppendFound = false,bDropFound = false;
+
+ sal_Int32 nSize = 0;
+ Type aAppendType = cppu::UnoType<XAppend>::get();
+ Type aDropType = cppu::UnoType<XDrop>::get();
+ if(m_xDrvColumns.is())
+ {
+ Reference<XTypeProvider> xTypes(m_xDrvColumns,UNO_QUERY);
+ Sequence< Type > aTypes(xTypes->getTypes());
+
+ const Type* pBegin = aTypes.getConstArray();
+ const Type* pEnd = pBegin + aTypes.getLength();
+ for (;pBegin != pEnd ; ++pBegin)
+ {
+ if(aAppendType == *pBegin)
+ bAppendFound = true;
+ else if(aDropType == *pBegin)
+ bDropFound = true;
+ }
+ nSize = (bDropFound ? (bAppendFound ? 0 : 1) : (bAppendFound ? 1 : 2));
+ }
+ else
+ {
+ if (m_pTable && m_pTable->isNew())
+ nSize = 0;
+ else if (m_bDropColumn)
+ nSize = m_bAddColumn ? 0 : 1;
+ else
+ nSize = m_bAddColumn ? 1 : 2;
+ bDropFound = (m_pTable && m_pTable->isNew()) || m_bDropColumn;
+ bAppendFound = (m_pTable && m_pTable->isNew()) || m_bAddColumn;
+ }
+ Sequence< Type > aTypes(::comphelper::concatSequences(OColumns_BASE::getTypes(),TXChild::getTypes()));
+ Sequence< Type > aRet(aTypes.getLength() - nSize);
+
+ const Type* pBegin = aTypes.getConstArray();
+ const Type* pEnd = pBegin + aTypes.getLength();
+ for(sal_Int32 i=0;pBegin != pEnd ;++pBegin)
+ {
+ if(*pBegin != aAppendType && *pBegin != aDropType)
+ aRet.getArray()[i++] = *pBegin;
+ else if(bDropFound && *pBegin == aDropType)
+ aRet.getArray()[i++] = *pBegin;
+ else if(bAppendFound && *pBegin == aAppendType)
+ aRet.getArray()[i++] = *pBegin;
+ }
+ return aRet;
+}
+
+// XAppend
+sdbcx::ObjectType OColumns::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ sdbcx::ObjectType xReturn;
+
+ Reference< XAppend > xAppend( m_xDrvColumns, UNO_QUERY );
+ if ( xAppend.is() )
+ {
+ xAppend->appendByDescriptor(descriptor);
+ xReturn = createObject( _rForName );
+ }
+ else if ( m_pTable && !m_pTable->isNew() )
+ {
+ if ( m_bAddColumn )
+ {
+ Reference< css::sdb::tools::XTableAlteration> xAlterService = m_pTable->getAlterService();
+ if ( xAlterService.is() )
+ {
+ xAlterService->addColumn(m_pTable,descriptor);
+ xReturn = createObject( _rForName );
+ }
+ else
+ xReturn = OColumns_BASE::appendObject( _rForName, descriptor );
+ }
+ else
+ ::dbtools::throwGenericSQLException( DBA_RES( RID_STR_NO_COLUMN_ADD ), static_cast<XChild*>(static_cast<TXChild*>(this)) );
+ }
+ else
+ xReturn = cloneDescriptor( descriptor );
+
+ if ( m_pColFactoryImpl )
+ m_pColFactoryImpl->columnAppended( descriptor );
+
+ ::dbaccess::notifyDataSourceModified(m_xParent);
+
+ return xReturn;
+}
+
+// XDrop
+void OColumns::dropObject(sal_Int32 _nPos, const OUString& _sElementName)
+{
+ Reference< XDrop > xDrop( m_xDrvColumns, UNO_QUERY );
+ if ( xDrop.is() )
+ {
+ xDrop->dropByName( _sElementName );
+ }
+ else if ( m_pTable && !m_pTable->isNew() )
+ {
+ if ( m_bDropColumn )
+ {
+ Reference< css::sdb::tools::XTableAlteration> xAlterService = m_pTable->getAlterService();
+ if ( xAlterService.is() )
+ xAlterService->dropColumn(m_pTable,_sElementName);
+ else
+ OColumns_BASE::dropObject(_nPos,_sElementName);
+ }
+ else
+ ::dbtools::throwGenericSQLException( DBA_RES( RID_STR_NO_COLUMN_DROP ), static_cast<XChild*>(static_cast<TXChild*>(this)) );
+ }
+
+ if ( m_pColFactoryImpl )
+ m_pColFactoryImpl->columnDropped(_sElementName);
+
+ ::dbaccess::notifyDataSourceModified(m_xParent);
+}
+
+Reference< XInterface > SAL_CALL OColumns::getParent( )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ return m_xParent;
+}
+
+void SAL_CALL OColumns::setParent( const Reference< XInterface >& _xParent )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ m_xParent = _xParent;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/columnsettings.cxx b/dbaccess/source/core/api/columnsettings.cxx
new file mode 100644
index 000000000..3f62a5a69
--- /dev/null
+++ b/dbaccess/source/core/api/columnsettings.cxx
@@ -0,0 +1,150 @@
+/* -*- 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 <columnsettings.hxx>
+#include <stringconstants.hxx>
+#include <strings.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+#include <comphelper/property.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Type;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::beans::XPropertySetInfo;
+
+ namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
+
+ // OColumnSettings
+
+ OColumnSettings::OColumnSettings()
+ :m_bHidden(false)
+ {
+ }
+
+ OColumnSettings::~OColumnSettings()
+ {
+ }
+
+ void OColumnSettings::registerProperties( IPropertyContainer& _rPropertyContainer )
+ {
+ const sal_Int32 nBoundAttr = PropertyAttribute::BOUND;
+ const sal_Int32 nMayBeVoidAttr = PropertyAttribute::MAYBEVOID | nBoundAttr;
+
+ const Type& rSalInt32Type = ::cppu::UnoType<sal_Int32>::get();
+ const Type& rStringType = ::cppu::UnoType<OUString>::get();
+
+ _rPropertyContainer.registerMayBeVoidProperty( PROPERTY_ALIGN, PROPERTY_ID_ALIGN, nMayBeVoidAttr, &m_aAlignment, rSalInt32Type );
+ _rPropertyContainer.registerMayBeVoidProperty( PROPERTY_NUMBERFORMAT, PROPERTY_ID_NUMBERFORMAT, nMayBeVoidAttr, &m_aFormatKey, rSalInt32Type );
+ _rPropertyContainer.registerMayBeVoidProperty( PROPERTY_RELATIVEPOSITION, PROPERTY_ID_RELATIVEPOSITION, nMayBeVoidAttr, &m_aRelativePosition, rSalInt32Type );
+ _rPropertyContainer.registerMayBeVoidProperty( PROPERTY_WIDTH, PROPERTY_ID_WIDTH, nMayBeVoidAttr, &m_aWidth, rSalInt32Type );
+ _rPropertyContainer.registerMayBeVoidProperty( PROPERTY_HELPTEXT, PROPERTY_ID_HELPTEXT, nMayBeVoidAttr, &m_aHelpText, rStringType );
+ _rPropertyContainer.registerMayBeVoidProperty( PROPERTY_CONTROLDEFAULT, PROPERTY_ID_CONTROLDEFAULT, nMayBeVoidAttr, &m_aControlDefault, rStringType );
+ _rPropertyContainer.registerProperty( PROPERTY_CONTROLMODEL, PROPERTY_ID_CONTROLMODEL, nBoundAttr, &m_xControlModel, cppu::UnoType<decltype(m_xControlModel)>::get() );
+ _rPropertyContainer.registerProperty( PROPERTY_HIDDEN, PROPERTY_ID_HIDDEN, nBoundAttr, &m_bHidden, cppu::UnoType<decltype(m_bHidden)>::get() );
+ }
+
+ bool OColumnSettings::isColumnSettingProperty( const sal_Int32 _nPropertyHandle )
+ {
+ return ( _nPropertyHandle == PROPERTY_ID_ALIGN )
+ || ( _nPropertyHandle == PROPERTY_ID_NUMBERFORMAT )
+ || ( _nPropertyHandle == PROPERTY_ID_RELATIVEPOSITION )
+ || ( _nPropertyHandle == PROPERTY_ID_WIDTH )
+ || ( _nPropertyHandle == PROPERTY_ID_HELPTEXT )
+ || ( _nPropertyHandle == PROPERTY_ID_CONTROLDEFAULT )
+ || ( _nPropertyHandle == PROPERTY_ID_CONTROLMODEL )
+ || ( _nPropertyHandle == PROPERTY_ID_HIDDEN );
+ }
+
+ bool OColumnSettings::isDefaulted( const sal_Int32 _nPropertyHandle, const Any& _rPropertyValue )
+ {
+ switch ( _nPropertyHandle )
+ {
+ case PROPERTY_ID_ALIGN:
+ case PROPERTY_ID_NUMBERFORMAT:
+ case PROPERTY_ID_RELATIVEPOSITION:
+ case PROPERTY_ID_WIDTH:
+ case PROPERTY_ID_HELPTEXT:
+ case PROPERTY_ID_CONTROLDEFAULT:
+ return !_rPropertyValue.hasValue();
+
+ case PROPERTY_ID_CONTROLMODEL:
+ return !Reference< XPropertySet >( _rPropertyValue, UNO_QUERY ).is();
+
+ case PROPERTY_ID_HIDDEN:
+ {
+ bool bHidden = false;
+ OSL_VERIFY( _rPropertyValue >>= bHidden );
+ return !bHidden;
+ }
+ }
+ OSL_FAIL( "OColumnSettings::isDefaulted: illegal property handle!" );
+ return false;
+ }
+
+ bool OColumnSettings::hasDefaultSettings( const Reference< XPropertySet >& _rxColumn )
+ {
+ ENSURE_OR_THROW( _rxColumn.is(), "illegal column" );
+ try
+ {
+ Reference< XPropertySetInfo > xPSI( _rxColumn->getPropertySetInfo(), UNO_SET_THROW );
+
+ struct PropertyDescriptor
+ {
+ OUString sName;
+ sal_Int32 nHandle;
+ };
+ const PropertyDescriptor aProps[] =
+ {
+ { OUString(PROPERTY_ALIGN), PROPERTY_ID_ALIGN },
+ { OUString(PROPERTY_NUMBERFORMAT), PROPERTY_ID_NUMBERFORMAT },
+ { OUString(PROPERTY_RELATIVEPOSITION), PROPERTY_ID_RELATIVEPOSITION },
+ { OUString(PROPERTY_WIDTH), PROPERTY_ID_WIDTH },
+ { OUString(PROPERTY_HELPTEXT), PROPERTY_ID_HELPTEXT },
+ { OUString(PROPERTY_CONTROLDEFAULT), PROPERTY_ID_CONTROLDEFAULT },
+ { OUString(PROPERTY_CONTROLMODEL), PROPERTY_ID_CONTROLMODEL },
+ { OUString(PROPERTY_HIDDEN), PROPERTY_ID_HIDDEN }
+ };
+
+ for (const auto & aProp : aProps)
+ {
+ if ( xPSI->hasPropertyByName( aProp.sName ) )
+ if ( !isDefaulted( aProp.nHandle, _rxColumn->getPropertyValue( aProp.sName ) ) )
+ return false;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return true;
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/datacolumn.cxx b/dbaccess/source/core/api/datacolumn.cxx
new file mode 100644
index 000000000..c597a4064
--- /dev/null
+++ b/dbaccess/source/core/api/datacolumn.cxx
@@ -0,0 +1,396 @@
+/* -*- 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 "datacolumn.hxx"
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <strings.hxx>
+
+using namespace dbaccess;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+
+ODataColumn::ODataColumn(
+ const Reference < XResultSetMetaData >& _xMetaData,
+ const Reference < XRow >& _xRow,
+ const Reference < XRowUpdate >& _xRowUpdate,
+ sal_Int32 _nPos,
+ const Reference< XDatabaseMetaData >& _rxDBMeta)
+ :OResultColumn(_xMetaData, _nPos, _rxDBMeta)
+ ,m_xRow(_xRow)
+ ,m_xRowUpdate(_xRowUpdate)
+{
+}
+
+ODataColumn::~ODataColumn()
+{
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > ODataColumn::getTypes()
+{
+ OTypeCollection aTypes(cppu::UnoType<XColumn>::get(),
+ cppu::UnoType<XColumnUpdate>::get(),
+ OColumn::getTypes());
+ return aTypes.getTypes();
+}
+
+Sequence< sal_Int8 > ODataColumn::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Any SAL_CALL ODataColumn::queryInterface( const Type & _rType )
+{
+ Any aReturn = OResultColumn::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = ::cppu::queryInterface(_rType,
+ static_cast< XColumn* >(this),
+ static_cast< XColumnUpdate* >(this)
+ );
+ return aReturn;
+}
+
+// XServiceInfo
+OUString ODataColumn::getImplementationName( )
+{
+ return "com.sun.star.sdb.ODataColumn";
+}
+
+Sequence< OUString > ODataColumn::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBCX_COLUMN, SERVICE_SDB_RESULTCOLUMN, SERVICE_SDB_DATACOLUMN };
+}
+
+// OComponentHelper
+void ODataColumn::disposing()
+{
+ OResultColumn::disposing();
+
+ m_xRow = nullptr;
+ m_xRowUpdate = nullptr;
+}
+
+// css::sdb::XColumn
+sal_Bool ODataColumn::wasNull()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->wasNull();
+}
+
+OUString ODataColumn::getString()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getString(m_nPos);
+}
+
+sal_Bool ODataColumn::getBoolean()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getBoolean(m_nPos);
+}
+
+sal_Int8 ODataColumn::getByte()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getByte(m_nPos);
+}
+
+sal_Int16 ODataColumn::getShort()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getShort(m_nPos);
+}
+
+sal_Int32 ODataColumn::getInt()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getInt(m_nPos);
+}
+
+sal_Int64 ODataColumn::getLong()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getLong(m_nPos);
+}
+
+float ODataColumn::getFloat()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getFloat(m_nPos);
+}
+
+double ODataColumn::getDouble()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getDouble(m_nPos);
+}
+
+Sequence< sal_Int8 > ODataColumn::getBytes()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getBytes(m_nPos);
+}
+
+css::util::Date ODataColumn::getDate()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getDate(m_nPos);
+}
+
+css::util::Time ODataColumn::getTime()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getTime(m_nPos);
+}
+
+css::util::DateTime ODataColumn::getTimestamp()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getTimestamp(m_nPos);
+}
+
+Reference< css::io::XInputStream > ODataColumn::getBinaryStream()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getBinaryStream(m_nPos);
+}
+
+Reference< css::io::XInputStream > ODataColumn::getCharacterStream()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getCharacterStream(m_nPos);
+}
+
+Any ODataColumn::getObject(const Reference< css::container::XNameAccess > & typeMap)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getObject(m_nPos, typeMap);
+}
+
+Reference< XRef > ODataColumn::getRef()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getRef(m_nPos);
+}
+
+Reference< XBlob > ODataColumn::getBlob()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getBlob(m_nPos);
+}
+
+Reference< XClob > ODataColumn::getClob()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getClob(m_nPos);
+}
+
+Reference< XArray > ODataColumn::getArray()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(!m_xRow.is());
+
+ return m_xRow->getArray(m_nPos);
+}
+
+// css::sdb::XColumnUpdate
+void ODataColumn::updateNull()
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateNull(m_nPos);
+}
+
+void ODataColumn::updateBoolean(sal_Bool x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateBoolean(m_nPos, x);
+}
+
+void ODataColumn::updateByte(sal_Int8 x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateByte(m_nPos, x);
+}
+
+void ODataColumn::updateShort(sal_Int16 x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateShort(m_nPos, x);
+}
+
+void ODataColumn::updateInt(sal_Int32 x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateInt(m_nPos, x);
+}
+
+void ODataColumn::updateLong(sal_Int64 x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateLong(m_nPos, x);
+}
+
+void ODataColumn::updateFloat(float x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateFloat(m_nPos, x);
+}
+
+void ODataColumn::updateDouble(double x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateDouble(m_nPos, x);
+}
+
+void ODataColumn::updateString(const OUString& x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateString(m_nPos, x);
+}
+
+void ODataColumn::updateBytes(const Sequence< sal_Int8 >& x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateBytes(m_nPos, x);
+}
+
+void ODataColumn::updateDate(const css::util::Date& x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateDate(m_nPos, x);
+}
+
+void ODataColumn::updateTime(const css::util::Time& x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateTime(m_nPos, x);
+}
+
+void ODataColumn::updateTimestamp(const css::util::DateTime& x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateTimestamp(m_nPos, x);
+}
+
+void ODataColumn::updateCharacterStream(const Reference< css::io::XInputStream > & x, sal_Int32 length)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateCharacterStream(m_nPos, x, length);
+}
+
+void ODataColumn::updateBinaryStream(const Reference< css::io::XInputStream > & x, sal_Int32 length)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateBinaryStream(m_nPos, x, length);
+}
+
+void ODataColumn::updateNumericObject(const Any& x, sal_Int32 scale)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateNumericObject(m_nPos, x, scale);
+}
+
+void ODataColumn::updateObject(const Any& x)
+{
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(!m_xRowUpdate.is());
+
+ m_xRowUpdate->updateObject(m_nPos, x);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/datacolumn.hxx b/dbaccess/source/core/api/datacolumn.hxx
new file mode 100644
index 000000000..46512d945
--- /dev/null
+++ b/dbaccess/source/core/api/datacolumn.hxx
@@ -0,0 +1,107 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/sdb/XColumn.hpp>
+#include <com/sun/star/sdb/XColumnUpdate.hpp>
+#include "resultcolumn.hxx"
+namespace dbaccess
+{
+
+ // ODataColumn
+
+ class ODataColumn : public OResultColumn,
+ public css::sdb::XColumn,
+ public css::sdb::XColumnUpdate
+ {
+ css::uno::Reference < css::sdbc::XRow > m_xRow;
+ css::uno::Reference < css::sdbc::XRowUpdate > m_xRowUpdate;
+ protected:
+ virtual ~ODataColumn() override;
+ public:
+ ODataColumn (const css::uno::Reference < css::sdbc::XResultSetMetaData >& _xMetaData,
+ const css::uno::Reference < css::sdbc::XRow >& _xRow,
+ const css::uno::Reference < css::sdbc::XRowUpdate >& _xRowUpdate,
+ sal_Int32 _nPos,
+ const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rxDBMeta);
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override { OResultColumn::acquire(); }
+ virtual void SAL_CALL release() noexcept override { OResultColumn::release(); }
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // css::sdb::XColumn
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( ) override;
+ virtual sal_Bool SAL_CALL getBoolean( ) override;
+ virtual sal_Int8 SAL_CALL getByte( ) override;
+ virtual sal_Int16 SAL_CALL getShort( ) override;
+ virtual sal_Int32 SAL_CALL getInt( ) override;
+ virtual sal_Int64 SAL_CALL getLong( ) override;
+ virtual float SAL_CALL getFloat( ) override;
+ virtual double SAL_CALL getDouble( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( ) override;
+ virtual css::util::Date SAL_CALL getDate( ) override;
+ virtual css::util::Time SAL_CALL getTime( ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( ) override;
+ virtual css::uno::Any SAL_CALL getObject( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( ) override;
+
+ // css::sdb::XColumnUpdate
+ virtual void SAL_CALL updateNull( ) override;
+ virtual void SAL_CALL updateBoolean( sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( float x ) override;
+ virtual void SAL_CALL updateDouble( double x ) override;
+ virtual void SAL_CALL updateString( const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( const css::uno::Any& x, sal_Int32 scale ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/datasettings.cxx b/dbaccess/source/core/api/datasettings.cxx
new file mode 100644
index 000000000..e845f1135
--- /dev/null
+++ b/dbaccess/source/core/api/datasettings.cxx
@@ -0,0 +1,191 @@
+/* -*- 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 <datasettings.hxx>
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include <comphelper/types.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/awt/FontEmphasisMark.hpp>
+#include <com/sun/star/awt/FontRelief.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+namespace dbaccess
+{
+// ODataSettings
+void ODataSettings::registerPropertiesFor(ODataSettings_Base* _pItem)
+{
+ if ( m_bQuery )
+ {
+ registerProperty(PROPERTY_HAVING_CLAUSE, PROPERTY_ID_HAVING_CLAUSE, PropertyAttribute::BOUND,
+ &_pItem->m_sHavingClause, cppu::UnoType<decltype(_pItem->m_sHavingClause)>::get());
+
+ registerProperty(PROPERTY_GROUP_BY, PROPERTY_ID_GROUP_BY, PropertyAttribute::BOUND,
+ &_pItem->m_sGroupBy, cppu::UnoType<decltype(_pItem->m_sGroupBy)>::get());
+ }
+
+ registerProperty(PROPERTY_FILTER, PROPERTY_ID_FILTER, PropertyAttribute::BOUND,
+ &_pItem->m_sFilter, cppu::UnoType<decltype(_pItem->m_sFilter)>::get());
+
+ registerProperty(PROPERTY_ORDER, PROPERTY_ID_ORDER, PropertyAttribute::BOUND,
+ &_pItem->m_sOrder, cppu::UnoType<decltype(_pItem->m_sOrder)>::get());
+
+ registerProperty(PROPERTY_APPLYFILTER, PROPERTY_ID_APPLYFILTER, PropertyAttribute::BOUND,
+ &_pItem->m_bApplyFilter, cppu::UnoType<bool>::get());
+
+ registerProperty(PROPERTY_FONT, PROPERTY_ID_FONT, PropertyAttribute::BOUND,
+ &_pItem->m_aFont, cppu::UnoType<decltype(_pItem->m_aFont)>::get());
+
+ registerMayBeVoidProperty(PROPERTY_ROW_HEIGHT, PROPERTY_ID_ROW_HEIGHT, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID,
+ &_pItem->m_aRowHeight, ::cppu::UnoType<sal_Int32>::get());
+
+ registerProperty(PROPERTY_AUTOGROW, PROPERTY_ID_AUTOGROW, PropertyAttribute::BOUND,
+ &_pItem->m_bAutoGrow, cppu::UnoType<bool>::get());
+
+ registerMayBeVoidProperty(PROPERTY_TEXTCOLOR, PROPERTY_ID_TEXTCOLOR, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID,
+ &_pItem->m_aTextColor, ::cppu::UnoType<sal_Int32>::get());
+
+ registerMayBeVoidProperty(PROPERTY_TEXTLINECOLOR, PROPERTY_ID_TEXTLINECOLOR, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID,
+ &_pItem->m_aTextLineColor, ::cppu::UnoType<sal_Int32>::get());
+
+ registerProperty(PROPERTY_TEXTEMPHASIS, PROPERTY_ID_TEXTEMPHASIS, PropertyAttribute::BOUND,
+ &_pItem->m_nFontEmphasis, cppu::UnoType<decltype(_pItem->m_nFontEmphasis)>::get());
+
+ registerProperty(PROPERTY_TEXTRELIEF, PROPERTY_ID_TEXTRELIEF, PropertyAttribute::BOUND,&_pItem->m_nFontRelief, cppu::UnoType<decltype(_pItem->m_nFontRelief)>::get());
+
+ registerProperty(PROPERTY_FONTNAME, PROPERTY_ID_FONTNAME, PropertyAttribute::BOUND,&_pItem->m_aFont.Name, cppu::UnoType<decltype(_pItem->m_aFont.Name)>::get());
+ registerProperty(PROPERTY_FONTHEIGHT, PROPERTY_ID_FONTHEIGHT, PropertyAttribute::BOUND,&_pItem->m_aFont.Height, cppu::UnoType<decltype(_pItem->m_aFont.Height)>::get());
+ registerProperty(PROPERTY_FONTWIDTH, PROPERTY_ID_FONTWIDTH, PropertyAttribute::BOUND,&_pItem->m_aFont.Width, cppu::UnoType<decltype(_pItem->m_aFont.Width)>::get());
+ registerProperty(PROPERTY_FONTSTYLENAME, PROPERTY_ID_FONTSTYLENAME, PropertyAttribute::BOUND,&_pItem->m_aFont.StyleName, cppu::UnoType<decltype(_pItem->m_aFont.StyleName)>::get());
+ registerProperty(PROPERTY_FONTFAMILY, PROPERTY_ID_FONTFAMILY, PropertyAttribute::BOUND,&_pItem->m_aFont.Family, cppu::UnoType<decltype(_pItem->m_aFont.Family)>::get());
+ registerProperty(PROPERTY_FONTCHARSET, PROPERTY_ID_FONTCHARSET, PropertyAttribute::BOUND,&_pItem->m_aFont.CharSet, cppu::UnoType<decltype(_pItem->m_aFont.CharSet)>::get());
+ registerProperty(PROPERTY_FONTPITCH, PROPERTY_ID_FONTPITCH, PropertyAttribute::BOUND,&_pItem->m_aFont.Pitch, cppu::UnoType<decltype(_pItem->m_aFont.Pitch)>::get());
+ registerProperty(PROPERTY_FONTCHARWIDTH, PROPERTY_ID_FONTCHARWIDTH, PropertyAttribute::BOUND,&_pItem->m_aFont.CharacterWidth, cppu::UnoType<decltype(_pItem->m_aFont.CharacterWidth)>::get());
+ registerProperty(PROPERTY_FONTWEIGHT, PROPERTY_ID_FONTWEIGHT, PropertyAttribute::BOUND,&_pItem->m_aFont.Weight, cppu::UnoType<decltype(_pItem->m_aFont.Weight)>::get());
+ registerProperty(PROPERTY_FONTSLANT, PROPERTY_ID_FONTSLANT, PropertyAttribute::BOUND,&_pItem->m_aFont.Slant, cppu::UnoType<decltype(_pItem->m_aFont.Slant)>::get());
+ registerProperty(PROPERTY_FONTUNDERLINE, PROPERTY_ID_FONTUNDERLINE, PropertyAttribute::BOUND,&_pItem->m_aFont.Underline, cppu::UnoType<decltype(_pItem->m_aFont.Underline)>::get());
+ registerProperty(PROPERTY_FONTSTRIKEOUT, PROPERTY_ID_FONTSTRIKEOUT, PropertyAttribute::BOUND,&_pItem->m_aFont.Strikeout, cppu::UnoType<decltype(_pItem->m_aFont.Strikeout)>::get());
+ registerProperty(PROPERTY_FONTORIENTATION, PROPERTY_ID_FONTORIENTATION, PropertyAttribute::BOUND,&_pItem->m_aFont.Orientation, cppu::UnoType<decltype(_pItem->m_aFont.Orientation)>::get());
+ registerProperty(PROPERTY_FONTKERNING, PROPERTY_ID_FONTKERNING, PropertyAttribute::BOUND,&_pItem->m_aFont.Kerning, cppu::UnoType<decltype(_pItem->m_aFont.Kerning)>::get());
+ registerProperty(PROPERTY_FONTWORDLINEMODE, PROPERTY_ID_FONTWORDLINEMODE,PropertyAttribute::BOUND,&_pItem->m_aFont.WordLineMode, cppu::UnoType<decltype(_pItem->m_aFont.WordLineMode)>::get());
+ registerProperty(PROPERTY_FONTTYPE, PROPERTY_ID_FONTTYPE, PropertyAttribute::BOUND,&_pItem->m_aFont.Type, cppu::UnoType<decltype(_pItem->m_aFont.Type)>::get());
+}
+
+ODataSettings::ODataSettings(OBroadcastHelper& _rBHelper,bool _bQuery)
+ :OPropertyStateContainer(_rBHelper)
+ ,m_bQuery(_bQuery)
+{
+}
+
+ODataSettings_Base::ODataSettings_Base()
+ :m_bApplyFilter(false)
+ ,m_bAutoGrow(false)
+ ,m_aFont(::comphelper::getDefaultFont())
+ ,m_nFontEmphasis(css::awt::FontEmphasisMark::NONE)
+ ,m_nFontRelief(css::awt::FontRelief::NONE)
+{
+}
+
+ODataSettings_Base::~ODataSettings_Base()
+{
+}
+
+void ODataSettings::getPropertyDefaultByHandle( sal_Int32 _nHandle, Any& _rDefault ) const
+{
+ static css::awt::FontDescriptor aFD = ::comphelper::getDefaultFont();
+ switch( _nHandle )
+ {
+ case PROPERTY_ID_HAVING_CLAUSE:
+ case PROPERTY_ID_GROUP_BY:
+ case PROPERTY_ID_FILTER:
+ case PROPERTY_ID_ORDER:
+ _rDefault <<= OUString();
+ break;
+ case PROPERTY_ID_FONT:
+ _rDefault <<= ::comphelper::getDefaultFont();
+ break;
+ case PROPERTY_ID_APPLYFILTER:
+ _rDefault <<= false;
+ break;
+ case PROPERTY_ID_TEXTRELIEF:
+ _rDefault <<= css::awt::FontRelief::NONE;
+ break;
+ case PROPERTY_ID_TEXTEMPHASIS:
+ _rDefault <<= css::awt::FontEmphasisMark::NONE;
+ break;
+ case PROPERTY_ID_FONTNAME:
+ _rDefault <<= aFD.Name;
+ break;
+ case PROPERTY_ID_FONTHEIGHT:
+ _rDefault <<= aFD.Height;
+ break;
+ case PROPERTY_ID_FONTWIDTH:
+ _rDefault <<= aFD.Width;
+ break;
+ case PROPERTY_ID_FONTSTYLENAME:
+ _rDefault <<= aFD.StyleName;
+ break;
+ case PROPERTY_ID_FONTFAMILY:
+ _rDefault <<= aFD.Family;
+ break;
+ case PROPERTY_ID_FONTCHARSET:
+ _rDefault <<= aFD.CharSet;
+ break;
+ case PROPERTY_ID_FONTPITCH:
+ _rDefault <<= aFD.Pitch;
+ break;
+ case PROPERTY_ID_FONTCHARWIDTH:
+ _rDefault <<= aFD.CharacterWidth;
+ break;
+ case PROPERTY_ID_FONTWEIGHT:
+ _rDefault <<= aFD.Weight;
+ break;
+ case PROPERTY_ID_FONTSLANT:
+ _rDefault <<= aFD.Slant;
+ break;
+ case PROPERTY_ID_FONTUNDERLINE:
+ _rDefault <<= aFD.Underline;
+ break;
+ case PROPERTY_ID_FONTSTRIKEOUT:
+ _rDefault <<= aFD.Strikeout;
+ break;
+ case PROPERTY_ID_FONTORIENTATION:
+ _rDefault <<= aFD.Orientation;
+ break;
+ case PROPERTY_ID_FONTKERNING:
+ _rDefault <<= aFD.Kerning;
+ break;
+ case PROPERTY_ID_FONTWORDLINEMODE:
+ _rDefault <<= aFD.WordLineMode;
+ break;
+ case PROPERTY_ID_FONTTYPE:
+ _rDefault <<= aFD.Type;
+ break;
+ }
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/definitioncolumn.cxx b/dbaccess/source/core/api/definitioncolumn.cxx
new file mode 100644
index 000000000..3f9542180
--- /dev/null
+++ b/dbaccess/source/core/api/definitioncolumn.cxx
@@ -0,0 +1,610 @@
+/* -*- 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 <bitset>
+
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include <definitioncolumn.hxx>
+#include <sdbcoretools.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+
+#include <comphelper/property.hxx>
+#include <connectivity/dbtools.hxx>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::cppu;
+using namespace ::comphelper;
+using namespace ::osl;
+using namespace dbaccess;
+
+namespace
+{
+ const sal_Int32 HAS_DESCRIPTION = 0x00000001;
+ const sal_Int32 HAS_DEFAULTVALUE = 0x00000002;
+ const sal_Int32 HAS_ROWVERSION = 0x00000004;
+ const sal_Int32 HAS_AUTOINCREMENT_CREATION = 0x00000008;
+ const sal_Int32 HAS_CATALOGNAME = 0x00000010;
+ const sal_Int32 HAS_SCHEMANAME = 0x00000020;
+ const sal_Int32 HAS_TABLENAME = 0x00000040;
+}
+
+// OTableColumnDescriptor
+IMPLEMENT_FORWARD_XINTERFACE2(OTableColumnDescriptor,OColumn,TXChild)
+
+void OTableColumnDescriptor::impl_registerProperties()
+{
+ sal_Int32 nDefaultAttr = m_bActAsDescriptor ? 0 : PropertyAttribute::READONLY;
+
+ registerProperty( PROPERTY_TYPENAME, PROPERTY_ID_TYPENAME, nDefaultAttr, &m_aTypeName, cppu::UnoType<decltype(m_aTypeName)>::get() );
+ registerProperty( PROPERTY_DESCRIPTION, PROPERTY_ID_DESCRIPTION, nDefaultAttr, &m_aDescription, cppu::UnoType<decltype(m_aDescription)>::get() );
+ registerProperty( PROPERTY_DEFAULTVALUE, PROPERTY_ID_DEFAULTVALUE, nDefaultAttr, &m_aDefaultValue, cppu::UnoType<decltype(m_aDefaultValue)>::get() );
+
+ if ( m_bActAsDescriptor )
+ registerProperty( PROPERTY_AUTOINCREMENTCREATION, PROPERTY_ID_AUTOINCREMENTCREATION, nDefaultAttr, &m_aAutoIncrementValue, cppu::UnoType<decltype(m_aAutoIncrementValue)>::get() );
+
+ registerProperty( PROPERTY_TYPE, PROPERTY_ID_TYPE, nDefaultAttr, &m_nType, cppu::UnoType<decltype(m_nType)>::get() );
+ registerProperty( PROPERTY_PRECISION, PROPERTY_ID_PRECISION, nDefaultAttr, &m_nPrecision, cppu::UnoType<decltype(m_nPrecision)>::get() );
+ registerProperty( PROPERTY_SCALE, PROPERTY_ID_SCALE, nDefaultAttr, &m_nScale, cppu::UnoType<decltype(m_nScale)>::get() );
+ registerProperty( PROPERTY_ISNULLABLE, PROPERTY_ID_ISNULLABLE, nDefaultAttr, &m_nIsNullable, cppu::UnoType<decltype(m_nIsNullable)>::get() );
+ registerProperty( PROPERTY_ISAUTOINCREMENT, PROPERTY_ID_ISAUTOINCREMENT, nDefaultAttr, &m_bAutoIncrement, cppu::UnoType<decltype(m_bAutoIncrement)>::get() );
+ registerProperty( PROPERTY_ISROWVERSION, PROPERTY_ID_ISROWVERSION, nDefaultAttr, &m_bRowVersion, cppu::UnoType<decltype(m_bRowVersion)>::get() );
+ registerProperty( PROPERTY_ISCURRENCY, PROPERTY_ID_ISCURRENCY, nDefaultAttr, &m_bCurrency, cppu::UnoType<decltype(m_bCurrency)>::get() );
+
+ OColumnSettings::registerProperties( *this );
+}
+
+IMPLEMENT_GET_IMPLEMENTATION_ID( OTableColumnDescriptor )
+
+// css::lang::XServiceInfo
+OUString OTableColumnDescriptor::getImplementationName( )
+{
+ return "com.sun.star.sdb.OTableColumnDescriptor";
+}
+
+Sequence< OUString > OTableColumnDescriptor::getSupportedServiceNames( )
+{
+ return { m_bActAsDescriptor? OUString(SERVICE_SDBCX_COLUMNDESCRIPTOR) : OUString(SERVICE_SDBCX_COLUMN),
+ SERVICE_SDB_COLUMNSETTINGS };
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* OTableColumnDescriptor::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper( aProps );
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& OTableColumnDescriptor::getInfoHelper()
+{
+ return *static_cast< ::comphelper::OPropertyArrayUsageHelper< OTableColumnDescriptor >* >(this)->getArrayHelper();
+}
+
+void OTableColumnDescriptor::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
+{
+ OColumn::setFastPropertyValue_NoBroadcast( nHandle, rValue );
+ ::dbaccess::notifyDataSourceModified( m_xParent );
+}
+
+Reference< XInterface > SAL_CALL OTableColumnDescriptor::getParent( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ return m_xParent;
+}
+
+void SAL_CALL OTableColumnDescriptor::setParent( const Reference< XInterface >& _xParent )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_xParent = _xParent;
+}
+
+// OTableColumn
+
+OTableColumn::OTableColumn( const OUString& _rName )
+ :OTableColumnDescriptor( false /* do not act as descriptor */ )
+{
+ m_sName = _rName;
+}
+
+OTableColumn::~OTableColumn()
+{
+}
+
+IMPLEMENT_GET_IMPLEMENTATION_ID( OTableColumn )
+
+OUString OTableColumn::getImplementationName( )
+{
+ return "com.sun.star.sdb.OTableColumn";
+}
+
+::cppu::IPropertyArrayHelper& SAL_CALL OTableColumn::getInfoHelper()
+{
+ return *OTableColumn_PBase::getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* OTableColumn::createArrayHelper( ) const
+{
+ return OTableColumnDescriptor::createArrayHelper();
+}
+
+// OQueryColumn
+
+OQueryColumn::OQueryColumn( const Reference< XPropertySet >& _rxParserColumn, const Reference< XConnection >& _rxConnection, const OUString &i_sLabel )
+ :OTableColumnDescriptor( false /* do not act as descriptor */ )
+ ,m_sLabel(i_sLabel)
+{
+ const sal_Int32 nPropAttr = PropertyAttribute::READONLY;
+ registerProperty( PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, nPropAttr, &m_sCatalogName, cppu::UnoType<decltype(m_sCatalogName)>::get() );
+ registerProperty( PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, nPropAttr, &m_sSchemaName, cppu::UnoType<decltype(m_sSchemaName)>::get() );
+ registerProperty( PROPERTY_TABLENAME, PROPERTY_ID_TABLENAME, nPropAttr, &m_sTableName, cppu::UnoType<decltype(m_sTableName)>::get() );
+ registerProperty( PROPERTY_REALNAME, PROPERTY_ID_REALNAME, nPropAttr, &m_sRealName, cppu::UnoType<decltype(m_sRealName)>::get() );
+ registerProperty( PROPERTY_LABEL, PROPERTY_ID_LABEL, nPropAttr, &m_sLabel, cppu::UnoType<decltype(m_sLabel)>::get() );
+
+
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_TYPENAME ) >>= m_aTypeName) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_TYPENAME);
+
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_ISNULLABLE ) >>= m_nIsNullable) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_ISNULLABLE);
+
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_PRECISION ) >>= m_nPrecision) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_PRECISION);
+
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_SCALE ) >>= m_nScale) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_SCALE);
+
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_TYPE ) >>= m_nType) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_TYPE);
+
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_ISAUTOINCREMENT ) >>= m_bAutoIncrement) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_ISAUTOINCREMENT);
+
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_ISCURRENCY ) >>= m_bCurrency) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_ISCURRENCY);
+
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_NAME ) >>= m_sName) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_NAME);
+
+ m_bRowVersion = false;
+
+ Reference< XPropertySetInfo > xPSI( _rxParserColumn->getPropertySetInfo(), UNO_SET_THROW );
+ if ( xPSI->hasPropertyByName( PROPERTY_DEFAULTVALUE ) )
+ if( ! (_rxParserColumn->getPropertyValue( PROPERTY_DEFAULTVALUE ) >>= m_aDefaultValue) )
+ SAL_WARN("dbaccess.core", "OQueryColumn: unable to get property " PROPERTY_DEFAULTVALUE);
+
+ // copy some optional properties from the parser column
+ struct PropertyDescriptor
+ {
+ OUString sName;
+ sal_Int32 nHandle;
+ };
+ const PropertyDescriptor aProps[] =
+ {
+ { OUString(PROPERTY_CATALOGNAME), PROPERTY_ID_CATALOGNAME },
+ { OUString(PROPERTY_SCHEMANAME), PROPERTY_ID_SCHEMANAME },
+ { OUString(PROPERTY_TABLENAME), PROPERTY_ID_TABLENAME },
+ { OUString(PROPERTY_REALNAME), PROPERTY_ID_REALNAME }
+ };
+ for (const auto & aProp : aProps)
+ {
+ if ( xPSI->hasPropertyByName( aProp.sName ) )
+ setFastPropertyValue_NoBroadcast( aProp.nHandle, _rxParserColumn->getPropertyValue( aProp.sName ) );
+ }
+
+ // determine the table column we're based on
+ osl_atomic_increment( &m_refCount );
+ {
+ m_xOriginalTableColumn = impl_determineOriginalTableColumn( _rxConnection );
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+OQueryColumn::~OQueryColumn()
+{
+}
+
+Reference< XPropertySet > OQueryColumn::impl_determineOriginalTableColumn( const Reference< XConnection >& _rxConnection )
+{
+ OSL_PRECOND( _rxConnection.is(), "OQueryColumn::impl_determineOriginalTableColumn: illegal connection!" );
+ if ( !_rxConnection.is() )
+ return nullptr;
+
+ Reference< XPropertySet > xOriginalTableColumn;
+ try
+ {
+ // determine the composed table name, plus the column name, as indicated by the
+ // respective properties
+ OUString sCatalog, sSchema, sTable;
+ if( ! (getPropertyValue( PROPERTY_CATALOGNAME ) >>= sCatalog) )
+ SAL_WARN("dbaccess.core", "impl_determineOriginalTableColumn: unable to get property " PROPERTY_CATALOGNAME);
+ if( ! (getPropertyValue( PROPERTY_SCHEMANAME ) >>= sSchema) )
+ SAL_WARN("dbaccess.core", "impl_determineOriginalTableColumn: unable to get property " PROPERTY_SCHEMANAME);
+ if( ! (getPropertyValue( PROPERTY_TABLENAME ) >>= sTable) )
+ SAL_WARN("dbaccess.core", "impl_determineOriginalTableColumn: unable to get property " PROPERTY_TABLENAME);
+ if ( sCatalog.isEmpty() && sSchema.isEmpty() && sTable.isEmpty() )
+ return nullptr;
+
+ OUString sComposedTableName = ::dbtools::composeTableName(
+ _rxConnection->getMetaData(), sCatalog, sSchema, sTable, false, ::dbtools::EComposeRule::Complete );
+
+ // retrieve the table in question
+ Reference< XTablesSupplier > xSuppTables( _rxConnection, UNO_QUERY_THROW );
+ Reference< XNameAccess > xTables( xSuppTables->getTables(), UNO_SET_THROW );
+ if ( !xTables->hasByName( sComposedTableName ) )
+ return nullptr;
+
+ Reference< XColumnsSupplier > xSuppCols( xTables->getByName( sComposedTableName ), UNO_QUERY_THROW );
+ Reference< XNameAccess > xColumns( xSuppCols->getColumns(), UNO_SET_THROW );
+
+ OUString sColumn;
+ if( ! (getPropertyValue( PROPERTY_REALNAME ) >>= sColumn) )
+ SAL_WARN("dbaccess.core", "impl_determineOriginalTableColumn: unable to get property " PROPERTY_REALNAME);
+ if ( !xColumns->hasByName( sColumn ) )
+ return nullptr;
+
+ xOriginalTableColumn.set( xColumns->getByName( sColumn ), UNO_QUERY );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return xOriginalTableColumn;
+}
+
+IMPLEMENT_GET_IMPLEMENTATION_ID( OQueryColumn )
+
+OUString SAL_CALL OQueryColumn::getImplementationName( )
+{
+ return "org.openoffice.comp.dbaccess.OQueryColumn";
+}
+
+::cppu::IPropertyArrayHelper& SAL_CALL OQueryColumn::getInfoHelper()
+{
+ return *OQueryColumn_PBase::getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* OQueryColumn::createArrayHelper() const
+{
+ return OTableColumnDescriptor::createArrayHelper();
+}
+
+void SAL_CALL OQueryColumn::getFastPropertyValue( Any& _rValue, sal_Int32 _nHandle ) const
+{
+ OTableColumnDescriptor::getFastPropertyValue( _rValue, _nHandle );
+
+ // special treatment for column settings:
+ if ( !OColumnSettings::isColumnSettingProperty( _nHandle ) )
+ return;
+
+ // If the setting has its default value, then try to obtain the value from the table column which
+ // this query column is based on
+ if ( !OColumnSettings::isDefaulted( _nHandle, _rValue ) )
+ return;
+
+ if ( !m_xOriginalTableColumn.is() )
+ return;
+
+ try
+ {
+ // determine original property name
+ OUString sPropName;
+ sal_Int16 nAttributes( 0 );
+ const_cast< OQueryColumn* >( this )->getInfoHelper().fillPropertyMembersByHandle( &sPropName, &nAttributes, _nHandle );
+ OSL_ENSURE( !sPropName.isEmpty(), "OColumnWrapper::impl_getPropertyNameFromHandle: property not found!" );
+
+ _rValue = m_xOriginalTableColumn->getPropertyValue( sPropName );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+// OColumnWrapper
+
+OColumnWrapper::OColumnWrapper( const Reference< XPropertySet > & rCol, const bool _bNameIsReadOnly )
+ :OColumn( _bNameIsReadOnly )
+ ,m_xAggregate(rCol)
+ ,m_nColTypeID(-1)
+{
+ // which type of aggregate property do we have?
+ // we distinguish the properties by the containment of optional properties
+ m_nColTypeID = 0;
+ if ( !m_xAggregate.is() )
+ return;
+
+ Reference <XPropertySetInfo > xInfo(m_xAggregate->getPropertySetInfo());
+ m_nColTypeID |= xInfo->hasPropertyByName(PROPERTY_DESCRIPTION) ? HAS_DESCRIPTION : 0;
+ m_nColTypeID |= xInfo->hasPropertyByName(PROPERTY_DEFAULTVALUE) ? HAS_DEFAULTVALUE : 0;
+ m_nColTypeID |= xInfo->hasPropertyByName(PROPERTY_ISROWVERSION) ? HAS_ROWVERSION : 0;
+ m_nColTypeID |= xInfo->hasPropertyByName(PROPERTY_AUTOINCREMENTCREATION) ? HAS_AUTOINCREMENT_CREATION : 0;
+ m_nColTypeID |= xInfo->hasPropertyByName(PROPERTY_CATALOGNAME) ? HAS_CATALOGNAME : 0;
+ m_nColTypeID |= xInfo->hasPropertyByName(PROPERTY_SCHEMANAME) ? HAS_SCHEMANAME : 0;
+ m_nColTypeID |= xInfo->hasPropertyByName(PROPERTY_TABLENAME) ? HAS_TABLENAME : 0;
+
+ m_xAggregate->getPropertyValue(PROPERTY_NAME) >>= m_sName;
+}
+
+OColumnWrapper::~OColumnWrapper()
+{
+}
+
+OUString OColumnWrapper::impl_getPropertyNameFromHandle( const sal_Int32 _nHandle ) const
+{
+ OUString sPropName;
+ sal_Int16 nAttributes( 0 );
+ const_cast< OColumnWrapper* >( this )->getInfoHelper().fillPropertyMembersByHandle( &sPropName, &nAttributes, _nHandle );
+ OSL_ENSURE( !sPropName.isEmpty(), "OColumnWrapper::impl_getPropertyNameFromHandle: property not found!" );
+ return sPropName;
+}
+
+void OColumnWrapper::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ // derived classes are free to either use the OPropertyContainer(Helper) mechanisms for properties,
+ // or to declare additional properties which are to be forwarded to the wrapped object. So we need
+ // to distinguish those cases.
+ if ( OColumn::isRegisteredProperty( nHandle ) )
+ {
+ OColumn::getFastPropertyValue( rValue, nHandle );
+ }
+ else
+ {
+ rValue = m_xAggregate->getPropertyValue( impl_getPropertyNameFromHandle( nHandle ) );
+ }
+}
+
+sal_Bool OColumnWrapper::convertFastPropertyValue( Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle,
+ const Any& rValue )
+{
+ bool bModified( false );
+ if ( OColumn::isRegisteredProperty( nHandle ) )
+ {
+ bModified = OColumn::convertFastPropertyValue( rConvertedValue, rOldValue, nHandle, rValue );
+ }
+ else
+ {
+ getFastPropertyValue( rOldValue, nHandle );
+ if ( rOldValue != rValue )
+ {
+ rConvertedValue = rValue;
+ bModified = true;
+ }
+ }
+ return bModified;
+}
+
+void OColumnWrapper::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
+{
+ if ( OColumn::isRegisteredProperty( nHandle ) )
+ {
+ OColumn::setFastPropertyValue_NoBroadcast( nHandle, rValue );
+ }
+ else
+ {
+ m_xAggregate->setPropertyValue( impl_getPropertyNameFromHandle( nHandle ), rValue );
+ }
+}
+
+// OTableColumnDescriptorWrapper
+OTableColumnDescriptorWrapper::OTableColumnDescriptorWrapper( const Reference< XPropertySet >& _rCol, const bool _bPureWrap, const bool _bIsDescriptor )
+ :OColumnWrapper( _rCol, !_bIsDescriptor )
+ ,m_bPureWrap( _bPureWrap )
+ ,m_bIsDescriptor( _bIsDescriptor )
+{
+ // let the ColumnSettings register its properties
+ OColumnSettings::registerProperties( *this );
+}
+
+// css::lang::XTypeProvider
+IMPLEMENT_GET_IMPLEMENTATION_ID( OTableColumnDescriptorWrapper )
+
+// css::lang::XServiceInfo
+OUString OTableColumnDescriptorWrapper::getImplementationName( )
+{
+ return "com.sun.star.sdb.OTableColumnDescriptorWrapper";
+}
+
+Sequence< OUString > OTableColumnDescriptorWrapper::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBCX_COLUMNDESCRIPTOR, SERVICE_SDB_COLUMNSETTINGS };
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* OTableColumnDescriptorWrapper::createArrayHelper( sal_Int32 nId ) const
+{
+ const sal_Int32 nHaveAlways = 7;
+
+ // Which optional properties are contained?
+ const sal_Int32 nHaveOptionally (std::bitset<7>(nId).count());
+
+ css::uno::Sequence< css::beans::Property> aDescriptor(nHaveAlways + nHaveOptionally);
+ css::beans::Property* pDesc = aDescriptor.getArray();
+ sal_Int32 nPos = 0;
+
+ pDesc[nPos++] = css::beans::Property(PROPERTY_ISAUTOINCREMENT, PROPERTY_ID_ISAUTOINCREMENT, cppu::UnoType<bool>::get(), 0);
+ pDesc[nPos++] = css::beans::Property(PROPERTY_ISCURRENCY, PROPERTY_ID_ISCURRENCY, cppu::UnoType<bool>::get(), 0);
+ pDesc[nPos++] = css::beans::Property(PROPERTY_ISNULLABLE, PROPERTY_ID_ISNULLABLE, cppu::UnoType<sal_Int32>::get(), 0);
+ pDesc[nPos++] = css::beans::Property(PROPERTY_PRECISION, PROPERTY_ID_PRECISION, cppu::UnoType<sal_Int32>::get(), 0);
+ pDesc[nPos++] = css::beans::Property(PROPERTY_SCALE, PROPERTY_ID_SCALE, cppu::UnoType<sal_Int32>::get(), 0);
+ pDesc[nPos++] = css::beans::Property(PROPERTY_TYPE, PROPERTY_ID_TYPE, cppu::UnoType<sal_Int32>::get(), 0);
+ pDesc[nPos++] = css::beans::Property(PROPERTY_TYPENAME, PROPERTY_ID_TYPENAME, cppu::UnoType<OUString >::get(), 0);
+
+ if ( nId & HAS_AUTOINCREMENT_CREATION )
+ {
+ pDesc[nPos++] = css::beans::Property(PROPERTY_AUTOINCREMENTCREATION, PROPERTY_ID_AUTOINCREMENTCREATION, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::MAYBEVOID );
+ }
+ if ( nId & HAS_DEFAULTVALUE )
+ {
+ pDesc[nPos++] = css::beans::Property(PROPERTY_DEFAULTVALUE, PROPERTY_ID_DEFAULTVALUE, cppu::UnoType<OUString >::get(), 0);
+ }
+ if ( nId & HAS_DESCRIPTION )
+ {
+ pDesc[nPos++] = css::beans::Property(PROPERTY_DESCRIPTION, PROPERTY_ID_DESCRIPTION, cppu::UnoType<OUString >::get(), 0);
+ }
+ if ( nId & HAS_ROWVERSION )
+ {
+ pDesc[nPos++] = css::beans::Property(PROPERTY_ISROWVERSION, PROPERTY_ID_ISROWVERSION, cppu::UnoType<bool>::get(), 0);
+ }
+ if ( nId & HAS_CATALOGNAME )
+ {
+ pDesc[nPos++] = css::beans::Property(PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, cppu::UnoType<OUString >::get(), 0);
+ }
+ if ( nId & HAS_SCHEMANAME )
+ {
+ pDesc[nPos++] = css::beans::Property(PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, cppu::UnoType<OUString >::get(), 0);
+ }
+ if ( nId & HAS_TABLENAME )
+ {
+ pDesc[nPos++] = css::beans::Property(PROPERTY_TABLENAME, PROPERTY_ID_TABLENAME, cppu::UnoType<OUString >::get(), 0);
+ }
+
+ OSL_ENSURE(nPos == aDescriptor.getLength(), "forgot to adjust the count ?");
+
+ if ( !m_bIsDescriptor )
+ {
+ for ( auto & prop : asNonConstRange(aDescriptor) )
+ {
+ prop.Attributes |= PropertyAttribute::READONLY;
+ }
+ }
+
+ // finally also describe the properties which are maintained by our base class, in particular the OPropertyContainerHelper
+ Sequence< Property > aBaseProperties;
+ describeProperties( aBaseProperties );
+
+ Sequence< Property > aAllProperties( ::comphelper::concatSequences( aDescriptor, aBaseProperties ) );
+ return new ::cppu::OPropertyArrayHelper( aAllProperties, false );
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& OTableColumnDescriptorWrapper::getInfoHelper()
+{
+ return *static_cast< OIdPropertyArrayUsageHelper< OTableColumnDescriptorWrapper >* >(this)->getArrayHelper(m_nColTypeID);
+}
+
+void OTableColumnDescriptorWrapper::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ if ( m_bPureWrap )
+ {
+ rValue = m_xAggregate->getPropertyValue( impl_getPropertyNameFromHandle( nHandle ) );
+ }
+ else
+ {
+ OColumnWrapper::getFastPropertyValue( rValue, nHandle );
+ }
+}
+
+sal_Bool OTableColumnDescriptorWrapper::convertFastPropertyValue( Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
+{
+ bool bModified(false);
+ if ( m_bPureWrap )
+ {
+ // do not delegate to OColumnWrapper: It would, for the properties which were registered with registerProperty,
+ // ask the OPropertyContainer base class, which is not what we want here.
+ // TODO: the whole "m_bPureWrap"-thingie is strange. We should have a dedicated class doing this wrapping,
+ // not a class which normally serves other purposes, and only sometimes does a "pure wrap". It makes the
+ // code unnecessarily hard to maintain, and error prone.
+ rOldValue = m_xAggregate->getPropertyValue( impl_getPropertyNameFromHandle( nHandle ) );
+ if ( rOldValue != rValue )
+ {
+ rConvertedValue = rValue;
+ bModified = true;
+ }
+ }
+ else
+ {
+ bModified = OColumnWrapper::convertFastPropertyValue( rConvertedValue, rOldValue, nHandle, rValue );
+ }
+ return bModified;
+}
+
+void OTableColumnDescriptorWrapper::setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const Any& rValue
+ )
+{
+ if ( m_bPureWrap )
+ {
+ m_xAggregate->setPropertyValue( impl_getPropertyNameFromHandle( nHandle ), rValue );
+ }
+ else
+ {
+ OColumnWrapper::setFastPropertyValue_NoBroadcast( nHandle, rValue );
+ }
+}
+
+// OTableColumnWrapper
+OTableColumnWrapper::OTableColumnWrapper( const Reference< XPropertySet >& rCol, const Reference< XPropertySet >& _xColDefinition,
+ const bool _bPureWrap )
+ :OTableColumnDescriptorWrapper( rCol, _bPureWrap, false )
+{
+ osl_atomic_increment( &m_refCount );
+ if ( _xColDefinition.is() )
+ {
+ try
+ {
+ ::comphelper::copyProperties( _xColDefinition, this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+OTableColumnWrapper::~OTableColumnWrapper()
+{
+}
+
+IMPLEMENT_GET_IMPLEMENTATION_ID( OTableColumnWrapper )
+
+OUString OTableColumnWrapper::getImplementationName( )
+{
+ return "com.sun.star.sdb.OTableColumnWrapper";
+}
+
+Sequence< OUString > OTableColumnWrapper::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBCX_COLUMN, SERVICE_SDB_COLUMNSETTINGS };
+}
+
+::cppu::IPropertyArrayHelper& OTableColumnWrapper::getInfoHelper()
+{
+ return *static_cast< OIdPropertyArrayUsageHelper< OTableColumnWrapper >* >(this)->getArrayHelper(m_nColTypeID);
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* OTableColumnWrapper::createArrayHelper( sal_Int32 nId ) const
+{
+ return OTableColumnDescriptorWrapper::createArrayHelper( nId );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/preparedstatement.cxx b/dbaccess/source/core/api/preparedstatement.cxx
new file mode 100644
index 000000000..02dd32379
--- /dev/null
+++ b/dbaccess/source/core/api/preparedstatement.cxx
@@ -0,0 +1,412 @@
+/* -*- 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/lang/DisposedException.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+
+#include <connectivity/dbtools.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <preparedstatement.hxx>
+#include <strings.hxx>
+#include "resultcolumn.hxx"
+#include "resultset.hxx"
+#include <tools/diagnose_ex.h>
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace dbaccess;
+
+
+OPreparedStatement::OPreparedStatement(const Reference< XConnection > & _xConn,
+ const Reference< XInterface > & _xStatement)
+ :OStatementBase(_xConn, _xStatement)
+{
+ m_xAggregateAsParameters.set( m_xAggregateAsSet, UNO_QUERY_THROW );
+
+ Reference<XDatabaseMetaData> xMeta = _xConn->getMetaData();
+ m_pColumns.reset( new OColumns(*this, m_aMutex, xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers(),std::vector< OUString>(), nullptr,nullptr) );
+}
+
+OPreparedStatement::~OPreparedStatement()
+{
+ m_pColumns->acquire();
+ m_pColumns->disposing();
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > OPreparedStatement::getTypes()
+{
+ OTypeCollection aTypes(cppu::UnoType<XServiceInfo>::get(),
+ cppu::UnoType<XPreparedStatement>::get(),
+ cppu::UnoType<XParameters>::get(),
+ cppu::UnoType<XResultSetMetaDataSupplier>::get(),
+ cppu::UnoType<XColumnsSupplier>::get(),
+ OStatementBase::getTypes() );
+
+ return aTypes.getTypes();
+}
+
+Sequence< sal_Int8 > OPreparedStatement::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// css::uno::XInterface
+Any OPreparedStatement::queryInterface( const Type & rType )
+{
+ Any aIface = OStatementBase::queryInterface( rType );
+ if (!aIface.hasValue())
+ aIface = ::cppu::queryInterface(
+ rType,
+ static_cast< XServiceInfo * >( this ),
+ static_cast< XParameters * >( this ),
+ static_cast< XColumnsSupplier * >( this ),
+ static_cast< XResultSetMetaDataSupplier * >( this ),
+ static_cast< XPreparedBatchExecution * >( this ),
+ static_cast< XMultipleResults * >( this ),
+ static_cast< XPreparedStatement * >( this ));
+ return aIface;
+}
+
+void OPreparedStatement::acquire() noexcept
+{
+ OStatementBase::acquire();
+}
+
+void OPreparedStatement::release() noexcept
+{
+ OStatementBase::release();
+}
+
+// XServiceInfo
+OUString OPreparedStatement::getImplementationName( )
+{
+ return "com.sun.star.sdb.OPreparedStatement";
+}
+
+sal_Bool OPreparedStatement::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > OPreparedStatement::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBC_PREPAREDSTATEMENT, SERVICE_SDB_PREPAREDSTATMENT };
+}
+
+// OComponentHelper
+void OPreparedStatement::disposing()
+{
+ {
+ MutexGuard aGuard(m_aMutex);
+ m_pColumns->disposing();
+ m_xAggregateAsParameters = nullptr;
+ }
+ OStatementBase::disposing();
+}
+
+// css::sdbcx::XColumnsSupplier
+Reference< css::container::XNameAccess > OPreparedStatement::getColumns()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ // do we have to populate the columns
+ if (!m_pColumns->isInitialized())
+ {
+ try
+ {
+ Reference< XResultSetMetaDataSupplier > xSuppMeta( m_xAggregateAsSet, UNO_QUERY_THROW );
+ Reference< XResultSetMetaData > xMetaData( xSuppMeta->getMetaData(), UNO_SET_THROW );
+
+ Reference< XConnection > xConn( getConnection(), UNO_SET_THROW );
+ Reference< XDatabaseMetaData > xDBMeta( xConn->getMetaData(), UNO_SET_THROW );
+
+ for (sal_Int32 i = 0, nCount = xMetaData->getColumnCount(); i < nCount; ++i)
+ {
+ // retrieve the name of the column
+ OUString aName = xMetaData->getColumnName(i + 1);
+ rtl::Reference<OResultColumn> pColumn = new OResultColumn(xMetaData, i + 1, xDBMeta);
+ // don't silently assume that the name is unique - preparedStatement implementations
+ // are allowed to return duplicate names, but we are required to have
+ // unique column names
+ if ( m_pColumns->hasByName( aName ) )
+ aName = ::dbtools::createUniqueName( m_pColumns.get(), aName );
+
+ m_pColumns->append(aName, pColumn.get());
+ }
+ }
+ catch (const SQLException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ m_pColumns->setInitialized();
+ }
+ return m_pColumns.get();
+}
+
+// XResultSetMetaDataSupplier
+Reference< XResultSetMetaData > OPreparedStatement::getMetaData()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ return Reference< XResultSetMetaDataSupplier >( m_xAggregateAsSet, UNO_QUERY_THROW )->getMetaData();
+}
+
+// XPreparedStatement
+Reference< XResultSet > OPreparedStatement::executeQuery()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ disposeResultSet();
+
+ Reference< XResultSet > xResultSet;
+ Reference< XResultSet > xDrvResultSet = Reference< XPreparedStatement >( m_xAggregateAsSet, UNO_QUERY_THROW )->executeQuery();
+ if (xDrvResultSet.is())
+ {
+ xResultSet = new OResultSet(xDrvResultSet, *this, m_pColumns->isCaseSensitive());
+
+ // keep the resultset weak
+ m_aResultSet = xResultSet;
+ }
+ return xResultSet;
+}
+
+sal_Int32 OPreparedStatement::executeUpdate()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ disposeResultSet();
+
+ return Reference< XPreparedStatement >( m_xAggregateAsSet, UNO_QUERY_THROW )->executeUpdate();
+}
+
+sal_Bool OPreparedStatement::execute()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ disposeResultSet();
+
+ return Reference< XPreparedStatement >( m_xAggregateAsSet, UNO_QUERY_THROW )->execute();
+}
+
+Reference< XConnection > OPreparedStatement::getConnection()
+{
+ return Reference< XConnection > (m_xParent, UNO_QUERY);
+}
+
+// XParameters
+void SAL_CALL OPreparedStatement::setNull( sal_Int32 parameterIndex, sal_Int32 sqlType )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setNull(parameterIndex, sqlType);
+}
+
+void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setObjectNull(parameterIndex, sqlType, typeName);
+}
+
+void SAL_CALL OPreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setBoolean(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setByte( sal_Int32 parameterIndex, sal_Int8 x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setByte(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setShort(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setInt(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setLong(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setFloat( sal_Int32 parameterIndex, float x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setFloat(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setDouble( sal_Int32 parameterIndex, double x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setDouble(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setString(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setBytes( sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setBytes(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setDate( sal_Int32 parameterIndex, const css::util::Date& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setDate(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setTime( sal_Int32 parameterIndex, const css::util::Time& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setTime(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setTimestamp(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setBinaryStream(parameterIndex, x, length);
+}
+
+void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setCharacterStream(parameterIndex, x, length);
+}
+
+void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setObject(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 targetSqlType, sal_Int32 scale )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setObjectWithInfo(parameterIndex, x, targetSqlType, scale);
+}
+
+void SAL_CALL OPreparedStatement::setRef( sal_Int32 parameterIndex, const Reference< XRef >& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setRef(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setBlob( sal_Int32 parameterIndex, const Reference< XBlob >& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setBlob(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setClob( sal_Int32 parameterIndex, const Reference< XClob >& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setClob(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::setArray( sal_Int32 parameterIndex, const Reference< XArray >& x )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->setArray(parameterIndex, x);
+}
+
+void SAL_CALL OPreparedStatement::clearParameters( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ m_xAggregateAsParameters->clearParameters();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/query.cxx b/dbaccess/source/core/api/query.cxx
new file mode 100644
index 000000000..33ceca9ce
--- /dev/null
+++ b/dbaccess/source/core/api/query.cxx
@@ -0,0 +1,383 @@
+/* -*- 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 "query.hxx"
+#include <stringconstants.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/PColumn.hxx>
+#include <connectivity/warningscontainer.hxx>
+#include "HelperCollections.hxx"
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+
+#include <comphelper/property.hxx>
+#include <unotools/sharedunocomponent.hxx>
+#include <definitioncolumn.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <ContainerMediator.hxx>
+
+using namespace dbaccess;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::comphelper;
+using namespace ::osl;
+using namespace ::cppu;
+using namespace ::utl;
+
+namespace dbaccess
+{
+
+// OQuery
+
+OQuery::OQuery( const Reference< XPropertySet >& _rxCommandDefinition
+ ,const Reference< XConnection >& _rxConn
+ ,const Reference< XComponentContext >& _xORB)
+ :OContentHelper(_xORB,nullptr,std::make_shared<OContentHelper_Impl>())
+ ,OQueryDescriptor_Base(m_aMutex,*this)
+ ,ODataSettings(OContentHelper::rBHelper,true)
+ ,m_xCommandDefinition(_rxCommandDefinition)
+ ,m_xConnection(_rxConn)
+ ,m_pWarnings( nullptr )
+ ,m_eDoingCurrently(AggregateAction::NONE)
+{
+ registerProperties();
+ ODataSettings::registerPropertiesFor(this);
+
+ osl_atomic_increment(&m_refCount);
+ OSL_ENSURE(m_xCommandDefinition.is(), "OQuery::OQuery : invalid CommandDefinition object !");
+ if ( m_xCommandDefinition.is() )
+ {
+ try
+ {
+ ::comphelper::copyProperties(_rxCommandDefinition,this);
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "OQueryDescriptor_Base::OQueryDescriptor_Base");
+ }
+
+ m_xCommandDefinition->addPropertyChangeListener(OUString(), this);
+ // m_xCommandDefinition->addPropertyChangeListener(PROPERTY_NAME, this);
+ m_xCommandPropInfo = m_xCommandDefinition->getPropertySetInfo();
+ }
+ OSL_ENSURE(m_xConnection.is(), "OQuery::OQuery : invalid connection !");
+ osl_atomic_decrement(&m_refCount);
+}
+
+OQuery::~OQuery()
+{
+}
+
+css::uno::Sequence<sal_Int8> OQuery::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+css::uno::Sequence< css::uno::Type > OQuery::getTypes()
+{
+ return ::comphelper::concatSequences(
+ OQueryDescriptor_Base::getTypes( ),
+ ODataSettings::getTypes( ),
+ OContentHelper::getTypes( )
+ );
+}
+
+IMPLEMENT_FORWARD_XINTERFACE3( OQuery,OContentHelper,OQueryDescriptor_Base,ODataSettings)
+
+void OQuery::rebuildColumns()
+{
+ OSL_PRECOND( getColumnCount() == 0, "OQuery::rebuildColumns: column container should be empty!" );
+ // the base class' definition of rebuildColumns promised that clearColumns is called before rebuildColumns
+
+ try
+ {
+ m_pColumnMediator = nullptr;
+
+ Reference<XColumnsSupplier> xColSup(m_xCommandDefinition,UNO_QUERY);
+ Reference< XNameAccess > xColumnDefinitions;
+ if ( xColSup.is() )
+ {
+ xColumnDefinitions = xColSup->getColumns();
+ if ( xColumnDefinitions.is() )
+ m_pColumnMediator = new OContainerMediator( m_pColumns.get(), xColumnDefinitions );
+ }
+
+ // fill the columns with columns from the statement
+ Reference< XMultiServiceFactory > xFactory( m_xConnection, UNO_QUERY_THROW );
+ SharedUNOComponent< XSingleSelectQueryComposer, DisposableComponent > xComposer(
+ Reference< XSingleSelectQueryComposer >( xFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW ) );
+
+ Reference< XNameAccess > xColumns;
+ Reference< XIndexAccess > xColumnsIndexed;
+ try
+ {
+ xComposer->setQuery( m_sCommand );
+ Reference< XColumnsSupplier > xCols( xComposer, UNO_QUERY_THROW );
+ xColumns.set( xCols->getColumns(), UNO_SET_THROW );
+ xColumnsIndexed.set( xColumns, UNO_QUERY_THROW );
+ }
+ catch( const SQLException& ) { }
+
+ SharedUNOComponent< XPreparedStatement, DisposableComponent > xPreparedStatement;
+ if ( !xColumns.is() || ( xColumnsIndexed->getCount() == 0 ) )
+ { // the QueryComposer could not parse it. Try a lean version.
+ xPreparedStatement.set( m_xConnection->prepareStatement( m_sCommand ), UNO_QUERY_THROW );
+ Reference< XResultSetMetaDataSupplier > xResMetaDataSup( xPreparedStatement, UNO_QUERY_THROW );
+ Reference< XResultSetMetaData > xResultSetMeta( xResMetaDataSup->getMetaData() );
+ if ( !xResultSetMeta.is() )
+ {
+ OUString sError( DBA_RES( RID_STR_STATEMENT_WITHOUT_RESULT_SET ) );
+ ::dbtools::throwSQLException( sError, StandardSQLState::GENERAL_ERROR, *this );
+ }
+
+ Reference< XDatabaseMetaData > xDBMeta( m_xConnection->getMetaData(), UNO_SET_THROW );
+ ::rtl::Reference< OSQLColumns > aParseColumns(
+ ::connectivity::parse::OParseColumn::createColumnsForResultSet( xResultSetMeta, xDBMeta,xColumnDefinitions ) );
+ xColumns = OPrivateColumns::createWithIntrinsicNames(
+ aParseColumns, xDBMeta->supportsMixedCaseQuotedIdentifiers(), *this, m_aMutex ).release();
+ if ( !xColumns.is() )
+ throw RuntimeException();
+ }
+
+ const Sequence<OUString> aColNames = xColumns->getElementNames();
+ for ( const OUString& rName : aColNames )
+ {
+ Reference<XPropertySet> xSource(xColumns->getByName( rName ),UNO_QUERY);
+ OUString sLabel = rName;
+ if ( xColumnDefinitions.is() && xColumnDefinitions->hasByName(rName) )
+ {
+ Reference<XPropertySet> xCommandColumn(xColumnDefinitions->getByName( rName ),UNO_QUERY);
+ xCommandColumn->getPropertyValue(PROPERTY_LABEL) >>= sLabel;
+ }
+ rtl::Reference<OQueryColumn> pColumn = new OQueryColumn( xSource, m_xConnection, sLabel);
+ pColumn->setParent( *this );
+
+ implAppendColumn( rName, pColumn.get() );
+ Reference< XPropertySet > xDest( *pColumn, UNO_QUERY_THROW );
+ if ( m_pColumnMediator.is() )
+ m_pColumnMediator->notifyElementCreated( rName, xDest );
+ }
+ }
+ catch( const SQLContext& e )
+ {
+ if ( m_pWarnings )
+ m_pWarnings->appendWarning( e );
+ }
+ catch( const SQLWarning& e )
+ {
+ if ( m_pWarnings )
+ m_pWarnings->appendWarning( e );
+ }
+ catch( const SQLException& e )
+ {
+ if ( m_pWarnings )
+ m_pWarnings->appendWarning( e );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+// XServiceInfo
+OUString SAL_CALL OQuery::getImplementationName()
+ {
+ return "com.sun.star.sdb.dbaccess.OQuery";
+ }
+sal_Bool SAL_CALL OQuery::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL OQuery::getSupportedServiceNames( )
+{
+ return { SERVICE_SDB_DATASETTINGS, SERVICE_SDB_QUERY, "com.sun.star.sdb.QueryDefinition" };
+}
+
+// css::beans::XPropertyChangeListener
+void SAL_CALL OQuery::propertyChange( const PropertyChangeEvent& _rSource )
+{
+ sal_Int32 nOwnHandle = -1;
+ {
+ MutexGuard aGuard(m_aMutex);
+
+ OSL_ENSURE(_rSource.Source.get() == Reference< XInterface >(m_xCommandDefinition, UNO_QUERY).get(),
+ "OQuery::propertyChange : where did this call come from ?");
+
+ if (m_eDoingCurrently == AggregateAction::SettingProperties)
+ // we're setting the property ourself, so we will do the necessary notifications later
+ return;
+
+ // forward this to our own member holding a copy of the property value
+ if (getArrayHelper()->hasPropertyByName(_rSource.PropertyName))
+ {
+ Property aOwnProp = getArrayHelper()->getPropertyByName(_rSource.PropertyName);
+ nOwnHandle = aOwnProp.Handle;
+ ODataSettings::setFastPropertyValue_NoBroadcast(nOwnHandle, _rSource.NewValue);
+ // don't use our own setFastPropertyValue_NoBroadcast, this would forward it to the CommandSettings,
+ // again
+ // and don't use the "real" setPropertyValue, this is too expensive and not sure to succeed
+ }
+ else
+ {
+ OSL_FAIL("OQuery::propertyChange : my CommandDefinition has more properties than I do !");
+ }
+ }
+
+ fire(&nOwnHandle, &_rSource.NewValue, &_rSource.OldValue, 1, false);
+}
+
+void SAL_CALL OQuery::disposing( const EventObject& _rSource )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ OSL_ENSURE(_rSource.Source.get() == Reference< XInterface >(m_xCommandDefinition, UNO_QUERY).get(),
+ "OQuery::disposing : where did this call come from ?");
+
+ m_xCommandDefinition->removePropertyChangeListener(OUString(), this);
+ m_xCommandDefinition = nullptr;
+}
+
+// XDataDescriptorFactory
+Reference< XPropertySet > SAL_CALL OQuery::createDataDescriptor( )
+{
+ return new OQueryDescriptor(*this);
+}
+
+// pseudo-XComponent
+void SAL_CALL OQuery::disposing()
+{
+ MutexGuard aGuard(m_aMutex);
+ if (m_xCommandDefinition.is())
+ {
+ m_xCommandDefinition->removePropertyChangeListener(OUString(), this);
+ m_xCommandDefinition = nullptr;
+ }
+ disposeColumns();
+
+ m_pWarnings = nullptr;
+}
+
+void OQuery::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle, const Any& _rValue )
+{
+ ODataSettings::setFastPropertyValue_NoBroadcast(_nHandle, _rValue);
+ OUString sAggPropName;
+ sal_Int16 nAttr = 0;
+ if (getInfoHelper().fillPropertyMembersByHandle(&sAggPropName,&nAttr,_nHandle) &&
+ m_xCommandPropInfo.is() &&
+ m_xCommandPropInfo->hasPropertyByName(sAggPropName))
+ { // the base class holds the property values itself, but we have to forward this to our CommandDefinition
+
+ m_eDoingCurrently = AggregateAction::SettingProperties;
+ OAutoActionReset aAutoReset(*this);
+ m_xCommandDefinition->setPropertyValue(sAggPropName, _rValue);
+
+ if ( PROPERTY_ID_COMMAND == _nHandle )
+ // the columns are out of date if we are based on a new statement...
+ setColumnsOutOfDate();
+ }
+}
+
+Reference< XPropertySetInfo > SAL_CALL OQuery::getPropertySetInfo( )
+{
+ return createPropertySetInfo( getInfoHelper() ) ;
+}
+
+::cppu::IPropertyArrayHelper& OQuery::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* OQuery::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ // our own props
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+rtl::Reference<OColumn> OQuery::createColumn(const OUString& /*_rName*/) const
+{
+ return nullptr;
+}
+
+void SAL_CALL OQuery::rename( const OUString& newName )
+{
+ MutexGuard aGuard(m_aMutex);
+ Reference<XRename> xRename(m_xCommandDefinition,UNO_QUERY);
+ OSL_ENSURE(xRename.is(),"No XRename interface!");
+ if(xRename.is())
+ xRename->rename(newName);
+}
+
+void OQuery::registerProperties()
+{
+ // the properties which OCommandBase supplies (it has no own registration, as it's not derived from
+ // an OPropertyStateContainer)
+ registerProperty(PROPERTY_NAME, PROPERTY_ID_NAME, PropertyAttribute::BOUND|PropertyAttribute::CONSTRAINED,
+ &m_sElementName, cppu::UnoType<decltype(m_sElementName)>::get());
+
+ registerProperty(PROPERTY_COMMAND, PROPERTY_ID_COMMAND, PropertyAttribute::BOUND,
+ &m_sCommand, cppu::UnoType<decltype(m_sCommand)>::get());
+
+ registerProperty(PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::BOUND,
+ &m_bEscapeProcessing, cppu::UnoType<bool>::get());
+
+ registerProperty(PROPERTY_UPDATE_TABLENAME, PROPERTY_ID_UPDATE_TABLENAME, PropertyAttribute::BOUND,
+ &m_sUpdateTableName, cppu::UnoType<decltype(m_sUpdateTableName)>::get());
+
+ registerProperty(PROPERTY_UPDATE_SCHEMANAME, PROPERTY_ID_UPDATE_SCHEMANAME, PropertyAttribute::BOUND,
+ &m_sUpdateSchemaName, cppu::UnoType<decltype(m_sUpdateSchemaName)>::get());
+
+ registerProperty(PROPERTY_UPDATE_CATALOGNAME, PROPERTY_ID_UPDATE_CATALOGNAME, PropertyAttribute::BOUND,
+ &m_sUpdateCatalogName, cppu::UnoType<decltype(m_sUpdateCatalogName)>::get());
+
+ registerProperty(PROPERTY_LAYOUTINFORMATION, PROPERTY_ID_LAYOUTINFORMATION, PropertyAttribute::BOUND,
+ &m_aLayoutInformation, cppu::UnoType<decltype(m_aLayoutInformation)>::get());
+}
+
+OUString OQuery::determineContentType() const
+{
+ return "application/vnd.org.openoffice.DatabaseQuery";
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/query.hxx b/dbaccess/source/core/api/query.hxx
new file mode 100644
index 000000000..fefcb94b4
--- /dev/null
+++ b/dbaccess/source/core/api/query.hxx
@@ -0,0 +1,147 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "querydescriptor.hxx"
+#include <cppuhelper/implbase3.hxx>
+#include <rtl/ref.hxx>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbcx/XRename.hpp>
+#include <ContentHelper.hxx>
+
+#include <map>
+
+namespace dbtools
+{
+ class WarningsContainer;
+}
+
+namespace dbaccess
+{
+
+// OQuery - an object implementing the sdb.Query service
+typedef ::cppu::ImplHelper3 < css::sdbcx::XDataDescriptorFactory,
+ css::beans::XPropertyChangeListener,
+ css::sdbcx::XRename
+ > OQuery_Base;
+class OQuery;
+class OColumn;
+typedef ::comphelper::OPropertyArrayUsageHelper< OQuery > OQuery_ArrayHelperBase;
+
+class OQuery :public OContentHelper
+ ,public OQueryDescriptor_Base
+ ,public OQuery_Base
+ ,public OQuery_ArrayHelperBase
+ ,public ODataSettings
+{
+ friend struct TRelease;
+
+protected:
+ css::uno::Reference< css::beans::XPropertySet > m_xCommandDefinition;
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+ css::uno::Reference< css::beans::XPropertySetInfo > m_xCommandPropInfo;
+ ::rtl::Reference< OContainerMediator > m_pColumnMediator;
+ ::dbtools::WarningsContainer* m_pWarnings;
+
+ // possible actions on our "aggregate"
+ enum class AggregateAction { NONE, SettingProperties };
+ AggregateAction m_eDoingCurrently;
+
+ /** a class which automatically resets m_eDoingCurrently in its destructor
+ */
+ class OAutoActionReset; // just for the following friend declaration
+ friend class OAutoActionReset;
+ class OAutoActionReset
+ {
+ OQuery& m_rActor;
+ public:
+ explicit OAutoActionReset(OQuery& _rActor) : m_rActor(_rActor) { }
+ ~OAutoActionReset() { m_rActor.m_eDoingCurrently = AggregateAction::NONE; }
+ };
+
+protected:
+ virtual ~OQuery() override;
+
+// OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+ using OQuery_ArrayHelperBase::getArrayHelper;
+
+public:
+ OQuery(
+ const css::uno::Reference< css::beans::XPropertySet >& _rxCommandDefinition,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConn,
+ const css::uno::Reference< css::uno::XComponentContext >& _xORB
+ );
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+// css::uno::XInterface
+ DECLARE_XINTERFACE( )
+
+// css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+// OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+// css::lang::XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+// css::sdbcx::XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+
+// css::beans::XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+
+// css::lang::XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& _rSource ) override;
+
+// OPropertySetHelper
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+
+public:
+ // the caller is responsible for the lifetime!
+ void setWarningsContainer( ::dbtools::WarningsContainer* _pWarnings ) { m_pWarnings = _pWarnings; }
+
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+protected:
+ virtual void SAL_CALL disposing() override;
+
+ virtual rtl::Reference<OColumn> createColumn(const OUString& _rName) const override;
+
+ virtual void rebuildColumns( ) override;
+
+ // OContentHelper overridables
+ virtual OUString determineContentType() const override;
+
+private:
+ void registerProperties();
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/querycomposer.cxx b/dbaccess/source/core/api/querycomposer.cxx
new file mode 100644
index 000000000..8bab87187
--- /dev/null
+++ b/dbaccess/source/core/api/querycomposer.cxx
@@ -0,0 +1,265 @@
+/* -*- 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/lang/DisposedException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdbc/ColumnSearch.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <comphelper/sequence.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <unotools/configmgr.hxx>
+#include <comphelper/types.hxx>
+#include <com/sun/star/sdb/SQLFilterOperator.hpp>
+#include <querycomposer.hxx>
+#include <strings.hxx>
+#include <composertools.hxx>
+#include <algorithm>
+
+using namespace dbaccess;
+using namespace comphelper;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::lang;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace ::utl;
+
+
+OQueryComposer::OQueryComposer(const Reference< XConnection>& _xConnection)
+ : OSubComponent(m_aMutex,_xConnection)
+{
+ OSL_ENSURE(_xConnection.is()," Connection can't be null!");
+
+ Reference<XMultiServiceFactory> xFac( _xConnection, UNO_QUERY_THROW );
+ m_xComposer.set( xFac->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW );
+ m_xComposerHelper.set( xFac->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW );
+}
+
+OQueryComposer::~OQueryComposer()
+{
+}
+
+void SAL_CALL OQueryComposer::disposing()
+{
+ ::comphelper::disposeComponent(m_xComposerHelper);
+ ::comphelper::disposeComponent(m_xComposer);
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > SAL_CALL OQueryComposer::getTypes()
+{
+ return ::comphelper::concatSequences(OSubComponent::getTypes(),OQueryComposer_BASE::getTypes());
+}
+
+Sequence< sal_Int8 > SAL_CALL OQueryComposer::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Any SAL_CALL OQueryComposer::queryInterface( const Type & rType )
+{
+ Any aRet = OSubComponent::queryInterface(rType);
+ if(!aRet.hasValue())
+ aRet = OQueryComposer_BASE::queryInterface(rType);
+ return aRet;
+}
+
+// XServiceInfo
+OUString OQueryComposer::getImplementationName( )
+{
+ return "com.sun.star.sdb.dbaccess.OQueryComposer";
+}
+
+sal_Bool OQueryComposer::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > OQueryComposer::getSupportedServiceNames( )
+{
+ return { SERVICE_SDB_SQLQUERYCOMPOSER };
+}
+
+// XSQLQueryComposer
+OUString SAL_CALL OQueryComposer::getQuery( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ Reference<XPropertySet> xProp(m_xComposer,UNO_QUERY);
+ OUString sQuery;
+ if ( xProp.is() )
+ xProp->getPropertyValue(PROPERTY_ORIGINAL) >>= sQuery;
+ return sQuery;
+}
+
+void SAL_CALL OQueryComposer::setQuery( const OUString& command )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ m_aFilters.clear();
+ m_xComposer->setQuery(command);
+ m_sOrgFilter = m_xComposer->getFilter();
+ m_sOrgOrder = m_xComposer->getOrder();
+}
+
+OUString SAL_CALL OQueryComposer::getComposedQuery( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ MutexGuard aGuard(m_aMutex);
+
+ return m_xComposer->getQuery();
+}
+
+OUString SAL_CALL OQueryComposer::getFilter( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ MutexGuard aGuard(m_aMutex);
+ FilterCreator aFilterCreator;
+ aFilterCreator = std::for_each(m_aFilters.begin(),m_aFilters.end(),aFilterCreator);
+ return aFilterCreator.getComposedAndClear();
+}
+
+Sequence< Sequence< PropertyValue > > SAL_CALL OQueryComposer::getStructuredFilter( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ MutexGuard aGuard(m_aMutex);
+ return m_xComposer->getStructuredFilter();
+}
+
+OUString SAL_CALL OQueryComposer::getOrder( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ OrderCreator aOrderCreator;
+ aOrderCreator = std::for_each(m_aOrders.begin(),m_aOrders.end(),aOrderCreator);
+ return aOrderCreator.getComposedAndClear();
+}
+
+void SAL_CALL OQueryComposer::appendFilterByColumn( const Reference< XPropertySet >& column )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ m_xComposerHelper->setQuery(getQuery());
+ m_xComposerHelper->setFilter(OUString());
+ m_xComposerHelper->appendFilterByColumn(column, true, SQLFilterOperator::EQUAL);
+
+ FilterCreator aFilterCreator;
+ aFilterCreator.append(getFilter());
+ aFilterCreator.append(m_xComposerHelper->getFilter());
+
+ setFilter( aFilterCreator.getComposedAndClear() );
+}
+
+void SAL_CALL OQueryComposer::appendOrderByColumn( const Reference< XPropertySet >& column, sal_Bool ascending )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ m_xComposerHelper->setQuery(getQuery());
+ m_xComposerHelper->setOrder(OUString());
+ m_xComposerHelper->appendOrderByColumn(column,ascending);
+
+ OrderCreator aOrderCreator;
+ aOrderCreator.append(getOrder());
+ aOrderCreator.append(m_xComposerHelper->getOrder());
+
+ setOrder(aOrderCreator.getComposedAndClear());
+}
+
+void SAL_CALL OQueryComposer::setFilter( const OUString& filter )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ FilterCreator aFilterCreator;
+ aFilterCreator.append(m_sOrgFilter);
+ aFilterCreator.append(filter);
+
+ m_aFilters.clear();
+ if ( !filter.isEmpty() )
+ m_aFilters.push_back(filter);
+
+ m_xComposer->setFilter( aFilterCreator.getComposedAndClear() );
+}
+
+void SAL_CALL OQueryComposer::setOrder( const OUString& order )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ OrderCreator aOrderCreator;
+ aOrderCreator.append(m_sOrgOrder);
+ aOrderCreator.append(order);
+
+ m_aOrders.clear();
+ if ( !order.isEmpty() )
+ m_aOrders.push_back(order);
+
+ m_xComposer->setOrder(aOrderCreator.getComposedAndClear());
+}
+
+// XTablesSupplier
+Reference< XNameAccess > SAL_CALL OQueryComposer::getTables( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return Reference<XTablesSupplier>(m_xComposer,UNO_QUERY_THROW)->getTables();
+}
+
+// XColumnsSupplier
+Reference< XNameAccess > SAL_CALL OQueryComposer::getColumns( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return Reference<XColumnsSupplier>(m_xComposer,UNO_QUERY_THROW)->getColumns();
+}
+
+Reference< XIndexAccess > SAL_CALL OQueryComposer::getParameters( )
+{
+ ::connectivity::checkDisposed(OSubComponent::rBHelper.bDisposed);
+
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return Reference<XParametersSupplier>(m_xComposer,UNO_QUERY_THROW)->getParameters();
+}
+
+void SAL_CALL OQueryComposer::acquire() noexcept
+{
+ OSubComponent::acquire();
+}
+
+void SAL_CALL OQueryComposer::release() noexcept
+{
+ OSubComponent::release();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/querycontainer.cxx b/dbaccess/source/core/api/querycontainer.cxx
new file mode 100644
index 000000000..583cab373
--- /dev/null
+++ b/dbaccess/source/core/api/querycontainer.cxx
@@ -0,0 +1,430 @@
+/* -*- 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 <querycontainer.hxx>
+#include "query.hxx"
+#include <strings.hxx>
+#include <objectnameapproval.hxx>
+#include <veto.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/container/XContainerApproveBroadcaster.hpp>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdb/QueryDefinition.hpp>
+
+#include <osl/diagnose.h>
+#include <comphelper/uno3.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+
+using namespace dbtools;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+namespace dbaccess
+{
+
+// OQueryContainer
+
+OQueryContainer::OQueryContainer(
+ const Reference< XNameContainer >& _rxCommandDefinitions
+ , const Reference< XConnection >& _rxConn
+ , const Reference< XComponentContext >& _rxORB,
+ ::dbtools::WarningsContainer* _pWarnings)
+ :ODefinitionContainer(_rxORB,nullptr,std::make_shared<ODefinitionContainer_Impl>())
+ ,m_pWarnings( _pWarnings )
+ ,m_xCommandDefinitions(_rxCommandDefinitions)
+ ,m_xConnection(_rxConn)
+ ,m_eDoingCurrently(AggregateAction::NONE)
+{
+}
+
+void OQueryContainer::init()
+{
+ Reference< XContainer > xContainer( m_xCommandDefinitions, UNO_QUERY_THROW );
+ xContainer->addContainerListener( this );
+
+ Reference< XContainerApproveBroadcaster > xContainerApprove( m_xCommandDefinitions, UNO_QUERY_THROW );
+ xContainerApprove->addContainerApproveListener( this );
+
+ // fill my structures
+ ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
+ Sequence< OUString > sDefinitionNames = m_xCommandDefinitions->getElementNames();
+ const OUString* pDefinitionName = sDefinitionNames.getConstArray();
+ const OUString* pEnd = pDefinitionName + sDefinitionNames.getLength();
+ for ( ; pDefinitionName != pEnd; ++pDefinitionName )
+ {
+ rDefinitions.insert( *pDefinitionName, TContentPtr() );
+ m_aDocuments.push_back(m_aDocumentMap.emplace( *pDefinitionName,Documents::mapped_type()).first);
+ }
+
+ setElementApproval( std::make_shared<ObjectNameApproval>( m_xConnection, ObjectNameApproval::TypeQuery ) );
+}
+
+rtl::Reference<OQueryContainer> OQueryContainer::create(
+ const Reference< XNameContainer >& _rxCommandDefinitions
+ , const Reference< XConnection >& _rxConn
+ , const Reference< XComponentContext >& _rxORB,
+ ::dbtools::WarningsContainer* _pWarnings)
+{
+ rtl::Reference c(
+ new OQueryContainer(
+ _rxCommandDefinitions, _rxConn, _rxORB, _pWarnings));
+ c->init();
+ return c;
+}
+
+OQueryContainer::~OQueryContainer()
+{
+ // dispose();
+ // maybe we're already disposed, but this should be uncritical
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( OQueryContainer,ODefinitionContainer,OQueryContainer_Base)
+
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( OQueryContainer,ODefinitionContainer,OQueryContainer_Base)
+
+void OQueryContainer::disposing()
+{
+ ODefinitionContainer::disposing();
+ MutexGuard aGuard(m_aMutex);
+ if ( !m_xCommandDefinitions.is() )
+ // already disposed
+ return;
+
+ Reference< XContainer > xContainer( m_xCommandDefinitions, UNO_QUERY );
+ xContainer->removeContainerListener( this );
+ Reference< XContainerApproveBroadcaster > xContainerApprove( m_xCommandDefinitions, UNO_QUERY );
+ xContainerApprove->removeContainerApproveListener( this );
+
+ m_xCommandDefinitions = nullptr;
+ m_xConnection = nullptr;
+}
+
+// XServiceInfo
+OUString SAL_CALL OQueryContainer::getImplementationName()
+ {
+ return "com.sun.star.sdb.dbaccess.OQueryContainer";
+ }
+sal_Bool SAL_CALL OQueryContainer::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL OQueryContainer::getSupportedServiceNames()
+{
+ return { SERVICE_SDBCX_CONTAINER, SERVICE_SDB_QUERIES };
+}
+
+// XDataDescriptorFactory
+Reference< XPropertySet > SAL_CALL OQueryContainer::createDataDescriptor( )
+{
+ return new OQueryDescriptor();
+}
+
+// XAppend
+void SAL_CALL OQueryContainer::appendByDescriptor( const Reference< XPropertySet >& _rxDesc )
+{
+ ResettableMutexGuard aGuard(m_aMutex);
+ if ( !m_xCommandDefinitions.is() )
+ throw DisposedException( OUString(), *this );
+
+ // first clone this object's CommandDefinition part
+ Reference< css::sdb::XQueryDefinition > xCommandDefinitionPart = css::sdb::QueryDefinition::create(m_aContext);
+
+ ::comphelper::copyProperties( _rxDesc, Reference<XPropertySet>(xCommandDefinitionPart, UNO_QUERY_THROW) );
+ // TODO : the columns part of the descriptor has to be copied
+
+ // create a wrapper for the object (*before* inserting into our command definition container)
+ Reference< XContent > xNewObject( implCreateWrapper( Reference< XContent>( xCommandDefinitionPart, UNO_QUERY_THROW ) ) );
+
+ OUString sNewObjectName;
+ _rxDesc->getPropertyValue(PROPERTY_NAME) >>= sNewObjectName;
+
+ try
+ {
+ notifyByName( aGuard, sNewObjectName, xNewObject, nullptr, E_INSERTED, ApproveListeners );
+ }
+ catch (const WrappedTargetException& e)
+ {
+ disposeComponent( xNewObject );
+ disposeComponent( xCommandDefinitionPart );
+ throw WrappedTargetRuntimeException(e.Message, e.Context, e.TargetException);
+ }
+ catch (const Exception&)
+ {
+ disposeComponent( xNewObject );
+ disposeComponent( xCommandDefinitionPart );
+ throw;
+ }
+
+ // insert the basic object into the definition container
+ {
+ m_eDoingCurrently = AggregateAction::Inserting;
+ OAutoActionReset aAutoReset(*this);
+ m_xCommandDefinitions->insertByName(sNewObjectName, Any(xCommandDefinitionPart));
+ }
+
+ implAppend( sNewObjectName, xNewObject );
+ try
+ {
+ notifyByName( aGuard, sNewObjectName, xNewObject, nullptr, E_INSERTED, ContainerListemers );
+ }
+ catch (const WrappedTargetException& e)
+ {
+ throw WrappedTargetRuntimeException(e.Message, e.Context, e.TargetException);
+ }
+}
+
+// XDrop
+void SAL_CALL OQueryContainer::dropByName( const OUString& _rName )
+{
+ MutexGuard aGuard(m_aMutex);
+ if ( !checkExistence(_rName) )
+ throw NoSuchElementException(_rName,*this);
+
+ if ( !m_xCommandDefinitions.is() )
+ throw DisposedException( OUString(), *this );
+
+ // now simply forward the remove request to the CommandDefinition container, we're a listener for the removal
+ // and thus we do everything necessary in ::elementRemoved
+ m_xCommandDefinitions->removeByName(_rName);
+}
+
+void SAL_CALL OQueryContainer::dropByIndex( sal_Int32 _nIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+ if ((_nIndex<0) || (_nIndex>getCount()))
+ throw IndexOutOfBoundsException();
+
+ if ( !m_xCommandDefinitions.is() )
+ throw DisposedException( OUString(), *this );
+
+ OUString sName;
+ Reference<XPropertySet> xProp(Reference<XIndexAccess>(m_xCommandDefinitions,UNO_QUERY_THROW)->getByIndex(_nIndex),UNO_QUERY);
+ if ( xProp.is() )
+ xProp->getPropertyValue(PROPERTY_NAME) >>= sName;
+
+ dropByName(sName);
+}
+
+void SAL_CALL OQueryContainer::elementInserted( const css::container::ContainerEvent& _rEvent )
+{
+ Reference< XContent > xNewElement;
+ OUString sElementName;
+ _rEvent.Accessor >>= sElementName;
+ {
+ MutexGuard aGuard(m_aMutex);
+ if (AggregateAction::Inserting == m_eDoingCurrently)
+ // nothing to do, we're inserting via an "appendByDescriptor"
+ return;
+
+ OSL_ENSURE(!sElementName.isEmpty(), "OQueryContainer::elementInserted : invalid name !");
+ OSL_ENSURE(m_aDocumentMap.find(sElementName) == m_aDocumentMap.end(), "OQueryContainer::elementInserted : oops... we're inconsistent with our master container !");
+ if (sElementName.isEmpty() || hasByName(sElementName))
+ return;
+
+ // insert an own new element
+ xNewElement = implCreateWrapper(sElementName);
+ }
+ insertByName(sElementName,Any(xNewElement));
+}
+
+void SAL_CALL OQueryContainer::elementRemoved( const css::container::ContainerEvent& _rEvent )
+{
+ OUString sAccessor;
+ _rEvent.Accessor >>= sAccessor;
+ {
+ OSL_ENSURE(!sAccessor.isEmpty(), "OQueryContainer::elementRemoved : invalid name !");
+ OSL_ENSURE(m_aDocumentMap.find(sAccessor) != m_aDocumentMap.end(), "OQueryContainer::elementRemoved : oops... we're inconsistent with our master container !");
+ if ( sAccessor.isEmpty() || !hasByName(sAccessor) )
+ return;
+ }
+ removeByName(sAccessor);
+}
+
+void SAL_CALL OQueryContainer::elementReplaced( const css::container::ContainerEvent& _rEvent )
+{
+ Reference< XContent > xNewElement;
+ OUString sAccessor;
+ _rEvent.Accessor >>= sAccessor;
+
+ {
+ MutexGuard aGuard(m_aMutex);
+ OSL_ENSURE(!sAccessor.isEmpty(), "OQueryContainer::elementReplaced : invalid name !");
+ OSL_ENSURE(m_aDocumentMap.find(sAccessor) != m_aDocumentMap.end(), "OQueryContainer::elementReplaced : oops... we're inconsistent with our master container !");
+ if (sAccessor.isEmpty() || !hasByName(sAccessor))
+ return;
+
+ xNewElement = implCreateWrapper(sAccessor);
+ }
+
+ replaceByName(sAccessor,Any(xNewElement));
+}
+
+Reference< XVeto > SAL_CALL OQueryContainer::approveInsertElement( const ContainerEvent& Event )
+{
+ OUString sName;
+ OSL_VERIFY( Event.Accessor >>= sName );
+ Reference< XContent > xElement( Event.Element, UNO_QUERY_THROW );
+
+ Reference< XVeto > xReturn;
+ try
+ {
+ getElementApproval()->approveElement( sName );
+ }
+ catch( const Exception& )
+ {
+ xReturn = new Veto( ::cppu::getCaughtException() );
+ }
+ return xReturn;
+}
+
+Reference< XVeto > SAL_CALL OQueryContainer::approveReplaceElement( const ContainerEvent& /*Event*/ )
+{
+ return nullptr;
+}
+
+Reference< XVeto > SAL_CALL OQueryContainer::approveRemoveElement( const ContainerEvent& /*Event*/ )
+{
+ return nullptr;
+}
+
+void SAL_CALL OQueryContainer::disposing( const css::lang::EventObject& _rSource )
+{
+ if (_rSource.Source.get() == Reference< XInterface >(m_xCommandDefinitions, UNO_QUERY).get())
+ { // our "master container" (with the command definitions) is being disposed
+ OSL_FAIL("OQueryContainer::disposing : nobody should dispose the CommandDefinition container before disposing my connection !");
+ dispose();
+ }
+ else
+ {
+ Reference< XContent > xSource(_rSource.Source, UNO_QUERY);
+ // it's one of our documents...
+ for (auto const& document : m_aDocumentMap)
+ {
+ if ( xSource == document.second.get() )
+ {
+ m_xCommandDefinitions->removeByName(document.first);
+ break;
+ }
+ }
+ ODefinitionContainer::disposing(_rSource);
+ }
+}
+
+OUString OQueryContainer::determineContentType() const
+{
+ return "application/vnd.org.openoffice.DatabaseQueryContainer";
+}
+
+Reference< XContent > OQueryContainer::implCreateWrapper(const OUString& _rName)
+{
+ Reference< XContent > xObject(m_xCommandDefinitions->getByName(_rName),UNO_QUERY);
+ return implCreateWrapper(xObject);
+}
+
+Reference< XContent > OQueryContainer::implCreateWrapper(const Reference< XContent >& _rxCommandDesc)
+{
+ Reference<XNameContainer> xContainer(_rxCommandDesc,UNO_QUERY);
+ Reference< XContent > xReturn;
+ if ( xContainer .is() )
+ {
+ xReturn = create( xContainer, m_xConnection, m_aContext, m_pWarnings ).
+ get();
+ }
+ else
+ {
+ rtl::Reference<OQuery> pNewObject = new OQuery( Reference< XPropertySet >( _rxCommandDesc, UNO_QUERY ), m_xConnection, m_aContext );
+ xReturn = pNewObject;
+
+ pNewObject->setWarningsContainer( m_pWarnings );
+// pNewObject->getColumns();
+ // Why? This is expensive. If you comment this in 'cause you really need it, be sure to run the
+ // QueryInQuery test in dbaccess/qa/complex/dbaccess ...
+ }
+
+ return xReturn;
+}
+
+Reference< XContent > OQueryContainer::createObject( const OUString& _rName)
+{
+ return implCreateWrapper(_rName);
+}
+
+bool OQueryContainer::checkExistence(const OUString& _rName)
+{
+ bool bRet = false;
+ if ( !m_bInPropertyChange )
+ {
+ bRet = m_xCommandDefinitions->hasByName(_rName);
+ Documents::const_iterator aFind = m_aDocumentMap.find(_rName);
+ if ( !bRet && aFind != m_aDocumentMap.end() )
+ {
+ m_aDocuments.erase( std::find(m_aDocuments.begin(),m_aDocuments.end(),aFind));
+ m_aDocumentMap.erase(aFind);
+ }
+ else if ( bRet && aFind == m_aDocumentMap.end() )
+ {
+ implAppend(_rName,nullptr);
+ }
+ }
+ return bRet;
+}
+
+sal_Bool SAL_CALL OQueryContainer::hasElements( )
+{
+ MutexGuard aGuard(m_aMutex);
+ return m_xCommandDefinitions->hasElements();
+}
+
+sal_Int32 SAL_CALL OQueryContainer::getCount( )
+{
+ MutexGuard aGuard(m_aMutex);
+ return Reference<XIndexAccess>(m_xCommandDefinitions,UNO_QUERY_THROW)->getCount();
+}
+
+Sequence< OUString > SAL_CALL OQueryContainer::getElementNames( )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ return m_xCommandDefinitions->getElementNames();
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/querydescriptor.cxx b/dbaccess/source/core/api/querydescriptor.cxx
new file mode 100644
index 000000000..0ac6d76e3
--- /dev/null
+++ b/dbaccess/source/core/api/querydescriptor.cxx
@@ -0,0 +1,269 @@
+/* -*- 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 "querydescriptor.hxx"
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::awt;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::osl;
+using namespace ::cppu;
+
+namespace dbaccess
+{
+
+// OQueryDescriptor
+
+OQueryDescriptor::OQueryDescriptor()
+ :OQueryDescriptor_Base(m_aMutex,*this)
+ ,ODataSettings(m_aBHelper,true)
+{
+ registerProperties();
+ ODataSettings::registerPropertiesFor(this);
+}
+
+OQueryDescriptor::OQueryDescriptor(const OQueryDescriptor_Base& _rSource)
+ :OQueryDescriptor_Base(_rSource,*this)
+ ,ODataSettings(m_aBHelper,true)
+{
+ registerProperties();
+ ODataSettings::registerPropertiesFor(this);
+}
+
+OQueryDescriptor::~OQueryDescriptor()
+{
+}
+
+css::uno::Sequence<sal_Int8> OQueryDescriptor::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+css::uno::Sequence< css::uno::Type > OQueryDescriptor::getTypes()
+{
+ return ::comphelper::concatSequences(
+ OQueryDescriptor_Base::getTypes( ),
+ ODataSettings::getTypes( )
+ );
+}
+
+IMPLEMENT_FORWARD_XINTERFACE3( OQueryDescriptor,OWeakObject,OQueryDescriptor_Base,ODataSettings)
+
+void OQueryDescriptor::registerProperties()
+{
+ // the properties which OCommandBase supplies (it has no own registration, as it's not derived from
+ // an OPropertyStateContainer)
+ registerProperty(PROPERTY_NAME, PROPERTY_ID_NAME, PropertyAttribute::BOUND|PropertyAttribute::CONSTRAINED,
+ &m_sElementName, cppu::UnoType<decltype(m_sElementName)>::get());
+
+ registerProperty(PROPERTY_COMMAND, PROPERTY_ID_COMMAND, PropertyAttribute::BOUND,
+ &m_sCommand, cppu::UnoType<decltype(m_sCommand)>::get());
+
+ registerProperty(PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::BOUND,
+ &m_bEscapeProcessing, cppu::UnoType<bool>::get());
+
+ registerProperty(PROPERTY_UPDATE_TABLENAME, PROPERTY_ID_UPDATE_TABLENAME, PropertyAttribute::BOUND,
+ &m_sUpdateTableName, cppu::UnoType<decltype(m_sUpdateTableName)>::get());
+
+ registerProperty(PROPERTY_UPDATE_SCHEMANAME, PROPERTY_ID_UPDATE_SCHEMANAME, PropertyAttribute::BOUND,
+ &m_sUpdateSchemaName, cppu::UnoType<decltype(m_sUpdateSchemaName)>::get());
+
+ registerProperty(PROPERTY_UPDATE_CATALOGNAME, PROPERTY_ID_UPDATE_CATALOGNAME, PropertyAttribute::BOUND,
+ &m_sUpdateCatalogName, cppu::UnoType<decltype(m_sUpdateCatalogName)>::get());
+
+ registerProperty(PROPERTY_LAYOUTINFORMATION, PROPERTY_ID_LAYOUTINFORMATION, PropertyAttribute::BOUND,
+ &m_aLayoutInformation, cppu::UnoType<decltype(m_aLayoutInformation)>::get());
+}
+
+Reference< XPropertySetInfo > SAL_CALL OQueryDescriptor::getPropertySetInfo( )
+{
+ return createPropertySetInfo( getInfoHelper() ) ;
+}
+
+::cppu::IPropertyArrayHelper& OQueryDescriptor::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+::cppu::IPropertyArrayHelper* OQueryDescriptor::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+
+OQueryDescriptor_Base::OQueryDescriptor_Base(::osl::Mutex& _rMutex,::cppu::OWeakObject& _rMySelf)
+ :m_bColumnsOutOfDate(true)
+ ,m_rMutex(_rMutex)
+{
+ m_pColumns.reset( new OColumns(_rMySelf, m_rMutex, true,std::vector< OUString>(), this,this) );
+}
+
+OQueryDescriptor_Base::OQueryDescriptor_Base(const OQueryDescriptor_Base& _rSource,::cppu::OWeakObject& _rMySelf)
+ :m_bColumnsOutOfDate(true)
+ ,m_rMutex(_rSource.m_rMutex)
+{
+ m_pColumns.reset( new OColumns(_rMySelf, m_rMutex, true,std::vector< OUString>(), this,this) );
+
+ m_sCommand = _rSource.m_sCommand;
+ m_bEscapeProcessing = _rSource.m_bEscapeProcessing;
+ m_sUpdateTableName = _rSource.m_sUpdateTableName;
+ m_sUpdateSchemaName = _rSource.m_sUpdateSchemaName;
+ m_sUpdateCatalogName = _rSource.m_sUpdateCatalogName;
+ m_aLayoutInformation = _rSource.m_aLayoutInformation;
+}
+
+OQueryDescriptor_Base::~OQueryDescriptor_Base()
+{
+ m_pColumns->acquire();
+ m_pColumns->disposing();
+}
+
+sal_Int64 SAL_CALL OQueryDescriptor_Base::getSomething( const Sequence< sal_Int8 >& _rIdentifier )
+{
+ return comphelper::getSomethingImpl(_rIdentifier, this);
+}
+
+const css::uno::Sequence<sal_Int8> & OQueryDescriptor_Base::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit aId;
+ return aId.getSeq();
+}
+
+css::uno::Sequence<sal_Int8> OQueryDescriptor_Base::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+void OQueryDescriptor_Base::setColumnsOutOfDate( bool _bOutOfDate )
+{
+ m_bColumnsOutOfDate = _bOutOfDate;
+ if ( !m_bColumnsOutOfDate )
+ m_pColumns->setInitialized();
+}
+
+void OQueryDescriptor_Base::implAppendColumn( const OUString& _rName, OColumn* _pColumn )
+{
+ m_pColumns->append( _rName, _pColumn );
+}
+
+void OQueryDescriptor_Base::clearColumns( )
+{
+ m_pColumns->clearColumns();
+
+ setColumnsOutOfDate();
+}
+
+Reference< XNameAccess > SAL_CALL OQueryDescriptor_Base::getColumns( )
+{
+ MutexGuard aGuard(m_rMutex);
+
+ if ( m_bColumnsOutOfDate )
+ {
+ // clear the current columns
+ clearColumns();
+
+ // do this before rebuildColumns. This prevents recursion, e.g. in the case where we
+ // have queries with cyclic references:
+ // foo := SELECT * FROM bar
+ // bar := SELECT * FROM foo
+ setColumnsOutOfDate( false );
+
+ // rebuild them
+ try
+ {
+ rebuildColumns();
+ }
+ catch ( const Exception& )
+ {
+ setColumnsOutOfDate();
+ throw;
+ }
+ }
+
+ return m_pColumns.get();
+}
+
+OUString SAL_CALL OQueryDescriptor_Base::getImplementationName( )
+{
+ return "com.sun.star.sdb.OQueryDescriptor";
+}
+
+sal_Bool SAL_CALL OQueryDescriptor_Base::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > SAL_CALL OQueryDescriptor_Base::getSupportedServiceNames( )
+{
+ return { SERVICE_SDB_DATASETTINGS, SERVICE_SDB_QUERYDESCRIPTOR };
+}
+
+void OQueryDescriptor_Base::disposeColumns()
+{
+ m_pColumns->disposing();
+}
+
+void OQueryDescriptor_Base::columnAppended( const Reference< XPropertySet >& /*_rxSourceDescriptor*/ )
+{
+ // not interested in
+}
+
+void OQueryDescriptor_Base::columnDropped(const OUString& /*_sName*/)
+{
+ // not interested in
+}
+
+Reference< XPropertySet > OQueryDescriptor_Base::createColumnDescriptor()
+{
+ OSL_FAIL( "OQueryDescriptor_Base::createColumnDescriptor: called why?" );
+ return nullptr;
+}
+
+void OQueryDescriptor_Base::rebuildColumns( )
+{
+}
+
+// IRefreshableColumns
+void OQueryDescriptor_Base::refreshColumns()
+{
+ MutexGuard aGuard( m_rMutex );
+
+ clearColumns();
+ rebuildColumns();
+}
+
+rtl::Reference<OColumn> OQueryDescriptor_Base::createColumn( const OUString& /*_rName*/ ) const
+{
+ // creating a column/descriptor for a query/descriptor does not make sense at all
+ return nullptr;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/querydescriptor.hxx b/dbaccess/source/core/api/querydescriptor.hxx
new file mode 100644
index 000000000..e78b035da
--- /dev/null
+++ b/dbaccess/source/core/api/querydescriptor.hxx
@@ -0,0 +1,143 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <cppuhelper/implbase3.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <osl/mutex.hxx>
+
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+
+#include <apitools.hxx>
+#include <column.hxx>
+#include <datasettings.hxx>
+#include <commandbase.hxx>
+#include <comphelper/broadcasthelper.hxx>
+#include <comphelper/uno3.hxx>
+
+namespace dbaccess
+{
+
+// OQueryDescriptor_Base - a query descriptor (as the name suggests :)
+typedef ::cppu::ImplHelper3<
+ css::sdbcx::XColumnsSupplier,
+ css::lang::XUnoTunnel,
+ css::lang::XServiceInfo > OQueryDescriptor_BASE;
+
+class OQueryDescriptor_Base
+ :public OQueryDescriptor_BASE
+ ,public OCommandBase
+ ,public IColumnFactory
+ ,public ::connectivity::sdbcx::IRefreshableColumns
+{
+private:
+ bool m_bColumnsOutOfDate : 1; // the columns have to be rebuild on the next getColumns ?
+ ::osl::Mutex& m_rMutex;
+
+protected:
+ std::unique_ptr<OColumns> m_pColumns; // our column descriptions
+ OUString m_sElementName;
+ virtual ~OQueryDescriptor_Base();
+
+ void setColumnsOutOfDate( bool _bOutOfDate = true );
+
+ sal_Int32 getColumnCount() const { return m_pColumns ? m_pColumns->getCount() : 0; }
+ void clearColumns( );
+
+ void implAppendColumn( const OUString& _rName, OColumn* _pColumn );
+
+public:
+ OQueryDescriptor_Base(::osl::Mutex& _rMutex,::cppu::OWeakObject& _rMySelf);
+ /** constructs the object with a UNO QueryDescriptor. If you use this ctor, the resulting object
+ won't have any column information (the column container will be empty)
+ */
+ OQueryDescriptor_Base(const OQueryDescriptor_Base& _rSource,::cppu::OWeakObject& _rMySelf);
+
+// css::sdbcx::XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+
+// css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+
+// css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+protected:
+
+// IColumnFactory
+ virtual rtl::Reference<OColumn> createColumn(const OUString& _rName) const override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createColumnDescriptor() override;
+ virtual void columnAppended( const css::uno::Reference< css::beans::XPropertySet >& _rxSourceDescriptor ) override;
+ virtual void columnDropped(const OUString& _sName) override;
+
+ /** rebuild our columns set
+
+ clearColumns has already been called before, do <em>NOT</em> call it, again
+ */
+ virtual void rebuildColumns( );
+
+ void disposeColumns();
+
+ // IRefreshableColumns overridables
+ virtual void refreshColumns() override;
+};
+
+class OQueryDescriptor : public comphelper::OMutexAndBroadcastHelper
+ ,public ::cppu::OWeakObject
+ ,public OQueryDescriptor_Base
+ ,public ::comphelper::OPropertyArrayUsageHelper< OQueryDescriptor_Base >
+ ,public ODataSettings
+{
+ OQueryDescriptor(const OQueryDescriptor&) = delete;
+ void operator =(const OQueryDescriptor&) = delete;
+ // helper
+ void registerProperties();
+protected:
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ virtual ~OQueryDescriptor() override;
+public:
+ OQueryDescriptor();
+ explicit OQueryDescriptor(const OQueryDescriptor_Base& _rSource);
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+// css::uno::XInterface
+ DECLARE_XINTERFACE( )
+
+ // css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+};
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/resultcolumn.cxx b/dbaccess/source/core/api/resultcolumn.cxx
new file mode 100644
index 000000000..938e7d1d3
--- /dev/null
+++ b/dbaccess/source/core/api/resultcolumn.cxx
@@ -0,0 +1,296 @@
+/* -*- 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 "resultcolumn.hxx"
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <tools/diagnose_ex.h>
+#include <stringconstants.hxx>
+#include <strings.hxx>
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+using namespace dbaccess;
+
+
+OResultColumn::OResultColumn( const Reference < XResultSetMetaData >& _xMetaData, sal_Int32 _nPos,
+ const Reference< XDatabaseMetaData >& _rxDBMeta )
+ :OColumn( true )
+ ,m_xMetaData( _xMetaData )
+ ,m_xDBMetaData( _rxDBMeta )
+ ,m_nPos( _nPos )
+{
+}
+
+void OResultColumn::impl_determineIsRowVersion_nothrow()
+{
+ if ( m_aIsRowVersion.hasValue() )
+ return;
+ m_aIsRowVersion <<= false;
+
+ OSL_ENSURE( m_xDBMetaData.is(), "OResultColumn::impl_determineIsRowVersion_nothrow: no DBMetaData!" );
+ if ( !m_xDBMetaData.is() )
+ return;
+
+ try
+ {
+ OUString sCatalog, sSchema, sTable, sColumnName;
+ getPropertyValue( PROPERTY_CATALOGNAME ) >>= sCatalog;
+ getPropertyValue( PROPERTY_SCHEMANAME ) >>= sSchema;
+ getPropertyValue( PROPERTY_TABLENAME ) >>= sTable;
+ getPropertyValue( PROPERTY_NAME ) >>= sColumnName;
+
+ try
+ {
+ Reference< XResultSet > xVersionColumns = m_xDBMetaData->getVersionColumns(
+ Any( sCatalog ), sSchema, sTable );
+ if ( xVersionColumns.is() ) // allowed to be NULL
+ {
+ Reference< XRow > xResultRow( xVersionColumns, UNO_QUERY_THROW );
+ while ( xVersionColumns->next() )
+ {
+ if ( xResultRow->getString( 2 ) == sColumnName )
+ {
+ m_aIsRowVersion <<= true;
+ break;
+ }
+ }
+ }
+ }
+ catch(const SQLException&)
+ {
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+OResultColumn::~OResultColumn()
+{
+}
+
+// css::lang::XTypeProvider
+Sequence< sal_Int8 > OResultColumn::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XServiceInfo
+OUString OResultColumn::getImplementationName( )
+{
+ return "com.sun.star.sdb.OResultColumn";
+}
+
+Sequence< OUString > OResultColumn::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBCX_COLUMN, SERVICE_SDB_RESULTCOLUMN };
+}
+
+// OComponentHelper
+void OResultColumn::disposing()
+{
+ OColumn::disposing();
+
+ MutexGuard aGuard(m_aMutex);
+ m_xMetaData = nullptr;
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* OResultColumn::createArrayHelper( ) const
+{
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ { PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_DISPLAYSIZE, PROPERTY_ID_DISPLAYSIZE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISAUTOINCREMENT, PROPERTY_ID_ISAUTOINCREMENT, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISCASESENSITIVE, PROPERTY_ID_ISCASESENSITIVE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISCURRENCY, PROPERTY_ID_ISCURRENCY, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISDEFINITELYWRITABLE, PROPERTY_ID_ISDEFINITELYWRITABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISNULLABLE, PROPERTY_ID_ISNULLABLE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISREADONLY, PROPERTY_ID_ISREADONLY, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISROWVERSION, PROPERTY_ID_ISROWVERSION, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISSEARCHABLE, PROPERTY_ID_ISSEARCHABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISSIGNED, PROPERTY_ID_ISSIGNED, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_ISWRITABLE, PROPERTY_ID_ISWRITABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_LABEL, PROPERTY_ID_LABEL, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_NAME, PROPERTY_ID_NAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_PRECISION, PROPERTY_ID_PRECISION, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SCALE, PROPERTY_ID_SCALE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SERVICENAME, PROPERTY_ID_SERVICENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TABLENAME, PROPERTY_ID_TABLENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TYPE, PROPERTY_ID_TYPE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_TYPENAME, PROPERTY_ID_TYPENAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY }
+ }
+ };
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& OResultColumn::getInfoHelper()
+{
+ return *static_cast< ::comphelper::OPropertyArrayUsageHelper< OResultColumn >* >(this)->getArrayHelper();
+}
+
+namespace
+{
+ template< typename T >
+ void obtain( Any& _out_rValue, ::std::optional< T > & _rCache, const sal_Int32 _nPos, const Reference < XResultSetMetaData >& _rxResultMeta, T (SAL_CALL XResultSetMetaData::*Getter)( sal_Int32 ) )
+ {
+ if ( !_rCache )
+ _rCache = (_rxResultMeta.get()->*Getter)(_nPos);
+ _out_rValue <<= *_rCache;
+ }
+}
+
+void OResultColumn::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ try
+ {
+ if ( OColumn::isRegisteredProperty( nHandle ) )
+ {
+ OColumn::getFastPropertyValue( rValue, nHandle );
+ }
+ else
+ {
+ switch (nHandle)
+ {
+ case PROPERTY_ID_ISROWVERSION:
+ const_cast< OResultColumn* >( this )->impl_determineIsRowVersion_nothrow();
+ rValue = m_aIsRowVersion;
+ break;
+ case PROPERTY_ID_TABLENAME:
+ rValue <<= m_xMetaData->getTableName(m_nPos);
+ break;
+ case PROPERTY_ID_SCHEMANAME:
+ rValue <<= m_xMetaData->getSchemaName(m_nPos);
+ break;
+ case PROPERTY_ID_CATALOGNAME:
+ rValue <<= m_xMetaData->getCatalogName(m_nPos);
+ break;
+ case PROPERTY_ID_ISSIGNED:
+ obtain( rValue, m_isSigned, m_nPos, m_xMetaData, &XResultSetMetaData::isSigned );
+ break;
+ case PROPERTY_ID_ISCURRENCY:
+ obtain( rValue, m_isCurrency, m_nPos, m_xMetaData, &XResultSetMetaData::isCurrency );
+ break;
+ case PROPERTY_ID_ISSEARCHABLE:
+ obtain( rValue, m_bSearchable, m_nPos, m_xMetaData, &XResultSetMetaData::isSearchable );
+ break;
+ case PROPERTY_ID_ISCASESENSITIVE:
+ obtain( rValue, m_isCaseSensitive, m_nPos, m_xMetaData, &XResultSetMetaData::isCaseSensitive );
+ break;
+ case PROPERTY_ID_ISREADONLY:
+ obtain( rValue, m_isReadOnly, m_nPos, m_xMetaData, &XResultSetMetaData::isReadOnly );
+ break;
+ case PROPERTY_ID_ISWRITABLE:
+ obtain( rValue, m_isWritable, m_nPos, m_xMetaData, &XResultSetMetaData::isWritable );
+ break;
+ case PROPERTY_ID_ISDEFINITELYWRITABLE:
+ obtain( rValue, m_isDefinitelyWritable, m_nPos, m_xMetaData, &XResultSetMetaData::isDefinitelyWritable );
+ break;
+ case PROPERTY_ID_ISAUTOINCREMENT:
+ obtain( rValue, m_isAutoIncrement, m_nPos, m_xMetaData, &XResultSetMetaData::isAutoIncrement );
+ break;
+ case PROPERTY_ID_SERVICENAME:
+ rValue <<= m_xMetaData->getColumnServiceName(m_nPos);
+ break;
+ case PROPERTY_ID_LABEL:
+ obtain( rValue, m_sColumnLabel, m_nPos, m_xMetaData, &XResultSetMetaData::getColumnLabel );
+ break;
+ case PROPERTY_ID_DISPLAYSIZE:
+ obtain( rValue, m_nColumnDisplaySize, m_nPos, m_xMetaData, &XResultSetMetaData::getColumnDisplaySize );
+ break;
+ case PROPERTY_ID_TYPE:
+ obtain( rValue, m_nColumnType, m_nPos, m_xMetaData, &XResultSetMetaData::getColumnType );
+ break;
+ case PROPERTY_ID_PRECISION:
+ obtain( rValue, m_nPrecision, m_nPos, m_xMetaData, &XResultSetMetaData::getPrecision );
+ break;
+ case PROPERTY_ID_SCALE:
+ obtain( rValue, m_nScale, m_nPos, m_xMetaData, &XResultSetMetaData::getScale );
+ break;
+ case PROPERTY_ID_ISNULLABLE:
+ obtain( rValue, m_isNullable, m_nPos, m_xMetaData, &XResultSetMetaData::isNullable );
+ break;
+ case PROPERTY_ID_TYPENAME:
+ rValue <<= m_xMetaData->getColumnTypeName(m_nPos);
+ break;
+ default:
+ OSL_FAIL( "OResultColumn::getFastPropertyValue: unknown property handle!" );
+ break;
+ }
+ }
+ }
+ catch (SQLException& )
+ {
+ // default handling if we caught an exception
+ switch (nHandle)
+ {
+ case PROPERTY_ID_LABEL:
+ case PROPERTY_ID_TYPENAME:
+ case PROPERTY_ID_SERVICENAME:
+ case PROPERTY_ID_TABLENAME:
+ case PROPERTY_ID_SCHEMANAME:
+ case PROPERTY_ID_CATALOGNAME:
+ // empty string'S
+ rValue <<= OUString();
+ break;
+ case PROPERTY_ID_ISROWVERSION:
+ case PROPERTY_ID_ISAUTOINCREMENT:
+ case PROPERTY_ID_ISWRITABLE:
+ case PROPERTY_ID_ISDEFINITELYWRITABLE:
+ case PROPERTY_ID_ISCASESENSITIVE:
+ case PROPERTY_ID_ISSEARCHABLE:
+ case PROPERTY_ID_ISCURRENCY:
+ case PROPERTY_ID_ISSIGNED:
+ {
+ rValue <<= false;
+ } break;
+ case PROPERTY_ID_ISREADONLY:
+ {
+ rValue <<= true;
+ } break;
+ case PROPERTY_ID_SCALE:
+ case PROPERTY_ID_PRECISION:
+ case PROPERTY_ID_DISPLAYSIZE:
+ rValue <<= sal_Int32(0);
+ break;
+ case PROPERTY_ID_TYPE:
+ rValue <<= sal_Int32(DataType::SQLNULL);
+ break;
+ case PROPERTY_ID_ISNULLABLE:
+ rValue <<= ColumnValue::NULLABLE_UNKNOWN;
+ break;
+ }
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/resultcolumn.hxx b/dbaccess/source/core/api/resultcolumn.hxx
new file mode 100644
index 000000000..53803bac8
--- /dev/null
+++ b/dbaccess/source/core/api/resultcolumn.hxx
@@ -0,0 +1,87 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XResultSetMetaData.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <column.hxx>
+#include <optional>
+#include <comphelper/proparrhlp.hxx>
+namespace dbaccess
+{
+
+ // OResultColumn
+
+ class OResultColumn : public OColumn,
+ public ::comphelper::OPropertyArrayUsageHelper < OResultColumn >
+ {
+ protected:
+ css::uno::Reference < css::sdbc::XResultSetMetaData > m_xMetaData;
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xDBMetaData;
+ sal_Int32 m_nPos;
+ css::uno::Any m_aIsRowVersion;
+ mutable ::std::optional< sal_Bool > m_isSigned;
+ mutable ::std::optional< sal_Bool > m_isCurrency;
+ mutable ::std::optional< sal_Bool > m_bSearchable;
+ mutable ::std::optional< sal_Bool > m_isCaseSensitive;
+ mutable ::std::optional< sal_Bool > m_isReadOnly;
+ mutable ::std::optional< sal_Bool > m_isWritable;
+ mutable ::std::optional< sal_Bool > m_isDefinitelyWritable;
+ mutable ::std::optional< sal_Bool > m_isAutoIncrement;
+ mutable ::std::optional< sal_Int32 > m_isNullable;
+ mutable ::std::optional< OUString > m_sColumnLabel;
+ mutable ::std::optional< sal_Int32 > m_nColumnDisplaySize;
+ mutable ::std::optional< sal_Int32 > m_nColumnType;
+ mutable ::std::optional< sal_Int32 > m_nPrecision;
+ mutable ::std::optional< sal_Int32 > m_nScale;
+
+ virtual ~OResultColumn() override;
+ public:
+ OResultColumn(
+ const css::uno::Reference < css::sdbc::XResultSetMetaData >& _xMetaData,
+ sal_Int32 _nPos,
+ const css::uno::Reference< css::sdbc::XDatabaseMetaData >& _rxDBMeta );
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override;
+
+ private:
+ void impl_determineIsRowVersion_nothrow();
+
+ protected:
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/resultset.cxx b/dbaccess/source/core/api/resultset.cxx
new file mode 100644
index 000000000..2fe6cf355
--- /dev/null
+++ b/dbaccess/source/core/api/resultset.cxx
@@ -0,0 +1,994 @@
+/* -*- 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 "resultset.hxx"
+#include <sal/log.hxx>
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbc/ResultSetType.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <comphelper/types.hxx>
+#include <tools/diagnose_ex.h>
+#include "datacolumn.hxx"
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace dbaccess;
+using namespace dbtools;
+
+
+OResultSet::OResultSet(const css::uno::Reference< css::sdbc::XResultSet >& _xResultSet,
+ const css::uno::Reference< css::uno::XInterface >& _xStatement,
+ bool _bCaseSensitive)
+ :OResultSetBase(m_aMutex)
+ ,OPropertySetHelper(OResultSetBase::rBHelper)
+ ,m_xDelegatorResultSet(_xResultSet)
+ ,m_aWarnings( Reference< XWarningsSupplier >( _xResultSet, UNO_QUERY ) )
+ ,m_nResultSetConcurrency(0)
+ ,m_bIsBookmarkable(false)
+{
+ m_pColumns.reset( new OColumns(*this, m_aMutex, _bCaseSensitive, std::vector< OUString>(), nullptr,nullptr) );
+
+ try
+ {
+ m_aStatement = _xStatement;
+ m_xDelegatorResultSetUpdate.set(m_xDelegatorResultSet, css::uno::UNO_QUERY);
+ m_xDelegatorRow.set(m_xDelegatorResultSet, css::uno::UNO_QUERY);
+ m_xDelegatorRowUpdate.set(m_xDelegatorResultSet, css::uno::UNO_QUERY);
+
+ Reference< XPropertySet > xSet(m_xDelegatorResultSet, UNO_QUERY);
+ sal_Int32 nResultSetType(0);
+ xSet->getPropertyValue(PROPERTY_RESULTSETTYPE) >>= nResultSetType;
+ xSet->getPropertyValue(PROPERTY_RESULTSETCONCURRENCY) >>= m_nResultSetConcurrency;
+
+ // test for Bookmarks
+ if (ResultSetType::FORWARD_ONLY != nResultSetType)
+ {
+ Reference <XPropertySetInfo > xInfo(xSet->getPropertySetInfo());
+ if (xInfo->hasPropertyByName(PROPERTY_ISBOOKMARKABLE))
+ {
+ m_bIsBookmarkable = ::comphelper::getBOOL(xSet->getPropertyValue(PROPERTY_ISBOOKMARKABLE));
+ OSL_ENSURE( !m_bIsBookmarkable || Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY).is(),
+ "OResultSet::OResultSet: aggregate is inconsistent in its bookmarkable attribute!" );
+ m_bIsBookmarkable = m_bIsBookmarkable && Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY).is();
+ }
+ }
+ }
+ catch (const Exception&)
+ {
+ }
+}
+
+OResultSet::~OResultSet()
+{
+ m_pColumns->acquire();
+ m_pColumns->disposing();
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > OResultSet::getTypes()
+{
+ OTypeCollection aTypes(cppu::UnoType<XPropertySet>::get(),
+ OResultSetBase::getTypes());
+
+ return aTypes.getTypes();
+}
+
+Sequence< sal_Int8 > OResultSet::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// css::uno::XInterface
+Any OResultSet::queryInterface( const Type & rType )
+{
+ Any aIface = OResultSetBase::queryInterface( rType );
+ if (!aIface.hasValue())
+ aIface = ::cppu::queryInterface(
+ rType,
+ static_cast< XPropertySet * >( this ));
+
+ return aIface;
+}
+
+void OResultSet::acquire() noexcept
+{
+ OResultSetBase::acquire();
+}
+
+void OResultSet::release() noexcept
+{
+ OResultSetBase::release();
+}
+
+
+// OResultSetBase
+void OResultSet::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ MutexGuard aGuard(m_aMutex);
+
+ // free the columns
+ m_pColumns->disposing();
+
+ // close the pending result set
+ Reference< XCloseable > (m_xDelegatorResultSet, UNO_QUERY_THROW)->close();
+
+ m_xDelegatorResultSet = nullptr;
+ m_xDelegatorRow = nullptr;
+ m_xDelegatorRowUpdate = nullptr;
+
+ m_aStatement.clear();
+}
+
+// XCloseable
+void OResultSet::close()
+{
+ {
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+ }
+ dispose();
+}
+
+// XServiceInfo
+OUString OResultSet::getImplementationName( )
+{
+ return "com.sun.star.sdb.OResultSet";
+}
+
+sal_Bool OResultSet::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > OResultSet::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBC_RESULTSET, SERVICE_SDB_RESULTSET };
+}
+
+// css::beans::XPropertySet
+Reference< XPropertySetInfo > OResultSet::getPropertySetInfo()
+{
+ return createPropertySetInfo( getInfoHelper() ) ;
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* OResultSet::createArrayHelper( ) const
+{
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ { PROPERTY_CURSORNAME, PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_FETCHDIRECTION, PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_FETCHSIZE, PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_ISBOOKMARKABLE, PROPERTY_ID_ISBOOKMARKABLE, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_RESULTSETCONCURRENCY, PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_RESULTSETTYPE, PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), css::beans::PropertyAttribute::READONLY }
+ }
+ };
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& OResultSet::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool OResultSet::convertFastPropertyValue(Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
+{
+ // be lazy ...
+ rConvertedValue = rValue;
+ getFastPropertyValue( rOldValue, nHandle );
+ return true;
+}
+
+void OResultSet::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
+{
+ // set it for the driver result set
+ Reference< XPropertySet > xSet(m_xDelegatorResultSet, UNO_QUERY);
+ switch (nHandle)
+ {
+ case PROPERTY_ID_FETCHDIRECTION:
+ xSet->setPropertyValue(PROPERTY_FETCHDIRECTION, rValue);
+ break;
+ case PROPERTY_ID_FETCHSIZE:
+ xSet->setPropertyValue(PROPERTY_FETCHSIZE, rValue);
+ break;
+ default:
+ SAL_WARN("dbaccess", "unknown Property");
+ }
+}
+
+void OResultSet::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_ISBOOKMARKABLE:
+ {
+ rValue <<= m_bIsBookmarkable;
+ } break;
+ default:
+ {
+ // get the property name
+ OUString aPropName;
+ sal_Int16 nAttributes;
+ const_cast<OResultSet*>(this)->getInfoHelper().
+ fillPropertyMembersByHandle(&aPropName, &nAttributes, nHandle);
+ OSL_ENSURE(!aPropName.isEmpty(), "property not found?");
+
+ // now read the value
+ rValue = Reference< XPropertySet >(m_xDelegatorResultSet, UNO_QUERY_THROW)->getPropertyValue(aPropName);
+ }
+ }
+}
+
+// XWarningsSupplier
+Any OResultSet::getWarnings()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+ return m_aWarnings.getWarnings();
+}
+
+void OResultSet::clearWarnings()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+ m_aWarnings.clearWarnings();
+}
+
+// css::sdbc::XResultSetMetaDataSupplier
+Reference< XResultSetMetaData > OResultSet::getMetaData()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return Reference< XResultSetMetaDataSupplier >(m_xDelegatorResultSet, UNO_QUERY_THROW)->getMetaData();
+}
+
+// css::sdbc::XColumnLocate
+sal_Int32 OResultSet::findColumn(const OUString& columnName)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return Reference< XColumnLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->findColumn(columnName);
+}
+
+namespace
+{
+ Reference< XDatabaseMetaData > lcl_getDBMetaDataFromStatement_nothrow( const Reference< XInterface >& _rxStatement )
+ {
+ Reference< XDatabaseMetaData > xDBMetaData;
+ try
+ {
+ Reference< XStatement > xStatement( _rxStatement, UNO_QUERY );
+ Reference< XPreparedStatement > xPreparedStatement( _rxStatement, UNO_QUERY );
+ Reference< XConnection > xConn;
+ if ( xStatement.is() )
+ xConn = xStatement->getConnection();
+ else if ( xPreparedStatement.is() )
+ xConn = xPreparedStatement->getConnection();
+ if ( xConn.is() )
+ xDBMetaData = xConn->getMetaData();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return xDBMetaData;
+ }
+}
+
+// css::sdbcx::XColumnsSupplier
+Reference< css::container::XNameAccess > OResultSet::getColumns()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ // do we have to populate the columns
+ if (!m_pColumns->isInitialized())
+ {
+ // get the metadata
+ Reference< XResultSetMetaData > xMetaData = Reference< XResultSetMetaDataSupplier >(m_xDelegatorResultSet, UNO_QUERY_THROW)->getMetaData();
+
+ sal_Int32 nColCount = 0;
+ // do we have columns
+ try
+ {
+ Reference< XDatabaseMetaData > xDBMetaData( lcl_getDBMetaDataFromStatement_nothrow( getStatement() ) );
+ nColCount = xMetaData->getColumnCount();
+
+ for ( sal_Int32 i = 0; i < nColCount; ++i)
+ {
+ // retrieve the name of the column
+ OUString sName = xMetaData->getColumnName(i + 1);
+ rtl::Reference<ODataColumn> pColumn = new ODataColumn(xMetaData, m_xDelegatorRow, m_xDelegatorRowUpdate, i + 1, xDBMetaData);
+
+ // don't silently assume that the name is unique - result set implementations
+ // are allowed to return duplicate names, but we are required to have
+ // unique column names
+ if ( m_pColumns->hasByName( sName ) )
+ sName = ::dbtools::createUniqueName( m_pColumns.get(), sName );
+
+ m_pColumns->append( sName, pColumn.get() );
+ }
+ }
+ catch ( const SQLException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ m_pColumns->setInitialized();
+
+ #if OSL_DEBUG_LEVEL > 0
+ // some sanity checks. Especially in case we auto-adjusted the column names above,
+ // this might be reasonable
+ try
+ {
+ const Reference< XNameAccess > xColNames( static_cast< XNameAccess* >( m_pColumns.get() ), UNO_SET_THROW );
+ const Sequence< OUString > aNames( xColNames->getElementNames() );
+ SAL_WARN_IF( aNames.getLength() != nColCount, "dbaccess",
+ "OResultSet::getColumns: invalid column count!" );
+ for ( auto const & name : aNames )
+ {
+ Reference< XPropertySet > xColProps( xColNames->getByName( name ), UNO_QUERY_THROW );
+ OUString sName;
+ OSL_VERIFY( xColProps->getPropertyValue( PROPERTY_NAME ) >>= sName );
+ SAL_WARN_IF( sName != name, "dbaccess", "OResultSet::getColumns: invalid column name!" );
+ }
+
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ #endif
+ }
+ return m_pColumns.get();
+}
+
+// css::sdbc::XRow
+sal_Bool OResultSet::wasNull()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->wasNull();
+}
+
+OUString OResultSet::getString(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getString(columnIndex);
+}
+
+sal_Bool OResultSet::getBoolean(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getBoolean(columnIndex);
+}
+
+sal_Int8 OResultSet::getByte(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getByte(columnIndex);
+}
+
+sal_Int16 OResultSet::getShort(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getShort(columnIndex);
+}
+
+sal_Int32 OResultSet::getInt(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getInt(columnIndex);
+}
+
+sal_Int64 OResultSet::getLong(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getLong(columnIndex);
+}
+
+float OResultSet::getFloat(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getFloat(columnIndex);
+}
+
+double OResultSet::getDouble(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getDouble(columnIndex);
+}
+
+Sequence< sal_Int8 > OResultSet::getBytes(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getBytes(columnIndex);
+}
+
+css::util::Date OResultSet::getDate(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getDate(columnIndex);
+}
+
+css::util::Time OResultSet::getTime(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getTime(columnIndex);
+}
+
+css::util::DateTime OResultSet::getTimestamp(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getTimestamp(columnIndex);
+}
+
+Reference< css::io::XInputStream > OResultSet::getBinaryStream(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getBinaryStream(columnIndex);
+}
+
+Reference< css::io::XInputStream > OResultSet::getCharacterStream(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getCharacterStream(columnIndex);
+}
+
+Any OResultSet::getObject(sal_Int32 columnIndex, const Reference< css::container::XNameAccess > & typeMap)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getObject(columnIndex, typeMap);
+}
+
+Reference< XRef > OResultSet::getRef(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getRef(columnIndex);
+}
+
+Reference< XBlob > OResultSet::getBlob(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getBlob(columnIndex);
+}
+
+Reference< XClob > OResultSet::getClob(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getClob(columnIndex);
+}
+
+Reference< XArray > OResultSet::getArray(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorRow->getArray(columnIndex);
+}
+
+// css::sdbc::XRowUpdate
+void OResultSet::updateNull(sal_Int32 columnIndex)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateNull(columnIndex);
+}
+
+void OResultSet::updateBoolean(sal_Int32 columnIndex, sal_Bool x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateBoolean(columnIndex, x);
+}
+
+void OResultSet::updateByte(sal_Int32 columnIndex, sal_Int8 x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateByte(columnIndex, x);
+}
+
+void OResultSet::updateShort(sal_Int32 columnIndex, sal_Int16 x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateShort(columnIndex, x);
+}
+
+void OResultSet::updateInt(sal_Int32 columnIndex, sal_Int32 x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateInt(columnIndex, x);
+}
+
+void OResultSet::updateLong(sal_Int32 columnIndex, sal_Int64 x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateLong(columnIndex, x);
+}
+
+void OResultSet::updateFloat(sal_Int32 columnIndex, float x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateFloat(columnIndex, x);
+}
+
+void OResultSet::updateDouble(sal_Int32 columnIndex, double x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateDouble(columnIndex, x);
+}
+
+void OResultSet::updateString(sal_Int32 columnIndex, const OUString& x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateString(columnIndex, x);
+}
+
+void OResultSet::updateBytes(sal_Int32 columnIndex, const Sequence< sal_Int8 >& x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateBytes(columnIndex, x);
+}
+
+void OResultSet::updateDate(sal_Int32 columnIndex, const css::util::Date& x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateDate(columnIndex, x);
+}
+
+void OResultSet::updateTime(sal_Int32 columnIndex, const css::util::Time& x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateTime(columnIndex, x);
+}
+
+void OResultSet::updateTimestamp(sal_Int32 columnIndex, const css::util::DateTime& x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateTimestamp(columnIndex, x);
+}
+
+void OResultSet::updateBinaryStream(sal_Int32 columnIndex, const Reference< css::io::XInputStream > & x, sal_Int32 length)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateBinaryStream(columnIndex, x, length);
+}
+
+void OResultSet::updateCharacterStream(sal_Int32 columnIndex, const Reference< css::io::XInputStream > & x, sal_Int32 length)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateCharacterStream(columnIndex, x, length);
+}
+
+void OResultSet::updateNumericObject(sal_Int32 columnIndex, const Any& x, sal_Int32 scale)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateNumericObject(columnIndex, x, scale);
+}
+
+void OResultSet::updateObject(sal_Int32 columnIndex, const Any& x)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorRowUpdate->updateObject(columnIndex, x);
+}
+
+// css::sdbc::XResultSet
+sal_Bool OResultSet::next()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->next();
+}
+
+sal_Bool OResultSet::isBeforeFirst()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->isBeforeFirst();
+}
+
+sal_Bool OResultSet::isAfterLast()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->isAfterLast();
+}
+
+sal_Bool OResultSet::isFirst()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->isFirst();
+}
+
+sal_Bool OResultSet::isLast()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->isLast();
+}
+
+void OResultSet::beforeFirst()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ m_xDelegatorResultSet->beforeFirst();
+}
+
+void OResultSet::afterLast()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ m_xDelegatorResultSet->afterLast();
+}
+
+sal_Bool OResultSet::first()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->first();
+}
+
+sal_Bool OResultSet::last()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->last();
+}
+
+sal_Int32 OResultSet::getRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->getRow();
+}
+
+sal_Bool OResultSet::absolute(sal_Int32 row)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->absolute(row);
+}
+
+sal_Bool OResultSet::relative(sal_Int32 rows)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->relative(rows);
+}
+
+sal_Bool OResultSet::previous()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->previous();
+}
+
+void OResultSet::refreshRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ m_xDelegatorResultSet->refreshRow();
+}
+
+sal_Bool OResultSet::rowUpdated()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->rowUpdated();
+}
+
+sal_Bool OResultSet::rowInserted()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->rowInserted();
+}
+
+sal_Bool OResultSet::rowDeleted()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_xDelegatorResultSet->rowDeleted();
+}
+
+Reference< XInterface > OResultSet::getStatement()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ return m_aStatement;
+}
+
+// css::sdbcx::XRowLocate
+Any OResultSet::getBookmark()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkBookmarkable();
+
+ return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->getBookmark();
+}
+
+sal_Bool OResultSet::moveToBookmark(const Any& bookmark)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkBookmarkable();
+
+ return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->moveToBookmark(bookmark);
+}
+
+sal_Bool OResultSet::moveRelativeToBookmark(const Any& bookmark, sal_Int32 rows)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkBookmarkable();
+
+ return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->moveRelativeToBookmark(bookmark, rows);
+}
+
+sal_Int32 OResultSet::compareBookmarks(const Any& _first, const Any& _second)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkBookmarkable();
+
+ return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->compareBookmarks(_first, _second);
+}
+
+sal_Bool OResultSet::hasOrderedBookmarks()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkBookmarkable();
+
+ return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->hasOrderedBookmarks();
+}
+
+sal_Int32 OResultSet::hashBookmark(const Any& bookmark)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkBookmarkable();
+
+ return Reference< XRowLocate >(m_xDelegatorResultSet, UNO_QUERY_THROW)->hashBookmark(bookmark);
+}
+
+// css::sdbc::XResultSetUpdate
+void OResultSet::insertRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorResultSetUpdate->insertRow();
+}
+
+void OResultSet::updateRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorResultSetUpdate->updateRow();
+}
+
+void OResultSet::deleteRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorResultSetUpdate->deleteRow();
+}
+
+void OResultSet::cancelRowUpdates()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorResultSetUpdate->cancelRowUpdates();
+}
+
+void OResultSet::moveToInsertRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorResultSetUpdate->moveToInsertRow();
+}
+
+void OResultSet::moveToCurrentRow()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OResultSetBase::rBHelper.bDisposed);
+
+ checkReadOnly();
+
+ m_xDelegatorResultSetUpdate->moveToCurrentRow();
+}
+
+void OResultSet::checkReadOnly() const
+{
+ if ( ( m_nResultSetConcurrency == ResultSetConcurrency::READ_ONLY )
+ || !m_xDelegatorResultSetUpdate.is()
+ )
+ throwSQLException( "The result set is read-only.", StandardSQLState::GENERAL_ERROR, *const_cast< OResultSet* >( this ) );
+}
+
+void OResultSet::checkBookmarkable() const
+{
+ if ( !m_bIsBookmarkable )
+ throwSQLException( "The result set does not have bookmark support.", StandardSQLState::GENERAL_ERROR, *const_cast< OResultSet* >( this ) );
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/resultset.hxx b/dbaccess/source/core/api/resultset.hxx
new file mode 100644
index 000000000..b2da0f248
--- /dev/null
+++ b/dbaccess/source/core/api/resultset.hxx
@@ -0,0 +1,221 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <column.hxx>
+#include <connectivity/warningscontainer.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/sdbcx/XRowLocate.hpp>
+#include <com/sun/star/sdbc/XRowUpdate.hpp>
+#include <com/sun/star/sdbc/XResultSetUpdate.hpp>
+#include <com/sun/star/sdbc/ResultSetConcurrency.hpp>
+
+#include <cppuhelper/propshlp.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <osl/diagnose.h>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+namespace dbaccess
+{
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XWarningsSupplier,
+ css::sdbc::XResultSet,
+ css::sdbc::XResultSetMetaDataSupplier,
+ css::sdbc::XRow,
+ css::sdbc::XCloseable,
+ css::sdbc::XColumnLocate,
+ css::sdbcx::XRowLocate,
+ css::sdbcx::XColumnsSupplier,
+ css::sdbc::XResultSetUpdate,
+ css::sdbc::XRowUpdate,
+ css::lang::XServiceInfo > OResultSetBase;
+
+ // OResultSet
+
+ class OResultSet final : public cppu::BaseMutex,
+ public OResultSetBase,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper < OResultSet >
+ {
+ css::uno::Reference< css::uno::XInterface> m_aStatement;
+
+ css::uno::Reference< css::sdbc::XResultSet > m_xDelegatorResultSet;
+ css::uno::Reference< css::sdbc::XResultSetUpdate > m_xDelegatorResultSetUpdate;
+ css::uno::Reference< css::sdbc::XRow > m_xDelegatorRow;
+ css::uno::Reference< css::sdbc::XRowUpdate > m_xDelegatorRowUpdate;
+
+ ::dbtools::WarningsContainer m_aWarnings;
+ std::unique_ptr<OColumns> m_pColumns;
+ sal_Int32 m_nResultSetConcurrency;
+ bool m_bIsBookmarkable : 1;
+
+ public:
+ OResultSet(const css::uno::Reference< css::sdbc::XResultSet >& _xResultSet,
+ const css::uno::Reference< css::uno::XInterface >& _xStatement,
+ bool _bCaseSensitive);
+ virtual ~OResultSet() override;
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // ::cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // css::sdbc::XCloseable
+ virtual void SAL_CALL close( ) override;
+
+ // css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ // cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override;
+
+ // css::sdbc::XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+ // css::sdbc::XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+
+ // css::sdbc::XColumnLocate
+ virtual sal_Int32 SAL_CALL findColumn( const OUString& columnName ) override;
+
+ // css::sdbcx::XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+
+ // css::sdbc::XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+
+ // css::sdbc::XResultSet
+ virtual sal_Bool SAL_CALL next( ) override;
+ virtual sal_Bool SAL_CALL isBeforeFirst( ) override;
+ virtual sal_Bool SAL_CALL isAfterLast( ) override;
+ virtual sal_Bool SAL_CALL isFirst( ) override;
+ virtual sal_Bool SAL_CALL isLast( ) override;
+ virtual void SAL_CALL beforeFirst( ) override;
+ virtual void SAL_CALL afterLast( ) override;
+ virtual sal_Bool SAL_CALL first( ) override;
+ virtual sal_Bool SAL_CALL last( ) override;
+ virtual sal_Int32 SAL_CALL getRow( ) override;
+ virtual sal_Bool SAL_CALL absolute( sal_Int32 row ) override;
+ virtual sal_Bool SAL_CALL relative( sal_Int32 rows ) override;
+ virtual sal_Bool SAL_CALL previous( ) override;
+ virtual void SAL_CALL refreshRow( ) override;
+ virtual sal_Bool SAL_CALL rowUpdated( ) override;
+ virtual sal_Bool SAL_CALL rowInserted( ) override;
+ virtual sal_Bool SAL_CALL rowDeleted( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement( ) override;
+
+ // css::sdbcx::XRowLocate
+ virtual css::uno::Any SAL_CALL getBookmark( ) override;
+ virtual sal_Bool SAL_CALL moveToBookmark( const css::uno::Any& bookmark ) override;
+ virtual sal_Bool SAL_CALL moveRelativeToBookmark( const css::uno::Any& bookmark, sal_Int32 rows ) override;
+ virtual sal_Int32 SAL_CALL compareBookmarks( const css::uno::Any& first, const css::uno::Any& second ) override;
+ virtual sal_Bool SAL_CALL hasOrderedBookmarks( ) override;
+ virtual sal_Int32 SAL_CALL hashBookmark( const css::uno::Any& bookmark ) override;
+
+ // css::sdbc::XResultSetUpdate
+ virtual void SAL_CALL insertRow( ) override;
+ virtual void SAL_CALL updateRow( ) override;
+ virtual void SAL_CALL deleteRow( ) override;
+ virtual void SAL_CALL cancelRowUpdates( ) override;
+ virtual void SAL_CALL moveToInsertRow( ) override;
+ virtual void SAL_CALL moveToCurrentRow( ) override;
+
+ // css::sdbc::XRowUpdate
+ virtual void SAL_CALL updateNull( sal_Int32 columnIndex ) override;
+ virtual void SAL_CALL updateBoolean( sal_Int32 columnIndex, sal_Bool x ) override;
+ virtual void SAL_CALL updateByte( sal_Int32 columnIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL updateShort( sal_Int32 columnIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL updateInt( sal_Int32 columnIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL updateLong( sal_Int32 columnIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL updateFloat( sal_Int32 columnIndex, float x ) override;
+ virtual void SAL_CALL updateDouble( sal_Int32 columnIndex, double x ) override;
+ virtual void SAL_CALL updateString( sal_Int32 columnIndex, const OUString& x ) override;
+ virtual void SAL_CALL updateBytes( sal_Int32 columnIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL updateDate( sal_Int32 columnIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL updateTime( sal_Int32 columnIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL updateTimestamp( sal_Int32 columnIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL updateBinaryStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateCharacterStream( sal_Int32 columnIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL updateObject( sal_Int32 columnIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL updateNumericObject( sal_Int32 columnIndex, const css::uno::Any& x, sal_Int32 scale ) override;
+
+ private:
+ void checkReadOnly() const;
+ void checkBookmarkable() const;
+
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/statement.cxx b/dbaccess/source/core/api/statement.cxx
new file mode 100644
index 000000000..3a67cbaeb
--- /dev/null
+++ b/dbaccess/source/core/api/statement.cxx
@@ -0,0 +1,591 @@
+/* -*- 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 <statement.hxx>
+#include "resultset.hxx"
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <cppuhelper/queryinterface.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/types.hxx>
+#include <tools/diagnose_ex.h>
+#include <connectivity/dbexception.hxx>
+
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace dbaccess;
+using namespace dbtools;
+
+
+OStatementBase::OStatementBase(const Reference< XConnection > & _xConn,
+ const Reference< XInterface > & _xStatement)
+ :OSubComponent(m_aMutex, _xConn)
+ ,OPropertySetHelper(OComponentHelper::rBHelper)
+ ,m_bUseBookmarks( false )
+ ,m_bEscapeProcessing( true )
+
+{
+ OSL_ENSURE(_xStatement.is() ,"Statement is NULL!");
+ m_xAggregateAsSet.set(_xStatement,UNO_QUERY);
+ m_xAggregateAsCancellable.set(m_xAggregateAsSet, UNO_QUERY);
+}
+
+OStatementBase::~OStatementBase()
+{
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > OStatementBase::getTypes()
+{
+ OTypeCollection aTypes(cppu::UnoType<XPropertySet>::get(),
+ cppu::UnoType<XWarningsSupplier>::get(),
+ cppu::UnoType<XCloseable>::get(),
+ cppu::UnoType<XMultipleResults>::get(),
+ cppu::UnoType<css::util::XCancellable>::get(),
+ OSubComponent::getTypes() );
+ Reference< XGeneratedResultSet > xGRes(m_xAggregateAsSet, UNO_QUERY);
+ if ( xGRes.is() )
+ aTypes = OTypeCollection(cppu::UnoType<XGeneratedResultSet>::get(),aTypes.getTypes());
+ Reference< XPreparedBatchExecution > xPreparedBatchExecution(m_xAggregateAsSet, UNO_QUERY);
+ if ( xPreparedBatchExecution.is() )
+ aTypes = OTypeCollection(cppu::UnoType<XPreparedBatchExecution>::get(),aTypes.getTypes());
+
+ return aTypes.getTypes();
+}
+
+// css::uno::XInterface
+Any OStatementBase::queryInterface( const Type & rType )
+{
+ Any aIface = OSubComponent::queryInterface( rType );
+ if (!aIface.hasValue())
+ {
+ aIface = ::cppu::queryInterface(
+ rType,
+ static_cast< XPropertySet * >( this ),
+ static_cast< XWarningsSupplier * >( this ),
+ static_cast< XCloseable * >( this ),
+ static_cast< XMultipleResults * >( this ),
+ static_cast< css::util::XCancellable * >( this ));
+ if ( !aIface.hasValue() )
+ {
+ Reference< XGeneratedResultSet > xGRes(m_xAggregateAsSet, UNO_QUERY);
+ if ( cppu::UnoType<XGeneratedResultSet>::get()== rType && xGRes.is() )
+ aIface = ::cppu::queryInterface(rType,static_cast< XGeneratedResultSet * >( this ));
+ }
+ if ( !aIface.hasValue() )
+ {
+ Reference< XPreparedBatchExecution > xGRes(m_xAggregateAsSet, UNO_QUERY);
+ if ( cppu::UnoType<XPreparedBatchExecution>::get()== rType && xGRes.is() )
+ aIface = ::cppu::queryInterface(rType,static_cast< XPreparedBatchExecution * >( this ));
+ }
+ }
+ return aIface;
+}
+
+void OStatementBase::acquire() noexcept
+{
+ OSubComponent::acquire();
+}
+
+void OStatementBase::release() noexcept
+{
+ OSubComponent::release();
+}
+
+void OStatementBase::disposeResultSet()
+{
+ // free the cursor if alive
+ Reference< XComponent > xComp(m_aResultSet.get(), UNO_QUERY);
+ if (xComp.is())
+ xComp->dispose();
+ m_aResultSet.clear();
+}
+
+// OComponentHelper
+void OStatementBase::disposing()
+{
+ OPropertySetHelper::disposing();
+
+ MutexGuard aGuard(m_aMutex);
+
+ // free pending results
+ disposeResultSet();
+
+ // free the original statement
+ {
+ MutexGuard aCancelGuard(m_aCancelMutex);
+ m_xAggregateAsCancellable = nullptr;
+ }
+
+ if ( m_xAggregateAsSet.is() )
+ {
+ try
+ {
+ Reference< XCloseable > (m_xAggregateAsSet, UNO_QUERY_THROW)->close();
+ }
+ catch(RuntimeException& )
+ {// don't care for anymore
+ }
+ }
+ m_xAggregateAsSet = nullptr;
+
+ // free the parent at last
+ OSubComponent::disposing();
+}
+
+// XCloseable
+void OStatementBase::close()
+{
+ {
+ MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ }
+ dispose();
+}
+
+// OPropertySetHelper
+Reference< XPropertySetInfo > OStatementBase::getPropertySetInfo()
+{
+ return createPropertySetInfo( getInfoHelper() ) ;
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* OStatementBase::createArrayHelper( ) const
+{
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ { PROPERTY_CURSORNAME, PROPERTY_ID_CURSORNAME, cppu::UnoType<OUString>::get(), 0 },
+ { PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, cppu::UnoType<bool>::get(), 0 },
+ { PROPERTY_FETCHDIRECTION, PROPERTY_ID_FETCHDIRECTION, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_FETCHSIZE, PROPERTY_ID_FETCHSIZE, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_MAXFIELDSIZE, PROPERTY_ID_MAXFIELDSIZE, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_MAXROWS, PROPERTY_ID_MAXROWS, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_QUERYTIMEOUT, PROPERTY_ID_QUERYTIMEOUT, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_RESULTSETCONCURRENCY, PROPERTY_ID_RESULTSETCONCURRENCY, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_RESULTSETTYPE, PROPERTY_ID_RESULTSETTYPE, cppu::UnoType<sal_Int32>::get(), 0 },
+ { PROPERTY_USEBOOKMARKS, PROPERTY_ID_USEBOOKMARKS, cppu::UnoType<bool>::get(), 0 }
+ }
+ };
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& OStatementBase::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool OStatementBase::convertFastPropertyValue(Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
+{
+ bool bModified(false);
+ switch (nHandle)
+ {
+ case PROPERTY_ID_USEBOOKMARKS:
+ bModified = ::comphelper::tryPropertyValue( rConvertedValue, rOldValue, rValue, m_bUseBookmarks );
+ break;
+
+ case PROPERTY_ID_ESCAPE_PROCESSING:
+ bModified = ::comphelper::tryPropertyValue( rConvertedValue, rOldValue, rValue, m_bEscapeProcessing );
+ break;
+
+ default:
+ if ( m_xAggregateAsSet.is() )
+ {
+ // get the property name
+ OUString sPropName;
+ getInfoHelper().fillPropertyMembersByHandle( &sPropName, nullptr, nHandle );
+
+ // now set the value
+ Any aCurrentValue = m_xAggregateAsSet->getPropertyValue( sPropName );
+ if ( aCurrentValue != rValue )
+ {
+ rOldValue = aCurrentValue;
+ rConvertedValue = rValue;
+ bModified = true;
+ }
+ }
+ break;
+ }
+ return bModified;
+}
+
+void OStatementBase::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
+{
+ switch ( nHandle )
+ {
+ case PROPERTY_ID_USEBOOKMARKS:
+ {
+ m_bUseBookmarks = ::comphelper::getBOOL( rValue );
+ if ( m_xAggregateAsSet.is() && m_xAggregateAsSet->getPropertySetInfo()->hasPropertyByName( PROPERTY_USEBOOKMARKS ) )
+ m_xAggregateAsSet->setPropertyValue( PROPERTY_USEBOOKMARKS, rValue );
+ }
+ break;
+
+ case PROPERTY_ID_ESCAPE_PROCESSING:
+ m_bEscapeProcessing = ::comphelper::getBOOL( rValue );
+ if ( m_xAggregateAsSet.is() )
+ m_xAggregateAsSet->setPropertyValue( PROPERTY_ESCAPE_PROCESSING, rValue );
+ break;
+
+ default:
+ if ( m_xAggregateAsSet.is() )
+ {
+ OUString sPropName;
+ getInfoHelper().fillPropertyMembersByHandle( &sPropName, nullptr, nHandle );
+ m_xAggregateAsSet->setPropertyValue( sPropName, rValue );
+ }
+ break;
+ }
+}
+
+void OStatementBase::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ switch (nHandle)
+ {
+ case PROPERTY_ID_USEBOOKMARKS:
+ rValue <<= m_bUseBookmarks;
+ break;
+
+ case PROPERTY_ID_ESCAPE_PROCESSING:
+ // don't rely on our aggregate - if it implements this wrong, and always returns
+ // TRUE here, then we would loop in impl_doEscapeProcessing_nothrow
+ rValue <<= m_bEscapeProcessing;
+ break;
+
+ default:
+ if ( m_xAggregateAsSet.is() )
+ {
+ OUString sPropName;
+ const_cast< OStatementBase* >( this )->getInfoHelper().fillPropertyMembersByHandle( &sPropName, nullptr, nHandle );
+ rValue = m_xAggregateAsSet->getPropertyValue( sPropName );
+ }
+ break;
+ }
+}
+
+// XWarningsSupplier
+Any OStatementBase::getWarnings()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ return Reference< XWarningsSupplier >(m_xAggregateAsSet, UNO_QUERY_THROW)->getWarnings();
+}
+
+void OStatementBase::clearWarnings()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ Reference< XWarningsSupplier >(m_xAggregateAsSet, UNO_QUERY_THROW)->clearWarnings();
+}
+
+// css::util::XCancellable
+void OStatementBase::cancel()
+{
+ // no blocking as cancel is typically called from a different thread
+ MutexGuard aCancelGuard(m_aCancelMutex);
+ if (m_xAggregateAsCancellable.is())
+ m_xAggregateAsCancellable->cancel();
+ // else do nothing
+}
+
+// XMultipleResults
+Reference< XResultSet > SAL_CALL OStatementBase::getResultSet( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsMultipleResultSets())
+ throwFunctionSequenceException(*this);
+
+ return Reference< XMultipleResults >(m_xAggregateAsSet, UNO_QUERY_THROW)->getResultSet();
+}
+
+sal_Int32 SAL_CALL OStatementBase::getUpdateCount( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsMultipleResultSets())
+ throwFunctionSequenceException(*this);
+
+ return Reference< XMultipleResults >(m_xAggregateAsSet, UNO_QUERY_THROW)->getUpdateCount();
+}
+
+sal_Bool SAL_CALL OStatementBase::getMoreResults( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsMultipleResultSets())
+ throwFunctionSequenceException(*this);
+
+ // free the previous results
+ disposeResultSet();
+
+ return Reference< XMultipleResults >(m_xAggregateAsSet, UNO_QUERY_THROW)->getMoreResults();
+}
+
+// XPreparedBatchExecution
+void SAL_CALL OStatementBase::addBatch( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsBatchUpdates())
+ throwFunctionSequenceException(*this);
+
+ Reference< XPreparedBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->addBatch();
+}
+
+void SAL_CALL OStatementBase::clearBatch( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsBatchUpdates())
+ throwFunctionSequenceException(*this);
+
+ Reference< XPreparedBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->clearBatch();
+}
+
+Sequence< sal_Int32 > SAL_CALL OStatementBase::executeBatch( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsBatchUpdates())
+ throwFunctionSequenceException(*this);
+
+ // free the previous results
+ disposeResultSet();
+
+ return Reference< XPreparedBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->executeBatch();
+}
+
+Reference< XResultSet > SAL_CALL OStatementBase::getGeneratedValues( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ Reference< XGeneratedResultSet > xGRes(m_xAggregateAsSet, UNO_QUERY);
+
+ if ( xGRes.is() )
+ return xGRes->getGeneratedValues( );
+ return Reference< XResultSet >();
+}
+
+
+// OStatement
+
+OStatement::OStatement( const Reference< XConnection >& _xConn, const Reference< XInterface > & _xStatement )
+ :OStatementBase( _xConn, _xStatement )
+ ,m_bAttemptedComposerCreation( false )
+{
+ m_xAggregateStatement.set( _xStatement, UNO_QUERY_THROW );
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( OStatement, OStatementBase, OStatement_IFACE );
+IMPLEMENT_FORWARD_XTYPEPROVIDER2( OStatement, OStatementBase, OStatement_IFACE );
+
+// XServiceInfo
+OUString OStatement::getImplementationName( )
+{
+ return "com.sun.star.sdb.OStatement";
+}
+
+sal_Bool OStatement::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > OStatement::getSupportedServiceNames( )
+{
+ return { SERVICE_SDBC_STATEMENT };
+}
+
+// XStatement
+Reference< XResultSet > OStatement::executeQuery( const OUString& _rSQL )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ disposeResultSet();
+ Reference< XResultSet > xResultSet;
+
+ OUString sSQL( impl_doEscapeProcessing_nothrow( _rSQL ) );
+
+ Reference< XResultSet > xInnerResultSet = m_xAggregateStatement->executeQuery( sSQL );
+ Reference< XConnection > xConnection( m_xParent, UNO_QUERY_THROW );
+
+ if ( xInnerResultSet.is() )
+ {
+ Reference< XDatabaseMetaData > xMeta = xConnection->getMetaData();
+ bool bCaseSensitive = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers();
+ xResultSet = new OResultSet( xInnerResultSet, *this, bCaseSensitive );
+
+ // keep the resultset weak
+ m_aResultSet = xResultSet;
+ }
+
+ return xResultSet;
+}
+
+sal_Int32 OStatement::executeUpdate( const OUString& _rSQL )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ disposeResultSet();
+
+ OUString sSQL( impl_doEscapeProcessing_nothrow( _rSQL ) );
+ return m_xAggregateStatement->executeUpdate( sSQL );
+}
+
+sal_Bool OStatement::execute( const OUString& _rSQL )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ disposeResultSet();
+
+ OUString sSQL( impl_doEscapeProcessing_nothrow( _rSQL ) );
+ return m_xAggregateStatement->execute( sSQL );
+}
+
+void OStatement::addBatch( const OUString& _rSQL )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsBatchUpdates())
+ throwFunctionSequenceException(*this);
+
+ OUString sSQL( impl_doEscapeProcessing_nothrow( _rSQL ) );
+ Reference< XBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->addBatch( sSQL );
+}
+
+void OStatement::clearBatch( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsBatchUpdates())
+ throwFunctionSequenceException(*this);
+
+ Reference< XBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->clearBatch();
+}
+
+Sequence< sal_Int32 > OStatement::executeBatch( )
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
+ // first check the meta data
+ Reference<XDatabaseMetaData> xMeta = Reference< XConnection > (m_xParent, UNO_QUERY_THROW)->getMetaData();
+ if (!xMeta.is() || !xMeta->supportsBatchUpdates())
+ throwFunctionSequenceException(*this);
+ return Reference< XBatchExecution >(m_xAggregateAsSet, UNO_QUERY_THROW)->executeBatch( );
+}
+
+
+Reference< XConnection > OStatement::getConnection()
+{
+ return Reference< XConnection >( m_xParent, UNO_QUERY );
+}
+
+void SAL_CALL OStatement::disposing()
+{
+ OStatementBase::disposing();
+ m_xComposer.clear();
+ m_xAggregateStatement.clear();
+}
+
+OUString OStatement::impl_doEscapeProcessing_nothrow( const OUString& _rSQL ) const
+{
+ if ( !m_bEscapeProcessing )
+ return _rSQL;
+ try
+ {
+ if ( !impl_ensureComposer_nothrow() )
+ return _rSQL;
+
+ bool bParseable = false;
+ try { m_xComposer->setQuery( _rSQL ); bParseable = true; }
+ catch( const SQLException& ) { }
+
+ if ( !bParseable )
+ // if we cannot parse it, silently accept this. The driver is probably able to cope with it then
+ return _rSQL;
+
+ OUString sLowLevelSQL = m_xComposer->getQueryWithSubstitution();
+ return sLowLevelSQL;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return _rSQL;
+}
+
+bool OStatement::impl_ensureComposer_nothrow() const
+{
+ if ( m_bAttemptedComposerCreation )
+ return m_xComposer.is();
+
+ const_cast< OStatement* >( this )->m_bAttemptedComposerCreation = true;
+ try
+ {
+ Reference< XMultiServiceFactory > xFactory( m_xParent, UNO_QUERY_THROW );
+ const_cast< OStatement* >( this )->m_xComposer.set( xFactory->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER ), UNO_QUERY_THROW );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return m_xComposer.is();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/table.cxx b/dbaccess/source/core/api/table.cxx
new file mode 100644
index 000000000..f9a1dffb9
--- /dev/null
+++ b/dbaccess/source/core/api/table.cxx
@@ -0,0 +1,352 @@
+/* -*- 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 <table.hxx>
+#include <definitioncolumn.hxx>
+#include <stringconstants.hxx>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include "CIndexes.hxx"
+
+#include <osl/diagnose.h>
+#include <comphelper/servicehelper.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdb/tools/XTableRename.hpp>
+#include <com/sun/star/sdb/tools/XTableAlteration.hpp>
+
+#include <connectivity/TKeys.hxx>
+#include <connectivity/dbtools.hxx>
+
+#include <ContainerMediator.hxx>
+
+using namespace dbaccess;
+using namespace connectivity;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+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 ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+// ODBTable
+
+ODBTable::ODBTable(connectivity::sdbcx::OCollection* _pTables
+ ,const Reference< XConnection >& _rxConn
+ ,const OUString& _rCatalog
+ ,const OUString& _rSchema
+ ,const OUString& _rName
+ ,const OUString& _rType
+ ,const OUString& _rDesc
+ ,const Reference< XNameAccess >& _xColumnDefinitions)
+ :OTable_Base(_pTables,_rxConn,_rxConn->getMetaData().is() && _rxConn->getMetaData()->supportsMixedCaseQuotedIdentifiers(), _rName, _rType, _rDesc, _rSchema, _rCatalog )
+ ,m_xColumnDefinitions(_xColumnDefinitions)
+ ,m_nPrivileges(0)
+{
+ OSL_ENSURE(getMetaData().is(), "ODBTable::ODBTable : invalid conn !");
+ OSL_ENSURE(!_rName.isEmpty(), "ODBTable::ODBTable : name !");
+ // TODO : think about collecting the privileges here, as we can't ensure that in getFastPropertyValue, where
+ // we do this at the moment, the statement needed can be supplied by the connection (for example the SQL-Server
+ // ODBC driver does not allow more than one statement per connection, and in getFastPropertyValue it's more
+ // likely that it's already used up than it's here.)
+}
+
+ODBTable::ODBTable(connectivity::sdbcx::OCollection* _pTables
+ ,const Reference< XConnection >& _rxConn)
+ :OTable_Base(_pTables,_rxConn, _rxConn->getMetaData().is() && _rxConn->getMetaData()->supportsMixedCaseQuotedIdentifiers())
+ ,m_nPrivileges(-1)
+{
+}
+
+ODBTable::~ODBTable()
+{
+}
+
+rtl::Reference<OColumn> ODBTable::createColumn(const OUString& _rName) const
+{
+ Reference<XPropertySet> xProp;
+ if ( m_xDriverColumns.is() && m_xDriverColumns->hasByName(_rName) )
+ {
+ xProp.set(m_xDriverColumns->getByName(_rName),UNO_QUERY);
+ }
+ else
+ {
+ OColumns* pColumns = static_cast<OColumns*>(m_xColumns.get());
+ xProp.set(pColumns->createBaseObject(_rName),UNO_QUERY);
+ }
+
+ Reference<XPropertySet> xColumnDefinition;
+ if ( m_xColumnDefinitions.is() && m_xColumnDefinitions->hasByName(_rName) )
+ xColumnDefinition.set(m_xColumnDefinitions->getByName(_rName),UNO_QUERY);
+ return new OTableColumnWrapper( xProp, xColumnDefinition, false );
+}
+
+void ODBTable::columnAppended( const Reference< XPropertySet >& /*_rxSourceDescriptor*/ )
+{
+ // not interested in
+}
+
+void ODBTable::columnDropped(const OUString& _sName)
+{
+ Reference<XDrop> xDrop(m_xColumnDefinitions,UNO_QUERY);
+ if ( xDrop.is() && m_xColumnDefinitions->hasByName(_sName) )
+ {
+ xDrop->dropByName(_sName);
+ }
+}
+
+Sequence< sal_Int8 > ODBTable::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// OComponentHelper
+void SAL_CALL ODBTable::disposing()
+{
+ OPropertySetHelper::disposing();
+ OTable_Base::disposing();
+ m_xColumnDefinitions = nullptr;
+ m_xDriverColumns = nullptr;
+ m_pColumnMediator = nullptr;
+}
+
+void ODBTable::getFastPropertyValue(Any& _rValue, sal_Int32 _nHandle) const
+{
+ if ((PROPERTY_ID_PRIVILEGES == _nHandle) && (-1 == m_nPrivileges))
+ { // somebody is asking for the privileges and we do not know them, yet
+ const_cast<ODBTable*>(this)->m_nPrivileges = ::dbtools::getTablePrivileges(getMetaData(),m_CatalogName,m_SchemaName, m_Name);
+ }
+
+ OTable_Base::getFastPropertyValue(_rValue, _nHandle);
+}
+
+void ODBTable::construct()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ // we don't collect the privileges here, this is potentially expensive. Instead we determine them on request.
+ // (see getFastPropertyValue)
+ m_nPrivileges = -1;
+
+ OTable_Base::construct();
+
+ registerProperty(PROPERTY_FILTER, PROPERTY_ID_FILTER, PropertyAttribute::BOUND,
+ &m_sFilter, cppu::UnoType<OUString>::get());
+
+ registerProperty(PROPERTY_ORDER, PROPERTY_ID_ORDER, PropertyAttribute::BOUND,
+ &m_sOrder, cppu::UnoType<OUString>::get());
+
+ registerProperty(PROPERTY_APPLYFILTER, PROPERTY_ID_APPLYFILTER, PropertyAttribute::BOUND,
+ &m_bApplyFilter, cppu::UnoType<bool>::get());
+
+ registerProperty(PROPERTY_FONT, PROPERTY_ID_FONT, PropertyAttribute::BOUND,
+ &m_aFont, cppu::UnoType<css::awt::FontDescriptor>::get());
+
+ registerMayBeVoidProperty(PROPERTY_ROW_HEIGHT, PROPERTY_ID_ROW_HEIGHT, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID,
+ &m_aRowHeight, cppu::UnoType<sal_Int32>::get());
+
+ registerProperty(PROPERTY_AUTOGROW, PROPERTY_ID_AUTOGROW, PropertyAttribute::BOUND,
+ &m_bAutoGrow, cppu::UnoType<bool>::get());
+
+ registerMayBeVoidProperty(PROPERTY_TEXTCOLOR, PROPERTY_ID_TEXTCOLOR, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID,
+ &m_aTextColor, cppu::UnoType<sal_Int32>::get());
+
+ registerProperty(PROPERTY_PRIVILEGES, PROPERTY_ID_PRIVILEGES, PropertyAttribute::BOUND | PropertyAttribute::READONLY,
+ &m_nPrivileges, cppu::UnoType<sal_Int32>::get());
+
+ registerMayBeVoidProperty(PROPERTY_TEXTLINECOLOR, PROPERTY_ID_TEXTLINECOLOR, PropertyAttribute::BOUND | PropertyAttribute::MAYBEVOID,
+ &m_aTextLineColor, cppu::UnoType<sal_Int32>::get());
+
+ registerProperty(PROPERTY_TEXTEMPHASIS, PROPERTY_ID_TEXTEMPHASIS, PropertyAttribute::BOUND,
+ &m_nFontEmphasis, cppu::UnoType<sal_Int16>::get());
+
+ registerProperty(PROPERTY_TEXTRELIEF, PROPERTY_ID_TEXTRELIEF, PropertyAttribute::BOUND,
+ &m_nFontRelief, cppu::UnoType<sal_Int16>::get());
+
+ registerProperty(PROPERTY_FONTNAME, PROPERTY_ID_FONTNAME, PropertyAttribute::BOUND,&m_aFont.Name, cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_FONTHEIGHT, PROPERTY_ID_FONTHEIGHT, PropertyAttribute::BOUND,&m_aFont.Height, cppu::UnoType<sal_Int16>::get());
+ registerProperty(PROPERTY_FONTWIDTH, PROPERTY_ID_FONTWIDTH, PropertyAttribute::BOUND,&m_aFont.Width, cppu::UnoType<sal_Int16>::get());
+ registerProperty(PROPERTY_FONTSTYLENAME, PROPERTY_ID_FONTSTYLENAME, PropertyAttribute::BOUND,&m_aFont.StyleName, cppu::UnoType<OUString>::get());
+ registerProperty(PROPERTY_FONTFAMILY, PROPERTY_ID_FONTFAMILY, PropertyAttribute::BOUND,&m_aFont.Family, cppu::UnoType<sal_Int16>::get());
+ registerProperty(PROPERTY_FONTCHARSET, PROPERTY_ID_FONTCHARSET, PropertyAttribute::BOUND,&m_aFont.CharSet, cppu::UnoType<sal_Int16>::get());
+ registerProperty(PROPERTY_FONTPITCH, PROPERTY_ID_FONTPITCH, PropertyAttribute::BOUND,&m_aFont.Pitch, cppu::UnoType<sal_Int16>::get());
+ registerProperty(PROPERTY_FONTCHARWIDTH, PROPERTY_ID_FONTCHARWIDTH, PropertyAttribute::BOUND,&m_aFont.CharacterWidth, cppu::UnoType<float>::get());
+ registerProperty(PROPERTY_FONTWEIGHT, PROPERTY_ID_FONTWEIGHT, PropertyAttribute::BOUND,&m_aFont.Weight, cppu::UnoType<float>::get());
+ registerProperty(PROPERTY_FONTSLANT, PROPERTY_ID_FONTSLANT, PropertyAttribute::BOUND,&m_aFont.Slant, cppu::UnoType<css::awt::FontSlant>::get());
+ registerProperty(PROPERTY_FONTUNDERLINE, PROPERTY_ID_FONTUNDERLINE, PropertyAttribute::BOUND,&m_aFont.Underline, cppu::UnoType<sal_Int16>::get());
+ registerProperty(PROPERTY_FONTSTRIKEOUT, PROPERTY_ID_FONTSTRIKEOUT, PropertyAttribute::BOUND,&m_aFont.Strikeout, cppu::UnoType<sal_Int16>::get());
+ registerProperty(PROPERTY_FONTORIENTATION, PROPERTY_ID_FONTORIENTATION, PropertyAttribute::BOUND,&m_aFont.Orientation, cppu::UnoType<float>::get());
+ registerProperty(PROPERTY_FONTKERNING, PROPERTY_ID_FONTKERNING, PropertyAttribute::BOUND,&m_aFont.Kerning, cppu::UnoType<sal_Bool>::get());
+ registerProperty(PROPERTY_FONTWORDLINEMODE, PROPERTY_ID_FONTWORDLINEMODE,PropertyAttribute::BOUND,&m_aFont.WordLineMode, cppu::UnoType<sal_Bool>::get());
+ registerProperty(PROPERTY_FONTTYPE, PROPERTY_ID_FONTTYPE, PropertyAttribute::BOUND,&m_aFont.Type, cppu::UnoType<sal_Int16>::get());
+
+ refreshColumns();
+}
+
+::cppu::IPropertyArrayHelper* ODBTable::createArrayHelper( sal_Int32 _nId) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ if(!_nId)
+ {
+ for(Property & prop : asNonConstRange(aProps))
+ {
+ if (prop.Name == PROPERTY_CATALOGNAME)
+ prop.Attributes = PropertyAttribute::READONLY;
+ else if (prop.Name == PROPERTY_SCHEMANAME)
+ prop.Attributes = PropertyAttribute::READONLY;
+ else if (prop.Name == PROPERTY_DESCRIPTION)
+ prop.Attributes = PropertyAttribute::READONLY;
+ else if (prop.Name == PROPERTY_NAME)
+ prop.Attributes = PropertyAttribute::READONLY;
+ }
+ }
+
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+::cppu::IPropertyArrayHelper & SAL_CALL ODBTable::getInfoHelper()
+{
+ return *ODBTable_PROP::getArrayHelper(isNew() ? 1 : 0);
+}
+
+// XServiceInfo
+OUString SAL_CALL ODBTable::getImplementationName()
+ {
+ return "com.sun.star.sdb.dbaccess.ODBTable";
+ }
+sal_Bool SAL_CALL ODBTable::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL ODBTable::getSupportedServiceNames()
+{
+ return { SERVICE_SDBCX_TABLE };
+}
+
+
+Any SAL_CALL ODBTable::queryInterface( const Type & rType )
+{
+ if(rType == cppu::UnoType<XRename>::get()&& !getRenameService().is() )
+ return Any();
+ if(rType == cppu::UnoType<XAlterTable>::get()&& !getAlterService().is() )
+ return Any();
+ return OTable_Base::queryInterface( rType);
+}
+
+Sequence< Type > SAL_CALL ODBTable::getTypes( )
+{
+ Type aRenameType = cppu::UnoType<XRename>::get();
+ Type aAlterType = cppu::UnoType<XAlterTable>::get();
+
+ Sequence< Type > aTypes(OTable_Base::getTypes());
+ std::vector<Type> aOwnTypes;
+ aOwnTypes.reserve(aTypes.getLength());
+
+ const Type* pIter = aTypes.getConstArray();
+ const Type* pEnd = pIter + aTypes.getLength();
+ for(;pIter != pEnd ;++pIter)
+ {
+ if( (*pIter != aRenameType || getRenameService().is()) && (*pIter != aAlterType || getAlterService().is()))
+ aOwnTypes.push_back(*pIter);
+ }
+
+ return Sequence< Type >(aOwnTypes.data(), aOwnTypes.size());
+}
+
+// XRename,
+void SAL_CALL ODBTable::rename( const OUString& _rNewName )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed);
+ if ( !getRenameService().is() )
+ throw SQLException(DBA_RES(RID_STR_NO_TABLE_RENAME),*this,SQLSTATE_GENERAL,1000,Any() );
+
+ Reference<XPropertySet> xTable(this);
+ getRenameService()->rename(xTable,_rNewName);
+ ::connectivity::OTable_TYPEDEF::rename(_rNewName);
+}
+
+// XAlterTable,
+void SAL_CALL ODBTable::alterColumnByName( const OUString& _rName, const Reference< XPropertySet >& _rxDescriptor )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(connectivity::sdbcx::OTableDescriptor_BASE::rBHelper.bDisposed);
+ if ( !getAlterService().is() )
+ throw SQLException(DBA_RES(RID_STR_NO_TABLE_RENAME),*this,SQLSTATE_GENERAL,1000,Any() );
+
+ if ( !m_xColumns->hasByName(_rName) )
+ throw SQLException(DBA_RES(RID_STR_COLUMN_NOT_VALID),*this,SQLSTATE_GENERAL,1000,Any() );
+
+ Reference<XPropertySet> xTable(this);
+ getAlterService()->alterColumnByName(xTable,_rName,_rxDescriptor);
+ m_xColumns->refresh();
+}
+
+sal_Int64 SAL_CALL ODBTable::getSomething( const Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this,
+ comphelper::FallbackToGetSomethingOf<OTable_Base>{});
+}
+
+const Sequence< sal_Int8 > & ODBTable::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit s_Id;
+ return s_Id.getSeq();
+}
+
+Reference< XPropertySet > ODBTable::createColumnDescriptor()
+{
+ return new OTableColumnDescriptor( true );
+}
+
+sdbcx::OCollection* ODBTable::createColumns(const ::std::vector< OUString>& _rNames)
+{
+ Reference<XDatabaseMetaData> xMeta = getMetaData();
+ OColumns* pCol = new OColumns(*this, m_aMutex, nullptr, isCaseSensitive(), _rNames, this,this,
+ getAlterService().is() || (xMeta.is() && xMeta->supportsAlterTableWithAddColumn()),
+ getAlterService().is() || (xMeta.is() && xMeta->supportsAlterTableWithDropColumn()));
+ static_cast<OColumnsHelper*>(pCol)->setParent(this);
+ pCol->setParent(*this);
+ m_pColumnMediator = new OContainerMediator( pCol, m_xColumnDefinitions );
+ pCol->setMediator( m_pColumnMediator.get() );
+ return pCol;
+}
+
+sdbcx::OCollection* ODBTable::createKeys(const ::std::vector< OUString>& _rNames)
+{
+ return new connectivity::OKeysHelper(this,m_aMutex,_rNames);
+}
+
+sdbcx::OCollection* ODBTable::createIndexes(const ::std::vector< OUString>& _rNames)
+{
+ return new OIndexes(this,m_aMutex,_rNames,nullptr);
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/tablecontainer.cxx b/dbaccess/source/core/api/tablecontainer.cxx
new file mode 100644
index 000000000..3971dd154
--- /dev/null
+++ b/dbaccess/source/core/api/tablecontainer.cxx
@@ -0,0 +1,456 @@
+/* -*- 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 <tablecontainer.hxx>
+#include <table.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/processfactory.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <com/sun/star/beans/XPropertyState.hpp>
+#include <com/sun/star/sdb/TableDefinition.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+#include <TableDeco.hxx>
+#include <sdbcoretools.hxx>
+#include <ContainerMediator.hxx>
+#include <objectnameapproval.hxx>
+#include <tools/diagnose_ex.h>
+
+using namespace dbaccess;
+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::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+using namespace ::connectivity::sdbcx;
+
+namespace
+{
+ bool lcl_isPropertySetDefaulted(const Sequence< OUString>& _aNames,const Reference<XPropertySet>& _xProp)
+ {
+ Reference<XPropertyState> xState(_xProp,UNO_QUERY);
+ if ( !xState )
+ return false;
+ const OUString* pIter = _aNames.getConstArray();
+ const OUString* pEnd = pIter + _aNames.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ try
+ {
+ PropertyState aState = xState->getPropertyState(*pIter);
+ if ( aState != PropertyState_DEFAULT_VALUE )
+ break;
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "" );
+ }
+ }
+ return ( pIter == pEnd );
+ }
+}
+
+// OTableContainer
+
+OTableContainer::OTableContainer(::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const Reference< XConnection >& _xCon,
+ bool _bCase,
+ const Reference< XNameContainer >& _xTableDefinitions,
+ IRefreshListener* _pRefreshListener,
+ std::atomic<std::size_t>& _nInAppend)
+ :OFilteredContainer(_rParent,_rMutex,_xCon,_bCase,_pRefreshListener,_nInAppend)
+ ,m_xTableDefinitions(_xTableDefinitions)
+{
+}
+
+OTableContainer::~OTableContainer()
+{
+}
+
+void OTableContainer::removeMasterContainerListener()
+{
+ try
+ {
+ Reference<XContainer> xCont( m_xMasterContainer, UNO_QUERY_THROW );
+ xCont->removeContainerListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+OUString OTableContainer::getTableTypeRestriction() const
+{
+ // no restriction at all (other than the ones provided externally)
+ return OUString();
+}
+
+// XServiceInfo
+OUString SAL_CALL OTableContainer::getImplementationName()
+ {
+ return "com.sun.star.sdb.dbaccess.OTableContainer";
+ }
+sal_Bool SAL_CALL OTableContainer::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL OTableContainer::getSupportedServiceNames()
+{
+ return { SERVICE_SDBCX_CONTAINER, SERVICE_SDBCX_TABLES };
+}
+
+
+namespace
+{
+void lcl_createDefinitionObject(const OUString& _rName
+ ,const Reference< XNameContainer >& _xTableDefinitions
+ ,Reference<XPropertySet>& _xTableDefinition
+ ,Reference<XNameAccess>& _xColumnDefinitions)
+{
+ if ( !_xTableDefinitions.is() )
+ return;
+
+ if ( _xTableDefinitions->hasByName(_rName) )
+ _xTableDefinition.set(_xTableDefinitions->getByName(_rName),UNO_QUERY);
+ else
+ {
+ // set as folder
+ _xTableDefinition = TableDefinition::createWithName( ::comphelper::getProcessComponentContext(), _rName );
+ _xTableDefinitions->insertByName(_rName,Any(_xTableDefinition));
+ }
+ Reference<XColumnsSupplier> xColumnsSupplier(_xTableDefinition,UNO_QUERY);
+ if ( xColumnsSupplier.is() )
+ _xColumnDefinitions = xColumnsSupplier->getColumns();
+}
+
+}
+
+connectivity::sdbcx::ObjectType OTableContainer::createObject(const OUString& _rName)
+{
+ Reference<XColumnsSupplier > xSup;
+ if(m_xMasterContainer.is() && m_xMasterContainer->hasByName(_rName))
+ xSup.set(m_xMasterContainer->getByName(_rName),UNO_QUERY);
+
+ connectivity::sdbcx::ObjectType xRet;
+ if ( m_xMetaData.is() )
+ {
+ Reference<XPropertySet> xTableDefinition;
+ Reference<XNameAccess> xColumnDefinitions;
+ lcl_createDefinitionObject(_rName,m_xTableDefinitions,xTableDefinition,xColumnDefinitions);
+
+ if ( xSup.is() )
+ {
+ rtl::Reference<ODBTableDecorator> pTable = new ODBTableDecorator( m_xConnection, xSup, ::dbtools::getNumberFormats( m_xConnection ) ,xColumnDefinitions);
+ xRet = pTable;
+ pTable->construct();
+ }
+ else
+ {
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData,
+ _rName,
+ sCatalog,
+ sSchema,
+ sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+ Any aCatalog;
+ if(!sCatalog.isEmpty())
+ aCatalog <<= sCatalog;
+ OUString sType,sDescription;
+ Sequence< OUString> aTypeFilter;
+ getAllTableTypeFilter( aTypeFilter );
+
+ Reference< XResultSet > xRes;
+ if ( m_xMetaData.is() )
+ xRes = m_xMetaData->getTables(aCatalog,sSchema,sTable,aTypeFilter);
+ if(xRes.is() && xRes->next())
+ {
+ Reference< XRow > xRow(xRes,UNO_QUERY);
+ if(xRow.is())
+ {
+ sType = xRow->getString(4);
+ sDescription = xRow->getString(5);
+ }
+ }
+ ::comphelper::disposeComponent(xRes);
+ rtl::Reference<ODBTable> pTable = new ODBTable(this
+ ,m_xConnection
+ ,sCatalog
+ ,sSchema
+ ,sTable
+ ,sType
+ ,sDescription
+ ,xColumnDefinitions);
+ xRet = pTable;
+ pTable->construct();
+ }
+ Reference<XPropertySet> xDest(xRet,UNO_QUERY);
+ if ( xTableDefinition.is() )
+ ::comphelper::copyProperties(xTableDefinition,xDest);
+
+ if ( !m_pTableMediator.is() )
+ m_pTableMediator = new OContainerMediator(
+ this, m_xTableDefinitions );
+ if ( m_pTableMediator.is() )
+ m_pTableMediator->notifyElementCreated(_rName,xDest);
+ }
+
+ return xRet;
+}
+
+Reference< XPropertySet > OTableContainer::createDescriptor()
+{
+ Reference< XPropertySet > xRet;
+
+ // first we have to look if the master tables support this
+ // and if so then create a table object as well with the master tables
+ Reference<XColumnsSupplier > xMasterColumnsSup;
+ Reference<XDataDescriptorFactory> xDataFactory(m_xMasterContainer,UNO_QUERY);
+ if ( xDataFactory.is() && m_xMetaData.is() )
+ {
+ xMasterColumnsSup.set( xDataFactory->createDataDescriptor(), UNO_QUERY );
+ rtl::Reference<ODBTableDecorator> pTable = new ODBTableDecorator( m_xConnection, xMasterColumnsSup, ::dbtools::getNumberFormats( m_xConnection ) ,nullptr);
+ xRet = pTable;
+ pTable->construct();
+ }
+ else
+ {
+ rtl::Reference<ODBTable> pTable = new ODBTable(this, m_xConnection);
+ xRet = pTable;
+ pTable->construct();
+ }
+ return xRet;
+}
+
+// XAppend
+ObjectType OTableContainer::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ // append the new table with a create stmt
+ OUString aName = getString(descriptor->getPropertyValue(PROPERTY_NAME));
+ if(m_xMasterContainer.is() && m_xMasterContainer->hasByName(aName))
+ {
+ OUString sMessage(DBA_RES(RID_STR_TABLE_IS_FILTERED));
+ throw SQLException(sMessage.replaceAll("$name$", aName),static_cast<XTypeProvider*>(static_cast<OFilteredContainer*>(this)),SQLSTATE_GENERAL,1000,Any());
+ }
+
+ Reference< XConnection > xConnection( m_xConnection.get(), UNO_QUERY );
+ PContainerApprove pApprove = std::make_shared<ObjectNameApproval>( xConnection, ObjectNameApproval::TypeTable );
+ pApprove->approveElement( aName );
+
+ {
+ EnsureReset aReset(m_nInAppend);
+ Reference<XAppend> xAppend(m_xMasterContainer,UNO_QUERY);
+ if(xAppend.is())
+ {
+ xAppend->appendByDescriptor(descriptor);
+ }
+ else
+ {
+ OUString aSql = ::dbtools::createSqlCreateTableStatement(descriptor,m_xConnection);
+
+ Reference<XConnection> xCon = m_xConnection;
+ OSL_ENSURE(xCon.is(),"Connection is null!");
+ if ( xCon.is() )
+ {
+ Reference< XStatement > xStmt = xCon->createStatement( );
+ if ( xStmt.is() )
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ }
+ }
+
+ Reference<XPropertySet> xTableDefinition;
+ Reference<XNameAccess> xColumnDefinitions;
+ lcl_createDefinitionObject(getNameForObject(descriptor),m_xTableDefinitions,xTableDefinition,xColumnDefinitions);
+ Reference<XColumnsSupplier> xSup(descriptor,UNO_QUERY);
+ Reference<XDataDescriptorFactory> xFac(xColumnDefinitions,UNO_QUERY);
+ Reference<XAppend> xAppend(xColumnDefinitions,UNO_QUERY);
+ bool bModified = false;
+ if ( xSup.is() && xColumnDefinitions.is() && xFac.is() && xAppend.is() )
+ {
+ Reference<XNameAccess> xNames = xSup->getColumns();
+ if ( xNames.is() )
+ {
+ Reference<XPropertySet> xProp = xFac->createDataDescriptor();
+ Sequence< OUString> aSeq = xNames->getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( !xColumnDefinitions->hasByName(*pIter) )
+ {
+ Reference<XPropertySet> xColumn(xNames->getByName(*pIter),UNO_QUERY);
+ if ( !OColumnSettings::hasDefaultSettings( xColumn ) )
+ {
+ ::comphelper::copyProperties( xColumn, xProp );
+ xAppend->appendByDescriptor( xProp );
+ bModified = true;
+ }
+ }
+ }
+ }
+ }
+ Sequence< OUString> aNames{
+ PROPERTY_FILTER, PROPERTY_ORDER, PROPERTY_APPLYFILTER, PROPERTY_FONT,
+ PROPERTY_ROW_HEIGHT, PROPERTY_TEXTCOLOR, PROPERTY_TEXTLINECOLOR,
+ PROPERTY_TEXTEMPHASIS, PROPERTY_TEXTRELIEF};
+ if ( bModified || !lcl_isPropertySetDefaulted(aNames,xTableDefinition) )
+ ::dbaccess::notifyDataSourceModified(m_xTableDefinitions);
+
+ return createObject( _rForName );
+}
+
+// XDrop
+void OTableContainer::dropObject(sal_Int32 _nPos, const OUString& _sElementName)
+{
+ Reference< XDrop > xDrop(m_xMasterContainer,UNO_QUERY);
+ if(xDrop.is())
+ xDrop->dropByName(_sElementName);
+ else
+ {
+ OUString sComposedName;
+
+ bool bIsView = false;
+ Reference<XPropertySet> xTable(getObject(_nPos),UNO_QUERY);
+ if ( xTable.is() && m_xMetaData.is() )
+ {
+ OUString sSchema,sCatalog,sTable;
+ if (m_xMetaData->supportsCatalogsInTableDefinitions())
+ xTable->getPropertyValue(PROPERTY_CATALOGNAME) >>= sCatalog;
+ if (m_xMetaData->supportsSchemasInTableDefinitions())
+ xTable->getPropertyValue(PROPERTY_SCHEMANAME) >>= sSchema;
+ xTable->getPropertyValue(PROPERTY_NAME) >>= sTable;
+
+ sComposedName = ::dbtools::composeTableName( m_xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InTableDefinitions );
+
+ OUString sType;
+ xTable->getPropertyValue(PROPERTY_TYPE) >>= sType;
+ bIsView = sType.equalsIgnoreAsciiCase("VIEW");
+ }
+
+ if(sComposedName.isEmpty())
+ ::dbtools::throwFunctionSequenceException(static_cast<XTypeProvider*>(static_cast<OFilteredContainer*>(this)));
+
+ OUString aSql("DROP ");
+
+ if ( bIsView ) // here we have a view
+ aSql += "VIEW ";
+ else
+ aSql += "TABLE ";
+ aSql += sComposedName;
+ Reference<XConnection> xCon = m_xConnection;
+ OSL_ENSURE(xCon.is(),"Connection is null!");
+ if ( xCon.is() )
+ {
+ Reference< XStatement > xStmt = xCon->createStatement( );
+ if(xStmt.is())
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ }
+
+ if ( m_xTableDefinitions.is() && m_xTableDefinitions->hasByName(_sElementName) )
+ {
+ m_xTableDefinitions->removeByName(_sElementName);
+ }
+}
+
+void SAL_CALL OTableContainer::elementInserted( const ContainerEvent& Event )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OUString sName;
+ Event.Accessor >>= sName;
+ if ( !m_nInAppend && !hasByName(sName) )
+ {
+ if(!m_xMasterContainer.is() || m_xMasterContainer->hasByName(sName))
+ {
+ ObjectType xName = createObject(sName);
+ insertElement(sName,xName);
+ // and notify our listeners
+ ContainerEvent aEvent(static_cast<XContainer*>(this), Any(sName), Any(xName), Any());
+ m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
+ }
+ }
+}
+
+void SAL_CALL OTableContainer::elementRemoved( const ContainerEvent& /*Event*/ )
+{
+}
+
+void SAL_CALL OTableContainer::elementReplaced( const ContainerEvent& Event )
+{
+ // create a new config entry
+ OUString sOldComposedName,sNewComposedName;
+ Event.ReplacedElement >>= sOldComposedName;
+ Event.Accessor >>= sNewComposedName;
+
+ renameObject(sOldComposedName,sNewComposedName);
+}
+
+void OTableContainer::disposing()
+{
+ OFilteredContainer::disposing();
+ // say goodbye to our listeners
+ m_xTableDefinitions = nullptr;
+ m_pTableMediator = nullptr;
+}
+
+void SAL_CALL OTableContainer::disposing( const css::lang::EventObject& /*Source*/ )
+{
+}
+
+void OTableContainer::addMasterContainerListener()
+{
+ try
+ {
+ Reference< XContainer > xCont( m_xMasterContainer, UNO_QUERY_THROW );
+ xCont->addContainerListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/api/viewcontainer.cxx b/dbaccess/source/core/api/viewcontainer.cxx
new file mode 100644
index 000000000..462a3b1d0
--- /dev/null
+++ b/dbaccess/source/core/api/viewcontainer.cxx
@@ -0,0 +1,254 @@
+/* -*- 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 <strings.hxx>
+#include <viewcontainer.hxx>
+#include <View.hxx>
+
+#include <comphelper/types.hxx>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbexception.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+using namespace dbaccess;
+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::sdb;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::container;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+using namespace ::connectivity::sdbcx;
+
+// OViewContainer
+
+OViewContainer::OViewContainer(::cppu::OWeakObject& _rParent
+ ,::osl::Mutex& _rMutex
+ ,const Reference< XConnection >& _xCon
+ ,bool _bCase
+ ,IRefreshListener* _pRefreshListener
+ ,std::atomic<std::size_t>& _nInAppend)
+ :OFilteredContainer(_rParent,_rMutex,_xCon,_bCase,_pRefreshListener,_nInAppend)
+ ,m_bInElementRemoved(false)
+{
+}
+
+OViewContainer::~OViewContainer()
+{
+}
+
+// XServiceInfo
+OUString SAL_CALL OViewContainer::getImplementationName()
+ {
+ return "com.sun.star.sdb.dbaccess.OViewContainer";
+ }
+sal_Bool SAL_CALL OViewContainer::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL OViewContainer::getSupportedServiceNames()
+{
+ return { SERVICE_SDBCX_CONTAINER, SERVICE_SDBCX_TABLES };
+}
+
+
+ObjectType OViewContainer::createObject(const OUString& _rName)
+{
+ ObjectType xProp;
+ if ( m_xMasterContainer.is() && m_xMasterContainer->hasByName(_rName) )
+ xProp.set(m_xMasterContainer->getByName(_rName),UNO_QUERY);
+
+ if ( !xProp.is() )
+ {
+ OUString sCatalog,sSchema,sTable;
+ ::dbtools::qualifiedNameComponents(m_xMetaData,
+ _rName,
+ sCatalog,
+ sSchema,
+ sTable,
+ ::dbtools::EComposeRule::InDataManipulation);
+ return new View(m_xConnection,
+ isCaseSensitive(),
+ sCatalog,
+ sSchema,
+ sTable
+ );
+ }
+
+ return xProp;
+}
+
+Reference< XPropertySet > OViewContainer::createDescriptor()
+{
+ Reference< XPropertySet > xRet;
+ // first we have to look if the master tables support this
+ // and if so then create a table object as well with the master tables
+ Reference<XDataDescriptorFactory> xDataFactory(m_xMasterContainer,UNO_QUERY);
+ if(xDataFactory.is())
+ xRet = xDataFactory->createDataDescriptor();
+ else
+ xRet = new ::connectivity::sdbcx::OView(isCaseSensitive(),m_xMetaData);
+
+ return xRet;
+}
+
+// XAppend
+ObjectType OViewContainer::appendObject( const OUString& _rForName, const Reference< XPropertySet >& descriptor )
+{
+ // append the new table with a create stmt
+ OUString aName = getString(descriptor->getPropertyValue(PROPERTY_NAME));
+
+ Reference<XAppend> xAppend(m_xMasterContainer,UNO_QUERY);
+ Reference< XPropertySet > xProp = descriptor;
+ if(xAppend.is())
+ {
+ EnsureReset aReset(m_nInAppend);
+
+ xAppend->appendByDescriptor(descriptor);
+ if(m_xMasterContainer->hasByName(aName))
+ xProp.set(m_xMasterContainer->getByName(aName),UNO_QUERY);
+ }
+ else
+ {
+ OUString sComposedName = ::dbtools::composeTableName( m_xMetaData, descriptor, ::dbtools::EComposeRule::InTableDefinitions, true );
+ if(sComposedName.isEmpty())
+ ::dbtools::throwFunctionSequenceException(static_cast<XTypeProvider*>(static_cast<OFilteredContainer*>(this)));
+
+ OUString sCommand;
+ descriptor->getPropertyValue(PROPERTY_COMMAND) >>= sCommand;
+
+ OUString aSQL = "CREATE VIEW " + sComposedName + " AS " + sCommand;
+
+ Reference<XConnection> xCon = m_xConnection;
+ OSL_ENSURE(xCon.is(),"Connection is null!");
+ if ( xCon.is() )
+ {
+ ::utl::SharedUNOComponent< XStatement > xStmt( xCon->createStatement() );
+ if ( xStmt.is() )
+ xStmt->execute( aSQL );
+ }
+ }
+
+ return createObject( _rForName );
+}
+
+// XDrop
+void OViewContainer::dropObject(sal_Int32 _nPos, const OUString& _sElementName)
+{
+ if ( m_bInElementRemoved )
+ return;
+
+ Reference< XDrop > xDrop(m_xMasterContainer,UNO_QUERY);
+ if(xDrop.is())
+ xDrop->dropByName(_sElementName);
+ else
+ {
+ OUString sComposedName;
+
+ Reference<XPropertySet> xTable(getObject(_nPos),UNO_QUERY);
+ if ( xTable.is() )
+ {
+ OUString sCatalog,sSchema,sTable;
+ xTable->getPropertyValue(PROPERTY_CATALOGNAME) >>= sCatalog;
+ xTable->getPropertyValue(PROPERTY_SCHEMANAME) >>= sSchema;
+ xTable->getPropertyValue(PROPERTY_NAME) >>= sTable;
+
+ sComposedName = ::dbtools::composeTableName( m_xMetaData, sCatalog, sSchema, sTable, true, ::dbtools::EComposeRule::InTableDefinitions );
+ }
+
+ if(sComposedName.isEmpty())
+ ::dbtools::throwFunctionSequenceException(static_cast<XTypeProvider*>(static_cast<OFilteredContainer*>(this)));
+
+ OUString aSql = "DROP VIEW " + sComposedName;
+ Reference<XConnection> xCon = m_xConnection;
+ OSL_ENSURE(xCon.is(),"Connection is null!");
+ if ( xCon.is() )
+ {
+ Reference< XStatement > xStmt = xCon->createStatement( );
+ if(xStmt.is())
+ xStmt->execute(aSql);
+ ::comphelper::disposeComponent(xStmt);
+ }
+ }
+}
+
+void SAL_CALL OViewContainer::elementInserted( const ContainerEvent& Event )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OUString sName;
+ if ( ( Event.Accessor >>= sName )
+ && ( !m_nInAppend )
+ && ( !hasByName( sName ) )
+ )
+ {
+ Reference<XPropertySet> xProp(Event.Element,UNO_QUERY);
+ OUString sType;
+ xProp->getPropertyValue(PROPERTY_TYPE) >>= sType;
+ if ( sType == "VIEW" )
+ insertElement(sName,createObject(sName));
+ }
+}
+
+void SAL_CALL OViewContainer::elementRemoved( const ContainerEvent& Event )
+{
+ ::osl::MutexGuard aGuard(m_rMutex);
+ OUString sName;
+ if ( !((Event.Accessor >>= sName) && hasByName(sName)) )
+ return;
+
+ m_bInElementRemoved = true;
+ try
+ {
+ dropByName(sName);
+ }
+ catch(Exception&)
+ {
+ m_bInElementRemoved = false;
+ throw;
+ }
+ m_bInElementRemoved = false;
+}
+
+void SAL_CALL OViewContainer::disposing( const css::lang::EventObject& /*Source*/ )
+{
+}
+
+void SAL_CALL OViewContainer::elementReplaced( const ContainerEvent& /*Event*/ )
+{
+}
+
+OUString OViewContainer::getTableTypeRestriction() const
+{
+ // no restriction at all (other than the ones provided externally)
+ return "VIEW";
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/ComponentDefinition.cxx b/dbaccess/source/core/dataaccess/ComponentDefinition.cxx
new file mode 100644
index 000000000..a3a645982
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/ComponentDefinition.cxx
@@ -0,0 +1,285 @@
+/* -*- 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 "ComponentDefinition.hxx"
+#include <stringconstants.hxx>
+#include <strings.hxx>
+
+#include <osl/diagnose.h>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+//#include <cppuhelper/interfacecontainer.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <definitioncolumn.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::cppu;
+
+namespace dbaccess
+{
+
+/// helper class for column property change events which holds the OComponentDefinition weak
+class OColumnPropertyListener:
+ public ::cppu::WeakImplHelper< XPropertyChangeListener >
+{
+ OComponentDefinition* m_pComponent;
+protected:
+ virtual ~OColumnPropertyListener() override {}
+public:
+ explicit OColumnPropertyListener(OComponentDefinition* _pComponent) : m_pComponent(_pComponent){}
+ OColumnPropertyListener(const OColumnPropertyListener&) = delete;
+ const OColumnPropertyListener& operator=(const OColumnPropertyListener&) = delete;
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const PropertyChangeEvent& /*_rEvent*/ ) override
+ {
+ if ( m_pComponent )
+ m_pComponent->notifyDataSourceModified();
+ }
+ // XEventListener
+ virtual void SAL_CALL disposing( const EventObject& /*_rSource*/ ) override
+ {
+ }
+ void clear() { m_pComponent = nullptr; }
+};
+
+OComponentDefinition_Impl::OComponentDefinition_Impl()
+{
+}
+
+OComponentDefinition_Impl::~OComponentDefinition_Impl()
+{
+}
+
+// OComponentDefinition
+
+
+void OComponentDefinition::initialize( const Sequence< Any >& aArguments )
+{
+ OUString rName;
+ if( (aArguments.getLength() == 1) && (aArguments[0] >>= rName) )
+ {
+ Sequence<Any> aNewArgs(comphelper::InitAnyPropertySequence(
+ {
+ {PROPERTY_NAME, Any(rName)}
+ }));
+ OContentHelper::initialize(aNewArgs);
+ }
+ else
+ OContentHelper::initialize(aArguments);
+}
+
+void OComponentDefinition::registerProperties()
+{
+ m_xColumnPropertyListener = new OColumnPropertyListener(this);
+ OComponentDefinition_Impl& rDefinition( getDefinition() );
+ ODataSettings::registerPropertiesFor( &rDefinition );
+
+ registerProperty(PROPERTY_NAME, PROPERTY_ID_NAME, PropertyAttribute::BOUND | PropertyAttribute::READONLY|PropertyAttribute::CONSTRAINED,
+ &rDefinition.m_aProps.aTitle, cppu::UnoType<decltype(rDefinition.m_aProps.aTitle)>::get());
+
+ if ( m_bTable )
+ {
+ registerProperty(PROPERTY_SCHEMANAME, PROPERTY_ID_SCHEMANAME, PropertyAttribute::BOUND,
+ &rDefinition.m_sSchemaName, cppu::UnoType<decltype(rDefinition.m_sSchemaName)>::get());
+
+ registerProperty(PROPERTY_CATALOGNAME, PROPERTY_ID_CATALOGNAME, PropertyAttribute::BOUND,
+ &rDefinition.m_sCatalogName, cppu::UnoType<decltype(rDefinition.m_sCatalogName)>::get());
+ }
+}
+
+OComponentDefinition::OComponentDefinition(const Reference< XComponentContext >& _xORB
+ ,const Reference< XInterface >& _xParentContainer
+ ,const TContentPtr& _pImpl
+ ,bool _bTable)
+ :OContentHelper(_xORB,_xParentContainer,_pImpl)
+ ,ODataSettings(OContentHelper::rBHelper,!_bTable)
+ ,m_bTable(_bTable)
+{
+ registerProperties();
+}
+
+OComponentDefinition::~OComponentDefinition()
+{
+}
+
+OComponentDefinition::OComponentDefinition( const Reference< XInterface >& _rxContainer
+ ,const OUString& _rElementName
+ ,const Reference< XComponentContext >& _xORB
+ ,const TContentPtr& _pImpl
+ ,bool _bTable)
+ :OContentHelper(_xORB,_rxContainer,_pImpl)
+ ,ODataSettings(OContentHelper::rBHelper,!_bTable)
+ ,m_bTable(_bTable)
+{
+ registerProperties();
+
+ m_pImpl->m_aProps.aTitle = _rElementName;
+ OSL_ENSURE(!m_pImpl->m_aProps.aTitle.isEmpty(), "OComponentDefinition::OComponentDefinition : invalid name !");
+}
+
+css::uno::Sequence<sal_Int8> OComponentDefinition::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+css::uno::Sequence< css::uno::Type > OComponentDefinition::getTypes()
+{
+ return ::comphelper::concatSequences(
+ ODataSettings::getTypes( ),
+ OContentHelper::getTypes( ),
+ OComponentDefinition_BASE::getTypes( )
+ );
+}
+IMPLEMENT_FORWARD_XINTERFACE3( OComponentDefinition,OContentHelper,ODataSettings,OComponentDefinition_BASE)
+
+OUString SAL_CALL OComponentDefinition::getImplementationName()
+{
+ return "com.sun.star.comp.dba.OComponentDefinition";
+}
+
+Sequence< OUString > SAL_CALL OComponentDefinition::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.TableDefinition", "com.sun.star.ucb.Content" };
+}
+
+void SAL_CALL OComponentDefinition::disposing()
+{
+ OContentHelper::disposing();
+ if (m_pColumns)
+ {
+ m_pColumns->disposing();
+ }
+ m_xColumnPropertyListener->clear();
+ m_xColumnPropertyListener.clear();
+}
+
+IPropertyArrayHelper& OComponentDefinition::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+IPropertyArrayHelper* OComponentDefinition::createArrayHelper( ) const
+{
+ Sequence< Property > aProps;
+ describeProperties(aProps);
+ return new OPropertyArrayHelper(aProps);
+}
+
+Reference< XPropertySetInfo > SAL_CALL OComponentDefinition::getPropertySetInfo( )
+{
+ Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+
+OUString OComponentDefinition::determineContentType() const
+{
+ return m_bTable
+ ? OUString( "application/vnd.org.openoffice.DatabaseTable" )
+ : OUString( "application/vnd.org.openoffice.DatabaseCommandDefinition" );
+}
+
+Reference< XNameAccess> OComponentDefinition::getColumns()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(OContentHelper::rBHelper.bDisposed);
+
+ if (!m_pColumns)
+ {
+ std::vector< OUString> aNames;
+
+ const OComponentDefinition_Impl& rDefinition( getDefinition() );
+ aNames.reserve( rDefinition.size() );
+
+ for (auto const& definition : rDefinition)
+ aNames.push_back(definition.first);
+
+ m_pColumns.reset(new OColumns(*this, m_aMutex, true, aNames, this, nullptr, true, false, false));
+ m_pColumns->setParent(*this);
+ }
+ // see OCollection::acquire
+ return m_pColumns.get();
+}
+
+rtl::Reference<OColumn> OComponentDefinition::createColumn(const OUString& _rName) const
+{
+ const OComponentDefinition_Impl& rDefinition( getDefinition() );
+ OComponentDefinition_Impl::const_iterator aFind = rDefinition.find( _rName );
+ if ( aFind != rDefinition.end() )
+ {
+ aFind->second->addPropertyChangeListener(OUString(),m_xColumnPropertyListener);
+ return new OTableColumnWrapper( aFind->second, aFind->second, true );
+ }
+ OSL_FAIL( "OComponentDefinition::createColumn: is this a valid case?" );
+ // This here is the last place creating a OTableColumn, and somehow /me thinks it is not needed ...
+ return new OTableColumn( _rName );
+}
+
+Reference< XPropertySet > OComponentDefinition::createColumnDescriptor()
+{
+ return new OTableColumnDescriptor( true );
+}
+
+void OComponentDefinition::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
+{
+ ODataSettings::setFastPropertyValue_NoBroadcast(nHandle,rValue);
+ notifyDataSourceModified();
+}
+
+void OComponentDefinition::columnDropped(const OUString& _sName)
+{
+ getDefinition().erase( _sName );
+ notifyDataSourceModified();
+}
+
+void OComponentDefinition::columnAppended( const Reference< XPropertySet >& _rxSourceDescriptor )
+{
+ OUString sName;
+ _rxSourceDescriptor->getPropertyValue( PROPERTY_NAME ) >>= sName;
+
+ Reference<XPropertySet> xColDesc = new OTableColumnDescriptor( true );
+ ::comphelper::copyProperties( _rxSourceDescriptor, xColDesc );
+ getDefinition().insert( sName, xColDesc );
+
+ // formerly, here was a setParent at the xColDesc. The parent used was an adapter (ChildHelper_Impl)
+ // which held another XChild weak, and forwarded all getParent requests to this other XChild.
+ // m_pColumns was used for this. This was nonsense, since m_pColumns dies when our instance dies,
+ // but xColDesc will live longer than this. So effectively, the setParent call was pretty useless.
+ //
+ // The intention for this parenting was that the column descriptor is able to find the data source,
+ // by traveling up the parent hierarchy until there's an XDataSource. This didn't work (which
+ // for instance causes #i65023#). We need another way to properly ensure this.
+
+ notifyDataSourceModified();
+}
+
+} // namespace dbaccess
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dba_OComponentDefinition(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new dbaccess::OComponentDefinition(
+ context, nullptr, std::make_shared<dbaccess::OComponentDefinition_Impl>()));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/ComponentDefinition.hxx b/dbaccess/source/core/dataaccess/ComponentDefinition.hxx
new file mode 100644
index 000000000..4c10a5354
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/ComponentDefinition.hxx
@@ -0,0 +1,159 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <commandbase.hxx>
+#include <com/sun/star/sdbcx/XRename.hpp>
+#include <cppuhelper/implbase1.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <rtl/ref.hxx>
+#include <datasettings.hxx>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <ContentHelper.hxx>
+#include <apitools.hxx>
+#include <column.hxx>
+
+#include <memory>
+namespace dbaccess
+{
+
+ typedef ::cppu::ImplHelper1< css::sdbcx::XColumnsSupplier > OComponentDefinition_BASE;
+
+ class OComponentDefinition_Impl : public OContentHelper_Impl
+ ,public ODataSettings_Base
+ {
+ public:
+ typedef std::map < OUString
+ , css::uno::Reference< css::beans::XPropertySet >
+ > Columns;
+ typedef Columns::iterator iterator;
+ typedef Columns::const_iterator const_iterator;
+
+ private:
+ Columns m_aColumns;
+
+ public:
+ OUString m_sSchemaName;
+ OUString m_sCatalogName;
+
+ public:
+ OComponentDefinition_Impl();
+ virtual ~OComponentDefinition_Impl() override;
+
+ size_t size() const { return m_aColumns.size(); }
+
+ const_iterator begin() const { return m_aColumns.begin(); }
+ const_iterator end() const { return m_aColumns.end(); }
+
+ const_iterator find( const OUString& _rName ) const { return m_aColumns.find( _rName ); }
+
+ void erase( const OUString& _rName ) { m_aColumns.erase( _rName ); }
+
+ void insert( const OUString& _rName, const css::uno::Reference< css::beans::XPropertySet >& _rxColumn )
+ {
+ OSL_PRECOND( m_aColumns.find( _rName ) == m_aColumns.end(), "OComponentDefinition_Impl::insert: there's already an element with this name!" );
+ m_aColumns.emplace( _rName, _rxColumn );
+ }
+ };
+
+class OColumnPropertyListener;
+// OComponentDefinition - a database "document" which describes a query
+class OComponentDefinition :public OContentHelper
+ ,public ODataSettings
+ ,public IColumnFactory
+ ,public OComponentDefinition_BASE
+ ,public ::comphelper::OPropertyArrayUsageHelper< OComponentDefinition >
+{
+ // no Reference! see OCollection::acquire
+ std::unique_ptr<OColumns> m_pColumns;
+ rtl::Reference<OColumnPropertyListener> m_xColumnPropertyListener;
+ bool m_bTable;
+
+protected:
+ virtual ~OComponentDefinition() override;
+ virtual void SAL_CALL disposing() override;
+
+ const OComponentDefinition_Impl& getDefinition() const { return dynamic_cast< const OComponentDefinition_Impl& >( *m_pImpl ); }
+ OComponentDefinition_Impl& getDefinition() { return dynamic_cast< OComponentDefinition_Impl& >( *m_pImpl ); }
+public:
+ OComponentDefinition(
+ const css::uno::Reference< css::uno::XComponentContext >&,
+ const css::uno::Reference< css::uno::XInterface >& _xParentContainer,
+ const TContentPtr& _pImpl,
+ bool _bTable = true);
+
+ OComponentDefinition(
+ const css::uno::Reference< css::uno::XInterface >& _rxContainer
+ ,const OUString& _rElementName
+ ,const css::uno::Reference< css::uno::XComponentContext >&
+ ,const TContentPtr& _pImpl
+ ,bool _bTable = true
+ );
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+// css::uno::XInterface
+ DECLARE_XINTERFACE( )
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( css::uno::Sequence< css::uno::Any > const & rArguments) override;
+
+ // css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // IColumnFactory
+ virtual rtl::Reference<OColumn> createColumn(const OUString& _rName) const override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createColumnDescriptor() override;
+ virtual void columnAppended( const css::uno::Reference< css::beans::XPropertySet >& _rxSourceDescriptor ) override;
+ virtual void columnDropped(const OUString& _sName) override;
+ using OContentHelper::notifyDataSourceModified;
+
+protected:
+// OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue) override;
+
+ // OContentHelper overridables
+ virtual OUString determineContentType() const override;
+
+private:
+ void registerProperties();
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/ContentHelper.cxx b/dbaccess/source/core/dataaccess/ContentHelper.cxx
new file mode 100644
index 000000000..558dd7450
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/ContentHelper.cxx
@@ -0,0 +1,615 @@
+/* -*- 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 <ContentHelper.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <ucbhelper/cancelcommandexecution.hxx>
+#include <com/sun/star/ucb/UnsupportedCommandException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/lang/IllegalAccessException.hpp>
+#include <com/sun/star/beans/IllegalTypeException.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <ucbhelper/propertyvalueset.hxx>
+#include <ucbhelper/contentidentifier.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <tools/diagnose_ex.h>
+#include <sdbcoretools.hxx>
+#include <stringconstants.hxx>
+#include <strings.hxx>
+
+#include <map>
+
+namespace dbaccess
+{
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::container;
+using namespace ::cppu;
+
+OContentHelper_Impl::OContentHelper_Impl()
+ : m_pDataSource(nullptr)
+{
+}
+
+OContentHelper_Impl::~OContentHelper_Impl()
+{
+}
+
+OContentHelper::OContentHelper(const Reference< XComponentContext >& _xORB
+ ,const Reference< XInterface >& _xParentContainer
+ ,const TContentPtr& _pImpl)
+ : OContentHelper_COMPBASE(m_aMutex)
+ ,m_aContentListeners(m_aMutex)
+ ,m_aPropertyChangeListeners(m_aMutex)
+ ,m_xParentContainer( _xParentContainer )
+ ,m_aContext( _xORB )
+ ,m_pImpl(_pImpl)
+ ,m_nCommandId(0)
+{
+}
+
+void SAL_CALL OContentHelper::disposing()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ // say goodbye to our listeners
+ EventObject aEvt(*this);
+ m_aContentListeners.disposeAndClear(aEvt);
+
+ m_xParentContainer = nullptr;
+}
+
+OUString SAL_CALL OContentHelper::getImplementationName()
+ {
+ return "com.sun.star.comp.sdb.Content";
+ }
+sal_Bool SAL_CALL OContentHelper::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ }
+css::uno::Sequence< OUString > SAL_CALL OContentHelper::getSupportedServiceNames()
+{
+ return { "com.sun.star.ucb.Content" };
+}
+
+
+const css::uno::Sequence<sal_Int8> & OContentHelper::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit aId;
+ return aId.getSeq();
+}
+
+css::uno::Sequence<sal_Int8> OContentHelper::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XContent
+Reference< XContentIdentifier > SAL_CALL OContentHelper::getIdentifier( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ OUString aIdentifier( "private:" + impl_getHierarchicalName( true ) );
+ return new ::ucbhelper::ContentIdentifier( aIdentifier );
+}
+
+OUString OContentHelper::impl_getHierarchicalName( bool _includingRootContainer ) const
+{
+ OUStringBuffer aHierarchicalName( m_pImpl->m_aProps.aTitle );
+ Reference< XInterface > xParent = m_xParentContainer;
+ while( xParent.is() )
+ {
+ Reference<XPropertySet> xProp( xParent, UNO_QUERY );
+ Reference< XChild > xChild( xParent, UNO_QUERY );
+ xParent.set( xChild.is() ? xChild->getParent() : Reference< XInterface >(), UNO_QUERY );
+ if ( xProp.is() && xParent.is() )
+ {
+ OUString sName;
+ xProp->getPropertyValue( PROPERTY_NAME ) >>= sName;
+
+ OUString sPrevious = aHierarchicalName.makeStringAndClear();
+ aHierarchicalName.append( sName + "/" + sPrevious );
+ }
+ }
+ OUString sHierarchicalName( aHierarchicalName.makeStringAndClear() );
+ if ( !_includingRootContainer )
+ sHierarchicalName = sHierarchicalName.copy( sHierarchicalName.indexOf( '/' ) + 1 );
+ return sHierarchicalName;
+}
+
+OUString SAL_CALL OContentHelper::getContentType()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if ( !m_pImpl->m_aProps.aContentType )
+ { // content type not yet retrieved
+ m_pImpl->m_aProps.aContentType = determineContentType();
+ }
+
+ return *m_pImpl->m_aProps.aContentType;
+}
+
+void SAL_CALL OContentHelper::addContentEventListener( const Reference< XContentEventListener >& _rxListener )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if ( _rxListener.is() )
+ m_aContentListeners.addInterface(_rxListener);
+}
+
+void SAL_CALL OContentHelper::removeContentEventListener( const Reference< XContentEventListener >& _rxListener )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if (_rxListener.is())
+ m_aContentListeners.removeInterface(_rxListener);
+}
+
+// XCommandProcessor
+sal_Int32 SAL_CALL OContentHelper::createCommandIdentifier( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ // Just increase counter on every call to generate an identifier.
+ return ++m_nCommandId;
+}
+
+Any SAL_CALL OContentHelper::execute( const Command& aCommand, sal_Int32 /*CommandId*/, const Reference< XCommandEnvironment >& Environment )
+{
+ Any aRet;
+ if ( aCommand.Name == "getPropertyValues" )
+ {
+ // getPropertyValues
+
+ Sequence< Property > Properties;
+ if ( !( aCommand.Argument >>= Properties ) )
+ {
+ OSL_FAIL( "Wrong argument type!" );
+ ucbhelper::cancelCommandExecution(
+ Any( IllegalArgumentException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ -1 ) ),
+ Environment );
+ // Unreachable
+ }
+ aRet <<= getPropertyValues( Properties);
+ }
+ else if ( aCommand.Name == "setPropertyValues" )
+ {
+ // setPropertyValues
+
+ Sequence< PropertyValue > aProperties;
+ if ( !( aCommand.Argument >>= aProperties ) )
+ {
+ OSL_FAIL( "Wrong argument type!" );
+ ucbhelper::cancelCommandExecution(
+ Any( IllegalArgumentException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ -1 ) ),
+ Environment );
+ // Unreachable
+ }
+
+ if ( !aProperties.hasElements() )
+ {
+ OSL_FAIL( "No properties!" );
+ ucbhelper::cancelCommandExecution(
+ Any( IllegalArgumentException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ -1 ) ),
+ Environment );
+ // Unreachable
+ }
+
+ aRet <<= setPropertyValues( aProperties );
+ }
+ else if ( aCommand.Name == "getPropertySetInfo" )
+ {
+ // getPropertySetInfo
+
+ Reference<XPropertySet> xProp(*this,UNO_QUERY);
+ if ( xProp.is() )
+ aRet <<= xProp->getPropertySetInfo();
+ // aRet <<= getPropertySetInfo(); // TODO
+ }
+ else
+ {
+ // Unsupported command
+
+ OSL_FAIL( "Content::execute - unsupported command!" );
+
+ ucbhelper::cancelCommandExecution(
+ Any( UnsupportedCommandException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ) ) ),
+ Environment );
+ // Unreachable
+ }
+
+ return aRet;
+}
+
+void SAL_CALL OContentHelper::abort( sal_Int32 /*CommandId*/ )
+{
+}
+
+// XPropertiesChangeNotifier
+void SAL_CALL OContentHelper::addPropertiesChangeListener( const Sequence< OUString >& PropertyNames, const Reference< XPropertiesChangeListener >& Listener )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ sal_Int32 nCount = PropertyNames.getLength();
+ if ( !nCount )
+ {
+ // Note: An empty sequence means a listener for "all" properties.
+ m_aPropertyChangeListeners.addInterface(OUString(), Listener );
+ }
+ else
+ {
+ const OUString* pSeq = PropertyNames.getConstArray();
+
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ const OUString& rName = pSeq[ n ];
+ if ( !rName.isEmpty() )
+ m_aPropertyChangeListeners.addInterface(rName, Listener );
+ }
+ }
+}
+
+void SAL_CALL OContentHelper::removePropertiesChangeListener( const Sequence< OUString >& PropertyNames, const Reference< XPropertiesChangeListener >& Listener )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ sal_Int32 nCount = PropertyNames.getLength();
+ if ( !nCount )
+ {
+ // Note: An empty sequence means a listener for "all" properties.
+ m_aPropertyChangeListeners.removeInterface( OUString(), Listener );
+ }
+ else
+ {
+ const OUString* pSeq = PropertyNames.getConstArray();
+
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ const OUString& rName = pSeq[ n ];
+ if ( !rName.isEmpty() )
+ m_aPropertyChangeListeners.removeInterface( rName, Listener );
+ }
+ }
+}
+
+// XPropertyContainer
+void SAL_CALL OContentHelper::addProperty( const OUString& /*Name*/, sal_Int16 /*Attributes*/, const Any& /*DefaultValue*/ )
+{
+ OSL_FAIL( "OContentHelper::addProperty: not implemented!" );
+}
+
+void SAL_CALL OContentHelper::removeProperty( const OUString& /*Name*/ )
+{
+ OSL_FAIL( "OContentHelper::removeProperty: not implemented!" );
+}
+
+// XInitialization
+void SAL_CALL OContentHelper::initialize( const Sequence< Any >& _aArguments )
+{
+ const Any* pBegin = _aArguments.getConstArray();
+ const Any* pEnd = pBegin + _aArguments.getLength();
+ PropertyValue aValue;
+ for(;pBegin != pEnd;++pBegin)
+ {
+ *pBegin >>= aValue;
+ if ( aValue.Name == "Parent" )
+ {
+ m_xParentContainer.set(aValue.Value,UNO_QUERY);
+ }
+ else if ( aValue.Name == PROPERTY_NAME )
+ {
+ aValue.Value >>= m_pImpl->m_aProps.aTitle;
+ }
+ else if ( aValue.Name == PROPERTY_PERSISTENT_NAME )
+ {
+ aValue.Value >>= m_pImpl->m_aProps.sPersistentName;
+ }
+ }
+}
+
+Sequence< Any > OContentHelper::setPropertyValues(const Sequence< PropertyValue >& rValues )
+{
+ osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
+
+ Sequence< Any > aRet( rValues.getLength() );
+ auto aRetRange = asNonConstRange(aRet);
+ Sequence< PropertyChangeEvent > aChanges( rValues.getLength() );
+ sal_Int32 nChanged = 0;
+
+ PropertyChangeEvent aEvent;
+ aEvent.Source = static_cast< cppu::OWeakObject * >( this );
+ aEvent.Further = false;
+ aEvent.PropertyHandle = -1;
+
+ const PropertyValue* pValues = rValues.getConstArray();
+ sal_Int32 nCount = rValues.getLength();
+
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ const PropertyValue& rValue = pValues[ n ];
+
+ if ( rValue.Name == "ContentType" || rValue.Name == "IsDocument" || rValue.Name == "IsFolder" )
+ {
+ // Read-only property!
+ aRetRange[ n ] <<= IllegalAccessException("Property is read-only!",
+ static_cast< cppu::OWeakObject * >( this ) );
+ }
+ else if ( rValue.Name == "Title" )
+ {
+ OUString aNewValue;
+ if ( rValue.Value >>= aNewValue )
+ {
+ if ( aNewValue != m_pImpl->m_aProps.aTitle )
+ {
+ aEvent.PropertyName = rValue.Name;
+ aEvent.OldValue <<= m_pImpl->m_aProps.aTitle;
+
+ try
+ {
+ impl_rename_throw( aNewValue ,false);
+ OSL_ENSURE( m_pImpl->m_aProps.aTitle == aNewValue, "OContentHelper::setPropertyValues('Title'): rename did not work!" );
+
+ aEvent.NewValue <<= aNewValue;
+ aChanges.getArray()[ nChanged ] = aEvent;
+ nChanged++;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "OContentHelper::setPropertyValues('Title'): caught an exception while renaming!" );
+ }
+ }
+ else
+ {
+ // Old value equals new value. No error!
+ }
+ }
+ else
+ {
+ aRetRange[ n ] <<= IllegalTypeException("Property value has wrong type!",
+ static_cast< cppu::OWeakObject * >( this ) );
+ }
+ }
+
+ else
+ {
+ aRetRange[ n ] <<= Exception("No property set for storing the value!",
+ static_cast< cppu::OWeakObject * >( this ) );
+ }
+ }
+
+ if ( nChanged > 0 )
+ {
+ notifyDataSourceModified();
+ aGuard.clear();
+ aChanges.realloc( nChanged );
+ notifyPropertiesChange( aChanges );
+ }
+
+ return aRet;
+}
+
+// static
+Reference< XRow > OContentHelper::getPropertyValues( const Sequence< Property >& rProperties)
+{
+ // Note: Empty sequence means "get values of all supported properties".
+
+ rtl::Reference< ::ucbhelper::PropertyValueSet > xRow = new ::ucbhelper::PropertyValueSet( m_aContext );
+
+ sal_Int32 nCount = rProperties.getLength();
+ if ( nCount )
+ {
+ const Property* pProps = rProperties.getConstArray();
+ for ( sal_Int32 n = 0; n < nCount; ++n )
+ {
+ const Property& rProp = pProps[ n ];
+
+ // Process Core properties.
+
+ if ( rProp.Name == "ContentType" )
+ {
+ xRow->appendString ( rProp, getContentType() );
+ }
+ else if ( rProp.Name == "Title" )
+ {
+ xRow->appendString ( rProp, m_pImpl->m_aProps.aTitle );
+ }
+ else if ( rProp.Name == "IsDocument" )
+ {
+ xRow->appendBoolean( rProp, m_pImpl->m_aProps.bIsDocument );
+ }
+ else if ( rProp.Name == "IsFolder" )
+ {
+ xRow->appendBoolean( rProp, m_pImpl->m_aProps.bIsFolder );
+ }
+ else
+ xRow->appendVoid(rProp);
+ }
+ }
+ else
+ {
+ // Append all Core Properties.
+ xRow->appendString (
+ Property( "ContentType", -1,
+ cppu::UnoType<OUString>::get(),
+ PropertyAttribute::BOUND
+ | PropertyAttribute::READONLY ),
+ getContentType() );
+ xRow->appendString (
+ Property( "Title", -1,
+ cppu::UnoType<OUString>::get(),
+ PropertyAttribute::BOUND ),
+ m_pImpl->m_aProps.aTitle );
+ xRow->appendBoolean(
+ Property( "IsDocument", -1,
+ cppu::UnoType<bool>::get(),
+ PropertyAttribute::BOUND
+ | PropertyAttribute::READONLY ),
+ m_pImpl->m_aProps.bIsDocument );
+ xRow->appendBoolean(
+ Property( "IsFolder", -1,
+ cppu::UnoType<bool>::get(),
+ PropertyAttribute::BOUND
+ | PropertyAttribute::READONLY ),
+ m_pImpl->m_aProps.bIsFolder );
+
+ // @@@ Append other properties supported directly.
+ }
+
+ return xRow;
+}
+
+void OContentHelper::notifyPropertiesChange( const Sequence< PropertyChangeEvent >& evt ) const
+{
+
+ sal_Int32 nCount = evt.getLength();
+ if ( !nCount )
+ return;
+
+ // First, notify listeners interested in changes of every property.
+ comphelper::OInterfaceContainerHelper3<XPropertiesChangeListener>* pAllPropsContainer = m_aPropertyChangeListeners.getContainer( OUString() );
+ if ( pAllPropsContainer )
+ pAllPropsContainer->notifyEach( &XPropertiesChangeListener::propertiesChange, evt );
+
+ typedef std::map< XPropertiesChangeListener*, Sequence< PropertyChangeEvent > > PropertiesEventListenerMap;
+ PropertiesEventListenerMap aListeners;
+
+ const PropertyChangeEvent* propertyChangeEvent = evt.getConstArray();
+
+ for ( sal_Int32 n = 0; n < nCount; ++n, ++propertyChangeEvent )
+ {
+ const PropertyChangeEvent& rEvent = *propertyChangeEvent;
+ const OUString& rName = rEvent.PropertyName;
+
+ comphelper::OInterfaceContainerHelper3<XPropertiesChangeListener>* pPropsContainer = m_aPropertyChangeListeners.getContainer( rName );
+ if ( pPropsContainer )
+ {
+ comphelper::OInterfaceIteratorHelper3 aIter( *pPropsContainer );
+ while ( aIter.hasMoreElements() )
+ {
+ Sequence< PropertyChangeEvent >* propertyEvents;
+
+ XPropertiesChangeListener* pListener = aIter.next().get();
+ PropertiesEventListenerMap::iterator it = aListeners.find( pListener );
+ if ( it == aListeners.end() )
+ {
+ // Not in map - create and insert new entry.
+ auto pair = aListeners.emplace( pListener, Sequence< PropertyChangeEvent >( nCount ));
+ propertyEvents = &pair.first->second;
+ }
+ else
+ propertyEvents = &(*it).second;
+
+ propertyEvents->getArray()[n] = rEvent;
+ }
+ }
+ }
+
+ // Notify listeners.
+ for (auto & rPair : aListeners)
+ {
+ XPropertiesChangeListener* pListener = rPair.first;
+ Sequence< PropertyChangeEvent >& rSeq = rPair.second;
+
+ // Propagate event.
+ pListener->propertiesChange( rSeq );
+ }
+}
+
+// css::lang::XUnoTunnel
+sal_Int64 OContentHelper::getSomething( const Sequence< sal_Int8 > & rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+Reference< XInterface > SAL_CALL OContentHelper::getParent( )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ return m_xParentContainer;
+}
+
+void SAL_CALL OContentHelper::setParent( const Reference< XInterface >& _xParent )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ m_xParentContainer = _xParent;
+}
+
+void OContentHelper::impl_rename_throw(const OUString& _sNewName,bool _bNotify )
+{
+ osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex);
+ if ( _sNewName == m_pImpl->m_aProps.aTitle )
+ return;
+ try
+ {
+ Sequence<PropertyChangeEvent> aChanges{
+ { /* Source */ static_cast<cppu::OWeakObject*>(this),
+ /* PropertyName */ PROPERTY_NAME,
+ /* Further */ false,
+ /* PropertyHandle */ PROPERTY_ID_NAME,
+ /* OldValue */ Any(m_pImpl->m_aProps.aTitle),
+ /* NewValue */ Any(_sNewName) }
+ };
+
+ aGuard.clear();
+
+ m_pImpl->m_aProps.aTitle = _sNewName;
+ if ( _bNotify )
+ notifyPropertiesChange( aChanges );
+ notifyDataSourceModified();
+ }
+ catch(const PropertyVetoException&)
+ {
+ throw ElementExistException(_sNewName,*this);
+ }
+}
+
+void SAL_CALL OContentHelper::rename( const OUString& newName )
+{
+
+ impl_rename_throw(newName);
+
+}
+
+void OContentHelper::notifyDataSourceModified()
+{
+ ::dbaccess::notifyDataSourceModified(m_xParentContainer);
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/ModelImpl.cxx b/dbaccess/source/core/dataaccess/ModelImpl.cxx
new file mode 100644
index 000000000..5a4078fcc
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/ModelImpl.cxx
@@ -0,0 +1,1432 @@
+/* -*- 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 <databasecontext.hxx>
+#include "databasedocument.hxx"
+#include "datasource.hxx"
+#include <definitioncontainer.hxx>
+#include <ModelImpl.hxx>
+#include <sdbcoretools.hxx>
+
+#include <com/sun/star/beans/PropertyBag.hpp>
+#include <com/sun/star/container/XSet.hpp>
+#include <com/sun/star/document/MacroExecMode.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/embed/XTransactionBroadcaster.hpp>
+#include <com/sun/star/embed/StorageFactory.hpp>
+#include <com/sun/star/frame/theGlobalEventBroadcaster.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/sdb/BooleanComparisonMode.hpp>
+#include <com/sun/star/script/DocumentScriptLibraryContainer.hpp>
+#include <com/sun/star/script/DocumentDialogLibraryContainer.hpp>
+#include <com/sun/star/util/NumberFormatsSupplier.hpp>
+#include <com/sun/star/security/DocumentDigitalSignatures.hpp>
+#include <com/sun/star/security/XDocumentDigitalSignatures.hpp>
+#include <com/sun/star/task/DocumentMacroConfirmationRequest.hpp>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/processfactory.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/signaturestate.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/file.hxx>
+#include <osl/diagnose.h>
+#include <sal/log.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/configmgr.hxx>
+#include <unotools/tempfile.hxx>
+#include <i18nlangtag/languagetag.hxx>
+
+#include <algorithm>
+
+using namespace css;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::view;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::script;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace ::comphelper;
+
+namespace dbaccess
+{
+
+// DocumentStorageAccess
+class DocumentStorageAccess : public ::cppu::WeakImplHelper< XDocumentSubStorageSupplier
+ , XTransactionListener >
+{
+ typedef std::map< OUString, Reference< XStorage > > NamedStorages;
+
+ ::osl::Mutex m_aMutex;
+ /// all sub storages which we ever gave to the outer world
+ NamedStorages m_aExposedStorages;
+ ODatabaseModelImpl* m_pModelImplementation;
+ bool m_bPropagateCommitToRoot;
+ bool m_bDisposingSubStorages;
+
+public:
+ explicit DocumentStorageAccess( ODatabaseModelImpl& _rModelImplementation )
+ :m_pModelImplementation( &_rModelImplementation )
+ ,m_bPropagateCommitToRoot( true )
+ ,m_bDisposingSubStorages( false )
+ {
+ }
+
+protected:
+ virtual ~DocumentStorageAccess() override
+ {
+ }
+
+public:
+ void dispose();
+
+ // XDocumentSubStorageSupplier
+ virtual Reference< XStorage > SAL_CALL getDocumentSubStorage( const OUString& aStorageName, ::sal_Int32 _nMode ) override;
+ virtual Sequence< OUString > SAL_CALL getDocumentSubStoragesNames( ) override;
+
+ // XTransactionListener
+ virtual void SAL_CALL preCommit( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL commited( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL preRevert( const css::lang::EventObject& aEvent ) override;
+ virtual void SAL_CALL reverted( const css::lang::EventObject& aEvent ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ /// disposes all storages managed by this instance
+ void disposeStorages();
+
+ /// disposes all known sub storages
+ void commitStorages();
+
+ /// commits the dedicated "database" storage
+ bool commitEmbeddedStorage( bool _bPreventRootCommits );
+
+private:
+ /** opens the sub storage with the given name, in the given mode
+ */
+ Reference< XStorage > impl_openSubStorage_nothrow( const OUString& _rStorageName, sal_Int32 _nMode );
+
+ void impl_suspendCommitPropagation()
+ {
+ OSL_ENSURE( m_bPropagateCommitToRoot, "DocumentStorageAccess::impl_suspendCommitPropagation: already suspended" );
+ m_bPropagateCommitToRoot = false;
+ }
+ void impl_resumeCommitPropagation()
+ {
+ OSL_ENSURE( !m_bPropagateCommitToRoot, "DocumentStorageAccess::impl_resumeCommitPropagation: not suspended" );
+ m_bPropagateCommitToRoot = true;
+ }
+
+};
+
+void DocumentStorageAccess::dispose()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ for (auto const& exposedStorage : m_aExposedStorages)
+ {
+ try
+ {
+ Reference< XTransactionBroadcaster > xBroadcaster(exposedStorage.second, UNO_QUERY);
+ if ( xBroadcaster.is() )
+ xBroadcaster->removeTransactionListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ m_aExposedStorages.clear();
+
+ m_pModelImplementation = nullptr;
+}
+
+Reference< XStorage > DocumentStorageAccess::impl_openSubStorage_nothrow( const OUString& _rStorageName, sal_Int32 _nDesiredMode )
+{
+ OSL_ENSURE( !_rStorageName.isEmpty(),"ODatabaseModelImpl::impl_openSubStorage_nothrow: Invalid storage name!" );
+
+ Reference< XStorage > xStorage;
+ try
+ {
+ Reference< XStorage > xRootStorage( m_pModelImplementation->getOrCreateRootStorage() );
+ if ( xRootStorage.is() )
+ {
+ sal_Int32 nRealMode = m_pModelImplementation->m_bDocumentReadOnly ? ElementModes::READ : _nDesiredMode;
+ if ( nRealMode == ElementModes::READ )
+ {
+ if ( xRootStorage.is() && !xRootStorage->hasByName( _rStorageName ) )
+ return xStorage;
+ }
+
+ xStorage = xRootStorage->openStorageElement( _rStorageName, nRealMode );
+
+ Reference< XTransactionBroadcaster > xBroad( xStorage, UNO_QUERY );
+ if ( xBroad.is() )
+ xBroad->addTransactionListener( this );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return xStorage;
+}
+
+void DocumentStorageAccess::disposeStorages()
+{
+ m_bDisposingSubStorages = true;
+
+ for (auto & exposedStorage : m_aExposedStorages)
+ {
+ try
+ {
+ ::comphelper::disposeComponent( exposedStorage.second );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ m_aExposedStorages.clear();
+
+ m_bDisposingSubStorages = false;
+}
+
+void DocumentStorageAccess::commitStorages()
+{
+ try
+ {
+ for (auto const& exposedStorage : m_aExposedStorages)
+ {
+ tools::stor::commitStorageIfWriteable( exposedStorage.second );
+ }
+ }
+ catch(const WrappedTargetException&)
+ {
+ // WrappedTargetException not allowed to leave
+ throw IOException();
+ }
+}
+
+bool DocumentStorageAccess::commitEmbeddedStorage( bool _bPreventRootCommits )
+{
+ if ( _bPreventRootCommits )
+ impl_suspendCommitPropagation();
+
+ bool bSuccess = false;
+ try
+ {
+ NamedStorages::const_iterator pos = m_aExposedStorages.find( "database" );
+ if ( pos != m_aExposedStorages.end() )
+ bSuccess = tools::stor::commitStorageIfWriteable( pos->second );
+ }
+ catch( Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if ( _bPreventRootCommits )
+ impl_resumeCommitPropagation();
+
+ return bSuccess;
+
+}
+
+Reference< XStorage > SAL_CALL DocumentStorageAccess::getDocumentSubStorage( const OUString& aStorageName, ::sal_Int32 _nDesiredMode )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ NamedStorages::const_iterator pos = m_aExposedStorages.find( aStorageName );
+ if ( pos == m_aExposedStorages.end() )
+ {
+ Reference< XStorage > xResult = impl_openSubStorage_nothrow( aStorageName, _nDesiredMode );
+ pos = m_aExposedStorages.emplace( aStorageName, xResult ).first;
+ }
+
+ return pos->second;
+}
+
+Sequence< OUString > SAL_CALL DocumentStorageAccess::getDocumentSubStoragesNames( )
+{
+ Reference< XStorage > xRootStor( m_pModelImplementation->getRootStorage() );
+ if ( !xRootStor.is() )
+ return Sequence< OUString >();
+
+ std::vector< OUString > aNames;
+
+ const Sequence< OUString > aElementNames( xRootStor->getElementNames() );
+ for ( OUString const & name : aElementNames )
+ {
+ if ( xRootStor->isStorageElement( name ) )
+ aNames.push_back( name );
+ }
+ return aNames.empty()
+ ? Sequence< OUString >()
+ : Sequence< OUString >( aNames.data(), aNames.size() );
+}
+
+void SAL_CALL DocumentStorageAccess::preCommit( const css::lang::EventObject& /*aEvent*/ )
+{
+ // not interested in
+}
+
+void SAL_CALL DocumentStorageAccess::commited( const css::lang::EventObject& aEvent )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( m_pModelImplementation )
+ m_pModelImplementation->setModified( true );
+
+ if ( !(m_pModelImplementation && m_bPropagateCommitToRoot) )
+ return;
+
+ Reference< XStorage > xStorage( aEvent.Source, UNO_QUERY );
+
+ // check if this is the dedicated "database" sub storage
+ NamedStorages::const_iterator pos = m_aExposedStorages.find( "database" );
+ if ( ( pos != m_aExposedStorages.end() )
+ && ( pos->second == xStorage )
+ )
+ {
+ // if so, also commit the root storage
+ m_pModelImplementation->commitRootStorage();
+ }
+}
+
+void SAL_CALL DocumentStorageAccess::preRevert( const css::lang::EventObject& /*aEvent*/ )
+{
+ // not interested in
+}
+
+void SAL_CALL DocumentStorageAccess::reverted( const css::lang::EventObject& /*aEvent*/ )
+{
+ // not interested in
+}
+
+void SAL_CALL DocumentStorageAccess::disposing( const css::lang::EventObject& Source )
+{
+ OSL_ENSURE( Reference< XStorage >( Source.Source, UNO_QUERY ).is(), "DocumentStorageAccess::disposing: No storage? What's this?" );
+
+ if ( m_bDisposingSubStorages )
+ return;
+
+ auto find = std::find_if(m_aExposedStorages.begin(), m_aExposedStorages.end(),
+ [&Source](const NamedStorages::value_type& rEntry) { return rEntry.second == Source.Source; });
+ if (find != m_aExposedStorages.end())
+ m_aExposedStorages.erase( find );
+}
+
+// ODatabaseModelImpl
+
+ODatabaseModelImpl::ODatabaseModelImpl( const Reference< XComponentContext >& _rxContext, ODatabaseContext& _rDBContext )
+ :m_aContainer(4)
+ ,m_aMacroMode( *this )
+ ,m_nImposedMacroExecMode( MacroExecMode::NEVER_EXECUTE )
+ ,m_rDBContext( _rDBContext )
+ ,m_refCount(0)
+ ,m_bModificationLock( false )
+ ,m_bDocumentInitialized( false )
+ ,m_nScriptingSignatureState(SignatureState::UNKNOWN)
+ ,m_aContext( _rxContext )
+ ,m_nLoginTimeout(0)
+ ,m_bReadOnly(false)
+ ,m_bPasswordRequired(false)
+ ,m_bSuppressVersionColumns(true)
+ ,m_bModified(false)
+ ,m_bDocumentReadOnly(false)
+ ,m_bMacroCallsSeenWhileLoading(false)
+ ,m_pSharedConnectionManager(nullptr)
+ ,m_nControllerLockCount(0)
+{
+ // some kind of default
+ m_sConnectURL = "jdbc:";
+ m_aTableFilter = { "%" };
+ impl_construct_nothrow();
+}
+
+ODatabaseModelImpl::ODatabaseModelImpl(
+ const OUString& _rRegistrationName,
+ const Reference< XComponentContext >& _rxContext,
+ ODatabaseContext& _rDBContext
+ )
+ :m_aContainer(4)
+ ,m_aMacroMode( *this )
+ ,m_nImposedMacroExecMode( MacroExecMode::NEVER_EXECUTE )
+ ,m_rDBContext( _rDBContext )
+ ,m_refCount(0)
+ ,m_bModificationLock( false )
+ ,m_bDocumentInitialized( false )
+ ,m_nScriptingSignatureState(SignatureState::UNKNOWN)
+ ,m_aContext( _rxContext )
+ ,m_sName(_rRegistrationName)
+ ,m_nLoginTimeout(0)
+ ,m_bReadOnly(false)
+ ,m_bPasswordRequired(false)
+ ,m_bSuppressVersionColumns(true)
+ ,m_bModified(false)
+ ,m_bDocumentReadOnly(false)
+ ,m_bMacroCallsSeenWhileLoading(false)
+ ,m_pSharedConnectionManager(nullptr)
+ ,m_nControllerLockCount(0)
+{
+ impl_construct_nothrow();
+}
+
+ODatabaseModelImpl::~ODatabaseModelImpl()
+{
+}
+
+void ODatabaseModelImpl::impl_construct_nothrow()
+{
+ // create the property bag to hold the settings (also known as "Info" property)
+ try
+ {
+ // the set of property value types in the bag is limited:
+ Sequence< Type > aAllowedTypes({
+ cppu::UnoType<sal_Bool>::get(),
+ cppu::UnoType<double>::get(),
+ cppu::UnoType<OUString>::get(),
+ cppu::UnoType<sal_Int32>::get(),
+ cppu::UnoType<sal_Int16>::get(),
+ cppu::UnoType<Sequence< Any >>::get(),
+ });
+
+ m_xSettings = PropertyBag::createWithTypes( m_aContext, aAllowedTypes, false/*AllowEmptyPropertyName*/, true/*AutomaticAddition*/ );
+
+ // insert the default settings
+ Reference< XPropertyContainer > xContainer( m_xSettings, UNO_QUERY_THROW );
+ Reference< XSet > xSettingsSet( m_xSettings, UNO_QUERY_THROW );
+ const AsciiPropertyValue* pSettings = getDefaultDataSourceSettings();
+ for ( ; pSettings->AsciiName; ++pSettings )
+ {
+ if ( !pSettings->DefaultValue.hasValue() )
+ {
+ Property aProperty(
+ OUString::createFromAscii( pSettings->AsciiName ),
+ -1,
+ pSettings->ValueType,
+ PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT | PropertyAttribute::MAYBEVOID
+ );
+ xSettingsSet->insert( Any( aProperty ) );
+ }
+ else
+ {
+ xContainer->addProperty(
+ OUString::createFromAscii( pSettings->AsciiName ),
+ PropertyAttribute::BOUND | PropertyAttribute::MAYBEDEFAULT,
+ pSettings->DefaultValue
+ );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ m_rDBContext.appendAtTerminateListener(*this);
+}
+
+namespace
+{
+ OUString lcl_getContainerStorageName_throw( ODatabaseModelImpl::ObjectType _eType )
+ {
+ const char* pAsciiName( nullptr );
+ switch ( _eType )
+ {
+ case ODatabaseModelImpl::E_FORM: pAsciiName = "forms"; break;
+ case ODatabaseModelImpl::E_REPORT: pAsciiName = "reports"; break;
+ case ODatabaseModelImpl::E_QUERY: pAsciiName = "queries"; break;
+ case ODatabaseModelImpl::E_TABLE: pAsciiName = "tables"; break;
+ default:
+ throw RuntimeException();
+ }
+ return OUString::createFromAscii( pAsciiName );
+ }
+
+ bool lcl_hasObjectWithMacros_throw( const ODefinitionContainer_Impl& _rObjectDefinitions, const Reference< XStorage >& _rxContainerStorage )
+ {
+ bool bSomeDocHasMacros = false;
+
+ for (auto const& objectDefinition : _rObjectDefinitions)
+ {
+ const TContentPtr& rDefinition( objectDefinition.second );
+ const OUString& rPersistentName( rDefinition->m_aProps.sPersistentName );
+
+ if ( rPersistentName.isEmpty() )
+ { // it's a logical sub folder used to organize the real objects
+ const ODefinitionContainer_Impl& rSubFoldersObjectDefinitions( dynamic_cast< const ODefinitionContainer_Impl& >( *rDefinition ) );
+ bSomeDocHasMacros = lcl_hasObjectWithMacros_throw( rSubFoldersObjectDefinitions, _rxContainerStorage );
+ if (bSomeDocHasMacros)
+ break;
+ continue;
+ }
+
+ bSomeDocHasMacros = ODatabaseModelImpl::objectHasMacros( _rxContainerStorage, rPersistentName );
+ if (bSomeDocHasMacros)
+ break;
+ }
+ return bSomeDocHasMacros;
+ }
+
+ bool lcl_hasObjectsWithMacros_nothrow( ODatabaseModelImpl& _rModel, const ODatabaseModelImpl::ObjectType _eType )
+ {
+ bool bSomeDocHasMacros = false;
+
+ const OContentHelper_Impl& rContainerData( *_rModel.getObjectContainer( _eType ) );
+ const ODefinitionContainer_Impl& rObjectDefinitions = dynamic_cast< const ODefinitionContainer_Impl& >( rContainerData );
+
+ try
+ {
+ Reference< XStorage > xContainerStorage( _rModel.getStorage( _eType ) );
+ // note the READWRITE here: If the storage already existed before, then the OpenMode will
+ // be ignored, anyway.
+ // If the storage did not yet exist, then it will be created. If the database document
+ // is read-only, the OpenMode will be automatically downgraded to READ. Otherwise,
+ // the storage will in fact be created as READWRITE. While this is not strictly necessary
+ // for this particular use case here, it is required since the storage is *cached*, and
+ // later use cases will need the READWRITE mode.
+
+ if ( xContainerStorage.is() )
+ bSomeDocHasMacros = lcl_hasObjectWithMacros_throw( rObjectDefinitions, xContainerStorage );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ // be on the safe side: If we can't reliably determine whether there are macros,
+ // assume there actually are. Better this way, than the other way round.
+ bSomeDocHasMacros = true;
+ }
+
+ return bSomeDocHasMacros;
+ }
+}
+
+bool ODatabaseModelImpl::objectHasMacros( const Reference< XStorage >& _rxContainerStorage, const OUString& _rPersistentName )
+{
+ OSL_PRECOND( _rxContainerStorage.is(), "ODatabaseModelImpl::objectHasMacros: this will crash!" );
+
+ bool bHasMacros = true;
+ try
+ {
+ if ( !_rxContainerStorage->hasByName( _rPersistentName ) )
+ return false;
+
+ Reference< XStorage > xObjectStor( _rxContainerStorage->openStorageElement(
+ _rPersistentName, ElementModes::READ ) );
+
+ bHasMacros = ::sfx2::DocumentMacroMode::storageHasMacros( xObjectStor );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return bHasMacros;
+}
+
+void ODatabaseModelImpl::reset()
+{
+ m_bReadOnly = false;
+ std::vector<TContentPtr>(4).swap(m_aContainer);
+
+ if ( m_pStorageAccess.is() )
+ {
+ m_pStorageAccess->dispose();
+ m_pStorageAccess.clear();
+ }
+}
+
+void ODatabaseModelImpl::disposing( const css::lang::EventObject& Source )
+{
+ Reference<XConnection> xCon(Source.Source,UNO_QUERY);
+ if ( xCon.is() )
+ {
+ bool bStore = false;
+ for (OWeakConnectionArray::iterator i = m_aConnections.begin(); i != m_aConnections.end(); )
+ {
+ css::uno::Reference< css::sdbc::XConnection > xIterConn ( *i );
+ if ( !xIterConn.is())
+ {
+ i = m_aConnections.erase(i);
+ }
+ else if ( xCon == xIterConn )
+ {
+ *i = css::uno::WeakReference< css::sdbc::XConnection >();
+ bStore = true;
+ break;
+ } else
+ ++i;
+ }
+
+ if ( bStore )
+ commitRootStorage();
+ }
+ else
+ {
+ OSL_FAIL( "ODatabaseModelImpl::disposing: where does this come from?" );
+ }
+}
+
+void ODatabaseModelImpl::clearConnections()
+{
+ OWeakConnectionArray aConnections;
+ aConnections.swap( m_aConnections );
+
+ Reference< XConnection > xConn;
+ for (auto const& connection : aConnections)
+ {
+ xConn = connection;
+ if ( xConn.is() )
+ {
+ try
+ {
+ xConn->close();
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+
+ m_pSharedConnectionManager = nullptr;
+ m_xSharedConnectionManager = nullptr;
+}
+
+void ODatabaseModelImpl::dispose()
+{
+ // dispose the data source and the model
+ try
+ {
+ Reference< XDataSource > xDS( m_xDataSource );
+ ::comphelper::disposeComponent( xDS );
+
+ Reference< XModel > xModel( m_xModel );
+ ::comphelper::disposeComponent( xModel );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ m_xDataSource = WeakReference<XDataSource>();
+ m_xModel = WeakReference< XModel >();
+
+ for (auto const& elem : m_aContainer)
+ {
+ if ( elem )
+ elem->m_pDataSource = nullptr;
+ }
+ m_aContainer.clear();
+
+ clearConnections();
+
+ m_xNumberFormatsSupplier = nullptr;
+
+ try
+ {
+ bool bCouldStore = commitEmbeddedStorage( true );
+ // "true" means that committing the embedded storage should not trigger committing the root
+ // storage. This is because we are going to commit the root storage ourself, anyway
+ disposeStorages();
+ if ( bCouldStore )
+ commitRootStorage();
+
+ impl_switchToStorage_throw( nullptr );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if ( m_pStorageAccess.is() )
+ {
+ m_pStorageAccess->dispose();
+ m_pStorageAccess.clear();
+ }
+}
+
+const Reference< XNumberFormatsSupplier > & ODatabaseModelImpl::getNumberFormatsSupplier()
+{
+ if (!m_xNumberFormatsSupplier.is())
+ {
+ // the arguments : the work locale of the current user
+ Locale aLocale( LanguageTag::convertToLocale( utl::ConfigManager::getWorkLocale(), false));
+
+ m_xNumberFormatsSupplier.set( NumberFormatsSupplier::createWithLocale( m_aContext, aLocale ) );
+ }
+ return m_xNumberFormatsSupplier;
+}
+
+void ODatabaseModelImpl::setDocFileLocation( const OUString& i_rLoadedFrom )
+{
+ ENSURE_OR_THROW( !i_rLoadedFrom.isEmpty(), "invalid URL" );
+ m_sDocFileLocation = i_rLoadedFrom;
+}
+
+void ODatabaseModelImpl::setResource( const OUString& i_rDocumentURL, const Sequence< PropertyValue >& _rArgs )
+{
+ ENSURE_OR_THROW( !i_rDocumentURL.isEmpty(), "invalid URL" );
+
+ ::comphelper::NamedValueCollection aMediaDescriptor( _rArgs );
+#if OSL_DEBUG_LEVEL > 0
+ if ( aMediaDescriptor.has( "SalvagedFile" ) )
+ {
+ OUString sSalvagedFile( aMediaDescriptor.getOrDefault( "SalvagedFile", OUString() ) );
+ // If SalvagedFile is an empty string, this indicates "the document is being recovered, but i_rDocumentURL already
+ // is the real document URL, not the temporary document location"
+ if ( sSalvagedFile.isEmpty() )
+ sSalvagedFile = i_rDocumentURL;
+
+ OSL_ENSURE( sSalvagedFile == i_rDocumentURL, "ODatabaseModelImpl::setResource: inconsistency!" );
+ // nowadays, setResource should only be called with the logical URL of the document
+ }
+#endif
+
+ m_aMediaDescriptor = stripLoadArguments( aMediaDescriptor );
+
+ impl_switchToLogicalURL( i_rDocumentURL );
+}
+
+::comphelper::NamedValueCollection ODatabaseModelImpl::stripLoadArguments( const ::comphelper::NamedValueCollection& _rArguments )
+{
+ OSL_ENSURE( !_rArguments.has( "Model" ), "ODatabaseModelImpl::stripLoadArguments: this is suspicious (1)!" );
+ OSL_ENSURE( !_rArguments.has( "ViewName" ), "ODatabaseModelImpl::stripLoadArguments: this is suspicious (2)!" );
+
+ ::comphelper::NamedValueCollection aMutableArgs( _rArguments );
+ aMutableArgs.remove( "Model" );
+ aMutableArgs.remove( "ViewName" );
+ return aMutableArgs;
+}
+
+void ODatabaseModelImpl::disposeStorages()
+{
+ getDocumentStorageAccess()->disposeStorages();
+}
+
+Reference< XSingleServiceFactory > ODatabaseModelImpl::createStorageFactory() const
+{
+ return StorageFactory::create( m_aContext );
+}
+
+void ODatabaseModelImpl::commitRootStorage()
+{
+ Reference< XStorage > xStorage( getOrCreateRootStorage() );
+ bool bSuccess = commitStorageIfWriteable_ignoreErrors( xStorage );
+ SAL_WARN_IF(!bSuccess && xStorage.is(), "dbaccess",
+ "ODatabaseModelImpl::commitRootStorage: could not commit the storage!");
+}
+
+Reference< XStorage > const & ODatabaseModelImpl::getOrCreateRootStorage()
+{
+ if ( !m_xDocumentStorage.is() )
+ {
+ Reference< XSingleServiceFactory> xStorageFactory = StorageFactory::create( m_aContext );
+ Any aSource = m_aMediaDescriptor.get( "Stream" );
+ if ( !aSource.hasValue() )
+ aSource = m_aMediaDescriptor.get( "InputStream" );
+ if ( !aSource.hasValue() && !m_sDocFileLocation.isEmpty() )
+ aSource <<= m_sDocFileLocation;
+ // TODO: shouldn't we also check URL?
+
+ OSL_ENSURE( aSource.hasValue(), "ODatabaseModelImpl::getOrCreateRootStorage: no source to create the storage from!" );
+
+ if ( aSource.hasValue() )
+ {
+ Sequence< Any > aStorageCreationArgs{ aSource, Any(ElementModes::READWRITE) };
+
+ Reference< XStorage > xDocumentStorage;
+ OUString sURL;
+ aSource >>= sURL;
+ // Don't try to load a meta-URL as-is.
+ if (!sURL.startsWithIgnoreAsciiCase("vnd.sun.star.pkg:"))
+ {
+ try
+ {
+ xDocumentStorage.set( xStorageFactory->createInstanceWithArguments( aStorageCreationArgs ), UNO_QUERY_THROW );
+ }
+ catch( const Exception& )
+ {
+ m_bDocumentReadOnly = true;
+ aStorageCreationArgs.getArray()[1] <<= ElementModes::READ;
+ try
+ {
+ xDocumentStorage.set( xStorageFactory->createInstanceWithArguments( aStorageCreationArgs ), UNO_QUERY_THROW );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+
+ impl_switchToStorage_throw( xDocumentStorage );
+ }
+ }
+ return m_xDocumentStorage.getTyped();
+}
+
+DocumentStorageAccess* ODatabaseModelImpl::getDocumentStorageAccess()
+{
+ if ( !m_pStorageAccess.is() )
+ {
+ m_pStorageAccess = new DocumentStorageAccess( *this );
+ }
+ return m_pStorageAccess.get();
+}
+
+void ODatabaseModelImpl::modelIsDisposing( const bool _wasInitialized, ResetModelAccess )
+{
+ m_xModel.clear();
+
+ // Basic libraries and Dialog libraries are a model facet, though held at this impl class.
+ // They automatically dispose themself when the model they belong to is being disposed.
+ // So, to not be tempted to do anything with them, again, we reset them.
+ m_xBasicLibraries.clear();
+ m_xDialogLibraries.clear();
+
+ m_bDocumentInitialized = _wasInitialized;
+}
+
+Reference< XDocumentSubStorageSupplier > ODatabaseModelImpl::getDocumentSubStorageSupplier()
+{
+ return getDocumentStorageAccess();
+}
+
+bool ODatabaseModelImpl::commitEmbeddedStorage( bool _bPreventRootCommits )
+{
+ return getDocumentStorageAccess()->commitEmbeddedStorage( _bPreventRootCommits );
+}
+
+bool ODatabaseModelImpl::commitStorageIfWriteable_ignoreErrors( const Reference< XStorage >& _rxStorage )
+{
+ bool bTryToPreserveScriptSignature = false;
+ utl::TempFile aTempFile;
+ aTempFile.EnableKillingFile();
+ OUString sTmpFileUrl = aTempFile.GetURL();
+ SignatureState aSignatureState = getScriptingSignatureState();
+ OUString sLocation = getDocFileLocation();
+ bool bIsEmbedded = sLocation.startsWith("vnd.sun.star.pkg:") && sLocation.endsWith("/EmbeddedDatabase");
+ if (!bIsEmbedded && !sLocation.isEmpty()
+ && (aSignatureState == SignatureState::OK || aSignatureState == SignatureState::NOTVALIDATED
+ || aSignatureState == SignatureState::INVALID
+ || aSignatureState == SignatureState::UNKNOWN))
+ {
+ bTryToPreserveScriptSignature = true;
+ // We need to first save the file (which removes the macro signature), then add the macro signature again.
+ // For that, we need a temporary copy of the original file.
+ osl::File::RC rc = osl::File::copy(sLocation, sTmpFileUrl);
+ if (rc != osl::FileBase::E_None)
+ throw uno::RuntimeException("Could not create temp file");
+ }
+
+ bool bSuccess = false;
+ try
+ {
+ bSuccess = tools::stor::commitStorageIfWriteable( _rxStorage );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ // Preserve script signature if the script has not changed
+ if (bTryToPreserveScriptSignature)
+ {
+ OUString aODFVersion(comphelper::OStorageHelper::GetODFVersionFromStorage(_rxStorage));
+ uno::Reference<security::XDocumentDigitalSignatures> xDDSigns;
+ try
+ {
+ xDDSigns = security::DocumentDigitalSignatures::createWithVersion(
+ comphelper::getProcessComponentContext(), aODFVersion);
+
+ const OUString aScriptSignName
+ = xDDSigns->getScriptingContentSignatureDefaultStreamName();
+
+ if (!aScriptSignName.isEmpty())
+ {
+ Reference<XStorage> xReadOrig
+ = comphelper::OStorageHelper::GetStorageOfFormatFromURL(
+ ZIP_STORAGE_FORMAT_STRING, sTmpFileUrl, ElementModes::READ);
+ if (!xReadOrig.is())
+ throw uno::RuntimeException("Could not read " + sTmpFileUrl);
+ uno::Reference<embed::XStorage> xMetaInf
+ = xReadOrig->openStorageElement("META-INF", embed::ElementModes::READ);
+
+ uno::Reference<embed::XStorage> xTargetMetaInf
+ = _rxStorage->openStorageElement("META-INF", embed::ElementModes::READWRITE);
+ if (xMetaInf.is() && xTargetMetaInf.is() && xMetaInf->hasByName(aScriptSignName))
+ {
+ xMetaInf->copyElementTo(aScriptSignName, xTargetMetaInf, aScriptSignName);
+
+ uno::Reference<embed::XTransactedObject> xTransact(xTargetMetaInf,
+ uno::UNO_QUERY);
+ if (xTransact.is())
+ xTransact->commit();
+
+ xTargetMetaInf->dispose();
+
+ // now check the copied signature
+ uno::Sequence<security::DocumentSignatureInformation> aInfos
+ = xDDSigns->verifyScriptingContentSignatures(
+ _rxStorage, uno::Reference<io::XInputStream>());
+ SignatureState nState = DocumentSignatures::getSignatureState(aInfos);
+ if (nState == SignatureState::OK || nState == SignatureState::NOTVALIDATED
+ || nState == SignatureState::PARTIAL_OK)
+ {
+ // commit the ZipStorage from target medium
+ xTransact.set(_rxStorage, uno::UNO_QUERY);
+ if (xTransact.is())
+ xTransact->commit();
+ }
+ else
+ {
+ SAL_WARN("dbaccess", "An invalid signature was copied!");
+ }
+ }
+ }
+ }
+ catch (uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "");
+ }
+ }
+
+ return bSuccess;
+}
+
+void ODatabaseModelImpl::setModified( bool _bModified )
+{
+ if ( isModifyLocked() )
+ return;
+
+ try
+ {
+ Reference< XModifiable > xModi( m_xModel.get(), UNO_QUERY );
+ if ( xModi.is() )
+ xModi->setModified( _bModified );
+ else
+ m_bModified = _bModified;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+Reference<XDataSource> ODatabaseModelImpl::getOrCreateDataSource()
+{
+ Reference<XDataSource> xDs = m_xDataSource;
+ if ( !xDs.is() )
+ {
+ xDs = new ODatabaseSource(this);
+ m_xDataSource = xDs;
+ }
+ return xDs;
+}
+
+Reference< XModel> ODatabaseModelImpl::getModel_noCreate() const
+{
+ return m_xModel;
+}
+
+Reference< XModel > ODatabaseModelImpl::createNewModel_deliverOwnership()
+{
+ Reference< XModel > xModel( m_xModel );
+ OSL_PRECOND( !xModel.is(), "ODatabaseModelImpl::createNewModel_deliverOwnership: not to be called if there already is a model!" );
+ if ( !xModel.is() )
+ {
+ bool bHadModelBefore = m_bDocumentInitialized;
+
+ xModel = ODatabaseDocument::createDatabaseDocument( this, ODatabaseDocument::FactoryAccess() );
+ m_xModel = xModel;
+
+ try
+ {
+ Reference< XGlobalEventBroadcaster > xModelCollection = theGlobalEventBroadcaster::get( m_aContext );
+ xModelCollection->insert( Any( xModel ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if ( bHadModelBefore )
+ {
+ // do an attachResources
+ // In case the document is loaded regularly, this is not necessary, as our loader will do it.
+ // However, in case that the document is implicitly created by asking the data source for the document,
+ // then nobody would call the doc's attachResource. So, we do it here, to ensure it's in a proper
+ // state, fires all events, and so on.
+ // #i105505#
+ xModel->attachResource( xModel->getURL(), m_aMediaDescriptor.getPropertyValues() );
+ }
+ }
+ return xModel;
+}
+
+void ODatabaseModelImpl::acquire()
+{
+ osl_atomic_increment(&m_refCount);
+}
+
+void ODatabaseModelImpl::release()
+{
+ if ( osl_atomic_decrement(&m_refCount) == 0 )
+ {
+ acquire(); // prevent multiple releases
+ m_rDBContext.removeFromTerminateListener(*this);
+ dispose();
+ m_rDBContext.storeTransientProperties(*this);
+ if (!m_sDocumentURL.isEmpty())
+ m_rDBContext.revokeDatabaseDocument(*this);
+ delete this;
+ }
+}
+
+void ODatabaseModelImpl::commitStorages()
+{
+ getDocumentStorageAccess()->commitStorages();
+}
+
+Reference< XStorage > ODatabaseModelImpl::getStorage( const ObjectType _eType )
+{
+ return getDocumentStorageAccess()->getDocumentSubStorage( getObjectContainerStorageName( _eType ),
+ css::embed::ElementModes::READWRITE );
+}
+
+const AsciiPropertyValue* ODatabaseModelImpl::getDefaultDataSourceSettings()
+{
+ static const AsciiPropertyValue aKnownSettings[] =
+ {
+ // known JDBC settings
+ AsciiPropertyValue( "JavaDriverClass", Any( OUString() ) ),
+ AsciiPropertyValue( "JavaDriverClassPath", Any( OUString() ) ),
+ AsciiPropertyValue( "IgnoreCurrency", Any( false ) ),
+ // known settings for file-based drivers
+ AsciiPropertyValue( "Extension", Any( OUString() ) ),
+ AsciiPropertyValue( "CharSet", Any( OUString() ) ),
+ AsciiPropertyValue( "HeaderLine", Any( true ) ),
+ AsciiPropertyValue( "FieldDelimiter", Any( OUString( "," ) ) ),
+ AsciiPropertyValue( "StringDelimiter", Any( OUString( "\"" ) ) ),
+ AsciiPropertyValue( "DecimalDelimiter", Any( OUString( "." ) ) ),
+ AsciiPropertyValue( "ThousandDelimiter", Any( OUString() ) ),
+ AsciiPropertyValue( "ShowDeleted", Any( false ) ),
+ // known ODBC settings
+ AsciiPropertyValue( "SystemDriverSettings", Any( OUString() ) ),
+ AsciiPropertyValue( "UseCatalog", Any( false ) ),
+ AsciiPropertyValue( "TypeInfoSettings", Any( Sequence< Any >()) ),
+ // settings related to auto increment handling
+ AsciiPropertyValue( "AutoIncrementCreation", Any( OUString() ) ),
+ AsciiPropertyValue( "AutoRetrievingStatement", Any( OUString() ) ),
+ AsciiPropertyValue( "IsAutoRetrievingEnabled", Any( false ) ),
+ // known LDAP driver settings
+ AsciiPropertyValue( "HostName", Any( OUString() ) ),
+ AsciiPropertyValue( "PortNumber", Any( sal_Int32(389) ) ),
+ AsciiPropertyValue( "BaseDN", Any( OUString() ) ),
+ AsciiPropertyValue( "MaxRowCount", Any( sal_Int32(100) ) ),
+ // known MySQLNative driver settings
+ AsciiPropertyValue( "LocalSocket", Any( OUString() ) ),
+ AsciiPropertyValue( "NamedPipe", Any( OUString() ) ),
+ // misc known driver settings
+ AsciiPropertyValue( "ParameterNameSubstitution", Any( false ) ),
+ AsciiPropertyValue( "AddIndexAppendix", Any( true ) ),
+ AsciiPropertyValue( "IgnoreDriverPrivileges", Any( true ) ),
+ AsciiPropertyValue( "ImplicitCatalogRestriction", ::cppu::UnoType< OUString >::get() ),
+ AsciiPropertyValue( "ImplicitSchemaRestriction", ::cppu::UnoType< OUString >::get() ),
+ AsciiPropertyValue( "PrimaryKeySupport", ::cppu::UnoType< sal_Bool >::get() ),
+ AsciiPropertyValue( "ShowColumnDescription", Any( false ) ),
+ // known SDB level settings
+ AsciiPropertyValue( "NoNameLengthLimit", Any( false ) ),
+ AsciiPropertyValue( "AppendTableAliasName", Any( false ) ),
+ AsciiPropertyValue( "GenerateASBeforeCorrelationName", Any( false ) ),
+ AsciiPropertyValue( "ColumnAliasInOrderBy", Any( true ) ),
+ AsciiPropertyValue( "EnableSQL92Check", Any( false ) ),
+ AsciiPropertyValue( "BooleanComparisonMode", Any( BooleanComparisonMode::EQUAL_INTEGER ) ),
+ AsciiPropertyValue( "TableTypeFilterMode", Any( sal_Int32(3) ) ),
+ AsciiPropertyValue( "RespectDriverResultSetType", Any( false ) ),
+ AsciiPropertyValue( "UseSchemaInSelect", Any( true ) ),
+ AsciiPropertyValue( "UseCatalogInSelect", Any( true ) ),
+ AsciiPropertyValue( "EnableOuterJoinEscape", Any( true ) ),
+ AsciiPropertyValue( "PreferDosLikeLineEnds", Any( false ) ),
+ AsciiPropertyValue( "FormsCheckRequiredFields", Any( true ) ),
+ AsciiPropertyValue( "EscapeDateTime", Any( true ) ),
+
+ // known services to handle database tasks
+ AsciiPropertyValue( "TableAlterationServiceName", Any( OUString() ) ),
+ AsciiPropertyValue( "TableRenameServiceName", Any( OUString() ) ),
+ AsciiPropertyValue( "ViewAlterationServiceName", Any( OUString() ) ),
+ AsciiPropertyValue( "ViewAccessServiceName", Any( OUString() ) ),
+ AsciiPropertyValue( "CommandDefinitions", Any( OUString() ) ),
+ AsciiPropertyValue( "Forms", Any( OUString() ) ),
+ AsciiPropertyValue( "Reports", Any( OUString() ) ),
+ AsciiPropertyValue( "KeyAlterationServiceName", Any( OUString() ) ),
+ AsciiPropertyValue( "IndexAlterationServiceName", Any( OUString() ) ),
+
+ AsciiPropertyValue()
+ };
+ return aKnownSettings;
+}
+
+TContentPtr& ODatabaseModelImpl::getObjectContainer( ObjectType _eType )
+{
+ OSL_PRECOND( _eType >= E_FORM && _eType <= E_TABLE, "ODatabaseModelImpl::getObjectContainer: illegal index!" );
+ TContentPtr& rContentPtr = m_aContainer[ _eType ];
+
+ if ( !rContentPtr )
+ {
+ rContentPtr = std::make_shared<ODefinitionContainer_Impl>();
+ rContentPtr->m_pDataSource = this;
+ rContentPtr->m_aProps.aTitle = lcl_getContainerStorageName_throw( _eType );
+ }
+ return rContentPtr;
+}
+
+bool ODatabaseModelImpl::adjustMacroMode_AutoReject()
+{
+ return m_aMacroMode.adjustMacroMode( nullptr );
+}
+
+bool ODatabaseModelImpl::checkMacrosOnLoading()
+{
+ Reference< XInteractionHandler > xInteraction;
+ xInteraction = m_aMediaDescriptor.getOrDefault( "InteractionHandler", xInteraction );
+ return m_aMacroMode.checkMacrosOnLoading( xInteraction );
+}
+
+void ODatabaseModelImpl::resetMacroExecutionMode()
+{
+ m_aMacroMode = ::sfx2::DocumentMacroMode( *this );
+}
+
+Reference< XStorageBasedLibraryContainer > ODatabaseModelImpl::getLibraryContainer( bool _bScript )
+{
+ Reference< XStorageBasedLibraryContainer >& rxContainer( _bScript ? m_xBasicLibraries : m_xDialogLibraries );
+ if ( rxContainer.is() )
+ return rxContainer;
+
+ Reference< XStorageBasedDocument > xDocument( getModel_noCreate(), UNO_QUERY_THROW );
+ // this is only to be called if there already exists a document model - in fact, it is
+ // to be called by the document model only
+
+ try
+ {
+ Reference< XStorageBasedLibraryContainer > (*Factory)( const Reference< XComponentContext >&, const Reference< XStorageBasedDocument >&)
+ = _bScript ? &DocumentScriptLibraryContainer::create : &DocumentDialogLibraryContainer::create;
+
+ rxContainer.set(
+ (*Factory)( m_aContext, xDocument ),
+ UNO_SET_THROW
+ );
+ }
+ catch( const RuntimeException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ throw WrappedTargetRuntimeException(
+ OUString(),
+ xDocument,
+ ::cppu::getCaughtException()
+ );
+ }
+ return rxContainer;
+}
+
+void ODatabaseModelImpl::storeLibraryContainersTo( const Reference< XStorage >& _rxToRootStorage )
+{
+ if ( m_xBasicLibraries.is() )
+ m_xBasicLibraries->storeLibrariesToStorage( _rxToRootStorage );
+
+ if ( m_xDialogLibraries.is() )
+ m_xDialogLibraries->storeLibrariesToStorage( _rxToRootStorage );
+}
+
+Reference< XStorage > ODatabaseModelImpl::switchToStorage( const Reference< XStorage >& _rxNewRootStorage )
+{
+ if ( !_rxNewRootStorage.is() )
+ throw IllegalArgumentException();
+
+ return impl_switchToStorage_throw( _rxNewRootStorage );
+}
+
+namespace
+{
+ void lcl_modifyListening( ::sfx2::IModifiableDocument& _rDocument,
+ const Reference< XStorage >& _rxStorage, ::rtl::Reference< ::sfx2::DocumentStorageModifyListener >& _inout_rListener,
+ comphelper::SolarMutex& _rMutex, bool _bListen )
+ {
+ Reference< XModifiable > xModify( _rxStorage, UNO_QUERY );
+ OSL_ENSURE( xModify.is() || !_rxStorage.is(), "lcl_modifyListening: storage can't notify us!" );
+
+ if ( xModify.is() && !_bListen && _inout_rListener.is() )
+ {
+ xModify->removeModifyListener( _inout_rListener );
+ }
+
+ if ( _inout_rListener.is() )
+ {
+ _inout_rListener->dispose();
+ _inout_rListener = nullptr;
+ }
+
+ if ( xModify.is() && _bListen )
+ {
+ _inout_rListener = new ::sfx2::DocumentStorageModifyListener( _rDocument, _rMutex );
+ xModify->addModifyListener( _inout_rListener );
+ }
+ }
+}
+
+namespace
+{
+ void lcl_rebaseScriptStorage_throw( const Reference< XStorageBasedLibraryContainer >& _rxContainer,
+ const Reference< XStorage >& _rxNewRootStorage )
+ {
+ if ( _rxContainer.is() )
+ {
+ if ( _rxNewRootStorage.is() )
+ _rxContainer->setRootStorage( _rxNewRootStorage );
+// else
+ // TODO: what to do here? dispose the container?
+ }
+ }
+}
+
+Reference< XStorage > const & ODatabaseModelImpl::impl_switchToStorage_throw( const Reference< XStorage >& _rxNewRootStorage )
+{
+ // stop listening for modifications at the old storage
+ lcl_modifyListening( *this, m_xDocumentStorage.getTyped(), m_pStorageModifyListener, Application::GetSolarMutex(), false );
+
+ // set new storage
+ m_xDocumentStorage.reset( _rxNewRootStorage, SharedStorage::TakeOwnership );
+
+ // start listening for modifications
+ lcl_modifyListening( *this, m_xDocumentStorage.getTyped(), m_pStorageModifyListener, Application::GetSolarMutex(), true );
+
+ // forward new storage to Basic and Dialog library containers
+ lcl_rebaseScriptStorage_throw( m_xBasicLibraries, m_xDocumentStorage.getTyped() );
+ lcl_rebaseScriptStorage_throw( m_xDialogLibraries, m_xDocumentStorage.getTyped() );
+
+ m_bReadOnly = !tools::stor::storageIsWritable_nothrow( m_xDocumentStorage.getTyped() );
+ // TODO: our data source, if it exists, must broadcast the change of its ReadOnly property
+
+ return m_xDocumentStorage.getTyped();
+}
+
+void ODatabaseModelImpl::impl_switchToLogicalURL( const OUString& i_rDocumentURL )
+{
+ if ( i_rDocumentURL == m_sDocumentURL )
+ return;
+
+ const OUString sOldURL( m_sDocumentURL );
+ // update our name, if necessary
+ if ( ( m_sName == m_sDocumentURL ) // our name is our old URL
+ || ( m_sName.isEmpty() ) // we do not have a name, yet (i.e. are not registered at the database context)
+ )
+ {
+ INetURLObject aURL( i_rDocumentURL );
+ if ( aURL.GetProtocol() != INetProtocol::NotValid )
+ {
+ m_sName = i_rDocumentURL;
+ // TODO: our data source must broadcast the change of the Name property
+ }
+ }
+
+ // remember URL
+ m_sDocumentURL = i_rDocumentURL;
+
+ // update our location, if necessary
+ if ( m_sDocFileLocation.isEmpty() )
+ m_sDocFileLocation = m_sDocumentURL;
+
+ // register at the database context, or change registration
+ if (!sOldURL.isEmpty())
+ m_rDBContext.databaseDocumentURLChange( sOldURL, m_sDocumentURL );
+ else
+ m_rDBContext.registerDatabaseDocument( *this );
+}
+
+OUString ODatabaseModelImpl::getObjectContainerStorageName( const ObjectType _eType )
+{
+ return lcl_getContainerStorageName_throw( _eType );
+}
+
+sal_Int16 ODatabaseModelImpl::getCurrentMacroExecMode() const
+{
+ sal_Int16 nCurrentMode = MacroExecMode::NEVER_EXECUTE;
+ try
+ {
+ nCurrentMode = m_aMediaDescriptor.getOrDefault( "MacroExecutionMode", nCurrentMode );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return nCurrentMode;
+}
+
+void ODatabaseModelImpl::setCurrentMacroExecMode( sal_uInt16 nMacroMode )
+{
+ m_aMediaDescriptor.put( "MacroExecutionMode", nMacroMode );
+}
+
+OUString ODatabaseModelImpl::getDocumentLocation() const
+{
+ return getURL();
+ // formerly, we returned getDocFileLocation here, which is the location of the file from which we
+ // recovered the "real" document.
+ // However, during CWS autorecovery evolving, we clarified (with MAV/MT) the role of XModel::getURL and
+ // XStorable::getLocation. In this course, we agreed that for a macro security check, the *document URL*
+ // (not the recovery file URL) is to be used: The recovery file lies in the backup folder, and by definition,
+ // this folder is considered to be secure. So, the document URL needs to be used to decide about the security.
+}
+
+ODatabaseModelImpl::EmbeddedMacros ODatabaseModelImpl::determineEmbeddedMacros()
+{
+ if ( !m_aEmbeddedMacros )
+ {
+ if ( ::sfx2::DocumentMacroMode::storageHasMacros( getOrCreateRootStorage() ) )
+ {
+ m_aEmbeddedMacros = eDocumentWideMacros;
+ }
+ else if ( lcl_hasObjectsWithMacros_nothrow( *this, E_FORM )
+ || lcl_hasObjectsWithMacros_nothrow( *this, E_REPORT )
+ )
+ {
+ m_aEmbeddedMacros = eSubDocumentMacros;
+ }
+ else
+ {
+ m_aEmbeddedMacros = eNoMacros;
+ }
+ }
+ return *m_aEmbeddedMacros;
+}
+
+bool ODatabaseModelImpl::documentStorageHasMacros() const
+{
+ const_cast< ODatabaseModelImpl* >( this )->determineEmbeddedMacros();
+ return ( *m_aEmbeddedMacros != eNoMacros );
+}
+
+bool ODatabaseModelImpl::macroCallsSeenWhileLoading() const
+{
+ return m_bMacroCallsSeenWhileLoading;
+}
+
+Reference< XEmbeddedScripts > ODatabaseModelImpl::getEmbeddedDocumentScripts() const
+{
+ return Reference< XEmbeddedScripts >( getModel_noCreate(), UNO_QUERY );
+}
+
+SignatureState ODatabaseModelImpl::getScriptingSignatureState()
+{
+ return m_nScriptingSignatureState;
+}
+
+bool ODatabaseModelImpl::hasTrustedScriptingSignature(bool bAllowUIToAddAuthor)
+{
+ bool bResult = false;
+
+ try
+ {
+ // Don't use m_xDocumentStorage, that somehow has an incomplete storage representation
+ // which leads to signatures not being found
+ Reference<XStorage> xStorage = comphelper::OStorageHelper::GetStorageOfFormatFromURL(
+ ZIP_STORAGE_FORMAT_STRING, m_sDocFileLocation, ElementModes::READ);
+
+ OUString aODFVersion(comphelper::OStorageHelper::GetODFVersionFromStorage(getOrCreateRootStorage()));
+ uno::Reference<security::XDocumentDigitalSignatures> xSigner(
+ security::DocumentDigitalSignatures::createWithVersion(
+ comphelper::getProcessComponentContext(), aODFVersion));
+ const uno::Sequence<security::DocumentSignatureInformation> aInfo
+ = xSigner->verifyScriptingContentSignatures(xStorage,
+ uno::Reference<io::XInputStream>());
+
+ if (!aInfo.hasElements())
+ return false;
+
+ m_nScriptingSignatureState = DocumentSignatures::getSignatureState(aInfo);
+ if (m_nScriptingSignatureState == SignatureState::OK
+ || m_nScriptingSignatureState == SignatureState::NOTVALIDATED)
+ {
+ bResult = std::any_of(aInfo.begin(), aInfo.end(),
+ [&xSigner](const security::DocumentSignatureInformation& rInfo) {
+ return xSigner->isAuthorTrusted(rInfo.Signer);
+ });
+ }
+
+ if (!bResult && bAllowUIToAddAuthor)
+ {
+ Reference<XInteractionHandler> xInteraction;
+ xInteraction = m_aMediaDescriptor.getOrDefault("InteractionHandler", xInteraction);
+ if (xInteraction.is())
+ {
+ task::DocumentMacroConfirmationRequest aRequest;
+ aRequest.DocumentURL = m_sDocFileLocation;
+ aRequest.DocumentStorage = xStorage;
+ aRequest.DocumentSignatureInformation = aInfo;
+ aRequest.DocumentVersion = aODFVersion;
+ aRequest.Classification = task::InteractionClassification_QUERY;
+ bResult = SfxMedium::CallApproveHandler(xInteraction, uno::Any(aRequest), true);
+ }
+ }
+ }
+ catch (uno::Exception&)
+ {
+ }
+
+ return bResult;
+}
+
+void ODatabaseModelImpl::storageIsModified()
+{
+ setModified( true );
+}
+
+ModelDependentComponent::ModelDependentComponent( const ::rtl::Reference< ODatabaseModelImpl >& _model )
+ :m_pImpl( _model )
+{
+}
+
+ModelDependentComponent::~ModelDependentComponent()
+{
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/SharedConnection.cxx b/dbaccess/source/core/dataaccess/SharedConnection.cxx
new file mode 100644
index 000000000..31a8e68ba
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/SharedConnection.cxx
@@ -0,0 +1,154 @@
+/* -*- 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 "SharedConnection.hxx"
+#include <comphelper/uno3.hxx>
+
+namespace dbaccess
+{
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::container;
+using namespace connectivity;
+
+OSharedConnection::OSharedConnection(Reference<XAggregation>& _rxProxyConnection)
+ : OSharedConnection_BASE(m_aMutex)
+{
+ setDelegation(_rxProxyConnection, m_refCount);
+}
+
+OSharedConnection::~OSharedConnection() {}
+
+void SAL_CALL OSharedConnection::disposing()
+{
+ OSharedConnection_BASE::disposing();
+ OConnectionWrapper::disposing();
+}
+
+Reference<XStatement> SAL_CALL OSharedConnection::createStatement()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->createStatement();
+}
+
+Reference<XPreparedStatement> SAL_CALL OSharedConnection::prepareStatement(const OUString& sql)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->prepareStatement(sql);
+}
+
+Reference<XPreparedStatement> SAL_CALL OSharedConnection::prepareCall(const OUString& sql)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->prepareCall(sql);
+}
+
+OUString SAL_CALL OSharedConnection::nativeSQL(const OUString& sql)
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->nativeSQL(sql);
+}
+
+sal_Bool SAL_CALL OSharedConnection::getAutoCommit()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->getAutoCommit();
+}
+
+void SAL_CALL OSharedConnection::commit()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ m_xConnection->commit();
+}
+
+void SAL_CALL OSharedConnection::rollback()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ m_xConnection->rollback();
+}
+
+sal_Bool SAL_CALL OSharedConnection::isClosed()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if (!m_xConnection.is())
+ return true;
+
+ return m_xConnection->isClosed();
+}
+
+Reference<XDatabaseMetaData> SAL_CALL OSharedConnection::getMetaData()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->getMetaData();
+}
+
+sal_Bool SAL_CALL OSharedConnection::isReadOnly()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->isReadOnly();
+}
+
+OUString SAL_CALL OSharedConnection::getCatalog()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->getCatalog();
+}
+
+sal_Int32 SAL_CALL OSharedConnection::getTransactionIsolation()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->getTransactionIsolation();
+}
+
+Reference<css::container::XNameAccess> SAL_CALL OSharedConnection::getTypeMap()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ checkDisposed(rBHelper.bDisposed);
+
+ return m_xConnection->getTypeMap();
+}
+
+IMPLEMENT_GET_IMPLEMENTATION_ID(OSharedConnection)
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/SharedConnection.hxx b/dbaccess/source/core/dataaccess/SharedConnection.hxx
new file mode 100644
index 000000000..ea6e961cf
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/SharedConnection.hxx
@@ -0,0 +1,118 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <connectivity/ConnectionWrapper.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <com/sun/star/sdbc/SQLException.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <comphelper/sequence.hxx>
+
+namespace dbaccess
+{
+ // OSharedConnection: This class implements a simple forwarding of connection calls.
+ // All methods will be forwarded with exception of the set methods, which are not allowed
+ // to be called on shared connections. Instances of this class will be created when the
+ // datasource is asked for not isolated connection.
+ typedef ::cppu::WeakComponentImplHelper< css::sdbc::XConnection
+ > OSharedConnection_BASE;
+ typedef ::connectivity::OConnectionWrapper OSharedConnection_BASE2;
+
+ class OSharedConnection : public ::cppu::BaseMutex
+ , public OSharedConnection_BASE
+ , public OSharedConnection_BASE2
+ {
+ protected:
+ virtual void SAL_CALL disposing() override;
+ virtual ~OSharedConnection() override;
+ public:
+ explicit OSharedConnection(css::uno::Reference< css::uno::XAggregation >& _rxProxyConnection);
+
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override;
+
+ virtual void SAL_CALL acquire() noexcept override { OSharedConnection_BASE::acquire(); }
+ virtual void SAL_CALL release() noexcept override { OSharedConnection_BASE::release(); }
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override
+ {
+ return ::comphelper::concatSequences(
+ OSharedConnection_BASE::getTypes(),
+ OSharedConnection_BASE2::getTypes()
+ );
+ }
+
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& _rType ) override
+ {
+ css::uno::Any aReturn = OSharedConnection_BASE::queryInterface(_rType);
+ if ( !aReturn.hasValue() )
+ aReturn = OSharedConnection_BASE2::queryInterface(_rType);
+ return aReturn;
+ }
+
+ // XCloseable
+ virtual void SAL_CALL close( ) override
+ {
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ ::connectivity::checkDisposed(rBHelper.bDisposed);
+ }
+ dispose();
+ }
+
+ // XConnection
+ virtual void SAL_CALL setAutoCommit( sal_Bool /*autoCommit*/ ) override
+ {
+ throw css::sdbc::SQLException("This call is not allowed when sharing connections.",*this,"S10000",0,css::uno::Any());
+ }
+ virtual void SAL_CALL setReadOnly( sal_Bool /*readOnly*/ ) override
+ {
+ throw css::sdbc::SQLException("This call is not allowed when sharing connections.",*this,"S10000",0,css::uno::Any());
+ }
+ virtual void SAL_CALL setCatalog( const OUString& /*catalog*/ ) override
+ {
+ throw css::sdbc::SQLException("This call is not allowed when sharing connections.",*this,"S10000",0,css::uno::Any());
+ }
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 /*level*/ ) override
+ {
+ throw css::sdbc::SQLException("This call is not allowed when sharing connections.",*this,"S10000",0,css::uno::Any());
+ }
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& /*typeMap*/ ) override
+ {
+ throw css::sdbc::SQLException("This call is not allowed when sharing connections.",*this,"S10000",0,css::uno::Any());
+ }
+ // XConnection
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/bookmarkcontainer.cxx b/dbaccess/source/core/dataaccess/bookmarkcontainer.cxx
new file mode 100644
index 000000000..a03caea57
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/bookmarkcontainer.cxx
@@ -0,0 +1,301 @@
+/* -*- 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 <bookmarkcontainer.hxx>
+
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <comphelper/enumhelper.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+namespace dbaccess
+{
+
+// OBookmarkContainer
+
+OBookmarkContainer::OBookmarkContainer(OWeakObject& _rParent, Mutex& _rMutex)
+ :m_rParent(_rParent)
+ ,m_aContainerListeners(_rMutex)
+ ,m_rMutex(_rMutex)
+{
+}
+
+
+void SAL_CALL OBookmarkContainer::acquire( ) noexcept
+{
+ m_rParent.acquire();
+}
+
+void SAL_CALL OBookmarkContainer::release( ) noexcept
+{
+ m_rParent.release();
+}
+
+OBookmarkContainer::~OBookmarkContainer()
+{
+}
+
+// XServiceInfo
+OUString SAL_CALL OBookmarkContainer::getImplementationName( )
+{
+ return "com.sun.star.comp.dba.OBookmarkContainer";
+}
+
+sal_Bool SAL_CALL OBookmarkContainer::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > SAL_CALL OBookmarkContainer::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdb.DefinitionContainer" };
+}
+
+// XNameContainer
+void SAL_CALL OBookmarkContainer::insertByName( const OUString& _rName, const Any& aElement )
+{
+ MutexGuard aGuard(m_rMutex);
+
+ if (checkExistence(_rName))
+ throw ElementExistException();
+
+ if (_rName.isEmpty())
+ throw IllegalArgumentException();
+
+ // approve the new object
+ OUString sNewLink;
+ if (!(aElement >>= sNewLink))
+ throw IllegalArgumentException();
+
+ implAppend(_rName, sNewLink);
+
+ // notify the listeners
+ if (m_aContainerListeners.getLength())
+ {
+ ContainerEvent aEvent(*this, Any(_rName), Any(sNewLink), Any());
+ m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
+ }
+}
+
+void SAL_CALL OBookmarkContainer::removeByName( const OUString& _rName )
+{
+ OUString sOldBookmark;
+ {
+ MutexGuard aGuard(m_rMutex);
+
+ // check the arguments
+ if (_rName.isEmpty())
+ throw IllegalArgumentException();
+
+ if (!checkExistence(_rName))
+ throw NoSuchElementException();
+
+ // the old element (for the notifications)
+ sOldBookmark = m_aBookmarks[_rName];
+
+ // do the removal
+ implRemove(_rName);
+ }
+
+ // notify the listeners
+ if (m_aContainerListeners.getLength())
+ {
+ ContainerEvent aEvent(*this, Any(_rName), Any(sOldBookmark), Any());
+ m_aContainerListeners.notifyEach( &XContainerListener::elementRemoved, aEvent );
+ }
+}
+
+// XNameReplace
+void SAL_CALL OBookmarkContainer::replaceByName( const OUString& _rName, const Any& aElement )
+{
+ ClearableMutexGuard aGuard(m_rMutex);
+
+ // check the arguments
+ if (_rName.isEmpty())
+ throw IllegalArgumentException();
+
+ // do we have such an element?
+ if (!checkExistence(_rName))
+ throw NoSuchElementException();
+
+ // approve the new object
+ OUString sNewLink;
+ if (!(aElement >>= sNewLink))
+ throw IllegalArgumentException();
+
+ // the old element (for the notifications)
+ OUString sOldLink = m_aBookmarks[_rName];
+
+ // do the replace
+ implReplace(_rName, sNewLink);
+
+ // notify the listeners
+ aGuard.clear();
+ if (m_aContainerListeners.getLength())
+ {
+ ContainerEvent aEvent(*this, Any(_rName), Any(sNewLink), Any(sOldLink));
+ m_aContainerListeners.notifyEach( &XContainerListener::elementReplaced, aEvent );
+ }
+}
+
+void SAL_CALL OBookmarkContainer::addContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ MutexGuard aGuard(m_rMutex);
+ if (_rxListener.is())
+ m_aContainerListeners.addInterface(_rxListener);
+}
+
+void SAL_CALL OBookmarkContainer::removeContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ MutexGuard aGuard(m_rMutex);
+ if (_rxListener.is())
+ m_aContainerListeners.removeInterface(_rxListener);
+}
+
+// XElementAccess
+Type SAL_CALL OBookmarkContainer::getElementType( )
+{
+ return ::cppu::UnoType<OUString>::get();
+}
+
+sal_Bool SAL_CALL OBookmarkContainer::hasElements( )
+{
+ MutexGuard aGuard(m_rMutex);
+ return !m_aBookmarks.empty();
+}
+
+// XEnumerationAccess
+Reference< XEnumeration > SAL_CALL OBookmarkContainer::createEnumeration( )
+{
+ MutexGuard aGuard(m_rMutex);
+ return new ::comphelper::OEnumerationByIndex(static_cast<XIndexAccess*>(this));
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL OBookmarkContainer::getCount( )
+{
+ MutexGuard aGuard(m_rMutex);
+ return m_aBookmarks.size();
+}
+
+Any SAL_CALL OBookmarkContainer::getByIndex( sal_Int32 _nIndex )
+{
+ MutexGuard aGuard(m_rMutex);
+
+ if ((_nIndex < 0) || (o3tl::make_unsigned(_nIndex) >= m_aBookmarksIndexed.size()))
+ throw IndexOutOfBoundsException();
+
+ return Any(m_aBookmarksIndexed[_nIndex]->second);
+}
+
+Any SAL_CALL OBookmarkContainer::getByName( const OUString& _rName )
+{
+ MutexGuard aGuard(m_rMutex);
+
+ if (!checkExistence(_rName))
+ throw NoSuchElementException();
+
+ return Any(m_aBookmarks[_rName]);
+}
+
+Sequence< OUString > SAL_CALL OBookmarkContainer::getElementNames( )
+{
+ MutexGuard aGuard(m_rMutex);
+
+ Sequence< OUString > aNames(m_aBookmarks.size());
+ OUString* pNames = aNames.getArray();
+
+ for (auto const& bookmarkIndexed : m_aBookmarksIndexed)
+ {
+ *pNames = bookmarkIndexed->first;
+ ++pNames;
+ }
+
+ return aNames;
+}
+
+sal_Bool SAL_CALL OBookmarkContainer::hasByName( const OUString& _rName )
+{
+ MutexGuard aGuard(m_rMutex);
+
+ return checkExistence(_rName);
+}
+
+void OBookmarkContainer::implRemove(const OUString& _rName)
+{
+ MutexGuard aGuard(m_rMutex);
+
+ // look for the name in the index access vector
+ MapString2String::const_iterator aMapPos = m_aBookmarks.end();
+ auto aSearch = std::find_if(m_aBookmarksIndexed.begin(), m_aBookmarksIndexed.end(),
+ [&_rName](const MapString2String::iterator& rIter) { return rIter->first == _rName; });
+ if (aSearch != m_aBookmarksIndexed.end())
+ {
+ aMapPos = *aSearch;
+ m_aBookmarksIndexed.erase(aSearch);
+ }
+
+ if (m_aBookmarks.end() == aMapPos)
+ {
+ OSL_FAIL("OBookmarkContainer::implRemove: inconsistence!");
+ return;
+ }
+
+ // remove the map entries
+ m_aBookmarks.erase(aMapPos);
+}
+
+void OBookmarkContainer::implAppend(const OUString& _rName, const OUString& _rDocumentLocation)
+{
+ MutexGuard aGuard(m_rMutex);
+
+ OSL_ENSURE(m_aBookmarks.find(_rName) == m_aBookmarks.end(),"Bookmark already known!");
+ m_aBookmarksIndexed.push_back(m_aBookmarks.emplace( _rName,_rDocumentLocation).first);
+}
+
+void OBookmarkContainer::implReplace(const OUString& _rName, const OUString& _rNewLink)
+{
+ MutexGuard aGuard(m_rMutex);
+ OSL_ENSURE(checkExistence(_rName), "OBookmarkContainer::implReplace : invalid name !");
+
+ m_aBookmarks[_rName] = _rNewLink;
+}
+
+Reference< XInterface > SAL_CALL OBookmarkContainer::getParent( )
+{
+ return m_rParent;
+}
+
+void SAL_CALL OBookmarkContainer::setParent( const Reference< XInterface >& /*Parent*/ )
+{
+ throw NoSupportException();
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/commandcontainer.cxx b/dbaccess/source/core/dataaccess/commandcontainer.cxx
new file mode 100644
index 000000000..8afb81520
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/commandcontainer.cxx
@@ -0,0 +1,100 @@
+/* -*- 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 "commandcontainer.hxx"
+#include "commanddefinition.hxx"
+
+#include <com/sun/star/sdb/TableDefinition.hpp>
+#include <com/sun/star/sdb/CommandDefinition.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::ucb;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+namespace dbaccess
+{
+
+// OCommandContainer
+
+OCommandContainer::OCommandContainer( const Reference< css::uno::XComponentContext >& _xORB
+ ,const Reference< XInterface >& _xParentContainer
+ ,const TContentPtr& _pImpl
+ ,bool _bTables
+ )
+ :ODefinitionContainer(_xORB,_xParentContainer,_pImpl,!_bTables)
+ ,m_bTables(_bTables)
+{
+}
+
+OCommandContainer::~OCommandContainer()
+{
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( OCommandContainer,ODefinitionContainer,OCommandContainer_BASE)
+css::uno::Sequence< css::uno::Type > OCommandContainer::getTypes()
+{
+ return ::comphelper::concatSequences(
+ ODefinitionContainer::getTypes( ),
+ OCommandContainer_BASE::getTypes( )
+ );
+}
+
+css::uno::Sequence<sal_Int8> OCommandContainer::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+Reference< XContent > OCommandContainer::createObject( const OUString& _rName)
+{
+ const ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
+ OSL_ENSURE( rDefinitions.find(_rName) != rDefinitions.end(), "OCommandContainer::createObject: Invalid entry in map!" );
+
+ const TContentPtr& pElementContent( rDefinitions.find( _rName )->second );
+ if ( m_bTables )
+ return new OComponentDefinition( *this, _rName, m_aContext, pElementContent, m_bTables );
+ else
+ return static_cast< css::sdb::XQueryDefinition * > ( new OCommandDefinition( *this, _rName, m_aContext, pElementContent ) );
+}
+
+Reference< XInterface > SAL_CALL OCommandContainer::createInstanceWithArguments(const Sequence< Any >& /*aArguments*/ )
+{
+ return createInstance( );
+}
+
+Reference< XInterface > SAL_CALL OCommandContainer::createInstance( )
+{
+ if(m_bTables)
+ return css::sdb::TableDefinition::createDefault( m_aContext );
+ else
+ return css::sdb::CommandDefinition::create( m_aContext );
+}
+
+OUString OCommandContainer::determineContentType() const
+{
+ return "application/vnd.org.openoffice.DatabaseCommandDefinitionContainer";
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/commandcontainer.hxx b/dbaccess/source/core/dataaccess/commandcontainer.hxx
new file mode 100644
index 000000000..3ea36f648
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/commandcontainer.hxx
@@ -0,0 +1,72 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <definitioncontainer.hxx>
+
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+
+#include <cppuhelper/implbase1.hxx>
+
+namespace dbaccess
+{
+// OCommandContainer
+
+typedef ::cppu::ImplHelper1 < css::lang::XSingleServiceFactory
+ > OCommandContainer_BASE;
+
+class OCommandContainer : public ODefinitionContainer
+ ,public OCommandContainer_BASE
+{
+ bool m_bTables;
+
+public:
+ /** constructs the container.<BR>
+ */
+ OCommandContainer(
+ const css::uno::Reference< css::uno::XComponentContext >& _xORB
+ ,const css::uno::Reference< css::uno::XInterface >& _xParentContainer
+ ,const TContentPtr& _pImpl
+ ,bool _bTables
+ );
+
+ DECLARE_XINTERFACE( )
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+ // XSingleServiceFactory
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceWithArguments( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+protected:
+ virtual ~OCommandContainer() override;
+
+ // ODefinitionContainer
+ virtual css::uno::Reference< css::ucb::XContent > createObject(const OUString& _rName) override;
+
+protected:
+ // OContentHelper overridables
+ virtual OUString determineContentType() const override;
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/commanddefinition.cxx b/dbaccess/source/core/dataaccess/commanddefinition.cxx
new file mode 100644
index 000000000..f04c47228
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/commanddefinition.cxx
@@ -0,0 +1,153 @@
+/* -*- 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 "commanddefinition.hxx"
+#include <stringconstants.hxx>
+#include <strings.hxx>
+
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+
+namespace dbaccess
+{
+
+void OCommandDefinition::registerProperties()
+{
+ OCommandDefinition_Impl& rCommandDefinition = dynamic_cast< OCommandDefinition_Impl& >( *m_pImpl );
+ registerProperty(PROPERTY_COMMAND, PROPERTY_ID_COMMAND, PropertyAttribute::BOUND,
+ &rCommandDefinition.m_sCommand, cppu::UnoType<decltype(rCommandDefinition.m_sCommand)>::get());
+
+ registerProperty(PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::BOUND,
+ &rCommandDefinition.m_bEscapeProcessing, cppu::UnoType<bool>::get());
+
+ registerProperty(PROPERTY_UPDATE_TABLENAME, PROPERTY_ID_UPDATE_TABLENAME, PropertyAttribute::BOUND,
+ &rCommandDefinition.m_sUpdateTableName, cppu::UnoType<decltype(rCommandDefinition.m_sUpdateTableName)>::get());
+
+ registerProperty(PROPERTY_UPDATE_SCHEMANAME, PROPERTY_ID_UPDATE_SCHEMANAME, PropertyAttribute::BOUND,
+ &rCommandDefinition.m_sUpdateSchemaName, cppu::UnoType<decltype(rCommandDefinition.m_sUpdateSchemaName)>::get());
+
+ registerProperty(PROPERTY_UPDATE_CATALOGNAME, PROPERTY_ID_UPDATE_CATALOGNAME, PropertyAttribute::BOUND,
+ &rCommandDefinition.m_sUpdateCatalogName, cppu::UnoType<decltype(rCommandDefinition.m_sUpdateCatalogName)>::get());
+ registerProperty(PROPERTY_LAYOUTINFORMATION, PROPERTY_ID_LAYOUTINFORMATION, PropertyAttribute::BOUND,
+ &rCommandDefinition.m_aLayoutInformation, cppu::UnoType<decltype(rCommandDefinition.m_aLayoutInformation)>::get());
+}
+
+OCommandDefinition::OCommandDefinition(const Reference< XComponentContext >& _xORB
+ ,const Reference< XInterface >& _rxContainer
+ ,const TContentPtr& _pImpl)
+ :OComponentDefinition(_xORB,_rxContainer,_pImpl,false)
+{
+ registerProperties();
+}
+
+OCommandDefinition::~OCommandDefinition()
+{
+}
+
+OCommandDefinition::OCommandDefinition( const Reference< XInterface >& _rxContainer
+ ,const OUString& _rElementName
+ ,const Reference< XComponentContext >& _xORB
+ ,const TContentPtr& _pImpl)
+ :OComponentDefinition(_rxContainer,_rElementName,_xORB,_pImpl,false)
+{
+ registerProperties();
+}
+
+css::uno::Sequence<sal_Int8> OCommandDefinition::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+css::uno::Sequence< css::uno::Type > OCommandDefinition::getTypes()
+{
+ return ::comphelper::concatSequences(
+ OCommandDefinition_Base::getTypes( ),
+ OComponentDefinition::getTypes( )
+ );
+}
+IMPLEMENT_FORWARD_XINTERFACE2( OCommandDefinition,OComponentDefinition,OCommandDefinition_Base)
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL OCommandDefinition::getPropertySetInfo()
+{
+ Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+::cppu::IPropertyArrayHelper& OCommandDefinition::getInfoHelper()
+{
+ return *OCommandDefinition_PROP::getArrayHelper();
+}
+::cppu::IPropertyArrayHelper* OCommandDefinition::createArrayHelper( ) const
+{
+ css::uno::Sequence< css::beans::Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+
+OUString SAL_CALL OCommandDefinition::getImplementationName()
+{
+ return "com.sun.star.comp.dba.OCommandDefinition";
+}
+
+css::uno::Sequence<OUString> SAL_CALL OCommandDefinition::getSupportedServiceNames()
+{
+ return {
+ "com.sun.star.sdb.QueryDefinition",
+ "com.sun.star.sdb.CommandDefinition",
+ "com.sun.star.ucb.Content"
+ };
+}
+
+void SAL_CALL OCommandDefinition::rename( const OUString& newName )
+{
+ try
+ {
+ sal_Int32 nHandle = PROPERTY_ID_NAME;
+ osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex);
+ Any aOld(m_pImpl->m_aProps.aTitle);
+ aGuard.clear();
+ Any aNew(newName);
+ fire(&nHandle, &aNew, &aOld, 1, true );
+
+ m_pImpl->m_aProps.aTitle = newName;
+ fire(&nHandle, &aNew, &aOld, 1, false );
+ }
+ catch(const PropertyVetoException&)
+ {
+ throw ElementExistException(newName,*this);
+ }
+}
+
+} // namespace dbaccess
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dba_OCommandDefinition(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new dbaccess::OCommandDefinition(
+ context, nullptr, std::make_shared<dbaccess::OCommandDefinition_Impl>() ));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/commanddefinition.hxx b/dbaccess/source/core/dataaccess/commanddefinition.hxx
new file mode 100644
index 000000000..ed348a889
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/commanddefinition.hxx
@@ -0,0 +1,125 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <commandbase.hxx>
+#include <apitools.hxx>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sdbcx/XRename.hpp>
+#include <com/sun/star/sdb/XQueryDefinition.hpp>
+#include <datasettings.hxx>
+#include <ContentHelper.hxx>
+#include "ComponentDefinition.hxx"
+
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase2.hxx>
+
+namespace dbaccess
+{
+
+// OCommandDefinition - a database "document" which describes a query
+ class OCommandDefinition_Impl : public OComponentDefinition_Impl
+ ,public OCommandBase
+ {
+ public:
+ };
+
+typedef ::cppu::ImplHelper2 < css::sdbcx::XRename,
+ css::sdb::XQueryDefinition
+ > OCommandDefinition_Base;
+class OCommandDefinition;
+typedef ::comphelper::OPropertyArrayUsageHelper< OCommandDefinition >
+ OCommandDefinition_PROP;
+
+class OCommandDefinition : public OComponentDefinition
+ ,public OCommandDefinition_Base
+ ,public OCommandDefinition_PROP
+{
+protected:
+ virtual ~OCommandDefinition() override;
+
+public:
+ OCommandDefinition(const css::uno::Reference< css::uno::XComponentContext >& ,
+ const css::uno::Reference< css::uno::XInterface >& _xParentContainer,
+ const TContentPtr& _pImpl);
+
+ OCommandDefinition(
+ const css::uno::Reference< css::uno::XInterface >& _rxContainer
+ ,const OUString& _rElementName
+ ,const css::uno::Reference< css::uno::XComponentContext >&
+ ,const TContentPtr& _pImpl
+ );
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+// css::uno::XInterface
+ DECLARE_XINTERFACE( )
+
+// css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+ // overrides to resolve ambiguity
+ virtual void SAL_CALL setPropertyValue(const OUString& p1, const css::uno::Any& p2) override
+ { OComponentDefinition::setPropertyValue(p1, p2); }
+ virtual css::uno::Any SAL_CALL getPropertyValue(const OUString& p1) override
+ { return OComponentDefinition::getPropertyValue(p1); }
+ virtual void SAL_CALL addPropertyChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XPropertyChangeListener>& p2) override
+ { OComponentDefinition::addPropertyChangeListener(p1, p2); }
+ virtual void SAL_CALL removePropertyChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XPropertyChangeListener>& p2) override
+ { OComponentDefinition::removePropertyChangeListener(p1, p2); }
+ virtual void SAL_CALL addVetoableChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XVetoableChangeListener>& p2) override
+ { OComponentDefinition::addVetoableChangeListener(p1, p2); }
+ virtual void SAL_CALL removeVetoableChangeListener(const OUString& p1, const css::uno::Reference<css::beans::XVetoableChangeListener>& p2) override
+ { OComponentDefinition::removeVetoableChangeListener(p1, p2); }
+ virtual css::uno::Reference<css::ucb::XContentIdentifier> SAL_CALL getIdentifier() override
+ { return OComponentDefinition::getIdentifier(); }
+ virtual OUString SAL_CALL getContentType() override
+ { return OComponentDefinition::getContentType(); }
+ virtual void SAL_CALL addContentEventListener(const css::uno::Reference<css::ucb::XContentEventListener>& p1) override
+ { OComponentDefinition::addContentEventListener(p1); }
+ virtual void SAL_CALL removeContentEventListener(const css::uno::Reference<css::ucb::XContentEventListener>& p1) override
+ { OComponentDefinition::removeContentEventListener(p1); }
+ virtual void SAL_CALL dispose() override
+ { OComponentDefinition::dispose(); }
+ virtual void SAL_CALL addEventListener(const css::uno::Reference<css::lang::XEventListener>& p1) override
+ { OComponentDefinition::addEventListener(p1); }
+ virtual void SAL_CALL removeEventListener(const css::uno::Reference<css::lang::XEventListener>& p1) override
+ { OComponentDefinition::removeEventListener(p1); }
+
+ // OPropertySetHelper
+ virtual css::uno::Reference<css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual cppu::IPropertyArrayHelper* createArrayHelper() const override;
+
+
+private:
+ // helper
+ void registerProperties();
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/connection.cxx b/dbaccess/source/core/dataaccess/connection.cxx
new file mode 100644
index 000000000..37cf9e669
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/connection.cxx
@@ -0,0 +1,808 @@
+/* -*- 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 <iterator>
+
+#include "connection.hxx"
+#include "datasource.hxx"
+#include <strings.hrc>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <statement.hxx>
+#include <preparedstatement.hxx>
+#include <callablestatement.hxx>
+#include <SingleSelectQueryComposer.hxx>
+#include <querycomposer.hxx>
+
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdb/tools/ConnectionTools.hpp>
+#include <com/sun/star/reflection/ProxyFactory.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <connectivity/dbtools.hxx>
+#include <connectivity/dbmetadata.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <comphelper/sequence.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdb::application;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::reflection;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::graphic;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+using namespace ::dbtools;
+
+using ::com::sun::star::sdb::tools::XTableName;
+using ::com::sun::star::sdb::tools::XObjectNames;
+using ::com::sun::star::sdb::tools::XDataSourceMetaData;
+
+namespace dbaccess
+{
+
+// XServiceInfo
+OUString OConnection::getImplementationName( )
+{
+ return "com.sun.star.comp.dbaccess.Connection";
+}
+
+sal_Bool OConnection::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > OConnection::getSupportedServiceNames( )
+{
+ Sequence< OUString > aSupported = OConnectionWrapper::getSupportedServiceNames();
+
+ if ( comphelper::findValue( aSupported, SERVICE_SDB_CONNECTION ) == -1 )
+ {
+ sal_Int32 nLen = aSupported.getLength();
+ aSupported.realloc( nLen + 1 );
+ aSupported.getArray()[ nLen ] = SERVICE_SDB_CONNECTION;
+ }
+
+ return aSupported;
+}
+
+// XCloseable
+void OConnection::close()
+{
+ // being closed is the same as being disposed
+ dispose();
+}
+
+sal_Bool OConnection::isClosed()
+{
+ MutexGuard aGuard(m_aMutex);
+ return !m_xMasterConnection.is();
+}
+
+// XConnection
+Reference< XStatement > OConnection::createStatement()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ Reference< XStatement > xStatement;
+ Reference< XStatement > xMasterStatement = m_xMasterConnection->createStatement();
+ if ( xMasterStatement.is() )
+ {
+ xStatement = new OStatement(this, xMasterStatement);
+ m_aStatements.emplace_back(xStatement);
+ }
+ return xStatement;
+}
+
+Reference< XPreparedStatement > OConnection::prepareStatement(const OUString& sql)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ // TODO convert the SQL to SQL the driver understands
+ Reference< XPreparedStatement > xStatement;
+ Reference< XPreparedStatement > xMasterStatement = m_xMasterConnection->prepareStatement(sql);
+ if ( xMasterStatement.is() )
+ {
+ xStatement = new OPreparedStatement(this, xMasterStatement);
+ m_aStatements.emplace_back(xStatement);
+ }
+ return xStatement;
+}
+
+Reference< XPreparedStatement > OConnection::prepareCall(const OUString& sql)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ Reference< XPreparedStatement > xStatement;
+ Reference< XPreparedStatement > xMasterStatement = m_xMasterConnection->prepareCall(sql);
+ if ( xMasterStatement.is() )
+ {
+ xStatement = new OCallableStatement(this, xMasterStatement);
+ m_aStatements.emplace_back(xStatement);
+ }
+ return xStatement;
+}
+
+OUString OConnection::nativeSQL(const OUString& sql)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_xMasterConnection->nativeSQL(sql);
+}
+
+void OConnection::setAutoCommit(sal_Bool autoCommit)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ m_xMasterConnection->setAutoCommit(autoCommit);
+}
+
+sal_Bool OConnection::getAutoCommit()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_xMasterConnection->getAutoCommit();
+}
+
+void OConnection::commit()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ m_xMasterConnection->commit();
+}
+
+void OConnection::rollback()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ m_xMasterConnection->rollback();
+}
+
+Reference< XDatabaseMetaData > OConnection::getMetaData()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_xMasterConnection->getMetaData();
+}
+
+void OConnection::setReadOnly(sal_Bool readOnly)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ m_xMasterConnection->setReadOnly(readOnly);
+}
+
+sal_Bool OConnection::isReadOnly()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_xMasterConnection->isReadOnly();
+}
+
+void OConnection::setCatalog(const OUString& catalog)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ m_xMasterConnection->setCatalog(catalog);
+}
+
+OUString OConnection::getCatalog()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_xMasterConnection->getCatalog();
+}
+
+void OConnection::setTransactionIsolation(sal_Int32 level)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ m_xMasterConnection->setTransactionIsolation(level);
+}
+
+sal_Int32 OConnection::getTransactionIsolation()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_xMasterConnection->getTransactionIsolation();
+}
+
+Reference< XNameAccess > OConnection::getTypeMap()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_xMasterConnection->getTypeMap();
+}
+
+void OConnection::setTypeMap(const Reference< XNameAccess > & typeMap)
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ m_xMasterConnection->setTypeMap(typeMap);
+}
+
+// OConnection
+
+OConnection::OConnection(ODatabaseSource& _rDB
+ , Reference< XConnection > const & _rxMaster
+ , const Reference< XComponentContext >& _rxORB)
+ :OSubComponent(m_aMutex, static_cast< OWeakObject* >(&_rDB))
+ // as the queries reroute their refcounting to us, this m_aMutex is okey. If the queries
+ // container would do its own refcounting, it would have to acquire m_pMutex
+ // same for tables
+ ,m_aTableFilter(_rDB.m_pImpl->m_aTableFilter)
+ ,m_aTableTypeFilter(_rDB.m_pImpl->m_aTableTypeFilter)
+ ,m_aContext( _rxORB )
+ ,m_xMasterConnection(_rxMaster)
+ ,m_aWarnings( Reference< XWarningsSupplier >( _rxMaster, UNO_QUERY ) )
+ ,m_nInAppend(0)
+ ,m_bSupportsViews(false)
+ ,m_bSupportsUsers(false)
+ ,m_bSupportsGroups(false)
+{
+ osl_atomic_increment(&m_refCount);
+
+ try
+ {
+ Reference< XProxyFactory > xProxyFactory = ProxyFactory::create( m_aContext );
+ Reference<XAggregation> xAgg = xProxyFactory->createProxy(_rxMaster);
+ setDelegation(xAgg,m_refCount);
+ OSL_ENSURE(m_xConnection.is(), "OConnection::OConnection : invalid master connection !");
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ m_xTableUIProvider.set(m_xMasterConnection, css::uno::UNO_QUERY);
+
+ try
+ {
+ m_xQueries = OQueryContainer::create(Reference< XNameContainer >(_rDB.getQueryDefinitions(), UNO_QUERY), this, _rxORB, &m_aWarnings).get();
+
+ bool bCase = true;
+ Reference<XDatabaseMetaData> xMeta;
+ try
+ {
+ xMeta = getMetaData();
+ bCase = xMeta.is() && xMeta->supportsMixedCaseQuotedIdentifiers();
+ }
+ catch(const SQLException&)
+ {
+ }
+ Reference< XNameContainer > xTableDefinitions(_rDB.getTables(),UNO_QUERY);
+ m_pTables.reset( new OTableContainer( *this, m_aMutex, this, bCase, xTableDefinitions, this, m_nInAppend ) );
+
+ // check if we support types
+ if ( xMeta.is() )
+ {
+ Reference<XResultSet> xRes = xMeta->getTableTypes();
+ if(xRes.is())
+ {
+ Reference<XRow> xRow(xRes,UNO_QUERY);
+ while(xRes->next())
+ {
+ OUString sValue = xRow->getString(1);
+ if( !xRow->wasNull() && sValue == "VIEW")
+ {
+ m_bSupportsViews = true;
+ break;
+ }
+ }
+ }
+ // some dbs don't support this type so we should ask if a XViewsSupplier is supported
+ if(!m_bSupportsViews)
+ {
+ Reference< XViewsSupplier > xMaster(getMasterTables(),UNO_QUERY);
+
+ if (xMaster.is() && xMaster->getViews().is())
+ m_bSupportsViews = true;
+ }
+ if(m_bSupportsViews)
+ {
+ m_pViews.reset( new OViewContainer(*this, m_aMutex, this, bCase, this, m_nInAppend) );
+ m_pViews->addContainerListener(m_pTables.get());
+ m_pTables->addContainerListener(m_pViews.get());
+ }
+ m_bSupportsUsers = Reference< XUsersSupplier> (getMasterTables(),UNO_QUERY).is();
+ m_bSupportsGroups = Reference< XGroupsSupplier> (getMasterTables(),UNO_QUERY).is();
+
+ impl_checkTableQueryNames_nothrow();
+ }
+ }
+ catch(const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+OConnection::~OConnection()
+{
+}
+
+// XWarningsSupplier
+Any SAL_CALL OConnection::getWarnings()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_aWarnings.getWarnings();
+}
+
+void SAL_CALL OConnection::clearWarnings( )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ m_aWarnings.clearWarnings();
+}
+
+namespace
+{
+ struct CompareTypeByName
+ {
+ bool operator() ( const Type& _rLHS, const Type& _rRHS ) const
+ {
+ return _rLHS.getTypeName() < _rRHS.getTypeName();
+ }
+ };
+ typedef std::set< Type, CompareTypeByName > TypeBag;
+
+ void lcl_copyTypes( TypeBag& _out_rTypes, const Sequence< Type >& _rTypes )
+ {
+ std::copy( _rTypes.begin(), _rTypes.end(),
+ std::insert_iterator< TypeBag >( _out_rTypes, _out_rTypes.begin() ) );
+ }
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > OConnection::getTypes()
+{
+ TypeBag aNormalizedTypes;
+
+ lcl_copyTypes( aNormalizedTypes, OSubComponent::getTypes() );
+ lcl_copyTypes( aNormalizedTypes, OConnection_Base::getTypes() );
+ lcl_copyTypes( aNormalizedTypes, ::connectivity::OConnectionWrapper::getTypes() );
+
+ if ( !m_bSupportsViews )
+ aNormalizedTypes.erase( cppu::UnoType<XViewsSupplier>::get() );
+ if ( !m_bSupportsUsers )
+ aNormalizedTypes.erase( cppu::UnoType<XUsersSupplier>::get() );
+ if ( !m_bSupportsGroups )
+ aNormalizedTypes.erase( cppu::UnoType<XGroupsSupplier>::get() );
+
+ return comphelper::containerToSequence(aNormalizedTypes);
+}
+
+Sequence< sal_Int8 > OConnection::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// css::uno::XInterface
+Any OConnection::queryInterface( const Type & rType )
+{
+ if ( !m_bSupportsViews && rType.equals( cppu::UnoType<XViewsSupplier>::get() ) )
+ return Any();
+ else if ( !m_bSupportsUsers && rType.equals( cppu::UnoType<XUsersSupplier>::get() ) )
+ return Any();
+ else if ( !m_bSupportsGroups && rType.equals( cppu::UnoType<XGroupsSupplier>::get() ) )
+ return Any();
+ Any aReturn = OSubComponent::queryInterface( rType );
+ if (!aReturn.hasValue())
+ {
+ aReturn = OConnection_Base::queryInterface( rType );
+ if (!aReturn.hasValue())
+ aReturn = OConnectionWrapper::queryInterface( rType );
+ }
+ return aReturn;
+}
+
+void OConnection::acquire() noexcept
+{
+ // include this one when you want to see who calls it (call graph)
+ OSubComponent::acquire();
+}
+
+void OConnection::release() noexcept
+{
+ // include this one when you want to see who calls it (call graph)
+ OSubComponent::release();
+}
+
+// OSubComponent
+void OConnection::disposing()
+{
+ MutexGuard aGuard(m_aMutex);
+
+ OSubComponent::disposing();
+ OConnectionWrapper::disposing();
+
+ for (auto const& statement : m_aStatements)
+ {
+ Reference<XComponent> xComp(statement.get(),UNO_QUERY);
+ ::comphelper::disposeComponent(xComp);
+ }
+ m_aStatements.clear();
+ m_xMasterTables = nullptr;
+
+ if(m_pTables)
+ m_pTables->dispose();
+ if(m_pViews)
+ m_pViews->dispose();
+
+ ::comphelper::disposeComponent(m_xQueries);
+
+ for (auto const& composer : m_aComposers)
+ {
+ Reference<XComponent> xComp(composer.get(),UNO_QUERY);
+ ::comphelper::disposeComponent(xComp);
+ }
+
+ m_aComposers.clear();
+
+ try
+ {
+ if (m_xMasterConnection.is())
+ m_xMasterConnection->close();
+ }
+ catch(const Exception&)
+ {
+ }
+ m_xMasterConnection = nullptr;
+}
+
+// XChild
+Reference< XInterface > OConnection::getParent()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ return m_xParent;
+}
+
+void OConnection::setParent(const Reference< XInterface > & /*Parent*/)
+{
+ throw NoSupportException();
+}
+
+// XSQLQueryComposerFactory
+Reference< XSQLQueryComposer > OConnection::createQueryComposer()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ // Reference< XNumberFormatsSupplier > xSupplier = pParent->getNumberFormatsSupplier();
+ Reference< XSQLQueryComposer > xComposer( new OQueryComposer( this ) );
+ m_aComposers.emplace_back(xComposer);
+ return xComposer;
+}
+
+void OConnection::impl_fillTableFilter()
+{
+ Reference<XPropertySet> xProp(getParent(),UNO_QUERY);
+ if ( xProp.is() )
+ {
+ xProp->getPropertyValue(PROPERTY_TABLEFILTER) >>= m_aTableFilter;
+ xProp->getPropertyValue(PROPERTY_TABLETYPEFILTER) >>= m_aTableTypeFilter;
+ }
+}
+
+void OConnection::refresh(const Reference< XNameAccess >& _rToBeRefreshed)
+{
+ if ( _rToBeRefreshed == Reference< XNameAccess >(m_pTables.get()) )
+ {
+ if (m_pTables && !m_pTables->isInitialized())
+ {
+ impl_fillTableFilter();
+ // check if our "master connection" can supply tables
+ getMasterTables();
+
+ if (m_xMasterTables.is() && m_xMasterTables->getTables().is())
+ { // yes -> wrap them
+ m_pTables->construct(m_xMasterTables->getTables(),m_aTableFilter, m_aTableTypeFilter);
+ }
+ else
+ { // no -> use an own container
+ m_pTables->construct(m_aTableFilter, m_aTableTypeFilter);
+ }
+ }
+ }
+ else if ( _rToBeRefreshed == Reference< XNameAccess >(m_pViews.get()) )
+ {
+ if (m_pViews && !m_pViews->isInitialized())
+ {
+ impl_fillTableFilter();
+ // check if our "master connection" can supply tables
+ Reference< XViewsSupplier > xMaster(getMasterTables(),UNO_QUERY);
+
+ if (xMaster.is() && xMaster->getViews().is())
+ m_pViews->construct(xMaster->getViews(),m_aTableFilter, m_aTableTypeFilter);
+ else
+ m_pViews->construct(m_aTableFilter, m_aTableTypeFilter);
+ }
+ }
+}
+
+// XTablesSupplier
+Reference< XNameAccess > OConnection::getTables()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ refresh(m_pTables.get());
+
+ return m_pTables.get();
+}
+
+Reference< XNameAccess > SAL_CALL OConnection::getViews( )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ refresh(m_pViews.get());
+
+ return m_pViews.get();
+}
+
+// XQueriesSupplier
+Reference< XNameAccess > OConnection::getQueries()
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ return m_xQueries;
+}
+
+// css::sdb::XCommandPreparation
+Reference< XPreparedStatement > SAL_CALL OConnection::prepareCommand( const OUString& command, sal_Int32 commandType )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ OUString aStatement;
+ switch (commandType)
+ {
+ case CommandType::TABLE:
+ {
+ aStatement = "SELECT * FROM ";
+
+ OUString sCatalog, sSchema, sTable;
+ ::dbtools::qualifiedNameComponents( getMetaData(), command, sCatalog, sSchema, sTable, ::dbtools::EComposeRule::InDataManipulation );
+ aStatement += ::dbtools::composeTableNameForSelect( this, sCatalog, sSchema, sTable );
+ }
+ break;
+ case CommandType::QUERY:
+ if ( m_xQueries->hasByName(command) )
+ {
+ Reference< XPropertySet > xQuery(m_xQueries->getByName(command),UNO_QUERY);
+ xQuery->getPropertyValue(PROPERTY_COMMAND) >>= aStatement;
+ }
+ break;
+ default:
+ aStatement = command;
+ }
+ // TODO EscapeProcessing
+ return prepareStatement(aStatement);
+}
+
+Reference< XInterface > SAL_CALL OConnection::createInstance( const OUString& _sServiceSpecifier )
+{
+ Reference< XServiceInfo > xRet;
+ if ( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER == _sServiceSpecifier || _sServiceSpecifier == "com.sun.star.sdb.SingleSelectQueryAnalyzer" )
+ {
+ xRet = new OSingleSelectQueryComposer( getTables(),this, m_aContext );
+ m_aComposers.emplace_back(xRet);
+ }
+ else
+ {
+ if ( !_sServiceSpecifier.isEmpty() )
+ {
+ TSupportServices::const_iterator aFind = m_aSupportServices.find(_sServiceSpecifier);
+ if ( aFind == m_aSupportServices.end() )
+ {
+ Reference<XConnection> xMy(this);
+ Sequence<Any> aArgs{ Any(NamedValue("ActiveConnection",Any(xMy))) };
+ aFind = m_aSupportServices.emplace(
+ _sServiceSpecifier,
+ m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext(_sServiceSpecifier, aArgs, m_aContext)
+ ).first;
+ }
+ return aFind->second;
+ }
+ }
+ return Reference<XInterface>(xRet, UNO_QUERY);
+}
+
+Reference< XInterface > SAL_CALL OConnection::createInstanceWithArguments( const OUString& _sServiceSpecifier, const Sequence< Any >& /*Arguments*/ )
+{
+ return createInstance(_sServiceSpecifier);
+}
+
+Sequence< OUString > SAL_CALL OConnection::getAvailableServiceNames( )
+{
+ Sequence< OUString > aRet { SERVICE_NAME_SINGLESELECTQUERYCOMPOSER };
+ return aRet;
+}
+
+Reference< XTablesSupplier > const & OConnection::getMasterTables()
+{
+// check if out "master connection" can supply tables
+ if(!m_xMasterTables.is())
+ {
+ try
+ {
+ Reference<XDatabaseMetaData> xMeta = getMetaData();
+ if ( xMeta.is() )
+ m_xMasterTables = ::dbtools::getDataDefinitionByURLAndConnection( xMeta->getURL(), m_xMasterConnection, m_aContext );
+ }
+ catch(const SQLException&)
+ {
+ }
+ }
+ return m_xMasterTables;
+}
+
+// XUsersSupplier
+Reference< XNameAccess > SAL_CALL OConnection::getUsers( )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+
+ Reference<XUsersSupplier> xUsr(getMasterTables(),UNO_QUERY);
+ return xUsr.is() ? xUsr->getUsers() : Reference< XNameAccess >();
+}
+
+// XGroupsSupplier
+Reference< XNameAccess > SAL_CALL OConnection::getGroups( )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ Reference<XGroupsSupplier> xGrp(getMasterTables(),UNO_QUERY);
+ return xGrp.is() ? xGrp->getGroups() : Reference< XNameAccess >();
+}
+
+void OConnection::impl_loadConnectionTools_throw()
+{
+ m_xConnectionTools = css::sdb::tools::ConnectionTools::createWithConnection( m_aContext, this );
+}
+
+Reference< XTableName > SAL_CALL OConnection::createTableName( )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ impl_loadConnectionTools_throw();
+
+ return m_xConnectionTools->createTableName();
+}
+
+Reference< XObjectNames > SAL_CALL OConnection::getObjectNames( )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ impl_loadConnectionTools_throw();
+
+ return m_xConnectionTools->getObjectNames();
+}
+
+Reference< XDataSourceMetaData > SAL_CALL OConnection::getDataSourceMetaData( )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ impl_loadConnectionTools_throw();
+
+ return m_xConnectionTools->getDataSourceMetaData();
+}
+
+Reference< css::container::XNameAccess > SAL_CALL OConnection::getFieldsByCommandDescriptor( ::sal_Int32 commandType, const OUString& command, css::uno::Reference< css::lang::XComponent >& keepFieldsAlive )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ impl_loadConnectionTools_throw();
+
+ return m_xConnectionTools->getFieldsByCommandDescriptor(commandType,command,keepFieldsAlive);
+}
+
+Reference< XSingleSelectQueryComposer > SAL_CALL OConnection::getComposer( ::sal_Int32 commandType, const OUString& command )
+{
+ MutexGuard aGuard(m_aMutex);
+ checkDisposed();
+ impl_loadConnectionTools_throw();
+
+ return m_xConnectionTools->getComposer(commandType,command);
+}
+
+void OConnection::impl_checkTableQueryNames_nothrow()
+{
+ DatabaseMetaData aMeta( static_cast< XConnection* >( this ) );
+ if ( !aMeta.supportsSubqueriesInFrom() )
+ // nothing to do
+ return;
+
+ try
+ {
+ Reference< XNameAccess > xTables( getTables() );
+ const Sequence< OUString > aTableNames( xTables->getElementNames() );
+ std::set< OUString > aSortedTableNames( aTableNames.begin(), aTableNames.end() );
+
+ Reference< XNameAccess > xQueries( getQueries() );
+ const Sequence< OUString > aQueryNames( xQueries->getElementNames() );
+
+ for ( auto const & queryName : aQueryNames )
+ {
+ if ( aSortedTableNames.find( queryName ) != aSortedTableNames.end() )
+ {
+ OUString sConflictWarning( DBA_RES( RID_STR_CONFLICTING_NAMES ) );
+ m_aWarnings.appendWarning( sConflictWarning, "01SB0", *this );
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+Reference< XGraphic > SAL_CALL OConnection::getTableIcon( const OUString& TableName, ::sal_Int32 ColorMode )
+{
+ Reference< XGraphic > xReturn;
+
+ // ask our aggregate
+ if ( m_xTableUIProvider.is() )
+ xReturn = m_xTableUIProvider->getTableIcon( TableName, ColorMode );
+
+ // ask ourself
+ // well, we don't have own functionality here ...
+ // In the future, we might decide to delegate the complete handling to this interface.
+ // In this case, we would need to load the icon here.
+
+ return xReturn;
+}
+
+Reference< XInterface > SAL_CALL OConnection::getTableEditor( const Reference< XDatabaseDocumentUI >& DocumentUI, const OUString& TableName )
+{
+ Reference< XInterface > xReturn;
+
+ // ask our aggregate
+ if ( m_xTableUIProvider.is() )
+ xReturn = m_xTableUIProvider->getTableEditor( DocumentUI, TableName );
+
+ // ask ourself
+ // well, we don't have own functionality here ...
+ // In the future, we might decide to delegate the complete handling to this interface.
+ // In this case, we would need to instantiate a css.sdb.TableDesign here.
+
+ return xReturn;
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/connection.hxx b/dbaccess/source/core/dataaccess/connection.hxx
new file mode 100644
index 000000000..4ecfa7d70
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/connection.hxx
@@ -0,0 +1,229 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <atomic>
+#include <cstddef>
+#include <map>
+
+#include <apitools.hxx>
+#include <querycontainer.hxx>
+#include <tablecontainer.hxx>
+#include <viewcontainer.hxx>
+#include <RefreshListener.hxx>
+
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/sdb/XSQLQueryComposerFactory.hpp>
+#include <com/sun/star/sdb/XCommandPreparation.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XViewsSupplier.hpp>
+#include <com/sun/star/sdbcx/XUsersSupplier.hpp>
+#include <com/sun/star/sdbcx/XGroupsSupplier.hpp>
+#include <com/sun/star/sdb/XQueriesSupplier.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/sdb/tools/XConnectionTools.hpp>
+#include <com/sun/star/sdb/application/XTableUIProvider.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+
+#include <cppuhelper/implbase13.hxx>
+#include <connectivity/ConnectionWrapper.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/warningscontainer.hxx>
+
+namespace dbaccess
+{
+
+typedef cppu::ImplHelper13 < css::container::XChild
+ , css::sdbcx::XTablesSupplier
+ , css::sdbcx::XViewsSupplier
+ , css::sdbc::XConnection
+ , css::sdbc::XWarningsSupplier
+ , css::sdb::XQueriesSupplier
+ , css::sdb::XSQLQueryComposerFactory
+ , css::sdb::XCommandPreparation
+ , css::lang::XMultiServiceFactory
+ , css::sdbcx::XUsersSupplier
+ , css::sdbcx::XGroupsSupplier
+ , css::sdb::tools::XConnectionTools
+ , css::sdb::application::XTableUIProvider
+ > OConnection_Base;
+
+class ODatabaseSource;
+// OConnection
+class OConnection final :public ::cppu::BaseMutex
+ ,public OSubComponent
+ ,public ::connectivity::OConnectionWrapper
+ ,public OConnection_Base
+ ,public IRefreshListener
+{
+ css::uno::Reference< css::sdbcx::XTablesSupplier >
+ m_xMasterTables; // just to avoid the recreation of the catalog
+ connectivity::OWeakRefArray m_aStatements;
+ css::uno::Reference< css::container::XNameAccess >
+ m_xQueries;
+ connectivity::OWeakRefArray m_aComposers;
+
+ // the filter as set on the parent data link at construction of the connection
+ css::uno::Sequence< OUString > m_aTableFilter;
+ css::uno::Sequence< OUString > m_aTableTypeFilter;
+ css::uno::Reference< css::uno::XComponentContext > m_aContext;
+ css::uno::Reference< css::sdbc::XConnection > m_xMasterConnection;
+ css::uno::Reference< css::sdb::tools::XConnectionTools > m_xConnectionTools;
+ css::uno::Reference< css::sdb::application::XTableUIProvider > m_xTableUIProvider;
+
+ // defines the helper services for example to query the command of a view
+ // @ see com.sun.star.sdb.tools.XViewAccess
+ typedef std::map< OUString, css::uno::Reference< css::uno::XInterface> > TSupportServices;
+ TSupportServices m_aSupportServices;
+
+ std::unique_ptr<OTableContainer> m_pTables;
+ std::unique_ptr<OViewContainer> m_pViews;
+ ::dbtools::WarningsContainer m_aWarnings;
+ std::atomic<std::size_t> m_nInAppend;
+ bool m_bSupportsViews; // true when the getTableTypes return "VIEW" as type
+ bool m_bSupportsUsers;
+ bool m_bSupportsGroups;
+
+ virtual ~OConnection() override;
+public:
+ OConnection(ODatabaseSource& _rDB
+ ,css::uno::Reference< css::sdbc::XConnection > const & _rxMaster
+ ,const css::uno::Reference< css::uno::XComponentContext >& _rxORB);
+
+// css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+// css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+// OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+// css::container::XChild
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override;
+ virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override;
+
+// css::sdbcx::XTablesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables( ) override;
+// css::sdbcx::XViewsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getViews( ) override;
+
+// css::sdb::XQueriesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getQueries( ) override;
+
+// css::sdb::XSQLQueryComposerFactory
+ virtual css::uno::Reference< css::sdb::XSQLQueryComposer > SAL_CALL createQueryComposer( ) override;
+
+// css::sdb::XCommandPreparation
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCommand( const OUString& command, sal_Int32 commandType ) override;
+
+// css::sdbc::XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+// css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+// XConnection
+ virtual css::uno::Reference< css::sdbc::XStatement > SAL_CALL createStatement( ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareStatement( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XPreparedStatement > SAL_CALL prepareCall( const OUString& sql ) override;
+ virtual OUString SAL_CALL nativeSQL( const OUString& sql ) override;
+ virtual void SAL_CALL setAutoCommit( sal_Bool autoCommit ) override;
+ virtual sal_Bool SAL_CALL getAutoCommit( ) override;
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL rollback( ) override;
+ virtual sal_Bool SAL_CALL isClosed( ) override;
+ virtual css::uno::Reference< css::sdbc::XDatabaseMetaData > SAL_CALL getMetaData( ) override;
+ virtual void SAL_CALL setReadOnly( sal_Bool readOnly ) override;
+ virtual sal_Bool SAL_CALL isReadOnly( ) override;
+ virtual void SAL_CALL setCatalog( const OUString& catalog ) override;
+ virtual OUString SAL_CALL getCatalog( ) override;
+ virtual void SAL_CALL setTransactionIsolation( sal_Int32 level ) override;
+ virtual sal_Int32 SAL_CALL getTransactionIsolation( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTypeMap( ) override;
+ virtual void SAL_CALL setTypeMap( const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+
+// css::sdbc::XCloseable
+ virtual void SAL_CALL close( ) override;
+
+ // XMultiServiceFactory
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance( const OUString& aServiceSpecifier ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceWithArguments( const OUString& ServiceSpecifier, const css::uno::Sequence< css::uno::Any >& Arguments ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getAvailableServiceNames( ) override;
+
+ // XUsersSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getUsers( ) override;
+ // XGroupsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getGroups( ) override;
+
+ // XConnectionTools
+ virtual css::uno::Reference< css::sdb::tools::XTableName > SAL_CALL createTableName( ) override;
+ virtual css::uno::Reference< css::sdb::tools::XObjectNames > SAL_CALL getObjectNames( ) override;
+ virtual css::uno::Reference< css::sdb::tools::XDataSourceMetaData > SAL_CALL getDataSourceMetaData( ) override;
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getFieldsByCommandDescriptor( ::sal_Int32 commandType, const OUString& command, css::uno::Reference< css::lang::XComponent >& keepFieldsAlive ) override;
+ virtual css::uno::Reference< css::sdb::XSingleSelectQueryComposer > SAL_CALL getComposer( ::sal_Int32 commandType, const OUString& command ) override;
+
+ // XTableUIProvider
+ virtual css::uno::Reference< css::graphic::XGraphic > SAL_CALL getTableIcon( const OUString& TableName, ::sal_Int32 ColorMode ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getTableEditor( const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& DocumentUI, const OUString& TableName ) override;
+
+ // IRefreshListener
+ virtual void refresh(const css::uno::Reference< css::container::XNameAccess >& _rToBeRefreshed) override;
+
+private:
+ /// @throws css::lang::DisposedException
+ void checkDisposed()
+ {
+ if ( rBHelper.bDisposed || !m_xConnection.is() )
+ throw css::lang::DisposedException();
+ }
+
+ css::uno::Reference< css::sdbcx::XTablesSupplier > const & getMasterTables();
+
+ /** checks whether or not there are naming conflicts between tables and queries
+ */
+ void impl_checkTableQueryNames_nothrow();
+
+ /** loads the XConnectionTools implementation which we forward the respective functionality to
+
+ @throws css::uno::RuntimeException
+ if the implementation cannot be loaded
+
+ @postcond
+ m_xConnectionTools is nol <NULL/>
+ */
+ void impl_loadConnectionTools_throw();
+
+ /** reads the table filter and table type filter from the datasource
+ */
+ void impl_fillTableFilter();
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/dataaccessdescriptor.cxx b/dbaccess/source/core/dataaccess/dataaccessdescriptor.cxx
new file mode 100644
index 000000000..ef5239a67
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/dataaccessdescriptor.cxx
@@ -0,0 +1,229 @@
+/* -*- 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 <stringconstants.hxx>
+#include <strings.hxx>
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdb/XDataAccessDescriptorFactory.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <comphelper/broadcasthelper.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+
+namespace
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::lang::XServiceInfo;
+ using ::com::sun::star::beans::XPropertySetInfo;
+ using ::com::sun::star::beans::Property;
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::sdbc::XResultSet;
+ using ::com::sun::star::beans::XPropertySet;
+ using ::com::sun::star::beans::PropertyValue;
+
+ namespace PropertyAttribute = ::com::sun::star::beans::PropertyAttribute;
+ namespace CommandType = ::com::sun::star::sdb::CommandType;
+
+ // DataAccessDescriptor
+ typedef ::comphelper::OMutexAndBroadcastHelper DataAccessDescriptor_MutexBase;
+
+ typedef ::cppu::WeakImplHelper< XServiceInfo
+ > DataAccessDescriptor_TypeBase;
+
+ typedef ::comphelper::OPropertyContainer DataAccessDescriptor_PropertyBase;
+
+ class DataAccessDescriptor :public DataAccessDescriptor_MutexBase
+ ,public DataAccessDescriptor_TypeBase
+ ,public DataAccessDescriptor_PropertyBase
+ ,public ::comphelper::OPropertyArrayUsageHelper< DataAccessDescriptor >
+ {
+ public:
+ DataAccessDescriptor();
+
+ // UNO
+ DECLARE_XINTERFACE()
+ DECLARE_XTYPEPROVIDER()
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ protected:
+ virtual ~DataAccessDescriptor() override;
+
+ protected:
+ // XPropertySet
+ virtual Reference< XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ private:
+ // </properties>
+ OUString m_sDataSourceName;
+ OUString m_sDatabaseLocation;
+ OUString m_sConnectionResource;
+ Sequence< PropertyValue > m_aConnectionInfo;
+ Reference< XConnection > m_xActiveConnection;
+ OUString m_sCommand;
+ sal_Int32 m_nCommandType;
+ OUString m_sFilter;
+ OUString m_sOrder;
+ OUString m_sHavingClause;
+ OUString m_sGroupBy;
+ bool m_bEscapeProcessing;
+ Reference< XResultSet > m_xResultSet;
+ Sequence< Any > m_aSelection;
+ bool m_bBookmarkSelection;
+ OUString m_sColumnName;
+ Reference< XPropertySet > m_xColumn;
+ // </properties>
+ };
+
+ DataAccessDescriptor::DataAccessDescriptor()
+ :DataAccessDescriptor_PropertyBase( m_aBHelper )
+ ,m_nCommandType( CommandType::COMMAND )
+ ,m_bEscapeProcessing( true )
+ ,m_bBookmarkSelection( true )
+ {
+ registerProperty(PROPERTY_DATASOURCENAME, PROPERTY_ID_DATASOURCENAME, PropertyAttribute::BOUND, &m_sDataSourceName , cppu::UnoType<decltype(m_sDataSourceName )>::get());
+ registerProperty(PROPERTY_DATABASE_LOCATION, PROPERTY_ID_DATABASE_LOCATION, PropertyAttribute::BOUND, &m_sDatabaseLocation , cppu::UnoType<decltype(m_sDatabaseLocation )>::get());
+ registerProperty(PROPERTY_CONNECTION_RESOURCE, PROPERTY_ID_CONNECTION_RESOURCE, PropertyAttribute::BOUND, &m_sConnectionResource , cppu::UnoType<decltype(m_sConnectionResource )>::get());
+ registerProperty(PROPERTY_CONNECTION_INFO, PROPERTY_ID_CONNECTION_INFO, PropertyAttribute::BOUND, &m_aConnectionInfo , cppu::UnoType<decltype(m_aConnectionInfo )>::get());
+ registerProperty(PROPERTY_ACTIVE_CONNECTION, PROPERTY_ID_ACTIVE_CONNECTION, PropertyAttribute::BOUND, &m_xActiveConnection , cppu::UnoType<decltype(m_xActiveConnection )>::get());
+ registerProperty(PROPERTY_COMMAND, PROPERTY_ID_COMMAND, PropertyAttribute::BOUND, &m_sCommand , cppu::UnoType<decltype(m_sCommand )>::get());
+ registerProperty(PROPERTY_COMMAND_TYPE, PROPERTY_ID_COMMAND_TYPE, PropertyAttribute::BOUND, &m_nCommandType , cppu::UnoType<decltype(m_nCommandType )>::get());
+ registerProperty(PROPERTY_FILTER, PROPERTY_ID_FILTER, PropertyAttribute::BOUND, &m_sFilter , cppu::UnoType<decltype(m_sFilter )>::get());
+ registerProperty(PROPERTY_ORDER, PROPERTY_ID_ORDER, PropertyAttribute::BOUND, &m_sOrder , cppu::UnoType<decltype(m_sOrder )>::get());
+ registerProperty(PROPERTY_HAVING_CLAUSE, PROPERTY_ID_HAVING_CLAUSE, PropertyAttribute::BOUND, &m_sHavingClause , cppu::UnoType<decltype(m_sHavingClause )>::get());
+ registerProperty(PROPERTY_GROUP_BY, PROPERTY_ID_GROUP_BY, PropertyAttribute::BOUND, &m_sGroupBy , cppu::UnoType<decltype(m_sGroupBy )>::get());
+ registerProperty(PROPERTY_ESCAPE_PROCESSING, PROPERTY_ID_ESCAPE_PROCESSING, PropertyAttribute::BOUND, &m_bEscapeProcessing , cppu::UnoType<decltype(m_bEscapeProcessing )>::get());
+ registerProperty(PROPERTY_RESULT_SET, PROPERTY_ID_RESULT_SET, PropertyAttribute::BOUND, &m_xResultSet , cppu::UnoType<decltype(m_xResultSet )>::get());
+ registerProperty(PROPERTY_SELECTION, PROPERTY_ID_SELECTION, PropertyAttribute::BOUND, &m_aSelection , cppu::UnoType<decltype(m_aSelection )>::get());
+ registerProperty(PROPERTY_BOOKMARK_SELECTION, PROPERTY_ID_BOOKMARK_SELECTION, PropertyAttribute::BOUND, &m_bBookmarkSelection , cppu::UnoType<decltype(m_bBookmarkSelection )>::get());
+ registerProperty(PROPERTY_COLUMN_NAME, PROPERTY_ID_COLUMN_NAME, PropertyAttribute::BOUND, &m_sColumnName , cppu::UnoType<decltype(m_sColumnName )>::get());
+ registerProperty(PROPERTY_COLUMN, PROPERTY_ID_COLUMN, PropertyAttribute::BOUND, &m_xColumn , cppu::UnoType<decltype(m_xColumn )>::get());
+ }
+
+ DataAccessDescriptor::~DataAccessDescriptor()
+ {
+ }
+
+ IMPLEMENT_FORWARD_XINTERFACE2( DataAccessDescriptor, DataAccessDescriptor_TypeBase, DataAccessDescriptor_PropertyBase );
+
+ IMPLEMENT_FORWARD_XTYPEPROVIDER2( DataAccessDescriptor, DataAccessDescriptor_TypeBase, DataAccessDescriptor_PropertyBase );
+
+ OUString SAL_CALL DataAccessDescriptor::getImplementationName()
+ {
+ return "com.sun.star.comp.dba.DataAccessDescriptor";
+ }
+
+ sal_Bool SAL_CALL DataAccessDescriptor::supportsService( const OUString& rServiceName )
+ {
+ return cppu::supportsService(this, rServiceName);
+ }
+
+ Sequence< OUString > SAL_CALL DataAccessDescriptor::getSupportedServiceNames( )
+ {
+ return { "com.sun.star.sdb.DataAccessDescriptor" };
+ }
+
+ Reference< XPropertySetInfo > SAL_CALL DataAccessDescriptor::getPropertySetInfo()
+ {
+ Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+ }
+
+ ::cppu::IPropertyArrayHelper& DataAccessDescriptor::getInfoHelper()
+ {
+ return *getArrayHelper();
+ }
+
+ ::cppu::IPropertyArrayHelper* DataAccessDescriptor::createArrayHelper( ) const
+ {
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+ return new ::cppu::OPropertyArrayHelper( aProps );
+ }
+
+ // DataAccessDescriptorFactory
+ class DataAccessDescriptorFactory: public ::cppu::WeakImplHelper<XServiceInfo, css::sdb::XDataAccessDescriptorFactory>
+ {
+ public:
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XDataAccessDescriptorFactory
+ virtual Reference< XPropertySet > SAL_CALL createDataAccessDescriptor( ) override;
+
+ DataAccessDescriptorFactory();
+ };
+
+ DataAccessDescriptorFactory::DataAccessDescriptorFactory()
+ {
+ }
+
+ OUString SAL_CALL DataAccessDescriptorFactory::getImplementationName()
+ {
+ return "com.sun.star.comp.dba.DataAccessDescriptorFactory";
+ }
+
+ sal_Bool SAL_CALL DataAccessDescriptorFactory::supportsService( const OUString& rServiceName )
+ {
+ return cppu::supportsService(this, rServiceName);
+ }
+
+ Sequence< OUString > SAL_CALL DataAccessDescriptorFactory::getSupportedServiceNames()
+ {
+ return { "com.sun.star.sdb.DataAccessDescriptorFactory" };
+ }
+
+ Reference< XPropertySet > SAL_CALL DataAccessDescriptorFactory::createDataAccessDescriptor( )
+ {
+ return new DataAccessDescriptor();
+ }
+
+}
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface *
+com_sun_star_comp_dba_DataAccessDescriptorFactory(
+ css::uno::XComponentContext *,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ return cppu::acquire(new DataAccessDescriptorFactory());
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/databasecontext.cxx b/dbaccess/source/core/dataaccess/databasecontext.cxx
new file mode 100644
index 000000000..5afdadb67
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/databasecontext.cxx
@@ -0,0 +1,753 @@
+/* -*- 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_features.h>
+
+#include <strings.hrc>
+#include <strings.hxx>
+#include <core_resource.hxx>
+#include <databasecontext.hxx>
+#include "databaseregistrations.hxx"
+#include "datasource.hxx"
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/document/MacroExecMode.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/TerminationVetoException.hpp>
+#include <com/sun/star/frame/XLoadable.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/frame/XModel2.hpp>
+#include <com/sun/star/frame/XTerminateListener.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/registry/InvalidRegistryException.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/task/InteractionClassification.hpp>
+#include <com/sun/star/ucb/InteractiveIOException.hpp>
+#include <com/sun/star/ucb/IOErrorCode.hpp>
+#include <com/sun/star/uri/UriReferenceFactory.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/util/CloseVetoException.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+
+#include <basic/basmgr.hxx>
+#include <comphelper/enumhelper.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/processfactory.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/weak.hxx>
+#include <rtl/uri.hxx>
+#include <sal/log.hxx>
+#include <svl/filenotation.hxx>
+#include <tools/diagnose_ex.h>
+#include <tools/urlobj.hxx>
+#include <ucbhelper/content.hxx>
+#include <rtl/ref.hxx>
+#include <unotools/sharedunocomponent.hxx>
+#include <vector>
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::registry;
+using namespace ::com::sun::star;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace ::utl;
+
+using ::com::sun::star::task::InteractionClassification_ERROR;
+using ::com::sun::star::ucb::IOErrorCode_NO_FILE;
+using ::com::sun::star::ucb::InteractiveIOException;
+using ::com::sun::star::ucb::IOErrorCode_NOT_EXISTING;
+using ::com::sun::star::ucb::IOErrorCode_NOT_EXISTING_PATH;
+
+namespace dbaccess
+{
+
+ typedef ::cppu::WeakImplHelper< XTerminateListener
+ > DatabaseDocumentLoader_Base;
+ class DatabaseDocumentLoader : public DatabaseDocumentLoader_Base
+ {
+ private:
+ Reference< XDesktop2 > m_xDesktop;
+ std::vector< const ODatabaseModelImpl* > m_aDatabaseDocuments;
+
+ public:
+ explicit DatabaseDocumentLoader( const Reference<XComponentContext> & rxContext);
+
+ void append(const ODatabaseModelImpl& _rModelImpl )
+ {
+ m_aDatabaseDocuments.emplace_back(&_rModelImpl);
+ }
+
+ void remove(const ODatabaseModelImpl& _rModelImpl)
+ {
+ m_aDatabaseDocuments.erase(std::find(m_aDatabaseDocuments.begin(), m_aDatabaseDocuments.end(), &_rModelImpl));
+ }
+
+
+ private:
+ // XTerminateListener
+ virtual void SAL_CALL queryTermination( const lang::EventObject& Event ) override;
+ virtual void SAL_CALL notifyTermination( const lang::EventObject& Event ) override;
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ };
+
+ DatabaseDocumentLoader::DatabaseDocumentLoader( const Reference<XComponentContext> & rxContext )
+ {
+ try
+ {
+ m_xDesktop.set( Desktop::create(rxContext) );
+ m_xDesktop->addTerminateListener( this );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ void SAL_CALL DatabaseDocumentLoader::queryTermination( const lang::EventObject& /*Event*/ )
+ {
+ std::vector< const ODatabaseModelImpl* > aCpy(m_aDatabaseDocuments);
+ for( const auto& pCopy : aCpy )
+ {
+ try
+ {
+ const Reference< XModel2 > xMod( pCopy->getModel_noCreate(),
+ UNO_QUERY_THROW );
+ if( !xMod->getControllers()->hasMoreElements() )
+ {
+ Reference< util::XCloseable > xClose( xMod,
+ UNO_QUERY_THROW );
+ xClose->close( false );
+ }
+ }
+ catch( const CloseVetoException& )
+ {
+ throw TerminationVetoException();
+ }
+ }
+ }
+
+ void SAL_CALL DatabaseDocumentLoader::notifyTermination( const lang::EventObject& /*Event*/ )
+ {
+ }
+
+ void SAL_CALL DatabaseDocumentLoader::disposing( const lang::EventObject& /*Source*/ )
+ {
+ }
+
+// ODatabaseContext
+
+ODatabaseContext::ODatabaseContext( const Reference< XComponentContext >& _rxContext )
+ :DatabaseAccessContext_Base(m_aMutex)
+ ,m_aContext( _rxContext )
+ ,m_aContainerListeners(m_aMutex)
+{
+ m_xDatabaseDocumentLoader = new DatabaseDocumentLoader( _rxContext );
+
+#if HAVE_FEATURE_SCRIPTING
+ ::basic::BasicManagerRepository::registerCreationListener( *this );
+#endif
+
+ osl_atomic_increment( &m_refCount );
+ {
+ m_xDBRegistrationAggregate.set( createDataSourceRegistrations( m_aContext ), UNO_SET_THROW );
+ m_xDatabaseRegistrations.set( m_xDBRegistrationAggregate, UNO_QUERY_THROW );
+
+ m_xDBRegistrationAggregate->setDelegator( *this );
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+ODatabaseContext::~ODatabaseContext()
+{
+#if HAVE_FEATURE_SCRIPTING
+ ::basic::BasicManagerRepository::revokeCreationListener( *this );
+#endif
+
+ m_xDatabaseDocumentLoader.clear();
+ m_xDBRegistrationAggregate->setDelegator( nullptr );
+ m_xDBRegistrationAggregate.clear();
+ m_xDatabaseRegistrations.clear();
+}
+
+// XServiceInfo
+OUString ODatabaseContext::getImplementationName( )
+{
+ return "com.sun.star.comp.dba.ODatabaseContext";
+}
+
+sal_Bool ODatabaseContext::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Sequence< OUString > ODatabaseContext::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdb.DatabaseContext" };
+}
+
+Reference< XInterface > ODatabaseContext::impl_createNewDataSource()
+{
+ ::rtl::Reference pImpl( new ODatabaseModelImpl( m_aContext, *this ) );
+ Reference< XDataSource > xDataSource( pImpl->getOrCreateDataSource() );
+
+ return xDataSource;
+}
+
+Reference< XInterface > SAL_CALL ODatabaseContext::createInstance( )
+{
+ // for convenience of the API user, we ensure the document is fully initialized (effectively: XLoadable::initNew
+ // has been called at the DatabaseDocument).
+ return impl_createNewDataSource();
+}
+
+Reference< XInterface > SAL_CALL ODatabaseContext::createInstanceWithArguments( const Sequence< Any >& _rArguments )
+{
+ ::comphelper::NamedValueCollection aArgs( _rArguments );
+ OUString sURL = aArgs.getOrDefault( INFO_POOLURL, OUString() );
+
+ Reference< XInterface > xDataSource;
+ if ( !sURL.isEmpty() )
+ xDataSource = getObject( sURL );
+
+ if ( !xDataSource.is() )
+ xDataSource = impl_createNewDataSource();
+
+ return xDataSource;
+}
+
+// DatabaseAccessContext_Base
+void ODatabaseContext::disposing()
+{
+ // notify our listener
+ css::lang::EventObject aDisposeEvent(static_cast< XContainer* >(this));
+ m_aContainerListeners.disposeAndClear(aDisposeEvent);
+
+ // dispose the data sources
+ // disposing seems to remove elements, so work on copy for valid iterators
+ ObjectCache objCopy;
+ objCopy.swap(m_aDatabaseObjects);
+ for (auto const& elem : objCopy)
+ {
+ rtl::Reference< ODatabaseModelImpl > obj(elem.second);
+ // make sure obj is acquired and does not delete itself from within
+ // dispose()
+ obj->dispose();
+ }
+}
+
+// XNamingService
+Reference< XInterface > ODatabaseContext::getRegisteredObject(const OUString& _rName)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
+
+ OUString sURL( getDatabaseLocation( _rName ) );
+
+ if ( sURL.isEmpty() )
+ // there is a registration for this name, but no URL
+ throw IllegalArgumentException();
+
+ // check if URL is already loaded
+ Reference< XInterface > xExistent = getObject( sURL );
+ if ( xExistent.is() )
+ return xExistent;
+
+ return loadObjectFromURL( _rName, sURL );
+}
+
+Reference< XInterface > ODatabaseContext::loadObjectFromURL(const OUString& _rName,const OUString& _sURL)
+{
+ INetURLObject aURL( _sURL );
+
+ if ( aURL.GetProtocol() == INetProtocol::NotValid )
+ throw NoSuchElementException( _rName, *this );
+
+ bool bEmbeddedDataSource = aURL.isSchemeEqualTo(INetProtocol::VndSunStarPkg);
+ try
+ {
+ if (!bEmbeddedDataSource)
+ {
+ ::ucbhelper::Content aContent( _sURL, nullptr, comphelper::getProcessComponentContext() );
+ if ( !aContent.isDocument() )
+ throw InteractiveIOException(
+ _sURL, *this, InteractionClassification_ERROR, IOErrorCode_NO_FILE
+ );
+ }
+ }
+ catch ( const InteractiveIOException& e )
+ {
+ if ( ( e.Code == IOErrorCode_NO_FILE )
+ || ( e.Code == IOErrorCode_NOT_EXISTING )
+ || ( e.Code == IOErrorCode_NOT_EXISTING_PATH )
+ )
+ {
+ // #i40463# #i39187#
+ OUString sErrorMessage( DBA_RES( RID_STR_FILE_DOES_NOT_EXIST ) );
+ ::svt::OFileNotation aTransformer( _sURL );
+
+ SQLException aError;
+ aError.Message = sErrorMessage.replaceAll( "$file$", aTransformer.get( ::svt::OFileNotation::N_SYSTEM ) );
+
+ throw WrappedTargetException( _sURL, *this, Any( aError ) );
+ }
+ throw WrappedTargetException( _sURL, *this, ::cppu::getCaughtException() );
+ }
+ catch( const Exception& )
+ {
+ throw WrappedTargetException( _sURL, *this, ::cppu::getCaughtException() );
+ }
+
+ OSL_ENSURE( m_aDatabaseObjects.find( _sURL ) == m_aDatabaseObjects.end(),
+ "ODatabaseContext::loadObjectFromURL: not intended for already-cached objects!" );
+
+ ::rtl::Reference< ODatabaseModelImpl > pModelImpl;
+ {
+ pModelImpl.set( new ODatabaseModelImpl( _rName, m_aContext, *this ) );
+
+ Reference< XModel > xModel( pModelImpl->createNewModel_deliverOwnership(), UNO_SET_THROW );
+ Reference< XLoadable > xLoad( xModel, UNO_QUERY_THROW );
+
+ ::comphelper::NamedValueCollection aArgs;
+ aArgs.put( "URL", _sURL );
+ aArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG );
+ aArgs.put( "InteractionHandler", task::InteractionHandler::createWithParent(m_aContext, nullptr) );
+ if (bEmbeddedDataSource)
+ {
+ // In this case the host contains the real path, and the path is the embedded stream name.
+ auto const uri = css::uri::UriReferenceFactory::create(m_aContext)->parse(_sURL);
+ if (uri.is() && uri->isAbsolute()
+ && uri->hasAuthority() && !uri->hasQuery() && !uri->hasFragment())
+ {
+ auto const auth = uri->getAuthority();
+ auto const decAuth = rtl::Uri::decode(
+ auth, rtl_UriDecodeStrict, RTL_TEXTENCODING_UTF8);
+ if (auth.isEmpty() == decAuth.isEmpty()) {
+ // Decoding of auth to UTF-8 succeeded:
+ OUString sBaseURI = decAuth + uri->getPath();
+ aArgs.put("BaseURI", sBaseURI);
+ } else {
+ SAL_WARN(
+ "dbaccess.core",
+ "<" << _sURL << "> cannot be parse as vnd.sun.star.pkg URL");
+ }
+ } else {
+ SAL_WARN(
+ "dbaccess.core", "<" << _sURL << "> cannot be parse as vnd.sun.star.pkg URL");
+ }
+ }
+
+ Sequence< PropertyValue > aResource( aArgs.getPropertyValues() );
+ xLoad->load( aResource );
+ xModel->attachResource( _sURL, aResource );
+
+ ::utl::CloseableComponent aEnsureClose( xModel );
+ }
+
+ setTransientProperties( _sURL, *pModelImpl );
+
+ return pModelImpl->getOrCreateDataSource();
+}
+
+void ODatabaseContext::appendAtTerminateListener(const ODatabaseModelImpl& _rDataSourceModel)
+{
+ m_xDatabaseDocumentLoader->append(_rDataSourceModel);
+}
+
+void ODatabaseContext::removeFromTerminateListener(const ODatabaseModelImpl& _rDataSourceModel)
+{
+ m_xDatabaseDocumentLoader->remove(_rDataSourceModel);
+}
+
+void ODatabaseContext::setTransientProperties(const OUString& _sURL, ODatabaseModelImpl& _rDataSourceModel )
+{
+ if ( m_aDatasourceProperties.end() == m_aDatasourceProperties.find(_sURL) )
+ return;
+ try
+ {
+ OUString sAuthFailedPassword;
+ Reference< XPropertySet > xDSProps( _rDataSourceModel.getOrCreateDataSource(), UNO_QUERY_THROW );
+ const Sequence< PropertyValue >& rSessionPersistentProps = m_aDatasourceProperties[_sURL];
+ for ( auto const & prop : rSessionPersistentProps )
+ {
+ if ( prop.Name == "AuthFailedPassword" )
+ {
+ OSL_VERIFY( prop.Value >>= sAuthFailedPassword );
+ }
+ else
+ {
+ xDSProps->setPropertyValue( prop.Name, prop.Value );
+ }
+ }
+
+ _rDataSourceModel.m_sFailedPassword = sAuthFailedPassword;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void ODatabaseContext::registerObject(const OUString& _rName, const Reference< XInterface > & _rxObject)
+{
+ if ( _rName.isEmpty() )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+
+ Reference< XDocumentDataSource > xDocDataSource( _rxObject, UNO_QUERY );
+ Reference< XModel > xModel( xDocDataSource.is() ? xDocDataSource->getDatabaseDocument() : Reference< XOfficeDatabaseDocument >(), UNO_QUERY );
+ if ( !xModel.is() )
+ throw IllegalArgumentException( OUString(), *this, 2 );
+
+ OUString sURL = xModel->getURL();
+ if ( sURL.isEmpty() )
+ throw IllegalArgumentException( DBA_RES( RID_STR_DATASOURCE_NOT_STORED ), *this, 2 );
+
+ { // avoid deadlocks: lock m_aMutex after checking arguments
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
+
+ registerDatabaseLocation( _rName, sURL );
+
+ ODatabaseSource::setName( xDocDataSource, _rName, ODatabaseSource::DBContextAccess() );
+ }
+
+ // notify our container listeners
+ ContainerEvent aEvent(static_cast<XContainer*>(this), Any(_rName), Any(_rxObject), Any());
+ m_aContainerListeners.notifyEach( &XContainerListener::elementInserted, aEvent );
+}
+
+void ODatabaseContext::storeTransientProperties( ODatabaseModelImpl& _rModelImpl)
+{
+ Reference< XPropertySet > xSource( _rModelImpl.getOrCreateDataSource(), UNO_QUERY );
+ ::comphelper::NamedValueCollection aRememberProps;
+
+ try
+ {
+ // get the info about the properties, check which ones are transient and not readonly
+ Reference< XPropertySetInfo > xSetInfo;
+ if (xSource.is())
+ xSetInfo = xSource->getPropertySetInfo();
+ Sequence< Property > aProperties;
+ if (xSetInfo.is())
+ aProperties = xSetInfo->getProperties();
+
+ for ( const Property& rProperty : std::as_const(aProperties) )
+ {
+ if ( ( ( rProperty.Attributes & PropertyAttribute::TRANSIENT) != 0 )
+ && ( ( rProperty.Attributes & PropertyAttribute::READONLY) == 0 )
+ )
+ {
+ // found such a property
+ aRememberProps.put( rProperty.Name, xSource->getPropertyValue( rProperty.Name ) );
+ }
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ // additionally, remember the "failed password", which is not available as property
+ // #i86178#
+ aRememberProps.put( "AuthFailedPassword", _rModelImpl.m_sFailedPassword );
+
+ OUString sDocumentURL( _rModelImpl.getURL() );
+ if ( m_aDatabaseObjects.find( sDocumentURL ) != m_aDatabaseObjects.end() )
+ {
+ m_aDatasourceProperties[ sDocumentURL ] = aRememberProps.getPropertyValues();
+ }
+ else if ( m_aDatabaseObjects.find( _rModelImpl.m_sName ) != m_aDatabaseObjects.end() )
+ {
+ OSL_FAIL( "ODatabaseContext::storeTransientProperties: a database document register by name? This shouldn't happen anymore!" );
+ // all the code should have been changed so that registration is by URL only
+ m_aDatasourceProperties[ _rModelImpl.m_sName ] = aRememberProps.getPropertyValues();
+ }
+ else
+ {
+ OSL_ENSURE( sDocumentURL.isEmpty() && _rModelImpl.m_sName.isEmpty() ,
+ "ODatabaseContext::storeTransientProperties: a non-empty data source which I do not know?!" );
+ }
+}
+
+void SAL_CALL ODatabaseContext::addContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ m_aContainerListeners.addInterface(_rxListener);
+}
+
+void SAL_CALL ODatabaseContext::removeContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ m_aContainerListeners.removeInterface(_rxListener);
+}
+
+void ODatabaseContext::revokeObject(const OUString& _rName)
+{
+ ClearableMutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
+
+ OUString sURL = getDatabaseLocation( _rName );
+
+ revokeDatabaseLocation( _rName );
+ // will throw if something goes wrong
+
+ if ( m_aDatabaseObjects.find( _rName ) != m_aDatabaseObjects.end() )
+ {
+ m_aDatasourceProperties[ sURL ] = m_aDatasourceProperties[ _rName ];
+ }
+
+ // check if URL is already loaded
+ ObjectCache::const_iterator aExistent = m_aDatabaseObjects.find( sURL );
+ if ( aExistent != m_aDatabaseObjects.end() )
+ m_aDatabaseObjects.erase( aExistent );
+
+ // notify our container listeners
+ ContainerEvent aEvent( *this, Any( _rName ), Any(), Any() );
+ aGuard.clear();
+ m_aContainerListeners.notifyEach( &XContainerListener::elementRemoved, aEvent );
+}
+
+sal_Bool SAL_CALL ODatabaseContext::hasRegisteredDatabase( const OUString& Name )
+{
+ return m_xDatabaseRegistrations->hasRegisteredDatabase( Name );
+}
+
+Sequence< OUString > SAL_CALL ODatabaseContext::getRegistrationNames()
+{
+ return m_xDatabaseRegistrations->getRegistrationNames();
+}
+
+OUString SAL_CALL ODatabaseContext::getDatabaseLocation( const OUString& Name )
+{
+ return m_xDatabaseRegistrations->getDatabaseLocation( Name );
+}
+
+void SAL_CALL ODatabaseContext::registerDatabaseLocation( const OUString& Name, const OUString& Location )
+{
+ m_xDatabaseRegistrations->registerDatabaseLocation( Name, Location );
+}
+
+void SAL_CALL ODatabaseContext::revokeDatabaseLocation( const OUString& Name )
+{
+ m_xDatabaseRegistrations->revokeDatabaseLocation( Name );
+}
+
+void SAL_CALL ODatabaseContext::changeDatabaseLocation( const OUString& Name, const OUString& NewLocation )
+{
+ m_xDatabaseRegistrations->changeDatabaseLocation( Name, NewLocation );
+}
+
+sal_Bool SAL_CALL ODatabaseContext::isDatabaseRegistrationReadOnly( const OUString& Name )
+{
+ return m_xDatabaseRegistrations->isDatabaseRegistrationReadOnly( Name );
+}
+
+void SAL_CALL ODatabaseContext::addDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener )
+{
+ m_xDatabaseRegistrations->addDatabaseRegistrationsListener( Listener );
+}
+
+void SAL_CALL ODatabaseContext::removeDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener )
+{
+ m_xDatabaseRegistrations->removeDatabaseRegistrationsListener( Listener );
+}
+
+// css::container::XElementAccess
+Type ODatabaseContext::getElementType( )
+{
+ return cppu::UnoType<XDataSource>::get();
+}
+
+sal_Bool ODatabaseContext::hasElements()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
+
+ return getElementNames().hasElements();
+}
+
+// css::container::XEnumerationAccess
+Reference< css::container::XEnumeration > ODatabaseContext::createEnumeration()
+{
+ MutexGuard aGuard(m_aMutex);
+ return new ::comphelper::OEnumerationByName(static_cast<XNameAccess*>(this));
+}
+
+// css::container::XNameAccess
+Any ODatabaseContext::getByName(const OUString& _rName)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
+ if ( _rName.isEmpty() )
+ throw NoSuchElementException(_rName, *this);
+
+ try
+ {
+ Reference< XInterface > xExistent = getObject( _rName );
+ if ( xExistent.is() )
+ return Any( xExistent );
+
+ // see whether this is a registered name
+ OUString sURL;
+ if ( hasRegisteredDatabase( _rName ) )
+ {
+ sURL = getDatabaseLocation( _rName );
+ // is the object cached under its URL?
+ xExistent = getObject( sURL );
+ }
+ else
+ // interpret the name as URL
+ sURL = _rName;
+
+ if ( !xExistent.is() )
+ // try to load this as URL
+ xExistent = loadObjectFromURL( _rName, sURL );
+ return Any( xExistent );
+ }
+ catch (const NoSuchElementException&)
+ { // let these exceptions through
+ throw;
+ }
+ catch (const WrappedTargetException&)
+ { // let these exceptions through
+ throw;
+ }
+ catch (const RuntimeException&)
+ { // let these exceptions through
+ throw;
+ }
+ catch (const Exception&)
+ { // exceptions other than the specified ones -> wrap
+ Any aError = ::cppu::getCaughtException();
+ throw WrappedTargetException(_rName, *this, aError );
+ }
+}
+
+Sequence< OUString > ODatabaseContext::getElementNames()
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
+
+ return getRegistrationNames();
+}
+
+sal_Bool ODatabaseContext::hasByName(const OUString& _rName)
+{
+ MutexGuard aGuard(m_aMutex);
+ ::connectivity::checkDisposed(DatabaseAccessContext_Base::rBHelper.bDisposed);
+
+ return hasRegisteredDatabase( _rName );
+}
+
+Reference< XInterface > ODatabaseContext::getObject( const OUString& _rURL )
+{
+ ObjectCache::const_iterator aFind = m_aDatabaseObjects.find( _rURL );
+ Reference< XInterface > xExistent;
+ if ( aFind != m_aDatabaseObjects.end() )
+ xExistent = aFind->second->getOrCreateDataSource();
+ return xExistent;
+}
+
+void ODatabaseContext::registerDatabaseDocument( ODatabaseModelImpl& _rModelImpl )
+{
+ OUString sURL( _rModelImpl.getURL() );
+ SAL_INFO("dbaccess.core", "DatabaseContext: registering " << sURL);
+ if ( m_aDatabaseObjects.find( sURL ) == m_aDatabaseObjects.end() )
+ {
+ m_aDatabaseObjects[ sURL ] = &_rModelImpl;
+ setTransientProperties( sURL, _rModelImpl );
+ }
+ else
+ OSL_FAIL( "ODatabaseContext::registerDatabaseDocument: already have an object registered for this URL!" );
+}
+
+void ODatabaseContext::revokeDatabaseDocument( const ODatabaseModelImpl& _rModelImpl )
+{
+ const OUString& sURL( _rModelImpl.getURL() );
+ SAL_INFO("dbaccess.core", "DatabaseContext: deregistering " << sURL);
+ m_aDatabaseObjects.erase( sURL );
+}
+
+void ODatabaseContext::databaseDocumentURLChange( const OUString& _rOldURL, const OUString& _rNewURL )
+{
+ SAL_INFO("dbaccess.core", "DatabaseContext: changing registrations from " << _rOldURL <<
+ " to " << _rNewURL);
+ ObjectCache::const_iterator oldPos = m_aDatabaseObjects.find( _rOldURL );
+ ENSURE_OR_THROW( oldPos != m_aDatabaseObjects.end(), "illegal old database document URL" );
+ ObjectCache::const_iterator newPos = m_aDatabaseObjects.find( _rNewURL );
+ ENSURE_OR_THROW( newPos == m_aDatabaseObjects.end(), "illegal new database document URL" );
+
+ m_aDatabaseObjects[ _rNewURL ] = oldPos->second;
+ m_aDatabaseObjects.erase( oldPos );
+}
+
+sal_Int64 SAL_CALL ODatabaseContext::getSomething( const Sequence< sal_Int8 >& rId )
+{
+ return comphelper::getSomethingImpl(rId, this);
+}
+
+const Sequence< sal_Int8 > & ODatabaseContext::getUnoTunnelId()
+{
+ static const comphelper::UnoIdInit implId;
+ return implId.getSeq();
+}
+
+void ODatabaseContext::onBasicManagerCreated( const Reference< XModel >& _rxForDocument, BasicManager& _rBasicManager )
+{
+#if !HAVE_FEATURE_SCRIPTING
+ (void) _rxForDocument;
+ (void) _rBasicManager;
+#else
+ // if it's a database document ...
+ Reference< XOfficeDatabaseDocument > xDatabaseDocument( _rxForDocument, UNO_QUERY );
+ // ... or a sub document of a database document ...
+ if ( !xDatabaseDocument.is() )
+ {
+ Reference< XChild > xDocAsChild( _rxForDocument, UNO_QUERY );
+ if ( xDocAsChild.is() )
+ xDatabaseDocument.set( xDocAsChild->getParent(), UNO_QUERY );
+ }
+
+ // ... whose BasicManager has just been created, then add the global DatabaseDocument variable to its scope.
+ if ( xDatabaseDocument.is() )
+ _rBasicManager.SetGlobalUNOConstant( "ThisDatabaseDocument", Any( xDatabaseDocument ) );
+#endif
+}
+
+} // namespace dbaccess
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dba_ODatabaseContext_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new dbaccess::ODatabaseContext(context));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/databasedocument.cxx b/dbaccess/source/core/dataaccess/databasedocument.cxx
new file mode 100644
index 000000000..419d02d2d
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/databasedocument.cxx
@@ -0,0 +1,2211 @@
+/* -*- 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 <core_resource.hxx>
+#include <strings.hrc>
+#include "databasedocument.hxx"
+#include "documenteventexecutor.hxx"
+#include <databasecontext.hxx>
+#include "documentcontainer.hxx"
+#include <sdbcoretools.hxx>
+#include <strings.hxx>
+#include <recovery/dbdocrecovery.hxx>
+
+#include <officecfg/Office/Common.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/document/XExporter.hpp>
+#include <com/sun/star/document/XFilter.hpp>
+#include <com/sun/star/document/XImporter.hpp>
+#include <com/sun/star/document/XGraphicStorageHandler.hpp>
+#include <com/sun/star/document/GraphicStorageHandler.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/ModuleManager.hpp>
+#include <com/sun/star/io/IOException.hpp>
+#include <com/sun/star/io/XSeekable.hpp>
+#include <com/sun/star/io/XOutputStream.hpp>
+#include <com/sun/star/io/XTruncate.hpp>
+#include <com/sun/star/lang/NoSupportException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/script/provider/theMasterScriptProviderFactory.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
+#include <com/sun/star/task/XStatusIndicator.hpp>
+#include <com/sun/star/ucb/SimpleFileAccess.hpp>
+#include <com/sun/star/ui/UIConfigurationManager.hpp>
+#include <com/sun/star/util/CloseVetoException.hpp>
+#include <com/sun/star/view/XSelectionSupplier.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+#include <com/sun/star/xml/sax/Writer.hpp>
+
+#include <com/sun/star/script/XStorageBasedLibraryContainer.hpp>
+#include <com/sun/star/awt/XControl.hpp>
+#include <com/sun/star/awt/DialogProvider.hpp>
+
+#include <comphelper/documentconstants.hxx>
+#include <comphelper/enumhelper.hxx>
+#include <comphelper/genericpropertyset.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/numberedcollection.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/storagehelper.hxx>
+#include <comphelper/propertysetinfo.hxx>
+#include <comphelper/types.hxx>
+
+#include <connectivity/dbtools.hxx>
+
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <framework/titlehelper.hxx>
+#include <unotools/saveopt.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+
+#include <vcl/GraphicObject.hxx>
+#include <tools/urlobj.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::document;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::view;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star;
+using namespace ::com::sun::star::xml::sax;
+using namespace ::com::sun::star::script;
+using namespace ::com::sun::star::script::provider;
+using namespace ::com::sun::star::ui;
+using namespace ::cppu;
+
+namespace dbaccess
+{
+
+// ViewMonitor
+
+bool ViewMonitor::onControllerConnected( const Reference< XController >& _rxController )
+{
+ bool bFirstControllerEver = !m_bEverHadController;
+ m_bEverHadController = true;
+
+ m_xLastConnectedController = _rxController;
+ m_bLastIsFirstEverController = bFirstControllerEver;
+
+ return bFirstControllerEver;
+}
+
+bool ViewMonitor::onSetCurrentController( const Reference< XController >& _rxController )
+{
+ // we interpret this as "loading the document (including UI) is finished",
+ // if and only if this is the controller which was last connected, and it was the
+ // first controller ever connected
+ bool bLoadFinished = ( _rxController == m_xLastConnectedController ) && m_bLastIsFirstEverController;
+
+ // notify the respective events
+ if ( bLoadFinished )
+ m_rEventNotifier.notifyDocumentEventAsync( m_bIsNewDocument ? "OnNew" : "OnLoad" );
+
+ return bLoadFinished;
+}
+
+
+ODatabaseDocument::ODatabaseDocument(const ::rtl::Reference<ODatabaseModelImpl>& _pImpl )
+ :ModelDependentComponent( _pImpl )
+ ,ODatabaseDocument_OfficeDocument( getMutex() )
+ ,m_aModifyListeners( getMutex() )
+ ,m_aCloseListener( getMutex() )
+ ,m_aStorageListeners( getMutex() )
+ ,m_pEventContainer( new DocumentEvents( *this, getMutex(), _pImpl->getDocumentEvents() ) )
+ ,m_aEventNotifier( *this, getMutex() )
+ ,m_aViewMonitor( m_aEventNotifier )
+ ,m_eInitState( NotInitialized )
+ ,m_bClosing( false )
+ ,m_bAllowDocumentScripting( false )
+ ,m_bHasBeenRecovered( false )
+ ,m_bEmbedded(false)
+{
+ osl_atomic_increment( &m_refCount );
+ {
+ impl_reparent_nothrow( m_xForms );
+ impl_reparent_nothrow( m_xReports );
+ impl_reparent_nothrow( m_pImpl->m_xTableDefinitions );
+ impl_reparent_nothrow( m_pImpl->m_xCommandDefinitions );
+
+ m_pEventExecutor = new DocumentEventExecutor( m_pImpl->m_aContext, this );
+ }
+ osl_atomic_decrement( &m_refCount );
+
+ // if there previously was a document instance for the same Impl which was already initialized,
+ // then consider ourself initialized, too.
+ // #i94840#
+ if ( !m_pImpl->hadInitializedDocument() )
+ return;
+
+ // Note we set our init-state to "Initializing", not "Initialized". We're created from inside the ModelImpl,
+ // which is expected to call attachResource in case there was a previous incarnation of the document,
+ // so we can properly finish our initialization then.
+ impl_setInitializing();
+
+ if ( !m_pImpl->getURL().isEmpty() )
+ {
+ // if the previous incarnation of the DatabaseDocument already had a URL, then creating this incarnation
+ // here is effectively loading the document.
+ // #i105505#
+ m_aViewMonitor.onLoadedDocument();
+ }
+}
+
+ODatabaseDocument::~ODatabaseDocument()
+{
+ if ( !ODatabaseDocument_OfficeDocument::rBHelper.bInDispose && !ODatabaseDocument_OfficeDocument::rBHelper.bDisposed )
+ {
+ acquire();
+ dispose();
+ }
+}
+
+Any SAL_CALL ODatabaseDocument::queryInterface( const Type& _rType )
+{
+ // strip XEmbeddedScripts and XScriptInvocationContext if we have any form/report
+ // which already contains macros. In this case, the database document itself is not
+ // allowed to contain macros, too.
+ if ( !m_bAllowDocumentScripting
+ && ( _rType.equals( cppu::UnoType<XEmbeddedScripts>::get() )
+ || _rType.equals( cppu::UnoType<XScriptInvocationContext>::get() )
+ )
+ )
+ return Any();
+
+ Any aReturn = ODatabaseDocument_OfficeDocument::queryInterface(_rType);
+ if (!aReturn.hasValue())
+ aReturn = ODatabaseDocument_Title::queryInterface(_rType);
+ return aReturn;
+}
+
+void SAL_CALL ODatabaseDocument::acquire( ) noexcept
+{
+ ODatabaseDocument_OfficeDocument::acquire();
+}
+
+void SAL_CALL ODatabaseDocument::release( ) noexcept
+{
+ ODatabaseDocument_OfficeDocument::release();
+}
+
+Sequence< Type > SAL_CALL ODatabaseDocument::getTypes( )
+{
+ Sequence< Type > aTypes = ::comphelper::concatSequences(
+ ODatabaseDocument_OfficeDocument::getTypes(),
+ ODatabaseDocument_Title::getTypes()
+ );
+
+ // strip XEmbeddedScripts and XScriptInvocationContext if we have any form/report
+ // which already contains macros. In this case, the database document itself is not
+ // allowed to contain macros, too.
+ if ( !m_bAllowDocumentScripting )
+ {
+ auto [begin, end] = asNonConstRange(aTypes);
+ auto newEnd = std::remove_if( begin, end,
+ [](const Type& t)
+ { return t == cppu::UnoType<XEmbeddedScripts>::get() ||
+ t == cppu::UnoType<XScriptInvocationContext>::get();} );
+ aTypes.realloc( std::distance(begin, newEnd) );
+ }
+
+ return aTypes;
+}
+
+Sequence< sal_Int8 > SAL_CALL ODatabaseDocument::getImplementationId( )
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// local functions
+namespace
+{
+ Reference< XStatusIndicator > lcl_extractStatusIndicator( const ::comphelper::NamedValueCollection& _rArguments )
+ {
+ Reference< XStatusIndicator > xStatusIndicator;
+ return _rArguments.getOrDefault( "StatusIndicator", xStatusIndicator );
+ }
+
+ void lcl_triggerStatusIndicator_throw( const ::comphelper::NamedValueCollection& _rArguments, DocumentGuard& _rGuard, const bool _bStart )
+ {
+ Reference< XStatusIndicator > xStatusIndicator( lcl_extractStatusIndicator( _rArguments ) );
+ if ( !xStatusIndicator.is() )
+ return;
+
+ _rGuard.clear();
+ try
+ {
+ if ( _bStart )
+ xStatusIndicator->start( OUString(), sal_Int32(1000000) );
+ else
+ xStatusIndicator->end();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ _rGuard.reset();
+ // note that |reset| can throw a DisposedException
+ }
+
+ void lcl_extractStatusIndicator( const ::comphelper::NamedValueCollection& _rArguments, Sequence< Any >& _rCallArgs )
+ {
+ Reference< XStatusIndicator > xStatusIndicator( lcl_extractStatusIndicator( _rArguments ) );
+ if ( !xStatusIndicator.is() )
+ return;
+
+ sal_Int32 nLength = _rCallArgs.getLength();
+ _rCallArgs.realloc( nLength + 1 );
+ _rCallArgs.getArray()[ nLength ] <<= xStatusIndicator;
+ }
+
+ void lcl_extractAndStartStatusIndicator( const ::comphelper::NamedValueCollection& _rArguments, Reference< XStatusIndicator >& _rxStatusIndicator,
+ Sequence< Any >& _rCallArgs )
+ {
+ _rxStatusIndicator = lcl_extractStatusIndicator( _rArguments );
+ if ( !_rxStatusIndicator.is() )
+ return;
+
+ try
+ {
+ _rxStatusIndicator->start( OUString(), sal_Int32(1000000) );
+
+ sal_Int32 nLength = _rCallArgs.getLength();
+ _rCallArgs.realloc( nLength + 1 );
+ _rCallArgs.getArray()[ nLength ] <<= _rxStatusIndicator;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ Sequence< PropertyValue > lcl_appendFileNameToDescriptor( const ::comphelper::NamedValueCollection& _rDescriptor, const OUString& _rURL )
+ {
+ ::comphelper::NamedValueCollection aMutableDescriptor( _rDescriptor );
+ if ( !_rURL.isEmpty() )
+ {
+ aMutableDescriptor.put( "FileName", _rURL );
+ aMutableDescriptor.put( "URL", _rURL );
+ }
+ return aMutableDescriptor.getPropertyValues();
+ }
+}
+
+constexpr OUStringLiteral sPictures = u"Pictures";
+
+// base documents seem to have a different behaviour to other documents, the
+// root storage contents at least seem to be re-used over different saves, thus if there is a
+// top level Picture directory it is never cleared.
+// If we delete the 'Pictures' directory then the dialog library storage which does store
+// any embed images will not work properly. ( this is due to the fact it will
+// try to load the dialog which will try and access the embed images, if those images are not cached in
+// memory it will try to read them from the Picture directory which is now gone, so... we have to use this
+// inglorious hack below which basically will
+//
+// a) create a temp storage
+//
+// b) introspect any dialogs for any embed graphics and grab the associate URL(s)
+//
+// c) populate the temp storage with the associated embed images ( will be stored in a 'Pictures' folder )
+//
+// d) delete the 'Picture' element from the root storage
+//
+// e) copy the Pictures element of the temp storage to the root storage
+//
+// this assumes that we don't use the Pictures folder in the root of the base
+// document for anything, I believe this is a valid assumption ( as much as
+// I could check anyway )
+
+/// @throws RuntimeException
+static void lcl_uglyHackToStoreDialogeEmbedImages( const Reference< XStorageBasedLibraryContainer >& xDlgCont, const Reference< XStorage >& xStorage, const Reference< XModel >& rxModel, const Reference<XComponentContext >& rxContext )
+{
+ const Sequence< OUString > sLibraries = xDlgCont->getElementNames();
+ Reference< XStorage > xTmpPic = xStorage->openStorageElement( "tempPictures", ElementModes::READWRITE );
+
+ std::vector<uno::Reference<graphic::XGraphic>> vxGraphicList;
+ for ( OUString const & sLibrary : sLibraries )
+ {
+ xDlgCont->loadLibrary( sLibrary );
+ Reference< XNameContainer > xLib;
+ xDlgCont->getByName( sLibrary ) >>= xLib;
+ if ( xLib.is() )
+ {
+ Sequence< OUString > sDialogs = xLib->getElementNames();
+ sal_Int32 nDialogs( sDialogs.getLength() );
+ for ( sal_Int32 j=0; j < nDialogs; ++j )
+ {
+ Reference < awt::XDialogProvider > xDlgPrv = awt::DialogProvider::createWithModel(rxContext, rxModel);
+ OUString sDialogUrl =
+ "vnd.sun.star.script:" + sLibrary + "." + sDialogs[j] + "?location=document";
+
+ Reference< css::awt::XControl > xDialog( xDlgPrv->createDialog( sDialogUrl ), UNO_QUERY );
+ Reference< XInterface > xModel( xDialog->getModel() );
+ vcl::graphic::SearchForGraphics(xModel, vxGraphicList);
+ }
+ }
+ }
+ // if we have any image urls, make sure we copy the associated images into tempPictures
+ if (!vxGraphicList.empty())
+ {
+ // Export the images to the storage
+ uno::Reference<document::XGraphicStorageHandler> xGraphicStorageHandler;
+ xGraphicStorageHandler.set(GraphicStorageHandler::createWithStorage(rxContext, xTmpPic));
+ if (xGraphicStorageHandler.is())
+ {
+ for (uno::Reference<graphic::XGraphic> const & rxGraphic : vxGraphicList)
+ {
+ xGraphicStorageHandler->saveGraphic(rxGraphic);
+ }
+ }
+ // delete old 'Pictures' storage and copy the contents of tempPictures into xStorage
+ xStorage->removeElement( sPictures );
+ xTmpPic->copyElementTo( sPictures, xStorage, sPictures );
+ }
+ else
+ {
+ // clean up an existing Pictures dir
+ if ( xStorage->isStorageElement( sPictures ) )
+ xStorage->removeElement( sPictures );
+ }
+}
+
+void ODatabaseDocument::impl_setInitialized()
+{
+ m_eInitState = Initialized;
+
+ // start event notifications
+ m_aEventNotifier.onDocumentInitialized();
+}
+
+void ODatabaseDocument::impl_reset_nothrow()
+{
+ try
+ {
+ m_pImpl->clearConnections();
+ m_pImpl->disposeStorages();
+ m_pImpl->resetRootStorage();
+
+ clearObjectContainer( m_xForms );
+ clearObjectContainer( m_xReports );
+ clearObjectContainer( m_pImpl->m_xTableDefinitions );
+ clearObjectContainer( m_pImpl->m_xCommandDefinitions );
+
+ m_eInitState = NotInitialized;
+
+ m_pImpl->reset();
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ m_pImpl->m_bDocumentReadOnly = false;
+}
+
+namespace
+{
+ /** property map for import/export info set */
+ comphelper::PropertyMapEntry const aExportInfoMap[] =
+ {
+ { OUString("BaseURI"), 0, ::cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("StreamName"), 0, ::cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID, 0 },
+ { OUString("UsePrettyPrinting"), 0, ::cppu::UnoType<sal_Bool>::get(), beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("TargetStorage"), 0, cppu::UnoType<embed::XStorage>::get(), beans::PropertyAttribute::MAYBEVOID, 0},
+ { OUString("StreamRelPath"), 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID, 0},
+ };
+}
+
+void ODatabaseDocument::impl_import_nolck_throw( const Reference< XComponentContext >& _rContext, const Reference< XInterface >& _rxTargetComponent,
+ const ::comphelper::NamedValueCollection& _rResource )
+{
+ Sequence< Any > aFilterCreationArgs;
+ Reference< XStatusIndicator > xStatusIndicator;
+ lcl_extractAndStartStatusIndicator( _rResource, xStatusIndicator, aFilterCreationArgs );
+
+ uno::Reference< beans::XPropertySet > xInfoSet( comphelper::GenericPropertySet_CreateInstance( new comphelper::PropertySetInfo( aExportInfoMap ) ) );
+ OUString sBaseURI = _rResource.getOrDefault("BaseURI", OUString());
+ if (sBaseURI.isEmpty())
+ sBaseURI = _rResource.getOrDefault("URL",OUString());
+ assert(!sBaseURI.isEmpty()); // needed for relative URLs
+ xInfoSet->setPropertyValue("BaseURI", uno::Any(sBaseURI));
+ xInfoSet->setPropertyValue("StreamName", uno::Any(OUString("content.xml")));
+
+ const sal_Int32 nCount = aFilterCreationArgs.getLength();
+ aFilterCreationArgs.realloc(nCount + 1);
+ aFilterCreationArgs.getArray()[nCount] <<= xInfoSet;
+
+ Reference< XImporter > xImporter(
+ _rContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.comp.sdb.DBFilter", aFilterCreationArgs, _rContext),
+ UNO_QUERY_THROW );
+
+ Reference< XComponent > xComponent( _rxTargetComponent, UNO_QUERY_THROW );
+ xImporter->setTargetDocument( xComponent );
+
+ Reference< XFilter > xFilter( xImporter, UNO_QUERY_THROW );
+ Sequence< PropertyValue > aFilterArgs( ODatabaseModelImpl::stripLoadArguments( _rResource ).getPropertyValues() );
+ xFilter->filter( aFilterArgs );
+
+ if ( xStatusIndicator.is() )
+ xStatusIndicator->end();
+}
+
+void SAL_CALL ODatabaseDocument::initNew( )
+{
+ // SYNCHRONIZED ->
+ DocumentGuard aGuard( *this, DocumentGuard::InitMethod );
+
+ impl_reset_nothrow();
+
+ impl_setInitializing();
+
+ // create a temporary storage
+ Reference< XStorage > xTempStor( ::comphelper::OStorageHelper::GetTemporaryStorage( m_pImpl->m_aContext ) );
+
+ // store therein
+ impl_storeToStorage_throw( xTempStor, Sequence< PropertyValue >(), aGuard );
+
+ // let the impl know we're now based on this storage
+ m_pImpl->switchToStorage( xTempStor );
+
+ // for the newly created document, allow document-wide scripting
+ m_bAllowDocumentScripting = true;
+
+ impl_setInitialized();
+
+ m_aEventNotifier.notifyDocumentEventAsync( "OnTitleChanged" );
+
+ impl_setModified_nothrow( false, aGuard );
+ // <- SYNCHRONIZED
+
+ m_aEventNotifier.notifyDocumentEvent( "OnCreate" );
+
+ impl_notifyStorageChange_nolck_nothrow( xTempStor );
+}
+
+void SAL_CALL ODatabaseDocument::load( const Sequence< PropertyValue >& Arguments )
+{
+ // SYNCHRONIZED ->
+ DocumentGuard aGuard( *this, DocumentGuard::InitMethod );
+
+ impl_reset_nothrow();
+
+ ::comphelper::NamedValueCollection aResource( Arguments );
+ if ( aResource.has( "FileName" ) && !aResource.has( "URL" ) )
+ // FileName is the compatibility name for URL, so we might have clients passing
+ // a FileName only. However, some of our code works with the URL only, so ensure
+ // we have one.
+ aResource.put( "URL", aResource.get( "FileName" ) );
+ if ( aResource.has( "URL" ) && !aResource.has( "FileName" ) )
+ // similar ... just in case there is legacy code which expects a FileName only
+ aResource.put( "FileName", aResource.get( "URL" ) );
+
+ // now that somebody (perhaps) told us a macro execution mode, remember it as
+ // ImposedMacroExecMode
+ m_pImpl->setImposedMacroExecMode(
+ aResource.getOrDefault( "MacroExecutionMode", m_pImpl->getImposedMacroExecMode() ) );
+
+ impl_setInitializing();
+ try
+ {
+ aGuard.clear();
+ impl_import_nolck_throw( m_pImpl->m_aContext, *this, aResource );
+ aGuard.reset();
+ }
+ catch( const Exception& )
+ {
+ impl_reset_nothrow();
+ throw;
+ }
+ // tell our view monitor that the document has been loaded - this way it will fire the proper
+ // event (OnLoad instead of OnCreate) later on
+ m_aViewMonitor.onLoadedDocument();
+
+ // note that we do *not* call impl_setInitialized() here: The initialization is only complete
+ // when the XModel::attachResource has been called, not sooner.
+ // however, in case of embedding, XModel::attachResource is already called.
+ if (m_bEmbedded)
+ impl_setInitialized();
+
+ impl_setModified_nothrow( false, aGuard );
+ // <- SYNCHRONIZED
+}
+
+namespace
+{
+ bool lcl_hasAnyModifiedSubComponent_throw( const Reference< XController >& i_rController )
+ {
+ Reference< css::sdb::application::XDatabaseDocumentUI > xDatabaseUI( i_rController, UNO_QUERY_THROW );
+
+ const Sequence< Reference< XComponent > > aComponents( xDatabaseUI->getSubComponents() );
+
+ bool isAnyModified = false;
+ for ( auto const & xComponent : aComponents )
+ {
+ Reference< XModifiable > xModify( xComponent, UNO_QUERY );
+ if ( xModify.is() )
+ {
+ isAnyModified = xModify->isModified();
+ continue;
+ }
+
+ // TODO: clarify: anything else to care for? Both the sub components with and without model
+ // should support the XModifiable interface, so I think nothing more is needed here.
+ OSL_FAIL( "lcl_hasAnyModifiedSubComponent_throw: anything left to do here?" );
+ }
+
+ return isAnyModified;
+ }
+}
+
+sal_Bool SAL_CALL ODatabaseDocument::wasModifiedSinceLastSave()
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ // The implementation here is somewhat sloppy, in that it returns whether *any* part of the whole
+ // database document, including opened sub components, is modified. This is more than what is requested:
+ // We need to return <TRUE/> if the doc itself, or any of the opened sub components, has been modified
+ // since the last call to any of the save* methods, or since the document has been loaded/created.
+ // However, the API definition explicitly allows to be that sloppy ...
+
+ if ( isModified() )
+ return true;
+
+ // auto recovery is an "UI feature", it is to restore the UI the user knows. Thus,
+ // we ask our connected controllers, not simply our existing form/report definitions.
+ // (There is some information which even cannot be obtained without asking the controller.
+ // For instance, newly created, but not yet saved, forms/reports are accessible via the
+ // controller only, but not via the model.)
+
+ try
+ {
+ for (auto const& controller : m_aControllers)
+ {
+ if ( lcl_hasAnyModifiedSubComponent_throw(controller) )
+ return true;
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return false;
+}
+
+void SAL_CALL ODatabaseDocument::storeToRecoveryFile( const OUString& i_TargetLocation, const Sequence< PropertyValue >& i_MediaDescriptor )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ ModifyLock aLock( *this );
+
+ try
+ {
+ // create a storage for the target location
+ Reference< XStorage > xTargetStorage( impl_createStorageFor_throw( i_TargetLocation ) );
+
+ // first store the document as a whole into this storage
+ impl_storeToStorage_throw( xTargetStorage, i_MediaDescriptor, aGuard );
+
+ // save the sub components which need saving
+ DatabaseDocumentRecovery aDocRecovery( m_pImpl->m_aContext);
+ aDocRecovery.saveModifiedSubComponents( xTargetStorage, m_aControllers );
+
+ // commit the root storage
+ tools::stor::commitStorageIfWriteable( xTargetStorage );
+ }
+ catch( const IOException& )
+ {
+ throw;
+ }
+ catch( const RuntimeException& )
+ {
+ throw;
+ }
+ catch( const WrappedTargetException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ Any aError = ::cppu::getCaughtException();
+ throw WrappedTargetException( OUString(), *this, aError );
+ }
+}
+
+void SAL_CALL ODatabaseDocument::recoverFromFile( const OUString& i_SourceLocation, const OUString& i_SalvagedFile, const Sequence< PropertyValue >& i_MediaDescriptor )
+{
+ try
+ {
+ DocumentGuard aGuard( *this, DocumentGuard::InitMethod );
+
+ if ( i_SourceLocation.isEmpty() )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+
+
+ // load the document itself, by simply delegating to our "load" method
+
+ // our load implementation expects the SalvagedFile and URL to be in the media descriptor
+ ::comphelper::NamedValueCollection aMediaDescriptor( i_MediaDescriptor );
+ aMediaDescriptor.put( "SalvagedFile", i_SalvagedFile );
+ aMediaDescriptor.put( "URL", i_SourceLocation );
+
+ aGuard.clear(); // (load has an own guarding scheme)
+ load( aMediaDescriptor.getPropertyValues() );
+ aGuard.reset();
+
+ // Without a controller, we are unable to recover the sub components, as they're always tied to a controller.
+ // So, everything else is done when the first controller is connected.
+ m_bHasBeenRecovered = true;
+
+ // tell the impl that we've been loaded from the given location
+ m_pImpl->setDocFileLocation( i_SourceLocation );
+
+ // by definition (of XDocumentRecovery), we're responsible for delivering a fully-initialized document,
+ // which includes an attachResource call.
+ const OUString sLogicalDocumentURL( i_SalvagedFile.isEmpty() ? i_SourceLocation : i_SalvagedFile );
+ impl_attachResource( sLogicalDocumentURL, aMediaDescriptor.getPropertyValues(), aGuard );
+ // <- SYNCHRONIZED
+ }
+ catch( const IOException& )
+ {
+ throw;
+ }
+ catch( const RuntimeException& )
+ {
+ throw;
+ }
+ catch( const WrappedTargetException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ Any aError = ::cppu::getCaughtException();
+ throw WrappedTargetException( OUString(), *this, aError );
+ }
+}
+
+// XModel
+sal_Bool SAL_CALL ODatabaseDocument::attachResource( const OUString& _rURL, const Sequence< PropertyValue >& _rArguments )
+{
+ if (_rURL.isEmpty() && _rArguments.getLength() == 1 && _rArguments[0].Name == "SetEmbedded")
+ {
+ m_bEmbedded = true;
+ return true;
+ }
+
+ DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit );
+ bool bRet = false;
+ try
+ {
+ bRet = impl_attachResource( _rURL, _rArguments, aGuard );
+ }
+ catch( const RuntimeException& )
+ {
+ throw;
+ }
+ catch( const Exception& )
+ {
+ Any aError = ::cppu::getCaughtException();
+ throw WrappedTargetRuntimeException( OUString(), *this, aError );
+ }
+ return bRet;
+}
+
+bool ODatabaseDocument::impl_attachResource( const OUString& i_rLogicalDocumentURL,
+ const Sequence< PropertyValue >& i_rMediaDescriptor, DocumentGuard& _rDocGuard )
+{
+ if (i_rLogicalDocumentURL == getURL())
+ {
+ ::comphelper::NamedValueCollection aArgs(i_rMediaDescriptor);
+
+ // this misuse of attachresource is a hack of the Basic importer code
+ // repurposing existing interfaces for uses it probably wasn't intended
+ // for
+
+ // we do not support macro signatures, so we can ignore that request
+ aArgs.remove("BreakMacroSignature");
+
+ bool bMacroEventRead = false;
+ if ((aArgs.get( "MacroEventRead" ) >>= bMacroEventRead) && bMacroEventRead)
+ m_pImpl->m_bMacroCallsSeenWhileLoading = true;
+ aArgs.remove( "MacroEventRead" );
+
+ if (aArgs.empty())
+ return false;
+ }
+
+ // if no URL has been provided, the caller was lazy enough to not call our getURL - which is not allowed anymore,
+ // now since getURL and getLocation both return the same, so calling one of those should be simple.
+ OUString sDocumentURL( i_rLogicalDocumentURL );
+ OSL_ENSURE( !sDocumentURL.isEmpty(), "ODatabaseDocument::impl_attachResource: invalid URL!" );
+ if ( sDocumentURL.isEmpty() )
+ sDocumentURL = getURL();
+
+ m_pImpl->setResource( sDocumentURL, i_rMediaDescriptor );
+
+ if ( impl_isInitializing() )
+ { // this means we've just been loaded, and this is the attachResource call which follows
+ // the load call.
+ impl_setInitialized();
+
+ // determine whether the document as a whole, or sub documents, have macros. Especially the latter
+ // controls the availability of our XEmbeddedScripts and XScriptInvocationContext interfaces, and we
+ // should know this before anybody actually uses the object.
+ m_bAllowDocumentScripting = ( m_pImpl->determineEmbeddedMacros() != ODatabaseModelImpl::eSubDocumentMacros );
+
+ _rDocGuard.clear();
+ // <- SYNCHRONIZED
+ m_aEventNotifier.notifyDocumentEvent( "OnLoadFinished" );
+ }
+
+ return true;
+}
+
+OUString SAL_CALL ODatabaseDocument::getURL( )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit );
+ return m_pImpl->getURL();
+}
+
+Sequence< PropertyValue > SAL_CALL ODatabaseDocument::getArgs( )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit );
+ return m_pImpl->getMediaDescriptor().getPropertyValues();
+}
+
+Sequence< PropertyValue > SAL_CALL ODatabaseDocument::getArgs2( const ::css::uno::Sequence< ::rtl::OUString >& requestedArgs )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit );
+ std::vector<PropertyValue> aRet;
+ for (const auto & rArgName : requestedArgs)
+ aRet.push_back(PropertyValue(rArgName, 0, m_pImpl->getMediaDescriptor().get(rArgName), PropertyState_DIRECT_VALUE));
+ return comphelper::containerToSequence(aRet);
+}
+
+void SAL_CALL ODatabaseDocument::setArgs(const Sequence<beans::PropertyValue>& /* aArgs */)
+{
+ throw NoSupportException();
+}
+
+void SAL_CALL ODatabaseDocument::connectController( const Reference< XController >& _xController )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+#if OSL_DEBUG_LEVEL > 0
+ for (auto const& controller : m_aControllers)
+ {
+ OSL_ENSURE( controller != _xController, "ODatabaseDocument::connectController: this controller is already connected!" );
+ }
+#endif
+
+ m_aControllers.push_back( _xController );
+
+ m_aEventNotifier.notifyDocumentEventAsync( "OnViewCreated", Reference< XController2 >( _xController, UNO_QUERY ) );
+
+ bool bFirstControllerEver = m_aViewMonitor.onControllerConnected( _xController );
+ if ( !bFirstControllerEver )
+ return;
+
+ // check/adjust our macro mode.
+ m_pImpl->checkMacrosOnLoading();
+}
+
+void SAL_CALL ODatabaseDocument::disconnectController( const Reference< XController >& _xController )
+{
+ bool bNotifyViewClosed = false;
+ bool bLastControllerGone = false;
+ bool bIsClosing = false;
+
+ // SYNCHRONIZED ->
+ {
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ Controllers::iterator pos = std::find( m_aControllers.begin(), m_aControllers.end(), _xController );
+ OSL_ENSURE( pos != m_aControllers.end(), "ODatabaseDocument::disconnectController: don't know this controller!" );
+ if ( pos != m_aControllers.end() )
+ {
+ m_aControllers.erase( pos );
+ bNotifyViewClosed = true;
+ }
+
+ if ( m_xCurrentController == _xController )
+ m_xCurrentController = nullptr;
+
+ bLastControllerGone = m_aControllers.empty();
+ bIsClosing = m_bClosing;
+ }
+ // <- SYNCHRONIZED
+
+ if ( bNotifyViewClosed )
+ m_aEventNotifier.notifyDocumentEvent( "OnViewClosed", Reference< XController2 >( _xController, UNO_QUERY ) );
+
+ if ( !bLastControllerGone || bIsClosing )
+ return;
+
+ // if this was the last view, close the document as a whole
+ // #i51157#
+ try
+ {
+ close( true );
+ }
+ catch( const CloseVetoException& )
+ {
+ // okay, somebody vetoed and took ownership
+ }
+}
+
+void SAL_CALL ODatabaseDocument::lockControllers( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ ++m_pImpl->m_nControllerLockCount;
+}
+
+void SAL_CALL ODatabaseDocument::unlockControllers( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ --m_pImpl->m_nControllerLockCount;
+}
+
+sal_Bool SAL_CALL ODatabaseDocument::hasControllersLocked( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ return m_pImpl->m_nControllerLockCount != 0;
+}
+
+Reference< XController > SAL_CALL ODatabaseDocument::getCurrentController()
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ return m_xCurrentController.is() ? m_xCurrentController : ( m_aControllers.empty() ? Reference< XController >() : *m_aControllers.begin() );
+}
+
+void SAL_CALL ODatabaseDocument::setCurrentController( const Reference< XController >& _xController )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ m_xCurrentController = _xController;
+
+ if ( !m_aViewMonitor.onSetCurrentController( _xController ) )
+ return;
+
+ // check if there are sub components to recover from our document storage
+ bool bAttemptRecovery = m_bHasBeenRecovered;
+ if ( !bAttemptRecovery && m_pImpl->getMediaDescriptor().has( "ForceRecovery" ) )
+ // do not use getOrDefault, it will throw for invalid types, which is not desired here
+ m_pImpl->getMediaDescriptor().get( "ForceRecovery" ) >>= bAttemptRecovery;
+
+ if ( !bAttemptRecovery )
+ return;
+
+ try
+ {
+ DatabaseDocumentRecovery aDocRecovery( m_pImpl->m_aContext );
+ aDocRecovery.recoverSubDocuments( m_pImpl->getRootStorage(), _xController );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+Reference< XInterface > SAL_CALL ODatabaseDocument::getCurrentSelection( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ Reference< XInterface > xRet;
+ Reference< XSelectionSupplier > xDocView( getCurrentController(), UNO_QUERY );
+ if ( xDocView.is() )
+ xRet.set(xDocView->getSelection(),UNO_QUERY);
+
+ return xRet;
+}
+
+// XStorable
+sal_Bool SAL_CALL ODatabaseDocument::hasLocation( )
+{
+ return !getLocation().isEmpty();
+}
+
+OUString SAL_CALL ODatabaseDocument::getLocation( )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit );
+ return m_pImpl->getURL();
+ // both XStorable::getLocation and XModel::getURL have to return the URL of the document, *not*
+ // the location of the file which the document was possibly recovered from (which would be getDocFileLocation)
+}
+
+sal_Bool SAL_CALL ODatabaseDocument::isReadonly( )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit );
+ return m_pImpl->m_bDocumentReadOnly;
+}
+
+void SAL_CALL ODatabaseDocument::store( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ OUString sDocumentURL( m_pImpl->getURL() );
+ if ( !sDocumentURL.isEmpty() )
+ {
+ if ( m_pImpl->getDocFileLocation() == m_pImpl->getURL() )
+ if ( m_pImpl->m_bDocumentReadOnly )
+ throw IOException();
+
+ impl_storeAs_throw( m_pImpl->getURL(), m_pImpl->getMediaDescriptor(), SAVE, aGuard );
+ return;
+ }
+
+ // if we have no URL, but did survive the DocumentGuard above, then we've been inited via XLoadable::initNew,
+ // i.e. we're based on a temporary storage
+ OSL_ENSURE( m_pImpl->getDocFileLocation().isEmpty(), "ODatabaseDocument::store: unexpected URL inconsistency!" );
+
+ try
+ {
+ impl_storeToStorage_throw( m_pImpl->getRootStorage(), m_pImpl->getMediaDescriptor().getPropertyValues(), aGuard );
+ }
+ catch( const Exception& )
+ {
+ Any aError = ::cppu::getCaughtException();
+ if ( aError.isExtractableTo( ::cppu::UnoType< IOException >::get() )
+ || aError.isExtractableTo( ::cppu::UnoType< RuntimeException >::get() )
+ )
+ {
+ // allowed to leave
+ throw;
+ }
+ impl_throwIOExceptionCausedBySave_throw( aError, {} );
+ }
+}
+
+void ODatabaseDocument::impl_throwIOExceptionCausedBySave_throw( const Any& i_rError, std::u16string_view i_rTargetURL ) const
+{
+ OUString sErrorMessage = extractExceptionMessage( m_pImpl->m_aContext, i_rError );
+ sErrorMessage = ResourceManager::loadString(
+ RID_STR_ERROR_WHILE_SAVING,
+ "$location$", i_rTargetURL,
+ "$message$", sErrorMessage
+ );
+ throw IOException( sErrorMessage, *const_cast< ODatabaseDocument* >( this ) );
+}
+
+void ODatabaseDocument::impl_storeAs_throw( const OUString& _rURL, const ::comphelper::NamedValueCollection& _rArguments,
+ const StoreType _eType, DocumentGuard& _rGuard )
+{
+ OSL_PRECOND( ( _eType == SAVE ) || ( _eType == SAVE_AS ),
+ "ODatabaseDocument::impl_storeAs_throw: you introduced a new type which cannot be handled here!" );
+
+ // if we're in the process of initializing the document (which effectively means it is an implicit
+ // initialization triggered in storeAsURL), the we do not notify events, since to an observer, the SaveAs
+ // should not be noticeable
+ bool bIsInitializationProcess = impl_isInitializing();
+
+ if ( !bIsInitializationProcess )
+ {
+ _rGuard.clear();
+ m_aEventNotifier.notifyDocumentEvent( _eType == SAVE ? "OnSave" : "OnSaveAs", nullptr, Any( _rURL ) );
+ _rGuard.reset();
+ }
+
+ Reference< XStorage > xNewRootStorage;
+ // will be non-NULL if our storage changed
+
+ try
+ {
+ ModifyLock aLock( *this );
+ // ignore all changes of our "modified" state during storing
+
+ bool bLocationChanged = ( _rURL != m_pImpl->getDocFileLocation() );
+ if ( bLocationChanged )
+ {
+ // create storage for target URL
+ uno::Reference<embed::XStorage> xTargetStorage(
+ impl_GetStorageOrCreateFor_throw(_rArguments, _rURL));
+
+ if ( m_pImpl->isEmbeddedDatabase() )
+ m_pImpl->clearConnections();
+
+ // commit everything
+ m_pImpl->commitEmbeddedStorage();
+ m_pImpl->commitStorages();
+
+ // copy own storage to target storage
+ Reference< XStorage > xCurrentStorage( m_pImpl->getRootStorage() );
+ if ( xCurrentStorage.is() )
+ xCurrentStorage->copyToStorage( xTargetStorage );
+
+ m_pImpl->disposeStorages();
+
+ // each and every document definition obtained via m_xForms and m_xReports depends
+ // on the sub storages which we just disposed. So, dispose the forms/reports collections, too.
+ // This ensures that they're re-created when needed.
+ clearObjectContainer( m_xForms );
+ clearObjectContainer( m_xReports );
+
+ xNewRootStorage = m_pImpl->switchToStorage( xTargetStorage );
+
+ m_pImpl->m_bDocumentReadOnly = false;
+ }
+
+ // store to current storage
+ Reference< XStorage > xCurrentStorage( m_pImpl->getOrCreateRootStorage(), UNO_SET_THROW );
+ Sequence< PropertyValue > aMediaDescriptor( lcl_appendFileNameToDescriptor( _rArguments, _rURL ) );
+ impl_storeToStorage_throw( xCurrentStorage, aMediaDescriptor, _rGuard );
+
+ // success - tell our impl
+ m_pImpl->setDocFileLocation( _rURL );
+ m_pImpl->setResource( _rURL, aMediaDescriptor );
+
+ // if we are in an initialization process, then this is finished, now that we stored the document
+ if ( bIsInitializationProcess )
+ impl_setInitialized();
+ }
+ catch( const IOException& )
+ {
+ if ( !bIsInitializationProcess )
+ m_aEventNotifier.notifyDocumentEventAsync( _eType == SAVE ? "OnSaveFailed" : "OnSaveAsFailed", nullptr, Any( _rURL ) );
+ throw;
+ }
+ catch( const RuntimeException& )
+ {
+ if ( !bIsInitializationProcess )
+ m_aEventNotifier.notifyDocumentEventAsync( _eType == SAVE ? "OnSaveFailed" : "OnSaveAsFailed", nullptr, Any( _rURL ) );
+ throw;
+ }
+ catch( const Exception& )
+ {
+ Any aError = ::cppu::getCaughtException();
+
+ // notify the failure
+ if ( !bIsInitializationProcess )
+ m_aEventNotifier.notifyDocumentEventAsync( _eType == SAVE ? "OnSaveFailed" : "OnSaveAsFailed", nullptr, Any( _rURL ) );
+
+ impl_throwIOExceptionCausedBySave_throw( aError, _rURL );
+ }
+
+ // notify the document event
+ if ( !bIsInitializationProcess )
+ m_aEventNotifier.notifyDocumentEventAsync( _eType == SAVE ? "OnSaveDone" : "OnSaveAsDone", nullptr, Any( _rURL ) );
+
+ // reset our "modified" flag, and clear the guard
+ impl_setModified_nothrow( false, _rGuard );
+ // <- SYNCHRONIZED
+
+ // notify storage listeners
+ if ( xNewRootStorage.is() )
+ impl_notifyStorageChange_nolck_nothrow( xNewRootStorage );
+}
+
+Reference< XStorage > ODatabaseDocument::impl_createStorageFor_throw( const OUString& _rURL ) const
+{
+ Reference< ucb::XSimpleFileAccess3 > xTempAccess(ucb::SimpleFileAccess::create(m_pImpl->m_aContext));
+ Reference< io::XStream > xStream = xTempAccess->openFileReadWrite( _rURL );
+ Reference< io::XTruncate > xTruncate(xStream,UNO_QUERY);
+ if ( xTruncate.is() )
+ {
+ xTruncate->truncate();
+ }
+ Sequence<Any> aParam{ Any(xStream), Any(ElementModes::READWRITE | ElementModes::TRUNCATE) };
+
+ Reference< XSingleServiceFactory > xStorageFactory( m_pImpl->createStorageFactory(), UNO_SET_THROW );
+ return Reference< XStorage >( xStorageFactory->createInstanceWithArguments( aParam ), UNO_QUERY_THROW );
+}
+
+css::uno::Reference<css::embed::XStorage> ODatabaseDocument::impl_GetStorageOrCreateFor_throw(
+ const ::comphelper::NamedValueCollection& _rArguments, const OUString& _rURL) const
+{
+ // Try to get the storage from arguments, then create storage for target URL
+ uno::Reference<embed::XStorage> xTargetStorage;
+ _rArguments.get("TargetStorage") >>= xTargetStorage;
+ if (!xTargetStorage.is())
+ xTargetStorage = impl_createStorageFor_throw(_rURL);
+
+ // In case we got a StreamRelPath, then xTargetStorage should reference that sub-storage.
+ OUString sStreamRelPath = _rArguments.getOrDefault("StreamRelPath", OUString());
+ if (!sStreamRelPath.isEmpty())
+ xTargetStorage
+ = xTargetStorage->openStorageElement(sStreamRelPath, embed::ElementModes::READWRITE);
+
+ return xTargetStorage;
+}
+
+void SAL_CALL ODatabaseDocument::storeAsURL( const OUString& _rURL, const Sequence< PropertyValue >& _rArguments )
+{
+ // SYNCHRONIZED ->
+ DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit );
+
+ // Normally, a document initialization is done via XLoadable::load or XLoadable::initNew. For convenience
+ // reasons, and to not break existing API clients, it's allowed to call storeAsURL without having initialized
+ // the document, in which case the initialization will be done implicitly.
+ bool bImplicitInitialization = !impl_isInitialized();
+ // implicit initialization while another initialization is just running is not possible
+ if ( bImplicitInitialization && impl_isInitializing() )
+ throw RuntimeException();
+
+ if ( bImplicitInitialization )
+ impl_setInitializing();
+
+ try
+ {
+ impl_storeAs_throw( _rURL, _rArguments, SAVE_AS, aGuard );
+ // <- SYNCHRONIZED
+
+ // impl_storeAs_throw cleared the lock on our mutex, but the below lines need this lock
+ // SYNCHRONIZED ->
+ aGuard.reset();
+
+ // our title might have changed, potentially at least
+ // Sadly, we cannot check this: Calling getTitle here and now would not deliver
+ // an up-to-date result, as the call is delegated to our TitleHelper instance, which itself
+ // updates its title only if it gets the OnSaveAsDone event (which was sent asynchronously
+ // by impl_storeAs_throw). So, we simply notify always, and also asynchronously
+ m_aEventNotifier.notifyDocumentEventAsync( "OnTitleChanged" );
+ }
+ catch( const Exception& )
+ {
+ impl_reset_nothrow();
+ throw;
+ }
+
+ if ( bImplicitInitialization )
+ m_bAllowDocumentScripting = true;
+
+ aGuard.clear();
+ // <- SYNCHRONIZED
+
+ if ( bImplicitInitialization )
+ m_aEventNotifier.notifyDocumentEvent( "OnCreate" );
+}
+
+void ODatabaseDocument::impl_storeToStorage_throw( const Reference< XStorage >& _rxTargetStorage, const Sequence< PropertyValue >& _rMediaDescriptor,
+ DocumentGuard& _rDocGuard ) const
+{
+ if ( !_rxTargetStorage.is() )
+ throw IllegalArgumentException( OUString(), *const_cast< ODatabaseDocument* >( this ), 1 );
+
+ if ( !m_pImpl.is() )
+ throw DisposedException( OUString(), *const_cast< ODatabaseDocument* >( this ) );
+
+ try
+ {
+ // commit everything
+ m_pImpl->commitEmbeddedStorage();
+ m_pImpl->commitStorages();
+
+ // copy own storage to target storage
+ if ( impl_isInitialized() )
+ {
+ Reference< XStorage > xCurrentStorage = m_pImpl->getOrCreateRootStorage();
+ // Root storage may be empty in case of embedding.
+ if ( xCurrentStorage.is() && xCurrentStorage != _rxTargetStorage )
+ xCurrentStorage->copyToStorage( _rxTargetStorage );
+ }
+
+ // write into target storage
+ ::comphelper::NamedValueCollection aWriteArgs( _rMediaDescriptor );
+ lcl_triggerStatusIndicator_throw( aWriteArgs, _rDocGuard, true );
+ impl_writeStorage_throw( _rxTargetStorage, aWriteArgs );
+ lcl_triggerStatusIndicator_throw( aWriteArgs, _rDocGuard, false );
+
+ // commit target storage
+ m_pImpl->commitStorageIfWriteable_ignoreErrors(_rxTargetStorage);
+ }
+ catch( const IOException& ) { throw; }
+ catch( const RuntimeException& ) { throw; }
+ catch ( const Exception& e )
+ {
+ throw IOException( e.Message, *const_cast< ODatabaseDocument* >( this ) );
+ }
+}
+
+void SAL_CALL ODatabaseDocument::storeToURL( const OUString& _rURL, const Sequence< PropertyValue >& _rArguments )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ ModifyLock aLock( *this );
+
+ {
+ aGuard.clear();
+ m_aEventNotifier.notifyDocumentEvent( "OnSaveTo", nullptr, Any( _rURL ) );
+ aGuard.reset();
+ }
+
+ try
+ {
+ const ::comphelper::NamedValueCollection aArguments(_rArguments);
+ // create storage for target URL
+ Reference<XStorage> xTargetStorage(impl_GetStorageOrCreateFor_throw(aArguments, _rURL));
+
+ // extend media descriptor with URL
+ Sequence<PropertyValue> aMediaDescriptor(lcl_appendFileNameToDescriptor(aArguments, _rURL));
+
+ // store to this storage
+ impl_storeToStorage_throw( xTargetStorage, aMediaDescriptor, aGuard );
+ }
+ catch( const Exception& )
+ {
+ Any aError = ::cppu::getCaughtException();
+ m_aEventNotifier.notifyDocumentEventAsync( "OnSaveToFailed", nullptr, aError );
+
+ if ( aError.isExtractableTo( ::cppu::UnoType< IOException >::get() )
+ || aError.isExtractableTo( ::cppu::UnoType< RuntimeException >::get() )
+ )
+ {
+ // allowed to leave
+ throw;
+ }
+
+ impl_throwIOExceptionCausedBySave_throw( aError, _rURL );
+ }
+
+ m_aEventNotifier.notifyDocumentEventAsync( "OnSaveToDone", nullptr, Any( _rURL ) );
+}
+
+// XModifyBroadcaster
+void SAL_CALL ODatabaseDocument::addModifyListener( const Reference< XModifyListener >& _xListener )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ m_aModifyListeners.addInterface(_xListener);
+}
+
+void SAL_CALL ODatabaseDocument::removeModifyListener( const Reference< XModifyListener >& _xListener )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ m_aModifyListeners.removeInterface(_xListener);
+}
+
+// XModifiable
+sal_Bool SAL_CALL ODatabaseDocument::isModified( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ return m_pImpl->m_bModified;
+}
+
+void SAL_CALL ODatabaseDocument::setModified( sal_Bool _bModified )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit );
+ if ( impl_isInitialized() )
+ impl_setModified_nothrow( _bModified, aGuard );
+ // it's allowed to call setModified without the document being initialized already. In this case,
+ // we simply ignore the call - when the initialization is finished, the respective code will set
+ // a proper "modified" flag
+}
+
+void ODatabaseDocument::impl_setModified_nothrow( bool _bModified, DocumentGuard& _rGuard )
+{
+ // SYNCHRONIZED ->
+ bool bModifiedChanged = ( m_pImpl->m_bModified != _bModified ) && ( !m_pImpl->isModifyLocked() );
+
+ if ( bModifiedChanged )
+ {
+ m_pImpl->m_bModified = _bModified;
+ m_aEventNotifier.notifyDocumentEventAsync( "OnModifyChanged" );
+ }
+ _rGuard.clear();
+ // <- SYNCHRONIZED
+
+ if ( bModifiedChanged )
+ {
+ lang::EventObject aEvent( *this );
+ m_aModifyListeners.notifyEach( &XModifyListener::modified, aEvent );
+ }
+}
+
+// css::document::XEventBroadcaster
+void SAL_CALL ODatabaseDocument::addEventListener(const uno::Reference< document::XEventListener >& Listener )
+{
+ m_aEventNotifier.addLegacyEventListener( Listener );
+}
+
+void SAL_CALL ODatabaseDocument::removeEventListener( const uno::Reference< document::XEventListener >& Listener )
+{
+ m_aEventNotifier.removeLegacyEventListener( Listener );
+}
+
+void SAL_CALL ODatabaseDocument::addDocumentEventListener( const Reference< XDocumentEventListener >& Listener )
+{
+ m_aEventNotifier.addDocumentEventListener( Listener );
+}
+
+void SAL_CALL ODatabaseDocument::removeDocumentEventListener( const Reference< XDocumentEventListener >& Listener )
+{
+ m_aEventNotifier.removeDocumentEventListener( Listener );
+}
+
+void SAL_CALL ODatabaseDocument::notifyDocumentEvent( const OUString& EventName, const Reference< XController2 >& ViewController, const Any& Supplement )
+{
+ if ( EventName.isEmpty() )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+
+ // SYNCHRONIZED ->
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ if ( !DocumentEvents::needsSynchronousNotification( EventName ) )
+ {
+ m_aEventNotifier.notifyDocumentEventAsync( EventName, ViewController, Supplement );
+ return;
+ }
+ aGuard.clear();
+ // <- SYNCHRONIZED
+
+ m_aEventNotifier.notifyDocumentEvent( EventName, ViewController, Supplement );
+}
+
+Sequence< PropertyValue > SAL_CALL ODatabaseDocument::getPrinter( )
+{
+ OSL_FAIL( "ODatabaseDocument::getPrinter: not supported!" );
+ return Sequence< PropertyValue >();
+}
+
+void SAL_CALL ODatabaseDocument::setPrinter( const Sequence< PropertyValue >& /*aPrinter*/ )
+{
+ OSL_FAIL( "ODatabaseDocument::setPrinter: not supported!" );
+}
+
+void SAL_CALL ODatabaseDocument::print( const Sequence< PropertyValue >& /*xOptions*/ )
+{
+ OSL_FAIL( "ODatabaseDocument::print: not supported!" );
+}
+
+void ODatabaseDocument::impl_reparent_nothrow( const WeakReference< XNameAccess >& _rxContainer )
+{
+ Reference< XChild > xChild( _rxContainer.get(), UNO_QUERY );
+ if ( xChild.is() )
+ xChild->setParent( *this );
+}
+
+void ODatabaseDocument::clearObjectContainer( WeakReference< XNameAccess >& _rxContainer)
+{
+ Reference< XNameAccess > xContainer = _rxContainer;
+ ::comphelper::disposeComponent( xContainer );
+
+ Reference< XChild > xChild( _rxContainer.get(),UNO_QUERY );
+ if ( xChild.is() )
+ xChild->setParent( nullptr );
+ _rxContainer.clear();
+}
+
+Reference< XNameAccess > ODatabaseDocument::impl_getDocumentContainer_throw( ODatabaseModelImpl::ObjectType _eType )
+{
+ if ( ( _eType != ODatabaseModelImpl::E_FORM ) && ( _eType != ODatabaseModelImpl::E_REPORT ) )
+ throw IllegalArgumentException();
+
+ bool bFormsContainer = _eType == ODatabaseModelImpl::E_FORM;
+
+ WeakReference< XNameAccess >& rContainerRef( bFormsContainer ? m_xForms : m_xReports );
+ Reference< XNameAccess > xContainer = rContainerRef;
+ if ( !xContainer.is() )
+ {
+ Any aValue;
+ css::uno::Reference< css::uno::XInterface > xMy(*this);
+ if ( dbtools::getDataSourceSetting(xMy,bFormsContainer ? "Forms" : "Reports",aValue) )
+ {
+ OUString sSupportService;
+ aValue >>= sSupportService;
+ if ( !sSupportService.isEmpty() )
+ {
+ Sequence<Any> aArgs{ Any(NamedValue("DatabaseDocument",Any(xMy))) };
+ xContainer.set(
+ m_pImpl->m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext(sSupportService, aArgs, m_pImpl->m_aContext),
+ UNO_QUERY);
+ rContainerRef = xContainer;
+ }
+ }
+ if ( !xContainer.is() )
+ {
+ TContentPtr& rContainerData( m_pImpl->getObjectContainer( _eType ) );
+ rContainerRef = xContainer = new ODocumentContainer( m_pImpl->m_aContext, *this, rContainerData, bFormsContainer );
+ }
+ impl_reparent_nothrow( xContainer );
+ }
+ return xContainer;
+}
+
+void ODatabaseDocument::impl_closeControllerFrames_nolck_throw( bool _bDeliverOwnership )
+{
+ Controllers aCopy = m_aControllers;
+
+ for (auto const& elem : aCopy)
+ {
+ if ( !elem.is() )
+ continue;
+
+ try
+ {
+ Reference< XCloseable> xFrame( elem->getFrame(), UNO_QUERY );
+ if ( xFrame.is() )
+ xFrame->close( _bDeliverOwnership );
+ }
+ catch( const CloseVetoException& ) { throw; }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+}
+
+void ODatabaseDocument::impl_disposeControllerFrames_nothrow()
+{
+ Controllers aCopy;
+ aCopy.swap( m_aControllers ); // ensure m_aControllers is empty afterwards
+ for( const auto& rController : aCopy )
+ {
+ try
+ {
+ if( rController.is() )
+ {
+ Reference< XFrame > xFrame( rController->getFrame() );
+ ::comphelper::disposeComponent( xFrame );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+}
+
+void SAL_CALL ODatabaseDocument::close(sal_Bool bDeliverOwnership)
+{
+ // nearly everything below can/must be done without our mutex locked, the below is just for
+ // the checks for being disposed and the like
+ // SYNCHRONIZED ->
+ {
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ assert (!m_bClosing);
+ m_bClosing = true;
+ }
+ // <- SYNCHRONIZED
+
+ try
+ {
+ // allow listeners to veto
+ lang::EventObject aEvent( *this );
+ m_aCloseListener.forEach(
+ [&aEvent, &bDeliverOwnership] (uno::Reference<XCloseListener> const& xListener) {
+ return xListener->queryClosing(aEvent, bDeliverOwnership);
+ });
+
+ // notify that we're going to unload
+ m_aEventNotifier.notifyDocumentEvent( "OnPrepareUnload" );
+
+ impl_closeControllerFrames_nolck_throw( bDeliverOwnership );
+
+ m_aCloseListener.notifyEach( &XCloseListener::notifyClosing, const_cast<const lang::EventObject&>(aEvent) );
+
+ dispose();
+ }
+ catch ( const Exception& )
+ {
+ SolarMutexGuard g;
+ m_bClosing = false;
+ throw;
+ }
+
+ // SYNCHRONIZED ->
+ SolarMutexGuard g;
+ m_bClosing = false;
+ // <- SYNCHRONIZED
+}
+
+void SAL_CALL ODatabaseDocument::addCloseListener( const Reference< css::util::XCloseListener >& Listener )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ m_aCloseListener.addInterface(Listener);
+}
+
+void SAL_CALL ODatabaseDocument::removeCloseListener( const Reference< css::util::XCloseListener >& Listener )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ m_aCloseListener.removeInterface(Listener);
+}
+
+Reference< XNameAccess > SAL_CALL ODatabaseDocument::getFormDocuments( )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit );
+ return impl_getDocumentContainer_throw( ODatabaseModelImpl::E_FORM );
+}
+
+Reference< XNameAccess > SAL_CALL ODatabaseDocument::getReportDocuments( )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit );
+ return impl_getDocumentContainer_throw( ODatabaseModelImpl::E_REPORT );
+}
+
+void ODatabaseDocument::WriteThroughComponent( const Reference< XComponent >& xComponent, const char* pStreamName,
+ const char* pServiceName, const Sequence< Any >& _rArguments, const Sequence< PropertyValue >& rMediaDesc,
+ const Reference<XStorage>& _xStorageToSaveTo ) const
+{
+ OSL_ENSURE( pStreamName, "Need stream name!" );
+ OSL_ENSURE( pServiceName, "Need service name!" );
+
+ // open stream
+ OUString sStreamName = OUString::createFromAscii( pStreamName );
+ Reference< XStream > xStream = _xStorageToSaveTo->openStreamElement( sStreamName, ElementModes::READWRITE | ElementModes::TRUNCATE );
+ if ( !xStream.is() )
+ return;
+
+ Reference< XOutputStream > xOutputStream( xStream->getOutputStream() );
+ OSL_ENSURE( xOutputStream.is(), "Can't create output stream in package!" );
+ if ( !xOutputStream.is() )
+ return;
+
+ Reference< XSeekable > xSeek( xOutputStream, UNO_QUERY );
+ if ( xSeek.is() )
+ xSeek->seek(0);
+
+ Reference< XPropertySet > xStreamProp( xOutputStream, UNO_QUERY_THROW );
+ xStreamProp->setPropertyValue( INFO_MEDIATYPE, Any( OUString( "text/xml" ) ) );
+ xStreamProp->setPropertyValue( "Compressed", Any( true ) );
+
+ // write the stuff
+ WriteThroughComponent( xOutputStream, xComponent, pServiceName, _rArguments, rMediaDesc );
+}
+
+void ODatabaseDocument::WriteThroughComponent( const Reference< XOutputStream >& xOutputStream,
+ const Reference< XComponent >& xComponent, const char* pServiceName, const Sequence< Any >& _rArguments,
+ const Sequence< PropertyValue >& rMediaDesc ) const
+{
+ OSL_ENSURE( xOutputStream.is(), "I really need an output stream!" );
+ OSL_ENSURE( xComponent.is(), "Need component!" );
+ OSL_ENSURE( nullptr != pServiceName, "Need component name!" );
+
+ // get component
+ Reference< XWriter > xSaxWriter = xml::sax::Writer::create( m_pImpl->m_aContext );
+
+ // connect XML writer to output stream
+ xSaxWriter->setOutputStream( xOutputStream );
+
+ // prepare arguments (prepend doc handler to given arguments)
+ Sequence<Any> aArgs( 1 + _rArguments.getLength() );
+ auto pArgs = aArgs.getArray();
+ pArgs[0] <<= xSaxWriter;
+ for ( sal_Int32 i = 0; i < _rArguments.getLength(); ++i )
+ pArgs[ i+1 ] = _rArguments[i];
+
+ // get filter component
+ Reference< XExporter > xExporter( m_pImpl->m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext(OUString::createFromAscii(pServiceName), aArgs, m_pImpl->m_aContext), UNO_QUERY_THROW );
+
+ // connect model and filter
+ xExporter->setSourceDocument( xComponent );
+
+ // filter
+ Reference< XFilter > xFilter( xExporter, UNO_QUERY_THROW );
+ xFilter->filter( rMediaDesc );
+}
+
+void ODatabaseDocument::impl_writeStorage_throw( const Reference< XStorage >& _rxTargetStorage, const ::comphelper::NamedValueCollection& _rMediaDescriptor ) const
+{
+ // extract status indicator
+ Sequence< Any > aDelegatorArguments;
+ lcl_extractStatusIndicator( _rMediaDescriptor, aDelegatorArguments );
+
+ uno::Reference< beans::XPropertySet > xInfoSet( comphelper::GenericPropertySet_CreateInstance( new comphelper::PropertySetInfo( aExportInfoMap ) ) );
+
+ xInfoSet->setPropertyValue("UsePrettyPrinting", uno::Any(officecfg::Office::Common::Save::Document::PrettyPrinting::get()));
+ if ( officecfg::Office::Common::Save::URL::FileSystem::get() )
+ {
+ OUString sBaseURI = _rMediaDescriptor.getOrDefault("BaseURI", OUString());
+ if (sBaseURI.isEmpty())
+ sBaseURI = _rMediaDescriptor.getOrDefault("URL",OUString());
+ xInfoSet->setPropertyValue("BaseURI", uno::Any(sBaseURI));
+ }
+
+ // Set TargetStorage, so it doesn't have to be re-constructed based on possibly empty URL.
+ xInfoSet->setPropertyValue("TargetStorage", uno::Any(m_pImpl->getRootStorage()));
+
+ // Set StreamRelPath, in case this document is an embedded one.
+ OUString sStreamRelPath;
+ OUString sURL = _rMediaDescriptor.getOrDefault("URL", OUString());
+ if (sURL.startsWithIgnoreAsciiCase("vnd.sun.star.pkg:"))
+ {
+ // In this case the host contains the real path, and the path is the embedded stream name.
+ INetURLObject aURL(sURL);
+ sStreamRelPath = aURL.GetURLPath(INetURLObject::DecodeMechanism::WithCharset);
+ if (sStreamRelPath.startsWith("/"))
+ sStreamRelPath = sStreamRelPath.copy(1);
+ }
+ if (!sStreamRelPath.isEmpty())
+ xInfoSet->setPropertyValue("StreamRelPath", uno::Any(sStreamRelPath));
+
+ sal_Int32 nArgsLen = aDelegatorArguments.getLength();
+ aDelegatorArguments.realloc(nArgsLen+1);
+ aDelegatorArguments.getArray()[nArgsLen++] <<= xInfoSet;
+
+ Reference< XPropertySet > xProp( _rxTargetStorage, UNO_QUERY_THROW );
+ xProp->setPropertyValue( INFO_MEDIATYPE, Any( OUString(MIMETYPE_OASIS_OPENDOCUMENT_DATABASE_ASCII) ) );
+
+ OUString aVersion;
+ SvtSaveOptions::ODFSaneDefaultVersion const nDefVersion =
+ GetODFSaneDefaultVersion();
+ // older versions can not have this property set,
+ // it exists only starting from ODF1.2
+ if (nDefVersion >= SvtSaveOptions::ODFSVER_013)
+ {
+ aVersion = ODFVER_013_TEXT;
+ }
+ else if (nDefVersion >= SvtSaveOptions::ODFSVER_012)
+ {
+ aVersion = ODFVER_012_TEXT;
+ }
+
+ if (!aVersion.isEmpty())
+ {
+ try
+ {
+ xProp->setPropertyValue("Version" , uno::Any(aVersion));
+ }
+ catch (const uno::Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "exception setting Version");
+ }
+ }
+
+ Reference< XComponent > xComponent( *const_cast< ODatabaseDocument* >( this ), UNO_QUERY_THROW );
+
+ Sequence< PropertyValue > aMediaDescriptor;
+ _rMediaDescriptor >>= aMediaDescriptor;
+
+ xInfoSet->setPropertyValue("StreamName", uno::Any(OUString("settings.xml")));
+ WriteThroughComponent( xComponent, "settings.xml", "com.sun.star.comp.sdb.XMLSettingsExporter",
+ aDelegatorArguments, aMediaDescriptor, _rxTargetStorage );
+
+ xInfoSet->setPropertyValue("StreamName", uno::Any(OUString("content.xml")));
+ WriteThroughComponent( xComponent, "content.xml", "com.sun.star.comp.sdb.DBExportFilter",
+ aDelegatorArguments, aMediaDescriptor, _rxTargetStorage );
+
+ if ( _rxTargetStorage->hasByName ( sPictures ) )
+ {
+ try
+ {
+ // Delete any previously existing Pictures folder and regenerate
+ // any needed content if needed
+ Reference< XStorageBasedLibraryContainer > xDlgs = m_pImpl->getLibraryContainer( false );
+ if ( xDlgs.is() )
+ {
+ Reference< XModel > xModel(const_cast< ODatabaseDocument*>(this));
+ lcl_uglyHackToStoreDialogeEmbedImages( m_pImpl->getLibraryContainer(false), _rxTargetStorage, xModel, m_pImpl->m_aContext );
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ m_pImpl->storeLibraryContainersTo( _rxTargetStorage );
+}
+
+Reference< XUIConfigurationManager > SAL_CALL ODatabaseDocument::getUIConfigurationManager( )
+{
+ return Reference< XUIConfigurationManager >( getUIConfigurationManager2(), UNO_QUERY_THROW );
+}
+
+Reference< XUIConfigurationManager2 > const & ODatabaseDocument::getUIConfigurationManager2( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ if ( !m_xUIConfigurationManager.is() )
+ {
+ m_xUIConfigurationManager = UIConfigurationManager::create( m_pImpl->m_aContext );
+
+ OUString aUIConfigFolderName( "Configurations2" );
+
+ // First try to open with READWRITE and then READ
+ Reference< XStorage > xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, ElementModes::READWRITE );
+ if ( xConfigStorage.is() )
+ {
+ OUString aMediaType;
+ Reference< XPropertySet > xPropSet( xConfigStorage, UNO_QUERY );
+ Any a = xPropSet->getPropertyValue( INFO_MEDIATYPE );
+ if ( !( a >>= aMediaType ) || aMediaType.isEmpty() )
+ {
+ a <<= OUString("application/vnd.sun.xml.ui.configuration");
+ xPropSet->setPropertyValue( INFO_MEDIATYPE, a );
+ }
+ }
+ else
+ xConfigStorage = getDocumentSubStorage( aUIConfigFolderName, ElementModes::READ );
+
+ // initialize ui configuration manager with document substorage
+ m_xUIConfigurationManager->setStorage( xConfigStorage );
+ }
+
+ return m_xUIConfigurationManager;
+}
+
+Reference< XStorage > SAL_CALL ODatabaseDocument::getDocumentSubStorage( const OUString& aStorageName, sal_Int32 nMode )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ Reference< XDocumentSubStorageSupplier > xStorageAccess( m_pImpl->getDocumentSubStorageSupplier() );
+ return xStorageAccess->getDocumentSubStorage( aStorageName, nMode );
+}
+
+Sequence< OUString > SAL_CALL ODatabaseDocument::getDocumentSubStoragesNames( )
+{
+ Reference< XDocumentSubStorageSupplier > xStorageAccess( m_pImpl->getDocumentSubStorageSupplier() );
+ return xStorageAccess->getDocumentSubStoragesNames();
+}
+
+void ODatabaseDocument::impl_notifyStorageChange_nolck_nothrow( const Reference< XStorage >& xNewRootStorage )
+{
+ Reference< XInterface > xMe( *this );
+
+ m_aStorageListeners.forEach(
+ [&xMe, &xNewRootStorage] (uno::Reference<XStorageChangeListener> const& xListener) {
+ return xListener->notifyStorageChange(xMe, xNewRootStorage);
+ });
+}
+
+void ODatabaseDocument::disposing()
+{
+ if ( !m_pImpl.is() )
+ {
+ // this means that we're already disposed
+ OSL_ENSURE( ODatabaseDocument_OfficeDocument::rBHelper.bDisposed, "ODatabaseDocument::disposing: no impl anymore, but not yet disposed!" );
+ return;
+ }
+
+ if ( impl_isInitialized() )
+ m_aEventNotifier.notifyDocumentEvent( "OnUnload" );
+
+ Reference< XModel > xHoldAlive( this );
+
+ m_aEventNotifier.disposing();
+
+ lang::EventObject aDisposeEvent(static_cast<XWeak*>(this));
+ m_aModifyListeners.disposeAndClear( aDisposeEvent );
+ m_aCloseListener.disposeAndClear( aDisposeEvent );
+ m_aStorageListeners.disposeAndClear( aDisposeEvent );
+
+ // this is the list of objects which we currently hold as member. Upon resetting
+ // those members, we can (potentially) release the last reference to them, in which
+ // case they will be deleted - if they're C++ implementations, that is :).
+ // Some of those implementations are offending enough to require the SolarMutex, which
+ // means we should not release the last reference while our own mutex is locked ...
+ std::vector< Reference< XInterface > > aKeepAlive;
+
+ // SYNCHRONIZED ->
+ {
+ SolarMutexGuard aGuard;
+
+ OSL_ENSURE(m_aControllers.empty(),
+ "ODatabaseDocument::disposing: there still are controllers!");
+ // normally, nobody should explicitly dispose, but only XCloseable::close
+ // the document. And upon closing, our controllers are closed, too
+
+ {
+ uno::Reference<uno::XInterface> xUIInterface(m_xUIConfigurationManager);
+ aKeepAlive.push_back(xUIInterface);
+ }
+ m_xUIConfigurationManager = nullptr;
+
+ clearObjectContainer(m_xForms);
+ clearObjectContainer(m_xReports);
+
+ // reset the macro mode: in case the our impl struct stays alive (e.g. because our DataSource
+ // object still exists), and somebody subsequently re-opens the document, we want to have
+ // the security warning, again.
+ m_pImpl->resetMacroExecutionMode();
+
+ // similar arguing for our ViewMonitor
+ m_aViewMonitor.reset();
+
+ // tell our Impl to forget us
+ m_pImpl->modelIsDisposing(impl_isInitialized(), ODatabaseModelImpl::ResetModelAccess());
+
+ // now, at the latest, the controller array should be empty. Controllers are
+ // expected to listen for our disposal, and disconnect then
+ OSL_ENSURE(m_aControllers.empty(),
+ "ODatabaseDocument::disposing: there still are controllers!");
+ impl_disposeControllerFrames_nothrow();
+
+ {
+ uno::Reference<uno::XInterface> xModuleInterface(m_xModuleManager);
+ aKeepAlive.push_back(xModuleInterface);
+ }
+ m_xModuleManager.clear();
+
+ {
+ uno::Reference<uno::XInterface> xTitleInterface(m_xTitleHelper);
+ aKeepAlive.push_back(xTitleInterface);
+ }
+ m_xTitleHelper.clear();
+
+ m_pImpl.clear();
+ }
+ // <- SYNCHRONIZED
+
+ aKeepAlive.clear();
+}
+
+// XComponent
+void SAL_CALL ODatabaseDocument::dispose( )
+{
+ ::cppu::WeakComponentImplHelperBase::dispose();
+}
+
+void SAL_CALL ODatabaseDocument::addEventListener( const Reference< lang::XEventListener >& _xListener )
+{
+ ::cppu::WeakComponentImplHelperBase::addEventListener( _xListener );
+}
+
+void SAL_CALL ODatabaseDocument::removeEventListener( const Reference< lang::XEventListener >& _xListener )
+{
+ ::cppu::WeakComponentImplHelperBase::removeEventListener( _xListener );
+}
+
+// XServiceInfo
+OUString ODatabaseDocument::getImplementationName()
+{
+ return "com.sun.star.comp.dba.ODatabaseDocument";
+}
+
+Sequence< OUString > ODatabaseDocument::getSupportedServiceNames()
+{
+ return { "com.sun.star.sdb.OfficeDatabaseDocument", "com.sun.star.document.OfficeDocument" };
+}
+
+sal_Bool ODatabaseDocument::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+Reference< XDataSource > SAL_CALL ODatabaseDocument::getDataSource()
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodWithoutInit );
+ return m_pImpl->getOrCreateDataSource();
+}
+
+namespace
+{
+/// Property map for embedded import info set.
+comphelper::PropertyMapEntry const aEmbeddedImportInfoMap[] =
+{
+ {OUString("StreamRelPath"), 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID, 0},
+ {OUString("StreamName"), 0, cppu::UnoType<OUString>::get(), beans::PropertyAttribute::MAYBEVOID, 0},
+ {OUString("SourceStorage"), 0, cppu::UnoType<embed::XStorage>::get(), beans::PropertyAttribute::MAYBEVOID, 0},
+};
+}
+
+void SAL_CALL ODatabaseDocument::loadFromStorage(const Reference<XStorage>& xStorage, const Sequence<PropertyValue>& rMediaDescriptor)
+{
+ DocumentGuard aGuard(*this, DocumentGuard::InitMethod);
+
+ uno::Reference<beans::XPropertySet> xInfoSet(comphelper::GenericPropertySet_CreateInstance(new comphelper::PropertySetInfo(aEmbeddedImportInfoMap)));
+ xInfoSet->setPropertyValue("StreamRelPath", uno::Any(comphelper::NamedValueCollection::getOrDefault(rMediaDescriptor, u"HierarchicalDocumentName", OUString())));
+ xInfoSet->setPropertyValue("StreamName", uno::Any(OUString("content.xml")));
+ xInfoSet->setPropertyValue("SourceStorage", uno::Any(xStorage));
+
+ uno::Sequence<uno::Any> aFilterCreationArgs{ Any(xInfoSet) };
+
+ uno::Reference<document::XImporter> xImporter(m_pImpl->m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.comp.sdb.DBFilter", aFilterCreationArgs, m_pImpl->m_aContext), uno::UNO_QUERY_THROW);
+
+ uno::Reference<lang::XComponent> xComponent(*this, uno::UNO_QUERY_THROW);
+ xImporter->setTargetDocument(xComponent);
+
+ uno::Reference<document::XFilter> xFilter(xImporter, uno::UNO_QUERY_THROW);
+ uno::Sequence<beans::PropertyValue> aFilterArgs;
+ xFilter->filter(aFilterArgs);
+
+ // In case of embedding, XModel::attachResource is already called.
+ if (m_bEmbedded)
+ impl_setInitialized();
+
+ impl_setModified_nothrow(false, aGuard);
+}
+
+void SAL_CALL ODatabaseDocument::storeToStorage( const Reference< XStorage >& _rxStorage, const Sequence< PropertyValue >& _rMediaDescriptor )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ impl_storeToStorage_throw( _rxStorage, _rMediaDescriptor, aGuard );
+}
+
+void SAL_CALL ODatabaseDocument::switchToStorage( const Reference< XStorage >& _rxNewRootStorage )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ Reference< XStorage > xNewRootStorage( m_pImpl->switchToStorage( _rxNewRootStorage ) );
+
+ aGuard.clear();
+ impl_notifyStorageChange_nolck_nothrow( xNewRootStorage );
+}
+
+Reference< XStorage > SAL_CALL ODatabaseDocument::getDocumentStorage( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::MethodUsedDuringInit);
+ return m_pImpl->getOrCreateRootStorage();
+}
+
+void SAL_CALL ODatabaseDocument::addStorageChangeListener( const Reference< XStorageChangeListener >& Listener )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ m_aStorageListeners.addInterface( Listener );
+}
+
+void SAL_CALL ODatabaseDocument::removeStorageChangeListener( const Reference< XStorageChangeListener >& Listener )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ m_aStorageListeners.addInterface( Listener );
+}
+
+Reference< XStorageBasedLibraryContainer > SAL_CALL ODatabaseDocument::getBasicLibraries()
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit );
+ return m_pImpl->getLibraryContainer( true );
+}
+
+Reference< XStorageBasedLibraryContainer > SAL_CALL ODatabaseDocument::getDialogLibraries()
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ return m_pImpl->getLibraryContainer( false );
+}
+
+sal_Bool SAL_CALL ODatabaseDocument::getAllowMacroExecution()
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ return m_pImpl->adjustMacroMode_AutoReject();
+}
+
+Reference< XEmbeddedScripts > SAL_CALL ODatabaseDocument::getScriptContainer()
+{
+ return this;
+}
+
+Reference< provider::XScriptProvider > SAL_CALL ODatabaseDocument::getScriptProvider( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ Reference< XScriptProvider > xScriptProvider( m_xScriptProvider );
+ if ( !xScriptProvider.is() )
+ {
+ Reference < XScriptProviderFactory > xFactory =
+ theMasterScriptProviderFactory::get( m_pImpl->m_aContext );
+
+ Any aScriptProviderContext;
+ if ( m_bAllowDocumentScripting )
+ aScriptProviderContext <<= Reference< XModel >( this );
+
+ xScriptProvider.set( xFactory->createScriptProvider( aScriptProviderContext ), UNO_SET_THROW );
+ m_xScriptProvider = xScriptProvider;
+ }
+
+ return xScriptProvider;
+}
+
+Reference< XNameReplace > SAL_CALL ODatabaseDocument::getEvents( )
+{
+ DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit );
+ return m_pEventContainer.get();
+}
+
+Reference< XInterface > ODatabaseDocument::getThis() const
+{
+ return *const_cast< ODatabaseDocument* >( this );
+}
+
+namespace {
+
+struct CreateAny
+{
+ Any operator() (const Reference<XController>& lhs) const
+ {
+ return Any(lhs);
+ }
+};
+
+}
+
+// XModel2
+Reference< XEnumeration > SAL_CALL ODatabaseDocument::getControllers( )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ uno::Sequence< Any> aController( m_aControllers.size() );
+ std::transform( m_aControllers.begin(), m_aControllers.end(), aController.getArray(), CreateAny() );
+ return new ::comphelper::OAnyEnumeration(aController);
+}
+
+Sequence< OUString > SAL_CALL ODatabaseDocument::getAvailableViewControllerNames( )
+{
+ Sequence< OUString > aNames { SERVICE_SDB_APPLICATIONCONTROLLER };
+ return aNames;
+}
+
+Reference< XController2 > SAL_CALL ODatabaseDocument::createDefaultViewController( const Reference< XFrame >& Frame )
+{
+ return createViewController( "Default", Sequence< PropertyValue >(), Frame);
+}
+
+Reference< XController2 > SAL_CALL ODatabaseDocument::createViewController( const OUString& ViewName, const Sequence< PropertyValue >& Arguments, const Reference< XFrame >& Frame )
+{
+ if ( ViewName != "Default" && ViewName != "Preview" )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+ if ( !Frame.is() )
+ throw IllegalArgumentException( OUString(), *this, 3 );
+
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ aGuard.clear();
+
+ Reference< XController2 > xController(
+ m_pImpl->m_aContext->getServiceManager()->createInstanceWithContext("org.openoffice.comp.dbu.OApplicationController", m_pImpl->m_aContext),
+ UNO_QUERY_THROW );
+
+ ::comphelper::NamedValueCollection aInitArgs( Arguments );
+ aInitArgs.put( "Frame", Frame );
+ if ( ViewName == "Preview" )
+ aInitArgs.put( "Preview", true );
+ Reference< XInitialization > xInitController( xController, UNO_QUERY_THROW );
+ xInitController->initialize( aInitArgs.getWrappedPropertyValues() );
+
+ return xController;
+}
+
+Reference< XTitle > const & ODatabaseDocument::impl_getTitleHelper_throw()
+{
+ if ( ! m_xTitleHelper.is ())
+ {
+ Reference< XUntitledNumbers > xDesktop(Desktop::create(m_pImpl->m_aContext), uno::UNO_QUERY_THROW);
+ Reference< frame::XModel > xThis (getThis(), uno::UNO_QUERY_THROW);
+
+ m_xTitleHelper = new ::framework::TitleHelper(m_pImpl->m_aContext, xThis, xDesktop);
+ }
+
+ return m_xTitleHelper;
+}
+
+uno::Reference< frame::XUntitledNumbers > ODatabaseDocument::impl_getUntitledHelper_throw(const uno::Reference< uno::XInterface >& _xComponent)
+{
+ if ( !m_xModuleManager.is() )
+ m_xModuleManager.set( ModuleManager::create(m_pImpl->m_aContext) );
+
+ OUString sModuleId;
+ if (_xComponent.is())
+ sModuleId = m_xModuleManager->identify(_xComponent);
+
+ uno::Reference< frame::XUntitledNumbers > xNumberedControllers;
+
+ TNumberedController::const_iterator aFind = m_aNumberedControllers.find(sModuleId);
+ if ( aFind == m_aNumberedControllers.end() )
+ {
+ rtl::Reference<::comphelper::NumberedCollection> pHelper = new ::comphelper::NumberedCollection();
+ xNumberedControllers = pHelper;
+ pHelper->setOwner(uno::Reference< frame::XModel >(this));
+
+ m_aNumberedControllers.emplace( sModuleId,xNumberedControllers );
+ }
+ else
+ xNumberedControllers = aFind->second;
+
+ return xNumberedControllers;
+}
+
+// css.frame.XTitle
+OUString SAL_CALL ODatabaseDocument::getTitle()
+{
+ // SYNCHRONIZED ->
+ DocumentGuard aGuard( *this, DocumentGuard::MethodUsedDuringInit );
+ return impl_getTitleHelper_throw()->getTitle();
+}
+
+// css.frame.XTitle
+void SAL_CALL ODatabaseDocument::setTitle( const OUString& sTitle )
+{
+ // SYNCHRONIZED ->
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ impl_getTitleHelper_throw()->setTitle( sTitle );
+ m_aEventNotifier.notifyDocumentEventAsync( "OnTitleChanged" );
+ // <- SYNCHRONIZED
+}
+
+// css.frame.XTitleChangeBroadcaster
+void SAL_CALL ODatabaseDocument::addTitleChangeListener( const uno::Reference< frame::XTitleChangeListener >& xListener )
+{
+ // SYNCHRONIZED ->
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ uno::Reference< frame::XTitleChangeBroadcaster > xBroadcaster( impl_getTitleHelper_throw(), uno::UNO_QUERY_THROW );
+ xBroadcaster->addTitleChangeListener( xListener );
+}
+
+// css.frame.XTitleChangeBroadcaster
+void SAL_CALL ODatabaseDocument::removeTitleChangeListener( const uno::Reference< frame::XTitleChangeListener >& xListener )
+{
+ // SYNCHRONIZED ->
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+
+ uno::Reference< frame::XTitleChangeBroadcaster > xBroadcaster( impl_getTitleHelper_throw(), uno::UNO_QUERY_THROW );
+ xBroadcaster->removeTitleChangeListener( xListener );
+}
+
+// css.frame.XUntitledNumbers
+::sal_Int32 SAL_CALL ODatabaseDocument::leaseNumber( const uno::Reference< uno::XInterface >& xComponent )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ return impl_getUntitledHelper_throw(xComponent)->leaseNumber (xComponent);
+}
+
+// css.frame.XUntitledNumbers
+void SAL_CALL ODatabaseDocument::releaseNumber( ::sal_Int32 nNumber )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ impl_getUntitledHelper_throw()->releaseNumber (nNumber);
+}
+
+// css.frame.XUntitledNumbers
+void SAL_CALL ODatabaseDocument::releaseNumberForComponent( const uno::Reference< uno::XInterface >& xComponent )
+{
+ DocumentGuard aGuard(*this, DocumentGuard::DefaultMethod);
+ impl_getUntitledHelper_throw(xComponent)->releaseNumberForComponent (xComponent);
+}
+
+// css.frame.XUntitledNumbers
+OUString SAL_CALL ODatabaseDocument::getUntitledPrefix()
+{
+ return OUString();
+}
+
+} // namespace dbaccess
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dba_ODatabaseDocument(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ Reference<XUnoTunnel> xDBContextTunnel(DatabaseContext::create(context), UNO_QUERY_THROW);
+ dbaccess::ODatabaseContext* pContext
+ = comphelper::getFromUnoTunnel<dbaccess::ODatabaseContext>(xDBContextTunnel);
+ assert(pContext);
+
+ rtl::Reference pImpl(
+ new dbaccess::ODatabaseModelImpl(context, *pContext));
+ css::uno::Reference<XInterface> inst(pImpl->createNewModel_deliverOwnership());
+ inst->acquire();
+ return inst.get();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/databasedocument.hxx b/dbaccess/source/core/dataaccess/databasedocument.hxx
new file mode 100644
index 000000000..bd458d1b9
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/databasedocument.hxx
@@ -0,0 +1,753 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+#include <memory>
+
+#include <ModelImpl.hxx>
+#include "documenteventnotifier.hxx"
+
+#include <com/sun/star/document/XDocumentSubStorageSupplier.hpp>
+#include <com/sun/star/frame/DoubleInitializationException.hpp>
+#include <com/sun/star/frame/XModel3.hpp>
+#include <com/sun/star/frame/XTitle.hpp>
+#include <com/sun/star/frame/XTitleChangeBroadcaster.hpp>
+#include <com/sun/star/frame/XUntitledNumbers.hpp>
+#include <com/sun/star/frame/XStorable.hpp>
+#include <com/sun/star/sdb/XReportDocumentsSupplier.hpp>
+#include <com/sun/star/sdb/XFormDocumentsSupplier.hpp>
+#include <com/sun/star/view/XPrintable.hpp>
+#include <com/sun/star/frame/XModuleManager2.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/NotInitializedException.hpp>
+#include <com/sun/star/sdb/XOfficeDatabaseDocument.hpp>
+#include <com/sun/star/embed/XTransactionListener.hpp>
+#include <com/sun/star/document/XStorageBasedDocument.hpp>
+#include <com/sun/star/document/XEmbeddedScripts.hpp>
+#include <com/sun/star/document/XEventsSupplier.hpp>
+#include <com/sun/star/document/XScriptInvocationContext.hpp>
+#include <com/sun/star/script/XStorageBasedLibraryContainer.hpp>
+#include <com/sun/star/script/provider/XScriptProviderSupplier.hpp>
+#include <com/sun/star/frame/XLoadable.hpp>
+#include <com/sun/star/document/XEventBroadcaster.hpp>
+#include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
+#include <com/sun/star/document/XDocumentRecovery.hpp>
+#include <com/sun/star/ui/XUIConfigurationManager2.hpp>
+#include <com/sun/star/ui/XUIConfigurationManagerSupplier.hpp>
+#include <com/sun/star/util/XCloseable.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+
+#include <comphelper/interfacecontainer3.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/implbase3.hxx>
+#include <rtl/ref.hxx>
+
+namespace comphelper {
+ class NamedValueCollection;
+}
+
+namespace dbaccess
+{
+
+class DocumentEvents;
+class DocumentEventExecutor;
+class DocumentGuard;
+
+typedef std::vector< css::uno::Reference< css::frame::XController > > Controllers;
+
+// ViewMonitor
+/** helper class monitoring the views of a document, and firing appropriate events
+ when views are attached / detached
+*/
+class ViewMonitor
+{
+public:
+ explicit ViewMonitor( DocumentEventNotifier& _rEventNotifier )
+ :m_rEventNotifier( _rEventNotifier )
+ ,m_bIsNewDocument( true )
+ ,m_bEverHadController( false )
+ ,m_bLastIsFirstEverController( false )
+ ,m_xLastConnectedController()
+ {
+ }
+
+ ViewMonitor(const ViewMonitor&) = delete;
+ const ViewMonitor& operator=(const ViewMonitor&) = delete;
+
+ void reset()
+ {
+ m_bEverHadController = false;
+ m_bLastIsFirstEverController = false;
+ m_xLastConnectedController.clear();
+ }
+
+ /** to be called when a view (aka controller) has been connected to the document
+ @return
+ <TRUE/> if and only if this was the first-ever controller connected to the document
+ */
+ bool onControllerConnected(
+ const css::uno::Reference< css::frame::XController >& _rxController
+ );
+
+ /** to be called when a controller is set as current controller
+ @return <TRUE/>
+ if and only if the controller connection indicates that loading the document is finished. This
+ is the case if the given controller has previously been connected, and it was the first controller
+ ever for which this happened.
+ */
+ bool onSetCurrentController(
+ const css::uno::Reference< css::frame::XController >& _rxController
+ );
+
+ void onLoadedDocument() { m_bIsNewDocument = false; }
+
+private:
+ DocumentEventNotifier& m_rEventNotifier;
+ bool m_bIsNewDocument;
+ bool m_bEverHadController;
+ bool m_bLastIsFirstEverController;
+ css::uno::Reference< css::frame::XController >
+ m_xLastConnectedController;
+};
+
+// ODatabaseDocument
+typedef cppu::PartialWeakComponentImplHelper< css::frame::XModel3
+ , css::util::XModifiable
+ , css::frame::XStorable
+ , css::document::XEventBroadcaster
+ , css::document::XDocumentEventBroadcaster
+ , css::view::XPrintable
+ , css::util::XCloseable
+ , css::lang::XServiceInfo
+ , css::sdb::XOfficeDatabaseDocument
+ , css::ui::XUIConfigurationManagerSupplier
+ , css::document::XStorageBasedDocument
+ , css::document::XEmbeddedScripts
+ , css::document::XScriptInvocationContext
+ , css::script::provider::XScriptProviderSupplier
+ , css::document::XEventsSupplier
+ , css::frame::XLoadable
+ , css::document::XDocumentRecovery
+ > ODatabaseDocument_OfficeDocument;
+
+typedef ::cppu::ImplHelper3< css::frame::XTitle
+ , css::frame::XTitleChangeBroadcaster
+ , css::frame::XUntitledNumbers
+ > ODatabaseDocument_Title;
+
+class ODatabaseDocument :public ModelDependentComponent // ModelDependentComponent must be first!
+ ,public ODatabaseDocument_OfficeDocument
+ ,public ODatabaseDocument_Title
+{
+ enum InitState
+ {
+ NotInitialized,
+ Initializing,
+ Initialized
+ };
+
+ typedef std::map< OUString, css::uno::Reference< css::frame::XUntitledNumbers > > TNumberedController;
+ css::uno::Reference< css::ui::XUIConfigurationManager2> m_xUIConfigurationManager;
+
+ ::comphelper::OInterfaceContainerHelper3<css::util::XModifyListener> m_aModifyListeners;
+ ::comphelper::OInterfaceContainerHelper3<css::util::XCloseListener> m_aCloseListener;
+ ::comphelper::OInterfaceContainerHelper3<css::document::XStorageChangeListener> m_aStorageListeners;
+
+ std::unique_ptr<DocumentEvents> m_pEventContainer;
+ ::rtl::Reference< DocumentEventExecutor > m_pEventExecutor;
+ DocumentEventNotifier m_aEventNotifier;
+
+ css::uno::Reference< css::frame::XController > m_xCurrentController;
+ Controllers m_aControllers;
+ ViewMonitor m_aViewMonitor;
+
+ css::uno::WeakReference< css::container::XNameAccess > m_xForms;
+ css::uno::WeakReference< css::container::XNameAccess > m_xReports;
+ css::uno::WeakReference< css::script::provider::XScriptProvider > m_xScriptProvider;
+
+ /** @short such module manager is used to classify new opened documents. */
+ css::uno::Reference< css::frame::XModuleManager2 > m_xModuleManager;
+ css::uno::Reference< css::frame::XTitle > m_xTitleHelper;
+ TNumberedController m_aNumberedControllers;
+
+ /** true if and only if the DatabaseDocument's "initNew" or "load" have been called (or, well,
+ the document has be initialized implicitly - see storeAsURL
+ */
+ InitState m_eInitState;
+ bool m_bClosing;
+ bool m_bAllowDocumentScripting;
+ bool m_bHasBeenRecovered;
+ /// If XModel::attachResource() was called to inform us that the document is embedded into another one.
+ bool m_bEmbedded;
+
+ enum StoreType { SAVE, SAVE_AS };
+ /** stores the document to the given URL, rebases it to the respective new storage, if necessary, resets
+ the modified flag, and notifies any listeners as required
+
+ @param _rURL
+ the URL to store the document to
+ @param _rArguments
+ arguments for storing the document (MediaDescriptor)
+ @param _eType
+ the type of the store process (Save or SaveAs). The method will automatically
+ notify the proper events for this type.
+ @param _rGuard
+ the instance lock to be released before doing synchronous notifications
+ @throws css::io::IOException
+ @throws css::uno::RuntimeException
+ */
+ void impl_storeAs_throw(
+ const OUString& _rURL,
+ const ::comphelper::NamedValueCollection& _rArguments,
+ const StoreType _eType,
+ DocumentGuard& _rGuard
+ );
+
+ /** notifies our storage change listeners that our underlying storage changed
+
+ @param _rxNewRootStorage
+ the new root storage to be notified. If <NULL/>, it is assumed that no storage change actually
+ happened, and the listeners are not notified.
+ */
+ void impl_notifyStorageChange_nolck_nothrow(
+ const css::uno::Reference< css::embed::XStorage >& _rxNewRootStorage
+ );
+
+ /// write a single XML stream into the package
+ void WriteThroughComponent(
+ const css::uno::Reference< css::lang::XComponent > & xComponent, /// the component we export
+ const char* pStreamName, /// the stream name
+ const char* pServiceName, /// service name of the component
+ const css::uno::Sequence< css::uno::Any> & rArguments, /// the argument (XInitialization)
+ const css::uno::Sequence< css::beans::PropertyValue> & rMediaDesc,/// output descriptor
+ const css::uno::Reference< css::embed::XStorage >& _xStorageToSaveTo
+ ) const;
+
+ /// write a single output stream
+ /// (to be called either directly or by WriteThroughComponent(...))
+ void WriteThroughComponent(
+ const css::uno::Reference< css::io::XOutputStream >& xOutputStream,
+ const css::uno::Reference< css::lang::XComponent >& xComponent,
+ const char* pServiceName,
+ const css::uno::Sequence< css::uno::Any >& rArguments,
+ const css::uno::Sequence< css::beans::PropertyValue> & rMediaDesc
+ ) const;
+
+ /** writes the content and settings
+ @param sURL
+ The URL
+ @param lArguments
+ The media descriptor
+ @param _xStorageToSaveTo
+ The storage which should be used for saving
+ */
+ void impl_writeStorage_throw(
+ const css::uno::Reference< css::embed::XStorage >& _rxTargetStorage,
+ const ::comphelper::NamedValueCollection& _rMediaDescriptor
+ ) const;
+
+ // ModelDependentComponent overridables
+ virtual css::uno::Reference< css::uno::XInterface > getThis() const override;
+
+ css::uno::Reference< css::frame::XTitle > const & impl_getTitleHelper_throw();
+ css::uno::Reference< css::frame::XUntitledNumbers > impl_getUntitledHelper_throw(
+ const css::uno::Reference< css::uno::XInterface >& _xComponent = css::uno::Reference< css::uno::XInterface >());
+
+private:
+ explicit ODatabaseDocument(const ::rtl::Reference<ODatabaseModelImpl>& _pImpl);
+ // Do NOT create those documents directly, always use ODatabaseModelImpl::getModel. Reason is that
+ // ODatabaseDocument requires clear ownership, and in turn lifetime synchronisation with the ModelImpl.
+ // If you create a ODatabaseDocument directly, you might easily create a leak.
+ // #i50905#
+
+protected:
+ virtual void SAL_CALL disposing() override;
+
+ virtual ~ODatabaseDocument() override;
+
+public:
+ struct FactoryAccess { friend class ODatabaseModelImpl; private: FactoryAccess() { } };
+ static rtl::Reference<ODatabaseDocument> createDatabaseDocument( const ::rtl::Reference<ODatabaseModelImpl>& _pImpl, FactoryAccess /*accessControl*/ )
+ {
+ return new ODatabaseDocument( _pImpl );
+ }
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XInterface
+ virtual css::uno::Any SAL_CALL queryInterface(const css::uno::Type& _rType) override;
+ virtual void SAL_CALL acquire( ) noexcept override;
+ virtual void SAL_CALL release( ) noexcept override;
+
+ // XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId( ) override;
+
+ // XComponent
+ virtual void SAL_CALL dispose( ) override;
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::lang::XEventListener >& xListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::lang::XEventListener >& aListener ) override;
+
+ // XModel
+ virtual sal_Bool SAL_CALL attachResource( const OUString& URL, const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override ;
+ virtual OUString SAL_CALL getURL( ) override ;
+ virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL getArgs( ) override ;
+ virtual void SAL_CALL connectController( const css::uno::Reference< css::frame::XController >& Controller ) override ;
+ virtual void SAL_CALL disconnectController( const css::uno::Reference< css::frame::XController >& Controller ) override ;
+ virtual void SAL_CALL lockControllers( ) override ;
+ virtual void SAL_CALL unlockControllers( ) override ;
+ virtual sal_Bool SAL_CALL hasControllersLocked( ) override ;
+ virtual css::uno::Reference< css::frame::XController > SAL_CALL getCurrentController( ) override ;
+ virtual void SAL_CALL setCurrentController( const css::uno::Reference< css::frame::XController >& Controller ) override ;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getCurrentSelection( ) override ;
+
+ // XModel2
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL getControllers( ) override ;
+ virtual css::uno::Sequence< OUString > SAL_CALL getAvailableViewControllerNames( ) override ;
+ virtual css::uno::Reference< css::frame::XController2 > SAL_CALL createDefaultViewController( const css::uno::Reference< css::frame::XFrame >& Frame ) override ;
+ virtual css::uno::Reference< css::frame::XController2 > SAL_CALL createViewController( const OUString& ViewName, const css::uno::Sequence< css::beans::PropertyValue >& Arguments, const css::uno::Reference< css::frame::XFrame >& Frame ) override ;
+ virtual void SAL_CALL setArgs(const css::uno::Sequence<css::beans::PropertyValue>& aArgs) override;
+
+ // XModel3
+ virtual ::css::uno::Sequence< ::css::beans::PropertyValue > SAL_CALL getArgs2( const ::css::uno::Sequence< ::rtl::OUString >& requestedArgs ) override;
+
+ // XStorable
+ virtual sal_Bool SAL_CALL hasLocation( ) override ;
+ virtual OUString SAL_CALL getLocation( ) override ;
+ virtual sal_Bool SAL_CALL isReadonly( ) override ;
+ virtual void SAL_CALL store( ) override ;
+ virtual void SAL_CALL storeAsURL( const OUString& sURL, const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) override ;
+ virtual void SAL_CALL storeToURL( const OUString& sURL, const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) override ;
+
+ // XModifyBroadcaster
+ virtual void SAL_CALL addModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+ virtual void SAL_CALL removeModifyListener( const css::uno::Reference< css::util::XModifyListener >& aListener ) override;
+
+ // css::util::XModifiable
+ virtual sal_Bool SAL_CALL isModified( ) override ;
+ virtual void SAL_CALL setModified( sal_Bool bModified ) override ;
+
+ // XEventBroadcaster
+ virtual void SAL_CALL addEventListener( const css::uno::Reference< css::document::XEventListener >& aListener ) override;
+ virtual void SAL_CALL removeEventListener( const css::uno::Reference< css::document::XEventListener >& aListener ) override;
+
+ // XDocumentEventBroadcaster
+ virtual void SAL_CALL addDocumentEventListener( const css::uno::Reference< css::document::XDocumentEventListener >& Listener ) override;
+ virtual void SAL_CALL removeDocumentEventListener( const css::uno::Reference< css::document::XDocumentEventListener >& Listener ) override;
+ virtual void SAL_CALL notifyDocumentEvent( const OUString& EventName, const css::uno::Reference< css::frame::XController2 >& ViewController, const css::uno::Any& Supplement ) override;
+
+ // XPrintable
+ virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL getPrinter( ) override ;
+ virtual void SAL_CALL setPrinter( const css::uno::Sequence< css::beans::PropertyValue >& aPrinter ) override ;
+ virtual void SAL_CALL print( const css::uno::Sequence< css::beans::PropertyValue >& xOptions ) override ;
+
+ // XFormDocumentsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getFormDocuments( ) override;
+
+ // XReportDocumentsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getReportDocuments( ) override;
+
+ // XCloseable
+ virtual void SAL_CALL close( sal_Bool DeliverOwnership ) override;
+ virtual void SAL_CALL addCloseListener( const css::uno::Reference< css::util::XCloseListener >& Listener ) override;
+ virtual void SAL_CALL removeCloseListener( const css::uno::Reference< css::util::XCloseListener >& Listener ) override;
+
+ // XUIConfigurationManagerSupplier
+ virtual css::uno::Reference< css::ui::XUIConfigurationManager > SAL_CALL getUIConfigurationManager( ) override;
+
+ // XDocumentSubStorageSupplier
+ virtual css::uno::Reference< css::embed::XStorage > SAL_CALL getDocumentSubStorage( const OUString& aStorageName, sal_Int32 nMode ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getDocumentSubStoragesNames( ) override;
+
+ // XOfficeDatabaseDocument
+ virtual css::uno::Reference< css::sdbc::XDataSource > SAL_CALL getDataSource() override;
+
+ // XStorageBasedDocument
+ virtual void SAL_CALL loadFromStorage( const css::uno::Reference< css::embed::XStorage >& xStorage, const css::uno::Sequence< css::beans::PropertyValue >& aMediaDescriptor ) override;
+ virtual void SAL_CALL storeToStorage( const css::uno::Reference< css::embed::XStorage >& xStorage, const css::uno::Sequence< css::beans::PropertyValue >& aMediaDescriptor ) override;
+ virtual void SAL_CALL switchToStorage( const css::uno::Reference< css::embed::XStorage >& xStorage ) override;
+ virtual css::uno::Reference< css::embed::XStorage > SAL_CALL getDocumentStorage( ) override;
+ virtual void SAL_CALL addStorageChangeListener( const css::uno::Reference< css::document::XStorageChangeListener >& xListener ) override;
+ virtual void SAL_CALL removeStorageChangeListener( const css::uno::Reference< css::document::XStorageChangeListener >& xListener ) override;
+
+ // XEmbeddedScripts
+ virtual css::uno::Reference< css::script::XStorageBasedLibraryContainer > SAL_CALL getBasicLibraries() override;
+ virtual css::uno::Reference< css::script::XStorageBasedLibraryContainer > SAL_CALL getDialogLibraries() override;
+ virtual sal_Bool SAL_CALL getAllowMacroExecution() override;
+
+ // XScriptInvocationContext
+ virtual css::uno::Reference< css::document::XEmbeddedScripts > SAL_CALL getScriptContainer() override;
+
+ // XScriptProviderSupplier
+ virtual css::uno::Reference< css::script::provider::XScriptProvider > SAL_CALL getScriptProvider( ) override;
+
+ // XEventsSupplier
+ virtual css::uno::Reference< css::container::XNameReplace > SAL_CALL getEvents( ) override;
+
+ // XLoadable
+ virtual void SAL_CALL initNew( ) override;
+ virtual void SAL_CALL load( const css::uno::Sequence< css::beans::PropertyValue >& lArguments ) override;
+
+ // css.document.XDocumentRecovery
+ virtual sal_Bool SAL_CALL wasModifiedSinceLastSave() override;
+ virtual void SAL_CALL storeToRecoveryFile( const OUString& i_TargetLocation, const css::uno::Sequence< css::beans::PropertyValue >& i_MediaDescriptor ) override;
+ virtual void SAL_CALL recoverFromFile( const OUString& i_SourceLocation, const OUString& i_SalvagedFile, const css::uno::Sequence< css::beans::PropertyValue >& i_MediaDescriptor ) override;
+
+ // XTitle
+ virtual OUString SAL_CALL getTitle( ) override;
+ virtual void SAL_CALL setTitle( const OUString& sTitle ) override;
+
+ // XTitleChangeBroadcaster
+ virtual void SAL_CALL addTitleChangeListener( const css::uno::Reference< css::frame::XTitleChangeListener >& xListener ) override;
+ virtual void SAL_CALL removeTitleChangeListener( const css::uno::Reference< css::frame::XTitleChangeListener >& xListener ) override;
+
+ // XUntitledNumbers
+ virtual ::sal_Int32 SAL_CALL leaseNumber( const css::uno::Reference< css::uno::XInterface >& xComponent ) override;
+ virtual void SAL_CALL releaseNumber( ::sal_Int32 nNumber ) override;
+ virtual void SAL_CALL releaseNumberForComponent( const css::uno::Reference< css::uno::XInterface >& xComponent ) override;
+ virtual OUString SAL_CALL getUntitledPrefix( ) override;
+
+ /** clears the given object container
+
+ Clearing is done via disposal - the method calls XComponent::dispose at the given object,
+ which must be one of our impl's or our object containers (m_xForms, m_xReports,
+ m_xTableDefinitions, m_xCommandDefinitions)
+
+ @param _rxContainer
+ the container to clear
+ */
+ static void clearObjectContainer(
+ css::uno::WeakReference< css::container::XNameAccess >& _rxContainer);
+
+ /** checks whether the component is already initialized, throws a NotInitializedException if not
+ */
+ void checkInitialized() const
+ {
+ if ( !impl_isInitialized() )
+ throw css::lang::NotInitializedException( OUString(), getThis() );
+ }
+
+ /** checks the document is currently in the initialization phase, or already initialized.
+ Throws NotInitializedException if not so.
+ */
+ void checkNotUninitialized() const
+ {
+ if ( impl_isInitialized() || impl_isInitializing() )
+ // fine
+ return;
+
+ throw css::lang::NotInitializedException( OUString(), getThis() );
+ }
+
+ /** checks whether the document is currently being initialized, or already initialized,
+ throws a DoubleInitializationException if so
+ */
+ void checkNotInitialized() const
+ {
+ if ( impl_isInitializing() || impl_isInitialized() )
+ throw css::frame::DoubleInitializationException( OUString(), getThis() );
+ }
+
+private:
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::ui::XUIConfigurationManager2 > const & getUIConfigurationManager2();
+
+ /** returns whether the model is currently being initialized
+ */
+ bool impl_isInitializing() const { return m_eInitState == Initializing; }
+
+ /** returns whether the model is already initialized, i.e. the XModel's "initNew" or "load" methods have been called
+ */
+ bool impl_isInitialized() const { return m_eInitState == Initialized; }
+
+ /// tells the model it is being initialized now
+ void impl_setInitializing() { m_eInitState = Initializing; }
+
+ /// tells the model its initialization is done
+ void impl_setInitialized();
+
+ /** closes the frames of all connected controllers
+
+ @param _bDeliverOwnership
+ determines if the ownership should be transferred to the component which
+ possibly vetos the closing
+
+ @throws css::util::CloseVetoException
+ if the closing was vetoed by any instance
+ */
+ void impl_closeControllerFrames_nolck_throw( bool _bDeliverOwnership );
+
+ /** disposes the frames of all controllers which are still left in m_aControllers.
+ */
+ void impl_disposeControllerFrames_nothrow();
+
+ /** does a reparenting at the given object container to ourself
+
+ Calls XChild::setParent at the given object, which must be one of our impl's or our
+ object containers (m_xForms, m_xReports, m_xTableDefinitions, m_xCommandDefinitions)
+ */
+ void impl_reparent_nothrow( const css::uno::WeakReference< css::container::XNameAccess >& _rxContainer );
+
+ /** retrieves the forms or reports contained, creates and initializes it, if necessary
+
+ @throws DisposedException
+ if the instance is already disposed
+ @throws IllegalArgumentException
+ if <arg>_eType</arg> is not ODatabaseModelImpl::E_FORM and not ODatabaseModelImpl::E_REPORT
+ */
+ css::uno::Reference< css::container::XNameAccess >
+ impl_getDocumentContainer_throw( ODatabaseModelImpl::ObjectType _eType );
+
+ /** resets everything
+
+ @precond
+ m_pImpl is not <NULL/>
+ */
+ void
+ impl_reset_nothrow();
+
+ /** imports the document from the given resource.
+ */
+ static void
+ impl_import_nolck_throw(
+ const css::uno::Reference< css::uno::XComponentContext >& _rContext,
+ const css::uno::Reference< css::uno::XInterface >& _rxTargetComponent,
+ const ::comphelper::NamedValueCollection& _rResource
+ );
+
+ /** creates a storage for the given URL, truncating it if a file with this name already exists
+
+ @throws Exception
+ if creating the storage failed
+
+ @return
+ the newly created storage for the file at the given URL
+ */
+ css::uno::Reference< css::embed::XStorage >
+ impl_createStorageFor_throw(
+ const OUString& _rURL
+ ) const;
+
+ /** Extracts storage from arguments, or creates for the given URL, truncating it if a file with
+ this name already exists
+
+ @throws Exception
+ if creating the storage failed
+
+ @return
+ the storage that is either extracted from arguments, or newly created for the file at
+ the given URL
+ */
+ css::uno::Reference<css::embed::XStorage> impl_GetStorageOrCreateFor_throw(
+ const ::comphelper::NamedValueCollection& _rArguments, const OUString& _rURL) const;
+
+ /** sets our "modified" flag
+
+ will notify all our respective listeners, if the "modified" state actually changed
+
+ @param _bModified
+ the (new) flag indicating whether the document is currently modified or not
+ @param _rGuard
+ the guard for our instance. At method entry, the guard must hold the lock. At the moment
+ of method leave, the lock will be released.
+ @precond
+ our mutex is locked
+ @postcond
+ our mutex is not locked
+ */
+ void impl_setModified_nothrow( bool _bModified, DocumentGuard& _rGuard );
+
+ /** stores the document to the given storage
+
+ Note that the document is actually not rebased to this storage, it just stores a copy of itself
+ to the given target storage.
+
+ @param _rxTargetStorage
+ denotes the storage to store the document into
+ @param _rMediaDescriptor
+ contains additional parameters for storing the document
+ @param _rDocGuard
+ a guard which holds the (only) lock to the document, and which will be temporarily
+ released where necessary (e.g. for notifications, or calling into other components)
+
+ @throws css::uno::IllegalArgumentException
+ if the given storage is <NULL/>.
+
+ @throws css::uno::RuntimeException
+ when any of the used operations throws it
+
+ @throws css::io::IOException
+ when any of the used operations throws it, or any other exception occurs which is no
+ RuntimeException and no IOException
+ */
+ void impl_storeToStorage_throw(
+ const css::uno::Reference< css::embed::XStorage >& _rxTargetStorage,
+ const css::uno::Sequence< css::beans::PropertyValue >& _rMediaDescriptor,
+ DocumentGuard& _rDocGuard
+ ) const;
+
+ /** impl-version of attachResource
+
+ @param i_rLogicalDocumentURL
+ denotes the logical URL of the document, to be reported by getURL/getLocation
+ @param i_rMediaDescriptor
+ denotes additional document parameters
+ @param _rDocGuard
+ is the guard which currently protects the document instance
+ */
+ bool impl_attachResource(
+ const OUString& i_rLogicalDocumentURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& i_rMediaDescriptor,
+ DocumentGuard& _rDocGuard
+ );
+
+ /** throws an IOException with the message as defined in the RID_STR_ERROR_WHILE_SAVING resource, wrapping
+ the given caught non-IOException error
+ */
+ void impl_throwIOExceptionCausedBySave_throw(
+ const css::uno::Any& i_rError,
+ std::u16string_view i_rTargetURL
+ ) const;
+};
+
+/** an extended version of the ModelMethodGuard, which also cares for the initialization state
+ of the document
+*/
+class DocumentGuard : private ModelMethodGuard
+{
+public:
+ enum InitMethod_
+ {
+ // a method which is to initialize the document
+ InitMethod,
+ };
+
+ enum DefaultMethod_
+ {
+ // a default method
+ DefaultMethod
+ };
+
+ enum MethodUsedDuringInit_
+ {
+ // a method which is used (externally) during the initialization phase
+ MethodUsedDuringInit
+ };
+
+ enum MethodWithoutInit_
+ {
+ // a method which does not need initialization - use with care!
+ MethodWithoutInit
+ };
+
+
+ /** constructs the guard
+
+ @param _document
+ the ODatabaseDocument instance
+
+ @throws css::lang::DisposedException
+ If the given component is already disposed
+
+ @throws css::lang::NotInitializedException
+ if the given component is not yet initialized
+ */
+ DocumentGuard(const ODatabaseDocument& _document, DefaultMethod_)
+ : ModelMethodGuard(_document)
+ , m_document(_document )
+ {
+ m_document.checkInitialized();
+ }
+
+ /** constructs the guard
+
+ @param _document
+ the ODatabaseDocument instance
+
+ @throws css::lang::DisposedException
+ If the given component is already disposed
+
+ @throws css::frame::DoubleInitializationException
+ if the given component is already initialized, or currently being initialized.
+ */
+ DocumentGuard(const ODatabaseDocument& _document, InitMethod_)
+ : ModelMethodGuard(_document)
+ , m_document(_document)
+ {
+ m_document.checkNotInitialized();
+ }
+
+ /** constructs the guard
+
+ @param _document
+ the ODatabaseDocument instance
+
+ @throws css::lang::DisposedException
+ If the given component is already disposed
+
+ @throws css::lang::NotInitializedException
+ if the component is still uninitialized, and not in the initialization
+ phase currently.
+ */
+ DocumentGuard(const ODatabaseDocument& _document, MethodUsedDuringInit_)
+ : ModelMethodGuard(_document)
+ , m_document(_document)
+ {
+ m_document.checkNotUninitialized();
+ }
+
+ /** constructs the guard
+
+ @param _document
+ the ODatabaseDocument instance
+
+ @throws css::lang::DisposedException
+ If the given component is already disposed
+ */
+ DocumentGuard(const ODatabaseDocument& _document, MethodWithoutInit_)
+ : ModelMethodGuard( _document )
+ , m_document( _document )
+ {
+ }
+
+ void clear()
+ {
+ ModelMethodGuard::clear();
+ }
+ void reset()
+ {
+ ModelMethodGuard::reset();
+ m_document.checkDisposed();
+ }
+
+private:
+
+ const ODatabaseDocument& m_document;
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/databaseregistrations.cxx b/dbaccess/source/core/dataaccess/databaseregistrations.cxx
new file mode 100644
index 000000000..40fa526d1
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/databaseregistrations.cxx
@@ -0,0 +1,369 @@
+/* -*- 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 <com/sun/star/lang/IllegalAccessException.hpp>
+#include <com/sun/star/lang/IllegalArgumentException.hpp>
+#include <com/sun/star/container/ElementExistException.hpp>
+#include <com/sun/star/container/NoSuchElementException.hpp>
+#include <com/sun/star/sdb/XDatabaseRegistrations.hpp>
+
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <cppuhelper/implbase1.hxx>
+#include <osl/diagnose.h>
+#include <unotools/pathoptions.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/confignode.hxx>
+
+#include "databaseregistrations.hxx"
+
+namespace dbaccess
+{
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::container::NoSuchElementException;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::lang::IllegalAccessException;
+ using ::com::sun::star::container::ElementExistException;
+ using ::com::sun::star::sdb::XDatabaseRegistrations;
+ using ::com::sun::star::sdb::XDatabaseRegistrationsListener;
+ using ::com::sun::star::sdb::DatabaseRegistrationEvent;
+ using ::com::sun::star::uno::XAggregation;
+
+ static OUString getConfigurationRootPath()
+ {
+ return "org.openoffice.Office.DataAccess/RegisteredNames";
+ }
+
+ static OUString getLocationNodeName()
+ {
+ return "Location";
+ }
+
+ static OUString getNameNodeName()
+ {
+ return "Name";
+ }
+
+ // DatabaseRegistrations - declaration
+ typedef ::cppu::WeakAggImplHelper1 < XDatabaseRegistrations
+ > DatabaseRegistrations_Base;
+
+ namespace {
+
+ class DatabaseRegistrations :public ::cppu::BaseMutex
+ ,public DatabaseRegistrations_Base
+ {
+ public:
+ explicit DatabaseRegistrations( const Reference<XComponentContext>& _rxContext );
+
+ protected:
+ virtual ~DatabaseRegistrations() override;
+
+ public:
+ virtual sal_Bool SAL_CALL hasRegisteredDatabase( const OUString& Name ) override;
+ virtual Sequence< OUString > SAL_CALL getRegistrationNames() override;
+ virtual OUString SAL_CALL getDatabaseLocation( const OUString& Name ) override;
+ virtual void SAL_CALL registerDatabaseLocation( const OUString& Name, const OUString& Location ) override;
+ virtual void SAL_CALL revokeDatabaseLocation( const OUString& Name ) override;
+ virtual void SAL_CALL changeDatabaseLocation( const OUString& Name, const OUString& NewLocation ) override;
+ virtual sal_Bool SAL_CALL isDatabaseRegistrationReadOnly( const OUString& Name ) override;
+ virtual void SAL_CALL addDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener ) override;
+ virtual void SAL_CALL removeDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener ) override;
+
+ private:
+ void
+ impl_checkValidName_common(std::u16string_view _rName);
+ ::utl::OConfigurationNode
+ impl_checkValidName_throw_must_exist(const OUString& _rName);
+ ::utl::OConfigurationNode
+ impl_checkValidName_throw_must_not_exist(const OUString& _rName);
+
+ void impl_checkValidLocation_throw( std::u16string_view _rLocation );
+
+ /** retrieves the configuration node whose "Name" sub node has the given value
+
+ Since we separated the name of the registration node from the "Name" value of the registration, we cannot
+ simply do a "getByName" (equivalent) when we want to retrieve the node for a given registration name.
+ Instead, we must search all nodes.
+
+ If a node with the given display name does not exist, then a NoSuchElementException is thrown.
+
+ If no exception is thrown, then a valid node is returned: If the node existed it is returned.
+ */
+ ::utl::OConfigurationNode
+ impl_getNodeForName_throw_must_exist(const OUString& _rName);
+
+ /** retrieves the configuration node whose "Name" sub node has the given value
+
+ Since we separated the name of the registration node from the "Name" value of the registration, we cannot
+ simply do a "getByName" (equivalent) when we want to retrieve the node for a given registration name.
+ Instead, we must search all nodes.
+
+ If a node with the given name already exists, then an ElementExistException is thrown.
+
+ If no exception is thrown, then a valid node is returned: If the node did not yet exist a new node is created,
+ in this case the root node is not yet committed.
+ */
+ ::utl::OConfigurationNode
+ impl_getNodeForName_throw_must_not_exist(const OUString& _rName);
+
+
+ ::utl::OConfigurationNode
+ impl_getNodeForName_nothrow(std::u16string_view _rName);
+
+ private:
+ Reference<XComponentContext> m_aContext;
+ ::utl::OConfigurationTreeRoot m_aConfigurationRoot;
+ ::comphelper::OInterfaceContainerHelper3<XDatabaseRegistrationsListener> m_aRegistrationListeners;
+ };
+
+ }
+
+ // DatabaseRegistrations - implementation
+ DatabaseRegistrations::DatabaseRegistrations( const Reference<XComponentContext> & _rxContext )
+ :m_aContext( _rxContext )
+ ,m_aRegistrationListeners( m_aMutex )
+ {
+ m_aConfigurationRoot = ::utl::OConfigurationTreeRoot::createWithComponentContext(
+ m_aContext, getConfigurationRootPath() );
+ }
+
+ DatabaseRegistrations::~DatabaseRegistrations()
+ {
+ }
+
+ ::utl::OConfigurationNode DatabaseRegistrations::impl_getNodeForName_nothrow( std::u16string_view _rName )
+ {
+ const Sequence< OUString > aNames( m_aConfigurationRoot.getNodeNames() );
+ for ( auto const & nodeName : aNames )
+ {
+ ::utl::OConfigurationNode aNodeForName = m_aConfigurationRoot.openNode( nodeName );
+
+ OUString sTestName;
+ OSL_VERIFY( aNodeForName.getNodeValue( getNameNodeName() ) >>= sTestName );
+ if ( sTestName == _rName )
+ return aNodeForName;
+ }
+ return ::utl::OConfigurationNode();
+ }
+
+ ::utl::OConfigurationNode DatabaseRegistrations::impl_getNodeForName_throw_must_exist(const OUString& _rName)
+ {
+ ::utl::OConfigurationNode aNodeForName( impl_getNodeForName_nothrow( _rName ) );
+
+ if (!aNodeForName.isValid())
+ {
+ throw NoSuchElementException( _rName, *this );
+ }
+
+ return aNodeForName;
+ }
+
+ ::utl::OConfigurationNode DatabaseRegistrations::impl_getNodeForName_throw_must_not_exist(const OUString& _rName)
+ {
+ ::utl::OConfigurationNode aNodeForName( impl_getNodeForName_nothrow( _rName ) );
+
+ if (aNodeForName.isValid())
+ throw ElementExistException( _rName, *this );
+
+ // make unique
+ OUString sNewNodeName = "org.openoffice." + _rName;
+ while ( m_aConfigurationRoot.hasByName( sNewNodeName ) )
+ {
+ sNewNodeName = "org.openoffice." + _rName + " 2";
+ }
+
+ ::utl::OConfigurationNode aNewNode( m_aConfigurationRoot.createNode( sNewNodeName ) );
+ aNewNode.setNodeValue( getNameNodeName(), Any( _rName ) );
+ return aNewNode;
+ }
+
+ void DatabaseRegistrations::impl_checkValidName_common(std::u16string_view _rName)
+ {
+ if ( !m_aConfigurationRoot.isValid() )
+ throw RuntimeException( OUString(), *this );
+
+ if ( _rName.empty() )
+ throw IllegalArgumentException( OUString(), *this, 1 );
+ }
+
+ ::utl::OConfigurationNode DatabaseRegistrations::impl_checkValidName_throw_must_exist(const OUString& _rName)
+ {
+ impl_checkValidName_common(_rName);
+ return impl_getNodeForName_throw_must_exist(_rName);
+ }
+
+ ::utl::OConfigurationNode DatabaseRegistrations::impl_checkValidName_throw_must_not_exist(const OUString& _rName)
+ {
+ impl_checkValidName_common(_rName);
+ return impl_getNodeForName_throw_must_not_exist(_rName);
+ }
+
+ void DatabaseRegistrations::impl_checkValidLocation_throw( std::u16string_view _rLocation )
+ {
+ if ( _rLocation.empty() )
+ throw IllegalArgumentException( OUString(), *this, 2 );
+
+ INetURLObject aURL( _rLocation );
+ if ( aURL.GetProtocol() == INetProtocol::NotValid )
+ throw IllegalArgumentException( OUString(), *this, 2 );
+ }
+
+ sal_Bool SAL_CALL DatabaseRegistrations::hasRegisteredDatabase( const OUString& Name )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ ::utl::OConfigurationNode aNodeForName = impl_getNodeForName_nothrow( Name );
+ return aNodeForName.isValid();
+ }
+
+ Sequence< OUString > SAL_CALL DatabaseRegistrations::getRegistrationNames()
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !m_aConfigurationRoot.isValid() )
+ throw RuntimeException( OUString(), *this );
+
+ const Sequence< OUString > aProgrammaticNames( m_aConfigurationRoot.getNodeNames() );
+ Sequence< OUString > aDisplayNames( aProgrammaticNames.getLength() );
+ OUString* pDisplayName = aDisplayNames.getArray();
+
+ for ( auto const & name : aProgrammaticNames )
+ {
+ ::utl::OConfigurationNode aRegistrationNode = m_aConfigurationRoot.openNode( name );
+ OSL_VERIFY( aRegistrationNode.getNodeValue( getNameNodeName() ) >>= *pDisplayName );
+ ++pDisplayName;
+ }
+
+ return aDisplayNames;
+ }
+
+ OUString SAL_CALL DatabaseRegistrations::getDatabaseLocation( const OUString& Name )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ ::utl::OConfigurationNode aNodeForName = impl_checkValidName_throw_must_exist(Name);
+
+ OUString sLocation;
+ OSL_VERIFY( aNodeForName.getNodeValue( getLocationNodeName() ) >>= sLocation );
+ sLocation = SvtPathOptions().SubstituteVariable( sLocation );
+
+ return sLocation;
+ }
+
+ void SAL_CALL DatabaseRegistrations::registerDatabaseLocation( const OUString& Name, const OUString& Location )
+ {
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+
+ // check
+ impl_checkValidLocation_throw( Location );
+ ::utl::OConfigurationNode aDataSourceRegistration = impl_checkValidName_throw_must_not_exist(Name);
+
+ // register
+ aDataSourceRegistration.setNodeValue( getLocationNodeName(), Any( Location ) );
+ m_aConfigurationRoot.commit();
+
+ // notify
+ DatabaseRegistrationEvent aEvent( *this, Name, OUString(), Location );
+ aGuard.clear();
+ m_aRegistrationListeners.notifyEach( &XDatabaseRegistrationsListener::registeredDatabaseLocation, aEvent );
+ }
+
+ void SAL_CALL DatabaseRegistrations::revokeDatabaseLocation( const OUString& Name )
+ {
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+
+ // check
+ ::utl::OConfigurationNode aNodeForName = impl_checkValidName_throw_must_exist(Name);
+
+ // obtain properties for notification
+ OUString sLocation;
+ OSL_VERIFY( aNodeForName.getNodeValue( getLocationNodeName() ) >>= sLocation );
+
+ // revoke
+ if ( aNodeForName.isReadonly()
+ || !m_aConfigurationRoot.removeNode( aNodeForName.getLocalName() )
+ )
+ throw IllegalAccessException( OUString(), *this );
+
+ m_aConfigurationRoot.commit();
+
+ // notify
+ DatabaseRegistrationEvent aEvent( *this, Name, sLocation, OUString() );
+ aGuard.clear();
+ m_aRegistrationListeners.notifyEach( &XDatabaseRegistrationsListener::revokedDatabaseLocation, aEvent );
+ }
+
+ void SAL_CALL DatabaseRegistrations::changeDatabaseLocation( const OUString& Name, const OUString& NewLocation )
+ {
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+
+ // check
+ impl_checkValidLocation_throw( NewLocation );
+ ::utl::OConfigurationNode aDataSourceRegistration = impl_checkValidName_throw_must_exist(Name);
+
+ if ( aDataSourceRegistration.isReadonly() )
+ throw IllegalAccessException( OUString(), *this );
+
+ // obtain properties for notification
+ OUString sOldLocation;
+ OSL_VERIFY( aDataSourceRegistration.getNodeValue( getLocationNodeName() ) >>= sOldLocation );
+
+ // change
+ aDataSourceRegistration.setNodeValue( getLocationNodeName(), Any( NewLocation ) );
+ m_aConfigurationRoot.commit();
+
+ // notify
+ DatabaseRegistrationEvent aEvent( *this, Name, sOldLocation, NewLocation );
+ aGuard.clear();
+ m_aRegistrationListeners.notifyEach( &XDatabaseRegistrationsListener::changedDatabaseLocation, aEvent );
+ }
+
+ sal_Bool SAL_CALL DatabaseRegistrations::isDatabaseRegistrationReadOnly( const OUString& Name )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ ::utl::OConfigurationNode aDataSourceRegistration = impl_checkValidName_throw_must_exist(Name);
+ return aDataSourceRegistration.isReadonly();
+ }
+
+ void SAL_CALL DatabaseRegistrations::addDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener )
+ {
+ if ( Listener.is() )
+ m_aRegistrationListeners.addInterface( Listener );
+ }
+
+ void SAL_CALL DatabaseRegistrations::removeDatabaseRegistrationsListener( const Reference< XDatabaseRegistrationsListener >& Listener )
+ {
+ if ( Listener.is() )
+ m_aRegistrationListeners.removeInterface( Listener );
+ }
+
+ // DatabaseRegistrations - factory
+ Reference< XAggregation > createDataSourceRegistrations( const Reference<XComponentContext> & _rxContext )
+ {
+ return new DatabaseRegistrations( _rxContext );
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/databaseregistrations.hxx b/dbaccess/source/core/dataaccess/databaseregistrations.hxx
new file mode 100644
index 000000000..709bc9f98
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/databaseregistrations.hxx
@@ -0,0 +1,32 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/XAggregation.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace dbaccess
+{
+css::uno::Reference<css::uno::XAggregation>
+createDataSourceRegistrations(const css::uno::Reference<css::uno::XComponentContext>& _rxContext);
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/datasource.cxx b/dbaccess/source/core/dataaccess/datasource.cxx
new file mode 100644
index 000000000..d88b661c9
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/datasource.cxx
@@ -0,0 +1,1437 @@
+/* -*- 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 "datasource.hxx"
+#include "commandcontainer.hxx"
+#include <stringconstants.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include "connection.hxx"
+#include "SharedConnection.hxx"
+#include "databasedocument.hxx"
+#include <OAuthenticationContinuation.hxx>
+
+#include <hsqlimport.hxx>
+#include <migrwarndlg.hxx>
+
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyState.hpp>
+#include <com/sun/star/document/XDocumentSubStorageSupplier.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/reflection/ProxyFactory.hpp>
+#include <com/sun/star/sdb/DatabaseContext.hpp>
+#include <com/sun/star/sdb/SQLContext.hpp>
+#include <com/sun/star/sdbc/ConnectionPool.hpp>
+#include <com/sun/star/sdbc/XDriverAccess.hpp>
+#include <com/sun/star/sdbc/XDriverManager.hpp>
+#include <com/sun/star/sdbc/DriverManager.hpp>
+#include <com/sun/star/ucb/AuthenticationRequest.hpp>
+#include <com/sun/star/ucb/XInteractionSupplyAuthentication.hpp>
+
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/interaction.hxx>
+#include <comphelper/property.hxx>
+#include <comphelper/sequence.hxx>
+#include <comphelper/types.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <connectivity/dbexception.hxx>
+#include <connectivity/dbtools.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <osl/process.h>
+#include <sal/log.hxx>
+#include <tools/urlobj.hxx>
+#include <unotools/sharedunocomponent.hxx>
+#include <rtl/digest.h>
+
+#include <algorithm>
+#include <iterator>
+#include <set>
+
+#include <config_firebird.h>
+
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::task;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::reflection;
+using namespace ::cppu;
+using namespace ::osl;
+using namespace ::dbtools;
+using namespace ::comphelper;
+
+namespace dbaccess
+{
+
+namespace {
+
+/** helper class which implements a XFlushListener, and forwards all
+ notification events to another XFlushListener
+
+ The speciality is that the foreign XFlushListener instance, to which
+ the notifications are forwarded, is held weak.
+
+ Thus, the class can be used with XFlushable instance which hold
+ their listeners with a hard reference, if you simply do not *want*
+ to be held hard-ref-wise.
+*/
+class FlushNotificationAdapter : public ::cppu::WeakImplHelper< XFlushListener >
+{
+private:
+ WeakReference< XFlushable > m_aBroadcaster;
+ WeakReference< XFlushListener > m_aListener;
+
+public:
+ static void installAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener )
+ {
+ new FlushNotificationAdapter( _rxBroadcaster, _rxListener );
+ }
+
+protected:
+ FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener );
+ virtual ~FlushNotificationAdapter() override;
+
+ void impl_dispose();
+
+protected:
+ // XFlushListener
+ virtual void SAL_CALL flushed( const css::lang::EventObject& rEvent ) override;
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+};
+
+}
+
+FlushNotificationAdapter::FlushNotificationAdapter( const Reference< XFlushable >& _rxBroadcaster, const Reference< XFlushListener >& _rxListener )
+ :m_aBroadcaster( _rxBroadcaster )
+ ,m_aListener( _rxListener )
+{
+ OSL_ENSURE( _rxBroadcaster.is(), "FlushNotificationAdapter::FlushNotificationAdapter: invalid flushable!" );
+
+ osl_atomic_increment( &m_refCount );
+ {
+ if ( _rxBroadcaster.is() )
+ _rxBroadcaster->addFlushListener( this );
+ }
+ osl_atomic_decrement( &m_refCount );
+ OSL_ENSURE( m_refCount == 1, "FlushNotificationAdapter::FlushNotificationAdapter: broadcaster isn't holding by hard ref!?" );
+}
+
+FlushNotificationAdapter::~FlushNotificationAdapter()
+{
+}
+
+void FlushNotificationAdapter::impl_dispose()
+{
+ Reference< XFlushListener > xKeepAlive( this );
+
+ Reference< XFlushable > xFlushable( m_aBroadcaster );
+ if ( xFlushable.is() )
+ xFlushable->removeFlushListener( this );
+
+ m_aListener.clear();
+ m_aBroadcaster.clear();
+}
+
+void SAL_CALL FlushNotificationAdapter::flushed( const EventObject& rEvent )
+{
+ Reference< XFlushListener > xListener( m_aListener );
+ if ( xListener.is() )
+ xListener->flushed( rEvent );
+ else
+ impl_dispose();
+}
+
+void SAL_CALL FlushNotificationAdapter::disposing( const EventObject& Source )
+{
+ Reference< XFlushListener > xListener( m_aListener );
+ if ( xListener.is() )
+ xListener->disposing( Source );
+
+ impl_dispose();
+}
+
+OAuthenticationContinuation::OAuthenticationContinuation()
+ :m_bRememberPassword(true), // TODO: a meaningful default
+ m_bCanSetUserName(true)
+{
+}
+
+sal_Bool SAL_CALL OAuthenticationContinuation::canSetRealm( )
+{
+ return false;
+}
+
+void SAL_CALL OAuthenticationContinuation::setRealm( const OUString& /*Realm*/ )
+{
+ SAL_WARN("dbaccess","OAuthenticationContinuation::setRealm: not supported!");
+}
+
+sal_Bool SAL_CALL OAuthenticationContinuation::canSetUserName( )
+{
+ // we always allow this, even if the database document is read-only. In this case,
+ // it's simply that the user cannot store the new user name.
+ return m_bCanSetUserName;
+}
+
+void SAL_CALL OAuthenticationContinuation::setUserName( const OUString& _rUser )
+{
+ m_sUser = _rUser;
+}
+
+sal_Bool SAL_CALL OAuthenticationContinuation::canSetPassword( )
+{
+ return true;
+}
+
+void SAL_CALL OAuthenticationContinuation::setPassword( const OUString& _rPassword )
+{
+ m_sPassword = _rPassword;
+}
+
+Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberPasswordModes( RememberAuthentication& _reDefault )
+{
+ _reDefault = RememberAuthentication_SESSION;
+ return { _reDefault };
+}
+
+void SAL_CALL OAuthenticationContinuation::setRememberPassword( RememberAuthentication _eRemember )
+{
+ m_bRememberPassword = (RememberAuthentication_NO != _eRemember);
+}
+
+sal_Bool SAL_CALL OAuthenticationContinuation::canSetAccount( )
+{
+ return false;
+}
+
+void SAL_CALL OAuthenticationContinuation::setAccount( const OUString& )
+{
+ SAL_WARN("dbaccess","OAuthenticationContinuation::setAccount: not supported!");
+}
+
+Sequence< RememberAuthentication > SAL_CALL OAuthenticationContinuation::getRememberAccountModes( RememberAuthentication& _reDefault )
+{
+ _reDefault = RememberAuthentication_NO;
+ return { RememberAuthentication_NO };
+}
+
+void SAL_CALL OAuthenticationContinuation::setRememberAccount( RememberAuthentication /*Remember*/ )
+{
+ SAL_WARN("dbaccess","OAuthenticationContinuation::setRememberAccount: not supported!");
+}
+
+namespace {
+
+/** The class OSharedConnectionManager implements a structure to share connections.
+ It owns the master connections which will be disposed when the last connection proxy is gone.
+*/
+// need to hold the digest
+struct TDigestHolder
+{
+ sal_uInt8 m_pBuffer[RTL_DIGEST_LENGTH_SHA1];
+ TDigestHolder()
+ {
+ m_pBuffer[0] = 0;
+ }
+
+};
+
+}
+
+class OSharedConnectionManager : public ::cppu::WeakImplHelper< XEventListener >
+{
+
+ // contains the currently used master connections
+ struct TConnectionHolder
+ {
+ Reference< XConnection > xMasterConnection;
+ oslInterlockedCount nALiveCount;
+ };
+
+ // the less-compare functor, used for the stl::map
+ struct TDigestLess
+ {
+ bool operator() (const TDigestHolder& x, const TDigestHolder& y) const
+ {
+ sal_uInt32 i;
+ for(i=0;i < RTL_DIGEST_LENGTH_SHA1 && (x.m_pBuffer[i] >= y.m_pBuffer[i]); ++i)
+ ;
+ return i < RTL_DIGEST_LENGTH_SHA1;
+ }
+ };
+
+ typedef std::map< TDigestHolder,TConnectionHolder,TDigestLess> TConnectionMap; // holds the master connections
+ typedef std::map< Reference< XConnection >,TConnectionMap::iterator> TSharedConnectionMap;// holds the shared connections
+
+ ::osl::Mutex m_aMutex;
+ TConnectionMap m_aConnections; // remember the master connection in conjunction with the digest
+ TSharedConnectionMap m_aSharedConnection; // the shared connections with conjunction with an iterator into the connections map
+ Reference< XProxyFactory > m_xProxyFactory;
+
+protected:
+ virtual ~OSharedConnectionManager() override;
+
+public:
+ explicit OSharedConnectionManager(const Reference< XComponentContext >& _rxContext);
+
+ void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ Reference<XConnection> getConnection( const OUString& url,
+ const OUString& user,
+ const OUString& password,
+ const Sequence< PropertyValue >& _aInfo,
+ ODatabaseSource* _pDataSource);
+ void addEventListener(const Reference<XConnection>& _rxConnection, TConnectionMap::iterator const & _rIter);
+};
+
+OSharedConnectionManager::OSharedConnectionManager(const Reference< XComponentContext >& _rxContext)
+{
+ m_xProxyFactory.set( ProxyFactory::create( _rxContext ) );
+}
+
+OSharedConnectionManager::~OSharedConnectionManager()
+{
+}
+
+void SAL_CALL OSharedConnectionManager::disposing( const css::lang::EventObject& Source )
+{
+ MutexGuard aGuard(m_aMutex);
+ Reference<XConnection> xConnection(Source.Source,UNO_QUERY);
+ TSharedConnectionMap::const_iterator aFind = m_aSharedConnection.find(xConnection);
+ if ( m_aSharedConnection.end() != aFind )
+ {
+ osl_atomic_decrement(&aFind->second->second.nALiveCount);
+ if ( !aFind->second->second.nALiveCount )
+ {
+ ::comphelper::disposeComponent(aFind->second->second.xMasterConnection);
+ m_aConnections.erase(aFind->second);
+ }
+ m_aSharedConnection.erase(aFind);
+ }
+}
+
+Reference<XConnection> OSharedConnectionManager::getConnection( const OUString& url,
+ const OUString& user,
+ const OUString& password,
+ const Sequence< PropertyValue >& _aInfo,
+ ODatabaseSource* _pDataSource)
+{
+ MutexGuard aGuard(m_aMutex);
+ TConnectionMap::key_type nId;
+ Sequence< PropertyValue > aInfoCopy(_aInfo);
+ sal_Int32 nPos = aInfoCopy.getLength();
+ aInfoCopy.realloc( nPos + 2 );
+ auto pInfoCopy = aInfoCopy.getArray();
+ pInfoCopy[nPos].Name = "TableFilter";
+ pInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableFilter;
+ pInfoCopy[nPos].Name = "TableTypeFilter";
+ pInfoCopy[nPos++].Value <<= _pDataSource->m_pImpl->m_aTableTypeFilter;
+
+ OUString sUser = user;
+ OUString sPassword = password;
+ if ((sUser.isEmpty()) && (sPassword.isEmpty()) && (!_pDataSource->m_pImpl->m_sUser.isEmpty()))
+ { // ease the usage of this method. data source which are intended to have a user automatically
+ // fill in the user/password combination if the caller of this method does not specify otherwise
+ sUser = _pDataSource->m_pImpl->m_sUser;
+ if (!_pDataSource->m_pImpl->m_aPassword.isEmpty())
+ sPassword = _pDataSource->m_pImpl->m_aPassword;
+ }
+
+ ::connectivity::OConnectionWrapper::createUniqueId(url,aInfoCopy,nId.m_pBuffer,sUser,sPassword);
+ TConnectionMap::iterator aIter = m_aConnections.find(nId);
+
+ if ( m_aConnections.end() == aIter )
+ {
+ TConnectionHolder aHolder;
+ aHolder.nALiveCount = 0; // will be incremented by addListener
+ aHolder.xMasterConnection = _pDataSource->buildIsolatedConnection(user,password);
+ aIter = m_aConnections.emplace(nId,aHolder).first;
+ }
+
+ Reference<XConnection> xRet;
+ if ( aIter->second.xMasterConnection.is() )
+ {
+ Reference< XAggregation > xConProxy = m_xProxyFactory->createProxy(aIter->second.xMasterConnection);
+ xRet = new OSharedConnection(xConProxy);
+ m_aSharedConnection.emplace(xRet,aIter);
+ addEventListener(xRet,aIter);
+ }
+
+ return xRet;
+}
+
+void OSharedConnectionManager::addEventListener(const Reference<XConnection>& _rxConnection, TConnectionMap::iterator const & _rIter)
+{
+ Reference<XComponent> xComp(_rxConnection,UNO_QUERY);
+ xComp->addEventListener(this);
+ OSL_ENSURE( m_aConnections.end() != _rIter , "Iterator is end!");
+ osl_atomic_increment(&_rIter->second.nALiveCount);
+}
+
+namespace
+{
+ Sequence< PropertyValue > lcl_filterDriverProperties( const Reference< XDriver >& _xDriver, const OUString& _sUrl,
+ const Sequence< PropertyValue >& _rDataSourceSettings, const AsciiPropertyValue* _pKnownSettings )
+ {
+ if ( _xDriver.is() )
+ {
+ Sequence< DriverPropertyInfo > aDriverInfo(_xDriver->getPropertyInfo(_sUrl,_rDataSourceSettings));
+
+ const PropertyValue* pDataSourceSetting = _rDataSourceSettings.getConstArray();
+ const PropertyValue* pEnd = pDataSourceSetting + _rDataSourceSettings.getLength();
+
+ std::vector< PropertyValue > aRet;
+
+ for ( ; pDataSourceSetting != pEnd ; ++pDataSourceSetting )
+ {
+ bool bAllowSetting = false;
+ const AsciiPropertyValue* pSetting = _pKnownSettings;
+ for ( ; pSetting->AsciiName; ++pSetting )
+ {
+ if ( pDataSourceSetting->Name.equalsAscii( pSetting->AsciiName ) )
+ { // the particular data source setting is known
+
+ const DriverPropertyInfo* pAllowedDriverSetting = aDriverInfo.getConstArray();
+ const DriverPropertyInfo* pDriverSettingsEnd = pAllowedDriverSetting + aDriverInfo.getLength();
+ for ( ; pAllowedDriverSetting != pDriverSettingsEnd; ++pAllowedDriverSetting )
+ {
+ if ( pAllowedDriverSetting->Name.equalsAscii( pSetting->AsciiName ) )
+ { // the driver also allows this setting
+ bAllowSetting = true;
+ break;
+ }
+ }
+ break;
+ }
+ }
+ if ( bAllowSetting || !pSetting->AsciiName )
+ { // if the driver allows this particular setting, or if the setting is completely unknown,
+ // we pass it to the driver
+ aRet.push_back( *pDataSourceSetting );
+ }
+ }
+ if ( !aRet.empty() )
+ return comphelper::containerToSequence(aRet);
+ }
+ return Sequence< PropertyValue >();
+ }
+
+ typedef std::map< OUString, sal_Int32 > PropertyAttributeCache;
+
+ struct IsDefaultAndNotRemoveable
+ {
+ private:
+ const PropertyAttributeCache& m_rAttribs;
+
+ public:
+ explicit IsDefaultAndNotRemoveable( const PropertyAttributeCache& _rAttribs ) : m_rAttribs( _rAttribs ) { }
+
+ bool operator()( const PropertyValue& _rProp )
+ {
+ if ( _rProp.State != PropertyState_DEFAULT_VALUE )
+ return false;
+
+ bool bRemoveable = true;
+
+ PropertyAttributeCache::const_iterator pos = m_rAttribs.find( _rProp.Name );
+ OSL_ENSURE( pos != m_rAttribs.end(), "IsDefaultAndNotRemoveable: illegal property name!" );
+ if ( pos != m_rAttribs.end() )
+ bRemoveable = ( ( pos->second & PropertyAttribute::REMOVABLE ) != 0 );
+
+ return !bRemoveable;
+ }
+ };
+}
+
+
+ODatabaseSource::ODatabaseSource(const ::rtl::Reference<ODatabaseModelImpl>& _pImpl)
+ :ModelDependentComponent( _pImpl )
+ ,ODatabaseSource_Base( getMutex() )
+ ,OPropertySetHelper( ODatabaseSource_Base::rBHelper )
+ , m_Bookmarks(*this, getMutex())
+ ,m_aFlushListeners( getMutex() )
+{
+ // some kind of default
+ SAL_INFO("dbaccess", "DS: ctor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
+}
+
+ODatabaseSource::~ODatabaseSource()
+{
+ SAL_INFO("dbaccess", "DS: dtor: " << std::hex << this << ": " << std::hex << m_pImpl.get() );
+ if ( !ODatabaseSource_Base::rBHelper.bInDispose && !ODatabaseSource_Base::rBHelper.bDisposed )
+ {
+ acquire();
+ dispose();
+ }
+}
+
+void ODatabaseSource::setName( const Reference< XDocumentDataSource >& _rxDocument, const OUString& _rNewName, DBContextAccess )
+{
+ ODatabaseSource& rModelImpl = dynamic_cast< ODatabaseSource& >( *_rxDocument );
+
+ SolarMutexGuard g;
+ if ( rModelImpl.m_pImpl.is() )
+ rModelImpl.m_pImpl->m_sName = _rNewName;
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > ODatabaseSource::getTypes()
+{
+ OTypeCollection aPropertyHelperTypes( cppu::UnoType<XFastPropertySet>::get(),
+ cppu::UnoType<XPropertySet>::get(),
+ cppu::UnoType<XMultiPropertySet>::get());
+
+ return ::comphelper::concatSequences(
+ ODatabaseSource_Base::getTypes(),
+ aPropertyHelperTypes.getTypes()
+ );
+}
+
+Sequence< sal_Int8 > ODatabaseSource::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// css::uno::XInterface
+Any ODatabaseSource::queryInterface( const Type & rType )
+{
+ Any aIface = ODatabaseSource_Base::queryInterface( rType );
+ if ( !aIface.hasValue() )
+ aIface = ::cppu::OPropertySetHelper::queryInterface( rType );
+ return aIface;
+}
+
+void ODatabaseSource::acquire() noexcept
+{
+ ODatabaseSource_Base::acquire();
+}
+
+void ODatabaseSource::release() noexcept
+{
+ ODatabaseSource_Base::release();
+}
+
+void SAL_CALL ODatabaseSource::disposing( const css::lang::EventObject& Source )
+{
+ if ( m_pImpl.is() )
+ m_pImpl->disposing(Source);
+}
+
+// XServiceInfo
+OUString ODatabaseSource::getImplementationName( )
+{
+ return "com.sun.star.comp.dba.ODatabaseSource";
+}
+
+Sequence< OUString > ODatabaseSource::getSupportedServiceNames( )
+{
+ return { SERVICE_SDB_DATASOURCE, "com.sun.star.sdb.DocumentDataSource" };
+}
+
+sal_Bool ODatabaseSource::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+// OComponentHelper
+void ODatabaseSource::disposing()
+{
+ SAL_INFO("dbaccess", "DS: disp: " << std::hex << this << ", " << std::hex << m_pImpl.get() );
+ ODatabaseSource_Base::WeakComponentImplHelperBase::disposing();
+ OPropertySetHelper::disposing();
+
+ EventObject aDisposeEvent(static_cast<XWeak*>(this));
+ m_aFlushListeners.disposeAndClear( aDisposeEvent );
+
+ ODatabaseDocument::clearObjectContainer(m_pImpl->m_xCommandDefinitions);
+ ODatabaseDocument::clearObjectContainer(m_pImpl->m_xTableDefinitions);
+ m_pImpl.clear();
+}
+
+weld::Window* ODatabaseModelImpl::GetFrameWeld()
+{
+ if (m_xDialogParent.is())
+ return Application::GetFrameWeld(m_xDialogParent);
+
+ Reference<XModel> xModel = getModel_noCreate();
+ if (!xModel.is())
+ return nullptr;
+ Reference<XController> xController(xModel->getCurrentController());
+ if (!xController.is())
+ return nullptr;
+ Reference<XFrame> xFrame(xController->getFrame());
+ if (!xFrame.is())
+ return nullptr;
+ Reference<css::awt::XWindow> xWindow(xFrame->getContainerWindow());
+ return Application::GetFrameWeld(xWindow);
+}
+
+Reference< XConnection > ODatabaseSource::buildLowLevelConnection(const OUString& _rUid, const OUString& _rPwd)
+{
+ Reference< XConnection > xReturn;
+
+ Reference< XDriverManager > xManager;
+
+#if ENABLE_FIREBIRD_SDBC
+ bool bIgnoreMigration = false;
+ bool bNeedMigration = false;
+ Reference< XModel > xModel = m_pImpl->getModel_noCreate();
+ if ( xModel)
+ {
+ //See ODbTypeWizDialogSetup::SaveDatabaseDocument
+ ::comphelper::NamedValueCollection::get(xModel->getArgs(), u"IgnoreFirebirdMigration") >>= bIgnoreMigration;
+ }
+ else
+ {
+ //ignore when we don't have a model. E.g. Mailmerge, data sources, fields...
+ bIgnoreMigration = true;
+ }
+
+ if (!officecfg::Office::Common::Misc::ExperimentalMode::get())
+ bIgnoreMigration = true;
+
+ if(!bIgnoreMigration && m_pImpl->m_sConnectURL == "sdbc:embedded:hsqldb")
+ {
+ Reference<XStorage> const xRootStorage = m_pImpl->getOrCreateRootStorage();
+ OUString sMigrEnvVal;
+ osl_getEnvironment(OUString("DBACCESS_HSQL_MIGRATION").pData,
+ &sMigrEnvVal.pData);
+ if(!sMigrEnvVal.isEmpty())
+ bNeedMigration = true;
+ else
+ {
+ Reference<XPropertySet> const xPropSet(xRootStorage, UNO_QUERY_THROW);
+ sal_Int32 nOpenMode(0);
+ if ((xPropSet->getPropertyValue("OpenMode") >>= nOpenMode)
+ && (nOpenMode & css::embed::ElementModes::WRITE)
+ && (!Application::IsHeadlessModeEnabled()))
+ {
+ MigrationWarnDialog aWarnDlg(m_pImpl->GetFrameWeld());
+ bNeedMigration = aWarnDlg.run() == RET_OK;
+ }
+ }
+ if (bNeedMigration)
+ {
+ // back up content xml file if migration was successful
+ static constexpr OUStringLiteral BACKUP_XML_NAME = u"content_before_migration.xml";
+ try
+ {
+ if(xRootStorage->isStreamElement(BACKUP_XML_NAME))
+ xRootStorage->removeElement(BACKUP_XML_NAME);
+ }
+ catch (NoSuchElementException&)
+ {
+ SAL_INFO("dbaccess", "No file content_before_migration.xml found" );
+ }
+ xRootStorage->copyElementTo("content.xml", xRootStorage,
+ BACKUP_XML_NAME);
+
+ m_pImpl->m_sConnectURL = "sdbc:embedded:firebird";
+ }
+ }
+#endif
+
+ try {
+ xManager.set( ConnectionPool::create( m_pImpl->m_aContext ), UNO_QUERY_THROW );
+ } catch( const Exception& ) { }
+ if ( !xManager.is() )
+ // no connection pool installed, fall back to driver manager
+ xManager.set( DriverManager::create(m_pImpl->m_aContext ), UNO_QUERY_THROW );
+
+ OUString sUser(_rUid);
+ OUString sPwd(_rPwd);
+ if ((sUser.isEmpty()) && (sPwd.isEmpty()) && (!m_pImpl->m_sUser.isEmpty()))
+ { // ease the usage of this method. data source which are intended to have a user automatically
+ // fill in the user/password combination if the caller of this method does not specify otherwise
+ sUser = m_pImpl->m_sUser;
+ if (!m_pImpl->m_aPassword.isEmpty())
+ sPwd = m_pImpl->m_aPassword;
+ }
+
+ TranslateId pExceptionMessageId = RID_STR_COULDNOTCONNECT_UNSPECIFIED;
+ if (xManager.is())
+ {
+ sal_Int32 nAdditionalArgs(0);
+ if (!sUser.isEmpty()) ++nAdditionalArgs;
+ if (!sPwd.isEmpty()) ++nAdditionalArgs;
+
+ Sequence< PropertyValue > aUserPwd(nAdditionalArgs);
+ auto aUserPwdRange = asNonConstRange(aUserPwd);
+ sal_Int32 nArgPos = 0;
+ if (!sUser.isEmpty())
+ {
+ aUserPwdRange[ nArgPos ].Name = "user";
+ aUserPwdRange[ nArgPos ].Value <<= sUser;
+ ++nArgPos;
+ }
+ if (!sPwd.isEmpty())
+ {
+ aUserPwdRange[ nArgPos ].Name = "password";
+ aUserPwdRange[ nArgPos ].Value <<= sPwd;
+ }
+ Reference< XDriver > xDriver;
+ try
+ {
+
+ // choose driver
+ Reference< XDriverAccess > xAccessDrivers( xManager, UNO_QUERY );
+ if ( xAccessDrivers.is() )
+ xDriver = xAccessDrivers->getDriverByURL( m_pImpl->m_sConnectURL );
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "ODatabaseSource::buildLowLevelConnection: got a strange exception while analyzing the error" );
+ }
+ if ( !xDriver.is() || !xDriver->acceptsURL( m_pImpl->m_sConnectURL ) )
+ {
+ // Nowadays, it's allowed for a driver to be registered for a given URL, but actually not to accept it.
+ // This is because registration nowadays happens at compile time (by adding respective configuration data),
+ // but acceptance is decided at runtime.
+ pExceptionMessageId = RID_STR_COULDNOTCONNECT_NODRIVER;
+ }
+ else
+ {
+ Sequence< PropertyValue > aDriverInfo = lcl_filterDriverProperties(
+ xDriver,
+ m_pImpl->m_sConnectURL,
+ m_pImpl->m_xSettings->getPropertyValues(),
+ dbaccess::ODatabaseModelImpl::getDefaultDataSourceSettings()
+ );
+
+ if ( m_pImpl->isEmbeddedDatabase() )
+ {
+ sal_Int32 nCount = aDriverInfo.getLength();
+ aDriverInfo.realloc(nCount + 3 );
+ auto pDriverInfo = aDriverInfo.getArray();
+
+ pDriverInfo[nCount].Name = "URL";
+ pDriverInfo[nCount++].Value <<= m_pImpl->getURL();
+
+ pDriverInfo[nCount].Name = "Storage";
+ Reference< css::document::XDocumentSubStorageSupplier> xDocSup( m_pImpl->getDocumentSubStorageSupplier() );
+ pDriverInfo[nCount++].Value <<= xDocSup->getDocumentSubStorage("database",ElementModes::READWRITE);
+
+ pDriverInfo[nCount].Name = "Document";
+ pDriverInfo[nCount++].Value <<= getDatabaseDocument();
+ }
+ if (nAdditionalArgs)
+ xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL, ::comphelper::concatSequences(aUserPwd,aDriverInfo));
+ else
+ xReturn = xManager->getConnectionWithInfo(m_pImpl->m_sConnectURL,aDriverInfo);
+
+ if ( m_pImpl->isEmbeddedDatabase() )
+ {
+ // see ODatabaseSource::flushed for comment on why we register as FlushListener
+ // at the connection
+ Reference< XFlushable > xFlushable( xReturn, UNO_QUERY );
+ if ( xFlushable.is() )
+ FlushNotificationAdapter::installAdapter( xFlushable, this );
+ }
+ }
+ }
+ else
+ pExceptionMessageId = RID_STR_COULDNOTLOAD_MANAGER;
+
+ if ( !xReturn.is() )
+ {
+ OUString sMessage = DBA_RES(pExceptionMessageId)
+ .replaceAll("$name$", m_pImpl->m_sConnectURL);
+
+ SQLContext aContext;
+ aContext.Message = DBA_RES(RID_STR_CONNECTION_REQUEST).
+ replaceFirst("$name$", m_pImpl->m_sConnectURL);
+
+ throwGenericSQLException( sMessage, static_cast< XDataSource* >( this ), Any( aContext ) );
+ }
+
+#if ENABLE_FIREBIRD_SDBC
+ if( bNeedMigration )
+ {
+ Reference< css::document::XDocumentSubStorageSupplier> xDocSup(
+ m_pImpl->getDocumentSubStorageSupplier() );
+ dbahsql::HsqlImporter importer(xReturn,
+ xDocSup->getDocumentSubStorage("database",ElementModes::READWRITE) );
+ importer.importHsqlDatabase(m_pImpl->GetFrameWeld());
+ }
+#endif
+
+ return xReturn;
+}
+
+// OPropertySetHelper
+Reference< XPropertySetInfo > ODatabaseSource::getPropertySetInfo()
+{
+ return createPropertySetInfo( getInfoHelper() ) ;
+}
+
+// comphelper::OPropertyArrayUsageHelper
+::cppu::IPropertyArrayHelper* ODatabaseSource::createArrayHelper( ) const
+{
+ return new ::cppu::OPropertyArrayHelper
+ {
+ {
+ { PROPERTY_INFO, PROPERTY_ID_INFO, cppu::UnoType<Sequence< PropertyValue >>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_ISPASSWORDREQUIRED, PROPERTY_ID_ISPASSWORDREQUIRED, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_ISREADONLY, PROPERTY_ID_ISREADONLY, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_LAYOUTINFORMATION, PROPERTY_ID_LAYOUTINFORMATION, cppu::UnoType<Sequence< PropertyValue >>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_NAME, PROPERTY_ID_NAME, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_NUMBERFORMATSSUPPLIER, PROPERTY_ID_NUMBERFORMATSSUPPLIER, cppu::UnoType<XNumberFormatsSupplier>::get(),
+ css::beans::PropertyAttribute::READONLY | css::beans::PropertyAttribute::TRANSIENT },
+ { PROPERTY_PASSWORD, PROPERTY_ID_PASSWORD, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::TRANSIENT },
+ { PROPERTY_SETTINGS, PROPERTY_ID_SETTINGS, cppu::UnoType<XPropertySet>::get(), css::beans::PropertyAttribute::BOUND | css::beans::PropertyAttribute::READONLY },
+ { PROPERTY_SUPPRESSVERSIONCL, PROPERTY_ID_SUPPRESSVERSIONCL, cppu::UnoType<bool>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_TABLEFILTER, PROPERTY_ID_TABLEFILTER, cppu::UnoType<Sequence< OUString >>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_TABLETYPEFILTER, PROPERTY_ID_TABLETYPEFILTER, cppu::UnoType<Sequence< OUString >>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_URL, PROPERTY_ID_URL, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND },
+ { PROPERTY_USER, PROPERTY_ID_USER, cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::BOUND }
+ }
+ };
+}
+
+// cppu::OPropertySetHelper
+::cppu::IPropertyArrayHelper& ODatabaseSource::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+sal_Bool ODatabaseSource::convertFastPropertyValue(Any & rConvertedValue, Any & rOldValue, sal_Int32 nHandle, const Any& rValue )
+{
+ bool bModified(false);
+ if ( m_pImpl.is() )
+ {
+ switch (nHandle)
+ {
+ case PROPERTY_ID_TABLEFILTER:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableFilter);
+ break;
+ case PROPERTY_ID_TABLETYPEFILTER:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aTableTypeFilter);
+ break;
+ case PROPERTY_ID_USER:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sUser);
+ break;
+ case PROPERTY_ID_PASSWORD:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aPassword);
+ break;
+ case PROPERTY_ID_ISPASSWORDREQUIRED:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bPasswordRequired);
+ break;
+ case PROPERTY_ID_SUPPRESSVERSIONCL:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_bSuppressVersionColumns);
+ break;
+ case PROPERTY_ID_LAYOUTINFORMATION:
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_aLayoutInformation);
+ break;
+ case PROPERTY_ID_URL:
+ {
+ bModified = ::comphelper::tryPropertyValue(rConvertedValue, rOldValue, rValue, m_pImpl->m_sConnectURL);
+ } break;
+ case PROPERTY_ID_INFO:
+ {
+ Sequence<PropertyValue> aValues;
+ if (!(rValue >>= aValues))
+ throw IllegalArgumentException();
+
+ for ( auto const & checkName : std::as_const(aValues) )
+ {
+ if ( checkName.Name.isEmpty() )
+ throw IllegalArgumentException();
+ }
+
+ Sequence< PropertyValue > aSettings = m_pImpl->m_xSettings->getPropertyValues();
+ bModified = aSettings.getLength() != aValues.getLength();
+ if ( !bModified )
+ {
+ const PropertyValue* pInfoIter = aSettings.getConstArray();
+ const PropertyValue* checkValue = aValues.getConstArray();
+ for ( ;!bModified && checkValue != std::cend(aValues) ; ++checkValue,++pInfoIter)
+ {
+ bModified = checkValue->Name != pInfoIter->Name;
+ if ( !bModified )
+ {
+ bModified = checkValue->Value != pInfoIter->Value;
+ }
+ }
+ }
+
+ rConvertedValue = rValue;
+ rOldValue <<= aSettings;
+ }
+ break;
+ default:
+ SAL_WARN("dbaccess", "ODatabaseSource::convertFastPropertyValue: unknown or readonly Property!" );
+ }
+ }
+ return bModified;
+}
+
+namespace
+{
+ struct SelectPropertyName
+ {
+ public:
+ const OUString& operator()( const PropertyValue& _lhs )
+ {
+ return _lhs.Name;
+ }
+ };
+
+ /** sets a new set of property values for a given property bag instance
+
+ The method takes a property bag, and a sequence of property values to set for this bag.
+ Upon return, every property which is not part of the given sequence is
+ <ul><li>removed from the bag, if it's a removable property</li>
+ <li><em>or</em>reset to its default value, if it's not a removable property</li>
+ </ul>.
+
+ @param _rxPropertyBag
+ the property bag to operate on
+ @param _rAllNewPropertyValues
+ the new property values to set for the bag
+ */
+ void lcl_setPropertyValues_resetOrRemoveOther( const Reference< XPropertyBag >& _rxPropertyBag, const Sequence< PropertyValue >& _rAllNewPropertyValues )
+ {
+ // sequences are ugly to operate on
+ std::set<OUString> aToBeSetPropertyNames;
+ std::transform(
+ _rAllNewPropertyValues.begin(),
+ _rAllNewPropertyValues.end(),
+ std::inserter( aToBeSetPropertyNames, aToBeSetPropertyNames.end() ),
+ SelectPropertyName()
+ );
+
+ try
+ {
+ // obtain all properties currently known at the bag
+ Reference< XPropertySetInfo > xPSI( _rxPropertyBag->getPropertySetInfo(), UNO_SET_THROW );
+ const Sequence< Property > aAllExistentProperties( xPSI->getProperties() );
+
+ Reference< XPropertyState > xPropertyState( _rxPropertyBag, UNO_QUERY_THROW );
+
+ // loop through them, and reset resp. default properties which are not to be set
+ for ( auto const & existentProperty : aAllExistentProperties )
+ {
+ if ( aToBeSetPropertyNames.find( existentProperty.Name ) != aToBeSetPropertyNames.end() )
+ continue;
+
+ // this property is not to be set, but currently exists in the bag.
+ // -> Remove it, or reset it to the default.
+ if ( ( existentProperty.Attributes & PropertyAttribute::REMOVABLE ) != 0 )
+ _rxPropertyBag->removeProperty( existentProperty.Name );
+ else
+ xPropertyState->setPropertyToDefault( existentProperty.Name );
+ }
+
+ // finally, set the new property values
+ _rxPropertyBag->setPropertyValues( _rAllNewPropertyValues );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+}
+
+void ODatabaseSource::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
+{
+ if ( !m_pImpl.is() )
+ return;
+
+ switch(nHandle)
+ {
+ case PROPERTY_ID_TABLEFILTER:
+ rValue >>= m_pImpl->m_aTableFilter;
+ break;
+ case PROPERTY_ID_TABLETYPEFILTER:
+ rValue >>= m_pImpl->m_aTableTypeFilter;
+ break;
+ case PROPERTY_ID_USER:
+ rValue >>= m_pImpl->m_sUser;
+ // if the user name has changed, reset the password
+ m_pImpl->m_aPassword.clear();
+ break;
+ case PROPERTY_ID_PASSWORD:
+ rValue >>= m_pImpl->m_aPassword;
+ break;
+ case PROPERTY_ID_ISPASSWORDREQUIRED:
+ m_pImpl->m_bPasswordRequired = any2bool(rValue);
+ break;
+ case PROPERTY_ID_SUPPRESSVERSIONCL:
+ m_pImpl->m_bSuppressVersionColumns = any2bool(rValue);
+ break;
+ case PROPERTY_ID_URL:
+ rValue >>= m_pImpl->m_sConnectURL;
+ break;
+ case PROPERTY_ID_INFO:
+ {
+ Sequence< PropertyValue > aInfo;
+ OSL_VERIFY( rValue >>= aInfo );
+ lcl_setPropertyValues_resetOrRemoveOther( m_pImpl->m_xSettings, aInfo );
+ }
+ break;
+ case PROPERTY_ID_LAYOUTINFORMATION:
+ rValue >>= m_pImpl->m_aLayoutInformation;
+ break;
+ }
+ m_pImpl->setModified(true);
+}
+
+void ODatabaseSource::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
+{
+ if ( !m_pImpl.is() )
+ return;
+
+ switch (nHandle)
+ {
+ case PROPERTY_ID_TABLEFILTER:
+ rValue <<= m_pImpl->m_aTableFilter;
+ break;
+ case PROPERTY_ID_TABLETYPEFILTER:
+ rValue <<= m_pImpl->m_aTableTypeFilter;
+ break;
+ case PROPERTY_ID_USER:
+ rValue <<= m_pImpl->m_sUser;
+ break;
+ case PROPERTY_ID_PASSWORD:
+ rValue <<= m_pImpl->m_aPassword;
+ break;
+ case PROPERTY_ID_ISPASSWORDREQUIRED:
+ rValue <<= m_pImpl->m_bPasswordRequired;
+ break;
+ case PROPERTY_ID_SUPPRESSVERSIONCL:
+ rValue <<= m_pImpl->m_bSuppressVersionColumns;
+ break;
+ case PROPERTY_ID_ISREADONLY:
+ rValue <<= m_pImpl->m_bReadOnly;
+ break;
+ case PROPERTY_ID_INFO:
+ {
+ try
+ {
+ // collect the property attributes of all current settings
+ Reference< XPropertySet > xSettingsAsProps( m_pImpl->m_xSettings, UNO_QUERY_THROW );
+ Reference< XPropertySetInfo > xPST( xSettingsAsProps->getPropertySetInfo(), UNO_SET_THROW );
+ const Sequence< Property > aSettings( xPST->getProperties() );
+ std::map< OUString, sal_Int32 > aPropertyAttributes;
+ for ( auto const & setting : aSettings )
+ {
+ aPropertyAttributes[ setting.Name ] = setting.Attributes;
+ }
+
+ // get all current settings with their values
+ Sequence< PropertyValue > aValues( m_pImpl->m_xSettings->getPropertyValues() );
+
+ // transform them so that only property values which fulfill certain
+ // criteria survive
+ Sequence< PropertyValue > aNonDefaultOrUserDefined( aValues.getLength() );
+ auto [begin, end] = asNonConstRange(aValues);
+ auto pCopyStart = aNonDefaultOrUserDefined.getArray();
+ const PropertyValue* pCopyEnd = std::remove_copy_if(
+ begin,
+ end,
+ pCopyStart,
+ IsDefaultAndNotRemoveable( aPropertyAttributes )
+ );
+ aNonDefaultOrUserDefined.realloc( pCopyEnd - pCopyStart );
+ rValue <<= aNonDefaultOrUserDefined;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ break;
+ case PROPERTY_ID_SETTINGS:
+ rValue <<= m_pImpl->m_xSettings;
+ break;
+ case PROPERTY_ID_URL:
+ rValue <<= m_pImpl->m_sConnectURL;
+ break;
+ case PROPERTY_ID_NUMBERFORMATSSUPPLIER:
+ rValue <<= m_pImpl->getNumberFormatsSupplier();
+ break;
+ case PROPERTY_ID_NAME:
+ rValue <<= m_pImpl->m_sName;
+ break;
+ case PROPERTY_ID_LAYOUTINFORMATION:
+ rValue <<= m_pImpl->m_aLayoutInformation;
+ break;
+ default:
+ SAL_WARN("dbaccess","unknown Property");
+ }
+}
+
+// XDataSource
+void ODatabaseSource::setLoginTimeout(sal_Int32 seconds)
+{
+ ModelMethodGuard aGuard( *this );
+ m_pImpl->m_nLoginTimeout = seconds;
+}
+
+sal_Int32 ODatabaseSource::getLoginTimeout()
+{
+ ModelMethodGuard aGuard( *this );
+ return m_pImpl->m_nLoginTimeout;
+}
+
+// XCompletedConnection
+Reference< XConnection > SAL_CALL ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler )
+{
+ return connectWithCompletion(_rxHandler,false);
+}
+
+Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password)
+{
+ return getConnection(user,password,false);
+}
+
+Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnection( const OUString& user, const OUString& password )
+{
+ return getConnection(user,password,true);
+}
+
+Reference< XConnection > SAL_CALL ODatabaseSource::getIsolatedConnectionWithCompletion( const Reference< XInteractionHandler >& _rxHandler )
+{
+ return connectWithCompletion(_rxHandler,true);
+}
+
+Reference< XConnection > ODatabaseSource::connectWithCompletion( const Reference< XInteractionHandler >& _rxHandler,bool _bIsolated )
+{
+ ModelMethodGuard aGuard( *this );
+
+ if (!_rxHandler.is())
+ {
+ SAL_WARN("dbaccess","ODatabaseSource::connectWithCompletion: invalid interaction handler!");
+ return getConnection(m_pImpl->m_sUser, m_pImpl->m_aPassword,_bIsolated);
+ }
+
+ OUString sUser(m_pImpl->m_sUser), sPassword(m_pImpl->m_aPassword);
+ bool bNewPasswordGiven = false;
+
+ if (m_pImpl->m_bPasswordRequired && sPassword.isEmpty())
+ { // we need a password, but don't have one yet.
+ // -> ask the user
+
+ // build an interaction request
+ // two continuations (Ok and Cancel)
+ rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
+ rtl::Reference<OAuthenticationContinuation> pAuthenticate = new OAuthenticationContinuation;
+
+ // the name which should be referred in the login dialog
+ OUString sServerName( m_pImpl->m_sName );
+ INetURLObject aURLCheck( sServerName );
+ if ( aURLCheck.GetProtocol() != INetProtocol::NotValid )
+ sServerName = aURLCheck.getBase( INetURLObject::LAST_SEGMENT, true, INetURLObject::DecodeMechanism::Unambiguous );
+
+ // the request
+ AuthenticationRequest aRequest;
+ aRequest.ServerName = sServerName;
+ aRequest.HasRealm = aRequest.HasAccount = false;
+ aRequest.HasUserName = aRequest.HasPassword = true;
+ aRequest.UserName = m_pImpl->m_sUser;
+ aRequest.Password = m_pImpl->m_sFailedPassword.isEmpty() ? m_pImpl->m_aPassword : m_pImpl->m_sFailedPassword;
+ rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest(Any(aRequest));
+ // some knittings
+ pRequest->addContinuation(pAbort);
+ pRequest->addContinuation(pAuthenticate);
+
+ // handle the request
+ try
+ {
+ _rxHandler->handle(pRequest);
+ }
+ catch(Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if (!pAuthenticate->wasSelected())
+ return Reference< XConnection >();
+
+ // get the result
+ sUser = m_pImpl->m_sUser = pAuthenticate->getUser();
+ sPassword = pAuthenticate->getPassword();
+
+ if (pAuthenticate->getRememberPassword())
+ {
+ m_pImpl->m_aPassword = pAuthenticate->getPassword();
+ bNewPasswordGiven = true;
+ }
+ m_pImpl->m_sFailedPassword.clear();
+ }
+
+ try
+ {
+ return getConnection(sUser, sPassword,_bIsolated);
+ }
+ catch(Exception&)
+ {
+ if (bNewPasswordGiven)
+ {
+ m_pImpl->m_sFailedPassword = m_pImpl->m_aPassword;
+ // assume that we had an authentication problem. Without this we may, after an unsuccessful connect, while
+ // the user gave us a password and the order to remember it, never allow a password input again (at least
+ // not without restarting the session)
+ m_pImpl->m_aPassword.clear();
+ }
+ throw;
+ }
+}
+
+Reference< XConnection > ODatabaseSource::buildIsolatedConnection(const OUString& user, const OUString& password)
+{
+ Reference< XConnection > xConn;
+ Reference< XConnection > xSdbcConn = buildLowLevelConnection(user, password);
+ OSL_ENSURE( xSdbcConn.is(), "ODatabaseSource::buildIsolatedConnection: invalid return value of buildLowLevelConnection!" );
+ // buildLowLevelConnection is expected to always succeed
+ if ( xSdbcConn.is() )
+ {
+ // build a connection server and return it (no stubs)
+ xConn = new OConnection(*this, xSdbcConn, m_pImpl->m_aContext);
+ }
+ return xConn;
+}
+
+Reference< XConnection > ODatabaseSource::getConnection(const OUString& user, const OUString& password,bool _bIsolated)
+{
+ ModelMethodGuard aGuard( *this );
+
+ Reference< XConnection > xConn;
+ if ( _bIsolated )
+ {
+ xConn = buildIsolatedConnection(user,password);
+ }
+ else
+ { // create a new proxy for the connection
+ if ( !m_pImpl->m_xSharedConnectionManager.is() )
+ {
+ // TODO ideally we could just have one field, but to make that work
+ // we'd need to move OSharedConnectionManager into its own file and header
+ rtl::Reference<OSharedConnectionManager> manager =
+ new OSharedConnectionManager( m_pImpl->m_aContext );
+ m_pImpl->m_pSharedConnectionManager = manager.get();
+ m_pImpl->m_xSharedConnectionManager = m_pImpl->m_pSharedConnectionManager;
+ }
+ xConn = m_pImpl->m_pSharedConnectionManager->getConnection(
+ m_pImpl->m_sConnectURL, user, password, m_pImpl->m_xSettings->getPropertyValues(), this );
+ }
+
+ if ( xConn.is() )
+ {
+ Reference< XComponent> xComp(xConn,UNO_QUERY);
+ if ( xComp.is() )
+ xComp->addEventListener( static_cast< XContainerListener* >( this ) );
+ m_pImpl->m_aConnections.emplace_back(xConn);
+ }
+
+ return xConn;
+}
+
+Reference< XNameAccess > SAL_CALL ODatabaseSource::getBookmarks( )
+{
+ ModelMethodGuard aGuard( *this );
+ // tdf#114596 this may look nutty but see OBookmarkContainer::acquire()
+ return static_cast<XNameContainer*>(&m_Bookmarks);
+}
+
+Reference< XNameAccess > SAL_CALL ODatabaseSource::getQueryDefinitions( )
+{
+ ModelMethodGuard aGuard( *this );
+
+ Reference< XNameAccess > xContainer = m_pImpl->m_xCommandDefinitions;
+ if ( !xContainer.is() )
+ {
+ Any aValue;
+ css::uno::Reference< css::uno::XInterface > xMy(*this);
+ if ( dbtools::getDataSourceSetting(xMy,"CommandDefinitions",aValue) )
+ {
+ OUString sSupportService;
+ aValue >>= sSupportService;
+ if ( !sSupportService.isEmpty() )
+ {
+ Sequence<Any> aArgs{ Any(NamedValue("DataSource",Any(xMy))) };
+ xContainer.set( m_pImpl->m_aContext->getServiceManager()->createInstanceWithArgumentsAndContext(sSupportService, aArgs, m_pImpl->m_aContext), UNO_QUERY);
+ }
+ }
+ if ( !xContainer.is() )
+ {
+ TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_QUERY ) );
+ xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, false );
+ }
+ m_pImpl->m_xCommandDefinitions = xContainer;
+ }
+ return xContainer;
+}
+
+// XTablesSupplier
+Reference< XNameAccess > ODatabaseSource::getTables()
+{
+ ModelMethodGuard aGuard( *this );
+
+ Reference< XNameAccess > xContainer = m_pImpl->m_xTableDefinitions;
+ if ( !xContainer.is() )
+ {
+ TContentPtr& rContainerData( m_pImpl->getObjectContainer( ODatabaseModelImpl::E_TABLE ) );
+ xContainer = new OCommandContainer( m_pImpl->m_aContext, *this, rContainerData, true );
+ m_pImpl->m_xTableDefinitions = xContainer;
+ }
+ return xContainer;
+}
+
+void SAL_CALL ODatabaseSource::flush( )
+{
+ try
+ {
+ // SYNCHRONIZED ->
+ {
+ ModelMethodGuard aGuard( *this );
+
+ typedef ::utl::SharedUNOComponent< XModel, ::utl::CloseableComponent > SharedModel;
+ SharedModel xModel( m_pImpl->getModel_noCreate(), SharedModel::NoTakeOwnership );
+
+ if ( !xModel.is() )
+ xModel.reset( m_pImpl->createNewModel_deliverOwnership(), SharedModel::TakeOwnership );
+
+ Reference< css::frame::XStorable> xStorable( xModel, UNO_QUERY_THROW );
+ xStorable->store();
+ }
+ // <- SYNCHRONIZED
+
+ css::lang::EventObject aFlushedEvent(*this);
+ m_aFlushListeners.notifyEach( &XFlushListener::flushed, aFlushedEvent );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void SAL_CALL ODatabaseSource::flushed( const EventObject& /*rEvent*/ )
+{
+ ModelMethodGuard aGuard( *this );
+
+ // Okay, this is some hack.
+ //
+ // In general, we have the problem that embedded databases write into their underlying storage, which
+ // logically is one of our sub storage, and practically is a temporary file maintained by the
+ // package implementation. As long as we did not commit this storage and our main storage,
+ // the changes made by the embedded database engine are not really reflected in the database document
+ // file. This is Bad (TM) for a "real" database application - imagine somebody entering some
+ // data, and then crashing: For a database application, you would expect that the data still is present
+ // when you connect to the database next time.
+ //
+ // Since this is a conceptual problem as long as we do use those ZIP packages (in fact, we *cannot*
+ // provide the desired functionality as long as we do not have a package format which allows O(1) writes),
+ // we cannot completely fix this. However, we can relax the problem by committing more often - often
+ // enough so that data loss is more seldom, and seldom enough so that there's no noticeable performance
+ // decrease.
+ //
+ // For this, we introduced a few places which XFlushable::flush their connections, and register as
+ // XFlushListener at the embedded connection (which needs to provide the XFlushable functionality).
+ // Then, when the connection is flushed, we commit both the database storage and our main storage.
+ //
+ // #i55274#
+
+ OSL_ENSURE( m_pImpl->isEmbeddedDatabase(), "ODatabaseSource::flushed: no embedded database?!" );
+ bool bWasModified = m_pImpl->m_bModified;
+ m_pImpl->commitEmbeddedStorage();
+ m_pImpl->setModified( bWasModified );
+}
+
+void SAL_CALL ODatabaseSource::addFlushListener( const Reference< css::util::XFlushListener >& _xListener )
+{
+ m_aFlushListeners.addInterface(_xListener);
+}
+
+void SAL_CALL ODatabaseSource::removeFlushListener( const Reference< css::util::XFlushListener >& _xListener )
+{
+ m_aFlushListeners.removeInterface(_xListener);
+}
+
+void SAL_CALL ODatabaseSource::elementInserted( const ContainerEvent& /*Event*/ )
+{
+ ModelMethodGuard aGuard( *this );
+ if ( m_pImpl.is() )
+ m_pImpl->setModified(true);
+}
+
+void SAL_CALL ODatabaseSource::elementRemoved( const ContainerEvent& /*Event*/ )
+{
+ ModelMethodGuard aGuard( *this );
+ if ( m_pImpl.is() )
+ m_pImpl->setModified(true);
+}
+
+void SAL_CALL ODatabaseSource::elementReplaced( const ContainerEvent& /*Event*/ )
+{
+ ModelMethodGuard aGuard( *this );
+ if ( m_pImpl.is() )
+ m_pImpl->setModified(true);
+}
+
+// XDocumentDataSource
+Reference< XOfficeDatabaseDocument > SAL_CALL ODatabaseSource::getDatabaseDocument()
+{
+ ModelMethodGuard aGuard( *this );
+
+ Reference< XModel > xModel( m_pImpl->getModel_noCreate() );
+ if ( !xModel.is() )
+ xModel = m_pImpl->createNewModel_deliverOwnership();
+
+ return Reference< XOfficeDatabaseDocument >( xModel, UNO_QUERY_THROW );
+}
+
+void SAL_CALL ODatabaseSource::initialize( css::uno::Sequence< css::uno::Any > const & rArguments)
+{
+ ::comphelper::NamedValueCollection aProperties( rArguments );
+ if (aProperties.has("ParentWindow"))
+ aProperties.get("ParentWindow") >>= m_pImpl->m_xDialogParent;
+}
+
+Reference< XInterface > ODatabaseSource::getThis() const
+{
+ return *const_cast< ODatabaseSource* >( this );
+}
+
+} // namespace dbaccess
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dba_ODatabaseSource(css::uno::XComponentContext* context,
+ css::uno::Sequence<css::uno::Any> const &)
+{
+ css::uno::Reference<XInterface> inst(
+ DatabaseContext::create(context)->createInstance());
+ inst->acquire();
+ return inst.get();
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/datasource.hxx b/dbaccess/source/core/dataaccess/datasource.hxx
new file mode 100644
index 000000000..5b5985eac
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/datasource.hxx
@@ -0,0 +1,220 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/sdb/XBookmarksSupplier.hpp>
+#include <com/sun/star/sdb/XQueryDefinitionsSupplier.hpp>
+#include <com/sun/star/sdbc/XIsolatedConnection.hpp>
+#include <com/sun/star/util/XNumberFormatter.hpp>
+#include <com/sun/star/document/XEventListener.hpp>
+#include <com/sun/star/util/XFlushable.hpp>
+#include <cppuhelper/propshlp.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <com/sun/star/embed/XTransactionListener.hpp>
+#include <apitools.hxx>
+#include <bookmarkcontainer.hxx>
+#include <rtl/ref.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/sdb/XCompletedConnection.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <ContentHelper.hxx>
+#include <com/sun/star/document/XStorageBasedDocument.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/util/XRefreshable.hpp>
+#include <com/sun/star/sdb/XDocumentDataSource.hpp>
+#include <ModelImpl.hxx>
+
+namespace dbaccess
+{
+
+class OSharedConnectionManager;
+
+// ODatabaseSource
+typedef ::cppu::WeakComponentImplHelper< css::lang::XServiceInfo
+ , css::sdbc::XDataSource
+ , css::sdb::XBookmarksSupplier
+ , css::sdb::XQueryDefinitionsSupplier
+ , css::sdb::XCompletedConnection
+ , css::container::XContainerListener
+ , css::sdbc::XIsolatedConnection
+ , css::sdbcx::XTablesSupplier
+ , css::util::XFlushable
+ , css::util::XFlushListener
+ , css::sdb::XDocumentDataSource
+ , css::lang::XInitialization
+ > ODatabaseSource_Base;
+
+class ODatabaseSource :public ModelDependentComponent // must be first
+ ,public ODatabaseSource_Base
+ ,public ::cppu::OPropertySetHelper
+ ,public ::comphelper::OPropertyArrayUsageHelper < ODatabaseSource >
+{
+ friend class ODatabaseContext;
+ friend class OConnection;
+ friend class OSharedConnectionManager;
+
+private:
+ using ODatabaseSource_Base::rBHelper;
+ // note: this thing uses the ref-count of "this", see OBookmarkContainer::acquire!
+ OBookmarkContainer m_Bookmarks;
+ ::comphelper::OInterfaceContainerHelper3<css::util::XFlushListener> m_aFlushListeners;
+
+private:
+ virtual ~ODatabaseSource() override;
+
+public:
+ explicit ODatabaseSource( const ::rtl::Reference< ODatabaseModelImpl >& _pImpl );
+
+ struct DBContextAccess { friend class ODatabaseContext; private: DBContextAccess() { } };
+
+ /** sets a new name for the data source
+
+ The name of a data source (our m_sName member) is the registration name, *if* the
+ data source actually *is* registered at the database context.
+
+ Normally, this name is passed at time of creation of the ODatabaseModelImpl instance,
+ but if a newly created data source is registered, then it must be possible to propagate
+ the new registration name.
+ */
+ static void setName(
+ const css::uno::Reference< css::sdb::XDocumentDataSource >& _rxDocument,
+ const OUString& _rNewName,
+ DBContextAccess
+ );
+
+ // XContainerListener
+ virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override;
+ // css::sdbcx::XTablesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables( ) override;
+
+// css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+// css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+// css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+// OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+// css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+// comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+// cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override;
+
+// css::sdb::XCompletedConnection
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL connectWithCompletion( const css::uno::Reference< css::task::XInteractionHandler >& handler ) override;
+
+// css::sdbc::XDataSource
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( const OUString& user, const OUString& password ) override;
+ virtual void SAL_CALL setLoginTimeout( sal_Int32 seconds ) override;
+ virtual sal_Int32 SAL_CALL getLoginTimeout( ) override;
+
+//::css::sdb::XBookmarksSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getBookmarks( ) override;
+
+//::css::sdb::XQueryDefinitionsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getQueryDefinitions( ) override;
+
+// css::sdbc::XIsolatedConnection
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getIsolatedConnection( const OUString& user, const OUString& password ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getIsolatedConnectionWithCompletion( const css::uno::Reference< css::task::XInteractionHandler >& handler ) override;
+
+// XFlushable
+ virtual void SAL_CALL flush( ) override;
+ virtual void SAL_CALL addFlushListener( const css::uno::Reference< css::util::XFlushListener >& l ) override;
+ virtual void SAL_CALL removeFlushListener( const css::uno::Reference< css::util::XFlushListener >& l ) override;
+
+ // XFlushListener
+ virtual void SAL_CALL flushed( const css::lang::EventObject& rEvent ) override;
+
+ // XDocumentDataSource
+ virtual css::uno::Reference< css::sdb::XOfficeDatabaseDocument > SAL_CALL getDatabaseDocument() override;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+protected:
+ // ModelDependentComponent overridables
+ virtual css::uno::Reference< css::uno::XInterface > getThis() const override;
+
+private:
+// helper
+ /** open a connection for the current settings. this is the simple connection we get from the driver
+ manager, so it can be used as a master for a "high level" sdb connection.
+ */
+ css::uno::Reference< css::sdbc::XConnection > buildLowLevelConnection(
+ const OUString& _rUid, const OUString& _rPwd
+ );
+
+ css::uno::Reference< css::sdbc::XConnection > buildIsolatedConnection(
+ const OUString& user, const OUString& password
+ );
+
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::sdbc::XConnection > getConnection( const OUString& user, const OUString& password , bool _bIsolated);
+ /// @throws css::sdbc::SQLException
+ /// @throws css::uno::RuntimeException
+ css::uno::Reference< css::sdbc::XConnection > connectWithCompletion( const css::uno::Reference< css::task::XInteractionHandler >& handler , bool _bIsolated);
+
+protected:
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/definitioncontainer.cxx b/dbaccess/source/core/dataaccess/definitioncontainer.cxx
new file mode 100644
index 000000000..81d8b0302
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/definitioncontainer.cxx
@@ -0,0 +1,679 @@
+/* -*- 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 <definitioncontainer.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+
+#include <tools/diagnose_ex.h>
+#include <o3tl/safeint.hxx>
+#include <osl/diagnose.h>
+#include <comphelper/enumhelper.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <com/sun/star/lang/IndexOutOfBoundsException.hpp>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#include <comphelper/servicehelper.hxx>
+#include <comphelper/types.hxx>
+#include <rtl/ref.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::sdbcx;
+using namespace ::com::sun::star::sdb;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+using namespace ::com::sun::star::ucb;
+
+namespace dbaccess
+{
+
+// ODefinitionContainer_Impl
+void ODefinitionContainer_Impl::erase( const TContentPtr& _pDefinition )
+{
+ NamedDefinitions::const_iterator aPos = find( _pDefinition );
+ if ( aPos != end() )
+ m_aDefinitions.erase( aPos );
+}
+
+ODefinitionContainer_Impl::const_iterator ODefinitionContainer_Impl::find( const TContentPtr& _pDefinition ) const
+{
+ return std::find_if(
+ m_aDefinitions.begin(),
+ m_aDefinitions.end(),
+ [&_pDefinition] (const NamedDefinitions::value_type& namedDef) {
+ return namedDef.second == _pDefinition;
+ });
+}
+
+ODefinitionContainer_Impl::iterator ODefinitionContainer_Impl::find( const TContentPtr& _pDefinition )
+{
+ return std::find_if(
+ m_aDefinitions.begin(),
+ m_aDefinitions.end(),
+ [&_pDefinition] (const NamedDefinitions::value_type& namedDef) {
+ return namedDef.second == _pDefinition;
+ });
+}
+
+// ODefinitionContainer
+
+ODefinitionContainer::ODefinitionContainer( const Reference< XComponentContext >& _xORB
+ , const Reference< XInterface >& _xParentContainer
+ , const TContentPtr& _pImpl
+ , bool _bCheckSlash
+ )
+ :OContentHelper(_xORB,_xParentContainer,_pImpl)
+ ,m_aApproveListeners(m_aMutex)
+ ,m_aContainerListeners(m_aMutex)
+ ,m_bInPropertyChange(false)
+ ,m_bCheckSlash(_bCheckSlash)
+{
+ assert(m_pImpl);
+ m_pImpl->m_aProps.bIsDocument = false;
+ m_pImpl->m_aProps.bIsFolder = true;
+
+ const ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
+ for (auto const& definition : rDefinitions)
+ m_aDocuments.push_back(
+ m_aDocumentMap.emplace(definition.first, Documents::mapped_type() ).first );
+
+}
+
+void SAL_CALL ODefinitionContainer::disposing()
+{
+ OContentHelper::disposing();
+
+ MutexGuard aGuard(m_aMutex);
+
+ // say goodbye to our listeners
+ EventObject aEvt(*this);
+ m_aApproveListeners.disposeAndClear(aEvt);
+ m_aContainerListeners.disposeAndClear(aEvt);
+
+ // dispose our elements
+ for (auto const& elem : m_aDocumentMap)
+ {
+ Reference<XContent> xProp = elem.second;
+ if ( xProp.is() )
+ {
+ removeObjectListener(xProp);
+ ::comphelper::disposeComponent(xProp);
+ }
+ }
+
+ // remove our elements
+ m_aDocuments.clear();
+ // !!! do this before clearing the map which the vector elements refer to !!!
+ m_aDocumentMap.clear();
+}
+
+ODefinitionContainer::~ODefinitionContainer()
+{
+}
+
+IMPLEMENT_FORWARD_XINTERFACE2( ODefinitionContainer,OContentHelper,ODefinitionContainer_Base)
+css::uno::Sequence< css::uno::Type > ODefinitionContainer::getTypes()
+{
+ return ::comphelper::concatSequences(
+ OContentHelper::getTypes( ),
+ ODefinitionContainer_Base::getTypes( )
+ );
+}
+
+
+css::uno::Sequence<sal_Int8> ODefinitionContainer::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+// XServiceInfo
+OUString SAL_CALL ODefinitionContainer::getImplementationName( )
+{
+ return "com.sun.star.sdb.ODefinitionContainer";
+}
+
+Sequence< OUString > SAL_CALL ODefinitionContainer::getSupportedServiceNames( )
+{
+ return { "com.sun.star.sdb.DefinitionContainer", "com.sun.star.ucb.Content" };
+}
+
+// XNameContainer
+void SAL_CALL ODefinitionContainer::insertByName( const OUString& _rName, const Any& aElement )
+{
+ ResettableMutexGuard aGuard(m_aMutex);
+
+ // approve the new object
+ Reference< XContent > xNewElement(aElement,UNO_QUERY);
+ approveNewObject( _rName, xNewElement ); // will throw if necessary
+
+ notifyByName( aGuard, _rName, xNewElement, nullptr, E_INSERTED, ApproveListeners );
+ implAppend( _rName, xNewElement );
+ notifyByName( aGuard, _rName, xNewElement, nullptr, E_INSERTED, ContainerListemers );
+}
+
+void SAL_CALL ODefinitionContainer::removeByName( const OUString& _rName )
+{
+ ResettableMutexGuard aGuard(m_aMutex);
+
+ // check the arguments
+ if (_rName.isEmpty())
+ throw IllegalArgumentException();
+
+ if (!checkExistence(_rName))
+ throw NoSuchElementException(_rName,*this);
+
+ // the old element (for the notifications)
+ Reference< XContent > xOldElement = implGetByName( _rName, impl_haveAnyListeners_nothrow() );
+
+ // do the removal
+ notifyByName( aGuard, _rName, nullptr, xOldElement, E_REMOVED, ApproveListeners );
+ implRemove( _rName );
+ notifyByName( aGuard, _rName, nullptr, xOldElement, E_REMOVED, ContainerListemers );
+
+ removeObjectListener( xOldElement );
+ disposeComponent(xOldElement);
+}
+
+// XNameReplace
+void SAL_CALL ODefinitionContainer::replaceByName( const OUString& _rName, const Any& aElement )
+{
+ ResettableMutexGuard aGuard(m_aMutex);
+
+ try
+ {
+ // let derived classes approve the new object
+ Reference< XContent > xNewElement(aElement,UNO_QUERY);
+ approveNewObject( _rName, xNewElement ); // will throw if necessary
+
+ // the old element (for the notifications)
+ Reference< XContent > xOldElement = implGetByName( _rName, impl_haveAnyListeners_nothrow() );
+
+ notifyByName( aGuard, _rName, xNewElement, xOldElement, E_REPLACED, ApproveListeners );
+ implReplace( _rName, xNewElement );
+ notifyByName( aGuard, _rName, xNewElement, xOldElement, E_REPLACED, ContainerListemers );
+
+ // and dispose it
+ disposeComponent(xOldElement);
+ }
+ catch (const RuntimeException&)
+ {
+ throw;
+ }
+ catch (const NoSuchElementException&)
+ {
+ throw;
+ }
+ catch (const WrappedTargetException&)
+ {
+ throw;
+ }
+ catch (const Exception& e)
+ {
+ css::uno::Any a(cppu::getCaughtException());
+ throw css::lang::WrappedTargetException(
+ "wrapped Exception " + e.Message,
+ css::uno::Reference<css::uno::XInterface>(), a);
+ }
+}
+
+namespace
+{
+ typedef Reference< XVeto > ( SAL_CALL XContainerApproveListener::*ContainerApprovalMethod )( const ContainerEvent& );
+
+ struct RaiseExceptionFromVeto
+ {
+ private:
+ ContainerApprovalMethod m_pMethod;
+ const ContainerEvent& m_rEvent;
+
+ public:
+ explicit RaiseExceptionFromVeto( ContainerApprovalMethod _pMethod, const ContainerEvent& _rEvent )
+ :m_pMethod( _pMethod )
+ ,m_rEvent( _rEvent )
+ {
+ }
+
+ void operator()( const Reference< XContainerApproveListener >& Listener ) const
+ {
+ Reference< XVeto > xVeto = (Listener.get()->*m_pMethod)( m_rEvent );
+ if ( !xVeto.is() )
+ return;
+
+ Any eVetoDetails = xVeto->getDetails();
+
+ IllegalArgumentException aIllegalArgumentError;
+ if ( eVetoDetails >>= aIllegalArgumentError )
+ throw aIllegalArgumentError;
+
+ WrappedTargetException aWrappedError;
+ if ( eVetoDetails >>= aWrappedError )
+ throw aWrappedError;
+
+ throw WrappedTargetException( xVeto->getReason(), Listener, eVetoDetails );
+ }
+ };
+}
+
+void ODefinitionContainer::notifyByName( ResettableMutexGuard& _rGuard, const OUString& _rName,
+ const Reference< XContent >& _xNewElement, const Reference< XContent >& _xOldElement,
+ ContainerOperation _eOperation, ListenerType _eType )
+{
+ bool bApprove = ( _eType == ApproveListeners );
+
+ ::comphelper::OInterfaceContainerHelper2& rContainer( bApprove ? m_aApproveListeners : m_aContainerListeners );
+ if ( !rContainer.getLength() )
+ return;
+
+ ContainerEvent aEvent( *this, Any( _rName ), Any( _xNewElement ), Any( _xOldElement ) );
+
+ _rGuard.clear();
+ switch ( _eOperation )
+ {
+ case E_INSERTED:
+ if ( bApprove )
+ rContainer.forEach< XContainerApproveListener, RaiseExceptionFromVeto >(
+ RaiseExceptionFromVeto( &XContainerApproveListener::approveInsertElement, aEvent ) );
+ else
+ rContainer.notifyEach( &XContainerListener::elementInserted, aEvent );
+ break;
+ case E_REPLACED:
+ if ( bApprove )
+ rContainer.forEach< XContainerApproveListener, RaiseExceptionFromVeto >(
+ RaiseExceptionFromVeto( &XContainerApproveListener::approveReplaceElement, aEvent ) );
+ else
+ rContainer.notifyEach( &XContainerListener::elementReplaced, aEvent );
+ break;
+ case E_REMOVED:
+ if ( bApprove )
+ rContainer.forEach< XContainerApproveListener, RaiseExceptionFromVeto >(
+ RaiseExceptionFromVeto( &XContainerApproveListener::approveRemoveElement, aEvent ) );
+ else
+ rContainer.notifyEach( &XContainerListener::elementRemoved, aEvent );
+ break;
+ }
+
+ if ( bApprove )
+ _rGuard.reset();
+}
+
+void SAL_CALL ODefinitionContainer::addContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ if (_rxListener.is())
+ m_aContainerListeners.addInterface(_rxListener);
+}
+
+void SAL_CALL ODefinitionContainer::removeContainerListener( const Reference< XContainerListener >& _rxListener )
+{
+ if (_rxListener.is())
+ m_aContainerListeners.removeInterface(_rxListener);
+}
+
+void SAL_CALL ODefinitionContainer::addContainerApproveListener( const Reference< XContainerApproveListener >& Listener )
+{
+ if ( Listener.is() )
+ m_aApproveListeners.addInterface( Listener );
+}
+
+void SAL_CALL ODefinitionContainer::removeContainerApproveListener( const Reference< XContainerApproveListener >& Listener )
+{
+ if ( Listener.is() )
+ m_aApproveListeners.removeInterface( Listener );
+}
+
+// XElementAccess
+Type SAL_CALL ODefinitionContainer::getElementType( )
+{
+ return cppu::UnoType<XContent>::get();
+}
+
+sal_Bool SAL_CALL ODefinitionContainer::hasElements( )
+{
+ MutexGuard aGuard(m_aMutex);
+ return !m_aDocuments.empty();
+}
+
+// XEnumerationAccess
+Reference< XEnumeration > SAL_CALL ODefinitionContainer::createEnumeration( )
+{
+ MutexGuard aGuard(m_aMutex);
+ return new ::comphelper::OEnumerationByIndex(static_cast<XIndexAccess*>(this));
+}
+
+// XIndexAccess
+sal_Int32 SAL_CALL ODefinitionContainer::getCount( )
+{
+ MutexGuard aGuard(m_aMutex);
+ return m_aDocuments.size();
+}
+
+Any SAL_CALL ODefinitionContainer::getByIndex( sal_Int32 _nIndex )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ if ((_nIndex < 0) || (o3tl::make_unsigned(_nIndex) >= m_aDocuments.size()))
+ throw IndexOutOfBoundsException();
+
+ Documents::iterator aPos = m_aDocuments[_nIndex];
+ Reference<XContent> xProp = aPos->second;
+ if (!xProp.is())
+ { // that's the first access to the object
+ // -> create it
+ xProp = createObject(aPos->first);
+ aPos->second = Documents::mapped_type();
+ // and update the name-access map
+ }
+
+ return Any(xProp);
+}
+
+Any SAL_CALL ODefinitionContainer::getByName( const OUString& _rName )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ return Any( implGetByName( _rName, true ) );
+}
+
+Reference< XContent > ODefinitionContainer::implGetByName(const OUString& _rName, bool _bReadIfNecessary)
+{
+ Documents::iterator aMapPos = m_aDocumentMap.find(_rName);
+ if (aMapPos == m_aDocumentMap.end())
+ throw NoSuchElementException(_rName,*this);
+
+ Reference< XContent > xProp = aMapPos->second;
+
+ if (_bReadIfNecessary && !xProp.is())
+ { // the object has never been accessed before, so we have to read it now
+ // (that's the expensive part)
+
+ // create the object and insert it into the map
+ xProp = createObject(_rName);
+ aMapPos->second = xProp;
+ addObjectListener(xProp);
+ }
+
+ return xProp;
+}
+
+Sequence< OUString > SAL_CALL ODefinitionContainer::getElementNames( )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ Sequence< OUString > aNames(m_aDocumentMap.size());
+ OUString* pNames = aNames.getArray();
+ for (auto const& elem : m_aDocumentMap)
+ {
+ *pNames = elem.first;
+ ++pNames;
+ }
+
+ return aNames;
+}
+
+sal_Bool SAL_CALL ODefinitionContainer::hasByName( const OUString& _rName )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ return checkExistence(_rName);
+}
+
+void SAL_CALL ODefinitionContainer::disposing( const EventObject& _rSource )
+{
+ MutexGuard aGuard(m_aMutex);
+ Reference< XContent > xSource(_rSource.Source, UNO_QUERY);
+ // it's one of our documents...
+ for (auto & elem : m_aDocumentMap)
+ {
+ if ( xSource == elem.second.get() )
+ {
+ removeObjectListener(xSource);
+ // and clear our document map/vector, so the object will be recreated on next access
+ elem.second = Documents::mapped_type();
+ }
+ }
+}
+
+void ODefinitionContainer::implRemove(const OUString& _rName)
+{
+ // from the object maps
+ Documents::const_iterator aFind = m_aDocumentMap.find(_rName);
+ if ( aFind != m_aDocumentMap.end() )
+ {
+ m_aDocuments.erase( std::find(m_aDocuments.begin(),m_aDocuments.end(),aFind));
+ m_aDocumentMap.erase(aFind);
+
+ getDefinitions().erase( _rName );
+
+ notifyDataSourceModified();
+ }
+}
+
+namespace
+{
+ bool lcl_ensureName( const Reference< XContent >& _rxContent, const OUString& _rName )
+ {
+ if ( !_rxContent.is() )
+ return true;
+
+ // obtain the current name. If it's the same as the new one,
+ // don't do anything
+ try
+ {
+ Reference< XPropertySet > xProps( _rxContent, UNO_QUERY );
+ if ( xProps.is() )
+ {
+ OUString sCurrentName;
+ OSL_VERIFY( xProps->getPropertyValue( PROPERTY_NAME ) >>= sCurrentName );
+ if ( sCurrentName == _rName )
+ return true;
+ }
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "lcl_ensureName: caught an exception while obtaining the current name!" );
+ }
+
+ // set the new name
+ Reference< XRename > xRename( _rxContent, UNO_QUERY );
+ OSL_ENSURE( xRename.is(), "lcl_ensureName: invalid content (not renameable)!" );
+ if ( !xRename.is() )
+ return false;
+ try
+ {
+ xRename->rename( _rName );
+ return true;
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "lcl_ensureName" );
+ }
+ return false;
+ }
+}
+
+void ODefinitionContainer::implAppend(const OUString& _rName, const Reference< XContent >& _rxNewObject)
+{
+ MutexGuard aGuard(m_aMutex);
+ try
+ {
+ Reference<XChild> xChild(_rxNewObject,UNO_QUERY);
+ if ( xChild.is() )
+ xChild->setParent(static_cast<OWeakObject*>(this));
+
+ ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
+ ODefinitionContainer_Impl::const_iterator aFind = rDefinitions.find( _rName );
+ if ( aFind == rDefinitions.end() )
+ {
+ // ensure that the new object has the proper name.
+ // Somebody could create an object with name "foo", and insert it as "bar"
+ // into a container. In this case, we need to ensure that the object name
+ // is also "bar"
+ // #i44786#
+ lcl_ensureName( _rxNewObject, _rName );
+
+ ::rtl::Reference< OContentHelper > pContent = comphelper::getFromUnoTunnel<OContentHelper>( _rxNewObject );
+ if ( pContent.is() )
+ {
+ TContentPtr pImpl = pContent->getImpl();
+ rDefinitions.erase( pImpl );
+ pImpl->m_aProps.aTitle = _rName;
+ rDefinitions.insert( _rName, pImpl );
+ }
+ }
+
+ m_aDocuments.push_back(m_aDocumentMap.emplace(_rName,_rxNewObject).first);
+ notifyDataSourceModified();
+ // now update our structures
+ if ( _rxNewObject.is() )
+ addObjectListener(_rxNewObject);
+ }
+ catch(Exception&)
+ {
+ OSL_FAIL("ODefinitionContainer::implAppend: caught something !");
+ }
+}
+
+void ODefinitionContainer::implReplace(const OUString& _rName, const Reference< XContent >& _rxNewObject)
+{
+ OSL_ENSURE(checkExistence(_rName), "ODefinitionContainer::implReplace : invalid name !");
+
+ Documents::iterator aFind = m_aDocumentMap.find(_rName);
+ removeObjectListener(aFind->second);
+ aFind->second = _rxNewObject;
+ addObjectListener(aFind->second);
+}
+
+void ODefinitionContainer::approveNewObject(const OUString& _sName,const Reference< XContent >& _rxObject) const
+{
+ // check the arguments
+ if ( _sName.isEmpty() )
+ throw IllegalArgumentException(
+ DBA_RES( RID_STR_NAME_MUST_NOT_BE_EMPTY ),
+ *this,
+ 0 );
+
+ if ( m_bCheckSlash && _sName.indexOf( '/' ) != -1 )
+ throw IllegalArgumentException(
+ m_aErrorHelper.getErrorMessage( ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES ),
+ *this,
+ 0 );
+
+ if ( !_rxObject.is() )
+ throw IllegalArgumentException(
+ DBA_RES( RID_STR_NO_NULL_OBJECTS_IN_CONTAINER ),
+ *this,
+ 0 );
+
+ const ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
+ if ( rDefinitions.find( _sName ) != rDefinitions.end() )
+ throw ElementExistException(
+ DBA_RES( RID_STR_NAME_ALREADY_USED ),
+ *this );
+
+ ::rtl::Reference< OContentHelper > pContent( comphelper::getFromUnoTunnel<OContentHelper>( _rxObject ) );
+ if ( !pContent.is() )
+ throw IllegalArgumentException(
+ DBA_RES( RID_STR_OBJECT_CONTAINER_MISMATCH ),
+ *this,
+ 1 );
+
+ if ( rDefinitions.find( pContent->getImpl() ) != rDefinitions.end() )
+ throw ElementExistException(
+ DBA_RES( RID_STR_OBJECT_ALREADY_CONTAINED ),
+ *this );
+}
+
+// XPropertyChangeListener
+void SAL_CALL ODefinitionContainer::propertyChange( const PropertyChangeEvent& evt )
+{
+ if( evt.PropertyName != PROPERTY_NAME && evt.PropertyName != "Title" )
+ return;
+
+ MutexGuard aGuard(m_aMutex);
+
+ m_bInPropertyChange = true;
+ try
+ {
+ OUString sNewName,sOldName;
+ evt.OldValue >>= sOldName;
+ evt.NewValue >>= sNewName;
+ Reference<XContent> xContent( evt.Source, UNO_QUERY );
+ removeObjectListener( xContent );
+ implRemove( sOldName );
+ implAppend( sNewName, xContent );
+ }
+ catch(const Exception& ex)
+ {
+ css::uno::Any anyEx = cppu::getCaughtException();
+ throw css::lang::WrappedTargetRuntimeException( ex.Message,
+ nullptr, anyEx );
+ }
+ m_bInPropertyChange = false;
+}
+
+// XVetoableChangeListener
+void SAL_CALL ODefinitionContainer::vetoableChange( const PropertyChangeEvent& aEvent )
+{
+ MutexGuard aGuard(m_aMutex);
+
+ if( aEvent.PropertyName == PROPERTY_NAME || aEvent.PropertyName == "Title" )
+ {
+ OUString sNewName;
+ aEvent.NewValue >>= sNewName;
+ if(hasByName(sNewName))
+ throw PropertyVetoException();
+ }
+}
+
+void ODefinitionContainer::addObjectListener(const Reference< XContent >& _xNewObject)
+{
+ OSL_ENSURE(_xNewObject.is(),"ODefinitionContainer::addObjectListener: Object is null!");
+ Reference<XPropertySet> xProp(_xNewObject,UNO_QUERY);
+ if ( xProp.is() )
+ {
+ xProp->addPropertyChangeListener(PROPERTY_NAME, this);
+ xProp->addVetoableChangeListener(PROPERTY_NAME, this);
+ }
+}
+
+void ODefinitionContainer::removeObjectListener(const Reference< XContent >& _xNewObject)
+{
+ Reference<XPropertySet> xProp(_xNewObject,UNO_QUERY);
+ if ( xProp.is() )
+ {
+ xProp->removePropertyChangeListener(PROPERTY_NAME, this);
+ xProp->removeVetoableChangeListener(PROPERTY_NAME, this);
+ }
+}
+
+bool ODefinitionContainer::checkExistence(const OUString& _rName)
+{
+ return m_aDocumentMap.find(_rName) != m_aDocumentMap.end();
+}
+
+}
+
+// namespace dbaccess
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documentcontainer.cxx b/dbaccess/source/core/dataaccess/documentcontainer.cxx
new file mode 100644
index 000000000..6a9f17adb
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documentcontainer.cxx
@@ -0,0 +1,770 @@
+/* -*- 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 "documentcontainer.hxx"
+#include <stringconstants.hxx>
+#include "documentdefinition.hxx"
+#include <ModelImpl.hxx>
+#include <com/sun/star/ucb/OpenCommandArgument2.hpp>
+#include <com/sun/star/ucb/OpenMode.hpp>
+#include <connectivity/dbtools.hxx>
+#include "myucp_resultset.hxx"
+#include <ucbhelper/cancelcommandexecution.hxx>
+#include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
+#include <com/sun/star/ucb/InsertCommandArgument.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#include <comphelper/mimeconfighelper.hxx>
+#include <connectivity/sqlerror.hxx>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/servicehelper.hxx>
+#include <com/sun/star/lang/WrappedTargetRuntimeException.hpp>
+
+#include <vcl/svapp.hxx>
+#include <osl/mutex.hxx>
+#include <o3tl/string_view.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::container;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::sdb;
+using namespace ::com::sun::star::io;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+namespace dbaccess
+{
+
+namespace {
+
+// LocalNameApproval
+class LocalNameApproval : public IContainerApprove
+{
+ ::connectivity::SQLError m_aErrors;
+
+public:
+ void approveElement( const OUString& _rName ) override;
+};
+
+}
+
+void LocalNameApproval::approveElement( const OUString& _rName )
+{
+ if ( _rName.indexOf( '/' ) != -1 )
+ throw IllegalArgumentException(
+ m_aErrors.getErrorMessage( ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES ),
+ nullptr,
+ 0
+ );
+}
+
+// ODocumentContainer
+
+ODocumentContainer::ODocumentContainer(const Reference< XComponentContext >& _xORB
+ ,const Reference< XInterface >& _xParentContainer
+ ,const TContentPtr& _pImpl
+ , bool _bFormsContainer
+ )
+ :ODefinitionContainer(_xORB,_xParentContainer,_pImpl)
+ ,OPropertyStateContainer(OContentHelper::rBHelper)
+ ,m_bFormsContainer(_bFormsContainer)
+{
+ registerProperty(PROPERTY_NAME, PROPERTY_ID_NAME, PropertyAttribute::BOUND | PropertyAttribute::READONLY | PropertyAttribute::CONSTRAINED,
+ &m_pImpl->m_aProps.aTitle, cppu::UnoType<decltype(m_pImpl->m_aProps.aTitle)>::get());
+
+ setElementApproval( std::make_shared<LocalNameApproval>() );
+}
+
+ODocumentContainer::~ODocumentContainer()
+{
+
+ if ( !OContentHelper::rBHelper.bInDispose && !OContentHelper::rBHelper.bDisposed )
+ {
+ acquire();
+ dispose();
+ }
+}
+
+IMPLEMENT_FORWARD_XINTERFACE3( ODocumentContainer,ODefinitionContainer,ODocumentContainer_Base,OPropertyStateContainer)
+
+css::uno::Sequence<sal_Int8> ODocumentContainer::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+css::uno::Sequence< css::uno::Type > ODocumentContainer::getTypes()
+{
+ return ::comphelper::concatSequences(
+ ODefinitionContainer::getTypes( ),
+ OPropertyStateContainer::getTypes( ),
+ ODocumentContainer_Base::getTypes( )
+ );
+}
+OUString SAL_CALL ODocumentContainer::getImplementationName()
+ {
+ return "com.sun.star.comp.dba.ODocumentContainer";
+ };
+sal_Bool SAL_CALL ODocumentContainer::supportsService(const OUString& _rServiceName)
+ {
+ const css::uno::Sequence< OUString > aSupported(getSupportedServiceNames());
+ for (const OUString& s : aSupported)
+ if (s == _rServiceName)
+ return true;
+
+ return false;
+ };
+css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL ODocumentContainer::getPropertySetInfo()
+{
+ Reference< XPropertySetInfo > xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+::cppu::IPropertyArrayHelper& ODocumentContainer::getInfoHelper()
+{
+ return *ODocumentContainer::getArrayHelper();
+}
+::cppu::IPropertyArrayHelper* ODocumentContainer::createArrayHelper( ) const
+{
+ css::uno::Sequence< css::beans::Property > aProps;
+ describeProperties(aProps);
+ return new ::cppu::OPropertyArrayHelper(aProps);
+}
+
+
+Sequence< OUString > SAL_CALL ODocumentContainer::getSupportedServiceNames( )
+{
+ return { m_bFormsContainer ? OUString(SERVICE_NAME_FORM_COLLECTION) : OUString(SERVICE_NAME_REPORT_COLLECTION) };
+}
+
+OUString ODocumentContainer::determineContentType() const
+{
+ return OUString();
+}
+
+Reference< XContent > ODocumentContainer::createObject( const OUString& _rName)
+{
+ const ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
+ ODefinitionContainer_Impl::const_iterator aFind = rDefinitions.find( _rName );
+ OSL_ENSURE( aFind != rDefinitions.end(), "ODocumentContainer::createObject:Invalid entry in map!" );
+ if ( aFind->second->m_aProps.bIsFolder )
+ return new ODocumentContainer( m_aContext, *this, aFind->second, m_bFormsContainer );
+ return new ODocumentDefinition( *this, m_aContext, aFind->second, m_bFormsContainer );
+}
+
+Reference< XInterface > SAL_CALL ODocumentContainer::createInstance( const OUString& aServiceSpecifier )
+{
+ return createInstanceWithArguments( aServiceSpecifier, Sequence< Any >() );
+}
+
+namespace
+{
+ template< class TYPE >
+ void lcl_extractAndRemove( ::comphelper::NamedValueCollection& io_rArguments, const OUString& i_rName, TYPE& o_rValue )
+ {
+ if ( io_rArguments.has( i_rName ) )
+ {
+ io_rArguments.get_ensureType( i_rName, o_rValue );
+ io_rArguments.remove( i_rName );
+ }
+ }
+}
+
+Reference< XInterface > SAL_CALL ODocumentContainer::createInstanceWithArguments( const OUString& ServiceSpecifier, const Sequence< Any >& _aArguments )
+{
+ Reference< XInterface > xRet;
+ Reference< XContent > xContent;
+ if ( ServiceSpecifier == SERVICE_SDB_DOCUMENTDEFINITION )
+ {
+ MutexGuard aGuard(m_aMutex);
+
+ // extract known arguments
+ OUString sName, sPersistentName, sURL, sMediaType, sDocServiceName;
+ Reference< XCommandProcessor > xCopyFrom;
+ Reference< XConnection > xConnection;
+ bool bAsTemplate( false );
+ Sequence< sal_Int8 > aClassID;
+
+ ::comphelper::NamedValueCollection aArgs( _aArguments );
+ lcl_extractAndRemove( aArgs, PROPERTY_NAME, sName );
+ lcl_extractAndRemove( aArgs, PROPERTY_PERSISTENT_NAME, sPersistentName );
+ lcl_extractAndRemove( aArgs, PROPERTY_URL, sURL );
+ lcl_extractAndRemove( aArgs, PROPERTY_EMBEDDEDOBJECT, xCopyFrom );
+ lcl_extractAndRemove( aArgs, PROPERTY_ACTIVE_CONNECTION, xConnection );
+ lcl_extractAndRemove( aArgs, PROPERTY_AS_TEMPLATE, bAsTemplate );
+ lcl_extractAndRemove( aArgs, INFO_MEDIATYPE, sMediaType );
+ lcl_extractAndRemove( aArgs, "DocumentServiceName" , sDocServiceName );
+
+ // ClassID has two allowed types, so a special treatment here
+ Any aClassIDArg = aArgs.get( "ClassID" );
+ if ( aClassIDArg.hasValue() )
+ {
+ if ( !( aClassIDArg >>= aClassID ) )
+ {
+ // Extended for usage also with a string
+ OUString sClassIDString;
+ if ( !( aClassIDArg >>= sClassIDString ) )
+ throw IllegalArgumentException( OUString(), *this, 2 );
+
+ aClassID = ::comphelper::MimeConfigurationHelper::GetSequenceClassIDRepresentation( sClassIDString );
+ }
+
+#if OSL_DEBUG_LEVEL > 0
+ OUString sClassIDString = ::comphelper::MimeConfigurationHelper::GetStringClassIDRepresentation( aClassID );
+ (void)sClassIDString;
+#endif
+ aArgs.remove( "ClassID" );
+ }
+ // Everything which now is still present in the arguments is passed to the embedded object
+ const Sequence< PropertyValue > aCreationArgs( aArgs.getPropertyValues() );
+
+ const ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
+ bool bNew = sPersistentName.isEmpty();
+ if ( bNew )
+ {
+ sPersistentName = "Obj" + OUString::number(rDefinitions.size() + 1);
+ Reference<XNameAccess> xElements = getContainerStorage();
+ if ( xElements.is() )
+ sPersistentName = ::dbtools::createUniqueName(xElements,sPersistentName);
+
+ const bool bNeedClassID = !aClassID.hasElements() && sURL.isEmpty() ;
+ if ( xCopyFrom.is() )
+ {
+ Sequence<Any> aIni{ Any(getContainerStorage()), Any(sPersistentName) };
+ Command aCommand;
+ aCommand.Name = "copyTo";
+ aCommand.Argument <<= aIni;
+
+ xCopyFrom->execute(aCommand,-1,Reference< XCommandEnvironment >());
+ Reference<XPropertySet> xProp(xCopyFrom,UNO_QUERY);
+ if ( xProp.is() && xProp->getPropertySetInfo().is() && xProp->getPropertySetInfo()->hasPropertyByName(PROPERTY_AS_TEMPLATE) )
+ xProp->getPropertyValue(PROPERTY_AS_TEMPLATE) >>= bAsTemplate;
+
+ // if we do not have an own class ID, see if we can determine one from the copy we just created
+ if ( bNeedClassID )
+ ODocumentDefinition::GetDocumentServiceFromMediaType( getContainerStorage(), sPersistentName, m_aContext, aClassID );
+ }
+ else
+ {
+ if ( bNeedClassID )
+ {
+ if ( !sMediaType.isEmpty() )
+ ODocumentDefinition::GetDocumentServiceFromMediaType( sMediaType, m_aContext, aClassID );
+ else if ( !sDocServiceName.isEmpty() )
+ {
+ ::comphelper::MimeConfigurationHelper aConfigHelper( m_aContext );
+ const Sequence< NamedValue > aProps( aConfigHelper.GetObjectPropsByDocumentName( sDocServiceName ) );
+ const ::comphelper::NamedValueCollection aMediaTypeProps( aProps );
+ aClassID = aMediaTypeProps.getOrDefault( "ClassID", Sequence< sal_Int8 >() );
+ }
+ }
+ }
+ }
+
+ ODefinitionContainer_Impl::const_iterator aFind = rDefinitions.find( sName );
+ TContentPtr pElementImpl;
+ if ( bNew || ( aFind == rDefinitions.end() ) )
+ {
+ pElementImpl = std::make_shared<OContentHelper_Impl>();
+ if ( !bNew )
+ pElementImpl->m_aProps.aTitle = sName;
+
+ pElementImpl->m_aProps.sPersistentName = sPersistentName;
+ pElementImpl->m_aProps.bAsTemplate = bAsTemplate;
+ pElementImpl->m_pDataSource = m_pImpl->m_pDataSource;
+ }
+ else
+ pElementImpl = aFind->second;
+
+ ::rtl::Reference< ODocumentDefinition > pDocDef = new ODocumentDefinition( *this, m_aContext, pElementImpl, m_bFormsContainer );
+ if ( aClassID.hasElements() )
+ {
+ pDocDef->initialLoad( aClassID, aCreationArgs, xConnection );
+ }
+ else
+ {
+ OSL_ENSURE( !aCreationArgs.hasElements(), "ODocumentContainer::createInstance: additional creation args are lost, if you do not provide a class ID." );
+ }
+ xContent = pDocDef.get();
+
+ if ( !sURL.isEmpty() )
+ {
+ Sequence<Any> aIni{ Any(sURL) };
+ Command aCommand;
+ aCommand.Name = "insert";
+ aCommand.Argument <<= aIni;
+ Reference< XCommandProcessor > xCommandProcessor(xContent,UNO_QUERY);
+ if ( xContent.is() )
+ {
+ xCommandProcessor->execute(aCommand,-1,Reference< XCommandEnvironment >());
+ }
+ }
+ }
+ else if ( ServiceSpecifier == SERVICE_NAME_FORM_COLLECTION || SERVICE_NAME_REPORT_COLLECTION == ServiceSpecifier )
+ {
+ const Any* pBegin = _aArguments.getConstArray();
+ const Any* pEnd = pBegin + _aArguments.getLength();
+ PropertyValue aValue;
+ OUString sName;
+ Reference<XNameAccess> xCopyFrom;
+ for(;pBegin != pEnd;++pBegin)
+ {
+ *pBegin >>= aValue;
+ if ( aValue.Name == PROPERTY_NAME)
+ {
+ aValue.Value >>= sName;
+ }
+ else if ( aValue.Name == PROPERTY_EMBEDDEDOBJECT)
+ {
+ xCopyFrom.set(aValue.Value,UNO_QUERY);
+ }
+ }
+ OSL_ENSURE(!sName.isEmpty(),"Invalid name for a document container!");
+ const ODefinitionContainer_Impl& rDefinitions( getDefinitions() );
+ ODefinitionContainer_Impl::const_iterator aFind = rDefinitions.find( sName );
+ TContentPtr pElementImpl;
+ if ( aFind == rDefinitions.end() )
+ {
+ pElementImpl = std::make_shared<ODefinitionContainer_Impl>();
+ pElementImpl->m_aProps.aTitle = sName;
+ pElementImpl->m_pDataSource = m_pImpl->m_pDataSource;
+ }
+ else
+ pElementImpl = aFind->second;
+ OSL_ENSURE( pElementImpl ," Invalid entry in map!");
+ xContent = new ODocumentContainer( m_aContext, *this, pElementImpl, ServiceSpecifier == SERVICE_NAME_FORM_COLLECTION );
+
+ // copy children
+ if ( xCopyFrom.is() )
+ {
+ Sequence< OUString> aSeq = xCopyFrom->getElementNames();
+ const OUString* elements = aSeq.getConstArray();
+ const OUString* elementsEnd = elements + aSeq.getLength();
+ Reference<XContent> xObjectToCopy;
+
+ Reference<XMultiServiceFactory> xORB(xContent,UNO_QUERY);
+ OSL_ENSURE(xORB.is(),"No service factory given");
+ if ( xORB.is() )
+ {
+ for(;elements != elementsEnd;++elements)
+ {
+ xCopyFrom->getByName(*elements) >>= xObjectToCopy;
+ Sequence<Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {"Name", Any(*elements)}, // set as folder
+ {"Parent", Any(xContent)},
+ {PROPERTY_EMBEDDEDOBJECT, Any(xObjectToCopy)},
+ }));
+
+ OUString sServiceName;
+ if ( Reference< XNameAccess >( xObjectToCopy, UNO_QUERY ).is() )
+ {
+ if ( m_bFormsContainer )
+ sServiceName = SERVICE_NAME_FORM_COLLECTION;
+ else
+ sServiceName = SERVICE_NAME_REPORT_COLLECTION;
+ }
+ else
+ sServiceName = SERVICE_SDB_DOCUMENTDEFINITION;
+
+ Reference<XContent > xNew(xORB->createInstanceWithArguments(sServiceName,aArguments),UNO_QUERY);
+ Reference<XNameContainer> xNameContainer(xContent,UNO_QUERY);
+ if ( xNameContainer.is() )
+ xNameContainer->insertByName(*elements,Any(xNew));
+ }
+ }
+ }
+ }
+ xRet = xContent;
+ return xRet;
+}
+
+Sequence< OUString > SAL_CALL ODocumentContainer::getAvailableServiceNames( )
+{
+ return
+ {
+ SERVICE_SDB_DOCUMENTDEFINITION,
+ SERVICE_NAME_FORM_COLLECTION,
+ SERVICE_NAME_REPORT_COLLECTION
+ };
+}
+
+Any SAL_CALL ODocumentContainer::execute( const Command& aCommand, sal_Int32 CommandId, const Reference< XCommandEnvironment >& Environment )
+{
+ Any aRet;
+ if ( aCommand.Name == "open" )
+ {
+ // open command for a folder content
+ OpenCommandArgument2 aOpenCommand;
+ if ( !( aCommand.Argument >>= aOpenCommand ) )
+ {
+ OSL_FAIL( "Wrong argument type!" );
+ ucbhelper::cancelCommandExecution(
+ Any( IllegalArgumentException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ -1 ) ),
+ Environment );
+ // Unreachable
+ }
+ bool bOpenFolder =
+ ( ( aOpenCommand.Mode == OpenMode::ALL ) ||
+ ( aOpenCommand.Mode == OpenMode::FOLDERS ) ||
+ ( aOpenCommand.Mode == OpenMode::DOCUMENTS ) );
+
+ if ( bOpenFolder )
+ {
+ // open as folder - return result set
+
+ Reference< XDynamicResultSet > xSet
+ = new DynamicResultSet( m_aContext,
+ this,
+ aOpenCommand,
+ Environment );
+ aRet <<= xSet;
+ }
+ else
+ {
+ // Unsupported.
+ ucbhelper::cancelCommandExecution(
+ Any( UnsupportedOpenModeException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ sal_Int16( aOpenCommand.Mode ) ) ),
+ Environment );
+ // Unreachable
+ }
+ }
+ else if ( aCommand.Name == "insert" )
+ {
+ // insert
+
+ InsertCommandArgument arg;
+ if ( !( aCommand.Argument >>= arg ) )
+ {
+ OSL_FAIL( "Wrong argument type!" );
+ ucbhelper::cancelCommandExecution(
+ Any( IllegalArgumentException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ -1 ) ),
+ Environment );
+ // Unreachable
+ }
+ }
+ else if ( aCommand.Name == "delete" )
+ {
+ // delete
+ Sequence< OUString> aSeq = getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ for(;pIter != pEnd;++pIter)
+ removeByName(*pIter);
+
+ dispose();
+ }
+ else
+ aRet = OContentHelper::execute(aCommand,CommandId,Environment);
+ return aRet;
+}
+
+namespace
+{
+ bool lcl_queryContent(std::u16string_view _sName,Reference< XNameContainer >& _xNameContainer,Any& _rRet,OUString& _sSimpleName)
+ {
+ sal_Int32 nIndex = 0;
+ OUString sName( o3tl::getToken(_sName,0,'/',nIndex) );
+ bool bRet = _xNameContainer->hasByName(sName);
+ if ( bRet )
+ {
+ _sSimpleName = sName;
+ _rRet = _xNameContainer->getByName(_sSimpleName);
+ while ( nIndex != -1 && bRet )
+ {
+ sName = o3tl::getToken(_sName,0,'/',nIndex);
+ _xNameContainer.set(_rRet,UNO_QUERY);
+ bRet = _xNameContainer.is();
+ if ( bRet )
+ {
+ bRet = _xNameContainer->hasByName(sName);
+ _sSimpleName = sName;
+ if ( bRet )
+ _rRet = _xNameContainer->getByName(sName);
+ }
+ }
+ }
+ if ( nIndex == -1 )
+ _sSimpleName = sName; // a content
+ else
+ _xNameContainer.clear(); // a sub folder doesn't exist
+ return bRet;
+ }
+}
+
+Reference< XComponent > SAL_CALL ODocumentContainer::loadComponentFromURL( const OUString& _sURL
+ , const OUString& /*TargetFrameName*/
+ , sal_Int32 /*SearchFlags*/
+ , const Sequence< PropertyValue >& Arguments )
+{
+ ::SolarMutexGuard aSolarGuard;
+
+ MutexGuard aGuard(m_aMutex);
+ Reference< XComponent > xComp;
+ try
+ {
+ Any aContent;
+ Reference< XNameContainer > xNameContainer(this);
+ OUString sName;
+ if ( !lcl_queryContent(_sURL,xNameContainer,aContent,sName) )
+ {
+ OUString sMessage(
+ DBA_RES(RID_STR_NAME_NOT_FOUND).replaceFirst("$name$", _sURL));
+ throw IllegalArgumentException( sMessage, *this, 1 );
+ }
+
+ Reference< XCommandProcessor > xContent(aContent,UNO_QUERY);
+ if ( xContent.is() )
+ {
+ Command aCommand;
+
+ ::comphelper::NamedValueCollection aArgs( Arguments );
+ aCommand.Name = aArgs.getOrDefault( "OpenMode", OUString("open") );
+ aArgs.remove( "OpenMode" );
+
+ OpenCommandArgument2 aOpenCommand;
+ aOpenCommand.Mode = OpenMode::DOCUMENT;
+ aArgs.put( "OpenCommandArgument", aOpenCommand );
+
+ aCommand.Argument <<= aArgs.getPropertyValues();
+ xComp.set(xContent->execute(aCommand,xContent->createCommandIdentifier(),Reference< XCommandEnvironment >()),UNO_QUERY);
+ }
+ }
+ catch(const NoSuchElementException&)
+ {
+ throw IllegalArgumentException();
+ }
+ catch(const WrappedTargetException &e)
+ {
+ throw WrappedTargetRuntimeException(e.Message, e.Context, e.TargetException);
+ }
+ return xComp;
+}
+
+Any SAL_CALL ODocumentContainer::getByHierarchicalName( const OUString& _sName )
+{
+ MutexGuard aGuard(m_aMutex);
+ Any aContent;
+ Reference< XNameContainer > xNameContainer(this);
+ OUString sName;
+ if ( lcl_queryContent(_sName,xNameContainer,aContent,sName) )
+ return aContent;
+ throw NoSuchElementException(_sName,*this);
+}
+
+sal_Bool SAL_CALL ODocumentContainer::hasByHierarchicalName( const OUString& _sName )
+{
+ MutexGuard aGuard(m_aMutex);
+ Any aContent;
+ Reference< XNameContainer > xNameContainer(this);
+ OUString sName;
+ return lcl_queryContent(_sName,xNameContainer,aContent,sName);
+}
+
+// XHierarchicalNameContainer
+void SAL_CALL ODocumentContainer::insertByHierarchicalName( const OUString& _sName, const Any& _aElement )
+{
+ Reference< XContent > xContent(_aElement,UNO_QUERY);
+ if ( !xContent.is() )
+ throw IllegalArgumentException();
+
+ MutexGuard aGuard(m_aMutex);
+ Any aContent;
+ Reference< XNameContainer > xNameContainer(this);
+ OUString sName;
+ if ( lcl_queryContent(_sName,xNameContainer,aContent,sName) )
+ throw ElementExistException(_sName,*this);
+
+ if ( !xNameContainer.is() )
+ {
+ sal_Int32 index = sName.getLength();
+ OUString sMessage(
+ DBA_RES(RID_STR_NO_SUB_FOLDER).replaceFirst("$folder$",
+ o3tl::getToken(_sName, 0,'/',index)));
+ throw IllegalArgumentException( sMessage, *this, 1 );
+ }
+
+ xNameContainer->insertByName(sName,_aElement);
+}
+
+void SAL_CALL ODocumentContainer::removeByHierarchicalName( const OUString& _sName )
+{
+ if ( _sName.isEmpty() )
+ throw NoSuchElementException(_sName,*this);
+
+ MutexGuard aGuard(m_aMutex);
+ Any aContent;
+ OUString sName;
+ Reference< XNameContainer > xNameContainer(this);
+ if ( !lcl_queryContent(_sName,xNameContainer,aContent,sName) )
+ throw NoSuchElementException(_sName,*this);
+
+ xNameContainer->removeByName(sName);
+}
+
+// XHierarchicalNameReplace
+void SAL_CALL ODocumentContainer::replaceByHierarchicalName( const OUString& _sName, const Any& _aElement )
+{
+ Reference< XContent > xContent(_aElement,UNO_QUERY);
+ if ( !xContent.is() )
+ throw IllegalArgumentException();
+
+ MutexGuard aGuard(m_aMutex);
+ Any aContent;
+ OUString sName;
+ Reference< XNameContainer > xNameContainer(this);
+ if ( !lcl_queryContent(_sName,xNameContainer,aContent,sName) )
+ throw NoSuchElementException(_sName,*this);
+
+ xNameContainer->replaceByName(sName,_aElement);
+}
+
+OUString SAL_CALL ODocumentContainer::getHierarchicalName()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return impl_getHierarchicalName( false );
+}
+
+OUString SAL_CALL ODocumentContainer::composeHierarchicalName( const OUString& i_rRelativeName )
+{
+ OUString aBuffer = getHierarchicalName() + "/" + i_rRelativeName;
+ return aBuffer;
+}
+
+::rtl::Reference<OContentHelper> ODocumentContainer::getContent(const OUString& _sName) const
+{
+ ::rtl::Reference<OContentHelper> pContent;
+ try
+ {
+ pContent = comphelper::getFromUnoTunnel<OContentHelper>(const_cast<ODocumentContainer*>(this)->implGetByName( _sName, true ));
+ }
+ catch(const Exception&)
+ {
+ }
+ return pContent;
+}
+
+void ODocumentContainer::getPropertyDefaultByHandle( sal_Int32 /*_nHandle*/, Any& _rDefault ) const
+{
+ _rDefault.clear();
+}
+
+void SAL_CALL ODocumentContainer::commit( )
+{
+ MutexGuard aGuard(m_aMutex);
+ for (auto const& elem : m_aDocumentMap)
+ {
+ Reference<XTransactedObject> xTrans(elem.second.get(),UNO_QUERY);
+ if ( xTrans.is() )
+ xTrans->commit();
+ }
+ Reference<XTransactedObject> xTrans(getContainerStorage(),UNO_QUERY);
+ if ( xTrans.is() )
+ xTrans->commit();
+}
+
+void SAL_CALL ODocumentContainer::revert( )
+{
+ MutexGuard aGuard(m_aMutex);
+ for (auto const& elem : m_aDocumentMap)
+ {
+ Reference<XTransactedObject> xTrans(elem.second.get(),UNO_QUERY);
+ if ( xTrans.is() )
+ xTrans->revert();
+ }
+ Reference<XTransactedObject> xTrans(getContainerStorage(),UNO_QUERY);
+ if ( xTrans.is() )
+ xTrans->revert();
+}
+
+Reference< XStorage> ODocumentContainer::getContainerStorage() const
+{
+ return m_pImpl->m_pDataSource
+ ? m_pImpl->m_pDataSource->getStorage( m_bFormsContainer ? ODatabaseModelImpl::E_FORM : ODatabaseModelImpl::E_REPORT )
+ : Reference< XStorage>();
+}
+
+void SAL_CALL ODocumentContainer::removeByName( const OUString& _rName )
+{
+ ResettableMutexGuard aGuard(m_aMutex);
+
+ // check the arguments
+ if (_rName.isEmpty())
+ throw IllegalArgumentException();
+
+ if (!checkExistence(_rName))
+ throw NoSuchElementException(_rName,*this);
+
+ Reference< XCommandProcessor > xContent( implGetByName( _rName, true ), UNO_QUERY );
+ if ( xContent.is() )
+ {
+ Command aCommand;
+
+ aCommand.Name = "delete";
+ xContent->execute(aCommand,xContent->createCommandIdentifier(),Reference< XCommandEnvironment >());
+ }
+
+ // do the removal
+ implRemove(_rName);
+
+ notifyByName( aGuard, _rName, nullptr, nullptr, E_REMOVED, ContainerListemers );
+}
+
+void SAL_CALL ODocumentContainer::rename( const OUString& newName )
+{
+ try
+ {
+ osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex);
+ if ( newName == m_pImpl->m_aProps.aTitle )
+ return;
+
+ sal_Int32 nHandle = PROPERTY_ID_NAME;
+ Any aOld(m_pImpl->m_aProps.aTitle);
+ Any aNew(newName);
+
+ aGuard.clear();
+ fire(&nHandle, &aNew, &aOld, 1, true );
+ m_pImpl->m_aProps.aTitle = newName;
+ fire(&nHandle, &aNew, &aOld, 1, false );
+ }
+ catch(const PropertyVetoException&)
+ {
+ throw ElementExistException(newName,*this);
+ }
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documentcontainer.hxx b/dbaccess/source/core/dataaccess/documentcontainer.hxx
new file mode 100644
index 000000000..d47709e80
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documentcontainer.hxx
@@ -0,0 +1,137 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <definitioncontainer.hxx>
+#include <cppuhelper/implbase5.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/frame/XComponentLoader.hpp>
+#include <com/sun/star/container/XHierarchicalNameContainer.hpp>
+#include <com/sun/star/container/XHierarchicalName.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <comphelper/propertystatecontainer.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <rtl/ref.hxx>
+#include <apitools.hxx>
+
+namespace dbaccess
+{
+typedef ::cppu::ImplHelper5 < css::frame::XComponentLoader
+ , css::lang::XMultiServiceFactory
+ , css::container::XHierarchicalNameContainer
+ , css::container::XHierarchicalName
+ , css::embed::XTransactedObject
+ > ODocumentContainer_Base;
+// ODocumentContainer - collections of database documents (reports/forms)
+class ODocumentContainer : public ODefinitionContainer
+ , public ODocumentContainer_Base
+ , public ::comphelper::OPropertyStateContainer
+ , public ::comphelper::OPropertyArrayUsageHelper< ODocumentContainer >
+{
+ bool m_bFormsContainer;
+
+public:
+ /** constructs the container.<BR>
+ */
+ ODocumentContainer(
+ const css::uno::Reference< css::uno::XComponentContext >& _xORB
+ , const css::uno::Reference< css::uno::XInterface >& _xParentContainer
+ ,const TContentPtr& _pImpl
+ , bool _bFormsContainer
+ );
+
+ // css::uno::XInterface
+ DECLARE_XINTERFACE( )
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+ // css::lang::XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XComponentLoader
+ virtual css::uno::Reference< css::lang::XComponent > SAL_CALL loadComponentFromURL( const OUString& URL, const OUString& TargetFrameName, sal_Int32 SearchFlags, const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override;
+
+ // css::lang::XMultiServiceFactory
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance( const OUString& aServiceSpecifier ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceWithArguments( const OUString& ServiceSpecifier, const css::uno::Sequence< css::uno::Any >& Arguments ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getAvailableServiceNames( ) override;
+
+ // XCommandProcessor
+ virtual css::uno::Any SAL_CALL execute( const css::ucb::Command& aCommand, sal_Int32 CommandId, const css::uno::Reference< css::ucb::XCommandEnvironment >& Environment ) override ;
+
+ // XHierarchicalNameAccess
+ virtual css::uno::Any SAL_CALL getByHierarchicalName( const OUString& _sName ) override;
+ virtual sal_Bool SAL_CALL hasByHierarchicalName( const OUString& _sName ) override;
+
+ // XHierarchicalNameContainer
+ virtual void SAL_CALL insertByHierarchicalName( const OUString& aName, const css::uno::Any& aElement ) override;
+ virtual void SAL_CALL removeByHierarchicalName( const OUString& Name ) override;
+
+ // XHierarchicalName
+ virtual OUString SAL_CALL getHierarchicalName( ) override;
+ virtual OUString SAL_CALL composeHierarchicalName( const OUString& aRelativeName ) override;
+
+ // XNameContainer
+ virtual void SAL_CALL removeByName( const OUString& _rName ) override;
+
+ // XHierarchicalNameReplace
+ virtual void SAL_CALL replaceByHierarchicalName( const OUString& aName, const css::uno::Any& aElement ) override;
+
+ // css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // XTransactedObject
+ virtual void SAL_CALL commit( ) override;
+ virtual void SAL_CALL revert( ) override;
+
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+ // OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // helper
+ ::rtl::Reference<OContentHelper> getContent(const OUString& _sName) const;
+ css::uno::Reference< css::embed::XStorage > getContainerStorage() const;
+
+protected:
+ virtual ~ODocumentContainer() override;
+
+ /** OContentHelper
+ */
+ virtual OUString determineContentType() const override;
+
+ // ODefinitionContainer
+ virtual css::uno::Reference< css::ucb::XContent > createObject(
+ const OUString& _rName
+ ) override;
+
+ virtual void getPropertyDefaultByHandle( sal_Int32 _nHandle, css::uno::Any& _rDefault ) const override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documentdefinition.cxx b/dbaccess/source/core/dataaccess/documentdefinition.cxx
new file mode 100644
index 000000000..98e84d6d4
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documentdefinition.cxx
@@ -0,0 +1,2102 @@
+/* -*- 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 "documentdefinition.hxx"
+#include <ModelImpl.hxx>
+#include <stringconstants.hxx>
+#include <sdbcoretools.hxx>
+#include <tools/diagnose_ex.h>
+#include <osl/diagnose.h>
+#include <comphelper/sequence.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/classids.hxx>
+#include <comphelper/propertysequence.hxx>
+#include <comphelper/propertyvalue.hxx>
+#include <comphelper/types.hxx>
+#include <com/sun/star/frame/XUntitledNumbers.hpp>
+#include <com/sun/star/awt/Size.hpp>
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/lang/XMultiServiceFactory.hpp>
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/frame/Desktop.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/frame/XTitle.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/task/XJobExecutor.hpp>
+#include <com/sun/star/report/XReportDefinition.hpp>
+#include <com/sun/star/report/XReportEngine.hpp>
+#include <com/sun/star/ucb/OpenMode.hpp>
+#include <com/sun/star/embed/WrongStateException.hpp>
+#include <com/sun/star/embed/EmbeddedObjectCreator.hpp>
+#include <com/sun/star/embed/Aspects.hpp>
+#include <com/sun/star/embed/OOoEmbeddedObjectFactory.hpp>
+#include <ucbhelper/cancelcommandexecution.hxx>
+#include <com/sun/star/ucb/UnsupportedOpenModeException.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/embed/XEmbedPersist.hpp>
+#include <com/sun/star/embed/EmbedStates.hpp>
+#include <com/sun/star/embed/EntryInitModes.hpp>
+#include <com/sun/star/ucb/MissingPropertiesException.hpp>
+#include <com/sun/star/ucb/OpenCommandArgument2.hpp>
+#include <com/sun/star/util/CloseVetoException.hpp>
+#include <com/sun/star/frame/XModule.hpp>
+#include <com/sun/star/datatransfer/DataFlavor.hpp>
+#include <com/sun/star/datatransfer/XTransferable.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/embed/XCommonEmbedPersist.hpp>
+#include "intercept.hxx"
+#include <com/sun/star/sdb/ErrorCondition.hpp>
+#include <com/sun/star/sdb/XInteractionDocumentSave.hpp>
+#include <com/sun/star/task/InteractionHandler.hpp>
+#include <com/sun/star/sdb/DocumentSaveRequest.hpp>
+#include <com/sun/star/document/XDocumentPropertiesSupplier.hpp>
+#include <com/sun/star/document/MacroExecMode.hpp>
+#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
+#include <com/sun/star/form/XFormsSupplier.hpp>
+#include <com/sun/star/form/XForm.hpp>
+#include <comphelper/interaction.hxx>
+#include <connectivity/dbtools.hxx>
+#include <vcl/svapp.hxx>
+#include <osl/mutex.hxx>
+#include <com/sun/star/view/XViewSettingsSupplier.hpp>
+#include <core_resource.hxx>
+#include <strings.hrc>
+#include <strings.hxx>
+#include <com/sun/star/task/XInteractionApprove.hpp>
+#include <com/sun/star/task/XInteractionDisapprove.hpp>
+#include <com/sun/star/frame/XLayoutManager.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/exc_hlp.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <comphelper/mimeconfighelper.hxx>
+#include <com/sun/star/container/XContentEnumerationAccess.hpp>
+#include <com/sun/star/io/WrongFormatException.hpp>
+#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
+#include <com/sun/star/sdb/application/DatabaseObject.hpp>
+#include <com/sun/star/util/XModifiable2.hpp>
+
+using namespace ::com::sun::star;
+using namespace view;
+using namespace uno;
+using namespace util;
+using namespace ucb;
+using namespace beans;
+using namespace lang;
+using namespace awt;
+using namespace embed;
+using namespace frame;
+using namespace document;
+using namespace sdbc;
+using namespace sdb;
+using namespace io;
+using namespace container;
+using namespace datatransfer;
+using namespace task;
+using namespace form;
+using namespace drawing;
+using namespace ::osl;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+using sdb::application::XDatabaseDocumentUI;
+namespace DatabaseObject = sdb::application::DatabaseObject;
+
+#define DEFAULT_WIDTH 10000
+#define DEFAULT_HEIGHT 7500
+
+namespace dbaccess
+{
+
+ typedef ::std::optional< bool > optional_bool;
+
+ // helper
+ namespace
+ {
+ OUString lcl_determineContentType_nothrow( const Reference< XStorage >& _rxContainerStorage,
+ const OUString& _rEntityName )
+ {
+ OUString sContentType;
+ try
+ {
+ ::utl::SharedUNOComponent< XPropertySet > xStorageProps(
+ _rxContainerStorage->openStorageElement( _rEntityName, ElementModes::READ ), UNO_QUERY_THROW );
+ OSL_VERIFY( xStorageProps->getPropertyValue( INFO_MEDIATYPE ) >>= sContentType );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return sContentType;
+ }
+ }
+
+ // OEmbedObjectHolder
+ typedef ::cppu::WeakComponentImplHelper< embed::XStateChangeListener > TEmbedObjectHolder;
+
+ namespace {
+
+ class OEmbedObjectHolder : public ::cppu::BaseMutex
+ ,public TEmbedObjectHolder
+ {
+ Reference< XEmbeddedObject > m_xBroadCaster;
+ ODocumentDefinition* m_pDefinition;
+ bool m_bInStateChange;
+ protected:
+ virtual void SAL_CALL disposing() override;
+ public:
+ OEmbedObjectHolder(const Reference< XEmbeddedObject >& _xBroadCaster,ODocumentDefinition* _pDefinition)
+ : TEmbedObjectHolder(m_aMutex)
+ ,m_xBroadCaster(_xBroadCaster)
+ ,m_pDefinition(_pDefinition)
+ ,m_bInStateChange(false)
+ {
+ osl_atomic_increment( &m_refCount );
+ {
+ if ( m_xBroadCaster.is() )
+ m_xBroadCaster->addStateChangeListener(this);
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+ virtual void SAL_CALL changingState( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) override;
+ virtual void SAL_CALL stateChanged( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState ) override;
+ virtual void SAL_CALL disposing( const lang::EventObject& Source ) override;
+ };
+
+ }
+
+ void SAL_CALL OEmbedObjectHolder::disposing()
+ {
+ if ( m_xBroadCaster.is() )
+ m_xBroadCaster->removeStateChangeListener(this);
+ m_xBroadCaster = nullptr;
+ m_pDefinition = nullptr;
+ }
+
+ void SAL_CALL OEmbedObjectHolder::changingState( const lang::EventObject& /*aEvent*/, ::sal_Int32 /*nOldState*/, ::sal_Int32 /*nNewState*/ )
+ {
+ }
+
+ void SAL_CALL OEmbedObjectHolder::stateChanged( const lang::EventObject& aEvent, ::sal_Int32 nOldState, ::sal_Int32 nNewState )
+ {
+ if ( !m_bInStateChange && nNewState == EmbedStates::RUNNING && nOldState == EmbedStates::ACTIVE && m_pDefinition )
+ {
+ m_bInStateChange = true;
+ Reference<XInterface> xHoldAlive(static_cast< ::cppu::OWeakObject* >(m_pDefinition),UNO_QUERY);
+ {
+ Reference<XEmbeddedObject> xEmbeddedObject(aEvent.Source,UNO_QUERY);
+ if ( xEmbeddedObject.is() )
+ xEmbeddedObject->changeState(EmbedStates::LOADED);
+ }
+ m_bInStateChange = false;
+ }
+ }
+
+ void SAL_CALL OEmbedObjectHolder::disposing( const lang::EventObject& /*Source*/ )
+ {
+ m_xBroadCaster = nullptr;
+ }
+
+ // OEmbeddedClientHelper
+ class OEmbeddedClientHelper : public ::cppu::WeakImplHelper<XEmbeddedClient>
+ {
+ public:
+ virtual void SAL_CALL saveObject( ) override
+ {
+ }
+ // XComponentSupplier
+ virtual Reference< util::XCloseable > SAL_CALL getComponent( ) override
+ {
+ return Reference< css::util::XCloseable >();
+ }
+
+ // XEmbeddedClient
+ virtual void SAL_CALL visibilityChanged( sal_Bool /*bVisible*/ ) override
+ {
+ }
+ };
+
+ namespace {
+
+ // LockModifiable
+ class LockModifiable
+ {
+ public:
+ explicit LockModifiable( const Reference< XInterface >& i_rModifiable )
+ :m_xModifiable( i_rModifiable, UNO_QUERY )
+ {
+ OSL_ENSURE( m_xModifiable.is(), "LockModifiable::LockModifiable: invalid component!" );
+ if ( m_xModifiable.is() )
+ {
+ if ( !m_xModifiable->isSetModifiedEnabled() )
+ {
+ // somebody already locked that, no need to lock it, again, and no need to unlock it later
+ m_xModifiable.clear();
+ }
+ else
+ {
+ m_xModifiable->disableSetModified();
+ }
+ }
+ }
+
+ ~LockModifiable()
+ {
+ if ( m_xModifiable.is() )
+ m_xModifiable->enableSetModified();
+ }
+
+ private:
+ Reference< XModifiable2 > m_xModifiable;
+ };
+
+ }
+
+ // LifetimeCoupler
+ typedef ::cppu::WeakImplHelper< css::lang::XEventListener
+ > LifetimeCoupler_Base;
+
+ namespace {
+
+ /** helper class which couples the lifetime of a component to the lifetime
+ of another component
+
+ Instances of this class are constructed with two components. The first is
+ simply held by reference, and thus kept alive. The second one is observed
+ for <code>disposing</code> calls - if they occur, i.e. if the component dies,
+ the reference to the first component is cleared.
+
+ This way, you can ensure that a certain component is kept alive as long
+ as a second component is not disposed.
+ */
+ class LifetimeCoupler : public LifetimeCoupler_Base
+ {
+ private:
+ Reference< XInterface > m_xClient;
+
+ public:
+ static void couple( const Reference< XInterface >& _rxClient, const Reference< XComponent >& _rxActor )
+ {
+ new LifetimeCoupler( _rxClient, _rxActor );
+ }
+
+ private:
+ LifetimeCoupler( const Reference< XInterface >& _rxClient, const Reference< XComponent >& _rxActor )
+ :m_xClient( _rxClient )
+ {
+ OSL_ENSURE( _rxActor.is(), "LifetimeCoupler::LifetimeCoupler: this will crash!" );
+ osl_atomic_increment( &m_refCount );
+ {
+ _rxActor->addEventListener( this );
+ }
+ osl_atomic_decrement( &m_refCount );
+ OSL_ENSURE( m_refCount, "LifetimeCoupler::LifetimeCoupler: the actor is not holding us by hard ref - this won't work!" );
+ }
+
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ protected:
+ };
+
+ }
+
+ void SAL_CALL LifetimeCoupler::disposing( const css::lang::EventObject& /*Source*/ )
+ {
+ m_xClient.clear();
+ }
+
+ namespace {
+
+ // ODocumentSaveContinuation
+ class ODocumentSaveContinuation : public OInteraction< XInteractionDocumentSave >
+ {
+ OUString m_sName;
+ Reference<XContent> m_xParentContainer;
+
+ public:
+ ODocumentSaveContinuation() { }
+
+ const Reference<XContent>& getContent() const { return m_xParentContainer; }
+ const OUString& getName() const { return m_sName; }
+
+ // XInteractionDocumentSave
+ virtual void SAL_CALL setName( const OUString& _sName,const Reference<XContent>& _xParent) override;
+ };
+
+ }
+
+ void SAL_CALL ODocumentSaveContinuation::setName( const OUString& _sName,const Reference<XContent>& _xParent)
+ {
+ m_sName = _sName;
+ m_xParentContainer = _xParent;
+ }
+
+OUString ODocumentDefinition::GetDocumentServiceFromMediaType( const Reference< XStorage >& _rxContainerStorage,
+ const OUString& _rEntityName, const Reference< XComponentContext >& _rContext,
+ Sequence< sal_Int8 >& _rClassId )
+{
+ return GetDocumentServiceFromMediaType(
+ lcl_determineContentType_nothrow( _rxContainerStorage, _rEntityName ),
+ _rContext, _rClassId );
+}
+
+OUString ODocumentDefinition::GetDocumentServiceFromMediaType( const OUString& _rMediaType,
+ const Reference< XComponentContext >& _rContext, Sequence< sal_Int8 >& _rClassId )
+{
+ OUString sResult;
+ try
+ {
+ ::comphelper::MimeConfigurationHelper aConfigHelper( _rContext );
+ sResult = aConfigHelper.GetDocServiceNameFromMediaType( _rMediaType );
+ _rClassId = comphelper::MimeConfigurationHelper::GetSequenceClassIDRepresentation(aConfigHelper.GetExplicitlyRegisteredObjClassID( _rMediaType ));
+ if ( !_rClassId.hasElements() && !sResult.isEmpty() )
+ {
+ Reference< XNameAccess > xObjConfig = aConfigHelper.GetObjConfiguration();
+ if ( xObjConfig.is() )
+ {
+ const Sequence< OUString > aClassIDs = xObjConfig->getElementNames();
+ for ( OUString const & classId : aClassIDs )
+ {
+ Reference< XNameAccess > xObjectProps;
+ OUString aEntryDocName;
+
+ if ( ( xObjConfig->getByName( classId ) >>= xObjectProps ) && xObjectProps.is()
+ && ( xObjectProps->getByName("ObjectDocumentServiceName") >>= aEntryDocName )
+ && aEntryDocName == sResult )
+ {
+ _rClassId = comphelper::MimeConfigurationHelper::GetSequenceClassIDRepresentation(classId);
+ break;
+ }
+ }
+ }
+ }
+#if OSL_DEBUG_LEVEL > 0
+ // alternative, shorter approach
+ const Sequence< NamedValue > aProps( aConfigHelper.GetObjectPropsByMediaType( _rMediaType ) );
+ const ::comphelper::NamedValueCollection aMediaTypeProps( aProps );
+ const OUString sAlternativeResult = aMediaTypeProps.getOrDefault( "ObjectDocumentServiceName", OUString() );
+ OSL_ENSURE( sAlternativeResult == sResult, "ODocumentDefinition::GetDocumentServiceFromMediaType: failed, this approach is *not* equivalent (1)!" );
+ const Sequence< sal_Int8 > aAlternativeClassID = aMediaTypeProps.getOrDefault( "ClassID", Sequence< sal_Int8 >() );
+ OSL_ENSURE( aAlternativeClassID == _rClassId, "ODocumentDefinition::GetDocumentServiceFromMediaType: failed, this approach is *not* equivalent (2)!" );
+#endif
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return sResult;
+}
+
+// ODocumentDefinition
+
+ODocumentDefinition::ODocumentDefinition( const Reference< XInterface >& _rxContainer, const Reference< XComponentContext >& _xORB,
+ const TContentPtr& _pImpl, bool _bForm )
+ :OContentHelper(_xORB,_rxContainer,_pImpl)
+ ,OPropertyStateContainer(OContentHelper::rBHelper)
+ ,m_bForm(_bForm)
+ ,m_bOpenInDesign(false)
+ ,m_bInExecute(false)
+ ,m_bRemoveListener(false)
+{
+ registerProperties();
+}
+
+void ODocumentDefinition::initialLoad( const Sequence< sal_Int8 >& i_rClassID, const Sequence< PropertyValue >& i_rCreationArgs,
+ const Reference< XConnection >& i_rConnection )
+{
+ OSL_ENSURE( i_rClassID.hasElements(), "ODocumentDefinition::initialLoad: illegal class ID!" );
+ if ( !i_rClassID.hasElements() )
+ return;
+
+ loadEmbeddedObject( i_rConnection, i_rClassID, i_rCreationArgs, false, false );
+}
+
+ODocumentDefinition::~ODocumentDefinition()
+{
+ if ( !OContentHelper::rBHelper.bInDispose && !OContentHelper::rBHelper.bDisposed )
+ {
+ acquire();
+ dispose();
+ }
+
+ if ( m_pInterceptor.is() )
+ {
+ m_pInterceptor->dispose();
+ m_pInterceptor.clear();
+ }
+}
+
+void ODocumentDefinition::closeObject()
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if ( m_xEmbeddedObject.is() )
+ {
+ try
+ {
+ m_xEmbeddedObject->close(true);
+ }
+ catch(const Exception&)
+ {
+ }
+ m_xEmbeddedObject = nullptr;
+ m_pClientHelper.clear();
+ }
+}
+
+void SAL_CALL ODocumentDefinition::disposing()
+{
+ OContentHelper::disposing();
+ ::osl::MutexGuard aGuard(m_aMutex);
+ closeObject();
+ ::comphelper::disposeComponent(m_xListener);
+ if ( m_bRemoveListener )
+ {
+ Reference<util::XCloseable> xCloseable(m_pImpl->m_pDataSource->getModel_noCreate(),UNO_QUERY);
+ if ( xCloseable.is() )
+ xCloseable->removeCloseListener(this);
+ }
+}
+
+css::uno::Sequence<sal_Int8> ODocumentDefinition::getImplementationId()
+{
+ return css::uno::Sequence<sal_Int8>();
+}
+
+css::uno::Sequence< css::uno::Type > ODocumentDefinition::getTypes()
+{
+ return ::comphelper::concatSequences(
+ OContentHelper::getTypes( ),
+ OPropertyStateContainer::getTypes( ),
+ ODocumentDefinition_Base::getTypes( )
+ );
+}
+IMPLEMENT_FORWARD_XINTERFACE3( ODocumentDefinition,OContentHelper,OPropertyStateContainer,ODocumentDefinition_Base)
+
+void ODocumentDefinition::registerProperties()
+{
+ registerProperty(PROPERTY_NAME, PROPERTY_ID_NAME, PropertyAttribute::CONSTRAINED | PropertyAttribute::BOUND | PropertyAttribute::READONLY,
+ &m_pImpl->m_aProps.aTitle, cppu::UnoType<decltype(m_pImpl->m_aProps.aTitle)>::get());
+
+ registerProperty(PROPERTY_AS_TEMPLATE, PROPERTY_ID_AS_TEMPLATE, PropertyAttribute::READONLY, &m_pImpl->m_aProps.bAsTemplate,
+ cppu::UnoType<decltype(m_pImpl->m_aProps.bAsTemplate)>::get());
+
+ registerProperty(PROPERTY_PERSISTENT_NAME, PROPERTY_ID_PERSISTENT_NAME, PropertyAttribute::READONLY, &m_pImpl->m_aProps.sPersistentName,
+ cppu::UnoType<decltype(m_pImpl->m_aProps.sPersistentName)>::get());
+
+ registerProperty(PROPERTY_IS_FORM, PROPERTY_ID_IS_FORM, PropertyAttribute::READONLY, &m_bForm, cppu::UnoType<decltype(m_bForm)>::get());
+}
+
+void SAL_CALL ODocumentDefinition::getFastPropertyValue( Any& o_rValue, sal_Int32 i_nHandle ) const
+{
+ if ( i_nHandle == PROPERTY_ID_PERSISTENT_PATH )
+ {
+ OUString sPersistentPath;
+ if ( !m_pImpl->m_aProps.sPersistentName.isEmpty() )
+ {
+ sPersistentPath = ODatabaseModelImpl::getObjectContainerStorageName( m_bForm ? ODatabaseModelImpl::E_FORM : ODatabaseModelImpl::E_REPORT )
+ + "/" + m_pImpl->m_aProps.sPersistentName;
+ }
+ o_rValue <<= sPersistentPath;
+ return;
+ }
+
+ OPropertyStateContainer::getFastPropertyValue( o_rValue, i_nHandle );
+}
+
+Reference< XPropertySetInfo > SAL_CALL ODocumentDefinition::getPropertySetInfo( )
+{
+ Reference<XPropertySetInfo> xInfo( createPropertySetInfo( getInfoHelper() ) );
+ return xInfo;
+}
+
+IPropertyArrayHelper& ODocumentDefinition::getInfoHelper()
+{
+ return *getArrayHelper();
+}
+
+IPropertyArrayHelper* ODocumentDefinition::createArrayHelper( ) const
+{
+ // properties maintained by our base class (see registerProperties)
+ Sequence< Property > aProps;
+ describeProperties( aProps );
+
+ // properties not maintained by our base class
+ Sequence< Property > aManualProps{ { /* Name */ PROPERTY_PERSISTENT_PATH,
+ /* Handle */ PROPERTY_ID_PERSISTENT_PATH,
+ /* Type */ ::cppu::UnoType<OUString>::get(),
+ /* Attributes */ PropertyAttribute::READONLY } };
+
+ return new OPropertyArrayHelper( ::comphelper::concatSequences( aProps, aManualProps ) );
+}
+
+namespace {
+
+class OExecuteImpl
+{
+ bool& m_rbSet;
+public:
+ explicit OExecuteImpl(bool& _rbSet) : m_rbSet(_rbSet){ m_rbSet=true; }
+ ~OExecuteImpl(){ m_rbSet = false; }
+};
+
+ bool lcl_extractOpenMode( const Any& _rValue, sal_Int32& _out_rMode )
+ {
+ OpenCommandArgument aOpenCommand;
+ if ( _rValue >>= aOpenCommand )
+ _out_rMode = aOpenCommand.Mode;
+ else
+ {
+ OpenCommandArgument2 aOpenCommand2;
+ if ( _rValue >>= aOpenCommand2 )
+ _out_rMode = aOpenCommand2.Mode;
+ else
+ return false;
+ }
+ return true;
+ }
+}
+
+void ODocumentDefinition::impl_removeFrameFromDesktop_throw( const Reference<XComponentContext> & _rxContext, const Reference< XFrame >& _rxFrame )
+{
+ Reference< XDesktop2 > xDesktop = Desktop::create( _rxContext );
+ Reference< XFrames > xFrames( xDesktop->getFrames(), UNO_SET_THROW );
+ xFrames->remove( _rxFrame );
+}
+
+void ODocumentDefinition::impl_onActivateEmbeddedObject_nothrow( const bool i_bReactivated )
+{
+ try
+ {
+ Reference< XModel > xModel( getComponent(), UNO_QUERY );
+ Reference< XController > xController( xModel.is() ? xModel->getCurrentController() : Reference< XController >() );
+ if ( !xController.is() )
+ return;
+
+ if ( !m_xListener.is() )
+ // it's the first time the embedded object has been activated
+ // create an OEmbedObjectHolder
+ m_xListener = new OEmbedObjectHolder( m_xEmbeddedObject, this );
+
+ // raise the window to top (especially necessary if this is not the first activation)
+ Reference< XFrame > xFrame( xController->getFrame(), UNO_SET_THROW );
+ Reference< XTopWindow > xTopWindow( xFrame->getContainerWindow(), UNO_QUERY_THROW );
+ xTopWindow->toFront();
+
+ // remove the frame from the desktop's frame collection because we need full control of it.
+ impl_removeFrameFromDesktop_throw( m_aContext, xFrame );
+
+ // ensure that we ourself are kept alive as long as the embedded object's frame is
+ // opened
+ LifetimeCoupler::couple( *this, xFrame );
+
+ // init the edit view
+ if ( m_bForm && m_bOpenInDesign && !i_bReactivated )
+ impl_initFormEditView( xController );
+ }
+ catch( const RuntimeException& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+namespace
+{
+ // PreserveVisualAreaSize
+ /** stack-guard for preserving the size of the VisArea of an XModel
+ */
+ class PreserveVisualAreaSize
+ {
+ private:
+ Reference< XVisualObject > m_xVisObject;
+ awt::Size m_aOriginalSize;
+
+ public:
+ explicit PreserveVisualAreaSize( const Reference< XModel >& _rxModel )
+ :m_xVisObject( _rxModel, UNO_QUERY )
+ {
+ if ( m_xVisObject.is() )
+ {
+ try
+ {
+ m_aOriginalSize = m_xVisObject->getVisualAreaSize( Aspects::MSOLE_CONTENT );
+ }
+ catch ( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "PreserveVisualAreaSize::PreserveVisualAreaSize" );
+ }
+ }
+ }
+
+ ~PreserveVisualAreaSize()
+ {
+ if ( m_xVisObject.is() && m_aOriginalSize.Width && m_aOriginalSize.Height )
+ {
+ try
+ {
+ m_xVisObject->setVisualAreaSize( Aspects::MSOLE_CONTENT, m_aOriginalSize );
+ }
+ catch ( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "PreserveVisualAreaSize::~PreserveVisualAreaSize" );
+ }
+ }
+ }
+ };
+
+ // LayoutManagerLock
+ /** helper class for stack-usage which during its lifetime locks a layout manager
+ */
+ class LayoutManagerLock
+ {
+ private:
+ Reference< XLayoutManager > m_xLayoutManager;
+
+ public:
+ explicit LayoutManagerLock( const Reference< XController >& _rxController )
+ {
+ OSL_ENSURE( _rxController.is(), "LayoutManagerLock::LayoutManagerLock: this will crash!" );
+ Reference< XFrame > xFrame( _rxController->getFrame() );
+ try
+ {
+ Reference< XPropertySet > xPropSet( xFrame, UNO_QUERY_THROW );
+ m_xLayoutManager.set(
+ xPropSet->getPropertyValue( "LayoutManager" ),
+ UNO_QUERY_THROW );
+ m_xLayoutManager->lock();
+
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "LayoutManagerLock::LayoutManagerLock" );
+ }
+ }
+
+ ~LayoutManagerLock()
+ {
+ try
+ {
+ // unlock the layout manager
+ if ( m_xLayoutManager.is() )
+ m_xLayoutManager->unlock();
+ }
+ catch( const Exception& )
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "LayoutManagerLock::~LayoutManagerLock" );
+ }
+ }
+ };
+}
+
+void ODocumentDefinition::impl_initFormEditView( const Reference< XController >& _rxController )
+{
+ try
+ {
+ Reference< XViewSettingsSupplier > xSettingsSupplier( _rxController, UNO_QUERY_THROW );
+ Reference< XPropertySet > xViewSettings( xSettingsSupplier->getViewSettings(), UNO_SET_THROW );
+
+ // the below code could indirectly tamper with the "modified" flag of the model, temporarily disable this
+ LockModifiable aLockModify( _rxController->getModel() );
+
+ // The visual area size can be changed by the setting of the following properties
+ // so it should be restored later
+ PreserveVisualAreaSize aPreserveVisAreaSize( _rxController->getModel() );
+
+ // Layout manager should not layout while the size is still not restored
+ // so it will stay locked for this time
+ LayoutManagerLock aLockLayout( _rxController );
+
+ // setting of the visual properties
+ xViewSettings->setPropertyValue("ShowRulers",Any(true));
+ xViewSettings->setPropertyValue("ShowVertRuler",Any(true));
+ xViewSettings->setPropertyValue("ShowHoriRuler",Any(true));
+ xViewSettings->setPropertyValue("IsRasterVisible",Any(true));
+ xViewSettings->setPropertyValue("IsSnapToRaster",Any(true));
+ xViewSettings->setPropertyValue("ShowOnlineLayout",Any(true));
+ xViewSettings->setPropertyValue("RasterSubdivisionX",Any(sal_Int32(5)));
+ xViewSettings->setPropertyValue("RasterSubdivisionY",Any(sal_Int32(5)));
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void ODocumentDefinition::impl_showOrHideComponent_throw( const bool i_bShow )
+{
+ const sal_Int32 nCurrentState = m_xEmbeddedObject.is() ? m_xEmbeddedObject->getCurrentState() : EmbedStates::LOADED;
+ switch ( nCurrentState )
+ {
+ default:
+ case EmbedStates::LOADED:
+ throw embed::WrongStateException( OUString(), *this );
+
+ case EmbedStates::RUNNING:
+ if ( !i_bShow )
+ // fine, a running (and not yet active) object is never visible
+ return;
+ {
+ LockModifiable aLockModify( impl_getComponent_throw() );
+ m_xEmbeddedObject->changeState( EmbedStates::ACTIVE );
+ impl_onActivateEmbeddedObject_nothrow( false );
+ }
+ break;
+
+ case EmbedStates::ACTIVE:
+ {
+ Reference< XModel > xEmbeddedDoc( impl_getComponent_throw(), UNO_QUERY_THROW );
+ Reference< XController > xEmbeddedController( xEmbeddedDoc->getCurrentController(), UNO_SET_THROW );
+ Reference< XFrame > xEmbeddedFrame( xEmbeddedController->getFrame(), UNO_SET_THROW );
+ Reference< XWindow > xEmbeddedWindow( xEmbeddedFrame->getContainerWindow(), UNO_SET_THROW );
+ xEmbeddedWindow->setVisible( i_bShow );
+ }
+ break;
+ }
+}
+
+Any ODocumentDefinition::onCommandOpenSomething( const Any& _rOpenArgument, const bool _bActivate,
+ const Reference< XCommandEnvironment >& _rxEnvironment )
+{
+ OExecuteImpl aExecuteGuard( m_bInExecute );
+
+ Reference< XConnection > xConnection;
+ sal_Int32 nOpenMode = OpenMode::DOCUMENT;
+
+ ::comphelper::NamedValueCollection aDocumentArgs;
+
+ // for the document, default to the interaction handler as used for loading the DB doc
+ // This might be overwritten below, when examining _rOpenArgument.
+ const ::comphelper::NamedValueCollection& aDBDocArgs( m_pImpl->m_pDataSource->getMediaDescriptor() );
+ Reference< XInteractionHandler > xHandler( aDBDocArgs.getOrDefault( "InteractionHandler", Reference< XInteractionHandler >() ) );
+ if ( xHandler.is() )
+ aDocumentArgs.put( "InteractionHandler", xHandler );
+
+ ::std::optional< sal_Int16 > aDocumentMacroMode;
+
+ if ( !lcl_extractOpenMode( _rOpenArgument, nOpenMode ) )
+ {
+ Sequence< PropertyValue > aArguments;
+ if ( _rOpenArgument >>= aArguments )
+ {
+ const PropertyValue* pIter = aArguments.getConstArray();
+ const PropertyValue* pEnd = pIter + aArguments.getLength();
+ for ( ;pIter != pEnd; ++pIter )
+ {
+ if ( pIter->Name == PROPERTY_ACTIVE_CONNECTION )
+ {
+ xConnection.set( pIter->Value, UNO_QUERY );
+ continue;
+ }
+
+ if ( lcl_extractOpenMode( pIter->Value, nOpenMode ) )
+ continue;
+
+ if ( pIter->Name == "MacroExecutionMode" )
+ {
+ sal_Int16 nMacroExecMode( !aDocumentMacroMode ? MacroExecMode::USE_CONFIG : *aDocumentMacroMode );
+ OSL_VERIFY( pIter->Value >>= nMacroExecMode );
+ aDocumentMacroMode = nMacroExecMode;
+ continue;
+ }
+
+ // unknown argument -> pass to the loaded document
+ aDocumentArgs.put( pIter->Name, pIter->Value );
+ }
+ }
+ }
+
+ bool bExecuteDBDocMacros = m_pImpl->m_pDataSource->checkMacrosOnLoading();
+ // Note that this call implies the user might be asked for the macro execution mode.
+ // Normally, this would happen when the database document is loaded, and subsequent calls
+ // will simply use the user's decision from this point in time.
+ // However, it is possible to programmatically load forms/reports, without actually
+ // loading the database document into a frame. In this case, the user will be asked
+ // here and now.
+ // #i87741#
+
+ // allow the command arguments to downgrade the macro execution mode, but not to upgrade
+ // it
+ if ( ( m_pImpl->m_pDataSource->getImposedMacroExecMode() == MacroExecMode::USE_CONFIG )
+ && bExecuteDBDocMacros
+ )
+ {
+ // while loading the whole database document, USE_CONFIG, was passed.
+ // Additionally, *by now* executing macros from the DB doc is allowed (this is what bExecuteDBDocMacros
+ // indicates). This means either one of:
+ // 1. The DB doc or one of the sub docs contained macros and
+ // 1a. the user explicitly allowed executing them
+ // 1b. the configuration allows executing them without asking the user
+ // 2. Neither the DB doc nor the sub docs contained macros, thus macro
+ // execution was silently enabled, assuming that any macro will be a
+ // user-created macro
+ //
+ // The problem with this: If the to-be-opened sub document has macros embedded in
+ // the content.xml (which is valid ODF, but normally not produced by OOo itself),
+ // then this has not been detected while loading the database document - it would
+ // be too expensive, as it effectively would require loading all forms/reports.
+ //
+ // So, in such a case, and with 2. above, we would silently execute those macros,
+ // regardless of the global security settings - which would be a security issue, of
+ // course.
+ if ( m_pImpl->m_pDataSource->determineEmbeddedMacros() == ODatabaseModelImpl::eNoMacros )
+ {
+ // this is case 2. from above
+ // So, pass a USE_CONFIG to the to-be-loaded document. This means that
+ // the user will be prompted with a security message upon opening this
+ // sub document, in case the settings require this, *and* the document
+ // contains scripts in the content.xml. But this is better than the security
+ // issue we had before ...
+ aDocumentMacroMode = MacroExecMode::USE_CONFIG;
+ }
+ }
+
+ if ( !aDocumentMacroMode )
+ {
+ // nobody so far felt responsible for setting it
+ // => use the DBDoc-wide macro exec mode for the document, too
+ aDocumentMacroMode = bExecuteDBDocMacros ? MacroExecMode::ALWAYS_EXECUTE_NO_WARN
+ : MacroExecMode::NEVER_EXECUTE;
+ }
+ aDocumentArgs.put( "MacroExecutionMode", *aDocumentMacroMode );
+
+ if ( ( nOpenMode == OpenMode::ALL )
+ || ( nOpenMode == OpenMode::FOLDERS )
+ || ( nOpenMode == OpenMode::DOCUMENTS )
+ || ( nOpenMode == OpenMode::DOCUMENT_SHARE_DENY_NONE )
+ || ( nOpenMode == OpenMode::DOCUMENT_SHARE_DENY_WRITE )
+ )
+ {
+ // not supported
+ ucbhelper::cancelCommandExecution(
+ Any( UnsupportedOpenModeException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ sal_Int16( nOpenMode ) ) ),
+ _rxEnvironment );
+ // Unreachable
+ OSL_FAIL( "unreachable" );
+ }
+
+ OSL_ENSURE( !m_pImpl->m_aProps.sPersistentName.isEmpty(),
+ "ODocumentDefinition::onCommandOpenSomething: no persistent name - cannot load!" );
+ if ( m_pImpl->m_aProps.sPersistentName.isEmpty() )
+ return Any();
+
+ // embedded objects themself do not support the hidden flag. We implement support for
+ // it by changing the STATE to RUNNING only, instead of ACTIVE.
+ bool bOpenHidden = aDocumentArgs.getOrDefault( "Hidden", false );
+ aDocumentArgs.remove( "Hidden" );
+
+ loadEmbeddedObject( xConnection, Sequence< sal_Int8 >(), aDocumentArgs.getPropertyValues(), false, !m_bOpenInDesign );
+ OSL_ENSURE( m_xEmbeddedObject.is(), "ODocumentDefinition::onCommandOpenSomething: what's this?" );
+ if ( !m_xEmbeddedObject.is() )
+ return Any();
+
+ Reference< XModel > xModel( getComponent(), UNO_QUERY );
+ Reference< report::XReportDefinition > xReportDefinition(xModel,UNO_QUERY);
+
+ Reference< XModule > xModule( xModel, UNO_QUERY );
+ if ( xModule.is() )
+ {
+ if ( m_bForm )
+ xModule->setIdentifier( "com.sun.star.sdb.FormDesign" );
+ else if ( !xReportDefinition.is() )
+ xModule->setIdentifier( "com.sun.star.text.TextDocument" );
+
+ updateDocumentTitle();
+ }
+
+ bool bIsAliveNewStyleReport = ( !m_bOpenInDesign && xReportDefinition.is() );
+ if ( bIsAliveNewStyleReport )
+ {
+ // we are in ReadOnly mode
+ // we would like to open the Writer or Calc with the report direct, without design it.
+ Reference< report::XReportEngine > xReportEngine( m_aContext->getServiceManager()->createInstanceWithContext("com.sun.star.comp.report.OReportEngineJFree", m_aContext), UNO_QUERY_THROW );
+
+ xReportEngine->setReportDefinition(xReportDefinition);
+ xReportEngine->setActiveConnection(m_xLastKnownConnection);
+ if ( bOpenHidden )
+ return Any( xReportEngine->createDocumentModel() );
+ return Any( xReportEngine->createDocumentAlive( nullptr ) );
+ }
+
+ if ( _bActivate && !bOpenHidden )
+ {
+ LockModifiable aLockModify( impl_getComponent_throw() );
+ m_xEmbeddedObject->changeState( EmbedStates::ACTIVE );
+ impl_onActivateEmbeddedObject_nothrow( false );
+ }
+ else
+ {
+ // ensure that we ourself are kept alive as long as the document is open
+ LifetimeCoupler::couple( *this, xModel );
+ }
+
+ if ( !m_bForm && m_pImpl->m_aProps.bAsTemplate && !m_bOpenInDesign )
+ ODocumentDefinition::fillReportData( m_aContext, getComponent(), xConnection );
+
+ return Any( xModel );
+}
+
+Any SAL_CALL ODocumentDefinition::execute( const Command& aCommand, sal_Int32 CommandId, const Reference< XCommandEnvironment >& Environment )
+{
+ Any aRet;
+
+ bool bOpen = aCommand.Name == "open";
+ bool bOpenInDesign = aCommand.Name == "openDesign";
+ bool bOpenForMail = aCommand.Name == "openForMail";
+ if ( bOpen || bOpenInDesign || bOpenForMail )
+ {
+ // opening the document involves a lot of VCL code, which is not thread-safe, but needs the SolarMutex locked.
+ // Unfortunately, the DocumentDefinition, as well as the EmbeddedObject implementation, calls into VCL-dependent
+ // components *without* releasing the own mutex, which is a guaranteed recipe for deadlocks.
+ // We have control over this implementation here, and in modifying it to release the own mutex before calling into
+ // the VCL-dependent components is not too difficult (was there, seen it).
+ // However, we do /not/ have control over the EmbeddedObject implementation, and from a first look, it seems as
+ // making it release the own mutex before calling SolarMutex-code is ... difficult, at least.
+ // So, to be on the same side, we lock the SolarMutex here. Yes, it sucks.
+ ::SolarMutexGuard aSolarGuard;
+ osl::MutexGuard aGuard(m_aMutex);
+ if ( m_bInExecute )
+ return aRet;
+
+ bool bActivateObject = true;
+ if ( bOpenForMail )
+ {
+ OSL_FAIL( "ODocumentDefinition::execute: 'openForMail' should not be used anymore - use the 'Hidden' parameter instead!" );
+ bActivateObject = false;
+ }
+
+ // if the object is already opened, do nothing
+ if ( m_xEmbeddedObject.is() )
+ {
+ sal_Int32 nCurrentState = m_xEmbeddedObject->getCurrentState();
+ bool bIsActive = ( nCurrentState == EmbedStates::ACTIVE );
+
+ if ( bIsActive )
+ {
+ // exception: new-style reports always create a new document when "open" is executed
+ Reference< report::XReportDefinition > xReportDefinition( impl_getComponent_throw( false ), UNO_QUERY );
+ bool bIsAliveNewStyleReport = ( xReportDefinition.is() && ( bOpen || bOpenForMail ) );
+
+ if ( !bIsAliveNewStyleReport )
+ {
+ impl_onActivateEmbeddedObject_nothrow( true );
+ return Any( getComponent() );
+ }
+ }
+ }
+
+ m_bOpenInDesign = bOpenInDesign || bOpenForMail;
+ return onCommandOpenSomething( aCommand.Argument, bActivateObject, Environment );
+ }
+
+ osl::MutexGuard aGuard(m_aMutex);
+ if ( m_bInExecute )
+ return aRet;
+
+ if ( aCommand.Name == "copyTo" )
+ {
+ Sequence<Any> aIni;
+ aCommand.Argument >>= aIni;
+ if ( aIni.getLength() != 2 )
+ {
+ OSL_FAIL( "Wrong argument type!" );
+ ucbhelper::cancelCommandExecution(
+ Any( IllegalArgumentException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ -1 ) ),
+ Environment );
+ // Unreachable
+ }
+ Reference< XStorage> xDest(aIni[0],UNO_QUERY);
+ OUString sPersistentName;
+ aIni[1] >>= sPersistentName;
+ Reference< XStorage> xStorage = getContainerStorage();
+
+ xStorage->copyElementTo(m_pImpl->m_aProps.sPersistentName,xDest,sPersistentName);
+ }
+ else if ( aCommand.Name == "preview" )
+ {
+ onCommandPreview(aRet);
+ }
+ else if ( aCommand.Name == "insert" )
+ {
+ Sequence<Any> aIni;
+ aCommand.Argument >>= aIni;
+ if ( !aIni.hasElements() )
+ {
+ OSL_FAIL( "Wrong argument count!" );
+ ucbhelper::cancelCommandExecution(
+ Any( IllegalArgumentException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ -1 ) ),
+ Environment );
+ // Unreachable
+ }
+ OUString sURL;
+ aIni[0] >>= sURL;
+ onCommandInsert( sURL, Environment );
+ }
+ else if ( aCommand.Name == "getdocumentinfo" // compatibility
+ || aCommand.Name == "getDocumentInfo" )
+ {
+ onCommandGetDocumentProperties( aRet );
+ }
+ else if ( aCommand.Name == "delete" )
+ {
+ // delete
+ closeObject();
+ Reference< XStorage> xStorage = getContainerStorage();
+ if ( xStorage.is() )
+ xStorage->removeElement(m_pImpl->m_aProps.sPersistentName);
+
+ dispose();
+
+ }
+ else if ( aCommand.Name == "storeOwn" // compatibility
+ || aCommand.Name == "store"
+ )
+ {
+ impl_store_throw();
+ }
+ else if ( aCommand.Name == "shutdown" // compatibility
+ || aCommand.Name == "close"
+ )
+ {
+ aRet <<= impl_close_throw();
+ }
+ else if ( aCommand.Name == "show" )
+ {
+ impl_showOrHideComponent_throw( true );
+ }
+ else if ( aCommand.Name == "hide" )
+ {
+ impl_showOrHideComponent_throw( false );
+ }
+ else
+ {
+ aRet = OContentHelper::execute(aCommand,CommandId,Environment);
+ }
+
+ return aRet;
+}
+
+namespace
+{
+ void lcl_resetChildFormsToEmptyDataSource( const Reference< XIndexAccess>& _rxFormsContainer )
+ {
+ OSL_PRECOND( _rxFormsContainer.is(), "lcl_resetChildFormsToEmptyDataSource: illegal call!" );
+ sal_Int32 count = _rxFormsContainer->getCount();
+ for ( sal_Int32 i = 0; i < count; ++i )
+ {
+ Reference< XForm > xForm( _rxFormsContainer->getByIndex( i ), UNO_QUERY );
+ if ( !xForm.is() )
+ continue;
+
+ // if the element is a form, reset its DataSourceName property to an empty string
+ try
+ {
+ Reference< XPropertySet > xFormProps( xForm, UNO_QUERY_THROW );
+ xFormProps->setPropertyValue( PROPERTY_DATASOURCENAME, Any( OUString() ) );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ // if the element is a container itself, step down the component hierarchy
+ Reference< XIndexAccess > xContainer( xForm, UNO_QUERY );
+ if ( xContainer.is() )
+ lcl_resetChildFormsToEmptyDataSource( xContainer );
+ }
+ }
+
+ void lcl_resetFormsToEmptyDataSource( const Reference< XEmbeddedObject>& _rxEmbeddedObject )
+ {
+ try
+ {
+ Reference< XDrawPageSupplier > xSuppPage( _rxEmbeddedObject->getComponent(), UNO_QUERY_THROW );
+ // if this interface does not exist, then either getComponent returned NULL,
+ // or the document is a multi-page document. The latter is allowed, but currently
+ // simply not handled by this code, as it would not normally happen.
+
+ Reference< XFormsSupplier > xSuppForms( xSuppPage->getDrawPage(), UNO_QUERY_THROW );
+ Reference< XIndexAccess > xForms( xSuppForms->getForms(), UNO_QUERY_THROW );
+ lcl_resetChildFormsToEmptyDataSource( xForms );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ }
+}
+
+void ODocumentDefinition::onCommandInsert( const OUString& _sURL, const Reference< XCommandEnvironment >& Environment )
+{
+ osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
+
+ // Check, if all required properties were set.
+ if ( _sURL.isEmpty() || m_xEmbeddedObject.is() )
+ {
+ OSL_FAIL( "Content::onCommandInsert - property value missing!" );
+
+ Sequence<OUString> aProps { PROPERTY_URL };
+ ucbhelper::cancelCommandExecution(
+ Any( MissingPropertiesException(
+ OUString(),
+ static_cast< cppu::OWeakObject * >( this ),
+ aProps ) ),
+ Environment );
+ // Unreachable
+ }
+
+ if ( !m_xEmbeddedObject.is() )
+ {
+ Reference< XStorage> xStorage = getContainerStorage();
+ if ( xStorage.is() )
+ {
+ Reference< XEmbeddedObjectCreator> xEmbedFactory = EmbeddedObjectCreator::create(m_aContext);
+ Sequence<PropertyValue> aEmpty;
+ Sequence<PropertyValue> aMediaDesc{ comphelper::makePropertyValue(PROPERTY_URL,
+ _sURL) };
+ m_xEmbeddedObject.set(xEmbedFactory->createInstanceInitFromMediaDescriptor( xStorage
+ ,m_pImpl->m_aProps.sPersistentName
+ ,aMediaDesc
+ ,aEmpty),UNO_QUERY);
+
+ lcl_resetFormsToEmptyDataSource( m_xEmbeddedObject );
+ // #i57669#
+
+ Reference<XEmbedPersist> xPersist(m_xEmbeddedObject,UNO_QUERY);
+ if ( xPersist.is() )
+ {
+ xPersist->storeOwn();
+ }
+ try
+ {
+ if ( m_xEmbeddedObject.is() )
+ m_xEmbeddedObject->close(true);
+ }
+ catch(const Exception&)
+ {
+ }
+ m_xEmbeddedObject = nullptr;
+ }
+ }
+
+ aGuard.clear();
+}
+
+bool ODocumentDefinition::save(bool _bApprove, const css::uno::Reference<css::awt::XTopWindow>& rDialogParent)
+{
+ // default handling: instantiate an interaction handler and let it handle the parameter request
+ if ( !m_bOpenInDesign )
+ return false;
+ try
+ {
+
+ {
+ ::SolarMutexGuard aSolarGuard;
+
+ // the request
+ Reference<XNameAccess> xName(m_xParentContainer,UNO_QUERY);
+ DocumentSaveRequest aRequest;
+ aRequest.Name = m_pImpl->m_aProps.aTitle;
+ if ( aRequest.Name.isEmpty() )
+ {
+ if ( m_bForm )
+ aRequest.Name = DBA_RES( RID_STR_FORM );
+ else
+ aRequest.Name = DBA_RES( RID_STR_REPORT );
+ aRequest.Name = ::dbtools::createUniqueName(xName,aRequest.Name);
+ }
+
+ aRequest.Content.set(m_xParentContainer,UNO_QUERY);
+ rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest(Any(aRequest));
+ // some knittings
+ // two continuations allowed: OK and Cancel
+ rtl::Reference<ODocumentSaveContinuation> pDocuSave;
+
+ if ( m_pImpl->m_aProps.aTitle.isEmpty() )
+ {
+ pDocuSave = new ODocumentSaveContinuation;
+ pRequest->addContinuation(pDocuSave);
+ }
+ if ( _bApprove )
+ {
+ rtl::Reference<OInteraction< XInteractionApprove >> pApprove = new OInteraction< XInteractionApprove >;
+ pRequest->addContinuation(pApprove);
+ }
+
+ rtl::Reference<OInteraction< XInteractionDisapprove >> pDisApprove = new OInteraction< XInteractionDisapprove >;
+ pRequest->addContinuation(pDisApprove);
+
+ rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
+ pRequest->addContinuation(pAbort);
+
+ Reference<XWindow> xDialogParent(rDialogParent, UNO_QUERY);
+
+ // create the handler, let it handle the request
+ Reference<XInteractionHandler2> xHandler(InteractionHandler::createWithParent(m_aContext, xDialogParent));
+ xHandler->handle(pRequest);
+
+ if ( pAbort->wasSelected() )
+ return false;
+ if ( pDisApprove->wasSelected() )
+ return true;
+ if ( pDocuSave && pDocuSave->wasSelected() )
+ {
+ Reference<XNameContainer> xNC( pDocuSave->getContent(), UNO_QUERY_THROW );
+
+ ::osl::ResettableMutexGuard aGuard( m_aMutex );
+ NameChangeNotifier aNameChangeAndNotify( *this, pDocuSave->getName(), aGuard );
+ m_pImpl->m_aProps.aTitle = pDocuSave->getName();
+
+ Reference< XContent> xContent = this;
+ xNC->insertByName(pDocuSave->getName(),Any(xContent));
+
+ updateDocumentTitle();
+ }
+ }
+
+ ::osl::MutexGuard aGuard(m_aMutex);
+ Reference<XEmbedPersist> xPersist(m_xEmbeddedObject,UNO_QUERY);
+ if ( xPersist.is() )
+ {
+ xPersist->storeOwn();
+ notifyDataSourceModified();
+ }
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "ODocumentDefinition::save: caught an Exception (tried to let the InteractionHandler handle it)!");
+ }
+ return true;
+}
+
+void ODocumentDefinition::saveAs()
+{
+ // default handling: instantiate an interaction handler and let it handle the parameter request
+ if ( !m_bOpenInDesign )
+ return;
+
+ {
+ osl::ClearableGuard< osl::Mutex > aGuard( m_aMutex );
+ if ( m_pImpl->m_aProps.aTitle.isEmpty() )
+ {
+ aGuard.clear();
+ save(false, css::uno::Reference<css::awt::XTopWindow>()); // (sal_False) : we don't want an approve dialog
+ return;
+ }
+ }
+ try
+ {
+ ::SolarMutexGuard aSolarGuard;
+
+ // the request
+ DocumentSaveRequest aRequest;
+ aRequest.Name = m_pImpl->m_aProps.aTitle;
+
+ aRequest.Content.set(m_xParentContainer,UNO_QUERY);
+ rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest(Any(aRequest));
+ // some knittings
+ // two continuations allowed: OK and Cancel
+ rtl::Reference<ODocumentSaveContinuation> pDocuSave = new ODocumentSaveContinuation;
+ pRequest->addContinuation(pDocuSave);
+ rtl::Reference<OInteraction< XInteractionDisapprove >> pDisApprove = new OInteraction< XInteractionDisapprove >;
+ pRequest->addContinuation(pDisApprove);
+ rtl::Reference<OInteractionAbort> pAbort = new OInteractionAbort;
+ pRequest->addContinuation(pAbort);
+
+ // create the handler, let it handle the request
+ Reference< XInteractionHandler2 > xHandler( InteractionHandler::createWithParent(m_aContext, nullptr) );
+ xHandler->handle(pRequest);
+
+ if ( pAbort->wasSelected() )
+ return;
+ if ( pDisApprove->wasSelected() )
+ return;
+ if ( pDocuSave->wasSelected() )
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+ Reference<XNameContainer> xNC(pDocuSave->getContent(),UNO_QUERY);
+ if ( xNC.is() )
+ {
+ if ( m_pImpl->m_aProps.aTitle != pDocuSave->getName() )
+ {
+ try
+ {
+ Reference< XStorage> xStorage = getContainerStorage();
+
+ OUString sPersistentName = ::dbtools::createUniqueName(xStorage,"Obj");
+ xStorage->copyElementTo(m_pImpl->m_aProps.sPersistentName,xStorage,sPersistentName);
+
+ OUString sOldName = m_pImpl->m_aProps.aTitle;
+ rename(pDocuSave->getName());
+ updateDocumentTitle();
+
+ uno::Sequence<uno::Any> aArguments(comphelper::InitAnyPropertySequence(
+ {
+ {PROPERTY_NAME, uno::Any(sOldName)}, // set as folder
+ {PROPERTY_PERSISTENT_NAME, uno::Any(sPersistentName)},
+ {PROPERTY_AS_TEMPLATE, uno::Any(m_pImpl->m_aProps.bAsTemplate)},
+ }));
+ Reference< XMultiServiceFactory > xORB( m_xParentContainer, UNO_QUERY_THROW );
+ Reference< XInterface > xComponent( xORB->createInstanceWithArguments( SERVICE_SDB_DOCUMENTDEFINITION, aArguments ) );
+ Reference< XNameContainer > xNameContainer( m_xParentContainer, UNO_QUERY_THROW );
+ xNameContainer->insertByName( sOldName, Any( xComponent ) );
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ Reference<XEmbedPersist> xPersist(m_xEmbeddedObject,UNO_QUERY);
+ if ( xPersist.is() )
+ {
+ xPersist->storeOwn();
+ notifyDataSourceModified();
+ }
+ }
+ }
+ }
+ catch(const Exception&)
+ {
+ TOOLS_WARN_EXCEPTION( "dbaccess", "ODocumentDefinition::save: caught an Exception (tried to let the InteractionHandler handle it)!");
+ }
+}
+
+namespace
+{
+ void lcl_putLoadArgs( ::comphelper::NamedValueCollection& _io_rArgs, const optional_bool& _bSuppressMacros, const optional_bool& _bReadOnly )
+ {
+ if ( !!_bSuppressMacros )
+ {
+ if ( *_bSuppressMacros )
+ {
+ // if we're to suppress macros, do exactly this
+ _io_rArgs.put( "MacroExecutionMode", MacroExecMode::NEVER_EXECUTE );
+ }
+ else
+ {
+ // otherwise, put the setting only if not already present
+ if ( !_io_rArgs.has( "MacroExecutionMode" ) )
+ {
+ _io_rArgs.put( "MacroExecutionMode", MacroExecMode::USE_CONFIG );
+ }
+ }
+ }
+
+ if ( !!_bReadOnly )
+ _io_rArgs.put( "ReadOnly", *_bReadOnly );
+ }
+}
+
+namespace
+{
+ Reference< XFrame > lcl_getDatabaseDocumentFrame( ODatabaseModelImpl const & _rImpl )
+ {
+ Reference< XModel > xDatabaseDocumentModel( _rImpl.getModel_noCreate() );
+
+ Reference< XController > xDatabaseDocumentController;
+ if ( xDatabaseDocumentModel.is() )
+ xDatabaseDocumentController = xDatabaseDocumentModel->getCurrentController();
+
+ Reference< XFrame > xFrame;
+ if ( xDatabaseDocumentController.is() )
+ xFrame = xDatabaseDocumentController->getFrame();
+
+ return xFrame;
+ }
+}
+
+bool ODocumentDefinition::objectSupportsEmbeddedScripts() const
+{
+ bool bAllowDocumentMacros = !m_pImpl->m_pDataSource
+ || ( m_pImpl->m_pDataSource->determineEmbeddedMacros() == ODatabaseModelImpl::eSubDocumentMacros );
+
+ // if *any* of the objects of the database document already has macros, we
+ // continue to allow it to have them, until the user does a migration.
+ // If there are no macros, we don't allow them to be created.
+
+ return bAllowDocumentMacros;
+}
+
+OUString ODocumentDefinition::determineContentType() const
+{
+ return lcl_determineContentType_nothrow( getContainerStorage(), m_pImpl->m_aProps.sPersistentName );
+}
+
+void ODocumentDefinition::separateOpenCommandArguments( const Sequence< PropertyValue >& i_rOpenCommandArguments,
+ ::comphelper::NamedValueCollection& o_rDocumentLoadArgs, ::comphelper::NamedValueCollection& o_rEmbeddedObjectDescriptor )
+{
+ ::comphelper::NamedValueCollection aOpenCommandArguments( i_rOpenCommandArguments );
+
+ static const std::u16string_view sObjectDescriptorArgs[] = { u"RecoveryStorage" };
+ for (const auto& rObjectDescriptorArg : sObjectDescriptorArgs)
+ {
+ const OUString sObjectDescriptorArg(rObjectDescriptorArg);
+ if ( aOpenCommandArguments.has( sObjectDescriptorArg ) )
+ {
+ o_rEmbeddedObjectDescriptor.put( sObjectDescriptorArg, aOpenCommandArguments.get( sObjectDescriptorArg ) );
+ aOpenCommandArguments.remove( sObjectDescriptorArg );
+ }
+ }
+
+ o_rDocumentLoadArgs.merge( aOpenCommandArguments, false );
+}
+
+Sequence< PropertyValue > ODocumentDefinition::fillLoadArgs( const Reference< XConnection>& _xConnection, const bool _bSuppressMacros, const bool _bReadOnly,
+ const Sequence< PropertyValue >& i_rOpenCommandArguments, Sequence< PropertyValue >& _out_rEmbeddedObjectDescriptor )
+{
+ // (re-)create interceptor, and put it into the descriptor of the embedded object
+ if ( m_pInterceptor.is() )
+ {
+ m_pInterceptor->dispose();
+ m_pInterceptor.clear();
+ }
+
+ m_pInterceptor = new OInterceptor( this );
+ Reference<XDispatchProviderInterceptor> xInterceptor = m_pInterceptor;
+
+ ::comphelper::NamedValueCollection aEmbeddedDescriptor;
+ aEmbeddedDescriptor.put( "OutplaceDispatchInterceptor", xInterceptor );
+
+ ::comphelper::NamedValueCollection aMediaDesc;
+ separateOpenCommandArguments( i_rOpenCommandArguments, aMediaDesc, aEmbeddedDescriptor );
+
+ // create the OutplaceFrameProperties, and put them into the descriptor of the embedded object
+ ::comphelper::NamedValueCollection OutplaceFrameProperties;
+ OutplaceFrameProperties.put( "TopWindow", true );
+ OutplaceFrameProperties.put( "SupportPersistentWindowState", true );
+
+ Reference< XFrame > xParentFrame;
+ if ( m_pImpl->m_pDataSource )
+ xParentFrame = lcl_getDatabaseDocumentFrame( *m_pImpl->m_pDataSource );
+ if ( !xParentFrame.is() )
+ { // i87957 we need a parent frame
+ Reference< XDesktop2 > xDesktop = Desktop::create( m_aContext );
+ xParentFrame.set( xDesktop, UNO_QUERY_THROW );
+ Reference<util::XCloseable> xCloseable(m_pImpl->m_pDataSource->getModel_noCreate(),UNO_QUERY);
+ if ( xCloseable.is() )
+ {
+ xCloseable->addCloseListener(this);
+ m_bRemoveListener = true;
+ }
+ }
+ OSL_ENSURE( xParentFrame.is(), "ODocumentDefinition::fillLoadArgs: no parent frame!" );
+ if ( xParentFrame.is() )
+ OutplaceFrameProperties.put( "ParentFrame", xParentFrame );
+
+ aEmbeddedDescriptor.put( "OutplaceFrameProperties", OutplaceFrameProperties.getNamedValues() );
+
+ // tell the embedded object to have (or not have) script support
+ aEmbeddedDescriptor.put( "EmbeddedScriptSupport", objectSupportsEmbeddedScripts() );
+
+ // tell the embedded object to not participate in the document recovery game - the DB doc will handle it
+ aEmbeddedDescriptor.put( "DocumentRecoverySupport", false );
+
+ // pass the descriptor of the embedded object to the caller
+ aEmbeddedDescriptor >>= _out_rEmbeddedObjectDescriptor;
+
+ // create the ComponentData, and put it into the document's media descriptor
+ {
+ ::comphelper::NamedValueCollection aComponentData;
+ aComponentData.put( "ActiveConnection", _xConnection );
+ aComponentData.put( "ApplyFormDesignMode", !_bReadOnly );
+ aMediaDesc.put( "ComponentData", aComponentData.getPropertyValues() );
+ }
+
+ if ( !m_pImpl->m_aProps.aTitle.isEmpty() )
+ aMediaDesc.put( "DocumentTitle", m_pImpl->m_aProps.aTitle );
+
+ aMediaDesc.put( "DocumentBaseURL", m_pImpl->m_pDataSource->getURL() );
+
+ // put the common load arguments into the document's media descriptor
+ lcl_putLoadArgs( aMediaDesc, optional_bool( _bSuppressMacros ), optional_bool( _bReadOnly ) );
+
+ return aMediaDesc.getPropertyValues();
+}
+
+void ODocumentDefinition::loadEmbeddedObject( const Reference< XConnection >& i_rConnection, const Sequence< sal_Int8 >& _aClassID,
+ const Sequence< PropertyValue >& i_rOpenCommandArguments, const bool _bSuppressMacros, const bool _bReadOnly )
+{
+ if ( !m_xEmbeddedObject.is() )
+ {
+ Reference< XStorage> xStorage = getContainerStorage();
+ if ( xStorage.is() )
+ {
+ Reference< XEmbeddedObjectCreator> xEmbedFactory = OOoEmbeddedObjectFactory::create(m_aContext);
+ OUString sDocumentService;
+ bool bSetSize = false;
+ sal_Int32 nEntryConnectionMode = EntryInitModes::DEFAULT_INIT;
+ Sequence< sal_Int8 > aClassID = _aClassID;
+ if ( aClassID.hasElements() )
+ {
+ nEntryConnectionMode = EntryInitModes::TRUNCATE_INIT;
+ bSetSize = true;
+ }
+ else
+ {
+ sDocumentService = GetDocumentServiceFromMediaType( getContentType(), m_aContext, aClassID );
+ // check if we are not a form and
+ // the org.libreoffice.report.pentaho.SOReportJobFactory is not present.
+ if ( !m_bForm && sDocumentService != "com.sun.star.text.TextDocument")
+ {
+ // we seem to be a "new style" report, check if report extension is present.
+ Reference< XContentEnumerationAccess > xEnumAccess( m_aContext->getServiceManager(), UNO_QUERY );
+ const OUString sReportEngineServiceName = ::dbtools::getDefaultReportEngineServiceName(m_aContext);
+ Reference< XEnumeration > xEnumDrivers = xEnumAccess->createContentEnumeration(sReportEngineServiceName);
+ if ( !xEnumDrivers.is() || !xEnumDrivers->hasMoreElements() )
+ {
+ css::io::WrongFormatException aWFE;
+ aWFE.Message = DBA_RES( RID_STR_MISSING_EXTENSION );
+ throw aWFE;
+ }
+ }
+ if ( !aClassID.hasElements() )
+ {
+ if ( m_bForm )
+ aClassID = MimeConfigurationHelper::GetSequenceClassID(SO3_SW_CLASSID);
+ else
+ {
+ aClassID = MimeConfigurationHelper::GetSequenceClassID(SO3_RPT_CLASSID_90);
+ }
+ }
+ }
+
+ OSL_ENSURE( aClassID.hasElements(),"No Class ID" );
+
+ Sequence< PropertyValue > aEmbeddedObjectDescriptor;
+ Sequence< PropertyValue > aLoadArgs( fillLoadArgs(
+ i_rConnection, _bSuppressMacros, _bReadOnly, i_rOpenCommandArguments, aEmbeddedObjectDescriptor ) );
+
+ m_xEmbeddedObject.set(xEmbedFactory->createInstanceUserInit(aClassID
+ ,sDocumentService
+ ,xStorage
+ ,m_pImpl->m_aProps.sPersistentName
+ ,nEntryConnectionMode
+ ,aLoadArgs
+ ,aEmbeddedObjectDescriptor
+ ),UNO_QUERY);
+ if ( m_xEmbeddedObject.is() )
+ {
+ if ( !m_pClientHelper.is() )
+ {
+ m_pClientHelper = new OEmbeddedClientHelper;
+ }
+ m_xEmbeddedObject->setClientSite(m_pClientHelper);
+ m_xEmbeddedObject->changeState(EmbedStates::RUNNING);
+ if ( bSetSize )
+ {
+ LockModifiable aLockModify( impl_getComponent_throw( false ) );
+
+ awt::Size aSize( DEFAULT_WIDTH, DEFAULT_HEIGHT );
+ m_xEmbeddedObject->setVisualAreaSize(Aspects::MSOLE_CONTENT,aSize);
+ }
+ }
+ }
+ }
+ else
+ {
+ sal_Int32 nCurrentState = m_xEmbeddedObject->getCurrentState();
+ if ( nCurrentState == EmbedStates::LOADED )
+ {
+ if ( !m_pClientHelper.is() )
+ {
+ m_pClientHelper = new OEmbeddedClientHelper;
+ }
+ m_xEmbeddedObject->setClientSite(m_pClientHelper);
+
+ Sequence< PropertyValue > aEmbeddedObjectDescriptor;
+ Sequence< PropertyValue > aLoadArgs( fillLoadArgs(
+ i_rConnection, _bSuppressMacros, _bReadOnly, i_rOpenCommandArguments, aEmbeddedObjectDescriptor ) );
+
+ Reference<XCommonEmbedPersist> xCommon(m_xEmbeddedObject,UNO_QUERY);
+ OSL_ENSURE(xCommon.is(),"unsupported interface!");
+ if ( xCommon.is() )
+ xCommon->reload( aLoadArgs, aEmbeddedObjectDescriptor );
+ m_xEmbeddedObject->changeState(EmbedStates::RUNNING);
+ }
+ else
+ {
+ OSL_ENSURE( ( nCurrentState == EmbedStates::RUNNING ) || ( nCurrentState == EmbedStates::ACTIVE ),
+ "ODocumentDefinition::loadEmbeddedObject: unexpected state!" );
+
+ // if the document was already loaded (which means the embedded object is in state RUNNING or ACTIVE),
+ // then just re-set some model parameters
+ try
+ {
+ // ensure the media descriptor doesn't contain any values which are intended for the
+ // EmbeddedObjectDescriptor only
+ ::comphelper::NamedValueCollection aEmbeddedObjectDescriptor;
+ ::comphelper::NamedValueCollection aNewMediaDesc;
+ separateOpenCommandArguments( i_rOpenCommandArguments, aNewMediaDesc, aEmbeddedObjectDescriptor );
+
+ // merge the new media descriptor into the existing media descriptor
+ const Reference< XModel > xModel( getComponent(), UNO_QUERY_THROW );
+ const Sequence< PropertyValue > aArgs = xModel->getArgs();
+ ::comphelper::NamedValueCollection aExistentMediaDesc( aArgs );
+ aExistentMediaDesc.merge( aNewMediaDesc, false );
+
+ lcl_putLoadArgs( aExistentMediaDesc, optional_bool(), optional_bool() );
+ // don't put _bSuppressMacros and _bReadOnly here - if the document was already
+ // loaded, we should not tamper with its settings.
+ // #i88977# #i86872#
+
+ xModel->attachResource( xModel->getURL(), aExistentMediaDesc.getPropertyValues() );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+ }
+
+ // set the OfficeDatabaseDocument instance as parent of the embedded document
+ // #i40358#
+ Reference< XChild > xDepdendDocAsChild( getComponent(), UNO_QUERY );
+ if ( xDepdendDocAsChild.is() )
+ {
+ try
+ {
+ if ( !xDepdendDocAsChild->getParent().is() )
+ { // first encounter
+ xDepdendDocAsChild->setParent( getDataSource( m_xParentContainer ) );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ if ( i_rConnection.is() )
+ m_xLastKnownConnection = i_rConnection;
+}
+
+void ODocumentDefinition::onCommandPreview(Any& _rImage)
+{
+ loadEmbeddedObjectForPreview();
+ if ( !m_xEmbeddedObject.is() )
+ return;
+
+ try
+ {
+ Reference<XTransferable> xTransfer(getComponent(),UNO_QUERY);
+ if ( xTransfer.is() )
+ {
+ DataFlavor aFlavor;
+ aFlavor.MimeType = "image/png";
+ aFlavor.HumanPresentableName = "Portable Network Graphics";
+ aFlavor.DataType = cppu::UnoType<Sequence < sal_Int8 >>::get();
+
+ _rImage = xTransfer->getTransferData( aFlavor );
+ }
+ }
+ catch( const Exception& )
+ {
+ }
+}
+
+void ODocumentDefinition::getPropertyDefaultByHandle( sal_Int32 /*_nHandle*/, Any& _rDefault ) const
+{
+ _rDefault.clear();
+}
+
+void ODocumentDefinition::onCommandGetDocumentProperties( Any& _rProps )
+{
+ loadEmbeddedObjectForPreview();
+ if ( !m_xEmbeddedObject.is() )
+ return;
+
+ try
+ {
+ Reference<XDocumentPropertiesSupplier> xDocSup(
+ getComponent(), UNO_QUERY );
+ if ( xDocSup.is() )
+ _rProps <<= xDocSup->getDocumentProperties();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+Reference< util::XCloseable > ODocumentDefinition::impl_getComponent_throw( const bool i_ForceCreate )
+{
+ OSL_ENSURE(m_xEmbeddedObject.is(),"Illegal call for embeddedObject");
+ Reference< util::XCloseable > xComp;
+ if ( m_xEmbeddedObject.is() )
+ {
+ int nState = m_xEmbeddedObject->getCurrentState();
+ if ( ( nState == EmbedStates::LOADED ) && i_ForceCreate )
+ {
+ m_xEmbeddedObject->changeState( EmbedStates::RUNNING );
+ nState = m_xEmbeddedObject->getCurrentState();
+ OSL_ENSURE( nState == EmbedStates::RUNNING, "ODocumentDefinition::impl_getComponent_throw: could not switch to RUNNING!" );
+ }
+
+ if ( nState == EmbedStates::ACTIVE || nState == EmbedStates::RUNNING )
+ {
+ if ( m_xEmbeddedObject.is() )
+ {
+ xComp = m_xEmbeddedObject->getComponent();
+ OSL_ENSURE(xComp.is(),"No valid component");
+ }
+ }
+ }
+ return xComp;
+}
+
+Reference< util::XCloseable > ODocumentDefinition::getComponent()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return impl_getComponent_throw();
+}
+
+namespace
+{
+ Reference< XDatabaseDocumentUI > lcl_getDatabaseDocumentUI( ODatabaseModelImpl const & _rModelImpl )
+ {
+ Reference< XDatabaseDocumentUI > xUI;
+
+ Reference< XModel > xModel( _rModelImpl.getModel_noCreate() );
+ if ( xModel.is() )
+ xUI.set( xModel->getCurrentController(), UNO_QUERY );
+ return xUI;
+ }
+}
+
+Reference< XComponent > ODocumentDefinition::impl_openUI_nolck_throw( bool _bForEditing )
+{
+ ::osl::ClearableMutexGuard aGuard( m_aMutex );
+ if ( !m_pImpl || !m_pImpl->m_pDataSource )
+ throw DisposedException();
+
+ Reference< XComponent > xComponent;
+ try
+ {
+ Reference< XDatabaseDocumentUI > xUI( lcl_getDatabaseDocumentUI( *m_pImpl->m_pDataSource ) );
+ if ( !xUI.is() )
+ {
+ // no XDatabaseDocumentUI -> just execute the respective command
+ m_bOpenInDesign = _bForEditing;
+ xComponent = Reference<XComponent>(onCommandOpenSomething(Any(), true, nullptr), UNO_QUERY);
+ OSL_ENSURE( xComponent.is(), "ODocumentDefinition::impl_openUI_nolck_throw: opening the thingie failed." );
+ return xComponent;
+ }
+
+
+ OUString sName( impl_getHierarchicalName( false ) );
+ sal_Int32 nObjectType = m_bForm ? DatabaseObject::FORM : DatabaseObject::REPORT;
+ aGuard.clear();
+
+ xComponent = xUI->loadComponent(
+ nObjectType, sName, _bForEditing
+ );
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const Exception& )
+ {
+ throw WrappedTargetException(
+ OUString(), *this, ::cppu::getCaughtException() );
+ }
+
+ return xComponent;
+}
+
+void ODocumentDefinition::impl_store_throw()
+{
+ Reference<XEmbedPersist> xPersist( m_xEmbeddedObject, UNO_QUERY );
+ if ( xPersist.is() )
+ {
+ xPersist->storeOwn();
+ notifyDataSourceModified();
+ }
+}
+
+bool ODocumentDefinition::impl_close_throw()
+{
+ bool bSuccess = prepareClose();
+ if ( bSuccess && m_xEmbeddedObject.is() )
+ {
+ m_xEmbeddedObject->changeState( EmbedStates::LOADED );
+ bSuccess = m_xEmbeddedObject->getCurrentState() == EmbedStates::LOADED;
+ }
+ return bSuccess;
+}
+
+Reference< XComponent > SAL_CALL ODocumentDefinition::open( )
+{
+ return impl_openUI_nolck_throw( false );
+}
+
+Reference< XComponent > SAL_CALL ODocumentDefinition::openDesign( )
+{
+ return impl_openUI_nolck_throw( true );
+}
+
+void SAL_CALL ODocumentDefinition::store( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ try
+ {
+ impl_store_throw();
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const Exception& )
+ {
+ throw WrappedTargetException(
+ OUString(), *this, ::cppu::getCaughtException() );
+ }
+}
+
+sal_Bool SAL_CALL ODocumentDefinition::close( )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ bool bSuccess = false;
+ try
+ {
+ bSuccess = impl_close_throw();
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const Exception& )
+ {
+ throw WrappedTargetException(
+ OUString(), *this, ::cppu::getCaughtException() );
+ }
+ return bSuccess;
+}
+
+OUString SAL_CALL ODocumentDefinition::getHierarchicalName()
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ return impl_getHierarchicalName( false );
+}
+
+OUString SAL_CALL ODocumentDefinition::composeHierarchicalName( const OUString& i_rRelativeName )
+{
+ return getHierarchicalName() + "/" + i_rRelativeName;
+}
+
+void SAL_CALL ODocumentDefinition::rename( const OUString& _rNewName )
+{
+ try
+ {
+ ::osl::ResettableMutexGuard aGuard(m_aMutex);
+ if ( _rNewName == m_pImpl->m_aProps.aTitle )
+ return;
+
+ // document definitions are organized in a hierarchical way, so reject names
+ // which contain a /, as this is reserved for hierarchy level separation
+ if ( _rNewName.indexOf( '/' ) != -1 )
+ m_aErrorHelper.raiseException( ErrorCondition::DB_OBJECT_NAME_WITH_SLASHES, *this );
+
+ NameChangeNotifier aNameChangeAndNotify( *this, _rNewName, aGuard );
+ m_pImpl->m_aProps.aTitle = _rNewName;
+
+ if ( m_xEmbeddedObject.is() && m_xEmbeddedObject->getCurrentState() == EmbedStates::ACTIVE )
+ updateDocumentTitle();
+ }
+ catch(const PropertyVetoException&)
+ {
+ throw ElementExistException(_rNewName,*this);
+ }
+}
+
+Reference< XStorage> ODocumentDefinition::getContainerStorage() const
+{
+ return m_pImpl->m_pDataSource
+ ? m_pImpl->m_pDataSource->getStorage( m_bForm ? ODatabaseModelImpl::E_FORM : ODatabaseModelImpl::E_REPORT )
+ : Reference< XStorage>();
+}
+
+bool ODocumentDefinition::isModified()
+{
+ osl::ClearableGuard< osl::Mutex > aGuard(m_aMutex);
+ bool bRet = false;
+ if ( m_xEmbeddedObject.is() )
+ {
+ Reference<XModifiable> xModel(getComponent(),UNO_QUERY);
+ bRet = xModel.is() && xModel->isModified();
+ }
+ return bRet;
+}
+
+bool ODocumentDefinition::prepareClose()
+{
+ if ( !m_xEmbeddedObject.is() )
+ return true;
+
+ try
+ {
+ // suspend the controller. Embedded objects are not allowed to raise
+ // own UI at their own discretion, instead, this has always to be triggered
+ // by the embedding component. Thus, we do the suspend call here.
+ // #i49370#
+
+ Reference< util::XCloseable > xComponent( impl_getComponent_throw( false ) );
+ if ( !xComponent.is() )
+ return true;
+
+ Reference< XModel > xModel( xComponent, UNO_QUERY );
+ Reference< XController > xController;
+ if ( xModel.is() )
+ xController = xModel->getCurrentController();
+
+ OSL_ENSURE( xController.is() || ( m_xEmbeddedObject->getCurrentState() < EmbedStates::ACTIVE ),
+ "ODocumentDefinition::prepareClose: no controller!" );
+ if ( !xController.is() )
+ // document has not yet been activated, i.e. has no UI, yet
+ return true;
+
+ if (!xController->suspend(true))
+ // controller vetoed the closing
+ return false;
+
+ if ( isModified() )
+ {
+ Reference< XFrame > xFrame( xController->getFrame() );
+ Reference<XTopWindow> xTopWindow;
+ if ( xFrame.is() )
+ {
+ xTopWindow = Reference<XTopWindow>(xFrame->getContainerWindow(), UNO_QUERY_THROW);
+ xTopWindow->toFront();
+ }
+ if (!save(true, xTopWindow))
+ {
+ // revert suspension
+ xController->suspend(false);
+ // saving failed or was cancelled
+ return false;
+ }
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ return true;
+}
+
+void ODocumentDefinition::fillReportData( const Reference< XComponentContext >& _rContext,
+ const Reference< util::XCloseable >& _rxComponent,
+ const Reference< XConnection >& _rxActiveConnection )
+{
+ uno::Sequence<uno::Any> aArgs(comphelper::InitAnyPropertySequence(
+ {
+ {"TextDocument", uno::Any(_rxComponent)},
+ {"ActiveConnection", uno::Any(_rxActiveConnection)}
+ }));
+ try
+ {
+ Reference< XJobExecutor > xExecutable(
+ _rContext->getServiceManager()->createInstanceWithArgumentsAndContext("com.sun.star.wizards.report.CallReportWizard", aArgs, _rContext), UNO_QUERY_THROW );
+ xExecutable->trigger( "fill" );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void ODocumentDefinition::updateDocumentTitle()
+{
+ OUString sName = m_pImpl->m_aProps.aTitle;
+ if ( m_pImpl->m_pDataSource )
+ {
+ if ( sName.isEmpty() )
+ {
+ if ( m_bForm )
+ sName = DBA_RES( RID_STR_FORM );
+ else
+ sName = DBA_RES( RID_STR_REPORT );
+ Reference< XUntitledNumbers > xUntitledProvider(m_pImpl->m_pDataSource->getModel_noCreate(), UNO_QUERY );
+ if ( xUntitledProvider.is() )
+ sName += OUString::number( xUntitledProvider->leaseNumber(getComponent()) );
+ }
+
+ Reference< XTitle > xDatabaseDocumentModel(m_pImpl->m_pDataSource->getModel_noCreate(),uno::UNO_QUERY);
+ if ( xDatabaseDocumentModel.is() )
+ sName = xDatabaseDocumentModel->getTitle() + " : " + sName;
+ }
+ Reference< XTitle> xTitle(getComponent(),UNO_QUERY);
+ if ( xTitle.is() )
+ xTitle->setTitle(sName);
+}
+
+void SAL_CALL ODocumentDefinition::queryClosing( const lang::EventObject&, sal_Bool )
+{
+ try
+ {
+ if ( !close() )
+ throw util::CloseVetoException();
+ }
+ catch(const lang::WrappedTargetException&)
+ {
+ throw util::CloseVetoException();
+ }
+}
+
+void SAL_CALL ODocumentDefinition::notifyClosing( const lang::EventObject& /*Source*/ )
+{
+}
+
+void SAL_CALL ODocumentDefinition::disposing( const lang::EventObject& /*Source*/ )
+{
+}
+
+void ODocumentDefinition::firePropertyChange( sal_Int32 i_nHandle, const Any& i_rNewValue, const Any& i_rOldValue,
+ bool i_bVetoable, const NotifierAccess& )
+{
+ fire( &i_nHandle, &i_rNewValue, &i_rOldValue, 1, i_bVetoable );
+}
+
+// NameChangeNotifier
+NameChangeNotifier::NameChangeNotifier( ODocumentDefinition& i_rDocumentDefinition, const OUString& i_rNewName,
+ ::osl::ResettableMutexGuard& i_rClearForNotify )
+ :m_rDocumentDefinition( i_rDocumentDefinition )
+ ,m_aOldValue( Any( i_rDocumentDefinition.getCurrentName() ) )
+ ,m_aNewValue( Any( i_rNewName ) )
+ ,m_rClearForNotify( i_rClearForNotify )
+{
+ impl_fireEvent_throw( true );
+}
+
+NameChangeNotifier::~NameChangeNotifier()
+{
+ impl_fireEvent_throw( false );
+}
+
+void NameChangeNotifier::impl_fireEvent_throw( const bool i_bVetoable )
+{
+ m_rClearForNotify.clear();
+ m_rDocumentDefinition.firePropertyChange(
+ PROPERTY_ID_NAME, m_aNewValue, m_aOldValue, i_bVetoable, ODocumentDefinition::NotifierAccess() );
+ m_rClearForNotify.reset();
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documentdefinition.hxx b/dbaccess/source/core/dataaccess/documentdefinition.hxx
new file mode 100644
index 000000000..5569276d4
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documentdefinition.hxx
@@ -0,0 +1,356 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <cppuhelper/propshlp.hxx>
+#include <cppuhelper/implbase4.hxx>
+#include <ContentHelper.hxx>
+#include <comphelper/propertystatecontainer.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <apitools.hxx>
+#include <comphelper/uno3.hxx>
+#include <com/sun/star/awt/XTopWindow.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/embed/XStateChangeListener.hpp>
+#include <com/sun/star/embed/XEmbeddedObject.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/sdb/XSubDocument.hpp>
+#include <com/sun/star/util/XCloseListener.hpp>
+#include <com/sun/star/container/XHierarchicalName.hpp>
+#include <rtl/ref.hxx>
+
+namespace comphelper
+{
+ class NamedValueCollection;
+}
+
+namespace dbaccess
+{
+
+ class OInterceptor;
+ class OEmbeddedClientHelper;
+// ODocumentDefinition - a database "document" which is simply a link to a real
+// document
+
+typedef ::cppu::ImplHelper4 < css::embed::XComponentSupplier
+ , css::sdb::XSubDocument
+ , css::util::XCloseListener
+ , css::container::XHierarchicalName
+ > ODocumentDefinition_Base;
+
+class ODocumentDefinition
+ :public OContentHelper
+ ,public ::comphelper::OPropertyStateContainer
+ ,public ::comphelper::OPropertyArrayUsageHelper< ODocumentDefinition >
+ ,public ODocumentDefinition_Base
+{
+ css::uno::Reference< css::embed::XEmbeddedObject> m_xEmbeddedObject;
+ css::uno::Reference< css::embed::XStateChangeListener > m_xListener;
+ css::uno::Reference< css::sdbc::XConnection > m_xLastKnownConnection;
+
+ rtl::Reference<OInterceptor> m_pInterceptor;
+ bool m_bForm; // <TRUE/> if it is a form
+ bool m_bOpenInDesign;
+ bool m_bInExecute;
+ bool m_bRemoveListener;
+ rtl::Reference<OEmbeddedClientHelper> m_pClientHelper;
+
+protected:
+ virtual ~ODocumentDefinition() override;
+
+public:
+
+ ODocumentDefinition(
+ const css::uno::Reference< css::uno::XInterface >& _rxContainer,
+ const css::uno::Reference< css::uno::XComponentContext >&,
+ const TContentPtr& _pImpl,
+ bool _bForm
+ );
+
+ void initialLoad(
+ const css::uno::Sequence< sal_Int8 >& i_rClassID,
+ const css::uno::Sequence< css::beans::PropertyValue >& i_rCreationArgs,
+ const css::uno::Reference< css::sdbc::XConnection >& i_rConnection
+ );
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+// css::uno::XInterface
+ DECLARE_XINTERFACE( )
+
+// css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // OPropertySetHelper
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& o_rValue,
+ sal_Int32 i_nHandle
+ ) const override;
+
+ // XComponentSupplier
+ virtual css::uno::Reference< css::util::XCloseable > SAL_CALL getComponent( ) override;
+
+ // XSubDocument
+ virtual css::uno::Reference< css::lang::XComponent > SAL_CALL open( ) override;
+ virtual css::uno::Reference< css::lang::XComponent > SAL_CALL openDesign( ) override;
+ virtual void SAL_CALL store( ) override;
+ virtual sal_Bool SAL_CALL close( ) override;
+
+ // XHierarchicalName
+ virtual OUString SAL_CALL getHierarchicalName( ) override;
+ virtual OUString SAL_CALL composeHierarchicalName( const OUString& aRelativeName ) override;
+
+// OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ // XCommandProcessor
+ virtual css::uno::Any SAL_CALL execute( const css::ucb::Command& aCommand, sal_Int32 CommandId, const css::uno::Reference< css::ucb::XCommandEnvironment >& Environment ) override ;
+
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+ // XCloseListener
+ virtual void SAL_CALL queryClosing( const css::lang::EventObject& Source, sal_Bool GetsOwnership ) override;
+ virtual void SAL_CALL notifyClosing( const css::lang::EventObject& Source ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ /** returns the forms/reports container storage, depending on m_bForm. Our own storage
+ inside this container storage is the one with the name as indicated by m_pImpl->m_aProps.sPersistentName.
+ */
+ css::uno::Reference< css::embed::XStorage >
+ getContainerStorage() const;
+
+ bool save(bool _bApprove, const css::uno::Reference<css::awt::XTopWindow>& rDialogParent);
+ void saveAs();
+ void closeObject();
+ bool isModified();
+ bool isNewReport() const { return !m_bForm && !m_pImpl->m_aProps.bAsTemplate; }
+
+ static void fillReportData(
+ const css::uno::Reference< css::uno::XComponentContext > & _rxContext,
+ const css::uno::Reference< css::util::XCloseable >& _rxComponent,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxActiveConnection
+ );
+
+ const css::uno::Reference< css::sdbc::XConnection >&
+ getConnection() const { return m_xLastKnownConnection; }
+
+ /** prepares closing the document component
+
+ The method suspends the controller associated with the document, and saves the document
+ if necessary.
+
+ @return
+ <TRUE/> if and only if the document component can be closed
+ */
+ bool prepareClose();
+
+ static OUString GetDocumentServiceFromMediaType(
+ const OUString& _rMediaType,
+ const css::uno::Reference< css::uno::XComponentContext > & _rxContext,
+ css::uno::Sequence< sal_Int8 >& _rClassId
+ );
+ static OUString GetDocumentServiceFromMediaType(
+ const css::uno::Reference< css::embed::XStorage >& _rxContainerStorage,
+ const OUString& _rEntityName,
+ const css::uno::Reference< css::uno::XComponentContext > & _rxContext,
+ css::uno::Sequence< sal_Int8 >& _rClassId
+ );
+
+ struct NotifierAccess { friend class NameChangeNotifier; private: NotifierAccess() { } };
+ const OUString& getCurrentName() const { return m_pImpl->m_aProps.aTitle; }
+ void firePropertyChange(
+ sal_Int32 i_nHandle,
+ const css::uno::Any& i_rNewValue,
+ const css::uno::Any& i_rOldValue,
+ bool i_bVetoable,
+ const NotifierAccess&
+ );
+
+private:
+ /** does necessary initializations after our embedded object has been switched to ACTIVE
+ */
+ void impl_onActivateEmbeddedObject_nothrow( const bool i_bReactivated );
+
+ /** initializes a newly created view/controller of a form which is displaying our embedded object
+
+ Has only to be called if the respective embedded object has been loaded for design (and
+ not for data entry)
+
+ @param _rxController
+ the controller which belongs to the XModel of our (active) embedded object
+ */
+ static void impl_initFormEditView( const css::uno::Reference< css::frame::XController >& _rxController );
+
+ /** removes the given frame from the desktop's frame collection
+ @throws css::uno::RuntimeException
+ */
+ static void impl_removeFrameFromDesktop_throw(
+ const css::uno::Reference< css::uno::XComponentContext >& _rContext,
+ const css::uno::Reference< css::frame::XFrame >& _rxFrame
+ );
+
+ /** opens the UI for this sub document
+ */
+ css::uno::Reference< css::lang::XComponent >
+ impl_openUI_nolck_throw( bool _bForEditing );
+
+ /** stores our document, if it's already loaded
+ */
+ void impl_store_throw();
+
+ /** closes our document, if it's open
+ */
+ bool impl_close_throw();
+
+ /** returns our component, creates it if necessary
+ */
+ css::uno::Reference< css::util::XCloseable >
+ impl_getComponent_throw( const bool i_ForceCreate = true );
+
+ /** shows or hides our component
+
+ The embedded object must exist, and be in state LOADED, at least.
+ */
+ void impl_showOrHideComponent_throw( const bool i_bShow );
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+ virtual void getPropertyDefaultByHandle( sal_Int32 _nHandle, css::uno::Any& _rDefault ) const override;
+
+ // helper
+ virtual void SAL_CALL disposing() override;
+
+ // OContentHelper overridables
+ virtual OUString determineContentType() const override;
+
+ /** fills the load arguments
+ */
+ css::uno::Sequence< css::beans::PropertyValue >
+ fillLoadArgs(
+ const css::uno::Reference< css::sdbc::XConnection>& _xConnection,
+ const bool _bSuppressMacros,
+ const bool _bReadOnly,
+ const css::uno::Sequence< css::beans::PropertyValue >& i_rOpenCommandArguments,
+ css::uno::Sequence< css::beans::PropertyValue >& _out_rEmbeddedObjectDescriptor
+ );
+
+ /** splits the given arguments to an "open*" command into arguments for loading the document, and arguments to be
+ put into the EmbeddedObjectDescriptor
+
+ Any values already present in <code>o_rDocumentLoadArgs</code> and <code>o_rEmbeddedObjectDescriptor</code>
+ will be overwritten by values from <code>i_rOpenCommandArguments</code>, if applicable, otherwise they will
+ be preserved.
+
+ @param i_rOpenCommandArguments
+ the arguments passed to the "open*" command at the content
+ @param o_rDocumentLoadArgs
+ the arguments to be passed when actually loading the embedded document.
+ @param o_rEmbeddedObjectDescriptor
+ the EmbeddedObjectDescriptor to be passed when initializing the embedded object
+ */
+ static void separateOpenCommandArguments(
+ const css::uno::Sequence< css::beans::PropertyValue >& i_rOpenCommandArguments,
+ ::comphelper::NamedValueCollection& o_rDocumentLoadArgs,
+ ::comphelper::NamedValueCollection& o_rEmbeddedObjectDescriptor
+ );
+
+ /** loads the EmbeddedObject if not already loaded
+ @param _aClassID
+ If set, it will be used to create the embedded object.
+ */
+ void loadEmbeddedObject(
+ const css::uno::Reference< css::sdbc::XConnection>& _xConnection,
+ const css::uno::Sequence< sal_Int8 >& _aClassID,
+ const css::uno::Sequence< css::beans::PropertyValue >& _rAdditionalArgs,
+ const bool _bSuppressMacros,
+ const bool _bReadOnly
+ );
+
+ /** loads the embedded object for preview. Macros will be suppressed, and the document will
+ be read-only.
+ */
+ void loadEmbeddedObjectForPreview()
+ {
+ loadEmbeddedObject(
+ nullptr,
+ css::uno::Sequence< sal_Int8 >(),
+ css::uno::Sequence< css::beans::PropertyValue >(),
+ true,
+ true
+ );
+ }
+
+ /** searches for read-only flag in the args of the model and sets it to the given value,
+ if the value was not found, it will be appended.
+ @param _bReadOnly
+ If <TRUE/> the document will be switched to readonly mode
+ */
+ void updateDocumentTitle();
+
+ void registerProperties();
+
+ /** determines whether the document we represent supports embedded scripts and macros
+ */
+ bool objectSupportsEmbeddedScripts() const;
+
+ //- commands
+
+ void onCommandGetDocumentProperties( css::uno::Any& _rProps );
+ /// @throws css::uno::Exception
+ void onCommandInsert( const OUString& _sURL, const css::uno::Reference< css::ucb::XCommandEnvironment >& Environment );
+ void onCommandPreview( css::uno::Any& _rImage );
+ css::uno::Any
+ onCommandOpenSomething(
+ const css::uno::Any& _rArgument,
+ const bool _bActivate,
+ const css::uno::Reference< css::ucb::XCommandEnvironment >& _rxEnvironment
+ );
+private:
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+};
+
+class NameChangeNotifier
+{
+public:
+ NameChangeNotifier(
+ ODocumentDefinition& i_rDocumentDefinition,
+ const OUString& i_rNewName,
+ ::osl::ResettableMutexGuard& i_rClearForNotify
+ );
+ ~NameChangeNotifier();
+
+private:
+ ODocumentDefinition& m_rDocumentDefinition;
+ const css::uno::Any m_aOldValue;
+ const css::uno::Any m_aNewValue;
+ ::osl::ResettableMutexGuard& m_rClearForNotify;
+
+ void impl_fireEvent_throw( const bool i_bVetoable );
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documenteventexecutor.cxx b/dbaccess/source/core/dataaccess/documenteventexecutor.cxx
new file mode 100644
index 000000000..3d16ee6eb
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documenteventexecutor.cxx
@@ -0,0 +1,199 @@
+/* -*- 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 "documenteventexecutor.hxx"
+
+#include <com/sun/star/document/XDocumentEventBroadcaster.hpp>
+#include <com/sun/star/util/URLTransformer.hpp>
+#include <com/sun/star/util/XURLTransformer.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/frame/XDispatchProvider.hpp>
+
+#include <comphelper/namedvaluecollection.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::RuntimeException;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::WeakReference;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::document::XDocumentEventBroadcaster;
+ using ::com::sun::star::document::XEventsSupplier;
+ using ::com::sun::star::container::XNameAccess;
+ using ::com::sun::star::frame::XModel;
+ using ::com::sun::star::util::URLTransformer;
+ using ::com::sun::star::util::XURLTransformer;
+ using ::com::sun::star::frame::XDispatchProvider;
+ using ::com::sun::star::frame::XDispatch;
+ using ::com::sun::star::util::URL;
+ using ::com::sun::star::beans::PropertyValue;
+ using ::com::sun::star::frame::XController;
+ using ::com::sun::star::document::DocumentEvent;
+
+ using namespace ::com::sun::star;
+
+ // DocumentEventExecutor_Data
+ struct DocumentEventExecutor_Data
+ {
+ WeakReference< XEventsSupplier > xDocument;
+ Reference< XURLTransformer > xURLTransformer;
+
+ explicit DocumentEventExecutor_Data( const Reference< XEventsSupplier >& _rxDocument )
+ :xDocument( _rxDocument )
+ {
+ }
+ };
+
+ namespace
+ {
+ void lcl_dispatchScriptURL_throw( DocumentEventExecutor_Data const & _rDocExecData,
+ const OUString& _rScriptURL, const DocumentEvent& _rTrigger )
+ {
+ Reference< XModel > xDocument( _rDocExecData.xDocument.get(), UNO_QUERY_THROW );
+
+ Reference< XController > xController( xDocument->getCurrentController() );
+ Reference< XDispatchProvider > xDispProv;
+ if ( xController.is() )
+ xDispProv.set( xController->getFrame(), UNO_QUERY );
+ if ( !xDispProv.is() )
+ {
+ OSL_FAIL( "lcl_dispatchScriptURL_throw: no controller/frame? How should I dispatch?" );
+ return;
+ }
+
+ URL aScriptURL;
+ aScriptURL.Complete = _rScriptURL;
+ if ( _rDocExecData.xURLTransformer.is() )
+ _rDocExecData.xURLTransformer->parseStrict( aScriptURL );
+
+ // unfortunately, executing a script can trigger all kind of complex stuff, and unfortunately, not
+ // every component involved into this properly cares for thread safety. To be on the safe side,
+ // we lock the solar mutex here.
+ SolarMutexGuard aSolarGuard;
+
+ Reference< XDispatch > xDispatch( xDispProv->queryDispatch( aScriptURL, OUString(), 0 ) );
+ if ( !xDispatch.is() )
+ {
+ OSL_FAIL( "lcl_dispatchScriptURL_throw: no dispatcher for the script URL!" );
+ return;
+ }
+
+ PropertyValue aEventParam;
+ aEventParam.Value <<= _rTrigger;
+ Sequence< PropertyValue > aDispatchArgs( &aEventParam, 1 );
+ xDispatch->dispatch( aScriptURL, aDispatchArgs );
+ }
+ }
+
+ // DocumentEventExecutor
+ DocumentEventExecutor::DocumentEventExecutor( const Reference<XComponentContext> & _rContext,
+ const Reference< XEventsSupplier >& _rxDocument )
+ :m_pData( new DocumentEventExecutor_Data( _rxDocument ) )
+ {
+ Reference< XDocumentEventBroadcaster > xBroadcaster( _rxDocument, UNO_QUERY_THROW );
+
+ osl_atomic_increment( &m_refCount );
+ {
+ xBroadcaster->addDocumentEventListener( this );
+ }
+ osl_atomic_decrement( &m_refCount );
+
+ try
+ {
+ m_pData->xURLTransformer = URLTransformer::create(_rContext);
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ DocumentEventExecutor::~DocumentEventExecutor()
+ {
+ }
+
+ void SAL_CALL DocumentEventExecutor::documentEventOccured( const DocumentEvent& Event )
+ {
+ Reference< XEventsSupplier > xEventsSupplier( m_pData->xDocument.get(), UNO_QUERY );
+ if ( !xEventsSupplier.is() )
+ {
+ OSL_FAIL( "DocumentEventExecutor::documentEventOccurred: no document anymore, but still being notified?" );
+ return;
+ }
+
+ Reference< XModel > xDocument( xEventsSupplier, UNO_QUERY_THROW );
+
+ try
+ {
+ Reference< XNameAccess > xDocEvents( xEventsSupplier->getEvents(), UNO_SET_THROW );
+ if ( !xDocEvents->hasByName( Event.EventName ) )
+ {
+ // this is worth an assertion: We are listener at the very same document which we just asked
+ // for its events. So when EventName is fired, why isn't it supported by xDocEvents?
+ OSL_FAIL( "DocumentEventExecutor::documentEventOccurred: an unsupported event is notified!" );
+ return;
+ }
+
+ const ::comphelper::NamedValueCollection aScriptDescriptor( xDocEvents->getByName( Event.EventName ) );
+
+ OUString sEventType;
+ bool bScriptAssigned = aScriptDescriptor.get_ensureType( "EventType", sEventType );
+
+ OUString sScript;
+ bScriptAssigned = bScriptAssigned && aScriptDescriptor.get_ensureType( "Script", sScript );
+
+ if ( !bScriptAssigned )
+ // no script is assigned to this event
+ return;
+
+ bool bDispatchScriptURL = ( sEventType == "Script" || sEventType == "Service" );
+ bool bNonEmptyScript = !sScript.isEmpty();
+
+ OSL_ENSURE( bDispatchScriptURL && bNonEmptyScript,
+ "DocumentEventExecutor::documentEventOccurred: invalid/unsupported script descriptor" );
+
+ if ( bDispatchScriptURL && bNonEmptyScript )
+ {
+ lcl_dispatchScriptURL_throw( *m_pData, sScript, Event );
+ }
+ }
+ catch( const RuntimeException& ) { throw; }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ void SAL_CALL DocumentEventExecutor::disposing( const lang::EventObject& /*_Source*/ )
+ {
+ // not interested in
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documenteventexecutor.hxx b/dbaccess/source/core/dataaccess/documenteventexecutor.hxx
new file mode 100644
index 000000000..90dc9083c
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documenteventexecutor.hxx
@@ -0,0 +1,59 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/document/XDocumentEventListener.hpp>
+#include <com/sun/star/document/XEventsSupplier.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <memory>
+
+namespace com::sun::star::uno { class XComponentContext; }
+
+namespace dbaccess
+{
+
+ struct DocumentEventExecutor_Data;
+ // DocumentEventExecutor
+ typedef ::cppu::WeakImplHelper < css::document::XDocumentEventListener
+ > DocumentEventExecutor_Base;
+ class DocumentEventExecutor : public DocumentEventExecutor_Base
+ {
+ public:
+ DocumentEventExecutor(
+ const css::uno::Reference< css::uno::XComponentContext >& _rContext,
+ const css::uno::Reference< css::document::XEventsSupplier >& _rxDocument );
+
+ protected:
+ virtual ~DocumentEventExecutor() override;
+
+ // css.document.XDocumentEventListener
+ virtual void SAL_CALL documentEventOccured( const css::document::DocumentEvent& Event ) override;
+ // css.lang.XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ private:
+ std::unique_ptr< DocumentEventExecutor_Data > m_pData;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documenteventnotifier.cxx b/dbaccess/source/core/dataaccess/documenteventnotifier.cxx
new file mode 100644
index 000000000..6a7088f95
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documenteventnotifier.cxx
@@ -0,0 +1,290 @@
+/* -*- 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 "documenteventnotifier.hxx"
+
+#include <com/sun/star/frame/DoubleInitializationException.hpp>
+
+#include <comphelper/asyncnotification.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <cppuhelper/weak.hxx>
+#include <tools/diagnose_ex.h>
+#include <vcl/svapp.hxx>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::frame::DoubleInitializationException;
+ using ::com::sun::star::document::XDocumentEventListener;
+ using ::com::sun::star::document::DocumentEvent;
+ using ::com::sun::star::frame::XController2;
+
+ using namespace ::com::sun::star;
+
+ // DocumentEventHolder
+ typedef ::comphelper::EventHolder< DocumentEvent > DocumentEventHolder;
+
+ // DocumentEventNotifier_Impl
+ class DocumentEventNotifier_Impl : public ::comphelper::IEventProcessor
+ {
+ oslInterlockedCount m_refCount;
+ ::cppu::OWeakObject& m_rDocument;
+ ::osl::Mutex& m_rMutex;
+ bool m_bInitialized;
+ bool m_bDisposed;
+ std::shared_ptr<::comphelper::AsyncEventNotifierAutoJoin> m_pEventBroadcaster;
+ ::comphelper::OInterfaceContainerHelper3<css::document::XEventListener> m_aLegacyEventListeners;
+ ::comphelper::OInterfaceContainerHelper3<XDocumentEventListener> m_aDocumentEventListeners;
+
+ public:
+ DocumentEventNotifier_Impl( ::cppu::OWeakObject& _rBroadcasterDocument, ::osl::Mutex& _rMutex )
+ :m_refCount( 0 )
+ ,m_rDocument( _rBroadcasterDocument )
+ ,m_rMutex( _rMutex )
+ ,m_bInitialized( false )
+ ,m_bDisposed( false )
+ ,m_aLegacyEventListeners( _rMutex )
+ ,m_aDocumentEventListeners( _rMutex )
+ {
+ }
+
+ // IEventProcessor
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ void addLegacyEventListener( const Reference< document::XEventListener >& Listener )
+ {
+ m_aLegacyEventListeners.addInterface( Listener );
+ }
+
+ void removeLegacyEventListener( const Reference< document::XEventListener >& Listener )
+ {
+ m_aLegacyEventListeners.removeInterface( Listener );
+ }
+
+ void addDocumentEventListener( const Reference< XDocumentEventListener >& Listener )
+ {
+ m_aDocumentEventListeners.addInterface( Listener );
+ }
+
+ void removeDocumentEventListener( const Reference< XDocumentEventListener >& Listener )
+ {
+ m_aDocumentEventListeners.removeInterface( Listener );
+ }
+
+ void disposing();
+
+ void onDocumentInitialized();
+
+ void notifyDocumentEvent( const OUString& EventName, const Reference< XController2 >& ViewController,
+ const Any& Supplement )
+ {
+ impl_notifyEvent_nothrow( DocumentEvent(
+ m_rDocument, EventName, ViewController, Supplement ) );
+ }
+
+ void notifyDocumentEventAsync( const OUString& EventName, const Reference< XController2 >& ViewController,
+ const Any& Supplement )
+ {
+ impl_notifyEventAsync_nothrow( DocumentEvent(
+ m_rDocument, EventName, ViewController, Supplement ) );
+ }
+
+ protected:
+ virtual ~DocumentEventNotifier_Impl()
+ {
+ }
+
+ // IEventProcessor
+ virtual void processEvent( const ::comphelper::AnyEvent& _rEvent ) override;
+
+ private:
+ void impl_notifyEvent_nothrow( const DocumentEvent& _rEvent );
+ void impl_notifyEventAsync_nothrow( const DocumentEvent& _rEvent );
+ };
+
+ void SAL_CALL DocumentEventNotifier_Impl::acquire() noexcept
+ {
+ osl_atomic_increment( &m_refCount );
+ }
+
+ void SAL_CALL DocumentEventNotifier_Impl::release() noexcept
+ {
+ if ( 0 == osl_atomic_decrement( &m_refCount ) )
+ delete this;
+ }
+
+ void DocumentEventNotifier_Impl::disposing()
+ {
+ // SYNCHRONIZED ->
+ // cancel any pending asynchronous events
+ ::osl::ResettableMutexGuard aGuard( m_rMutex );
+ if (m_pEventBroadcaster)
+ {
+ m_pEventBroadcaster->removeEventsForProcessor( this );
+ m_pEventBroadcaster->terminate();
+ }
+
+ auto xEventBroadcaster = std::exchange(m_pEventBroadcaster, {});
+
+ lang::EventObject aEvent( m_rDocument );
+ aGuard.clear();
+ // <-- SYNCHRONIZED
+
+ if (xEventBroadcaster)
+ {
+ comphelper::SolarMutex& rSolarMutex = Application::GetSolarMutex();
+ // unblock threads blocked on that so we can join
+ sal_uInt32 nLockCount = (rSolarMutex.IsCurrentThread()) ? rSolarMutex.release(true) : 0;
+ xEventBroadcaster->join();
+ if (nLockCount)
+ rSolarMutex.acquire(nLockCount);
+ xEventBroadcaster.reset();
+ }
+ m_aLegacyEventListeners.disposeAndClear( aEvent );
+ m_aDocumentEventListeners.disposeAndClear( aEvent );
+
+ // SYNCHRONIZED ->
+ aGuard.reset();
+ m_bDisposed = true;
+ // <-- SYNCHRONIZED
+ }
+
+ void DocumentEventNotifier_Impl::onDocumentInitialized()
+ {
+ if ( m_bInitialized )
+ throw DoubleInitializationException();
+
+ m_bInitialized = true;
+ if (m_pEventBroadcaster)
+ {
+ // there are already pending asynchronous events
+ ::comphelper::AsyncEventNotifierAutoJoin::launch(m_pEventBroadcaster);
+ }
+ }
+
+ void DocumentEventNotifier_Impl::impl_notifyEvent_nothrow( const DocumentEvent& _rEvent )
+ {
+ OSL_PRECOND( m_bInitialized,
+ "DocumentEventNotifier_Impl::impl_notifyEvent_nothrow: only to be called when the document is already initialized!" );
+ try
+ {
+ document::EventObject aLegacyEvent( _rEvent.Source, _rEvent.EventName );
+ m_aLegacyEventListeners.notifyEach( &document::XEventListener::notifyEvent, aLegacyEvent );
+ }
+ catch(const Exception&)
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ try
+ {
+ m_aDocumentEventListeners.notifyEach( &XDocumentEventListener::documentEventOccured, _rEvent );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ void DocumentEventNotifier_Impl::impl_notifyEventAsync_nothrow( const DocumentEvent& _rEvent )
+ {
+ if (!m_pEventBroadcaster)
+ {
+ m_pEventBroadcaster = ::comphelper::AsyncEventNotifierAutoJoin
+ ::newAsyncEventNotifierAutoJoin("DocumentEventNotifier");
+ if ( m_bInitialized )
+ {
+ // start processing the events if and only if we (our document, respectively) are
+ // already initialized
+ ::comphelper::AsyncEventNotifierAutoJoin::launch(m_pEventBroadcaster);
+ }
+ }
+ m_pEventBroadcaster->addEvent( new DocumentEventHolder( _rEvent ), this );
+ }
+
+ void DocumentEventNotifier_Impl::processEvent( const ::comphelper::AnyEvent& _rEvent )
+ {
+ // beware, this is called from the notification thread
+ {
+ ::osl::MutexGuard aGuard( m_rMutex );
+ if ( m_bDisposed )
+ return;
+ }
+ const DocumentEventHolder& rEventHolder = dynamic_cast< const DocumentEventHolder& >( _rEvent );
+ impl_notifyEvent_nothrow( rEventHolder.getEventObject() );
+ }
+
+ // DocumentEventNotifier
+ DocumentEventNotifier::DocumentEventNotifier( ::cppu::OWeakObject& _rBroadcasterDocument, ::osl::Mutex& _rMutex )
+ :m_pImpl( new DocumentEventNotifier_Impl( _rBroadcasterDocument, _rMutex ) )
+ {
+ }
+
+ DocumentEventNotifier::~DocumentEventNotifier()
+ {
+ }
+
+ void DocumentEventNotifier::disposing()
+ {
+ m_pImpl->disposing();
+ }
+
+ void DocumentEventNotifier::onDocumentInitialized()
+ {
+ m_pImpl->onDocumentInitialized();
+ }
+
+ void DocumentEventNotifier::addLegacyEventListener( const Reference< document::XEventListener >& Listener )
+ {
+ m_pImpl->addLegacyEventListener( Listener );
+ }
+
+ void DocumentEventNotifier::removeLegacyEventListener( const Reference< document::XEventListener >& Listener )
+ {
+ m_pImpl->removeLegacyEventListener( Listener );
+ }
+
+ void DocumentEventNotifier::addDocumentEventListener( const Reference< XDocumentEventListener >& Listener )
+ {
+ m_pImpl->addDocumentEventListener( Listener );
+ }
+
+ void DocumentEventNotifier::removeDocumentEventListener( const Reference< XDocumentEventListener >& Listener )
+ {
+ m_pImpl->removeDocumentEventListener( Listener );
+ }
+
+ void DocumentEventNotifier::notifyDocumentEvent( const OUString& EventName,
+ const Reference< XController2 >& ViewController, const Any& Supplement )
+ {
+ m_pImpl->notifyDocumentEvent( EventName, ViewController, Supplement );
+ }
+
+ void DocumentEventNotifier::notifyDocumentEventAsync( const OUString& EventName,
+ const Reference< XController2 >& ViewController, const Any& Supplement )
+ {
+ m_pImpl->notifyDocumentEventAsync( EventName, ViewController, Supplement );
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documenteventnotifier.hxx b/dbaccess/source/core/dataaccess/documenteventnotifier.hxx
new file mode 100644
index 000000000..6f3bffc4c
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documenteventnotifier.hxx
@@ -0,0 +1,128 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/document/XEventListener.hpp>
+#include <com/sun/star/document/XDocumentEventListener.hpp>
+
+#include <rtl/ref.hxx>
+
+namespace cppu
+{
+ class OWeakObject;
+}
+
+namespace dbaccess
+{
+
+ class DocumentEventNotifier_Impl;
+ // DocumentEventNotifier
+ class DocumentEventNotifier
+ {
+ public:
+ DocumentEventNotifier( ::cppu::OWeakObject& _rBroadcasterDocument, ::osl::Mutex& _rMutex );
+ ~DocumentEventNotifier();
+
+ void addLegacyEventListener( const css::uno::Reference< css::document::XEventListener >& Listener );
+ void removeLegacyEventListener( const css::uno::Reference< css::document::XEventListener >& Listener );
+ void addDocumentEventListener( const css::uno::Reference< css::document::XDocumentEventListener >& Listener );
+ void removeDocumentEventListener( const css::uno::Reference< css::document::XDocumentEventListener >& Listener );
+
+ /** disposes the instance
+ @precond
+ the mutex is not locked
+ */
+ void disposing();
+
+ /** tells the instance that its document is completely initialized now.
+
+ Before you call this method, no notification will actually happen
+
+ @precond
+ the mutex is locked
+ */
+ void onDocumentInitialized();
+
+ /** notifies a document event described by the given parameters
+
+ @precond
+ the mutex is not locked
+ @precond
+ ->onDocumentInitialized has been called
+ */
+ void notifyDocumentEvent(
+ const OUString& EventName,
+ const css::uno::Reference< css::frame::XController2 >& _rxViewController,
+ const css::uno::Any& Supplement
+ );
+
+ /** notifies a document event, described by the given parameters, asynchronously
+
+ Note that no event is actually notified before you called ->onDocumentInitialized.
+
+ @precond
+ the mutex is locked
+ */
+ void notifyDocumentEventAsync(
+ const OUString& EventName,
+ const css::uno::Reference< css::frame::XController2 >& ViewController,
+ const css::uno::Any& Supplement
+ );
+
+ /** notifies a document event to all registered listeners
+
+ @precond
+ the mutex is not locked
+ @precond
+ ->onDocumentInitialized has been called
+ */
+ void notifyDocumentEvent(
+ const char* _pAsciiEventName,
+ const css::uno::Reference< css::frame::XController2 >& _rxViewController = nullptr,
+ const css::uno::Any& _rSupplement = css::uno::Any()
+ )
+ {
+ notifyDocumentEvent( OUString::createFromAscii( _pAsciiEventName ), _rxViewController, _rSupplement );
+ }
+
+ /** notifies a document event to all registered listeners, asynchronously
+
+ Note that no event is actually notified before you called ->onDocumentInitialized.
+
+ @precond
+ the mutex is locked
+ */
+ void notifyDocumentEventAsync(
+ const char* _pAsciiEventName,
+ const css::uno::Reference< css::frame::XController2 >& _rxViewController = nullptr,
+ const css::uno::Any& _rSupplement = css::uno::Any()
+ )
+ {
+ notifyDocumentEventAsync( OUString::createFromAscii( _pAsciiEventName ), _rxViewController, _rSupplement );
+ }
+
+ private:
+ ::rtl::Reference< DocumentEventNotifier_Impl > m_pImpl;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/documentevents.cxx b/dbaccess/source/core/dataaccess/documentevents.cxx
new file mode 100644
index 000000000..571ad2c6f
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/documentevents.cxx
@@ -0,0 +1,216 @@
+/* -*- 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 <documentevents.hxx>
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include <o3tl/string_view.hxx>
+#include <osl/diagnose.h>
+#include <comphelper/namedvaluecollection.hxx>
+#include <comphelper/sequence.hxx>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::beans::PropertyValue;
+ using ::com::sun::star::container::NoSuchElementException;
+ using ::com::sun::star::lang::IllegalArgumentException;
+ using ::com::sun::star::uno::Sequence;
+ using ::com::sun::star::uno::Type;
+
+ // DocumentEvents_Data
+ struct DocumentEvents_Data
+ {
+ ::cppu::OWeakObject& rParent;
+ ::osl::Mutex& rMutex;
+ DocumentEventsData& rEventsData;
+
+ DocumentEvents_Data( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, DocumentEventsData& _rEventsData )
+ :rParent( _rParent )
+ ,rMutex( _rMutex )
+ ,rEventsData( _rEventsData )
+ {
+ }
+ DocumentEvents_Data(const DocumentEvents_Data&) = delete;
+ const DocumentEvents_Data& operator=(const DocumentEvents_Data&) = delete;
+ };
+
+ namespace {
+
+ // helper
+ struct DocumentEventData
+ {
+ const char* pAsciiEventName;
+ bool bNeedsSyncNotify;
+ };
+
+ const DocumentEventData* lcl_getDocumentEventData()
+ {
+ static const DocumentEventData s_aData[] = {
+ { "OnCreate", true },
+ { "OnLoadFinished", true },
+ { "OnNew", false }, // compatibility, see https://bz.apache.org/ooo/show_bug.cgi?id=46484
+ { "OnLoad", false }, // compatibility, see https://bz.apache.org/ooo/show_bug.cgi?id=46484
+ { "OnSaveAs", true },
+ { "OnSaveAsDone", false },
+ { "OnSaveAsFailed", false },
+ { "OnSave", true },
+ { "OnSaveDone", false },
+ { "OnSaveFailed", false },
+ { "OnSaveTo", true },
+ { "OnSaveToDone", false },
+ { "OnSaveToFailed", false },
+ { "OnPrepareUnload", true },
+ { "OnUnload", true },
+ { "OnFocus", false },
+ { "OnUnfocus", false },
+ { "OnModifyChanged", false },
+ { "OnViewCreated", false },
+ { "OnPrepareViewClosing", true },
+ { "OnViewClosed", false },
+ { "OnTitleChanged", false },
+ { "OnSubComponentOpened", false },
+ { "OnSubComponentClosed", false },
+ { nullptr, false }
+ };
+ return s_aData;
+ }
+ }
+
+ // DocumentEvents
+ DocumentEvents::DocumentEvents( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, DocumentEventsData& _rEventsData )
+ :m_pData( new DocumentEvents_Data( _rParent, _rMutex, _rEventsData ) )
+ {
+ const DocumentEventData* pEventData = lcl_getDocumentEventData();
+ while ( pEventData->pAsciiEventName )
+ {
+ OUString sEventName = OUString::createFromAscii( pEventData->pAsciiEventName );
+ DocumentEventsData::const_iterator existingPos = m_pData->rEventsData.find( sEventName );
+ if ( existingPos == m_pData->rEventsData.end() )
+ m_pData->rEventsData[ sEventName ] = Sequence< PropertyValue >();
+ ++pEventData;
+ }
+ }
+
+ DocumentEvents::~DocumentEvents()
+ {
+ }
+
+ void SAL_CALL DocumentEvents::acquire() noexcept
+ {
+ m_pData->rParent.acquire();
+ }
+
+ void SAL_CALL DocumentEvents::release() noexcept
+ {
+ m_pData->rParent.release();
+ }
+
+ bool DocumentEvents::needsSynchronousNotification( std::u16string_view _rEventName )
+ {
+ const DocumentEventData* pEventData = lcl_getDocumentEventData();
+ while ( pEventData->pAsciiEventName )
+ {
+ if ( o3tl::equalsAscii( _rEventName, pEventData->pAsciiEventName ) )
+ return pEventData->bNeedsSyncNotify;
+ ++pEventData;
+ }
+
+ // this is an unknown event ... assume async notification
+ return false;
+ }
+
+ void SAL_CALL DocumentEvents::replaceByName( const OUString& Name, const Any& Element )
+ {
+ ::osl::MutexGuard aGuard( m_pData->rMutex );
+
+ DocumentEventsData::iterator elementPos = m_pData->rEventsData.find( Name );
+ if ( elementPos == m_pData->rEventsData.end() )
+ throw NoSuchElementException( Name, *this );
+
+ Sequence< PropertyValue > aEventDescriptor;
+ if ( Element.hasValue() && !( Element >>= aEventDescriptor ) )
+ throw IllegalArgumentException( Element.getValueTypeName(), *this, 2 );
+
+ // Weird enough, the event assignment UI has (well: had) the idea of using an empty "EventType"/"Script"
+ // to indicate the event descriptor should be reset, instead of just passing an empty event descriptor.
+ ::comphelper::NamedValueCollection aCheck( aEventDescriptor );
+ if ( aCheck.has( "EventType" ) )
+ {
+ OUString sEventType = aCheck.getOrDefault( "EventType", OUString() );
+ OSL_ENSURE( !sEventType.isEmpty(), "DocumentEvents::replaceByName: doing a reset via an empty EventType is weird!" );
+ if ( sEventType.isEmpty() )
+ aEventDescriptor.realloc( 0 );
+ }
+ if ( aCheck.has( "Script" ) )
+ {
+ OUString sScript = aCheck.getOrDefault( "Script", OUString() );
+ OSL_ENSURE( !sScript.isEmpty(), "DocumentEvents::replaceByName: doing a reset via an empty Script is weird!" );
+ if ( sScript.isEmpty() )
+ aEventDescriptor.realloc( 0 );
+ }
+
+ elementPos->second = aEventDescriptor;
+ }
+
+ Any SAL_CALL DocumentEvents::getByName( const OUString& Name )
+ {
+ ::osl::MutexGuard aGuard( m_pData->rMutex );
+
+ DocumentEventsData::const_iterator elementPos = m_pData->rEventsData.find( Name );
+ if ( elementPos == m_pData->rEventsData.end() )
+ throw NoSuchElementException( Name, *this );
+
+ Any aReturn;
+ const Sequence< PropertyValue >& rEventDesc( elementPos->second );
+ if ( rEventDesc.hasElements() )
+ aReturn <<= rEventDesc;
+ return aReturn;
+ }
+
+ Sequence< OUString > SAL_CALL DocumentEvents::getElementNames( )
+ {
+ ::osl::MutexGuard aGuard( m_pData->rMutex );
+
+ return comphelper::mapKeysToSequence( m_pData->rEventsData );
+ }
+
+ sal_Bool SAL_CALL DocumentEvents::hasByName( const OUString& Name )
+ {
+ ::osl::MutexGuard aGuard( m_pData->rMutex );
+
+ return m_pData->rEventsData.find( Name ) != m_pData->rEventsData.end();
+ }
+
+ Type SAL_CALL DocumentEvents::getElementType( )
+ {
+ return ::cppu::UnoType< Sequence< PropertyValue > >::get();
+ }
+
+ sal_Bool SAL_CALL DocumentEvents::hasElements( )
+ {
+ ::osl::MutexGuard aGuard( m_pData->rMutex );
+ return !m_pData->rEventsData.empty();
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/intercept.cxx b/dbaccess/source/core/dataaccess/intercept.cxx
new file mode 100644
index 000000000..bef079d47
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/intercept.cxx
@@ -0,0 +1,363 @@
+/* -*- 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 "intercept.hxx"
+
+#include <tools/diagnose_ex.h>
+
+#include <memory>
+
+namespace dbaccess
+{
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::util;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::frame;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::embed;
+using namespace ::com::sun::star::container;
+using namespace ::comphelper;
+using namespace ::cppu;
+
+#define DISPATCH_SAVEAS 0
+#define DISPATCH_SAVE 1
+#define DISPATCH_CLOSEDOC 2
+#define DISPATCH_CLOSEWIN 3
+#define DISPATCH_CLOSEFRAME 4
+#define DISPATCH_RELOAD 5
+// the OSL_ENSURE in CTOR has to be changed too, when adding new defines
+
+void OInterceptor::dispose()
+{
+ EventObject aEvt( *this );
+
+ osl::MutexGuard aGuard(m_aMutex);
+
+ if ( m_pStatCL )
+ m_pStatCL->disposeAndClear( aEvt );
+
+ m_xSlaveDispatchProvider.clear();
+ m_xMasterDispatchProvider.clear();
+
+ m_pContentHolder = nullptr;
+}
+
+
+OInterceptor::OInterceptor( ODocumentDefinition* _pContentHolder )
+ :m_pContentHolder( _pContentHolder )
+ ,m_aInterceptedURL{ /* DISPATCH_SAVEAS */ ".uno:SaveAs",
+ /* DISPATCH_SAVE */ ".uno:Save",
+ /* DISPATCH_CLOSEDOC */ ".uno:CloseDoc",
+ /* DISPATCH_CLOSEWIN */ ".uno:CloseWin",
+ /* DISPATCH_CLOSEFRAME */ ".uno:CloseFrame",
+ /* DISPATCH_RELOAD */ ".uno:Reload" }
+{
+ OSL_ENSURE(DISPATCH_RELOAD < m_aInterceptedURL.getLength(),"Illegal size.");
+}
+
+
+OInterceptor::~OInterceptor()
+{
+}
+
+namespace {
+
+struct DispatchHelper
+{
+ URL aURL;
+ Sequence<PropertyValue > aArguments;
+};
+
+}
+
+//XDispatch
+void SAL_CALL OInterceptor::dispatch( const URL& URL,const Sequence<PropertyValue >& Arguments )
+{
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( !m_pContentHolder )
+ return;
+
+ if ( URL.Complete == m_aInterceptedURL[ DISPATCH_SAVE ] )
+ {
+ m_pContentHolder->save(false, css::uno::Reference<css::awt::XTopWindow>());
+ return;
+ }
+
+ if ( URL.Complete == m_aInterceptedURL[ DISPATCH_RELOAD ] )
+ {
+ ODocumentDefinition::fillReportData(
+ m_pContentHolder->getContext(),
+ m_pContentHolder->getComponent(),
+ m_pContentHolder->getConnection()
+ );
+ return;
+ }
+
+ if( URL.Complete == m_aInterceptedURL[ DISPATCH_SAVEAS ] )
+ {
+ if ( m_pContentHolder->isNewReport() )
+ {
+ m_pContentHolder->saveAs();
+ }
+ else if ( m_xSlaveDispatchProvider.is() )
+ {
+ Sequence< PropertyValue > aNewArgs = Arguments;
+ sal_Int32 nInd = 0;
+
+ while( nInd < aNewArgs.getLength() )
+ {
+ if ( aNewArgs[nInd].Name == "SaveTo" )
+ {
+ aNewArgs.getArray()[nInd].Value <<= true;
+ break;
+ }
+ nInd++;
+ }
+
+ if ( nInd == aNewArgs.getLength() )
+ {
+ aNewArgs.realloc( nInd + 1 );
+ auto pNewArgs = aNewArgs.getArray();
+ pNewArgs[nInd].Name = "SaveTo";
+ pNewArgs[nInd].Value <<= true;
+ }
+
+ Reference< XDispatch > xDispatch = m_xSlaveDispatchProvider->queryDispatch(URL, "_self", 0 );
+ if ( xDispatch.is() )
+ xDispatch->dispatch( URL, aNewArgs );
+ }
+ return;
+ }
+
+ if ( URL.Complete == m_aInterceptedURL[ DISPATCH_CLOSEDOC ]
+ || URL.Complete == m_aInterceptedURL[ DISPATCH_CLOSEWIN ]
+ || URL.Complete == m_aInterceptedURL[ DISPATCH_CLOSEFRAME ]
+ )
+ {
+ DispatchHelper* pHelper = new DispatchHelper;
+ pHelper->aArguments = Arguments;
+ pHelper->aURL = URL;
+ Application::PostUserEvent( LINK( this, OInterceptor, OnDispatch ), pHelper );
+ return;
+ }
+}
+
+IMPL_LINK( OInterceptor, OnDispatch, void*, _pDispatcher, void )
+{
+ std::unique_ptr<DispatchHelper> pHelper( static_cast< DispatchHelper* >( _pDispatcher ) );
+ try
+ {
+ if ( m_pContentHolder && m_pContentHolder->prepareClose() && m_xSlaveDispatchProvider.is() )
+ {
+ Reference< XDispatch > xDispatch = m_xSlaveDispatchProvider->queryDispatch(pHelper->aURL, "_self", 0 );
+ if ( xDispatch.is() )
+ {
+ Reference< XInterface > xKeepContentHolderAlive( *m_pContentHolder );
+ xDispatch->dispatch( pHelper->aURL,pHelper->aArguments);
+ }
+ }
+ }
+ catch ( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void SAL_CALL OInterceptor::addStatusListener(
+ const Reference<
+ XStatusListener >& Control,
+ const URL& URL )
+{
+ if(!Control.is())
+ return;
+
+ if ( m_pContentHolder && URL.Complete == m_aInterceptedURL[DISPATCH_SAVEAS] )
+ { // SaveAs
+
+ if ( !m_pContentHolder->isNewReport() )
+ {
+ FeatureStateEvent aStateEvent;
+ aStateEvent.FeatureURL.Complete = m_aInterceptedURL[DISPATCH_SAVEAS];
+ aStateEvent.FeatureDescriptor = "SaveCopyTo";
+ aStateEvent.IsEnabled = true;
+ aStateEvent.Requery = false;
+ aStateEvent.State <<= OUString("($3)");
+ Control->statusChanged(aStateEvent);
+ }
+
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ if(!m_pStatCL)
+ m_pStatCL.reset( new StatusListenerContainer(m_aMutex) );
+ }
+
+ m_pStatCL->addInterface(URL.Complete,Control);
+ }
+ else if ( m_pContentHolder && URL.Complete == m_aInterceptedURL[DISPATCH_SAVE] )
+ { // Save
+ FeatureStateEvent aStateEvent;
+ aStateEvent.FeatureURL.Complete = m_aInterceptedURL[DISPATCH_SAVE];
+ aStateEvent.FeatureDescriptor = "Update";
+ aStateEvent.IsEnabled = true;
+ aStateEvent.Requery = false;
+
+ Control->statusChanged(aStateEvent);
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ if(!m_pStatCL)
+ m_pStatCL.reset( new StatusListenerContainer(m_aMutex) );
+ }
+
+ m_pStatCL->addInterface(URL.Complete,Control);
+ }
+ else
+ {
+ sal_Int32 i = 2;
+ if(URL.Complete == m_aInterceptedURL[i] ||
+ URL.Complete == m_aInterceptedURL[++i] ||
+ URL.Complete == m_aInterceptedURL[++i] ||
+ URL.Complete == m_aInterceptedURL[i = DISPATCH_RELOAD] )
+ { // Close and return
+ FeatureStateEvent aStateEvent;
+ aStateEvent.FeatureURL.Complete = m_aInterceptedURL[i];
+ aStateEvent.FeatureDescriptor = "Close and Return";
+ aStateEvent.IsEnabled = true;
+ aStateEvent.Requery = false;
+ Control->statusChanged(aStateEvent);
+
+
+ {
+ osl::MutexGuard aGuard(m_aMutex);
+ if(!m_pStatCL)
+ m_pStatCL.reset( new StatusListenerContainer(m_aMutex) );
+ }
+
+ m_pStatCL->addInterface(URL.Complete,Control);
+ return;
+ }
+ }
+}
+
+
+void SAL_CALL OInterceptor::removeStatusListener(
+ const Reference<
+ XStatusListener >& Control,
+ const URL& URL )
+{
+ if(!(Control.is() && m_pStatCL))
+ return;
+ else
+ {
+ m_pStatCL->removeInterface(URL.Complete,Control);
+ return;
+ }
+}
+
+
+//XInterceptorInfo
+Sequence< OUString > SAL_CALL OInterceptor::getInterceptedURLs( )
+{
+ // now implemented as update
+ return m_aInterceptedURL;
+}
+
+
+// XDispatchProvider
+
+Reference< XDispatch > SAL_CALL OInterceptor::queryDispatch( const URL& URL,const OUString& TargetFrameName,sal_Int32 SearchFlags )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ const OUString* pIter = m_aInterceptedURL.getConstArray();
+ const OUString* pEnd = pIter + m_aInterceptedURL.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( URL.Complete == *pIter )
+ return static_cast<XDispatch*>(this);
+ }
+
+ if(m_xSlaveDispatchProvider.is())
+ return m_xSlaveDispatchProvider->queryDispatch(URL,TargetFrameName,SearchFlags);
+ else
+ return Reference<XDispatch>();
+}
+
+Sequence< Reference< XDispatch > > SAL_CALL OInterceptor::queryDispatches( const Sequence<DispatchDescriptor >& Requests )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ typedef Sequence<Reference<XDispatch>> DispatchSeq;
+ DispatchSeq aRet = m_xSlaveDispatchProvider.is() ?
+ m_xSlaveDispatchProvider->queryDispatches(Requests) :
+ DispatchSeq(Requests.getLength());
+
+ auto aRetRange = asNonConstRange(aRet);
+ for(sal_Int32 i = 0; i < Requests.getLength(); ++i)
+ {
+ const OUString* pIter = m_aInterceptedURL.getConstArray();
+ const OUString* pEnd = pIter + m_aInterceptedURL.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( Requests[i].FeatureURL.Complete == *pIter )
+ {
+ aRetRange[i] = static_cast<XDispatch*>(this);
+ break;
+ }
+ }
+ }
+
+ return aRet;
+}
+
+
+//XDispatchProviderInterceptor
+
+Reference< XDispatchProvider > SAL_CALL OInterceptor::getSlaveDispatchProvider( )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ return m_xSlaveDispatchProvider;
+}
+
+void SAL_CALL
+OInterceptor::setSlaveDispatchProvider( const Reference< XDispatchProvider >& NewDispatchProvider )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ m_xSlaveDispatchProvider = NewDispatchProvider;
+}
+
+
+Reference< XDispatchProvider > SAL_CALL OInterceptor::getMasterDispatchProvider( )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ return m_xMasterDispatchProvider;
+}
+
+
+void SAL_CALL OInterceptor::setMasterDispatchProvider(
+ const Reference< XDispatchProvider >& NewSupplier )
+{
+ osl::MutexGuard aGuard(m_aMutex);
+ m_xMasterDispatchProvider = NewSupplier;
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/intercept.hxx b/dbaccess/source/core/dataaccess/intercept.hxx
new file mode 100644
index 000000000..7ce53752f
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/intercept.hxx
@@ -0,0 +1,113 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <osl/mutex.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/interfacecontainer.hxx>
+#include <com/sun/star/frame/XDispatchProviderInterceptor.hpp>
+#include <com/sun/star/frame/XInterceptorInfo.hpp>
+#include <com/sun/star/frame/XDispatch.hpp>
+#include "documentdefinition.hxx"
+#include <vcl/svapp.hxx>
+
+namespace dbaccess
+{
+
+
+class OInterceptor : public ::cppu::WeakImplHelper< css::frame::XDispatchProviderInterceptor,
+ css::frame::XInterceptorInfo,
+ css::frame::XDispatch >
+{
+ DECL_LINK( OnDispatch, void*, void );
+protected:
+ virtual ~OInterceptor() override;
+public:
+
+ explicit OInterceptor( ODocumentDefinition* _pContentHolder );
+
+ /// @throws css::uno::RuntimeException
+ void dispose();
+
+ //XDispatch
+ virtual void SAL_CALL
+ dispatch(
+ const css::util::URL& URL,
+ const css::uno::Sequence< css::beans::PropertyValue >& Arguments ) override;
+
+ virtual void SAL_CALL
+ addStatusListener(
+ const css::uno::Reference< css::frame::XStatusListener >& Control,
+ const css::util::URL& URL ) override;
+
+ virtual void SAL_CALL
+ removeStatusListener(
+ const css::uno::Reference< css::frame::XStatusListener >& Control,
+ const css::util::URL& URL ) override;
+
+ //XInterceptorInfo
+ virtual css::uno::Sequence< OUString >
+ SAL_CALL getInterceptedURLs( ) override;
+
+ //XDispatchProvider ( inherited by XDispatchProviderInterceptor )
+ virtual css::uno::Reference< css::frame::XDispatch > SAL_CALL
+ queryDispatch(
+ const css::util::URL& URL,
+ const OUString& TargetFrameName,
+ sal_Int32 SearchFlags ) override;
+
+ virtual css::uno::Sequence< css::uno::Reference< css::frame::XDispatch > > SAL_CALL
+ queryDispatches(
+ const css::uno::Sequence< css::frame::DispatchDescriptor >& Requests ) override;
+
+ //XDispatchProviderInterceptor
+ virtual css::uno::Reference< css::frame::XDispatchProvider > SAL_CALL
+ getSlaveDispatchProvider( ) override;
+
+ virtual void SAL_CALL
+ setSlaveDispatchProvider(
+ const css::uno::Reference< css::frame::XDispatchProvider >& NewDispatchProvider ) override;
+
+ virtual css::uno::Reference< css::frame::XDispatchProvider > SAL_CALL
+ getMasterDispatchProvider( ) override;
+
+ virtual void SAL_CALL
+ setMasterDispatchProvider(
+ const css::uno::Reference< css::frame::XDispatchProvider >& NewSupplier ) override;
+
+private:
+
+ osl::Mutex m_aMutex;
+
+ ODocumentDefinition* m_pContentHolder;
+
+ css::uno::Reference< css::frame::XDispatchProvider > m_xSlaveDispatchProvider;
+ css::uno::Reference< css::frame::XDispatchProvider > m_xMasterDispatchProvider;
+
+ css::uno::Sequence< OUString > m_aInterceptedURL;
+
+ typedef comphelper::OMultiTypeInterfaceContainerHelperVar3<css::frame::XStatusListener, OUString>
+ StatusListenerContainer;
+ std::unique_ptr<StatusListenerContainer> m_pStatCL;
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/myucp_datasupplier.cxx b/dbaccess/source/core/dataaccess/myucp_datasupplier.cxx
new file mode 100644
index 000000000..e0d32d569
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/myucp_datasupplier.cxx
@@ -0,0 +1,330 @@
+/* -*- 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 <vector>
+
+#include <ucbhelper/contentidentifier.hxx>
+
+#include "myucp_datasupplier.hxx"
+#include <ContentHelper.hxx>
+#include <com/sun/star/ucb/IllegalIdentifierException.hpp>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::container;
+
+// @@@ Adjust namespace name.
+using namespace dbaccess;
+
+// @@@ Adjust namespace name.
+namespace dbaccess
+{
+
+namespace {
+
+// struct ResultListEntry.
+struct ResultListEntry
+{
+ OUString aId;
+ Reference< XContentIdentifier > xId;
+ ::rtl::Reference< OContentHelper > xContent;
+ Reference< XRow > xRow;
+ const ContentProperties& rData;
+
+ explicit ResultListEntry(const ContentProperties& rEntry) : rData( rEntry ) {}
+};
+
+}
+
+// struct DataSupplier_Impl.
+struct DataSupplier_Impl
+{
+ osl::Mutex m_aMutex;
+ std::vector< std::unique_ptr<ResultListEntry> > m_aResults;
+ rtl::Reference< ODocumentContainer > m_xContent;
+ bool m_bCountFinal;
+
+ explicit DataSupplier_Impl(const rtl::Reference< ODocumentContainer >& rContent)
+ : m_xContent(rContent)
+ , m_bCountFinal(false)
+ {
+ }
+};
+
+}
+
+// DataSupplier Implementation.
+
+DataSupplier::DataSupplier( const rtl::Reference< ODocumentContainer >& rContent )
+: m_pImpl( new DataSupplier_Impl( rContent ) )
+{
+
+}
+
+DataSupplier::~DataSupplier()
+{
+
+}
+
+OUString DataSupplier::queryContentIdentifierString( sal_uInt32 nIndex )
+{
+ osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
+
+ if ( static_cast<size_t>(nIndex) < m_pImpl->m_aResults.size() )
+ {
+ OUString aId = m_pImpl->m_aResults[ nIndex ]->aId;
+ if ( !aId.isEmpty() )
+ {
+ // Already cached.
+ return aId;
+ }
+ }
+
+ if ( getResult( nIndex ) )
+ {
+ OUString aId = m_pImpl->m_xContent->getIdentifier()->getContentIdentifier();
+
+ if ( !aId.isEmpty() )
+ aId += "/";
+
+ aId += m_pImpl->m_aResults[ nIndex ]->rData.aTitle;
+
+ m_pImpl->m_aResults[ nIndex ]->aId = aId;
+ return aId;
+ }
+ return OUString();
+}
+
+Reference< XContentIdentifier >
+DataSupplier::queryContentIdentifier( sal_uInt32 nIndex )
+{
+ osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
+
+ if ( static_cast<size_t>(nIndex) < m_pImpl->m_aResults.size() )
+ {
+ Reference< XContentIdentifier > xId = m_pImpl->m_aResults[ nIndex ]->xId;
+ if ( xId.is() )
+ {
+ // Already cached.
+ return xId;
+ }
+ }
+
+ OUString aId = queryContentIdentifierString( nIndex );
+ if ( !aId.isEmpty() )
+ {
+ Reference< XContentIdentifier > xId = new ::ucbhelper::ContentIdentifier( aId );
+ m_pImpl->m_aResults[ nIndex ]->xId = xId;
+ return xId;
+ }
+ return Reference< XContentIdentifier >();
+}
+
+Reference< XContent >
+DataSupplier::queryContent( sal_uInt32 _nIndex )
+{
+ osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
+
+ if ( static_cast<size_t>(_nIndex) < m_pImpl->m_aResults.size() )
+ {
+ Reference< XContent > xContent = m_pImpl->m_aResults[ _nIndex ]->xContent;
+ if ( xContent.is() )
+ {
+ // Already cached.
+ return xContent;
+ }
+ }
+
+ Reference< XContentIdentifier > xId = queryContentIdentifier( _nIndex );
+ if ( xId.is() )
+ {
+ try
+ {
+ Reference< XContent > xContent;
+ OUString sName = xId->getContentIdentifier();
+ sName = sName.copy(sName.lastIndexOf('/')+1);
+
+ m_pImpl->m_aResults[ _nIndex ]->xContent = m_pImpl->m_xContent->getContent(sName);
+
+ xContent = m_pImpl->m_aResults[ _nIndex ]->xContent.get();
+ return xContent;
+
+ }
+ catch ( IllegalIdentifierException& )
+ {
+ }
+ }
+ return Reference< XContent >();
+}
+
+bool DataSupplier::getResult( sal_uInt32 nIndex )
+{
+ osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
+
+ if ( static_cast<size_t>(nIndex) < m_pImpl->m_aResults.size() )
+ {
+ // Result already present.
+ return true;
+ }
+
+ // Result not (yet) present.
+
+ if ( m_pImpl->m_bCountFinal )
+ return false;
+
+ // Try to obtain result...
+
+ sal_uInt32 nOldCount = m_pImpl->m_aResults.size();
+ bool bFound = false;
+ sal_uInt32 nPos = nOldCount;
+
+ // @@@ Obtain data and put it into result list...
+ Sequence< OUString> aSeq = m_pImpl->m_xContent->getElementNames();
+ if ( nIndex < sal::static_int_cast< sal_uInt32 >( aSeq.getLength() ) )
+ {
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ for(pIter = pIter + nPos;pIter != pEnd;++pIter,++nPos)
+ {
+ m_pImpl->m_aResults.emplace_back(
+ new ResultListEntry( m_pImpl->m_xContent->getContent(*pIter)->getContentProperties() ) );
+
+ if ( nPos == nIndex )
+ {
+ // Result obtained.
+ bFound = true;
+ break;
+ }
+ }
+ }
+
+ if ( !bFound )
+ m_pImpl->m_bCountFinal = true;
+
+ rtl::Reference< ::ucbhelper::ResultSet > xResultSet = getResultSet();
+ if ( xResultSet.is() )
+ {
+ // Callbacks follow!
+ aGuard.clear();
+
+ if ( static_cast<size_t>(nOldCount) < m_pImpl->m_aResults.size() )
+ xResultSet->rowCountChanged(
+ nOldCount, m_pImpl->m_aResults.size() );
+
+ if ( m_pImpl->m_bCountFinal )
+ xResultSet->rowCountFinal();
+ }
+
+ return bFound;
+}
+
+sal_uInt32 DataSupplier::totalCount()
+{
+ osl::ClearableGuard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
+
+ if ( m_pImpl->m_bCountFinal )
+ return m_pImpl->m_aResults.size();
+
+ sal_uInt32 nOldCount = m_pImpl->m_aResults.size();
+
+ // @@@ Obtain data and put it into result list...
+ Sequence< OUString> aSeq = m_pImpl->m_xContent->getElementNames();
+ const OUString* pIter = aSeq.getConstArray();
+ const OUString* pEnd = pIter + aSeq.getLength();
+ for(;pIter != pEnd;++pIter)
+ m_pImpl->m_aResults.emplace_back(
+ new ResultListEntry( m_pImpl->m_xContent->getContent(*pIter)->getContentProperties() ) );
+
+ m_pImpl->m_bCountFinal = true;
+
+ rtl::Reference< ::ucbhelper::ResultSet > xResultSet = getResultSet();
+ if ( xResultSet.is() )
+ {
+ // Callbacks follow!
+ aGuard.clear();
+
+ if ( static_cast<size_t>(nOldCount) < m_pImpl->m_aResults.size() )
+ xResultSet->rowCountChanged(
+ nOldCount, m_pImpl->m_aResults.size() );
+
+ xResultSet->rowCountFinal();
+ }
+
+ return m_pImpl->m_aResults.size();
+}
+
+sal_uInt32 DataSupplier::currentCount()
+{
+ return m_pImpl->m_aResults.size();
+}
+
+bool DataSupplier::isCountFinal()
+{
+ return m_pImpl->m_bCountFinal;
+}
+
+Reference< XRow >
+DataSupplier::queryPropertyValues( sal_uInt32 nIndex )
+{
+ osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
+
+ if ( static_cast<size_t>(nIndex) < m_pImpl->m_aResults.size() )
+ {
+ Reference< XRow > xRow = m_pImpl->m_aResults[ nIndex ]->xRow;
+ if ( xRow.is() )
+ {
+ // Already cached.
+ return xRow;
+ }
+ }
+
+ if ( getResult( nIndex ) )
+ {
+ if ( !m_pImpl->m_aResults[ nIndex ]->xContent.is() )
+ queryContent(nIndex);
+
+ Reference< XRow > xRow = m_pImpl->m_aResults[ nIndex ]->xContent->getPropertyValues(getResultSet()->getProperties());
+ m_pImpl->m_aResults[ nIndex ]->xRow = xRow;
+ return xRow;
+ }
+
+ return Reference< XRow >();
+}
+
+void DataSupplier::releasePropertyValues( sal_uInt32 nIndex )
+{
+ osl::Guard< osl::Mutex > aGuard( m_pImpl->m_aMutex );
+
+ if ( static_cast<size_t>(nIndex) < m_pImpl->m_aResults.size() )
+ m_pImpl->m_aResults[ nIndex ]->xRow.clear();
+}
+
+void DataSupplier::close()
+{
+}
+
+void DataSupplier::validate()
+{
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/myucp_datasupplier.hxx b/dbaccess/source/core/dataaccess/myucp_datasupplier.hxx
new file mode 100644
index 000000000..8083f5ef5
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/myucp_datasupplier.hxx
@@ -0,0 +1,59 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <rtl/ref.hxx>
+#include <ucbhelper/resultset.hxx>
+#include "documentcontainer.hxx"
+#include <memory>
+
+namespace dbaccess
+{
+struct DataSupplier_Impl;
+
+class DataSupplier : public ucbhelper::ResultSetDataSupplier
+{
+ std::unique_ptr<DataSupplier_Impl> m_pImpl;
+
+public:
+ explicit DataSupplier(const rtl::Reference<ODocumentContainer>& rxContent);
+ virtual ~DataSupplier() override;
+
+ virtual OUString queryContentIdentifierString(sal_uInt32 nIndex) override;
+ virtual css::uno::Reference<css::ucb::XContentIdentifier>
+ queryContentIdentifier(sal_uInt32 nIndex) override;
+ virtual css::uno::Reference<css::ucb::XContent> queryContent(sal_uInt32 nIndex) override;
+
+ virtual bool getResult(sal_uInt32 nIndex) override;
+
+ virtual sal_uInt32 totalCount() override;
+ virtual sal_uInt32 currentCount() override;
+ virtual bool isCountFinal() override;
+
+ virtual css::uno::Reference<css::sdbc::XRow> queryPropertyValues(sal_uInt32 nIndex) override;
+ virtual void releasePropertyValues(sal_uInt32 nIndex) override;
+
+ virtual void close() override;
+
+ virtual void validate() override;
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/myucp_resultset.cxx b/dbaccess/source/core/dataaccess/myucp_resultset.cxx
new file mode 100644
index 000000000..67c1ad7c8
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/myucp_resultset.cxx
@@ -0,0 +1,74 @@
+/* -*- 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 .
+ */
+
+/**************************************************************************
+ TODO
+ **************************************************************************
+
+ - This implementation is not a dynamic result set!!! It only implements
+ the necessary interfaces, but never recognizes/notifies changes!!!
+
+ *************************************************************************/
+
+#include "myucp_datasupplier.hxx"
+#include "myucp_resultset.hxx"
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::ucb;
+using namespace ::com::sun::star::beans;
+using namespace ::com::sun::star::lang;
+using namespace ::com::sun::star::sdbc;
+using namespace ::com::sun::star::io;
+using namespace ::com::sun::star::container;
+
+using namespace dbaccess;
+
+// DynamicResultSet Implementation.
+DynamicResultSet::DynamicResultSet(
+ const Reference< XComponentContext >& rxContext,
+ const rtl::Reference< ODocumentContainer >& rxContent,
+ const OpenCommandArgument2& rCommand,
+ const Reference< XCommandEnvironment >& rxEnv )
+ :ResultSetImplHelper( rxContext, rCommand )
+ ,m_xContent(rxContent)
+ ,m_xEnv( rxEnv )
+{
+}
+
+// Non-interface methods.
+void DynamicResultSet::initStatic()
+{
+ m_xResultSet1
+ = new ::ucbhelper::ResultSet( m_xContext,
+ m_aCommand.Properties,
+ new DataSupplier( m_xContent ),
+ m_xEnv );
+}
+
+void DynamicResultSet::initDynamic()
+{
+ m_xResultSet1
+ = new ::ucbhelper::ResultSet( m_xContext,
+ m_aCommand.Properties,
+ new DataSupplier( m_xContent ),
+ m_xEnv );
+ m_xResultSet2 = m_xResultSet1;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/dataaccess/myucp_resultset.hxx b/dbaccess/source/core/dataaccess/myucp_resultset.hxx
new file mode 100644
index 000000000..ae269ffb8
--- /dev/null
+++ b/dbaccess/source/core/dataaccess/myucp_resultset.hxx
@@ -0,0 +1,49 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <rtl/ref.hxx>
+#include <ucbhelper/resultsethelper.hxx>
+#include "documentcontainer.hxx"
+
+
+// @@@ Adjust namespace name.
+namespace dbaccess {
+
+class DynamicResultSet : public ::ucbhelper::ResultSetImplHelper
+{
+ rtl::Reference< ODocumentContainer > m_xContent;
+ css::uno::Reference< css::ucb::XCommandEnvironment > m_xEnv;
+
+private:
+ virtual void initStatic() override;
+ virtual void initDynamic() override;
+
+public:
+ DynamicResultSet(
+ const css::uno::Reference< css::uno::XComponentContext >& rxContext,
+ const rtl::Reference< ODocumentContainer >& rxContent,
+ const css::ucb::OpenCommandArgument2& rCommand,
+ const css::uno::Reference< css::ucb::XCommandEnvironment >& rxEnv );
+};
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/ContainerMediator.hxx b/dbaccess/source/core/inc/ContainerMediator.hxx
new file mode 100644
index 000000000..37bfc0eba
--- /dev/null
+++ b/dbaccess/source/core/inc/ContainerMediator.hxx
@@ -0,0 +1,79 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <rtl/ref.hxx>
+
+#include <map>
+
+namespace dbaccess
+{
+
+ class OPropertyForward;
+
+ class OContainerMediator : public ::cppu::BaseMutex
+ ,public ::cppu::WeakImplHelper< css::container::XContainerListener >
+ {
+ private:
+ typedef std::map< OUString, ::rtl::Reference< OPropertyForward > > PropertyForwardList;
+ PropertyForwardList m_aForwardList;
+ css::uno::Reference< css::container::XNameAccess > m_xSettings; // can not be weak
+ css::uno::Reference< css::container::XContainer > m_xContainer; // can not be weak
+
+ protected:
+ virtual ~OContainerMediator() override;
+
+ public:
+ OContainerMediator(
+ const css::uno::Reference< css::container::XContainer >& _xContainer,
+ const css::uno::Reference< css::container::XNameAccess >& _xSettings
+ );
+
+ virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& _rEvent ) override;
+ virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& _rEvent ) override;
+ virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& _rEvent ) override;
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ void notifyElementCreated(const OUString& _sElementName
+ ,const css::uno::Reference< css::beans::XPropertySet>& _xElement);
+
+ private:
+ /** cleans up the instance, by deregistering as listener at the containers,
+ and resetting them to <NULL/>
+ */
+ void impl_cleanup_nothrow();
+
+ /** initializes the properties of the given object from its counterpart in our settings container
+ */
+ void impl_initSettings_nothrow(
+ const OUString& _rName,
+ const css::uno::Reference< css::beans::XPropertySet >& _rxDestination
+ );
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/ContentHelper.hxx b/dbaccess/source/core/inc/ContentHelper.hxx
new file mode 100644
index 000000000..004b785ef
--- /dev/null
+++ b/dbaccess/source/core/inc/ContentHelper.hxx
@@ -0,0 +1,183 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <com/sun/star/ucb/XContent.hpp>
+#include <com/sun/star/ucb/XCommandProcessor.hpp>
+#include <com/sun/star/beans/XPropertiesChangeNotifier.hpp>
+#include <com/sun/star/beans/XPropertyContainer.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XInitialization.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <comphelper/interfacecontainer3.hxx>
+#include <comphelper/multiinterfacecontainer3.hxx>
+#include <com/sun/star/beans/Property.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/sdbcx/XRename.hpp>
+#include <connectivity/sqlerror.hxx>
+#include <memory>
+
+namespace com::sun::star::beans { struct PropertyValue; }
+
+namespace dbaccess
+{
+ class ODatabaseModelImpl;
+ struct ContentProperties
+ {
+ OUString aTitle; // Title
+ ::std::optional< OUString >
+ aContentType; // ContentType (aka MediaType aka MimeType)
+ bool bIsDocument; // IsDocument
+ bool bIsFolder; // IsFolder
+ bool bAsTemplate; // AsTemplate
+ OUString sPersistentName;// persistent name of the document
+
+ ContentProperties()
+ :bIsDocument( true )
+ ,bIsFolder( false )
+ ,bAsTemplate( false )
+ {
+ }
+ };
+
+ class OContentHelper_Impl
+ {
+ public:
+ OContentHelper_Impl();
+ virtual ~OContentHelper_Impl();
+
+ ContentProperties m_aProps;
+ ODatabaseModelImpl* m_pDataSource; // this will stay alive as long as the content exists
+ };
+
+ typedef std::shared_ptr<OContentHelper_Impl> TContentPtr;
+
+ typedef comphelper::OMultiTypeInterfaceContainerHelperVar3<css::beans::XPropertiesChangeListener, OUString>
+ PropertyChangeListenerContainer;
+ typedef ::cppu::WeakComponentImplHelper< css::ucb::XContent
+ , css::ucb::XCommandProcessor
+ , css::lang::XServiceInfo
+ , css::beans::XPropertiesChangeNotifier
+ , css::beans::XPropertyContainer
+ , css::lang::XInitialization
+ , css::lang::XUnoTunnel
+ , css::container::XChild
+ , css::sdbcx::XRename
+ > OContentHelper_COMPBASE;
+
+ class OContentHelper : public ::cppu::BaseMutex
+ ,public OContentHelper_COMPBASE
+ {
+ css::uno::Sequence< css::uno::Any >
+ setPropertyValues( const css::uno::Sequence< css::beans::PropertyValue >& rValues );
+
+ void impl_rename_throw(const OUString& _sNewName,bool _bNotify = true);
+
+ protected:
+ ::comphelper::OInterfaceContainerHelper3<css::ucb::XContentEventListener> m_aContentListeners;
+ PropertyChangeListenerContainer m_aPropertyChangeListeners;
+ css::uno::Reference< css::uno::XInterface >
+ m_xParentContainer;
+ const css::uno::Reference< css::uno::XComponentContext >
+ m_aContext;
+ const ::connectivity::SQLError m_aErrorHelper;
+ TContentPtr m_pImpl;
+ sal_uInt32 m_nCommandId;
+
+ // helper
+ virtual void SAL_CALL disposing() override;
+
+ void notifyDataSourceModified();
+
+ /**
+ * This method can be used to propagate changes of property values.
+ *
+ * @param evt is a sequence of property change events.
+ */
+ void notifyPropertiesChange( const css::uno::Sequence< css::beans::PropertyChangeEvent >& evt ) const;
+
+ OUString impl_getHierarchicalName( bool _includingRootContainer ) const;
+
+ public:
+
+ OContentHelper( const css::uno::Reference< css::uno::XComponentContext >& _xORB
+ ,const css::uno::Reference< css::uno::XInterface >& _xParentContainer
+ ,const TContentPtr& _pImpl
+ );
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId( ) override;
+
+ // css::lang::XServiceInfo
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+ virtual OUString SAL_CALL getImplementationName( ) override;
+
+ // XContent
+ virtual css::uno::Reference< css::ucb::XContentIdentifier > SAL_CALL getIdentifier( ) override ;
+ virtual OUString SAL_CALL getContentType( ) override ;
+ virtual void SAL_CALL addContentEventListener( const css::uno::Reference< css::ucb::XContentEventListener >& Listener ) override ;
+ virtual void SAL_CALL removeContentEventListener( const css::uno::Reference< css::ucb::XContentEventListener >& Listener ) override ;
+
+ // XCommandProcessor
+ virtual sal_Int32 SAL_CALL createCommandIdentifier( ) override ;
+ virtual css::uno::Any SAL_CALL execute( const css::ucb::Command& aCommand, sal_Int32 CommandId, const css::uno::Reference< css::ucb::XCommandEnvironment >& Environment ) override ;
+ virtual void SAL_CALL abort( sal_Int32 CommandId ) override ;
+
+ // XPropertiesChangeNotifier
+ virtual void SAL_CALL addPropertiesChangeListener( const css::uno::Sequence< OUString >& PropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& Listener ) override ;
+ virtual void SAL_CALL removePropertiesChangeListener( const css::uno::Sequence< OUString >& PropertyNames, const css::uno::Reference< css::beans::XPropertiesChangeListener >& Listener ) override ;
+
+ // XPropertyContainer
+ virtual void SAL_CALL addProperty( const OUString& Name, sal_Int16 Attributes, const css::uno::Any& DefaultValue ) override ;
+ virtual void SAL_CALL removeProperty( const OUString& Name ) override ;
+
+ // XInitialization
+ virtual void SAL_CALL initialize( const css::uno::Sequence< css::uno::Any >& aArguments ) override;
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ // css::container::XChild
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override;
+ virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override;
+
+ // XRename
+ virtual void SAL_CALL rename( const OUString& newName ) override;
+
+ const ContentProperties& getContentProperties() const { return m_pImpl->m_aProps; }
+ css::uno::Reference< css::sdbc::XRow >
+ getPropertyValues( const css::uno::Sequence< css::beans::Property >& rProperties );
+
+ const css::uno::Reference< css::uno::XComponentContext >& getContext() const { return m_aContext; }
+
+ const TContentPtr& getImpl() const { return m_pImpl; }
+
+ protected:
+ virtual OUString determineContentType() const = 0;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/DatabaseDataProvider.hxx b/dbaccess/source/core/inc/DatabaseDataProvider.hxx
new file mode 100644
index 000000000..8c2029634
--- /dev/null
+++ b/dbaccess/source/core/inc/DatabaseDataProvider.hxx
@@ -0,0 +1,262 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/chart2/data/XDatabaseDataProvider.hpp>
+#include <com/sun/star/chart2/XInternalDataProvider.hpp>
+#include <com/sun/star/chart/XComplexDescriptionAccess.hpp>
+#include <com/sun/star/sdbc/XRowSet.hpp>
+#include <com/sun/star/container/XChild.hpp>
+
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/propertysetmixin.hxx>
+
+#include <connectivity/parameters.hxx>
+#include <connectivity/filtermanager.hxx>
+
+
+namespace dbaccess
+{
+
+typedef ::cppu::WeakComponentImplHelper< css::chart2::data::XDatabaseDataProvider
+ , css::container::XChild
+ , css::chart::XComplexDescriptionAccess
+ , css::lang::XServiceInfo > TDatabaseDataProvider;
+
+class DatabaseDataProvider: private ::cppu::BaseMutex,
+ public TDatabaseDataProvider,
+ public ::cppu::PropertySetMixin< css::chart2::data::XDatabaseDataProvider >
+{
+public:
+ explicit DatabaseDataProvider(css::uno::Reference< css::uno::XComponentContext > const & context);
+
+private:
+ // css::uno::XInterface:
+ virtual css::uno::Any SAL_CALL queryInterface(css::uno::Type const & type) override;
+ virtual void SAL_CALL acquire() noexcept override
+ { TDatabaseDataProvider::acquire(); }
+ virtual void SAL_CALL release() noexcept override
+ { TDatabaseDataProvider::release(); }
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // css::chart2::data::XDataProvider:
+ virtual sal_Bool SAL_CALL createDataSourcePossible(const css::uno::Sequence< css::beans::PropertyValue > & aArguments) override;
+ virtual css::uno::Reference< css::chart2::data::XDataSource > SAL_CALL createDataSource(const css::uno::Sequence< css::beans::PropertyValue > & aArguments) override;
+ virtual css::uno::Sequence< css::beans::PropertyValue > SAL_CALL detectArguments(const css::uno::Reference< css::chart2::data::XDataSource > & xDataSource) override;
+ virtual sal_Bool SAL_CALL createDataSequenceByRangeRepresentationPossible(const OUString & aRangeRepresentation) override;
+ virtual css::uno::Reference< css::chart2::data::XDataSequence > SAL_CALL createDataSequenceByRangeRepresentation(const OUString & aRangeRepresentation) override;
+
+ virtual css::uno::Reference<css::chart2::data::XDataSequence> SAL_CALL
+ createDataSequenceByValueArray(
+ const OUString& aRole, const OUString & aRangeRepresentation, const OUString& aRoleQualifier) override;
+
+ virtual css::uno::Reference< css::sheet::XRangeSelection > SAL_CALL getRangeSelection() override;
+
+ // css::chart2::data::XRangeXMLConversion:
+ virtual OUString SAL_CALL convertRangeToXML(const OUString & aRangeRepresentation) override;
+ virtual OUString SAL_CALL convertRangeFromXML(const OUString & aXMLRange) override;
+
+ // css::lang::XInitialization:
+ virtual void SAL_CALL initialize(const css::uno::Sequence< css::uno::Any > & aArguments) override;
+
+ // css::beans::XPropertySet:
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo() override;
+ virtual void SAL_CALL setPropertyValue(const OUString & aPropertyName, const css::uno::Any & aValue) override;
+ virtual css::uno::Any SAL_CALL getPropertyValue(const OUString & PropertyName) override;
+ virtual void SAL_CALL addPropertyChangeListener(const OUString & aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > & xListener) override;
+ virtual void SAL_CALL removePropertyChangeListener(const OUString & aPropertyName, const css::uno::Reference< css::beans::XPropertyChangeListener > & aListener) override;
+ virtual void SAL_CALL addVetoableChangeListener(const OUString & PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > & aListener) override;
+ virtual void SAL_CALL removeVetoableChangeListener(const OUString & PropertyName, const css::uno::Reference< css::beans::XVetoableChangeListener > & aListener) override;
+
+ // css::chart2::data::XDatabaseDataProvider:
+ virtual css::uno::Sequence< OUString > SAL_CALL getMasterFields() override;
+ virtual void SAL_CALL setMasterFields(const css::uno::Sequence< OUString > & the_value) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getDetailFields() override;
+ virtual void SAL_CALL setDetailFields(const css::uno::Sequence< OUString > & the_value) override;
+ virtual OUString SAL_CALL getCommand() override;
+ virtual void SAL_CALL setCommand(const OUString & the_value) override;
+ virtual ::sal_Int32 SAL_CALL getCommandType() override;
+ virtual void SAL_CALL setCommandType(::sal_Int32 the_value) override;
+ virtual OUString SAL_CALL getFilter() override;
+ virtual void SAL_CALL setFilter(const OUString & the_value) override;
+ virtual sal_Bool SAL_CALL getApplyFilter() override;
+ virtual void SAL_CALL setApplyFilter( sal_Bool _applyfilter ) override;
+ virtual OUString SAL_CALL getHavingClause() override;
+ virtual void SAL_CALL setHavingClause( const OUString& _havingclause ) override;
+ virtual OUString SAL_CALL getGroupBy() override;
+ virtual void SAL_CALL setGroupBy( const OUString& _groupby ) override;
+ virtual OUString SAL_CALL getOrder() override;
+ virtual void SAL_CALL setOrder( const OUString& _order ) override;
+ virtual sal_Bool SAL_CALL getEscapeProcessing() override;
+ virtual void SAL_CALL setEscapeProcessing(sal_Bool the_value) override;
+ virtual ::sal_Int32 SAL_CALL getRowLimit() override;
+ virtual void SAL_CALL setRowLimit( ::sal_Int32 _rowlimit ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getActiveConnection() override;
+ virtual void SAL_CALL setActiveConnection(const css::uno::Reference< css::sdbc::XConnection > & the_value) override;
+ virtual OUString SAL_CALL getDataSourceName() override;
+ virtual void SAL_CALL setDataSourceName( const OUString& _datasourcename ) override;
+
+ // css::sdbc::XParameters
+ virtual void SAL_CALL setNull(sal_Int32 parameterIndex, sal_Int32 sqlType) override;
+ virtual void SAL_CALL setObjectNull(sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName) override;
+ virtual void SAL_CALL setBoolean(sal_Int32 parameterIndex, sal_Bool x) override;
+ virtual void SAL_CALL setByte(sal_Int32 parameterIndex, sal_Int8 x) override;
+ virtual void SAL_CALL setShort(sal_Int32 parameterIndex, sal_Int16 x) override;
+ virtual void SAL_CALL setInt(sal_Int32 parameterIndex, sal_Int32 x) override;
+ virtual void SAL_CALL setLong(sal_Int32 parameterIndex, sal_Int64 x) override;
+ virtual void SAL_CALL setFloat(sal_Int32 parameterIndex, float x) override;
+ virtual void SAL_CALL setDouble(sal_Int32 parameterIndex, double x) override;
+ virtual void SAL_CALL setString(sal_Int32 parameterIndex, const OUString& x) override;
+ virtual void SAL_CALL setBytes(sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x) override;
+ virtual void SAL_CALL setDate(sal_Int32 parameterIndex, const css::util::Date& x) override;
+ virtual void SAL_CALL setTime(sal_Int32 parameterIndex, const css::util::Time& x) override;
+ virtual void SAL_CALL setTimestamp(sal_Int32 parameterIndex, const css::util::DateTime& x) override;
+ virtual void SAL_CALL setBinaryStream(sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream>& x, sal_Int32 length) override;
+ virtual void SAL_CALL setCharacterStream(sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream>& x, sal_Int32 length) override;
+ virtual void SAL_CALL setObject(sal_Int32 parameterIndex, const css::uno::Any& x) override;
+ virtual void SAL_CALL setObjectWithInfo(sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale) override;
+ virtual void SAL_CALL setRef(sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef>& x) override;
+ virtual void SAL_CALL setBlob(sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob>& x) override;
+ virtual void SAL_CALL setClob(sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob>& x) override;
+ virtual void SAL_CALL setArray(sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray>& x) override;
+ virtual void SAL_CALL clearParameters() override;
+
+ // css::sdbc::XRowSet
+ virtual void SAL_CALL execute() override;
+ virtual void SAL_CALL addRowSetListener(const css::uno::Reference< css::sdbc::XRowSetListener>& _rxListener) override;
+ virtual void SAL_CALL removeRowSetListener(const css::uno::Reference< css::sdbc::XRowSetListener>& _rxListener) override;
+
+ // css::sdbc::XResultSet
+ virtual sal_Bool SAL_CALL next() override;
+ virtual sal_Bool SAL_CALL isBeforeFirst() override;
+ virtual sal_Bool SAL_CALL isAfterLast() override;
+ virtual sal_Bool SAL_CALL isFirst() override;
+ virtual sal_Bool SAL_CALL isLast() override;
+ virtual void SAL_CALL beforeFirst() override;
+ virtual void SAL_CALL afterLast() override;
+ virtual sal_Bool SAL_CALL first() override;
+ virtual sal_Bool SAL_CALL last() override;
+ virtual sal_Int32 SAL_CALL getRow() override;
+ virtual sal_Bool SAL_CALL absolute(sal_Int32 row) override;
+ virtual sal_Bool SAL_CALL relative(sal_Int32 rows) override;
+ virtual sal_Bool SAL_CALL previous() override;
+ virtual void SAL_CALL refreshRow() override;
+ virtual sal_Bool SAL_CALL rowUpdated() override;
+ virtual sal_Bool SAL_CALL rowInserted() override;
+ virtual sal_Bool SAL_CALL rowDeleted() override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getStatement() override;
+
+ // container::XChild
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override;
+ virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override;
+
+ // ____ XComplexDescriptionAccess ____
+ virtual css::uno::Sequence< css::uno::Sequence< OUString > > SAL_CALL getComplexRowDescriptions() override;
+ virtual void SAL_CALL setComplexRowDescriptions( const css::uno::Sequence< css::uno::Sequence< OUString > >& aRowDescriptions ) override;
+ virtual css::uno::Sequence< css::uno::Sequence< OUString > > SAL_CALL getComplexColumnDescriptions() override;
+ virtual void SAL_CALL setComplexColumnDescriptions( const css::uno::Sequence< css::uno::Sequence< OUString > >& aColumnDescriptions ) override;
+
+ // ____ XChartDataArray (base of XComplexDescriptionAccess) ____
+ virtual css::uno::Sequence< css::uno::Sequence< double > > SAL_CALL getData() override;
+ virtual void SAL_CALL setData( const css::uno::Sequence< css::uno::Sequence< double > >& aData ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getRowDescriptions() override;
+ virtual void SAL_CALL setRowDescriptions( const css::uno::Sequence< OUString >& aRowDescriptions ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getColumnDescriptions() override;
+ virtual void SAL_CALL setColumnDescriptions( const css::uno::Sequence< OUString >& aColumnDescriptions ) override;
+
+ // ____ XChartData (base of XChartDataArray) ____
+ virtual void SAL_CALL addChartDataChangeEventListener(const css::uno::Reference< css::chart::XChartDataChangeEventListener >& aListener ) override;
+ virtual void SAL_CALL removeChartDataChangeEventListener(const css::uno::Reference< css::chart::XChartDataChangeEventListener >& aListener ) override;
+ virtual double SAL_CALL getNotANumber() override;
+ virtual sal_Bool SAL_CALL isNotANumber(double nNumber ) override;
+private:
+ DatabaseDataProvider(DatabaseDataProvider const &) = delete;
+ DatabaseDataProvider& operator =(DatabaseDataProvider const &) = delete;
+
+ virtual ~DatabaseDataProvider() override {}
+
+ // This function is called upon disposing the component,
+ // if your component needs special work when it becomes
+ // disposed, do it here.
+ virtual void SAL_CALL disposing() override;
+
+ void impl_fillRowSet_throw();
+ bool impl_fillParameters_nothrow( ::osl::ResettableMutexGuard& _rClearForNotifies);
+ void impl_fillInternalDataProvider_throw(bool _bHasCategories,const css::uno::Sequence< OUString >& i_aColumnNames);
+ void impl_invalidateParameter_nothrow();
+ css::uno::Any impl_getNumberFormatKey_nothrow(const OUString & _sRangeRepresentation) const;
+
+ template <typename T> void set( const OUString& _sProperty
+ ,const T& Value
+ ,T& _member)
+ {
+ BoundListeners l;
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if ( _member != Value )
+ {
+ prepareSet(_sProperty, css::uno::Any(_member), css::uno::Any(Value), &l);
+ _member = Value;
+ }
+ }
+ l.notify();
+ }
+
+ ::dbtools::ParameterManager m_aParameterManager;
+ ::dbtools::FilterManager m_aFilterManager;
+ std::map< OUString, css::uno::Any> m_aNumberFormats;
+
+ css::uno::Reference< css::uno::XComponentContext > m_xContext;
+ css::uno::Reference< css::sdbc::XConnection > m_xActiveConnection;
+ css::uno::Reference< css::sdbc::XRowSet > m_xRowSet;
+ css::uno::Reference< css::chart2::XInternalDataProvider > m_xInternal;
+ css::uno::Reference< css::chart::XComplexDescriptionAccess > m_xComplexDescriptionAccess;
+ css::uno::Reference< css::chart2::data::XRangeXMLConversion> m_xRangeConversion;
+ css::uno::Reference< css::task::XInteractionHandler> m_xHandler;
+ // the object doin' most of the work - an SDB-rowset
+ css::uno::Reference< css::uno::XAggregation> m_xAggregate;
+ css::uno::Reference< css::beans::XPropertySet> m_xAggregateSet;
+ css::uno::Reference< css::uno::XInterface> m_xParent;
+ css::uno::Sequence< OUString > m_MasterFields;
+ css::uno::Sequence< OUString > m_DetailFields;
+
+ OUString m_Command;
+ OUString m_DataSourceName;
+ sal_Int32 m_CommandType;
+ sal_Int32 m_RowLimit;
+ OUString m_Filter;
+ OUString m_HavingClause;
+ OUString m_Order;
+ OUString m_GroupBy;
+ bool m_EscapeProcessing;
+ bool m_ApplyFilter;
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/FilteredContainer.hxx b/dbaccess/source/core/inc/FilteredContainer.hxx
new file mode 100644
index 000000000..968f3a1d6
--- /dev/null
+++ b/dbaccess/source/core/inc/FilteredContainer.hxx
@@ -0,0 +1,136 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <sal/config.h>
+
+#include <atomic>
+#include <cstddef>
+
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+#include <connectivity/sdbcx/VCollection.hxx>
+
+namespace dbtools
+{
+ class WarningsContainer;
+}
+
+namespace dbaccess
+{
+ class IRefreshListener;
+
+ class OFilteredContainer : public ::connectivity::sdbcx::OCollection
+ {
+ private:
+ mutable bool m_bConstructed; // late ctor called
+
+ protected:
+ IRefreshListener* m_pRefreshListener;
+ std::atomic<std::size_t>& m_nInAppend;
+
+ // holds the original container which where set in construct but they can be null
+ css::uno::Reference< css::container::XNameAccess > m_xMasterContainer;
+ css::uno::WeakReference< css::sdbc::XConnection > m_xConnection;
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+
+ /** returns a string denoting the only type of tables allowed in this container, or an empty string
+ if there is no such restriction
+ */
+ virtual OUString getTableTypeRestriction() const = 0;
+
+ virtual void addMasterContainerListener(){}
+ virtual void removeMasterContainerListener(){}
+
+ // ::connectivity::sdbcx::OCollection
+ virtual void impl_refresh() override;
+
+ virtual OUString getNameForObject(const ::connectivity::sdbcx::ObjectType& _xObject) override;
+
+ /** tell the container to free all elements and all additional resources.<BR>
+ After using this method the object may be reconstructed by calling one of the <code>construct</code> methods.
+ */
+ virtual void disposing() override;
+
+ class EnsureReset
+ {
+ public:
+ EnsureReset( std::atomic<std::size_t>& _rValueLocation)
+ :m_rValue( _rValueLocation )
+ {
+ ++m_rValue;
+ }
+
+ ~EnsureReset()
+ {
+ --m_rValue;
+ }
+
+ private:
+ std::atomic<std::size_t>& m_rValue;
+ };
+
+ /** retrieve a table type filter to pass to <member scope="css::sdbc">XDatabaseMetaData::getTables</member>,
+ according to the current data source settings
+ */
+ void getAllTableTypeFilter( css::uno::Sequence< OUString >& /* [out] */ _rFilter ) const;
+
+ public:
+ /** ctor of the container. The parent has to support the <type scope="css::sdbc">XConnection</type>
+ interface.<BR>
+ @param _rParent the object which acts as parent for the container.
+ all refcounting is rerouted to this object
+ @param _rMutex the access safety object of the parent
+ @param _rTableFilter restricts the visible tables by name
+ @param _rTableTypeFilter restricts the visible tables by type
+ @see construct
+ */
+ OFilteredContainer( ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const css::uno::Reference< css::sdbc::XConnection >& _xCon,
+ bool _bCase,
+ IRefreshListener* _pRefreshListener,
+ std::atomic<std::size_t>& _nInAppend
+ );
+
+ void dispose() { disposing(); }
+
+ /** late ctor. The container will fill itself with the data got by the connection meta data, considering the
+ filters given (the connection is the parent object you passed in the ctor).
+ */
+ void construct(
+ const css::uno::Sequence< OUString >& _rTableFilter,
+ const css::uno::Sequence< OUString >& _rTableTypeFilter
+ );
+
+ /** late ctor. The container will fill itself with wrapper objects for the tables returned by the given
+ name container.
+ */
+ void construct(
+ const css::uno::Reference< css::container::XNameAccess >& _rxMasterContainer,
+ const css::uno::Sequence< OUString >& _rTableFilter,
+ const css::uno::Sequence< OUString >& _rTableTypeFilter
+ );
+
+ bool isInitialized() const { return m_bConstructed; }
+ };
+} // namespace
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/ModelImpl.hxx b/dbaccess/source/core/inc/ModelImpl.hxx
new file mode 100644
index 000000000..b6e2fe729
--- /dev/null
+++ b/dbaccess/source/core/inc/ModelImpl.hxx
@@ -0,0 +1,542 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "ContentHelper.hxx"
+#include "documentevents.hxx"
+
+#include <com/sun/star/beans/PropertyValue.hpp>
+#include <com/sun/star/beans/XPropertyBag.hpp>
+#include <com/sun/star/document/XDocumentSubStorageSupplier.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/frame/XModel.hpp>
+#include <com/sun/star/lang/XSingleServiceFactory.hpp>
+#include <com/sun/star/script/XStorageBasedLibraryContainer.hpp>
+#include <com/sun/star/sdbc/XDataSource.hpp>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+
+#include <comphelper/namedvaluecollection.hxx>
+#include <cppuhelper/weakref.hxx>
+#include <vcl/svapp.hxx>
+#include <sfx2/docmacromode.hxx>
+#include <sfx2/docstoragemodifylistener.hxx>
+#include <unotools/sharedunocomponent.hxx>
+#include <rtl/ref.hxx>
+
+namespace comphelper
+{
+ class NamedValueCollection;
+}
+
+namespace dbaccess
+{
+
+typedef std::vector< css::uno::WeakReference< css::sdbc::XConnection > > OWeakConnectionArray;
+
+struct AsciiPropertyValue
+{
+ // note: the canonic member order would be AsciiName / DefaultValue, but
+ // this crashes on unxlngi6.pro, since there's a bug which somehow results in
+ // getDefaultDataSourceSettings returning corrupted Any instances then.
+ css::uno::Any DefaultValue;
+ const char* AsciiName;
+ const css::uno::Type& ValueType;
+
+ AsciiPropertyValue()
+ :DefaultValue( )
+ ,AsciiName( nullptr )
+ ,ValueType( ::cppu::UnoType<void>::get() )
+ {
+ }
+
+ AsciiPropertyValue( const char* _pAsciiName, const css::uno::Any& _rDefaultValue )
+ :DefaultValue( _rDefaultValue )
+ ,AsciiName( _pAsciiName )
+ ,ValueType( _rDefaultValue.getValueType() )
+ {
+ OSL_ENSURE( ValueType.getTypeClass() != css::uno::TypeClass_VOID,
+ "AsciiPropertyValue::AsciiPropertyValue: NULL values not allowed here, use the other CTOR for this!" );
+ }
+ AsciiPropertyValue( const char* _pAsciiName, const css::uno::Type& _rValeType )
+ :DefaultValue()
+ ,AsciiName( _pAsciiName )
+ ,ValueType( _rValeType )
+ {
+ OSL_ENSURE( ValueType.getTypeClass() != css::uno::TypeClass_VOID,
+ "AsciiPropertyValue::AsciiPropertyValue: VOID property values not supported!" );
+ }
+};
+
+class ODatabaseContext;
+class OSharedConnectionManager;
+
+// ODatabaseModelImpl
+typedef ::utl::SharedUNOComponent< css::embed::XStorage > SharedStorage;
+
+class ODatabaseContext;
+class DocumentStorageAccess;
+class OSharedConnectionManager;
+class ODatabaseModelImpl :public ::sfx2::IMacroDocumentAccess
+ ,public ::sfx2::IModifiableDocument
+{
+public:
+ enum ObjectType
+ {
+ E_FORM = 0,
+ E_REPORT = 1,
+ E_QUERY = 2,
+ E_TABLE = 3
+ };
+
+ enum EmbeddedMacros
+ {
+ // the database document (storage) itself contains macros
+ eDocumentWideMacros,
+ // there are sub document( storage)s containing macros
+ eSubDocumentMacros,
+ // there are no known macro( storage)s
+ eNoMacros
+ };
+
+private:
+ css::uno::WeakReference< css::frame::XModel > m_xModel;
+ css::uno::WeakReference< css::sdbc::XDataSource > m_xDataSource;
+
+ rtl::Reference<DocumentStorageAccess> m_pStorageAccess;
+ std::vector< TContentPtr > m_aContainer; // one for each ObjectType
+ ::sfx2::DocumentMacroMode m_aMacroMode;
+ sal_Int16 m_nImposedMacroExecMode;
+
+ css::uno::Reference< css::script::XStorageBasedLibraryContainer > m_xBasicLibraries;
+ css::uno::Reference< css::script::XStorageBasedLibraryContainer > m_xDialogLibraries;
+
+ SharedStorage m_xDocumentStorage;
+ ::rtl::Reference< ::sfx2::DocumentStorageModifyListener > m_pStorageModifyListener;
+ ODatabaseContext& m_rDBContext;
+ DocumentEventsData m_aDocumentEvents;
+
+ ::comphelper::NamedValueCollection m_aMediaDescriptor;
+ /// the URL the document was loaded from
+ OUString m_sDocFileLocation;
+
+ oslInterlockedCount m_refCount;
+
+ /// do we have any object (forms/reports) which contains macros?
+ ::std::optional< EmbeddedMacros > m_aEmbeddedMacros;
+
+ /// true if setting the Modified flag of the document is currently locked
+ bool m_bModificationLock;
+
+ /// true if and only if a database document existed previously (though meanwhile disposed), and was already initialized
+ bool m_bDocumentInitialized;
+
+ /** the URL which the document should report as its URL
+
+ This might differ from ->m_sDocFileLocation in case the document was loaded
+ as part of a crash recovery process. In this case, ->m_sDocFileLocation points to
+ the temporary file where the DB had been saved to, after a crash.
+ ->m_sDocumentURL then is the URL of the document which actually had
+ been recovered.
+ */
+ OUString m_sDocumentURL;
+
+ SignatureState m_nScriptingSignatureState;
+
+public:
+ OWeakConnectionArray m_aConnections;
+ const css::uno::Reference< css::uno::XComponentContext > m_aContext;
+
+public:
+ css::uno::WeakReference< css::container::XNameAccess > m_xCommandDefinitions;
+ css::uno::WeakReference< css::container::XNameAccess > m_xTableDefinitions;
+
+ css::uno::Reference< css::util::XNumberFormatsSupplier >
+ m_xNumberFormatsSupplier;
+ OUString m_sConnectURL;
+ OUString m_sName; // transient, our creator has to tell us the title
+ OUString m_sUser;
+ OUString m_aPassword; // transient !
+ OUString m_sFailedPassword;
+ css::uno::Sequence< css::beans::PropertyValue>
+ m_aLayoutInformation;
+ sal_Int32 m_nLoginTimeout;
+ bool m_bReadOnly : 1;
+ bool m_bPasswordRequired : 1;
+ bool m_bSuppressVersionColumns : 1;
+ bool m_bModified : 1;
+ bool m_bDocumentReadOnly : 1;
+ bool m_bMacroCallsSeenWhileLoading : 1;
+ css::uno::Reference< css::beans::XPropertyBag >
+ m_xSettings;
+ css::uno::Sequence< OUString > m_aTableFilter;
+ css::uno::Sequence< OUString > m_aTableTypeFilter;
+ OSharedConnectionManager* m_pSharedConnectionManager;
+ css::uno::Reference< css::lang::XEventListener >
+ m_xSharedConnectionManager;
+ css::uno::Reference<css::awt::XWindow>
+ m_xDialogParent;
+ sal_uInt16 m_nControllerLockCount;
+
+ void reset();
+
+ /** determines whether the database document has an embedded data storage
+ */
+ bool isEmbeddedDatabase() const { return m_sConnectURL.startsWith("sdbc:embedded:"); }
+
+ /** stores the embedded storage ("database")
+
+ @param _bPreventRootCommits
+ Normally, committing the embedded storage results in also committing the root storage
+ - this is an automatism for data safety reasons.
+ If you pass <TRUE/> here, committing the root storage is prevented for this particular
+ call.
+ @return <TRUE/> if the storage could be committed, otherwise <FALSE/>
+ */
+ bool commitEmbeddedStorage( bool _bPreventRootCommits = false );
+
+ /// commits all sub storages
+ void commitStorages();
+
+ ODatabaseModelImpl(
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ ODatabaseContext& _pDBContext
+ );
+ virtual ~ODatabaseModelImpl();
+
+ ODatabaseModelImpl(
+ const OUString& _rRegistrationName,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxContext,
+ ODatabaseContext& _rDBContext
+ );
+
+ // XEventListener
+ /// @throws css::uno::RuntimeException
+ void disposing( const css::lang::EventObject& Source );
+
+ void setModified( bool bModified );
+
+ void dispose();
+
+ const OUString& getURL() const { return m_sDocumentURL; }
+ const OUString& getDocFileLocation() const { return m_sDocFileLocation; }
+
+ css::uno::Reference< css::embed::XStorage >
+ getStorage( const ObjectType _eType );
+
+// helper
+ const css::uno::Reference< css::util::XNumberFormatsSupplier >&
+ getNumberFormatsSupplier();
+
+ DocumentEventsData&
+ getDocumentEvents() { return m_aDocumentEvents; }
+
+ const ::comphelper::NamedValueCollection&
+ getMediaDescriptor() const { return m_aMediaDescriptor; }
+
+ void setResource(
+ const OUString& _rURL,
+ const css::uno::Sequence< css::beans::PropertyValue >& _rArgs
+ );
+ void setDocFileLocation(
+ const OUString& i_rLoadedFrom
+ );
+
+ static ::comphelper::NamedValueCollection
+ stripLoadArguments( const ::comphelper::NamedValueCollection& _rArguments );
+
+// other stuff
+
+ // disposes all elements in m_aStorages, and clears it
+ void disposeStorages();
+
+ /// creates a ->css::embed::StorageFactory
+ css::uno::Reference< css::lang::XSingleServiceFactory >
+ createStorageFactory() const;
+
+ /// commits our storage
+ void commitRootStorage();
+
+ /// commits a given storage if it's not readonly, ignoring (but asserting) all errors
+ bool commitStorageIfWriteable_ignoreErrors(
+ const css::uno::Reference< css::embed::XStorage >& _rxStorage
+ );
+
+ void clearConnections();
+
+ css::uno::Reference< css::embed::XStorage > const & getOrCreateRootStorage();
+ css::uno::Reference< css::embed::XStorage > const & getRootStorage() const { return m_xDocumentStorage.getTyped(); }
+ void resetRootStorage() { impl_switchToStorage_throw( nullptr ); }
+
+ /** returns the data source. If it doesn't exist it will be created
+ */
+ css::uno::Reference< css::sdbc::XDataSource> getOrCreateDataSource();
+
+ /** returns the model, if there already exists one
+ */
+ css::uno::Reference< css::frame::XModel > getModel_noCreate() const;
+
+ /** returns a new ->ODatabaseDocument
+
+ @precond
+ No ->ODatabaseDocument exists so far
+
+ @seealso
+ getModel_noCreate
+ */
+ css::uno::Reference< css::frame::XModel > createNewModel_deliverOwnership();
+
+ struct ResetModelAccess { friend class ODatabaseDocument; private: ResetModelAccess() { } };
+
+ /** resets the model to NULL
+
+ Only to be called when the model is being disposed
+ */
+ void modelIsDisposing( const bool _wasInitialized, ResetModelAccess );
+
+ bool hadInitializedDocument() const { return m_bDocumentInitialized; }
+
+ DocumentStorageAccess*
+ getDocumentStorageAccess();
+
+ css::uno::Reference< css::document::XDocumentSubStorageSupplier >
+ getDocumentSubStorageSupplier();
+
+ void acquire();
+
+ void release();
+
+ /// returns all known data source settings, including their default values
+ static const AsciiPropertyValue* getDefaultDataSourceSettings();
+
+ /** retrieves the requested container of objects (forms/reports/tables/queries)
+ */
+ TContentPtr& getObjectContainer( const ObjectType _eType );
+
+ /** returns the name of the storage which is used to stored objects of the given type, if applicable
+ */
+ static OUString
+ getObjectContainerStorageName( const ObjectType _eType );
+
+ /** determines whether a given object storage contains macros
+ */
+ static bool objectHasMacros(
+ const css::uno::Reference< css::embed::XStorage >& _rxContainerStorage,
+ const OUString& _rPersistentName
+ );
+
+ /** determines which kind of embedded macros are present in the document
+ */
+ EmbeddedMacros determineEmbeddedMacros();
+
+ /** checks our document's macro execution mode, using the interaction handler as supplied with our
+ load arguments
+ */
+ bool checkMacrosOnLoading();
+
+ /** adjusts our document's macro execution mode, without using any UI, assuming the user
+ would reject execution of macros, if she would have been asked.
+
+ If checkMacrosOnLoading has been called before (and thus the macro execution mode
+ is already adjusted), then the current execution mode is simply returned.
+
+ @return
+ whether or not macro execution is allowed
+ */
+ bool adjustMacroMode_AutoReject();
+
+ /** resets our macro execute mode, so next time the checkMacrosOnLoading is called, it will
+ behave as if it has never been called before
+ */
+ void resetMacroExecutionMode();
+
+ /** ensures that ->m_xBasicLibraries resp. m_xDialogLibraries exists
+
+ @return
+ the requested library container. Is never <NULL/>.
+
+ @throws RuntimeException
+ if something does wrong, which indicates a server error in the installation
+ */
+ css::uno::Reference< css::script::XStorageBasedLibraryContainer >
+ getLibraryContainer( bool _bScript );
+
+ /** lets our library containers store themself into the given root storage
+ */
+ void storeLibraryContainersTo( const css::uno::Reference< css::embed::XStorage >& _rxToRootStorage );
+
+ /** rebases the document to the given storage
+
+ No actual committing, copying, saving, whatsoever happens. The storage is just remembered as the documents
+ new storage, nothing more.
+
+ @throws css::lang::IllegalArgumentException
+ if the given storage is <NULL/>
+ @throws css::lang::RuntimeException
+ if any of the invoked operations does so
+ */
+ css::uno::Reference< css::embed::XStorage >
+ switchToStorage(
+ const css::uno::Reference< css::embed::XStorage >& _rxNewRootStorage
+ );
+
+ /** returns the macro mode imposed by an external instance, which passed it to attachResource
+ */
+ sal_Int16 getImposedMacroExecMode() const
+ {
+ return m_nImposedMacroExecMode;
+ }
+ void setImposedMacroExecMode( const sal_Int16 _nMacroMode )
+ {
+ m_nImposedMacroExecMode = _nMacroMode;
+ }
+
+public:
+ // IMacroDocumentAccess overridables
+ virtual sal_Int16 getCurrentMacroExecMode() const override;
+ virtual void setCurrentMacroExecMode( sal_uInt16 ) override;
+ virtual OUString getDocumentLocation() const override;
+ virtual bool documentStorageHasMacros() const override;
+ virtual bool macroCallsSeenWhileLoading() const override;
+ virtual css::uno::Reference< css::document::XEmbeddedScripts > getEmbeddedDocumentScripts() const override;
+ virtual SignatureState getScriptingSignatureState() override;
+ virtual bool hasTrustedScriptingSignature( bool bAllowUIToAddAuthor ) override;
+
+ // IModifiableDocument
+ virtual void storageIsModified() override;
+
+ // don't use directly, use the ModifyLock class instead
+ void lockModify() { m_bModificationLock = true; }
+ void unlockModify() { m_bModificationLock = false; }
+ bool isModifyLocked() const { return m_bModificationLock; }
+
+ weld::Window* GetFrameWeld();
+
+private:
+ void impl_construct_nothrow();
+ css::uno::Reference< css::embed::XStorage > const &
+ impl_switchToStorage_throw( const css::uno::Reference< css::embed::XStorage >& _rxNewRootStorage );
+
+ /** switches to the given document URL, which denotes the logical URL of the document, not necessarily the
+ URL where the doc was loaded/recovered from
+ */
+ void impl_switchToLogicalURL(
+ const OUString& i_rDocumentURL
+ );
+
+};
+
+/** a small base class for UNO components whose functionality depends on an ODatabaseModelImpl
+*/
+class ModelDependentComponent
+{
+protected:
+ ::rtl::Reference< ODatabaseModelImpl > m_pImpl;
+ ::osl::Mutex m_aMutex; // only use this to init WeakComponentImplHelper
+
+protected:
+ explicit ModelDependentComponent( const ::rtl::Reference< ODatabaseModelImpl >& _model );
+ virtual ~ModelDependentComponent();
+
+ /** returns the component itself
+ */
+ virtual css::uno::Reference< css::uno::XInterface > getThis() const = 0;
+
+ ::osl::Mutex& getMutex()
+ {
+ return m_aMutex;
+ }
+
+public:
+ /// checks whether the component is already disposed, throws a DisposedException if so
+ void checkDisposed() const
+ {
+ if ( !m_pImpl.is() )
+ throw css::lang::DisposedException( "Component is already disposed.", getThis() );
+ }
+
+ void lockModify()
+ {
+ m_pImpl->lockModify();
+ }
+
+ void unlockModify()
+ {
+ m_pImpl->unlockModify();
+ }
+};
+
+class ModifyLock
+{
+public:
+ explicit ModifyLock( ModelDependentComponent& _component )
+ :m_rComponent( _component )
+ {
+ m_rComponent.lockModify();
+ }
+
+ ~ModifyLock()
+ {
+ m_rComponent.unlockModify();
+ }
+
+private:
+ ModelDependentComponent& m_rComponent;
+};
+
+/** a guard for public methods of objects dependent on an ODatabaseModelImpl instance
+
+ Just put this guard onto the stack at the beginning of your method. Don't bother yourself
+ with a MutexGuard, checks for being disposed, and the like.
+*/
+class ModelMethodGuard
+{
+private:
+ // to avoid deadlocks, lock SolarMutex
+ SolarMutexResettableGuard m_SolarGuard;
+
+public:
+ /** constructs the guard
+
+ @param _component
+ the component whose functionality depends on an ODatabaseModelImpl instance
+
+ @throws css::lang::DisposedException
+ If the given component is already disposed
+ */
+ explicit ModelMethodGuard( const ModelDependentComponent& _component )
+ {
+ _component.checkDisposed();
+ }
+
+ void clear()
+ {
+ // note: this only releases *once* so may still be locked
+ m_SolarGuard.clear();
+ }
+
+ void reset()
+ {
+ m_SolarGuard.reset();
+ }
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/PropertyForward.hxx b/dbaccess/source/core/inc/PropertyForward.hxx
new file mode 100644
index 000000000..b8e602fc0
--- /dev/null
+++ b/dbaccess/source/core/inc/PropertyForward.hxx
@@ -0,0 +1,69 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/beans/XPropertySetInfo.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <cppuhelper/implbase.hxx>
+#include <cppuhelper/basemutex.hxx>
+
+#include <vector>
+
+namespace dbaccess
+{
+
+ // OPropertyForward
+ typedef ::cppu::WeakImplHelper< css::beans::XPropertyChangeListener
+ > OPropertyForward_Base;
+ class OPropertyForward :public ::cppu::BaseMutex
+ ,public OPropertyForward_Base
+ {
+ css::uno::Reference< css::beans::XPropertySet > m_xSource;
+ css::uno::Reference< css::beans::XPropertySet > m_xDest;
+ css::uno::Reference< css::beans::XPropertySetInfo > m_xDestInfo;
+ css::uno::Reference< css::container::XNameAccess > m_xDestContainer;
+ OUString m_sName;
+ bool m_bInInsert;
+
+ protected:
+ virtual ~OPropertyForward() override;
+
+ public:
+ OPropertyForward( const css::uno::Reference< css::beans::XPropertySet>& _xSource,
+ const css::uno::Reference< css::container::XNameAccess>& _xDestContainer,
+ const OUString& _sName,
+ const std::vector< OUString >& _aPropertyList
+ );
+
+ // css::beans::XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+
+ // css::lang::XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& _rSource ) override;
+
+ void setName( const OUString& _sName ) { m_sName = _sName; }
+ void setDefinition( const css::uno::Reference< css::beans::XPropertySet >& _xDest);
+ const css::uno::Reference< css::beans::XPropertySet >& getDefinition() const { return m_xDest; }
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/RefreshListener.hxx b/dbaccess/source/core/inc/RefreshListener.hxx
new file mode 100644
index 000000000..03836c308
--- /dev/null
+++ b/dbaccess/source/core/inc/RefreshListener.hxx
@@ -0,0 +1,42 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Reference.h>
+
+namespace com::sun::star::container { class XNameAccess; }
+
+
+namespace dbaccess
+{
+
+ // IRefreshListener
+ class SAL_NO_VTABLE IRefreshListener
+ {
+ public:
+ virtual void refresh(const css::uno::Reference< css::container::XNameAccess >& _rToBeRefreshed) = 0;
+
+ protected:
+ ~IRefreshListener() {}
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/SingleSelectQueryComposer.hxx b/dbaccess/source/core/inc/SingleSelectQueryComposer.hxx
new file mode 100644
index 000000000..a0edfd195
--- /dev/null
+++ b/dbaccess/source/core/inc/SingleSelectQueryComposer.hxx
@@ -0,0 +1,263 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/script/XTypeConverter.hpp>
+#include <cppuhelper/implbase5.hxx>
+#include <connectivity/sqliterator.hxx>
+#include <connectivity/sqlparse.hxx>
+#include <apitools.hxx>
+#include <comphelper/broadcasthelper.hxx>
+#include <comphelper/uno3.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/propertycontainer.hxx>
+#include <svx/ParseContext.hxx>
+
+namespace com::sun::star::util {
+ class XNumberFormatsSupplier;
+ class XNumberFormatter;
+}
+
+namespace dbaccess
+{
+ typedef ::cppu::ImplHelper5< css::sdb::XSingleSelectQueryComposer,
+ css::sdb::XParametersSupplier,
+ css::sdbcx::XColumnsSupplier,
+ css::sdbcx::XTablesSupplier,
+ css::lang::XServiceInfo > OSingleSelectQueryComposer_BASE;
+
+ class OPrivateColumns;
+ class OPrivateTables;
+
+ class OSingleSelectQueryComposer : public ::comphelper::OMutexAndBroadcastHelper
+ ,public OSubComponent
+ ,public ::comphelper::OPropertyContainer
+ ,public ::comphelper::OPropertyArrayUsageHelper < OSingleSelectQueryComposer >
+ ,public OSingleSelectQueryComposer_BASE
+ {
+ enum SQLPart
+ {
+ Where = 0, // the 0 is important, as it will be used as index into arrays
+ Group,
+ Having,
+ Order,
+
+ SQLPartCount
+ };
+ static void incSQLPart( SQLPart& e ) { e = static_cast<SQLPart>(1 + static_cast<size_t>(e)); }
+ enum EColumnType
+ {
+ SelectColumns = 0,
+ GroupByColumns = 1,
+ OrderColumns = 2,
+ ParameterColumns = 3
+ };
+ typedef std::function<const ::connectivity::OSQLParseNode*(::connectivity::OSQLParseTreeIterator *)>
+ TGetParseNode;
+ ::svxform::OSystemParseContext m_aParseContext;
+ ::connectivity::OSQLParser m_aSqlParser;
+ ::connectivity::OSQLParseTreeIterator m_aSqlIterator; // the iterator for the complete statement
+ ::connectivity::OSQLParseTreeIterator m_aAdditiveIterator; // the iterator for the "additive statement" (means without the clauses of the elementary statement)
+ std::vector<std::unique_ptr<OPrivateColumns>>
+ m_aColumnsCollection; // used for columns and parameters of old queries
+ std::vector<std::unique_ptr<OPrivateTables>>
+ m_aTablesCollection;
+
+ std::vector< OUString > m_aElementaryParts; // the filter/groupby/having/order of the elementary statement
+
+ css::uno::Reference< css::sdbc::XConnection> m_xConnection;
+ css::uno::Reference< css::sdbc::XDatabaseMetaData> m_xMetaData;
+ css::uno::Reference< css::container::XNameAccess> m_xConnectionTables;
+ css::uno::Reference< css::container::XNameAccess> m_xConnectionQueries;
+ css::uno::Reference< css::util::XNumberFormatsSupplier > m_xNumberFormatsSupplier;
+ css::uno::Reference< css::uno::XComponentContext> m_aContext;
+ css::uno::Reference< css::script::XTypeConverter > m_xTypeConverter;
+
+ std::vector<std::unique_ptr<OPrivateColumns>> m_aCurrentColumns;
+ std::unique_ptr<OPrivateTables> m_pTables; // currently used tables
+
+ OUString m_aPureSelectSQL; // the pure select statement, without filter/order/groupby/having
+ OUString m_sDecimalSep;
+ OUString m_sCommand;
+ css::lang::Locale m_aLocale;
+ sal_Int32 m_nBoolCompareMode; // how to compare bool values
+ sal_Int32 m_nCommandType;
+
+ // <properties>
+ OUString m_sOriginal;
+ // </properties>
+
+
+ bool setORCriteria(::connectivity::OSQLParseNode const * pCondition, ::connectivity::OSQLParseTreeIterator& _rIterator,
+ std::vector< std::vector < css::beans::PropertyValue > >& rFilters, const css::uno::Reference< css::util::XNumberFormatter > & xFormatter) const;
+ bool setANDCriteria(::connectivity::OSQLParseNode const * pCondition, ::connectivity::OSQLParseTreeIterator& _rIterator,
+ std::vector < css::beans::PropertyValue > & rFilters, const css::uno::Reference< css::util::XNumberFormatter > & xFormatter) const;
+ bool setLikePredicate(::connectivity::OSQLParseNode const * pCondition, ::connectivity::OSQLParseTreeIterator const & _rIterator,
+ std::vector < css::beans::PropertyValue > & rFilters, const css::uno::Reference< css::util::XNumberFormatter > & xFormatter) const;
+ bool setComparisonPredicate(::connectivity::OSQLParseNode const * pCondition, ::connectivity::OSQLParseTreeIterator const & _rIterator,
+ std::vector < css::beans::PropertyValue > & rFilters, const css::uno::Reference< css::util::XNumberFormatter > & xFormatter) const;
+
+ static OUString getColumnName(::connectivity::OSQLParseNode const * pColumnRef, ::connectivity::OSQLParseTreeIterator const & _rIterator);
+ OUString getTableAlias(const css::uno::Reference< css::beans::XPropertySet >& column ) const;
+ static sal_Int32 getPredicateType(::connectivity::OSQLParseNode const * _pPredicate);
+ // clears all Columns,Parameters and tables and insert it to their vectors
+ void clearCurrentCollections();
+ // clears the columns collection given by EColumnType
+ void clearColumns( const EColumnType _eType );
+
+ /** retrieves a particular part of a statement
+ @param _rIterator
+ the iterator to use.
+ */
+ OUString getStatementPart( TGetParseNode const & _aGetFunctor, ::connectivity::OSQLParseTreeIterator& _rIterator );
+ void setQuery_Impl( const OUString& command );
+
+ void setConditionByColumn( const css::uno::Reference< css::beans::XPropertySet >& column
+ , bool andCriteria
+ , std::function<bool(OSingleSelectQueryComposer *, const OUString&)> const & _aSetFunctor
+ ,sal_Int32 filterOperator);
+
+ /** getStructuredCondition returns the structured condition for the where or having clause
+ @param _aGetFunctor
+ A member function to get the correct parse node.
+
+ @return
+ The structured filter
+ */
+ css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > >
+ getStructuredCondition( TGetParseNode const & _aGetFunctor );
+
+ css::uno::Reference< css::container::XIndexAccess >
+ setCurrentColumns( EColumnType _eType, const ::rtl::Reference< ::connectivity::OSQLColumns >& _rCols );
+
+ //helper methods for mem_fun_t
+ bool implSetFilter(const OUString& _sFilter) { setFilter(_sFilter); return true;}
+ bool implSetHavingClause(const OUString& _sFilter) { setHavingClause(_sFilter); return true;}
+
+ /** returns the part of the select statement
+ @param _ePart
+ Which part should be returned.
+ @param _bWithKeyword
+ If <TRUE/> the keyword will be added too. Otherwise not.
+ @param _rIterator
+ The iterator to use.
+
+ @return
+ The part of the select statement.
+ */
+ OUString getSQLPart( SQLPart _ePart, ::connectivity::OSQLParseTreeIterator& _rIterator, bool _bWithKeyword );
+
+ /** retrieves the keyword for the given SQLPart
+ */
+ static OUString getKeyword( SQLPart _ePart );
+
+ /** sets a single "additive" clause, means a filter/groupby/having/order clause
+ */
+ void setSingleAdditiveClause( SQLPart _ePart, const OUString& _rClause );
+
+ /** composes a statement from m_aPureSelectSQL and the 4 usual clauses
+ */
+ OUString composeStatementFromParts( const std::vector< OUString >& _rParts );
+
+ /** return the name of the column in the *source* *table*.
+
+ That is, for (SELECT a AS b FROM t), it returns A or "t"."A", as appropriate.
+
+ Use e.g. for WHERE, GROUP BY and HAVING clauses.
+
+ @param bGroupBy: for GROUP BY clause? In that case, throw exception if trying to use an unrelated column and the database does not support that.
+ */
+ OUString impl_getColumnRealName_throw(const css::uno::Reference< css::beans::XPropertySet >& column, bool bGroupBy);
+
+ /** return the name of the column in the *query* for ORDER BY clause.
+
+ That is, for (SELECT a AS b FROM t), it returns "b"
+
+ Throws exception if trying to use an unrelated column and the database does not support that.
+ */
+ OUString impl_getColumnNameOrderBy_throw(const css::uno::Reference< css::beans::XPropertySet >& column);
+
+ protected:
+ virtual ~OSingleSelectQueryComposer() override;
+ public:
+
+ OSingleSelectQueryComposer( const css::uno::Reference< css::container::XNameAccess>& _xTableSupplier,
+ const css::uno::Reference< css::sdbc::XConnection>& _xConnection,
+ const css::uno::Reference< css::uno::XComponentContext>& _rContext);
+
+
+ void SAL_CALL disposing() override;
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+ // css::uno::XInterface
+ DECLARE_XINTERFACE( )
+
+ // XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ virtual css::uno::Reference< css::beans::XPropertySetInfo> SAL_CALL getPropertySetInfo() override;
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+
+
+ // css::sdb::XSingleSelectQueryComposer
+ virtual OUString SAL_CALL getElementaryQuery() override;
+ virtual void SAL_CALL setElementaryQuery( const OUString& _rElementary ) override;
+ virtual void SAL_CALL setFilter( const OUString& filter ) override;
+ virtual void SAL_CALL setStructuredFilter( const css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > >& filter ) override;
+ virtual void SAL_CALL appendFilterByColumn( const css::uno::Reference< css::beans::XPropertySet >& column, sal_Bool andCriteria,sal_Int32 filterOperator ) override;
+ virtual void SAL_CALL appendGroupByColumn( const css::uno::Reference< css::beans::XPropertySet >& column ) override;
+ virtual void SAL_CALL setGroup( const OUString& group ) override;
+ virtual void SAL_CALL setHavingClause( const OUString& filter ) override;
+ virtual void SAL_CALL setStructuredHavingClause( const css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > >& filter ) override;
+ virtual void SAL_CALL appendHavingClauseByColumn( const css::uno::Reference< css::beans::XPropertySet >& column, sal_Bool andCriteria,sal_Int32 filterOperator ) override;
+ virtual void SAL_CALL appendOrderByColumn( const css::uno::Reference< css::beans::XPropertySet >& column, sal_Bool ascending ) override;
+ virtual void SAL_CALL setOrder( const OUString& order ) override;
+
+ // XSingleSelectQueryAnalyzer
+ virtual OUString SAL_CALL getQuery( ) override;
+ virtual void SAL_CALL setQuery( const OUString& command ) override;
+ virtual void SAL_CALL setCommand( const OUString& command,sal_Int32 CommandType ) override;
+ virtual OUString SAL_CALL getFilter( ) override;
+ virtual css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > SAL_CALL getStructuredFilter( ) override;
+ virtual OUString SAL_CALL getGroup( ) override;
+ virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getGroupColumns( ) override;
+ virtual OUString SAL_CALL getHavingClause( ) override;
+ virtual css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > SAL_CALL getStructuredHavingClause( ) override;
+ virtual OUString SAL_CALL getOrder( ) override;
+ virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getOrderColumns( ) override;
+ virtual OUString SAL_CALL getQueryWithSubstitution( ) override;
+
+ // XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+ // XTablesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables( ) override;
+ // XParametersSupplier
+ virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getParameters( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/TableDeco.hxx b/dbaccess/source/core/inc/TableDeco.hxx
new file mode 100644
index 000000000..e40fac802
--- /dev/null
+++ b/dbaccess/source/core/inc/TableDeco.hxx
@@ -0,0 +1,164 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <memory>
+#include <com/sun/star/util/XNumberFormatsSupplier.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XIndexesSupplier.hpp>
+#include <com/sun/star/sdbcx/XKeysSupplier.hpp>
+#include <com/sun/star/sdbcx/XRename.hpp>
+#include <com/sun/star/sdbcx/XAlterTable.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <cppuhelper/compbase.hxx>
+#include "datasettings.hxx"
+#include "column.hxx"
+
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <comphelper/IdPropArrayHelper.hxx>
+
+namespace dbaccess
+{
+ typedef ::cppu::WeakComponentImplHelper< css::sdbcx::XColumnsSupplier,
+ css::sdbcx::XKeysSupplier,
+ css::container::XNamed,
+ css::lang::XServiceInfo,
+ css::sdbcx::XDataDescriptorFactory,
+ css::sdbcx::XIndexesSupplier,
+ css::sdbcx::XRename,
+ css::lang::XUnoTunnel,
+ css::sdbcx::XAlterTable> OTableDescriptor_BASE;
+ // OTables
+ class ODBTableDecorator;
+ typedef ::comphelper::OIdPropertyArrayUsageHelper< ODBTableDecorator > ODBTableDecorator_PROP;
+
+ class ODBTableDecorator :public cppu::BaseMutex
+ ,public OTableDescriptor_BASE
+ ,public ODataSettings //ODataSettings_Base
+ ,public IColumnFactory
+ ,public ::connectivity::sdbcx::IRefreshableColumns
+ ,public ODBTableDecorator_PROP
+ {
+ void fillPrivileges() const;
+ protected:
+ css::uno::Reference< css::container::XContainerListener > m_xColumnMediator;
+ css::uno::Reference< css::sdbcx::XColumnsSupplier > m_xTable;
+ css::uno::Reference< css::container::XNameAccess > m_xColumnDefinitions;
+ css::uno::Reference< css::sdbc::XConnection > m_xConnection;
+ css::uno::Reference< css::sdbc::XDatabaseMetaData > m_xMetaData;
+ css::uno::Reference< css::util::XNumberFormatsSupplier > m_xNumberFormats;
+
+ // <properties>
+ mutable sal_Int32 m_nPrivileges;
+ // </properties>
+ // note: this thing uses the ref-count of "this", see OCollection::acquire()!
+ std::unique_ptr<::connectivity::sdbcx::OCollection> m_pColumns;
+
+ // IColumnFactory
+ virtual rtl::Reference<OColumn> createColumn(const OUString& _rName) const override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createColumnDescriptor() override;
+ virtual void columnAppended( const css::uno::Reference< css::beans::XPropertySet >& _rxSourceDescriptor ) override;
+ virtual void columnDropped(const OUString& _sName) override;
+
+ virtual void refreshColumns() override;
+
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 _nId) const override;
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ // OPropertySetHelper
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL getFastPropertyValue(css::uno::Any& rValue, sal_Int32 nHandle) const override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+
+ virtual ~ODBTableDecorator() override;
+ public:
+ /** constructs a wrapper supporting the com.sun.star.sdb.Table service.
+
+ @param _rxConn
+ the connection the table belongs to. Must not be <NULL/>
+ @param _rxTable
+ the table from the driver can be <NULL/>
+ @throws css::sdbc::SQLException
+ */
+ ODBTableDecorator(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConn,
+ const css::uno::Reference< css::sdbcx::XColumnsSupplier >& _rxTable,
+ const css::uno::Reference< css::util::XNumberFormatsSupplier >& _rxNumberFormats,
+ const css::uno::Reference< css::container::XNameAccess >& _rxColumnDefinitions
+ );
+
+ // ODescriptor
+ void construct();
+
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // css::lang::XServiceInfo
+ DECLARE_SERVICE_INFO();
+ // XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+ // css::sdbcx::XRename,
+ virtual void SAL_CALL rename( const OUString& _rNewName ) override;
+
+ // css::sdbcx::XAlterTable,
+ virtual void SAL_CALL alterColumnByName( const OUString& _rName, const css::uno::Reference< css::beans::XPropertySet >& _rxDescriptor ) override;
+ virtual void SAL_CALL alterColumnByIndex( sal_Int32 _nIndex, const css::uno::Reference< css::beans::XPropertySet >& _rxDescriptor ) override;
+
+ // XNamed
+ virtual OUString SAL_CALL getName() override;
+ virtual void SAL_CALL setName( const OUString& aName ) override;
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ // XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+ // XKeysSupplier
+ virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getKeys( ) override;
+ // XIndexesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getIndexes( ) override;
+ // XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+
+ protected:
+ using ODataSettings::getFastPropertyValue;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/View.hxx b/dbaccess/source/core/inc/View.hxx
new file mode 100644
index 000000000..d3889ff56
--- /dev/null
+++ b/dbaccess/source/core/inc/View.hxx
@@ -0,0 +1,71 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <connectivity/sdbcx/VView.hxx>
+
+#include <com/sun/star/sdbcx/XAlterView.hpp>
+#include <com/sun/star/sdb/tools/XViewAccess.hpp>
+
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase1.hxx>
+
+namespace dbaccess
+{
+
+ // View
+ typedef ::connectivity::sdbcx::OView View_Base;
+ typedef ::cppu::ImplHelper1< css::sdbcx::XAlterView > View_IBASE;
+ class View :public View_Base
+ ,public View_IBASE
+ {
+ public:
+ View(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ bool _bCaseSensitive,
+ const OUString& _rCatalogName,
+ const OUString& _rSchemaName,
+ const OUString& _rName
+ );
+
+ // UNO
+ DECLARE_XINTERFACE()
+ DECLARE_XTYPEPROVIDER()
+
+ // XAlterView
+ virtual void SAL_CALL alterCommand( const OUString& NewCommand ) override;
+
+ protected:
+ virtual ~View() override;
+
+ protected:
+ // OPropertyContainer
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& _rValue, sal_Int32 _nHandle ) const override;
+
+ private:
+ css::uno::Reference< css::sdb::tools::XViewAccess> m_xViewAccess;
+ sal_Int32 m_nCommandHandle;
+ private:
+ using View_Base::getFastPropertyValue;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/bookmarkcontainer.hxx b/dbaccess/source/core/inc/bookmarkcontainer.hxx
new file mode 100644
index 000000000..464192542
--- /dev/null
+++ b/dbaccess/source/core/inc/bookmarkcontainer.hxx
@@ -0,0 +1,148 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+#include <vector>
+
+#include <comphelper/interfacecontainer3.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <osl/mutex.hxx>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+namespace dbaccess
+{
+
+// OBookmarkContainer - base class of collections of database definition
+// documents
+typedef ::cppu::WeakImplHelper<
+ css::container::XIndexAccess
+ , css::container::XNameContainer
+ , css::container::XEnumerationAccess
+ , css::container::XContainer
+ , css::lang::XServiceInfo
+ , css::container::XChild
+ > OBookmarkContainer_Base;
+
+class OBookmarkContainer final
+ :public OBookmarkContainer_Base
+{
+ typedef std::map<OUString, OUString> MapString2String;
+ typedef std::vector<MapString2String::iterator> MapIteratorVector;
+
+ MapString2String m_aBookmarks; // the bookmarks itself
+ MapIteratorVector m_aBookmarksIndexed; // for index access to the
+
+ ::cppu::OWeakObject& m_rParent; // for the ref counting
+ ::comphelper::OInterfaceContainerHelper3<css::container::XContainerListener>
+ m_aContainerListeners;
+ ::osl::Mutex& m_rMutex;
+
+public:
+ /** constructs the container.<BR>
+ after the construction of the object the creator has to call <code>initialize</code>.
+ @param _rParent the parent object which is used for ref counting
+ @param _rMutex the parent's mutex object for access safety
+ */
+ OBookmarkContainer(
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex
+ );
+
+ /** looks like the dtor ...
+ */
+ virtual ~OBookmarkContainer() override;
+
+// css::uno::XInterface
+ virtual void SAL_CALL acquire( ) noexcept override;
+ virtual void SAL_CALL release( ) noexcept override;
+
+// css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+// css::container::XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+// css::container::XEnumerationAccess
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration( ) override;
+
+// css::container::XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount( ) override;
+ virtual css::uno::Any SAL_CALL getByIndex( sal_Int32 _nIndex ) override;
+
+// css::container::XNameContainer
+ virtual void SAL_CALL insertByName( const OUString& _rName, const css::uno::Any& aElement ) override;
+ virtual void SAL_CALL removeByName( const OUString& _rName ) override;
+
+// css::container::XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& _rName, const css::uno::Any& aElement ) override;
+
+// css::container::XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+// css::container::XContainer
+ virtual void SAL_CALL addContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override;
+ virtual void SAL_CALL removeContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override;
+
+// css::container::XChild
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override;
+ virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override;
+
+private:
+ /** quickly checks if there already is an element with a given name. No access to the configuration occurs, i.e.
+ if there is such an object which is not already loaded, it won't be loaded now.
+ @param _rName the object name to check
+ @return sal_True if there already exists such an object
+ */
+ inline bool checkExistence(const OUString& _rName);
+
+ void implAppend(
+ const OUString& _rName,
+ const OUString& _rDocumentLocation
+ );
+
+ void implRemove(const OUString& _rName);
+
+ void implReplace(
+ const OUString& _rName,
+ const OUString& _rNewLink);
+
+};
+
+inline bool OBookmarkContainer::checkExistence(const OUString& _rName)
+{
+ return m_aBookmarks.find(_rName) != m_aBookmarks.end();
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/callablestatement.hxx b/dbaccess/source/core/inc/callablestatement.hxx
new file mode 100644
index 000000000..58e21189a
--- /dev/null
+++ b/dbaccess/source/core/inc/callablestatement.hxx
@@ -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 .
+ */
+#pragma once
+
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XOutParameters.hpp>
+#include "preparedstatement.hxx"
+
+namespace dbaccess
+{
+
+ // OCallableStatement
+
+ class OCallableStatement : public OPreparedStatement,
+ public css::sdbc::XRow,
+ public css::sdbc::XOutParameters
+ {
+ public:
+ OCallableStatement(const css::uno::Reference< css::sdbc::XConnection > & _xConn,
+ const css::uno::Reference< css::uno::XInterface > & _xStatement)
+ :OPreparedStatement(_xConn, _xStatement){}
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // css::sdbc::XOutParameters
+ virtual void SAL_CALL registerOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL registerNumericOutParameter( sal_Int32 parameterIndex, sal_Int32 sqlType, sal_Int32 scale ) override;
+
+ // css::sdbc::XRow
+ virtual sal_Bool SAL_CALL wasNull( ) override;
+ virtual OUString SAL_CALL getString( sal_Int32 columnIndex ) override;
+ virtual sal_Bool SAL_CALL getBoolean( sal_Int32 columnIndex ) override;
+ virtual sal_Int8 SAL_CALL getByte( sal_Int32 columnIndex ) override;
+ virtual sal_Int16 SAL_CALL getShort( sal_Int32 columnIndex ) override;
+ virtual sal_Int32 SAL_CALL getInt( sal_Int32 columnIndex ) override;
+ virtual sal_Int64 SAL_CALL getLong( sal_Int32 columnIndex ) override;
+ virtual float SAL_CALL getFloat( sal_Int32 columnIndex ) override;
+ virtual double SAL_CALL getDouble( sal_Int32 columnIndex ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getBytes( sal_Int32 columnIndex ) override;
+ virtual css::util::Date SAL_CALL getDate( sal_Int32 columnIndex ) override;
+ virtual css::util::Time SAL_CALL getTime( sal_Int32 columnIndex ) override;
+ virtual css::util::DateTime SAL_CALL getTimestamp( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getBinaryStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::io::XInputStream > SAL_CALL getCharacterStream( sal_Int32 columnIndex ) override;
+ virtual css::uno::Any SAL_CALL getObject( sal_Int32 columnIndex, const css::uno::Reference< css::container::XNameAccess >& typeMap ) override;
+ virtual css::uno::Reference< css::sdbc::XRef > SAL_CALL getRef( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XBlob > SAL_CALL getBlob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XClob > SAL_CALL getClob( sal_Int32 columnIndex ) override;
+ virtual css::uno::Reference< css::sdbc::XArray > SAL_CALL getArray( sal_Int32 columnIndex ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/column.hxx b/dbaccess/source/core/inc/column.hxx
new file mode 100644
index 000000000..aebc376b1
--- /dev/null
+++ b/dbaccess/source/core/inc/column.hxx
@@ -0,0 +1,217 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "columnsettings.hxx"
+
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/container/XNameAccess.hpp>
+#include <com/sun/star/container/XNamed.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+
+#include <comphelper/propertycontainer.hxx>
+#include <connectivity/TColumnsHelper.hxx>
+#include <connectivity/sdbcx/IRefreshable.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/compbase.hxx>
+#include <cppuhelper/implbase1.hxx>
+
+namespace dbaccess
+{
+
+
+ // OColumn
+
+ typedef ::cppu::WeakComponentImplHelper< css::lang::XServiceInfo,
+ css::container::XNamed
+ > OColumnBase;
+
+ class OColumn :public cppu::BaseMutex
+ ,public OColumnBase
+ ,public ::comphelper::OPropertyContainer
+ ,public IPropertyContainer // convenience for the derived class which also derive from OColumnSettings
+ {
+ friend class OColumns;
+
+ protected:
+ // <properties>
+ OUString m_sName;
+ // </properties>
+
+ protected:
+ OColumn( const bool _bNameIsReadOnly );
+
+ public:
+ virtual ~OColumn() override;
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override = 0;
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+ // cppu::OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XNamed
+ virtual OUString SAL_CALL getName( ) override;
+ virtual void SAL_CALL setName( const OUString& _rName ) override;
+
+ protected:
+ // IPropertyContainer
+ virtual void registerProperty( const OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes, void* _pPointerToMember, const css::uno::Type& _rMemberType ) override;
+ virtual void registerMayBeVoidProperty( const OUString& _rName, sal_Int32 _nHandle, sal_Int32 _nAttributes, css::uno::Any* _pPointerToMember, const css::uno::Type& _rExpectedType ) override;
+ };
+
+ // IColumnFactory - used by OColumns for creating new columns
+ class SAL_NO_VTABLE IColumnFactory
+ {
+ public:
+ /** creates an OColumn object which should represent the column with a given name
+ */
+ virtual rtl::Reference<OColumn>
+ createColumn( const OUString& _rName ) const = 0;
+
+ /** creates a column descriptor object.
+
+ A column descriptor object is used to append new columns to the collection. If such an append
+ actually happened, columnAppended is called afterwards.
+ */
+ virtual css::uno::Reference< css::beans::XPropertySet > createColumnDescriptor() = 0;
+
+ /** notifies that a column, created from a column descriptor, has been appended
+ */
+ virtual void columnAppended( const css::uno::Reference< css::beans::XPropertySet >& _rxSourceDescriptor ) = 0;
+
+ /** notifies that a column with a given name has been dropped
+ */
+ virtual void columnDropped( const OUString& _sName ) = 0;
+
+ protected:
+ ~IColumnFactory() {}
+ };
+
+ class OContainerMediator;
+ typedef ::cppu::ImplHelper1< css::container::XChild > TXChild;
+ typedef connectivity::OColumnsHelper OColumns_BASE;
+
+ class OColumns : public OColumns_BASE
+ ,public TXChild
+ {
+ OContainerMediator* m_pMediator;
+
+ protected:
+ // comes from the driver can be null
+ css::uno::Reference< css::container::XNameAccess > m_xDrvColumns;
+ css::uno::WeakReference< css::uno::XInterface > m_xParent;
+ IColumnFactory* m_pColFactoryImpl;
+ ::connectivity::sdbcx::IRefreshableColumns* m_pRefreshColumns;
+
+ bool m_bInitialized : 1;
+ bool m_bAddColumn : 1;
+ bool m_bDropColumn : 1;
+
+ virtual void impl_refresh() override;
+ virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual connectivity::sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+
+ public:
+ connectivity::sdbcx::ObjectType createBaseObject(const OUString& _rName)
+ {
+ return OColumns_BASE::createObject(_rName);
+ }
+ /** flag which determines whether the container is filled or not
+ */
+ bool isInitialized() const { return m_bInitialized; }
+ void setInitialized() {m_bInitialized = true;}
+ void setMediator(OContainerMediator* _pMediator) { m_pMediator = _pMediator; }
+
+ public:
+ /** constructs an empty container without configuration location.
+ @param rParent the parent object. This instance will be used for refcounting, so the parent
+ cannot die before the container does.
+ @param _rMutex the mutex of the parent.
+ @param _bCaseSensitive the initial case sensitivity flag
+ @see setCaseSensitive
+ */
+ OColumns(
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ bool _bCaseSensitive,
+ const std::vector< OUString>& _rVector,
+ IColumnFactory* _pColFactory,
+ ::connectivity::sdbcx::IRefreshableColumns* _pRefresh,
+ bool _bAddColumn = false,
+ bool _bDropColumn = false,
+ bool _bUseHardRef = true);
+
+ OColumns(
+ ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const css::uno::Reference< css::container::XNameAccess >& _rxDrvColumns,
+ bool _bCaseSensitive,
+ const std::vector< OUString> &_rVector,
+ IColumnFactory* _pColFactory,
+ ::connectivity::sdbcx::IRefreshableColumns* _pRefresh,
+ bool _bAddColumn = false,
+ bool _bDropColumn = false,
+ bool _bUseHardRef = true);
+ virtual ~OColumns() override;
+
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override { OColumns_BASE::acquire(); }
+ virtual void SAL_CALL release() noexcept override { OColumns_BASE::release(); }
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // css::container::XChild
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override;
+ virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override;
+
+ void append(const OUString& rName, OColumn*);
+ void clearColumns();
+ // only the name is identical to ::cppu::OComponentHelper
+ virtual void disposing() override;
+
+ private:
+ using OColumns_BASE::setParent;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/columnsettings.hxx b/dbaccess/source/core/inc/columnsettings.hxx
new file mode 100644
index 000000000..6b6c5d4c1
--- /dev/null
+++ b/dbaccess/source/core/inc/columnsettings.hxx
@@ -0,0 +1,88 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+
+namespace dbaccess
+{
+
+ // TODO: move the following to comphelper/propertycontainerhelper.hxx
+ class IPropertyContainer
+ {
+ public:
+ virtual void registerProperty(
+ const OUString& _rName,
+ sal_Int32 _nHandle,
+ sal_Int32 _nAttributes,
+ void* _pPointerToMember,
+ const css::uno::Type& _rMemberType
+ ) = 0;
+
+ virtual void registerMayBeVoidProperty(
+ const OUString& _rName,
+ sal_Int32 _nHandle,
+ sal_Int32 _nAttributes,
+ css::uno::Any* _pPointerToMember,
+ const css::uno::Type& _rExpectedType
+ ) = 0;
+
+ protected:
+ ~IPropertyContainer() {}
+ };
+
+ // OColumnSettings
+ class OColumnSettings
+ {
+ // <properties>
+ css::uno::Any m_aWidth; // sal_Int32 or void
+ css::uno::Any m_aFormatKey; // sal_Int32 or void
+ css::uno::Any m_aRelativePosition; // sal_Int32 or void
+ css::uno::Any m_aAlignment; // sal_Int32 (css::awt::TextAlign) or void
+ css::uno::Any m_aHelpText; // the description of the column which is visible in the helptext of the column
+ css::uno::Any m_aControlDefault; // the default value which should be displayed as by a control when moving to a new row
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xControlModel;
+ bool m_bHidden;
+ // </properties>
+
+ protected:
+ virtual ~OColumnSettings();
+
+ public:
+ OColumnSettings();
+
+ protected:
+ void registerProperties( IPropertyContainer& _rPropertyContainer );
+
+ /** determines whether the property with the given handle is handled by the class
+ */
+ static bool isColumnSettingProperty( const sal_Int32 _nPropertyHandle );
+ static bool isDefaulted( const sal_Int32 _nPropertyHandle, const css::uno::Any& _rPropertyValue );
+
+ public:
+ /** check if the persistent settings have their default value
+ */
+ static bool hasDefaultSettings( const css::uno::Reference< css::beans::XPropertySet >& _rxColumn );
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/commandbase.hxx b/dbaccess/source/core/inc/commandbase.hxx
new file mode 100644
index 000000000..1a0bd91d8
--- /dev/null
+++ b/dbaccess/source/core/inc/commandbase.hxx
@@ -0,0 +1,50 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+namespace dbaccess
+{
+
+// OCommandBase - a base class (in fact just a container for some members)
+// for classes implementing the sdb.CommandDefinition service
+class OCommandBase
+{
+public: // need public access
+// <properties>
+ css::uno::Sequence< css::beans::PropertyValue>
+ m_aLayoutInformation;
+ OUString m_sCommand;
+ bool m_bEscapeProcessing; // no BitField! So it can be used with an OPropertyStateContainer
+ OUString m_sUpdateTableName;
+ OUString m_sUpdateSchemaName;
+ OUString m_sUpdateCatalogName;
+// </properties>
+
+protected:
+ OCommandBase() : m_bEscapeProcessing(true) { }
+
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/composertools.hxx b/dbaccess/source/core/inc/composertools.hxx
new file mode 100644
index 000000000..337064757
--- /dev/null
+++ b/dbaccess/source/core/inc/composertools.hxx
@@ -0,0 +1,121 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <rtl/ustrbuf.hxx>
+#include <osl/diagnose.h>
+
+namespace dbaccess
+{
+
+ // TokenComposer
+ struct TokenComposer
+ {
+ private:
+ #ifdef DBG_UTIL
+ bool m_bUsed;
+ #endif
+
+ protected:
+ OUStringBuffer m_aBuffer;
+
+ public:
+ OUString getComposedAndClear()
+ {
+ #ifdef DBG_UTIL
+ m_bUsed = true;
+ #endif
+ return m_aBuffer.makeStringAndClear();
+ }
+
+ void clear()
+ {
+ #ifdef DBG_UTIL
+ m_bUsed = false;
+ #endif
+ m_aBuffer.setLength(0);
+ }
+
+ public:
+ TokenComposer()
+ #ifdef DBG_UTIL
+ :m_bUsed( false )
+ #endif
+ {
+ }
+
+ virtual ~TokenComposer()
+ {
+ }
+
+ TokenComposer(TokenComposer const &) = default;
+ TokenComposer(TokenComposer &&) = default;
+ TokenComposer & operator =(TokenComposer const &) = default;
+ TokenComposer & operator =(TokenComposer &&) = default;
+
+ void operator() (const OUString& lhs)
+ {
+ append(lhs);
+ }
+
+ void append( const OUString& lhs )
+ {
+ #ifdef DBG_UTIL
+ OSL_ENSURE( !m_bUsed, "FilterCreator::append: already used up!" );
+ #endif
+ if ( !lhs.isEmpty() )
+ {
+ if ( !m_aBuffer.isEmpty() )
+ appendNonEmptyToNonEmpty( lhs );
+ else
+ m_aBuffer.append( lhs );
+ }
+ }
+
+ /// append the given part. Only to be called when both the part and our buffer so far are not empty
+ virtual void appendNonEmptyToNonEmpty( const OUString& lhs ) = 0;
+ };
+
+ // FilterCreator
+ struct FilterCreator : public TokenComposer
+ {
+ virtual void appendNonEmptyToNonEmpty( const OUString& lhs ) override
+ {
+ m_aBuffer.insert( 0, ' ' );
+ m_aBuffer.insert( 0, '(' );
+ m_aBuffer.append( " ) AND ( " );
+ m_aBuffer.append( lhs );
+ m_aBuffer.append( " )" );
+ }
+ };
+
+ // FilterCreator
+ struct OrderCreator : public TokenComposer
+ {
+ virtual void appendNonEmptyToNonEmpty( const OUString& lhs ) override
+ {
+ m_aBuffer.append( ", " );
+ m_aBuffer.append( lhs );
+ }
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/containerapprove.hxx b/dbaccess/source/core/inc/containerapprove.hxx
new file mode 100644
index 000000000..f780e224a
--- /dev/null
+++ b/dbaccess/source/core/inc/containerapprove.hxx
@@ -0,0 +1,57 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <rtl/ustring.hxx>
+
+#include <memory>
+
+namespace dbaccess
+{
+
+ // IContainerApprove
+ /** interface for approving elements to be inserted into a container
+
+ On the long run, one could imagine that this interface completely encapsulates
+ container/element approvals in all our various container classes herein (document
+ containers, definition containers, table containers, query containers,
+ command definition containers, bookmark containers). This would decrease coupling
+ of the respective classes.
+ */
+ class SAL_NO_VTABLE IContainerApprove
+ {
+ public:
+ virtual ~IContainerApprove() {}
+
+ /** approves a given element for insertion into the container
+ @param _rName
+ specifies the name under which the element is going to be inserted
+ @throws Exception
+ if the name or the object are invalid, or not eligible for insertion
+ into the container
+ */
+ virtual void approveElement( const OUString& _rName ) = 0;
+ };
+
+ typedef std::shared_ptr< IContainerApprove > PContainerApprove;
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/databasecontext.hxx b/dbaccess/source/core/inc/databasecontext.hxx
new file mode 100644
index 000000000..e15585c81
--- /dev/null
+++ b/dbaccess/source/core/inc/databasecontext.hxx
@@ -0,0 +1,180 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <config_features.h>
+
+#include <map>
+
+#include "ModelImpl.hxx"
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/lang/XUnoTunnel.hpp>
+#include <com/sun/star/sdb/XDatabaseContext.hpp>
+#include <com/sun/star/sdb/XDatabaseRegistrations.hpp>
+#include <com/sun/star/uno/XAggregation.hpp>
+
+#if HAVE_FEATURE_SCRIPTING
+#include <basic/basrdll.hxx>
+#endif
+
+#include <basic/basicmanagerrepository.hxx>
+#include <cppuhelper/compbase.hxx>
+
+// needed for registration
+namespace com::sun::star {
+ namespace lang
+ {
+ class XMultiServiceFactory;
+ class IllegalArgumentException;
+ }
+}
+
+namespace dbaccess
+{
+class DatabaseDocumentLoader;
+
+typedef ::cppu::WeakComponentImplHelper< css::lang::XServiceInfo
+ , css::sdb::XDatabaseContext
+ , css::lang::XUnoTunnel
+ > DatabaseAccessContext_Base;
+
+class ODatabaseContext :public DatabaseAccessContext_Base
+ ,public ::basic::BasicManagerCreationListener
+{
+private:
+ /** loads the given object from the given URL
+ @throws WrappedTargetException
+ if an error occurs accessing the URL via the UCB
+ */
+ css::uno::Reference< css::uno::XInterface > loadObjectFromURL(const OUString& _rName,const OUString& _sURL);
+ css::uno::Reference< css::uno::XInterface > getObject( const OUString& _rURL );
+
+ /** sets all properties which were transient at the data source. e.g. password
+ @param _sURL The file URL of the data source
+ @param _xObject The data source itself.
+ */
+ void setTransientProperties(const OUString& _sURL, ODatabaseModelImpl& _rDataSourceModel );
+
+ /** creates a new data source
+ */
+ css::uno::Reference< css::uno::XInterface >
+ impl_createNewDataSource();
+
+#if HAVE_FEATURE_SCRIPTING
+ BasicDLL m_aBasicDLL;
+#endif
+
+protected:
+ ::osl::Mutex m_aMutex;
+ css::uno::Reference< css::uno::XComponentContext >
+ m_aContext;
+
+ css::uno::Reference< css::uno::XAggregation >
+ m_xDBRegistrationAggregate;
+ css::uno::Reference< css::sdb::XDatabaseRegistrations >
+ m_xDatabaseRegistrations;
+
+ typedef std::map<OUString, ODatabaseModelImpl*> ObjectCache;
+ ObjectCache m_aDatabaseObjects;
+
+ typedef std::map< OUString, css::uno::Sequence< css::beans::PropertyValue > > PropertyCache;
+ PropertyCache m_aDatasourceProperties;
+ // as we hold our data sources weak, we have to cache all properties on the data sources which are
+ // transient but stored as long as the session lasts. The database context is the session (as it lives
+ // as long as the session does), but the data sources may die before the session does, and then be
+ // recreated afterwards. So it's our (the context's) responsibility to store the session-persistent
+ // properties.
+
+ ::comphelper::OInterfaceContainerHelper3<css::container::XContainerListener> m_aContainerListeners;
+ rtl::Reference<DatabaseDocumentLoader> m_xDatabaseDocumentLoader;
+
+public:
+ explicit ODatabaseContext( const css::uno::Reference< css::uno::XComponentContext >& );
+ virtual ~ODatabaseContext() override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XSingleServiceFactory
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstance( ) override;
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL createInstanceWithArguments( const css::uno::Sequence< css::uno::Any >& _rArguments ) override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+ // XEnumerationAccess
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration( ) override;
+
+ // XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XNamingService
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getRegisteredObject( const OUString& Name ) override;
+ virtual void SAL_CALL registerObject( const OUString& Name, const css::uno::Reference< css::uno::XInterface >& Object ) override;
+ virtual void SAL_CALL revokeObject( const OUString& Name ) override;
+
+ // XDatabaseRegistrations
+ virtual sal_Bool SAL_CALL hasRegisteredDatabase( const OUString& Name ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getRegistrationNames() override;
+ virtual OUString SAL_CALL getDatabaseLocation( const OUString& Name ) override;
+ virtual void SAL_CALL registerDatabaseLocation( const OUString& Name, const OUString& Location ) override;
+ virtual void SAL_CALL revokeDatabaseLocation( const OUString& Name ) override;
+ virtual void SAL_CALL changeDatabaseLocation( const OUString& Name, const OUString& NewLocation ) override;
+ virtual sal_Bool SAL_CALL isDatabaseRegistrationReadOnly( const OUString& Name ) override;
+ virtual void SAL_CALL addDatabaseRegistrationsListener( const css::uno::Reference< css::sdb::XDatabaseRegistrationsListener >& Listener ) override;
+ virtual void SAL_CALL removeDatabaseRegistrationsListener( const css::uno::Reference< css::sdb::XDatabaseRegistrationsListener >& Listener ) override;
+
+ // XContainer
+ virtual void SAL_CALL addContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override;
+ virtual void SAL_CALL removeContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override;
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ void registerDatabaseDocument( ODatabaseModelImpl& _rModelImpl);
+ void revokeDatabaseDocument( const ODatabaseModelImpl& _rModelImpl);
+ void databaseDocumentURLChange(const OUString& _sOldName, const OUString& _sNewName);
+ void storeTransientProperties( ODatabaseModelImpl& _rModelImpl);
+ void appendAtTerminateListener(const ODatabaseModelImpl& _rDataSourceModel);
+ void removeFromTerminateListener(const ODatabaseModelImpl& _rDataSourceModel);
+
+private:
+ // BasicManagerCreationListener
+ virtual void onBasicManagerCreated(
+ const css::uno::Reference< css::frame::XModel >& _rxForDocument,
+ BasicManager& _rBasicManager
+ ) override;
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/datasettings.hxx b/dbaccess/source/core/inc/datasettings.hxx
new file mode 100644
index 000000000..8e24ebb71
--- /dev/null
+++ b/dbaccess/source/core/inc/datasettings.hxx
@@ -0,0 +1,77 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/awt/FontDescriptor.hpp>
+#include <rtl/ustring.hxx>
+#include <comphelper/propertystatecontainer.hxx>
+
+namespace dbaccess
+{
+
+// ODataSettings_Base - a base class which implements the property member
+// for an object implementing the sdb::DataSettings
+// service
+// the properties have to be registered when used
+class ODataSettings_Base
+{
+public:
+// <properties>
+ OUString m_sFilter;
+ OUString m_sHavingClause;
+ OUString m_sGroupBy;
+ OUString m_sOrder;
+ bool m_bApplyFilter; // no BitField ! the base class needs a pointer to this member !
+ bool m_bAutoGrow;
+ css::awt::FontDescriptor m_aFont;
+ css::uno::Any m_aRowHeight;
+ css::uno::Any m_aTextColor;
+ css::uno::Any m_aTextLineColor;
+ sal_Int16 m_nFontEmphasis;
+ sal_Int16 m_nFontRelief;
+// </properties>
+
+protected:
+ ODataSettings_Base();
+ ODataSettings_Base(const ODataSettings_Base& _rSource) = delete;
+ ~ODataSettings_Base();
+};
+// ODataSettings - a base class which implements the property handling
+// for an object implementing the sdb::DataSettings
+// service
+
+class ODataSettings : public ::comphelper::OPropertyStateContainer
+ , public ODataSettings_Base
+{
+ bool m_bQuery;
+protected:
+ ODataSettings(::cppu::OBroadcastHelper& _rBHelper,bool _bQuery = false);
+ virtual void getPropertyDefaultByHandle( sal_Int32 _nHandle, css::uno::Any& _rDefault ) const override;
+
+ /** register the properties from the param given. The parameter instance must be alive as long as its object lives.
+ @param _pItem
+ The database settings, can be <br>this</br>
+ */
+ void registerPropertiesFor(ODataSettings_Base* _pItem);
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/definitioncolumn.hxx b/dbaccess/source/core/inc/definitioncolumn.hxx
new file mode 100644
index 000000000..4d7ff3e17
--- /dev/null
+++ b/dbaccess/source/core/inc/definitioncolumn.hxx
@@ -0,0 +1,291 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include "column.hxx"
+#include "columnsettings.hxx"
+
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/ColumnValue.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/container/XChild.hpp>
+
+#include <comphelper/IdPropArrayHelper.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <comphelper/uno3.hxx>
+#include <cppuhelper/implbase1.hxx>
+
+namespace dbaccess
+{
+
+ typedef ::cppu::ImplHelper1< css::container::XChild > TXChild;
+ // OTableColumnDescriptor
+ /**
+ * provides the properties for description. A descriptor could be used to create a new table column.
+ */
+ class OTableColumnDescriptor : public OColumn
+ ,public OColumnSettings
+ ,public ::comphelper::OPropertyArrayUsageHelper < OTableColumnDescriptor >
+ ,public TXChild
+ {
+ css::uno::Reference< css::uno::XInterface > m_xParent;
+ const bool m_bActAsDescriptor;
+
+ protected:
+ // <properties>
+ OUString m_aTypeName;
+ OUString m_aDescription;
+ OUString m_aDefaultValue;
+ OUString m_aAutoIncrementValue;
+ sal_Int32 m_nType;
+ sal_Int32 m_nPrecision;
+ sal_Int32 m_nScale;
+ sal_Int32 m_nIsNullable;
+ bool m_bAutoIncrement;
+ bool m_bRowVersion;
+ bool m_bCurrency;
+ // </properties>
+
+ public:
+ OTableColumnDescriptor( const bool _bActAsDescriptor )
+ :OColumn( !_bActAsDescriptor )
+ ,m_bActAsDescriptor( _bActAsDescriptor )
+ ,m_nType( css::sdbc::DataType::SQLNULL )
+ ,m_nPrecision( 0 )
+ ,m_nScale( 0 )
+ ,m_nIsNullable( css::sdbc::ColumnValue::NULLABLE_UNKNOWN )
+ ,m_bAutoIncrement( false )
+ ,m_bRowVersion( false )
+ ,m_bCurrency( false )
+ {
+ impl_registerProperties();
+ }
+
+ DECLARE_XINTERFACE( )
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // css::container::XChild
+ virtual css::uno::Reference< css::uno::XInterface > SAL_CALL getParent( ) override;
+ virtual void SAL_CALL setParent( const css::uno::Reference< css::uno::XInterface >& Parent ) override;
+
+ // ::comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+
+ // ::cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const css::uno::Any& rValue ) override;
+
+ private:
+ void impl_registerProperties();
+ };
+
+ // OTableColumn
+ class OTableColumn;
+ typedef ::comphelper::OPropertyArrayUsageHelper < OTableColumn > OTableColumn_PBase;
+ /** describes a column of a table
+ */
+ class OTableColumn :public OTableColumnDescriptor
+ ,public OTableColumn_PBase
+ {
+ protected:
+ virtual ~OTableColumn() override;
+
+ public:
+ OTableColumn(const OUString& _rName);
+
+ // XTypeProvider
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+
+ // OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ };
+
+ // OQueryColumn
+ class OQueryColumn;
+ typedef ::comphelper::OPropertyArrayUsageHelper< OQueryColumn > OQueryColumn_PBase;
+ /** a column of a Query, with additional information obtained from parsing the query statement
+ */
+ class OQueryColumn :public OTableColumnDescriptor
+ ,public OQueryColumn_PBase
+ {
+ // <properties>
+ OUString m_sCatalogName;
+ OUString m_sSchemaName;
+ OUString m_sTableName;
+ OUString m_sRealName;
+ OUString m_sLabel;
+ // </properties>
+
+ css::uno::Reference< css::beans::XPropertySet > m_xOriginalTableColumn;
+
+ protected:
+ virtual ~OQueryColumn() override;
+
+ public:
+ OQueryColumn(
+ const css::uno::Reference< css::beans::XPropertySet>& _rxParserColumn,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ const OUString &i_sLabel
+ );
+
+ // XTypeProvider
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+
+ // *Property*
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper() const override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override;
+
+ private:
+ css::uno::Reference< css::beans::XPropertySet >
+ impl_determineOriginalTableColumn(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection
+ );
+
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+ };
+
+ // OColumnWrapper
+ /**
+ * describes all properties for a columns of a table. Only the view parts are provided
+ * directly, all the other parts are derived from a driver implementation
+ */
+ class OColumnWrapper :public OColumn
+ {
+ protected:
+ // definition which is provided by a driver!
+ css::uno::Reference< css::beans::XPropertySet >
+ m_xAggregate;
+
+ sal_Int32 m_nColTypeID;
+
+ protected:
+ OColumnWrapper( const css::uno::Reference< css::beans::XPropertySet >& _rCol, const bool _bNameIsReadOnly );
+ virtual ~OColumnWrapper() override;
+
+ public:
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+
+ protected:
+ OUString impl_getPropertyNameFromHandle( const sal_Int32 _nHandle ) const;
+
+ protected:
+ using OColumn::getFastPropertyValue;
+ };
+
+ // OTableColumnDescriptorWrapper
+ /**
+ * provides the properties for description. A descriptor could be used to create a new table column.
+ */
+ class OTableColumnDescriptorWrapper :public OColumnWrapper
+ ,public OColumnSettings
+ ,public ::comphelper::OIdPropertyArrayUsageHelper < OTableColumnDescriptorWrapper >
+ {
+ const bool m_bPureWrap;
+ const bool m_bIsDescriptor;
+
+ public:
+ OTableColumnDescriptorWrapper(const css::uno::Reference< css::beans::XPropertySet >& rCol,
+ const bool _bPureWrap, const bool _bIsDescriptor );
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // OIdPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 nId) const override;
+
+ // cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual void SAL_CALL getFastPropertyValue(
+ css::uno::Any& rValue,
+ sal_Int32 nHandle
+ ) const override;
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+
+ protected:
+ using OColumnWrapper::getFastPropertyValue;
+ };
+
+ // OTableColumnWrapper
+ /**
+ * describes all properties for a columns of a table. Only the view parts are provided
+ * directly, all the other parts are derived from a driver implementation
+ */
+ class OTableColumnWrapper :public OTableColumnDescriptorWrapper
+ ,public ::comphelper::OIdPropertyArrayUsageHelper < OTableColumnWrapper >
+ {
+ protected:
+ virtual ~OTableColumnWrapper() override;
+
+ public:
+ OTableColumnWrapper( const css::uno::Reference< css::beans::XPropertySet >& rCol,
+ const css::uno::Reference< css::beans::XPropertySet >& rColDefinition,
+ const bool _bPureWrap );
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // OIdPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper(sal_Int32 nId) const override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/definitioncontainer.hxx b/dbaccess/source/core/inc/definitioncontainer.hxx
new file mode 100644
index 000000000..9c871601a
--- /dev/null
+++ b/dbaccess/source/core/inc/definitioncontainer.hxx
@@ -0,0 +1,323 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <map>
+#include <vector>
+
+#include <cppuhelper/implbase7.hxx>
+#include <osl/mutex.hxx>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/container/XContainer.hpp>
+#include <com/sun/star/container/XEnumerationAccess.hpp>
+#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/beans/XPropertyChangeListener.hpp>
+#include <com/sun/star/beans/XVetoableChangeListener.hpp>
+#include <com/sun/star/container/XContainerApproveBroadcaster.hpp>
+#include "ContentHelper.hxx"
+#include "containerapprove.hxx"
+#include <comphelper/uno3.hxx>
+#include <comphelper/interfacecontainer2.hxx>
+
+namespace dbaccess
+{
+
+class ODefinitionContainer_Impl : public OContentHelper_Impl
+{
+public:
+ typedef std::map< OUString, TContentPtr > NamedDefinitions;
+ typedef NamedDefinitions::iterator iterator;
+ typedef NamedDefinitions::const_iterator const_iterator;
+
+private:
+ NamedDefinitions m_aDefinitions;
+
+public:
+ size_t size() const { return m_aDefinitions.size(); }
+
+ const_iterator begin() const { return m_aDefinitions.begin(); }
+ const_iterator end() const { return m_aDefinitions.end(); }
+
+ const_iterator find( const OUString& _rName ) const { return m_aDefinitions.find( _rName ); }
+ const_iterator find( const TContentPtr& _pDefinition ) const;
+
+ void erase( const OUString& _rName ) { m_aDefinitions.erase( _rName ); }
+ void erase( const TContentPtr& _pDefinition );
+
+ void insert( const OUString& _rName, TContentPtr _pDefinition )
+ {
+ m_aDefinitions.emplace( _rName, _pDefinition );
+ }
+
+private:
+ iterator find( const TContentPtr& _pDefinition );
+ // (for the moment, this is private. Make it public if needed. If really needed.)
+};
+
+// ODefinitionContainer - base class of collections of database definition
+// documents
+typedef ::cppu::ImplHelper7 < css::container::XIndexAccess
+ , css::container::XNameContainer
+ , css::container::XEnumerationAccess
+ , css::container::XContainer
+ , css::container::XContainerApproveBroadcaster
+ , css::beans::XPropertyChangeListener
+ , css::beans::XVetoableChangeListener
+ > ODefinitionContainer_Base;
+
+class ODefinitionContainer
+ :public OContentHelper
+ ,public ODefinitionContainer_Base
+{
+protected:
+ typedef std::map< OUString, css::uno::WeakReference< css::ucb::XContent > > Documents;
+
+ enum ContainerOperation
+ {
+ E_REPLACED,
+ E_REMOVED,
+ E_INSERTED
+ };
+
+ enum ListenerType
+ {
+ ApproveListeners,
+ ContainerListemers
+ };
+
+private:
+ PContainerApprove m_pElementApproval;
+
+protected:
+ // we can't just hold a vector of XContentRefs, as after initialization they're all empty
+ // cause we load them only on access
+ std::vector<Documents::iterator>
+ m_aDocuments; // for an efficient index access
+ Documents m_aDocumentMap; // for an efficient name access
+
+ ::comphelper::OInterfaceContainerHelper2
+ m_aApproveListeners;
+ ::comphelper::OInterfaceContainerHelper2
+ m_aContainerListeners;
+
+ bool m_bInPropertyChange;
+ bool m_bCheckSlash;
+
+protected:
+ /** Additionally to our own approvals which new elements must pass, derived classes
+ can specify an additional approval instance here.
+
+ Every time a new element is inserted into the container (or an element is replaced
+ with a new one), this new element must pass our own internal approval, plus the approval
+ given here.
+ */
+ void setElementApproval( PContainerApprove _pElementApproval ) { m_pElementApproval = _pElementApproval; }
+ const PContainerApprove& getElementApproval() const { return m_pElementApproval; }
+
+protected:
+ virtual ~ODefinitionContainer() override;
+
+ const ODefinitionContainer_Impl& getDefinitions() const
+ {
+ return dynamic_cast< const ODefinitionContainer_Impl& >( *m_pImpl );
+ }
+
+ ODefinitionContainer_Impl& getDefinitions()
+ {
+ return dynamic_cast< ODefinitionContainer_Impl& >( *m_pImpl );
+ }
+public:
+ /** constructs the container.
+ */
+ ODefinitionContainer(
+ const css::uno::Reference< css::uno::XComponentContext >& _xORB
+ , const css::uno::Reference< css::uno::XInterface >& _xParentContainer
+ , const TContentPtr& _pImpl
+ , bool _bCheckSlash = true
+ );
+
+// css::uno::XInterface
+ DECLARE_XINTERFACE( )
+
+ virtual css::uno::Sequence<css::uno::Type> SAL_CALL getTypes() override;
+ virtual css::uno::Sequence<sal_Int8> SAL_CALL getImplementationId() override;
+
+// css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+// css::container::XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+// css::container::XEnumerationAccess
+ virtual css::uno::Reference< css::container::XEnumeration > SAL_CALL createEnumeration( ) override;
+
+// css::container::XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount( ) override;
+ virtual css::uno::Any SAL_CALL getByIndex( sal_Int32 _nIndex ) override;
+
+// css::container::XNameContainer
+ virtual void SAL_CALL insertByName( const OUString& _rName, const css::uno::Any& aElement ) override;
+ virtual void SAL_CALL removeByName( const OUString& _rName ) override;
+
+// css::container::XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& _rName, const css::uno::Any& aElement ) override;
+
+// css::container::XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+// css::container::XContainer
+ virtual void SAL_CALL addContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override;
+ virtual void SAL_CALL removeContainerListener( const css::uno::Reference< css::container::XContainerListener >& xListener ) override;
+
+ // XContainerApproveBroadcaster
+ virtual void SAL_CALL addContainerApproveListener( const css::uno::Reference< css::container::XContainerApproveListener >& Listener ) override;
+ virtual void SAL_CALL removeContainerApproveListener( const css::uno::Reference< css::container::XContainerApproveListener >& Listener ) override;
+
+// css::lang::XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // XPropertyChangeListener
+ virtual void SAL_CALL propertyChange( const css::beans::PropertyChangeEvent& evt ) override;
+ // XVetoableChangeListener
+ virtual void SAL_CALL vetoableChange( const css::beans::PropertyChangeEvent& aEvent ) override;
+
+protected:
+ // helper
+ virtual void SAL_CALL disposing() override;
+
+ /** create an object from its persistent data within the configuration. To be overwritten by derived classes.
+ @param _rName the name the object has within the container
+ @return the newly created object or an empty reference if something went wrong
+ */
+ virtual css::uno::Reference< css::ucb::XContent > createObject(
+ const OUString& _rName) = 0;
+
+ /** get the object specified by the given name. If desired, the object will be read if not already done so.<BR>
+ @param _rName the object name
+ @param _bReadIfNecessary if sal_True, the object will be created if necessary
+ @return the property set interface of the object. Usually the return value is not NULL, but
+ if so, then the object could not be read from the configuration
+ @throws NoSuchElementException if there is no object with the given name.
+ @see createObject
+ */
+ css::uno::Reference< css::ucb::XContent >
+ implGetByName(const OUString& _rName, bool _bCreateIfNecessary);
+
+ /** quickly checks if there already is an element with a given name. No access to the configuration occurs, i.e.
+ if there is such an object which is not already loaded, it won't be loaded now.
+ @param _rName the object name to check
+ @return sal_True if there already exists such an object
+ */
+ virtual bool checkExistence(const OUString& _rName);
+
+ /** append a new object to the container. No plausibility checks are done, e.g. if the object is non-NULL or
+ if the name is already used by another object or anything like this. This method is for derived classes
+ which may support different methods to create and/or append objects, and don't want to deal with the
+ internal structures of this class.<BR>
+ The old component will not be disposed, this is the callers responsibility, too.
+ @param _rName the name of the new object
+ @param _rxNewObject the new object (not surprising, is it ?)
+ @see createConfigKey
+ @see implReplace
+ @see implRemove
+ */
+ void implAppend(
+ const OUString& _rName,
+ const css::uno::Reference< css::ucb::XContent >& _rxNewObject
+ );
+
+ /** remove all references to an object from the container. No plausibility checks are done, e.g. whether
+ or not there exists an object with the given name. This is the responsibility of the caller.<BR>
+ Additionally the node for the given object will be removed from the registry (including all sub nodes).<BR>
+ The old component will not be disposed, this is the callers responsibility, too.
+ @param _rName the objects name
+ @see implReplace
+ @see implAppend
+ */
+ void implRemove(const OUString& _rName);
+
+ /** remove an object in the container. No plausibility checks are done, e.g. whether
+ or not there exists an object with the given name or the object is non-NULL. This is the responsibility of the caller.<BR>
+ Additionally all object-related information within the registry will be deleted. The new object config node,
+ where the caller may want to store the new objects information, is returned.<BR>
+ The old component will not be disposed, this is the callers responsibility, too.
+ @param _rName the objects name
+ @param _rxNewObject the new object
+ @param _rNewObjectNode the configuration node where the new object may be stored
+ @see implAppend
+ @see implRemove
+ */
+ void implReplace(
+ const OUString& _rName,
+ const css::uno::Reference< css::ucb::XContent >& _rxNewObject
+ );
+
+ /** notifies our container/approve listeners
+ */
+ void notifyByName(
+ ::osl::ResettableMutexGuard& _rGuard,
+ const OUString& _rName,
+ const css::uno::Reference< css::ucb::XContent >& _xNewElement,
+ const css::uno::Reference< css::ucb::XContent >& xOldElement,
+ ContainerOperation _eOperation,
+ ListenerType _eType
+ );
+
+ operator css::uno::Reference< css::uno::XInterface > () const
+ {
+ return const_cast< XContainer* >( static_cast< const XContainer* >( this ) );
+ }
+
+private:
+ void addObjectListener(const css::uno::Reference< css::ucb::XContent >& _xNewObject);
+ void removeObjectListener(const css::uno::Reference< css::ucb::XContent >& _xNewObject);
+
+ /** approve that the object given may be inserted into the container.
+ Should be overridden by derived classes,
+ the default implementation just checks the object to be non-void.
+
+ @throws IllegalArgumentException
+ if the name or the object are invalid
+ @throws ElementExistException
+ if the object already exists in the container, or another object with the same name
+ already exists
+ @throws WrappedTargetException
+ if another error occurs which prevents insertion of the object into the container
+ */
+ void approveNewObject(
+ const OUString& _sName,
+ const css::uno::Reference< css::ucb::XContent >& _rxObject
+ ) const;
+
+ bool impl_haveAnyListeners_nothrow() const
+ {
+ return ( m_aContainerListeners.getLength() > 0 ) || ( m_aApproveListeners.getLength() > 0 );
+ }
+};
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/documentevents.hxx b/dbaccess/source/core/inc/documentevents.hxx
new file mode 100644
index 000000000..e7f7ef9ff
--- /dev/null
+++ b/dbaccess/source/core/inc/documentevents.hxx
@@ -0,0 +1,75 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/container/XNameReplace.hpp>
+#include <com/sun/star/beans/PropertyValue.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+#include <memory>
+#include <map>
+
+namespace dbaccess
+{
+
+ typedef std::map< OUString, css::uno::Sequence< css::beans::PropertyValue > >
+ DocumentEventsData;
+
+ // DocumentEvents
+ struct DocumentEvents_Data;
+
+ typedef ::cppu::WeakImplHelper< css::container::XNameReplace
+ > DocumentEvents_Base;
+
+ class DocumentEvents :public DocumentEvents_Base
+ {
+ public:
+ DocumentEvents( ::cppu::OWeakObject& _rParent, ::osl::Mutex& _rMutex, DocumentEventsData& _rEventsData );
+ virtual ~DocumentEvents() override;
+
+ DocumentEvents(const DocumentEvents&) = delete;
+ const DocumentEvents& operator=(const DocumentEvents&) = delete;
+
+ static bool needsSynchronousNotification( std::u16string_view _rEventName );
+
+ // XInterface
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // XNameReplace
+ virtual void SAL_CALL replaceByName( const OUString& aName, const css::uno::Any& aElement ) override;
+
+ // XNameAccess
+ virtual css::uno::Any SAL_CALL getByName( const OUString& aName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+ virtual sal_Bool SAL_CALL hasByName( const OUString& aName ) override;
+
+ // XElementAccess
+ virtual css::uno::Type SAL_CALL getElementType( ) override;
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+
+ private:
+ std::unique_ptr< DocumentEvents_Data > m_pData;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/migrwarndlg.hxx b/dbaccess/source/core/inc/migrwarndlg.hxx
new file mode 100644
index 000000000..24bacf300
--- /dev/null
+++ b/dbaccess/source/core/inc/migrwarndlg.hxx
@@ -0,0 +1,24 @@
+/* -*- 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/.
+ */
+#pragma once
+
+#include <vcl/weld.hxx>
+
+namespace dbaccess
+{
+class MigrationWarnDialog : public weld::MessageDialogController
+{
+ std::unique_ptr<weld::Button> m_xLater;
+
+public:
+ MigrationWarnDialog(weld::Window* pParent);
+};
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/object.hxx b/dbaccess/source/core/inc/object.hxx
new file mode 100644
index 000000000..a947f9c57
--- /dev/null
+++ b/dbaccess/source/core/inc/object.hxx
@@ -0,0 +1,30 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+enum ObjectType
+{
+ dbaTable,
+ dbaQuery,
+ dbaForm,
+ dbaReport
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/objectnameapproval.hxx b/dbaccess/source/core/inc/objectnameapproval.hxx
new file mode 100644
index 000000000..ddd538c79
--- /dev/null
+++ b/dbaccess/source/core/inc/objectnameapproval.hxx
@@ -0,0 +1,75 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <memory>
+#include "containerapprove.hxx"
+
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+namespace dbaccess
+{
+
+ // ObjectNameApproval
+ struct ObjectNameApproval_Impl;
+ /** implementation of the IContainerApprove interface which approves
+ elements for insertion into a query or tables container.
+
+ The only check done by this instance is whether the query name is
+ not already used, taking into account that in some databases, queries
+ and tables share the same namespace.
+
+ The class is not thread-safe.
+ */
+ class ObjectNameApproval : public IContainerApprove
+ {
+ std::unique_ptr< ObjectNameApproval_Impl > m_pImpl;
+
+ public:
+ enum ObjectType
+ {
+ TypeQuery,
+ TypeTable
+ };
+
+ public:
+ /** constructs the instance
+
+ @param _rxConnection
+ the connection relative to which the names should be checked. This connection
+ will be held weak. In case it is closed, subsequent calls to this instance's
+ methods throw a DisposedException.
+ @param _eType
+ specifies which type of objects is to be approved with this instance
+ */
+ ObjectNameApproval(
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConnection,
+ ObjectType _eType
+ );
+ virtual ~ObjectNameApproval() override;
+
+ // IContainerApprove
+ virtual void approveElement( const OUString& _rName ) override;
+
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/preparedstatement.hxx b/dbaccess/source/core/inc/preparedstatement.hxx
new file mode 100644
index 000000000..cea06d79a
--- /dev/null
+++ b/dbaccess/source/core/inc/preparedstatement.hxx
@@ -0,0 +1,105 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbc/XPreparedStatement.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbc/XParameters.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include "statement.hxx"
+#include "column.hxx"
+
+namespace dbaccess
+{
+
+ // OPreparedStatement
+
+ class OPreparedStatement : public OStatementBase,
+ public css::sdbc::XPreparedStatement,
+ public css::sdbc::XParameters,
+ public css::sdbc::XResultSetMetaDataSupplier,
+ public css::sdbcx::XColumnsSupplier,
+ public css::lang::XServiceInfo
+ {
+ std::unique_ptr<OColumns> m_pColumns;
+ css::uno::Reference< css::sdbc::XParameters > m_xAggregateAsParameters;
+
+ public:
+ OPreparedStatement(const css::uno::Reference< css::sdbc::XConnection > & _xConn,
+ const css::uno::Reference< css::uno::XInterface > & _xStatement);
+ virtual ~OPreparedStatement() override;
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+ // css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // css::sdbc::XPreparedStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate( ) override;
+ virtual sal_Bool SAL_CALL execute( ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+
+ // css::sdbcx::XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+
+ // css::sdbc::XResultSetMetaDataSupplier
+ virtual css::uno::Reference< css::sdbc::XResultSetMetaData > SAL_CALL getMetaData( ) override;
+
+ // css::sdbc::XParameters
+ virtual void SAL_CALL setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) override;
+ virtual void SAL_CALL setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName ) override;
+ virtual void SAL_CALL setBoolean( sal_Int32 parameterIndex, sal_Bool x ) override;
+ virtual void SAL_CALL setByte( sal_Int32 parameterIndex, sal_Int8 x ) override;
+ virtual void SAL_CALL setShort( sal_Int32 parameterIndex, sal_Int16 x ) override;
+ virtual void SAL_CALL setInt( sal_Int32 parameterIndex, sal_Int32 x ) override;
+ virtual void SAL_CALL setLong( sal_Int32 parameterIndex, sal_Int64 x ) override;
+ virtual void SAL_CALL setFloat( sal_Int32 parameterIndex, float x ) override;
+ virtual void SAL_CALL setDouble( sal_Int32 parameterIndex, double x ) override;
+ virtual void SAL_CALL setString( sal_Int32 parameterIndex, const OUString& x ) override;
+ virtual void SAL_CALL setBytes( sal_Int32 parameterIndex, const css::uno::Sequence< sal_Int8 >& x ) override;
+ virtual void SAL_CALL setDate( sal_Int32 parameterIndex, const css::util::Date& x ) override;
+ virtual void SAL_CALL setTime( sal_Int32 parameterIndex, const css::util::Time& x ) override;
+ virtual void SAL_CALL setTimestamp( sal_Int32 parameterIndex, const css::util::DateTime& x ) override;
+ virtual void SAL_CALL setBinaryStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setCharacterStream( sal_Int32 parameterIndex, const css::uno::Reference< css::io::XInputStream >& x, sal_Int32 length ) override;
+ virtual void SAL_CALL setObject( sal_Int32 parameterIndex, const css::uno::Any& x ) override;
+ virtual void SAL_CALL setObjectWithInfo( sal_Int32 parameterIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale ) override;
+ virtual void SAL_CALL setRef( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XRef >& x ) override;
+ virtual void SAL_CALL setBlob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XBlob >& x ) override;
+ virtual void SAL_CALL setClob( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XClob >& x ) override;
+ virtual void SAL_CALL setArray( sal_Int32 parameterIndex, const css::uno::Reference< css::sdbc::XArray >& x ) override;
+ virtual void SAL_CALL clearParameters( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/querycomposer.hxx b/dbaccess/source/core/inc/querycomposer.hxx
new file mode 100644
index 000000000..c5d764d98
--- /dev/null
+++ b/dbaccess/source/core/inc/querycomposer.hxx
@@ -0,0 +1,91 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <com/sun/star/sdb/XSQLQueryComposer.hpp>
+#include <com/sun/star/sdb/XParametersSupplier.hpp>
+#include <com/sun/star/sdbcx/XTablesSupplier.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <cppuhelper/implbase5.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <connectivity/sqliterator.hxx>
+#include <apitools.hxx>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+
+
+namespace dbaccess
+{
+ typedef ::cppu::ImplHelper5< css::sdb::XSQLQueryComposer,
+ css::sdb::XParametersSupplier,
+ css::sdbcx::XTablesSupplier,
+ css::sdbcx::XColumnsSupplier,
+ css::lang::XServiceInfo > OQueryComposer_BASE;
+
+ class OQueryComposer : public ::cppu::BaseMutex,
+ public OSubComponent,
+ public OQueryComposer_BASE
+ {
+ std::vector< OUString> m_aFilters;
+ std::vector< OUString> m_aOrders;
+ OUString m_sOrgFilter;
+ OUString m_sOrgOrder;
+ css::uno::Reference< css::sdb::XSingleSelectQueryComposer> m_xComposer;
+ css::uno::Reference< css::sdb::XSingleSelectQueryComposer> m_xComposerHelper;
+
+ protected:
+ virtual void SAL_CALL disposing() override;
+ virtual ~OQueryComposer() override;
+ public:
+
+ OQueryComposer( const css::uno::Reference< css::sdbc::XConnection>& _xConnection );
+
+ // css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+
+ // css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+ // XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+ // XSQLQueryComposer
+ virtual OUString SAL_CALL getQuery( ) override;
+ virtual void SAL_CALL setQuery( const OUString& command ) override;
+ virtual OUString SAL_CALL getComposedQuery( ) override;
+ virtual OUString SAL_CALL getFilter( ) override;
+ virtual css::uno::Sequence< css::uno::Sequence< css::beans::PropertyValue > > SAL_CALL getStructuredFilter( ) override;
+ virtual OUString SAL_CALL getOrder( ) override;
+ virtual void SAL_CALL appendFilterByColumn( const css::uno::Reference< css::beans::XPropertySet >& column ) override;
+ virtual void SAL_CALL appendOrderByColumn( const css::uno::Reference< css::beans::XPropertySet >& column, sal_Bool ascending ) override;
+ virtual void SAL_CALL setFilter( const OUString& filter ) override;
+ virtual void SAL_CALL setOrder( const OUString& order ) override;
+ // XTablesSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getTables( ) override;
+ // XColumnsSupplier
+ virtual css::uno::Reference< css::container::XNameAccess > SAL_CALL getColumns( ) override;
+ // XParametersSupplier
+ virtual css::uno::Reference< css::container::XIndexAccess > SAL_CALL getParameters( ) override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/querycontainer.hxx b/dbaccess/source/core/inc/querycontainer.hxx
new file mode 100644
index 000000000..a04a1ddf3
--- /dev/null
+++ b/dbaccess/source/core/inc/querycontainer.hxx
@@ -0,0 +1,165 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <cppuhelper/implbase5.hxx>
+#include <connectivity/CommonTools.hxx>
+#include <rtl/ref.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/uno/Sequence.hxx>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+#include <com/sun/star/sdbcx/XDrop.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/container/XContainerApproveListener.hpp>
+
+#include "definitioncontainer.hxx"
+
+namespace dbtools
+{
+ class WarningsContainer;
+}
+
+namespace dbaccess
+{
+
+ typedef ::cppu::ImplHelper5 < css::container::XContainerListener
+ , css::container::XContainerApproveListener
+ , css::sdbcx::XDataDescriptorFactory
+ , css::sdbcx::XAppend
+ , css::sdbcx::XDrop
+ > OQueryContainer_Base;
+
+ // OQueryContainer
+ class OQueryContainer : public ODefinitionContainer
+ , public OQueryContainer_Base
+ {
+ private:
+ ::dbtools::WarningsContainer* m_pWarnings;
+ css::uno::Reference< css::container::XNameContainer >
+ m_xCommandDefinitions;
+ css::uno::Reference< css::sdbc::XConnection >
+ m_xConnection;
+ // possible actions on our "aggregate"
+ enum class AggregateAction { NONE, Inserting };
+ AggregateAction m_eDoingCurrently;
+
+ /** a class which automatically resets m_eDoingCurrently in its destructor
+ */
+ class OAutoActionReset; // just for the following friend declaration
+ friend class OAutoActionReset;
+ class OAutoActionReset
+ {
+ OQueryContainer& m_rActor;
+ public:
+ OAutoActionReset(OQueryContainer& _rActor) : m_rActor(_rActor) { }
+ ~OAutoActionReset() { m_rActor.m_eDoingCurrently = AggregateAction::NONE; }
+ };
+
+ // ODefinitionContainer
+ virtual css::uno::Reference< css::ucb::XContent > createObject( const OUString& _rName) override;
+ virtual bool checkExistence(const OUString& _rName) override;
+
+ // helper
+ virtual void SAL_CALL disposing() override;
+ virtual ~OQueryContainer() override;
+
+ /** ctor of the container. The parent has to support the <type scope="css::sdbc">XConnection</type>
+ interface.<BR>
+
+ @param _pWarnings
+ specifies a warnings container (May be <NULL/>)
+
+ Any errors which occur during the lifetime of the query container,
+ which cannot be reported as exceptions (for instance in methods where throwing an SQLException is
+ not allowed) will be appended to this container.</p>
+ <p>The caller is responsible for ensuring the lifetime of the object pointed to by this parameter.
+ */
+ OQueryContainer(
+ const css::uno::Reference< css::container::XNameContainer >& _rxCommandDefinitions,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConn,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxORB,
+ ::dbtools::WarningsContainer* _pWarnings
+ );
+
+ void init();
+
+ public:
+ static rtl::Reference<OQueryContainer> create(
+ const css::uno::Reference< css::container::XNameContainer >& _rxCommandDefinitions,
+ const css::uno::Reference< css::sdbc::XConnection >& _rxConn,
+ const css::uno::Reference< css::uno::XComponentContext >& _rxORB,
+ ::dbtools::WarningsContainer* _pWarnings
+ );
+
+ DECLARE_XINTERFACE( )
+ DECLARE_XTYPEPROVIDER( )
+ DECLARE_SERVICE_INFO();
+
+ // css::container::XContainerListener
+ virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override;
+
+ // XContainerApproveListener
+ virtual css::uno::Reference< css::util::XVeto > SAL_CALL approveInsertElement( const css::container::ContainerEvent& Event ) override;
+ virtual css::uno::Reference< css::util::XVeto > SAL_CALL approveReplaceElement( const css::container::ContainerEvent& Event ) override;
+ virtual css::uno::Reference< css::util::XVeto > SAL_CALL approveRemoveElement( const css::container::ContainerEvent& Event ) override;
+
+ // css::lang::XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ // css::sdbcx::XDataDescriptorFactory
+ virtual css::uno::Reference< css::beans::XPropertySet > SAL_CALL createDataDescriptor( ) override;
+
+ // css::sdbcx::XAppend
+ virtual void SAL_CALL appendByDescriptor( const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+
+ // css::sdbcx::XDrop
+ virtual void SAL_CALL dropByName( const OUString& elementName ) override;
+ virtual void SAL_CALL dropByIndex( sal_Int32 index ) override;
+
+ // css::container::XElementAccess
+ virtual sal_Bool SAL_CALL hasElements( ) override;
+ // css::container::XIndexAccess
+ virtual sal_Int32 SAL_CALL getCount( ) override;
+ // css::container::XNameAccess
+ virtual css::uno::Sequence< OUString > SAL_CALL getElementNames( ) override;
+
+ private:
+ // OContentHelper overridables
+ virtual OUString determineContentType() const override;
+
+ // helper
+ /** create a query object wrapping a CommandDefinition given by name. To retrieve the object, the CommandDescription
+ container will be asked for the given name.<BR>
+ The returned object is acquired once.
+ */
+ css::uno::Reference< css::ucb::XContent > implCreateWrapper(const OUString& _rName);
+ /// create a query object wrapping a CommandDefinition. The returned object is acquired once.
+ css::uno::Reference< css::ucb::XContent > implCreateWrapper(const css::uno::Reference< css::ucb::XContent >& _rxCommandDesc);
+
+ };
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/recovery/dbdocrecovery.hxx b/dbaccess/source/core/inc/recovery/dbdocrecovery.hxx
new file mode 100644
index 000000000..e5f924650
--- /dev/null
+++ b/dbaccess/source/core/inc/recovery/dbdocrecovery.hxx
@@ -0,0 +1,71 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <vector>
+#include <memory>
+
+namespace dbaccess
+{
+
+ // DatabaseDocumentRecovery
+ struct DatabaseDocumentRecovery_Data;
+ class DatabaseDocumentRecovery
+ {
+ public:
+ DatabaseDocumentRecovery(
+ const css::uno::Reference< css::uno::XComponentContext >& i_rContext
+ );
+ ~DatabaseDocumentRecovery();
+
+ /** saves the modified sub components of the given controller(s) to the "recovery" sub storage of the document
+ storage.
+
+ @throws css::uno::Exception
+ in case of an error.
+ */
+ void saveModifiedSubComponents(
+ const css::uno::Reference< css::embed::XStorage >& i_rTargetStorage,
+ const std::vector< css::uno::Reference< css::frame::XController > >& i_rControllers
+ );
+
+ /** recovery sub components from the given document storage, if applicable
+
+ If the given document storage does not contain a recovery folder, the method silently returns.
+
+ @throws css::uno::Exception
+ in case of an error.
+ */
+ void recoverSubDocuments(
+ const css::uno::Reference< css::embed::XStorage >& i_rDocumentStorage,
+ const css::uno::Reference< css::frame::XController >& i_rTargetController
+ );
+
+ private:
+ const std::unique_ptr< DatabaseDocumentRecovery_Data > m_pData;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/sdbcoretools.hxx b/dbaccess/source/core/inc/sdbcoretools.hxx
new file mode 100644
index 000000000..5b100dcf1
--- /dev/null
+++ b/dbaccess/source/core/inc/sdbcoretools.hxx
@@ -0,0 +1,55 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace dbaccess
+{
+
+ void notifyDataSourceModified(const css::uno::Reference< css::uno::XInterface >& _rxObject);
+
+ css::uno::Reference< css::uno::XInterface >
+ getDataSource( const css::uno::Reference< css::uno::XInterface >& _rxDependentObject );
+
+ /** retrieves a to-be-displayed string for a given caught exception;
+ */
+ OUString extractExceptionMessage( const css::uno::Reference< css::uno::XComponentContext >& _rContext, const css::uno::Any& _rError );
+
+ namespace tools
+ {
+ namespace stor
+ {
+ bool storageIsWritable_nothrow(
+ const css::uno::Reference< css::embed::XStorage >& _rxStorage
+ );
+
+ /// commits a given storage if it's not readonly
+ bool commitStorageIfWriteable(
+ const css::uno::Reference< css::embed::XStorage >& _rxStorage
+ );
+ }
+
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/statement.hxx b/dbaccess/source/core/inc/statement.hxx
new file mode 100644
index 000000000..f43704068
--- /dev/null
+++ b/dbaccess/source/core/inc/statement.hxx
@@ -0,0 +1,179 @@
+/* -*- 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 .
+ */
+#pragma once
+
+#include <com/sun/star/lang/XServiceInfo.hpp>
+#include <com/sun/star/sdbc/XStatement.hpp>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/util/XCancellable.hpp>
+#include <com/sun/star/sdbc/XWarningsSupplier.hpp>
+#include <com/sun/star/sdbc/XCloseable.hpp>
+#include <com/sun/star/sdbc/XMultipleResults.hpp>
+#include <com/sun/star/sdbc/XPreparedBatchExecution.hpp>
+#include <com/sun/star/sdbc/XBatchExecution.hpp>
+#include <com/sun/star/sdbc/XGeneratedResultSet.hpp>
+#include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
+#include <cppuhelper/propshlp.hxx>
+#include <comphelper/proparrhlp.hxx>
+#include <cppuhelper/basemutex.hxx>
+#include <cppuhelper/implbase3.hxx>
+#include <apitools.hxx>
+
+
+// OStatementBase
+
+class OStatementBase : public cppu::BaseMutex,
+ public OSubComponent,
+ public ::cppu::OPropertySetHelper,
+ public ::comphelper::OPropertyArrayUsageHelper < OStatementBase >,
+ public css::util::XCancellable,
+ public css::sdbc::XWarningsSupplier,
+ public css::sdbc::XPreparedBatchExecution,
+ public css::sdbc::XMultipleResults,
+ public css::sdbc::XCloseable,
+ public css::sdbc::XGeneratedResultSet
+{
+protected:
+ ::osl::Mutex m_aCancelMutex;
+
+ css::uno::WeakReferenceHelper m_aResultSet;
+ css::uno::Reference< css::beans::XPropertySet > m_xAggregateAsSet;
+ css::uno::Reference< css::util::XCancellable > m_xAggregateAsCancellable;
+ bool m_bUseBookmarks;
+ bool m_bEscapeProcessing;
+
+ virtual ~OStatementBase() override;
+
+public:
+ OStatementBase(const css::uno::Reference< css::sdbc::XConnection > & _xConn,
+ const css::uno::Reference< css::uno::XInterface > & _xStatement);
+
+
+// css::lang::XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes() override;
+
+// css::uno::XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type & rType ) override;
+ virtual void SAL_CALL acquire() noexcept override;
+ virtual void SAL_CALL release() noexcept override;
+
+// OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+// css::beans::XPropertySet
+ virtual css::uno::Reference< css::beans::XPropertySetInfo > SAL_CALL getPropertySetInfo( ) override;
+
+// comphelper::OPropertyArrayUsageHelper
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( ) const override;
+
+// cppu::OPropertySetHelper
+ virtual ::cppu::IPropertyArrayHelper& SAL_CALL getInfoHelper() override;
+
+ virtual sal_Bool SAL_CALL convertFastPropertyValue(
+ css::uno::Any & rConvertedValue,
+ css::uno::Any & rOldValue,
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue ) override;
+ virtual void SAL_CALL setFastPropertyValue_NoBroadcast(
+ sal_Int32 nHandle,
+ const css::uno::Any& rValue
+ ) override;
+ virtual void SAL_CALL getFastPropertyValue( css::uno::Any& rValue, sal_Int32 nHandle ) const override;
+
+// css::sdbc::XWarningsSupplier
+ virtual css::uno::Any SAL_CALL getWarnings( ) override;
+ virtual void SAL_CALL clearWarnings( ) override;
+
+// css::util::XCancellable
+ virtual void SAL_CALL cancel( ) override;
+
+// css::sdbc::XCloseable
+ virtual void SAL_CALL close( ) override;
+
+// css::sdbc::XMultipleResults
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getResultSet( ) override;
+ virtual sal_Int32 SAL_CALL getUpdateCount( ) override;
+ virtual sal_Bool SAL_CALL getMoreResults( ) override;
+
+// css::sdbc::XPreparedBatchExecution
+ virtual void SAL_CALL addBatch( ) override;
+ virtual void SAL_CALL clearBatch( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override;
+// css::sdbc::XGeneratedResultSet
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL getGeneratedValues( ) override;
+
+// Helper
+ void disposeResultSet();
+
+protected:
+ using ::cppu::OPropertySetHelper::getFastPropertyValue;
+};
+
+
+// OStatement
+
+typedef ::cppu::ImplHelper3 < css::sdbc::XStatement
+ , css::lang::XServiceInfo
+ , css::sdbc::XBatchExecution
+ > OStatement_IFACE;
+class OStatement :public OStatementBase
+ ,public OStatement_IFACE
+{
+private:
+ css::uno::Reference< css::sdbc::XStatement > m_xAggregateStatement;
+ css::uno::Reference< css::sdb::XSingleSelectQueryComposer > m_xComposer;
+ bool m_bAttemptedComposerCreation;
+
+public:
+ OStatement(const css::uno::Reference< css::sdbc::XConnection > & _xConn,
+ const css::uno::Reference< css::uno::XInterface > & _xStatement);
+
+ DECLARE_XINTERFACE()
+ DECLARE_XTYPEPROVIDER()
+
+// css::lang::XServiceInfo
+ virtual OUString SAL_CALL getImplementationName( ) override;
+ virtual sal_Bool SAL_CALL supportsService( const OUString& ServiceName ) override;
+ virtual css::uno::Sequence< OUString > SAL_CALL getSupportedServiceNames( ) override;
+
+// css::sdbc::XStatement
+ virtual css::uno::Reference< css::sdbc::XResultSet > SAL_CALL executeQuery( const OUString& sql ) override;
+ virtual sal_Int32 SAL_CALL executeUpdate( const OUString& sql ) override;
+ virtual sal_Bool SAL_CALL execute( const OUString& sql ) override;
+ virtual css::uno::Reference< css::sdbc::XConnection > SAL_CALL getConnection( ) override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+
+ // XBatchExecution
+ virtual void SAL_CALL addBatch( const OUString& sql ) override;
+ virtual void SAL_CALL clearBatch( ) override;
+ virtual css::uno::Sequence< sal_Int32 > SAL_CALL executeBatch( ) override;
+
+ using OStatementBase::addBatch;
+
+private:
+ /** does escape processing for the given SQL command, if the our EscapeProcessing
+ property allows so.
+ */
+ OUString impl_doEscapeProcessing_nothrow( const OUString& _rSQL ) const;
+ bool impl_ensureComposer_nothrow() const;
+};
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/table.hxx b/dbaccess/source/core/inc/table.hxx
new file mode 100644
index 000000000..8c29bff44
--- /dev/null
+++ b/dbaccess/source/core/inc/table.hxx
@@ -0,0 +1,140 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdbc/XConnection.hpp>
+
+#include "datasettings.hxx"
+#include "column.hxx"
+#include <connectivity/CommonTools.hxx>
+#include <connectivity/TTableHelper.hxx>
+#include <comphelper/IdPropArrayHelper.hxx>
+
+namespace dbaccess
+{
+
+ // OTables
+ class ODBTable;
+ class OContainerMediator;
+ typedef ::comphelper::OIdPropertyArrayUsageHelper< ODBTable > ODBTable_PROP;
+ typedef ::connectivity::OTableHelper OTable_Base;
+
+ class ODBTable :public ODataSettings_Base
+ ,public ODBTable_PROP
+ ,public OTable_Base
+ ,public IColumnFactory
+ {
+ private:
+ ::rtl::Reference< OContainerMediator > m_pColumnMediator;
+
+ protected:
+ css::uno::Reference< css::container::XNameAccess > m_xColumnDefinitions;
+ css::uno::Reference< css::container::XNameAccess > m_xDriverColumns;
+
+ // <properties>
+ sal_Int32 m_nPrivileges;
+ // </properties>
+
+ virtual ::cppu::IPropertyArrayHelper* createArrayHelper( sal_Int32 _nId) const override;
+ virtual ::cppu::IPropertyArrayHelper & SAL_CALL getInfoHelper() override;
+
+ // IColumnFactory
+ virtual rtl::Reference<OColumn> createColumn(const OUString& _rName) const override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createColumnDescriptor() override;
+ virtual void columnAppended( const css::uno::Reference< css::beans::XPropertySet >& _rxSourceDescriptor ) override;
+ virtual void columnDropped(const OUString& _sName) override;
+
+ /** creates the column collection for the table
+ @param _rNames
+ The column names.
+ */
+ virtual ::connectivity::sdbcx::OCollection* createColumns(const ::std::vector< OUString>& _rNames) override;
+
+ /** creates the key collection for the table
+ @param _rNames
+ The key names.
+ */
+ virtual ::connectivity::sdbcx::OCollection* createKeys(const ::std::vector< OUString>& _rNames) override;
+
+ /** creates the index collection for the table
+ @param _rNames
+ The index names.
+ */
+ virtual ::connectivity::sdbcx::OCollection* createIndexes(const ::std::vector< OUString>& _rNames) override;
+
+ // OComponentHelper
+ virtual void SAL_CALL disposing() override;
+ public:
+ /** constructs a wrapper supporting the com.sun.star.sdb.Table service.<BR>
+ @param _rxConn the connection the table belongs to
+ @param _rxTable the table from the driver can be null
+ @param _rCatalog the name of the catalog the table belongs to. May be empty.
+ @param _rSchema the name of the schema the table belongs to. May be empty.
+ @param _rName the name of the table
+ @param _rType the type of the table, as supplied by the driver
+ @param _rDesc the description of the table, as supplied by the driver
+ @throws css::sdbc::SQLException
+ */
+ ODBTable(connectivity::sdbcx::OCollection* _pTables
+ ,const css::uno::Reference< css::sdbc::XConnection >& _rxConn
+ ,const OUString& _rCatalog
+ , const OUString& _rSchema
+ , const OUString& _rName
+ ,const OUString& _rType
+ , const OUString& _rDesc
+ ,const css::uno::Reference< css::container::XNameAccess >& _rxColumnDefinitions);
+
+ /// @throws css::sdbc::SQLException
+ ODBTable(connectivity::sdbcx::OCollection* _pTables
+ ,const css::uno::Reference< css::sdbc::XConnection >& _rxConn);
+ virtual ~ODBTable() override;
+
+ // ODescriptor
+ virtual void construct() override;
+
+ //XInterface
+ virtual css::uno::Any SAL_CALL queryInterface( const css::uno::Type& aType ) override;
+ //XTypeProvider
+ virtual css::uno::Sequence< css::uno::Type > SAL_CALL getTypes( ) override;
+ virtual css::uno::Sequence< sal_Int8 > SAL_CALL getImplementationId() override;
+ static const css::uno::Sequence< sal_Int8 > & getUnoTunnelId();
+
+ // css::lang::XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // css::beans::XPropertySet
+ virtual void SAL_CALL getFastPropertyValue(css::uno::Any& rValue, sal_Int32 nHandle) const override;
+
+ // css::sdbcx::XRename,
+ virtual void SAL_CALL rename( const OUString& _rNewName ) override;
+
+ // css::sdbcx::XAlterTable,
+ virtual void SAL_CALL alterColumnByName( const OUString& _rName, const css::uno::Reference< css::beans::XPropertySet >& _rxDescriptor ) override;
+
+ // css::lang::XUnoTunnel
+ virtual sal_Int64 SAL_CALL getSomething( const css::uno::Sequence< sal_Int8 >& aIdentifier ) override;
+
+ private:
+ using OTable_Base::createArrayHelper;
+ using OTable_Base::getFastPropertyValue;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/tablecontainer.hxx b/dbaccess/source/core/inc/tablecontainer.hxx
new file mode 100644
index 000000000..44358e4e2
--- /dev/null
+++ b/dbaccess/source/core/inc/tablecontainer.hxx
@@ -0,0 +1,96 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <atomic>
+#include <cstddef>
+
+#include <cppuhelper/implbase1.hxx>
+#include <rtl/ref.hxx>
+#include <com/sun/star/sdbc/XConnection.hpp>
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include "FilteredContainer.hxx"
+#include "RefreshListener.hxx"
+
+namespace dbaccess
+{
+ // OTableContainer
+ class OContainerMediator;
+
+ class OTableContainer : public OFilteredContainer,
+ public ::cppu::ImplHelper1< css::container::XContainerListener>
+ {
+ css::uno::Reference< css::container::XNameContainer > m_xTableDefinitions;
+ ::rtl::Reference< OContainerMediator > m_pTableMediator;
+
+ // OFilteredContainer
+ virtual void addMasterContainerListener() override;
+ virtual void removeMasterContainerListener() override;
+ virtual OUString getTableTypeRestriction() const override;
+
+ // ::connectivity::sdbcx::OCollection
+ virtual connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual connectivity::sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+
+ virtual void disposing() override;
+
+ // css::lang::XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ // XContainerListener
+ virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override;
+
+ public:
+ virtual void SAL_CALL acquire() noexcept override { OFilteredContainer::acquire();}
+ virtual void SAL_CALL release() noexcept override { OFilteredContainer::release();}
+
+ /** ctor of the container. The parent has to support the <type scope="css::sdbc">XConnection</type>
+ interface.<BR>
+ @param _rParent the object which acts as parent for the container.
+ all refcounting is rerouted to this object
+ @param _rMutex the access safety object of the parent
+ @param _rTableFilter restricts the visible tables by name
+ @param _rTableTypeFilter restricts the visible tables by type
+ @see construct
+ */
+ OTableContainer( ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const css::uno::Reference< css::sdbc::XConnection >& _xCon,
+ bool _bCase,
+ const css::uno::Reference< css::container::XNameContainer >& _xTableDefinitions,
+ IRefreshListener* _pRefreshListener,
+ std::atomic<std::size_t>& _nInAppend
+ );
+
+ virtual ~OTableContainer() override;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/veto.hxx b/dbaccess/source/core/inc/veto.hxx
new file mode 100644
index 000000000..5608e87d1
--- /dev/null
+++ b/dbaccess/source/core/inc/veto.hxx
@@ -0,0 +1,55 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/util/XVeto.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+namespace dbaccess
+{
+
+ // Veto
+ typedef ::cppu::WeakImplHelper< css::util::XVeto
+ > Veto_Base;
+ /** implements css::util::XVeto
+ */
+ class Veto : public Veto_Base
+ {
+ private:
+ const css::uno::Any m_aDetails;
+
+ public:
+ Veto( const css::uno::Any& _rDetails );
+
+ virtual OUString SAL_CALL getReason() override;
+ virtual css::uno::Any SAL_CALL getDetails() override;
+
+ protected:
+ virtual ~Veto() override;
+
+ private:
+ Veto( const Veto& ) = delete;
+ Veto& operator=( const Veto& ) = delete;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/inc/viewcontainer.hxx b/dbaccess/source/core/inc/viewcontainer.hxx
new file mode 100644
index 000000000..2f7f48cec
--- /dev/null
+++ b/dbaccess/source/core/inc/viewcontainer.hxx
@@ -0,0 +1,94 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <sal/config.h>
+
+#include <atomic>
+#include <cstddef>
+
+#include <cppuhelper/implbase1.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XContainerListener.hpp>
+
+#include "FilteredContainer.hxx"
+
+namespace dbtools
+{
+ class WarningsContainer;
+}
+
+namespace dbaccess
+{
+ // OViewContainer
+ class OViewContainer : public OFilteredContainer,
+ public ::cppu::ImplHelper1< css::container::XContainerListener>
+ {
+ public:
+ /** ctor of the container. The parent has to support the <type scope="css::sdbc">XConnection</type>
+ interface.<BR>
+ @param _rParent the object which acts as parent for the container.
+ all refcounting is rerouted to this object
+ @param _rMutex the access safety object of the parent
+ @param _rTableFilter restricts the visible tables by name
+ @param _rTableTypeFilter restricts the visible tables by type
+ @see construct
+ */
+ OViewContainer( ::cppu::OWeakObject& _rParent,
+ ::osl::Mutex& _rMutex,
+ const css::uno::Reference< css::sdbc::XConnection >& _xCon,
+ bool _bCase,
+ IRefreshListener* _pRefreshListener,
+ std::atomic<std::size_t>& _nInAppend
+ );
+
+ virtual ~OViewContainer() override;
+
+ protected:
+ // OFilteredContainer overridables
+ virtual OUString getTableTypeRestriction() const override;
+
+ private:
+ virtual void SAL_CALL acquire() noexcept override { OFilteredContainer::acquire();}
+ virtual void SAL_CALL release() noexcept override { OFilteredContainer::release();}
+ // css::lang::XServiceInfo
+ DECLARE_SERVICE_INFO();
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+ // XContainerListener
+ virtual void SAL_CALL elementInserted( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementRemoved( const css::container::ContainerEvent& Event ) override;
+ virtual void SAL_CALL elementReplaced( const css::container::ContainerEvent& Event ) override;
+
+ // ::connectivity::sdbcx::OCollection
+ virtual ::connectivity::sdbcx::ObjectType createObject(const OUString& _rName) override;
+ virtual css::uno::Reference< css::beans::XPropertySet > createDescriptor() override;
+ virtual connectivity::sdbcx::ObjectType appendObject( const OUString& _rForName, const css::uno::Reference< css::beans::XPropertySet >& descriptor ) override;
+ virtual void dropObject(sal_Int32 _nPos, const OUString& _sElementName) override;
+
+ using OFilteredContainer::disposing;
+
+ bool m_bInElementRemoved;
+ };
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/ContainerMediator.cxx b/dbaccess/source/core/misc/ContainerMediator.cxx
new file mode 100644
index 000000000..338858c87
--- /dev/null
+++ b/dbaccess/source/core/misc/ContainerMediator.cxx
@@ -0,0 +1,231 @@
+/* -*- 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 <ContainerMediator.hxx>
+#include <PropertyForward.hxx>
+
+#include <com/sun/star/beans/PropertyAttribute.hpp>
+#include <com/sun/star/container/XNameContainer.hpp>
+#include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
+#include <com/sun/star/sdbcx/XRename.hpp>
+#include <comphelper/property.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace dbaccess
+{
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+
+OContainerMediator::OContainerMediator( const Reference< XContainer >& _xContainer, const Reference< XNameAccess >& _xSettings )
+ : m_xSettings( _xSettings )
+ , m_xContainer( _xContainer )
+{
+
+ if ( _xSettings.is() && _xContainer.is() )
+ {
+ osl_atomic_increment(&m_refCount);
+ try
+ {
+ m_xContainer->addContainerListener(this);
+ Reference< XContainer > xContainer(_xSettings, UNO_QUERY);
+ if ( xContainer.is() )
+ xContainer->addContainerListener(this);
+ }
+ catch(Exception&)
+ {
+ TOOLS_WARN_EXCEPTION("dbaccess", "OContainerMediator::OContainerMediator");
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+ else
+ {
+ m_xSettings.clear();
+ m_xContainer.clear();
+ }
+}
+
+OContainerMediator::~OContainerMediator()
+{
+ acquire();
+ impl_cleanup_nothrow();
+}
+
+void OContainerMediator::impl_cleanup_nothrow()
+{
+ try
+ {
+ Reference< XContainer > xContainer( m_xSettings, UNO_QUERY );
+ if ( xContainer.is() )
+ xContainer->removeContainerListener( this );
+ m_xSettings.clear();
+
+ xContainer = m_xContainer;
+ if ( xContainer.is() )
+ xContainer->removeContainerListener( this );
+ m_xContainer.clear();
+
+ m_aForwardList.clear();
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void SAL_CALL OContainerMediator::elementInserted( const ContainerEvent& _rEvent )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ if ( _rEvent.Source == m_xSettings && m_xSettings.is() )
+ {
+ OUString sElementName;
+ _rEvent.Accessor >>= sElementName;
+ PropertyForwardList::const_iterator aFind = m_aForwardList.find(sElementName);
+ if ( aFind != m_aForwardList.end() )
+ {
+ Reference< XPropertySet> xDest(_rEvent.Element,UNO_QUERY);
+ aFind->second->setDefinition( xDest );
+ }
+ }
+}
+
+void SAL_CALL OContainerMediator::elementRemoved( const ContainerEvent& _rEvent )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+ Reference< XContainer > xContainer = m_xContainer;
+ if ( !(_rEvent.Source == xContainer && xContainer.is()) )
+ return;
+
+ OUString sElementName;
+ _rEvent.Accessor >>= sElementName;
+ m_aForwardList.erase(sElementName);
+ try
+ {
+ Reference<XNameContainer> xNameContainer( m_xSettings, UNO_QUERY );
+ if ( xNameContainer.is() && m_xSettings->hasByName( sElementName ) )
+ xNameContainer->removeByName( sElementName );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void SAL_CALL OContainerMediator::elementReplaced( const ContainerEvent& _rEvent )
+{
+ Reference< XContainer > xContainer = m_xContainer;
+ if ( !(_rEvent.Source == xContainer && xContainer.is()) )
+ return;
+
+ OUString sElementName;
+ _rEvent.ReplacedElement >>= sElementName;
+
+ PropertyForwardList::const_iterator aFind = m_aForwardList.find(sElementName);
+ if ( aFind == m_aForwardList.end() )
+ return;
+
+ OUString sNewName;
+ _rEvent.Accessor >>= sNewName;
+ try
+ {
+ Reference<XNameContainer> xNameContainer( m_xSettings, UNO_QUERY_THROW );
+ if ( xNameContainer.is() && m_xSettings->hasByName( sElementName ) )
+ {
+ Reference<XRename> xSource(m_xSettings->getByName(sElementName),UNO_QUERY_THROW);
+ xSource->rename(sNewName);
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ aFind->second->setName(sNewName);
+}
+
+void SAL_CALL OContainerMediator::disposing( const EventObject& /*Source*/ )
+{
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ impl_cleanup_nothrow();
+}
+
+void OContainerMediator::impl_initSettings_nothrow( const OUString& _rName, const Reference< XPropertySet >& _rxDestination )
+{
+ try
+ {
+ if ( m_xSettings.is() && m_xSettings->hasByName( _rName ) )
+ {
+ Reference< XPropertySet > xSettings( m_xSettings->getByName( _rName ), UNO_QUERY_THROW );
+ ::comphelper::copyProperties( xSettings, _rxDestination );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+}
+
+void OContainerMediator::notifyElementCreated( const OUString& _sName, const Reference< XPropertySet >& _xDest )
+{
+ if ( !m_xSettings.is() )
+ return;
+
+ PropertyForwardList::const_iterator aFind = m_aForwardList.find( _sName );
+ if ( aFind != m_aForwardList.end()
+ && aFind->second->getDefinition().is()
+ )
+ {
+ OSL_FAIL( "OContainerMediator::notifyElementCreated: is this really a valid case?" );
+ return;
+ }
+
+ std::vector< OUString > aPropertyList;
+ try
+ {
+ // initially copy from the settings object (if existent) to the newly created object
+ impl_initSettings_nothrow( _sName, _xDest );
+
+ // collect the to-be-monitored properties
+ Reference< XPropertySetInfo > xPSI( _xDest->getPropertySetInfo(), UNO_SET_THROW );
+ const Sequence< Property > aProperties( xPSI->getProperties() );
+ for ( auto const & property : aProperties )
+ {
+ if ( ( property.Attributes & PropertyAttribute::READONLY ) != 0 )
+ continue;
+ if ( ( property.Attributes & PropertyAttribute::BOUND ) == 0 )
+ continue;
+
+ aPropertyList.push_back( property.Name );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ ::rtl::Reference pForward( new OPropertyForward( _xDest, m_xSettings, _sName, aPropertyList ) );
+ m_aForwardList[ _sName ] = pForward;
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/DatabaseDataProvider.cxx b/dbaccess/source/core/misc/DatabaseDataProvider.cxx
new file mode 100644
index 000000000..8695d518c
--- /dev/null
+++ b/dbaccess/source/core/misc/DatabaseDataProvider.cxx
@@ -0,0 +1,1066 @@
+/* -*- 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 <DatabaseDataProvider.hxx>
+#include <strings.hxx>
+#include <cppuhelper/supportsservice.hxx>
+#include <comphelper/types.hxx>
+#include <comphelper/namedvaluecollection.hxx>
+#include <connectivity/FValue.hxx>
+#include <sal/macros.h>
+#include <tools/diagnose_ex.h>
+
+#include <com/sun/star/task/XInteractionHandler.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+#include <com/sun/star/sdbc/DataType.hpp>
+#include <com/sun/star/sdbc/XRow.hpp>
+#include <com/sun/star/sdbc/XResultSet.hpp>
+#include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
+#include <com/sun/star/sdbc/XColumnLocate.hpp>
+#include <com/sun/star/beans/NamedValue.hpp>
+#include <com/sun/star/chart/ChartDataRowSource.hpp>
+#include <com/sun/star/chart/XChartDataArray.hpp>
+
+#include <vector>
+
+// TODO: update for new HavingClause-aware FilterManager
+
+namespace dbaccess
+{
+using namespace ::com::sun::star;
+using ::com::sun::star::uno::Reference;
+
+DatabaseDataProvider::DatabaseDataProvider(uno::Reference< uno::XComponentContext > const & context) :
+ TDatabaseDataProvider(m_aMutex),
+ ::cppu::PropertySetMixin< chart2::data::XDatabaseDataProvider >(
+ context, IMPLEMENTS_PROPERTY_SET, uno::Sequence< OUString >()),
+ m_aParameterManager( m_aMutex, context ),
+ m_xContext(context),
+ m_CommandType(sdb::CommandType::COMMAND), // #i94114
+ m_RowLimit(0),
+ m_EscapeProcessing(true),
+ m_ApplyFilter(true)
+{
+ m_xInternal.set( m_xContext->getServiceManager()->createInstanceWithContext("com.sun.star.comp.chart.InternalDataProvider",m_xContext ), uno::UNO_QUERY );
+ m_xRangeConversion.set(m_xInternal,uno::UNO_QUERY);
+ m_xComplexDescriptionAccess.set(m_xInternal,uno::UNO_QUERY);
+
+ osl_atomic_increment( &m_refCount );
+ {
+ m_xRowSet.set( m_xContext->getServiceManager()->createInstanceWithContext(SERVICE_SDB_ROWSET,m_xContext ), uno::UNO_QUERY );
+ m_xAggregate.set(m_xRowSet,uno::UNO_QUERY);
+ m_xAggregateSet.set(m_xRowSet,uno::UNO_QUERY);
+ uno::Reference<beans::XPropertySet> xProp(static_cast< ::cppu::OWeakObject* >( this ),uno::UNO_QUERY);
+ m_aFilterManager.initialize( m_xAggregateSet );
+ m_aParameterManager.initialize( xProp, m_xAggregate );
+ m_xAggregateSet->setPropertyValue(PROPERTY_COMMAND_TYPE,uno::Any(m_CommandType));
+ m_xAggregateSet->setPropertyValue(PROPERTY_ESCAPE_PROCESSING,uno::Any(m_EscapeProcessing));
+ }
+ osl_atomic_decrement( &m_refCount );
+}
+
+void SAL_CALL DatabaseDataProvider::disposing()
+{
+ m_aParameterManager.dispose(); // (to free any references it may have to me)
+ m_aFilterManager.dispose(); // (ditto)
+
+ m_xParent.clear();
+ m_xAggregateSet.clear();
+ m_xAggregate.clear();
+ m_xRangeConversion.clear();
+ ::comphelper::disposeComponent(m_xRowSet);
+ ::comphelper::disposeComponent(m_xInternal);
+ m_xActiveConnection.clear();
+}
+
+uno::Any DatabaseDataProvider::queryInterface(uno::Type const & type)
+{
+ return TDatabaseDataProvider::queryInterface(type);
+}
+
+// XServiceInfo
+OUString SAL_CALL DatabaseDataProvider::getImplementationName( )
+{
+ return "com.sun.star.comp.dbaccess.DatabaseDataProvider";
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::supportsService( const OUString& _rServiceName )
+{
+ return cppu::supportsService(this, _rServiceName);
+}
+
+uno::Sequence< OUString > SAL_CALL DatabaseDataProvider::getSupportedServiceNames( )
+{
+ return { "com.sun.star.chart2.data.DatabaseDataProvider" };
+}
+
+// lang::XInitialization:
+void SAL_CALL DatabaseDataProvider::initialize(const uno::Sequence< uno::Any > & aArguments)
+{
+ osl::MutexGuard g(m_aMutex);
+ const uno::Any* pIter = aArguments.getConstArray();
+ const uno::Any* pEnd = pIter + aArguments.getLength();
+ for(;pIter != pEnd;++pIter)
+ {
+ if ( !m_xActiveConnection.is() )
+ (*pIter) >>= m_xActiveConnection;
+ else if ( !m_xHandler.is() )
+ (*pIter) >>= m_xHandler;
+ }
+ m_xAggregateSet->setPropertyValue( PROPERTY_ACTIVE_CONNECTION, uno::Any( m_xActiveConnection ) );
+}
+
+// chart2::data::XDataProvider:
+sal_Bool SAL_CALL DatabaseDataProvider::createDataSourcePossible(const uno::Sequence< beans::PropertyValue > & _aArguments)
+{
+ const beans::PropertyValue* pArgIter = _aArguments.getConstArray();
+ const beans::PropertyValue* pArgEnd = pArgIter + _aArguments.getLength();
+ for(;pArgIter != pArgEnd;++pArgIter)
+ {
+ if ( pArgIter->Name == "DataRowSource" )
+ {
+ css::chart::ChartDataRowSource eRowSource = css::chart::ChartDataRowSource_COLUMNS;
+ pArgIter->Value >>= eRowSource;
+ if ( eRowSource != css::chart::ChartDataRowSource_COLUMNS )
+ return false;
+ }
+ else if ( pArgIter->Name == "CellRangeRepresentation" )
+ {
+ OUString sRange;
+ pArgIter->Value >>= sRange;
+ if ( sRange != "all" )
+ return false;
+ }
+ else if ( pArgIter->Name == "FirstCellAsLabel" )
+ {
+ bool bFirstCellAsLabel = true;
+ pArgIter->Value >>= bFirstCellAsLabel;
+ if ( !bFirstCellAsLabel )
+ return false;
+ }
+ }
+ return true;
+}
+
+uno::Reference< chart2::data::XDataSource > SAL_CALL DatabaseDataProvider::createDataSource(const uno::Sequence< beans::PropertyValue > & _aArguments)
+{
+ osl::ResettableMutexGuard aClearForNotifies(m_aMutex);
+ if ( createDataSourcePossible(_aArguments) )
+ {
+ try
+ {
+ uno::Reference< chart::XChartDataArray> xChartData( m_xInternal, uno::UNO_QUERY_THROW );
+ xChartData->setData( uno::Sequence< uno::Sequence< double > >() );
+ xChartData->setColumnDescriptions( uno::Sequence< OUString >() );
+ if ( m_xInternal->hasDataByRangeRepresentation( OUString::number( 0 ) ) )
+ m_xInternal->deleteSequence(0);
+ }
+ catch( const uno::Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ ::comphelper::NamedValueCollection aArgs( _aArguments );
+ const bool bHasCategories = aArgs.getOrDefault( "HasCategories", true );
+ uno::Sequence< OUString > aColumnNames =
+ aArgs.getOrDefault( "ColumnDescriptions", uno::Sequence< OUString >() );
+
+ bool bRet = false;
+ if ( !m_Command.isEmpty() && m_xActiveConnection.is() )
+ {
+ try
+ {
+ impl_fillRowSet_throw();
+ if ( impl_fillParameters_nothrow(aClearForNotifies) )
+ m_xRowSet->execute();
+ impl_fillInternalDataProvider_throw(bHasCategories,aColumnNames);
+ bRet = true;
+ }
+ catch(const uno::Exception& /*e*/)
+ {
+ }
+ }
+ if ( !bRet ) // no command set or an error occurred, use Internal data handler
+ {
+ uno::Reference< lang::XInitialization> xIni(m_xInternal,uno::UNO_QUERY);
+ if ( xIni.is() )
+ {
+ beans::NamedValue aParam("CreateDefaultData",uno::Any(true));
+ uno::Sequence< uno::Any > aInitArgs{ uno::Any(aParam) };
+ xIni->initialize(aInitArgs);
+ }
+ }
+
+ }
+ return m_xInternal->createDataSource(_aArguments);
+}
+
+uno::Sequence< beans::PropertyValue > SAL_CALL DatabaseDataProvider::detectArguments(const uno::Reference< chart2::data::XDataSource > & _xDataSource)
+{
+ ::comphelper::NamedValueCollection aArguments;
+ aArguments.put( "CellRangeRepresentation", uno::Any( OUString( "all" ) ) );
+ aArguments.put( "DataRowSource", uno::Any( chart::ChartDataRowSource_COLUMNS ) );
+ // internal data always contains labels
+ aArguments.put( "FirstCellAsLabel", uno::Any( true ) );
+
+ bool bHasCategories = false;
+ if( _xDataSource.is())
+ {
+ uno::Sequence< uno::Reference< chart2::data::XLabeledDataSequence > > aSequences(_xDataSource->getDataSequences());
+ const sal_Int32 nCount( aSequences.getLength());
+ for( sal_Int32 nIdx=0; nIdx<nCount; ++nIdx )
+ {
+ if( aSequences[nIdx].is() )
+ {
+ uno::Reference< beans::XPropertySet > xSeqProp( aSequences[nIdx]->getValues(), uno::UNO_QUERY );
+ OUString aRole;
+ if ( xSeqProp.is()
+ && ( xSeqProp->getPropertyValue( "Role" ) >>= aRole )
+ && aRole == "categories"
+ )
+ {
+ bHasCategories = true;
+ break;
+ }
+ }
+ }
+ }
+ aArguments.put( "HasCategories", uno::Any( bHasCategories ) );
+ return aArguments.getPropertyValues();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::createDataSequenceByRangeRepresentationPossible(const OUString & /*aRangeRepresentation*/)
+{
+ return true;
+}
+
+uno::Any DatabaseDataProvider::impl_getNumberFormatKey_nothrow(const OUString & _sRangeRepresentation) const
+{
+ std::map< OUString,css::uno::Any>::const_iterator aFind = m_aNumberFormats.find(_sRangeRepresentation);
+ if ( aFind != m_aNumberFormats.end() )
+ return aFind->second;
+ return uno::Any(sal_Int32(0));
+}
+
+uno::Reference< chart2::data::XDataSequence > SAL_CALL DatabaseDataProvider::createDataSequenceByRangeRepresentation(const OUString & _sRangeRepresentation)
+{
+ osl::MutexGuard g(m_aMutex);
+ uno::Reference< chart2::data::XDataSequence > xData = m_xInternal->createDataSequenceByRangeRepresentation(_sRangeRepresentation);
+ uno::Reference<beans::XPropertySet> xProp(xData,uno::UNO_QUERY);
+ static constexpr OUStringLiteral s_sNumberFormatKey = u"NumberFormatKey";
+ if ( xProp.is() && xProp->getPropertySetInfo()->hasPropertyByName(s_sNumberFormatKey) )
+ {
+ xProp->setPropertyValue(s_sNumberFormatKey,impl_getNumberFormatKey_nothrow(_sRangeRepresentation));
+ }
+ return xData;
+}
+
+uno::Reference<chart2::data::XDataSequence>
+SAL_CALL DatabaseDataProvider::createDataSequenceByValueArray(
+ const OUString& /*aRole*/, const OUString& /*aRangeRepresentation*/, const OUString& /*aRoleQualifier*/ )
+{
+ return uno::Reference<chart2::data::XDataSequence>();
+}
+
+uno::Sequence< uno::Sequence< OUString > > SAL_CALL DatabaseDataProvider::getComplexRowDescriptions()
+{
+ return m_xComplexDescriptionAccess->getComplexRowDescriptions();
+}
+
+void SAL_CALL DatabaseDataProvider::setComplexRowDescriptions( const uno::Sequence< uno::Sequence< OUString > >& aRowDescriptions )
+{
+ m_xComplexDescriptionAccess->setComplexRowDescriptions(aRowDescriptions);
+}
+
+uno::Sequence< uno::Sequence< OUString > > SAL_CALL DatabaseDataProvider::getComplexColumnDescriptions()
+{
+ return m_xComplexDescriptionAccess->getComplexColumnDescriptions();
+}
+
+void SAL_CALL DatabaseDataProvider::setComplexColumnDescriptions( const uno::Sequence< uno::Sequence< OUString > >& aColumnDescriptions )
+{
+ m_xComplexDescriptionAccess->setComplexColumnDescriptions(aColumnDescriptions);
+}
+
+// ____ XChartDataArray ____
+uno::Sequence< uno::Sequence< double > > SAL_CALL DatabaseDataProvider::getData()
+{
+ return m_xComplexDescriptionAccess->getData();
+}
+
+void SAL_CALL DatabaseDataProvider::setData( const uno::Sequence< uno::Sequence< double > >& rDataInRows )
+{
+ m_xComplexDescriptionAccess->setData(rDataInRows);
+}
+
+void SAL_CALL DatabaseDataProvider::setRowDescriptions( const uno::Sequence< OUString >& aRowDescriptions )
+{
+ m_xComplexDescriptionAccess->setRowDescriptions(aRowDescriptions);
+}
+
+void SAL_CALL DatabaseDataProvider::setColumnDescriptions( const uno::Sequence< OUString >& aColumnDescriptions )
+{
+ m_xComplexDescriptionAccess->setColumnDescriptions(aColumnDescriptions);
+}
+
+uno::Sequence< OUString > SAL_CALL DatabaseDataProvider::getRowDescriptions()
+{
+ return m_xComplexDescriptionAccess->getRowDescriptions();
+}
+
+uno::Sequence< OUString > SAL_CALL DatabaseDataProvider::getColumnDescriptions()
+{
+ return m_xComplexDescriptionAccess->getColumnDescriptions();
+}
+
+// ____ XChartData (base of XChartDataArray) ____
+void SAL_CALL DatabaseDataProvider::addChartDataChangeEventListener(const uno::Reference< css::chart::XChartDataChangeEventListener >& x)
+{
+ m_xComplexDescriptionAccess->addChartDataChangeEventListener(x);
+}
+
+void SAL_CALL DatabaseDataProvider::removeChartDataChangeEventListener(const uno::Reference< css::chart::XChartDataChangeEventListener >& x)
+{
+ m_xComplexDescriptionAccess->removeChartDataChangeEventListener(x);
+}
+
+double SAL_CALL DatabaseDataProvider::getNotANumber()
+{
+ return m_xComplexDescriptionAccess->getNotANumber();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::isNotANumber( double nNumber )
+{
+ return m_xComplexDescriptionAccess->isNotANumber(nNumber);
+}
+
+uno::Reference< sheet::XRangeSelection > SAL_CALL DatabaseDataProvider::getRangeSelection()
+{
+ // TODO: Exchange the default return implementation for "getRangeSelection" !!!
+ // Exchange the default return implementation.
+ // NOTE: Default initialized polymorphic structs can cause problems because of
+ // missing default initialization of primitive types of some C++ compilers or
+ // different Any initialization in Java and C++ polymorphic structs.
+ return uno::Reference< sheet::XRangeSelection >();
+}
+
+// chart2::data::XRangeXMLConversion:
+OUString SAL_CALL DatabaseDataProvider::convertRangeToXML(const OUString & _sRangeRepresentation)
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_xRangeConversion->convertRangeToXML(_sRangeRepresentation);
+}
+
+OUString SAL_CALL DatabaseDataProvider::convertRangeFromXML(const OUString & _sXMLRange)
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_xRangeConversion->convertRangeFromXML(_sXMLRange);
+}
+
+// com.sun.star.beans.XPropertySet:
+uno::Reference< beans::XPropertySetInfo > SAL_CALL DatabaseDataProvider::getPropertySetInfo()
+{
+ return ::cppu::PropertySetMixin< chart2::data::XDatabaseDataProvider >::getPropertySetInfo();
+}
+
+void SAL_CALL DatabaseDataProvider::setPropertyValue(const OUString & aPropertyName, const uno::Any & aValue)
+{
+ ::cppu::PropertySetMixin< chart2::data::XDatabaseDataProvider >::setPropertyValue(aPropertyName, aValue);
+}
+
+uno::Any SAL_CALL DatabaseDataProvider::getPropertyValue(const OUString & aPropertyName)
+{
+ return ::cppu::PropertySetMixin< chart2::data::XDatabaseDataProvider >::getPropertyValue(aPropertyName);
+}
+
+void SAL_CALL DatabaseDataProvider::addPropertyChangeListener(const OUString & aPropertyName, const uno::Reference< beans::XPropertyChangeListener > & xListener)
+{
+ ::cppu::PropertySetMixin< chart2::data::XDatabaseDataProvider >::addPropertyChangeListener(aPropertyName, xListener);
+}
+
+void SAL_CALL DatabaseDataProvider::removePropertyChangeListener(const OUString & aPropertyName, const uno::Reference< beans::XPropertyChangeListener > & xListener)
+{
+ ::cppu::PropertySetMixin< chart2::data::XDatabaseDataProvider >::removePropertyChangeListener(aPropertyName, xListener);
+}
+
+void SAL_CALL DatabaseDataProvider::addVetoableChangeListener(const OUString & aPropertyName, const uno::Reference< beans::XVetoableChangeListener > & xListener)
+{
+ ::cppu::PropertySetMixin< chart2::data::XDatabaseDataProvider >::addVetoableChangeListener(aPropertyName, xListener);
+}
+
+void SAL_CALL DatabaseDataProvider::removeVetoableChangeListener(const OUString & aPropertyName, const uno::Reference< beans::XVetoableChangeListener > & xListener)
+{
+ ::cppu::PropertySetMixin< chart2::data::XDatabaseDataProvider >::removeVetoableChangeListener(aPropertyName, xListener);
+}
+
+// chart2::data::XDatabaseDataProvider:
+uno::Sequence< OUString > SAL_CALL DatabaseDataProvider::getMasterFields()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_MasterFields;
+}
+
+void SAL_CALL DatabaseDataProvider::setMasterFields(const uno::Sequence< OUString > & the_value)
+{
+ impl_invalidateParameter_nothrow();
+ set("MasterFields",the_value,m_MasterFields);
+}
+
+uno::Sequence< OUString > SAL_CALL DatabaseDataProvider::getDetailFields()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_DetailFields;
+}
+
+void SAL_CALL DatabaseDataProvider::setDetailFields(const uno::Sequence< OUString > & the_value)
+{
+ set("DetailFields",the_value,m_DetailFields);
+}
+
+OUString SAL_CALL DatabaseDataProvider::getCommand()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_Command;
+}
+
+void SAL_CALL DatabaseDataProvider::setCommand(const OUString & the_value)
+{
+ {
+ osl::MutexGuard g(m_aMutex);
+ impl_invalidateParameter_nothrow();
+ m_xAggregateSet->setPropertyValue( PROPERTY_COMMAND, uno::Any( the_value ) );
+ }
+ set(PROPERTY_COMMAND,the_value,m_Command);
+}
+
+::sal_Int32 SAL_CALL DatabaseDataProvider::getCommandType()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_CommandType;
+}
+
+void SAL_CALL DatabaseDataProvider::setCommandType(::sal_Int32 the_value)
+{
+ {
+ osl::MutexGuard g(m_aMutex);
+ m_xAggregateSet->setPropertyValue( PROPERTY_COMMAND_TYPE, uno::Any( the_value ) );
+ }
+ set(PROPERTY_COMMAND_TYPE,the_value,m_CommandType);
+}
+
+OUString SAL_CALL DatabaseDataProvider::getFilter()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_aFilterManager.getFilterComponent( dbtools::FilterManager::FilterComponent::PublicFilter );
+}
+
+void SAL_CALL DatabaseDataProvider::setFilter(const OUString & the_value)
+{
+ {
+ osl::MutexGuard g(m_aMutex);
+ m_aFilterManager.setFilterComponent( dbtools::FilterManager::FilterComponent::PublicFilter, the_value );
+ }
+ set(PROPERTY_FILTER,the_value,m_Filter);
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::getApplyFilter()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_ApplyFilter;
+}
+
+void SAL_CALL DatabaseDataProvider::setApplyFilter( sal_Bool the_value )
+{
+ {
+ osl::MutexGuard g(m_aMutex);
+ m_xAggregateSet->setPropertyValue( PROPERTY_APPLYFILTER, uno::Any( the_value ) );
+ }
+ set(PROPERTY_APPLYFILTER,static_cast<bool>(the_value),m_ApplyFilter);
+}
+
+OUString SAL_CALL DatabaseDataProvider::getHavingClause()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_HavingClause;
+}
+
+void SAL_CALL DatabaseDataProvider::setHavingClause( const OUString& the_value )
+{
+ {
+ osl::MutexGuard g(m_aMutex);
+ m_xAggregateSet->setPropertyValue( PROPERTY_HAVING_CLAUSE, uno::Any( the_value ) );
+ }
+ set(PROPERTY_HAVING_CLAUSE,the_value,m_HavingClause);
+}
+
+OUString SAL_CALL DatabaseDataProvider::getGroupBy()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_GroupBy;
+}
+
+void SAL_CALL DatabaseDataProvider::setGroupBy( const OUString& the_value )
+{
+ {
+ osl::MutexGuard g(m_aMutex);
+ m_xAggregateSet->setPropertyValue( PROPERTY_GROUP_BY, uno::Any( the_value ) );
+ }
+ set(PROPERTY_GROUP_BY,the_value,m_GroupBy);
+}
+
+OUString SAL_CALL DatabaseDataProvider::getOrder()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_Order;
+}
+
+void SAL_CALL DatabaseDataProvider::setOrder( const OUString& the_value )
+{
+ {
+ osl::MutexGuard g(m_aMutex);
+ m_xAggregateSet->setPropertyValue( PROPERTY_ORDER, uno::Any( the_value ) );
+ }
+ set(PROPERTY_ORDER,the_value,m_Order);
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::getEscapeProcessing()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_EscapeProcessing;
+}
+
+void SAL_CALL DatabaseDataProvider::setEscapeProcessing(sal_Bool the_value)
+{
+ set(PROPERTY_ESCAPE_PROCESSING,static_cast<bool>(the_value),m_EscapeProcessing);
+}
+
+::sal_Int32 SAL_CALL DatabaseDataProvider::getRowLimit()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_RowLimit;
+}
+
+void SAL_CALL DatabaseDataProvider::setRowLimit(::sal_Int32 the_value)
+{
+ set("RowLimit",the_value,m_RowLimit);
+}
+
+uno::Reference< sdbc::XConnection > SAL_CALL DatabaseDataProvider::getActiveConnection()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_xActiveConnection;
+}
+
+void SAL_CALL DatabaseDataProvider::setActiveConnection(const uno::Reference< sdbc::XConnection > & the_value)
+{
+ if ( !the_value.is() )
+ throw lang::IllegalArgumentException();
+ set(PROPERTY_ACTIVE_CONNECTION,the_value,m_xActiveConnection);
+}
+
+OUString SAL_CALL DatabaseDataProvider::getDataSourceName()
+{
+ osl::MutexGuard g(m_aMutex);
+ return m_DataSourceName;
+}
+
+void SAL_CALL DatabaseDataProvider::setDataSourceName(const OUString& the_value)
+{
+ set(PROPERTY_DATASOURCENAME,the_value,m_DataSourceName);
+}
+
+namespace
+{
+ struct ColumnDescription
+ {
+ OUString sName;
+ sal_Int32 nResultSetPosition;
+ sal_Int32 nDataType;
+
+ ColumnDescription()
+ :nResultSetPosition( 0 )
+ ,nDataType( sdbc::DataType::VARCHAR )
+ {
+ }
+ explicit ColumnDescription( const OUString& i_rName )
+ :sName( i_rName )
+ ,nResultSetPosition( 0 )
+ ,nDataType( sdbc::DataType::VARCHAR )
+ {
+ }
+ };
+
+ struct CreateColumnDescription
+ {
+ ColumnDescription operator()( const OUString& i_rName )
+ {
+ return ColumnDescription( i_rName );
+ }
+ };
+
+ struct SelectColumnName
+ {
+ const OUString& operator()( const ColumnDescription& i_rColumn )
+ {
+ return i_rColumn.sName;
+ }
+ };
+}
+
+void DatabaseDataProvider::impl_fillInternalDataProvider_throw(bool _bHasCategories,const uno::Sequence< OUString >& i_aColumnNames)
+{
+ // clear the data before fill the new one
+ uno::Reference< sdbcx::XColumnsSupplier > xColSup(m_xRowSet,uno::UNO_QUERY_THROW);
+ uno::Reference< container::XNameAccess > xColumns( xColSup->getColumns(), uno::UNO_SET_THROW );
+ const uno::Sequence< OUString > aRowSetColumnNames( xColumns->getElementNames() );
+
+ typedef std::vector< ColumnDescription > ColumnDescriptions;
+ ColumnDescriptions aColumns;
+ bool bFirstColumnIsCategory = _bHasCategories;
+ if ( i_aColumnNames.hasElements() )
+ {
+ // some normalizations ...
+ uno::Sequence< OUString > aImposedColumnNames( i_aColumnNames );
+
+ // strangely, there exist documents where the ColumnDescriptions end with a number of empty strings. /me
+ // thinks they're generated when you have a chart based on a result set with n columns, but remove some
+ // of those columns from the chart - it looks like a bug in the report XML export to me.
+ // So, get rid of the "trailing" empty columns
+ sal_Int32 nLastNonEmptyColName = aImposedColumnNames.getLength() - 1;
+ for ( ; nLastNonEmptyColName >= 0; --nLastNonEmptyColName )
+ {
+ if ( !aImposedColumnNames[ nLastNonEmptyColName ].isEmpty() )
+ break;
+ }
+ aImposedColumnNames.realloc( nLastNonEmptyColName + 1 );
+
+ // second, for X-Y-charts the ColumnDescriptions exported by chart miss the name of the first (non-category)
+ // column. This, this results in a ColumnDescriptions array like <"", "col2", "col3">, where you'd expect
+ // <"col1", "col2", "col3">.
+ // Fix this with some heuristics:
+ if ( aImposedColumnNames.hasElements() && ( !aImposedColumnNames[0].isEmpty() ) )
+ {
+ const sal_Int32 nAssumedRowSetColumnIndex = _bHasCategories ? 1 : 0;
+ if ( nAssumedRowSetColumnIndex < aRowSetColumnNames.getLength() )
+ aImposedColumnNames.getArray()[0] = aRowSetColumnNames[ nAssumedRowSetColumnIndex ];
+ }
+
+ const sal_Int32 nCount = aImposedColumnNames.getLength();
+ for ( sal_Int32 i = 0 ; i < nCount; ++i )
+ {
+ const OUString sColumnName( aImposedColumnNames[i] );
+ if ( !xColumns->hasByName( sColumnName ) )
+ continue;
+
+ if ( _bHasCategories && aColumns.empty() )
+ {
+ if ( aRowSetColumnNames.hasElements() )
+ aColumns.emplace_back( aRowSetColumnNames[0] );
+ else
+ aColumns.emplace_back( sColumnName );
+ bFirstColumnIsCategory = true;
+ }
+ aColumns.emplace_back( sColumnName );
+ }
+ }
+ if ( aColumns.empty() )
+ {
+ aColumns.resize( aRowSetColumnNames.getLength() );
+ std::transform(
+ aRowSetColumnNames.begin(),
+ aRowSetColumnNames.end(),
+ aColumns.begin(),
+ CreateColumnDescription()
+ );
+ }
+
+ // fill the data
+ uno::Reference< sdbc::XResultSet> xRes( m_xRowSet, uno::UNO_QUERY_THROW );
+ uno::Reference< sdbc::XRow> xRow( m_xRowSet,uno::UNO_QUERY_THROW );
+ uno::Reference< sdbc::XResultSetMetaDataSupplier > xSuppMeta( m_xRowSet,uno::UNO_QUERY_THROW );
+ uno::Reference< sdbc::XColumnLocate > xColumnLocate( m_xRowSet, uno::UNO_QUERY_THROW );
+
+ sal_Int32 columnIndex = 0;
+ for (auto & column : aColumns)
+ {
+ column.nResultSetPosition = xColumnLocate->findColumn( column.sName );
+
+ const uno::Reference< beans::XPropertySet > xColumn( xColumns->getByName( column.sName ), uno::UNO_QUERY_THROW );
+ const uno::Any aNumberFormat( xColumn->getPropertyValue( PROPERTY_NUMBERFORMAT ) );
+ OSL_VERIFY( xColumn->getPropertyValue( PROPERTY_TYPE ) >>= column.nDataType );
+
+ const OUString sRangeName = OUString::number( columnIndex );
+ m_aNumberFormats.emplace( sRangeName, aNumberFormat );
+ ++columnIndex;
+ }
+
+ std::vector< OUString > aRowLabels;
+ std::vector< std::vector< double > > aDataValues;
+ sal_Int32 nRowCount = 0;
+ ::connectivity::ORowSetValue aValue;
+ while( xRes->next() && (!m_RowLimit || nRowCount < m_RowLimit) )
+ {
+ ++nRowCount;
+
+ aValue.fill( aColumns[0].nResultSetPosition, aColumns[0].nDataType, xRow );
+ aRowLabels.push_back( aValue.getString() );
+
+ std::vector< double > aRow;
+ bool bFirstLoop = true;
+ for (auto const& column : aColumns)
+ {
+ if (bFirstLoop)
+ {
+ bFirstLoop = false;
+ if (bFirstColumnIsCategory)
+ continue;
+ }
+
+ aValue.fill( column.nResultSetPosition, column.nDataType, xRow );
+ if ( aValue.isNull() )
+ aRow.push_back( std::numeric_limits<double>::quiet_NaN() );
+ else
+ aRow.push_back( aValue.getDouble() );
+ }
+
+ aDataValues.push_back( aRow );
+ }
+
+ // insert default data when no rows exist
+ if ( !nRowCount )
+ {
+ nRowCount = 3;
+ static const double fDefaultData[ ] =
+ { 9.10, 3.20, 4.54,
+ 2.40, 8.80, 9.65,
+ 3.10, 1.50, 3.70,
+ 4.30, 9.02, 6.20 };
+ for(sal_Int32 h = 0,k = 0; h < nRowCount; ++h,++k )
+ {
+ aRowLabels.push_back(OUString::number(h+1));
+ std::vector< double > aRow;
+ const sal_Int32 nSize = SAL_N_ELEMENTS(fDefaultData);
+ for (size_t j = 0; j < (aColumns.size()-1); ++j,++k)
+ {
+ if ( k >= nSize )
+ k = 0;
+ aRow.push_back(fDefaultData[k]);
+ }
+ aDataValues.push_back(aRow);
+ }
+ }
+
+ uno::Reference< chart::XChartDataArray> xData(m_xInternal,uno::UNO_QUERY);
+ xData->setRowDescriptions(comphelper::containerToSequence(aRowLabels));
+
+ const size_t nOffset = bFirstColumnIsCategory ? 1 : 0;
+ uno::Sequence< OUString > aColumnDescriptions( aColumns.size() - nOffset );
+ std::transform(
+ aColumns.begin() + nOffset,
+ aColumns.end(),
+ aColumnDescriptions.getArray(),
+ SelectColumnName()
+ );
+ xData->setColumnDescriptions( aColumnDescriptions );
+
+ uno::Sequence< uno::Sequence< double > > aData(aDataValues.size());
+ uno::Sequence< double >* pDataIter = aData.getArray();
+ uno::Sequence< double >* pDataEnd = pDataIter + aData.getLength();
+ for(sal_Int32 i= 0;pDataIter != pDataEnd; ++pDataIter,++i )
+ {
+ if ( !aDataValues[i].empty() )
+ *pDataIter = comphelper::containerToSequence(aDataValues[i]);
+ }
+ xData->setData(aData);
+}
+
+void DatabaseDataProvider::impl_fillRowSet_throw()
+{
+ m_xAggregateSet->setPropertyValue( PROPERTY_FILTER, uno::Any( getFilter() ) );
+ uno::Reference< sdbc::XParameters> xParam(m_xRowSet,uno::UNO_QUERY_THROW);
+ xParam->clearParameters( );
+}
+
+bool DatabaseDataProvider::impl_fillParameters_nothrow( ::osl::ResettableMutexGuard& _rClearForNotifies)
+{
+ // do we have to fill the parameters again?
+ if ( !m_aParameterManager.isUpToDate() )
+ m_aParameterManager.updateParameterInfo( m_aFilterManager );
+
+ if ( m_aParameterManager.isUpToDate() )
+ return m_aParameterManager.fillParameterValues( m_xHandler, _rClearForNotifies );
+
+ return true;
+}
+
+// css::sdbc::XParameters
+void SAL_CALL DatabaseDataProvider::setNull(sal_Int32 parameterIndex, sal_Int32 sqlType)
+{
+ m_aParameterManager.setNull(parameterIndex, sqlType);
+}
+
+void SAL_CALL DatabaseDataProvider::setObjectNull(sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& typeName)
+{
+ m_aParameterManager.setObjectNull(parameterIndex, sqlType, typeName);
+}
+
+void SAL_CALL DatabaseDataProvider::setBoolean(sal_Int32 parameterIndex, sal_Bool x)
+{
+ m_aParameterManager.setBoolean(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setByte(sal_Int32 parameterIndex, sal_Int8 x)
+{
+ m_aParameterManager.setByte(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setShort(sal_Int32 parameterIndex, sal_Int16 x)
+{
+ m_aParameterManager.setShort(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setInt(sal_Int32 parameterIndex, sal_Int32 x)
+{
+ m_aParameterManager.setInt(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setLong(sal_Int32 parameterIndex, sal_Int64 x)
+{
+ m_aParameterManager.setLong(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setFloat(sal_Int32 parameterIndex, float x)
+{
+ m_aParameterManager.setFloat(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setDouble(sal_Int32 parameterIndex, double x)
+{
+ m_aParameterManager.setDouble(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setString(sal_Int32 parameterIndex, const OUString& x)
+{
+ m_aParameterManager.setString(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setBytes(sal_Int32 parameterIndex, const uno::Sequence< sal_Int8 >& x)
+{
+ m_aParameterManager.setBytes(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setDate(sal_Int32 parameterIndex, const util::Date& x)
+{
+ m_aParameterManager.setDate(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setTime(sal_Int32 parameterIndex, const util::Time& x)
+{
+ m_aParameterManager.setTime(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setTimestamp(sal_Int32 parameterIndex, const util::DateTime& x)
+{
+ m_aParameterManager.setTimestamp(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setBinaryStream(sal_Int32 parameterIndex, const uno::Reference<io::XInputStream>& x, sal_Int32 length)
+{
+ m_aParameterManager.setBinaryStream(parameterIndex, x, length);
+}
+
+void SAL_CALL DatabaseDataProvider::setCharacterStream(sal_Int32 parameterIndex, const uno::Reference<io::XInputStream>& x, sal_Int32 length)
+{
+ m_aParameterManager.setCharacterStream(parameterIndex, x, length);
+}
+
+void SAL_CALL DatabaseDataProvider::setObjectWithInfo(sal_Int32 parameterIndex, const uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale)
+{
+ m_aParameterManager.setObjectWithInfo(parameterIndex, x, targetSqlType, scale);
+}
+
+void SAL_CALL DatabaseDataProvider::setObject(sal_Int32 parameterIndex, const uno::Any& x)
+{
+ m_aParameterManager.setObject(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setRef(sal_Int32 parameterIndex, const uno::Reference<sdbc::XRef>& x)
+{
+ m_aParameterManager.setRef(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setBlob(sal_Int32 parameterIndex, const uno::Reference<sdbc::XBlob>& x)
+{
+ m_aParameterManager.setBlob(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setClob(sal_Int32 parameterIndex, const uno::Reference<sdbc::XClob>& x)
+{
+ m_aParameterManager.setClob(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::setArray(sal_Int32 parameterIndex, const Reference<sdbc::XArray>& x)
+{
+ m_aParameterManager.setArray(parameterIndex, x);
+}
+
+void SAL_CALL DatabaseDataProvider::clearParameters()
+{
+ m_aParameterManager.clearParameters();
+}
+
+// css::sdbc::XRowSet
+void SAL_CALL DatabaseDataProvider::execute()
+{
+ uno::Sequence< beans::PropertyValue > aEmpty;
+ createDataSource(aEmpty);
+}
+
+void SAL_CALL DatabaseDataProvider::addRowSetListener(const uno::Reference<sdbc::XRowSetListener>& _rListener)
+{
+ if (m_xRowSet.is())
+ m_xRowSet->addRowSetListener(_rListener);
+}
+
+void SAL_CALL DatabaseDataProvider::removeRowSetListener(const uno::Reference<sdbc::XRowSetListener>& _rListener)
+{
+ if (m_xRowSet.is())
+ m_xRowSet->removeRowSetListener(_rListener);
+}
+
+// css::sdbc::XResultSet
+sal_Bool SAL_CALL DatabaseDataProvider::next()
+{
+ return m_xRowSet->next();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::isBeforeFirst()
+{
+ return m_xRowSet->isBeforeFirst();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::isAfterLast()
+{
+ return m_xRowSet->isAfterLast();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::isFirst()
+{
+ return m_xRowSet->isFirst();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::isLast()
+{
+ return m_xRowSet->isLast();
+}
+
+void SAL_CALL DatabaseDataProvider::beforeFirst()
+{
+ m_xRowSet->beforeFirst();
+}
+
+void SAL_CALL DatabaseDataProvider::afterLast()
+{
+ m_xRowSet->afterLast();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::first()
+{
+ return m_xRowSet->first();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::last()
+{
+ return m_xRowSet->last();
+}
+
+sal_Int32 SAL_CALL DatabaseDataProvider::getRow()
+{
+ return m_xRowSet->getRow();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::absolute(sal_Int32 row)
+{
+ return m_xRowSet->absolute(row);
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::relative(sal_Int32 rows)
+{
+ return m_xRowSet->relative(rows);
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::previous()
+{
+ return m_xRowSet->previous();
+}
+
+void SAL_CALL DatabaseDataProvider::refreshRow()
+{
+ m_xRowSet->refreshRow();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::rowUpdated()
+{
+ return m_xRowSet->rowUpdated();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::rowInserted()
+{
+ return m_xRowSet->rowInserted();
+}
+
+sal_Bool SAL_CALL DatabaseDataProvider::rowDeleted()
+{
+ return m_xRowSet->rowDeleted();
+}
+
+uno::Reference< uno::XInterface > SAL_CALL DatabaseDataProvider::getStatement()
+{
+ return m_xRowSet->getStatement();
+}
+
+uno::Reference< uno::XInterface > SAL_CALL DatabaseDataProvider::getParent( )
+{
+ return m_xParent;
+}
+
+void SAL_CALL DatabaseDataProvider::setParent( const uno::Reference< uno::XInterface >& _xParent )
+{
+ osl::MutexGuard g(m_aMutex);
+ m_xParent = _xParent;
+}
+
+void DatabaseDataProvider::impl_invalidateParameter_nothrow()
+{
+ osl::MutexGuard g(m_aMutex);
+ m_aParameterManager.clearAllParameterInformation();
+}
+
+} // namespace dbaccess
+
+
+extern "C" SAL_DLLPUBLIC_EXPORT css::uno::XInterface*
+com_sun_star_comp_dbaccess_DatabaseDataProvider_get_implementation(
+ css::uno::XComponentContext* context, css::uno::Sequence<css::uno::Any> const& )
+{
+ return cppu::acquire(new dbaccess::DatabaseDataProvider(context));
+}
+
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/PropertyForward.cxx b/dbaccess/source/core/misc/PropertyForward.cxx
new file mode 100644
index 000000000..239bd422f
--- /dev/null
+++ b/dbaccess/source/core/misc/PropertyForward.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 <PropertyForward.hxx>
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/sdbcx/XDataDescriptorFactory.hpp>
+#include <com/sun/star/sdbcx/XAppend.hpp>
+
+#include <comphelper/property.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace dbaccess
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::container;
+ using namespace ::com::sun::star::sdbcx;
+ using namespace ::com::sun::star::lang;
+
+
+ OPropertyForward::OPropertyForward( const Reference< XPropertySet>& _xSource, const Reference< XNameAccess>& _xDestContainer,
+ const OUString& _sName, const std::vector< OUString>& _aPropertyList )
+ :m_xSource( _xSource, UNO_SET_THROW )
+ ,m_xDestContainer( _xDestContainer, UNO_SET_THROW )
+ ,m_sName( _sName )
+ ,m_bInInsert( false )
+ {
+
+ osl_atomic_increment(&m_refCount);
+ try
+ {
+ if ( _aPropertyList.empty() )
+ _xSource->addPropertyChangeListener( OUString(), this );
+ else
+ {
+ for (auto const& property : _aPropertyList)
+ _xSource->addPropertyChangeListener(property, this);
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+ OPropertyForward::~OPropertyForward()
+ {
+ }
+
+ void SAL_CALL OPropertyForward::propertyChange( const PropertyChangeEvent& evt )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+
+ if ( !m_xDestContainer.is() )
+ throw DisposedException( OUString(), *this );
+
+ try
+ {
+ if ( !m_xDest.is() )
+ {
+ if ( m_xDestContainer->hasByName( m_sName ) )
+ {
+ m_xDest.set( m_xDestContainer->getByName( m_sName ), UNO_QUERY_THROW );
+ }
+ else
+ {
+ Reference< XDataDescriptorFactory > xFactory( m_xDestContainer, UNO_QUERY_THROW );
+ m_xDest.set( xFactory->createDataDescriptor(), UNO_SET_THROW );
+
+ ::comphelper::copyProperties( m_xSource, m_xDest );
+
+ m_bInInsert = true;
+ Reference< XAppend > xAppend( m_xDestContainer, UNO_QUERY_THROW );
+ xAppend->appendByDescriptor( m_xDest );
+ m_bInInsert = false;
+ }
+
+ m_xDestInfo.set( m_xDest->getPropertySetInfo(), UNO_SET_THROW );
+ }
+
+ if ( m_xDestInfo->hasPropertyByName( evt.PropertyName ) )
+ {
+ m_xDest->setPropertyValue( evt.PropertyName, evt.NewValue );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+ void SAL_CALL OPropertyForward::disposing( const css::lang::EventObject& /*_rSource*/ )
+ {
+ ::osl::MutexGuard aGuard(m_aMutex);
+
+ if ( !m_xSource.is() )
+ throw DisposedException( OUString(), *this );
+
+ m_xSource->removePropertyChangeListener( OUString(), this );
+ m_xSource = nullptr;
+ m_xDestContainer = nullptr;
+ m_xDestInfo = nullptr;
+ m_xDest = nullptr;
+ }
+
+ void OPropertyForward::setDefinition( const css::uno::Reference< css::beans::XPropertySet>& _xDest )
+ {
+ ::osl::MutexGuard aGuard( m_aMutex );
+ if ( m_bInInsert )
+ return;
+
+ OSL_ENSURE( !m_xDest.is(), "OPropertyForward::setDefinition: definition object is already set!" );
+ try
+ {
+ m_xDest.set( _xDest, UNO_SET_THROW );
+ m_xDestInfo.set( m_xDest->getPropertySetInfo(), UNO_SET_THROW );
+ ::comphelper::copyProperties( m_xDest, m_xSource );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/apitools.cxx b/dbaccess/source/core/misc/apitools.cxx
new file mode 100644
index 000000000..efec92cf5
--- /dev/null
+++ b/dbaccess/source/core/misc/apitools.cxx
@@ -0,0 +1,114 @@
+/* -*- 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 <apitools.hxx>
+#include <cppuhelper/typeprovider.hxx>
+#include <sal/log.hxx>
+
+using namespace ::com::sun::star::uno;
+using namespace ::com::sun::star::lang;
+using namespace cppu;
+using namespace osl;
+
+// various helper functions
+// OSubComponent
+OSubComponent::OSubComponent(Mutex& _rMutex, const Reference< XInterface > & xParent)
+ :OComponentHelper(_rMutex)
+ ,m_xParent(xParent)
+{
+
+}
+
+OSubComponent::~OSubComponent()
+{
+ m_xParent = nullptr;
+
+}
+
+// css::lang::XTypeProvider
+Sequence< Type > OSubComponent::getTypes()
+{
+ OTypeCollection aTypes(cppu::UnoType<XComponent>::get(),
+ cppu::UnoType<XTypeProvider>::get(),
+ cppu::UnoType<XWeak>::get());
+
+ return aTypes.getTypes();
+}
+
+// XInterface
+
+void OSubComponent::release() noexcept
+{
+ Reference< XInterface > x( xDelegator );
+ if (! x.is())
+ {
+ if (osl_atomic_decrement( &m_refCount ) == 0 )
+ {
+ if (! rBHelper.bDisposed)
+ {
+ // *before* again incrementing our ref count, ensure that our weak connection point
+ // will not create references to us anymore (via XAdapter::queryAdapted)
+ disposeWeakConnectionPoint();
+
+ Reference< XInterface > xHoldAlive( *this );
+ // remember the parent
+ Reference< XInterface > xParent;
+ {
+ MutexGuard aGuard( rBHelper.rMutex );
+ xParent = m_xParent;
+ m_xParent = nullptr;
+ }
+
+ SAL_WARN_IF( m_refCount != 1, "dbaccess.core", "OSubComponent::release: invalid ref count (before dispose)!" );
+
+ // First dispose
+ dispose();
+
+ // only the alive ref holds the object
+ SAL_WARN_IF( m_refCount != 1, "dbaccess.core", "OSubComponent::release: invalid ref count (after dispose)!" );
+
+ // release the parent in the ~
+ if (xParent.is())
+ {
+ MutexGuard aGuard( rBHelper.rMutex );
+ m_xParent = xParent;
+ }
+
+ // destroy the object if xHoldAlive decrement the refcount to 0
+ return;
+ }
+ }
+ // restore the reference count
+ osl_atomic_increment( &m_refCount );
+ }
+
+ // as we cover the job of the componenthelper we use the ...
+ OWeakAggObject::release();
+}
+
+Any OSubComponent::queryInterface( const Type & rType )
+{
+ Any aReturn;
+ if (!rType.equals(cppu::UnoType<XAggregation>::get()))
+ aReturn = OComponentHelper::queryInterface(rType);
+
+ return aReturn;
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/dsntypes.cxx b/dbaccess/source/core/misc/dsntypes.cxx
new file mode 100644
index 000000000..d8ceed402
--- /dev/null
+++ b/dbaccess/source/core/misc/dsntypes.cxx
@@ -0,0 +1,565 @@
+/* -*- 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_java.h>
+#include <dsntypes.hxx>
+#include <unotools/confignode.hxx>
+#include <o3tl/safeint.hxx>
+#include <o3tl/string_view.hxx>
+#include <osl/diagnose.h>
+#include <tools/wldcrd.hxx>
+#include <osl/file.hxx>
+#include <officecfg/Office/Common.hxx>
+#include <comphelper/string.hxx>
+
+namespace dbaccess
+{
+
+ using namespace ::com::sun::star;
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::lang;
+
+ namespace
+ {
+ void lcl_extractHostAndPort(std::u16string_view _sUrl, OUString& _sHostname, sal_Int32& _nPortNumber)
+ {
+ if ( comphelper::string::getTokenCount(_sUrl, ':') >= 2 )
+ {
+ sal_Int32 nPos {0};
+ _sHostname = o3tl::getToken(_sUrl, 0, ':', nPos);
+ _nPortNumber = o3tl::toInt32(o3tl::getToken(_sUrl, 0, ':', nPos));
+ }
+ }
+ }
+// ODsnTypeCollection
+ODsnTypeCollection::ODsnTypeCollection(const css::uno::Reference< css::uno::XComponentContext >& _xContext)
+:m_aDriverConfig(_xContext)
+#if OSL_DEBUG_LEVEL > 0
+,m_nLivingIterators(0)
+#endif
+{
+ const uno::Sequence< OUString > aURLs = m_aDriverConfig.getURLs();
+ const OUString* pIter = aURLs.getConstArray();
+ const OUString* pEnd = pIter + aURLs.getLength();
+ for(;pIter != pEnd;++pIter )
+ {
+ m_aDsnPrefixes.push_back(*pIter);
+ m_aDsnTypesDisplayNames.push_back(m_aDriverConfig.getDriverTypeDisplayName(*pIter));
+ }
+
+ OSL_ENSURE(m_aDsnTypesDisplayNames.size() == m_aDsnPrefixes.size(),
+ "ODsnTypeCollection::ODsnTypeCollection : invalid resources !");
+}
+
+ODsnTypeCollection::~ODsnTypeCollection()
+{
+#if OSL_DEBUG_LEVEL > 0
+ OSL_ENSURE(0 == m_nLivingIterators, "ODsnTypeCollection::~ODsnTypeCollection : there are still living iterator objects!");
+#endif
+}
+
+OUString ODsnTypeCollection::getTypeDisplayName(std::u16string_view _sURL) const
+{
+ return m_aDriverConfig.getDriverTypeDisplayName(_sURL);
+}
+
+OUString ODsnTypeCollection::cutPrefix(std::u16string_view _sURL) const
+{
+ OUString sRet;
+ OUString sOldPattern;
+
+ // on Windows or with gen rendering, the urls may begin with an ~
+ std::u16string_view sCleanURL = comphelper::string::stripStart(_sURL, '~');
+
+ for (auto const& dsnPrefix : m_aDsnPrefixes)
+ {
+ WildCard aWildCard(dsnPrefix);
+ if ( sOldPattern.getLength() < dsnPrefix.getLength() && aWildCard.Matches(sCleanURL) )
+ {
+ // This relies on the fact that all patterns are of the form
+ // foo*
+ // that is, the very concept of "prefix" applies.
+ OUString prefix(comphelper::string::stripEnd(dsnPrefix, '*'));
+ OSL_ENSURE(o3tl::make_unsigned(prefix.getLength()) <= sCleanURL.size(), "How can A match B when A shorter than B?");
+ sRet = sCleanURL.substr(prefix.getLength());
+ sOldPattern = dsnPrefix;
+ }
+ }
+
+ return sRet;
+}
+
+OUString ODsnTypeCollection::getPrefix(const OUString& _sURL) const
+{
+ OUString sRet;
+ OUString sOldPattern;
+ for (auto const& dsnPrefix : m_aDsnPrefixes)
+ {
+ WildCard aWildCard(dsnPrefix);
+ if ( sOldPattern.getLength() < dsnPrefix.getLength() && aWildCard.Matches(_sURL) )
+ {
+ // This relies on the fact that all patterns are of the form
+ // foo*
+ // that is, the very concept of "prefix" applies.
+ sRet = comphelper::string::stripEnd(dsnPrefix, '*');
+ OSL_ENSURE(sRet.getLength() <= _sURL.getLength(), "How can A match B when A shorter than B?");
+ sOldPattern = dsnPrefix;
+ }
+ }
+
+ return sRet;
+}
+
+bool ODsnTypeCollection::hasDriver( const char* _pAsciiPattern ) const
+{
+ OUString sPrefix( getPrefix( OUString::createFromAscii( _pAsciiPattern ) ) );
+ return !sPrefix.isEmpty();
+}
+
+bool ODsnTypeCollection::isConnectionUrlRequired(std::u16string_view _sURL) const
+{
+ OUString sRet;
+ OUString sOldPattern;
+ for (auto const& dsnPrefix : m_aDsnPrefixes)
+ {
+ WildCard aWildCard(dsnPrefix);
+ if ( sOldPattern.getLength() < dsnPrefix.getLength() && aWildCard.Matches(_sURL) )
+ {
+ sRet = dsnPrefix;
+ sOldPattern = dsnPrefix;
+ }
+ }
+ return !sRet.isEmpty() && sRet[sRet.getLength()-1] == '*';
+}
+
+OUString ODsnTypeCollection::getMediaType(std::u16string_view _sURL) const
+{
+ const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL);
+ return aFeatures.getOrDefault("MediaType",OUString());
+}
+
+OUString ODsnTypeCollection::getDatasourcePrefixFromMediaType(std::u16string_view _sMediaType,std::u16string_view _sExtension)
+{
+ OUString sURL, sFallbackURL;
+ const uno::Sequence< OUString > aURLs = m_aDriverConfig.getURLs();
+ const OUString* pIter = aURLs.getConstArray();
+ const OUString* pEnd = pIter + aURLs.getLength();
+ for(;pIter != pEnd;++pIter )
+ {
+ const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(*pIter);
+ if ( aFeatures.getOrDefault("MediaType",OUString()) == _sMediaType )
+ {
+ const OUString sFileExtension = aFeatures.getOrDefault("Extension",OUString());
+ if ( _sExtension == sFileExtension )
+ {
+ sURL = *pIter;
+ break;
+ }
+ if ( sFileExtension.isEmpty() && !_sExtension.empty() )
+ sFallbackURL = *pIter;
+ }
+ }
+
+ if ( sURL.isEmpty() && !sFallbackURL.isEmpty() )
+ sURL = sFallbackURL;
+
+ sURL = comphelper::string::stripEnd(sURL, '*');
+ return sURL;
+}
+
+bool ODsnTypeCollection::isShowPropertiesEnabled( const OUString& _sURL )
+{
+ return !( _sURL.startsWithIgnoreAsciiCase("sdbc:embedded:hsqldb")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:embedded:firebird")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:address:outlook")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:address:outlookexp")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:address:mozilla:")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:address:kab")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:address:evolution:local")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:address:evolution:groupwise")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:address:evolution:ldap")
+ || _sURL.startsWithIgnoreAsciiCase("sdbc:address:macab") );
+}
+
+void ODsnTypeCollection::extractHostNamePort(const OUString& _rDsn,OUString& _sDatabaseName,OUString& _rsHostname,sal_Int32& _nPortNumber) const
+{
+ OUString sUrl = cutPrefix(_rDsn);
+ if ( _rDsn.startsWithIgnoreAsciiCase("jdbc:oracle:thin:") )
+ {
+ lcl_extractHostAndPort(sUrl,_rsHostname,_nPortNumber);
+ const sal_Int32 nUrlTokens {comphelper::string::getTokenCount(sUrl, ':')};
+ if ( _rsHostname.isEmpty() && nUrlTokens == 2 )
+ {
+ _nPortNumber = -1;
+ _rsHostname = sUrl.getToken(0,':');
+ }
+ if ( !_rsHostname.isEmpty() )
+ _rsHostname = _rsHostname.copy(_rsHostname.lastIndexOf('@')+1);
+ _sDatabaseName = sUrl.copy(sUrl.lastIndexOf(':')+1);
+ }
+ else if ( _rDsn.startsWithIgnoreAsciiCase("sdbc:address:ldap:") )
+ {
+ lcl_extractHostAndPort(sUrl,_sDatabaseName,_nPortNumber);
+ }
+ else if ( _rDsn.startsWithIgnoreAsciiCase("sdbc:mysql:mysqlc:")
+ || _rDsn.startsWithIgnoreAsciiCase("sdbc:mysql:jdbc:") )
+ {
+ lcl_extractHostAndPort(sUrl,_rsHostname,_nPortNumber);
+
+ const sal_Int32 nUrlTokens {comphelper::string::getTokenCount(sUrl, '/')};
+ if ( _nPortNumber == -1 && _rsHostname.isEmpty() && nUrlTokens == 2 )
+ _rsHostname = sUrl.getToken(0,'/');
+ _sDatabaseName = sUrl.copy(sUrl.lastIndexOf('/')+1);
+ }
+ else if ( _rDsn.startsWithIgnoreAsciiCase("sdbc:ado:access:Provider=Microsoft.ACE.OLEDB.12.0;DATA SOURCE=")
+ || _rDsn.startsWithIgnoreAsciiCase("sdbc:ado:access:PROVIDER=Microsoft.Jet.OLEDB.4.0;DATA SOURCE=") )
+ {
+ OUString sNewFileName;
+ if ( ::osl::FileBase::getFileURLFromSystemPath( sUrl, sNewFileName ) == ::osl::FileBase::E_None )
+ {
+ _sDatabaseName = sNewFileName;
+ }
+ }
+}
+
+OUString ODsnTypeCollection::getJavaDriverClass(std::u16string_view _sURL) const
+{
+ const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getProperties(_sURL);
+ return aFeatures.getOrDefault("JavaDriverClass",OUString());
+}
+
+bool ODsnTypeCollection::isFileSystemBased(std::u16string_view _sURL) const
+{
+ const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL);
+ return aFeatures.getOrDefault("FileSystemBased",false);
+}
+
+bool ODsnTypeCollection::supportsTableCreation(std::u16string_view _sURL) const
+{
+ const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL);
+ return aFeatures.getOrDefault("SupportsTableCreation",false);
+}
+
+bool ODsnTypeCollection::supportsColumnDescription(std::u16string_view _sURL) const
+{
+ const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL);
+ return aFeatures.getOrDefault("SupportsColumnDescription",false);
+}
+
+bool ODsnTypeCollection::supportsBrowsing(std::u16string_view _sURL) const
+{
+ const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL);
+ return aFeatures.getOrDefault("SupportsBrowsing",false);
+}
+
+bool ODsnTypeCollection::supportsDBCreation(std::u16string_view _sURL) const
+{
+ const ::comphelper::NamedValueCollection& aFeatures = m_aDriverConfig.getMetaData(_sURL);
+ return aFeatures.getOrDefault("SupportsDBCreation",false);
+}
+
+Sequence<PropertyValue> ODsnTypeCollection::getDefaultDBSettings( std::u16string_view _sURL ) const
+{
+ const ::comphelper::NamedValueCollection& aProperties = m_aDriverConfig.getProperties(_sURL);
+ return aProperties.getPropertyValues();
+}
+
+bool ODsnTypeCollection::isEmbeddedDatabase( std::u16string_view _sURL )
+{
+ return o3tl::starts_with( _sURL, u"sdbc:embedded:" );
+}
+
+OUString ODsnTypeCollection::getEmbeddedDatabase()
+{
+ if (!HAVE_FEATURE_JAVA || officecfg::Office::Common::Misc::ExperimentalMode::get())
+ return "sdbc:embedded:firebird";
+ else
+ return "sdbc:embedded:hsqldb";
+}
+
+
+DATASOURCE_TYPE ODsnTypeCollection::determineType(std::u16string_view _rDsn) const
+{
+ OUString sDsn(comphelper::string::stripEnd(_rDsn, '*'));
+ sal_Int32 nSeparator = sDsn.indexOf(u':');
+ if (-1 == nSeparator)
+ {
+ if (!sDsn.isEmpty())
+ {
+ // there should be at least one such separator
+ OSL_FAIL("ODsnTypeCollection::implDetermineType : missing the colon !");
+ }
+
+ return DST_UNKNOWN;
+ }
+
+ // find first :
+ if (sDsn.startsWithIgnoreAsciiCase("jdbc:oracle:thin:"))
+ return DST_ORACLE_JDBC;
+
+ if (sDsn.startsWithIgnoreAsciiCase("jdbc:"))
+ return DST_JDBC;
+
+ if (sDsn.equalsIgnoreAsciiCase("sdbc:embedded:hsqldb"))
+ return DST_EMBEDDED_HSQLDB;
+
+ if (sDsn.equalsIgnoreAsciiCase("sdbc:embedded:firebird"))
+ return DST_EMBEDDED_FIREBIRD;
+
+ // find second :
+ nSeparator = sDsn.indexOf(u':', nSeparator + 1);
+ if (-1 == nSeparator)
+ {
+ // at the moment only jdbc is allowed to have just one separator
+ OSL_FAIL("ODsnTypeCollection::implDetermineType : missing the second colon !");
+ return DST_UNKNOWN;
+ }
+
+ if (sDsn.startsWithIgnoreAsciiCase("sdbc:ado:"))
+ {
+ if (sDsn.startsWithIgnoreAsciiCase("sdbc:ado:access:"))
+ {
+ if (sDsn.startsWithIgnoreAsciiCase("sdbc:ado:access:Provider=Microsoft.ACE.OLEDB.12.0;"))
+ return DST_MSACCESS_2007;
+ else
+ return DST_MSACCESS;
+ }
+ return DST_ADO;
+ }
+
+ struct KnownPrefix
+ {
+ const OUString sPrefix;
+ const DATASOURCE_TYPE eType;
+ const bool bMatchComplete;
+
+ KnownPrefix( const OUString &_s, const DATASOURCE_TYPE _t, const bool _m )
+ :sPrefix( _s )
+ ,eType ( _t )
+ ,bMatchComplete( _m )
+ {
+ }
+
+ bool match( const OUString &url) const
+ {
+ if(bMatchComplete)
+ {
+ return url.equalsIgnoreAsciiCase(sPrefix);
+ }
+ else
+ {
+ return url.startsWithIgnoreAsciiCase(sPrefix);
+ }
+ }
+ };
+ const KnownPrefix aKnowPrefixes[] =
+ {
+ KnownPrefix( "sdbc:calc:", DST_CALC, false ),
+ KnownPrefix( "sdbc:writer:", DST_WRITER, false ),
+ KnownPrefix( "sdbc:flat:", DST_FLAT, false ),
+ KnownPrefix( "sdbc:odbc:", DST_ODBC, false ),
+ KnownPrefix( "sdbc:dbase:", DST_DBASE, false ),
+ KnownPrefix( "sdbc:firebird:", DST_FIREBIRD, false ),
+ KnownPrefix( "sdbc:mysql:odbc:", DST_MYSQL_ODBC, false ),
+ KnownPrefix( "sdbc:mysql:jdbc:", DST_MYSQL_JDBC, false ),
+ KnownPrefix( "sdbc:mysql:mysqlc:", DST_MYSQL_NATIVE, false ),
+ KnownPrefix( "sdbc:mysqlc:", DST_MYSQL_NATIVE_DIRECT,false ),
+ KnownPrefix( "sdbc:postgresql:", DST_POSTGRES ,false ),
+
+ KnownPrefix( "sdbc:address:mozilla:", DST_MOZILLA, true ),
+ KnownPrefix( "sdbc:address:thunderbird:", DST_THUNDERBIRD, true ),
+ KnownPrefix( "sdbc:address:ldap:", DST_LDAP, true ),
+ KnownPrefix( "sdbc:address:outlook", DST_OUTLOOK, true ),
+ KnownPrefix( "sdbc:address:outlookexp", DST_OUTLOOKEXP, true ),
+ KnownPrefix( "sdbc:address:evolution:ldap", DST_EVOLUTION_LDAP, true ),
+ KnownPrefix( "sdbc:address:evolution:groupwise",DST_EVOLUTION_GROUPWISE,true ),
+ KnownPrefix( "sdbc:address:evolution:local", DST_EVOLUTION, true ),
+ KnownPrefix( "sdbc:address:kab", DST_KAB, true ),
+ KnownPrefix( "sdbc:address:macab", DST_MACAB, true )
+ };
+
+ for (const auto & aKnowPrefixe : aKnowPrefixes)
+ {
+ if( aKnowPrefixe.match(sDsn) )
+ {
+ return aKnowPrefixe.eType;
+ }
+ }
+
+ return DST_UNKNOWN;
+}
+
+void ODsnTypeCollection::fillPageIds(std::u16string_view _sURL,std::vector<sal_Int16>& _rOutPathIds) const
+{
+ DATASOURCE_TYPE eType = determineType(_sURL);
+ switch(eType)
+ {
+ case DST_ADO:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_ADO);
+ break;
+ case DST_DBASE:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_DBASE);
+ break;
+ case DST_FLAT:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_TEXT);
+ break;
+ case DST_CALC:
+ case DST_WRITER:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_DOCUMENT_OR_SPREADSHEET);
+ break;
+ case DST_ODBC:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_ODBC);
+ break;
+ case DST_JDBC:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_JDBC);
+ break;
+ case DST_MYSQL_ODBC:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_MYSQL_INTRO);
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_MYSQL_ODBC);
+ break;
+ case DST_MYSQL_JDBC:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_MYSQL_INTRO);
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_MYSQL_JDBC);
+ break;
+ case DST_MYSQL_NATIVE:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_MYSQL_INTRO);
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_MYSQL_NATIVE);
+ break;
+ case DST_ORACLE_JDBC:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_ORACLE);
+ break;
+ case DST_LDAP:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_LDAP);
+ break;
+ case DST_MSACCESS:
+ case DST_MSACCESS_2007:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_MSACCESS);
+ break;
+ case DST_OUTLOOKEXP:
+ case DST_OUTLOOK:
+ case DST_MOZILLA:
+ case DST_THUNDERBIRD:
+ case DST_EVOLUTION:
+ case DST_EVOLUTION_GROUPWISE:
+ case DST_EVOLUTION_LDAP:
+ case DST_KAB:
+ case DST_MACAB:
+ case DST_EMBEDDED_HSQLDB:
+ case DST_EMBEDDED_FIREBIRD:
+ break;
+ default:
+ _rOutPathIds.push_back(PAGE_DBSETUPWIZARD_USERDEFINED);
+ break;
+ }
+}
+
+OUString ODsnTypeCollection::getType(std::u16string_view _sURL) const
+{
+ OUString sOldPattern;
+ for (auto const& dsnPrefix : m_aDsnPrefixes)
+ {
+ WildCard aWildCard(dsnPrefix);
+ if ( sOldPattern.getLength() < dsnPrefix.getLength() && aWildCard.Matches(_sURL) )
+ {
+ sOldPattern = dsnPrefix;
+ }
+ }
+ return sOldPattern;
+}
+
+sal_Int32 ODsnTypeCollection::getIndexOf(std::u16string_view _sURL) const
+{
+ sal_Int32 nRet = -1;
+ OUString sOldPattern;
+ sal_Int32 i = 0;
+ for (auto const& dsnPrefix : m_aDsnPrefixes)
+ {
+ WildCard aWildCard(dsnPrefix);
+ if ( sOldPattern.getLength() < dsnPrefix.getLength() && aWildCard.Matches(_sURL) )
+ {
+ nRet = i;
+ sOldPattern = dsnPrefix;
+ }
+ ++i;
+ }
+
+ return nRet;
+}
+
+sal_Int32 ODsnTypeCollection::size() const
+{
+ return m_aDsnPrefixes.size();
+}
+
+// ODsnTypeCollection::TypeIterator
+ODsnTypeCollection::TypeIterator::TypeIterator(const ODsnTypeCollection* _pContainer, sal_Int32 _nInitialPos)
+ :m_pContainer(_pContainer)
+ ,m_nPosition(_nInitialPos)
+{
+ OSL_ENSURE(m_pContainer, "ODsnTypeCollection::TypeIterator::TypeIterator : invalid container!");
+#if OSL_DEBUG_LEVEL > 0
+ ++const_cast<ODsnTypeCollection*>(m_pContainer)->m_nLivingIterators;
+#endif
+}
+
+ODsnTypeCollection::TypeIterator::TypeIterator(const TypeIterator& _rSource)
+ :m_pContainer(_rSource.m_pContainer)
+ ,m_nPosition(_rSource.m_nPosition)
+{
+#if OSL_DEBUG_LEVEL > 0
+ ++const_cast<ODsnTypeCollection*>(m_pContainer)->m_nLivingIterators;
+#endif
+}
+
+ODsnTypeCollection::TypeIterator::~TypeIterator()
+{
+#if OSL_DEBUG_LEVEL > 0
+ --const_cast<ODsnTypeCollection*>(m_pContainer)->m_nLivingIterators;
+#endif
+}
+
+OUString const & ODsnTypeCollection::TypeIterator::getDisplayName() const
+{
+ OSL_ENSURE(m_nPosition < static_cast<sal_Int32>(m_pContainer->m_aDsnTypesDisplayNames.size()), "ODsnTypeCollection::TypeIterator::getDisplayName : invalid position!");
+ return m_pContainer->m_aDsnTypesDisplayNames[m_nPosition];
+}
+
+OUString const & ODsnTypeCollection::TypeIterator::getURLPrefix() const
+{
+ OSL_ENSURE(m_nPosition < static_cast<sal_Int32>(m_pContainer->m_aDsnPrefixes.size()), "ODsnTypeCollection::TypeIterator::getDisplayName : invalid position!");
+ return m_pContainer->m_aDsnPrefixes[m_nPosition];
+}
+
+const ODsnTypeCollection::TypeIterator& ODsnTypeCollection::TypeIterator::operator++()
+{
+ OSL_ENSURE(m_nPosition < static_cast<sal_Int32>(m_pContainer->m_aDsnTypesDisplayNames.size()), "ODsnTypeCollection::TypeIterator::operator++ : invalid position!");
+ if (m_nPosition < static_cast<sal_Int32>(m_pContainer->m_aDsnTypesDisplayNames.size()))
+ ++m_nPosition;
+ return *this;
+}
+
+bool operator==(const ODsnTypeCollection::TypeIterator& lhs, const ODsnTypeCollection::TypeIterator& rhs)
+{
+ return (lhs.m_pContainer == rhs.m_pContainer) && (lhs.m_nPosition == rhs.m_nPosition);
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/migrwarndlg.cxx b/dbaccess/source/core/misc/migrwarndlg.cxx
new file mode 100644
index 000000000..d1712fba3
--- /dev/null
+++ b/dbaccess/source/core/misc/migrwarndlg.cxx
@@ -0,0 +1,22 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include <migrwarndlg.hxx>
+
+namespace dbaccess
+{
+MigrationWarnDialog::MigrationWarnDialog(weld::Window* pParent)
+ : MessageDialogController(pParent, "dbaccess/ui/migrwarndlg.ui", "MigrationWarnDialog")
+ , m_xLater(m_xBuilder->weld_button("no"))
+{
+ m_xLater->grab_focus();
+}
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/objectnameapproval.cxx b/dbaccess/source/core/misc/objectnameapproval.cxx
new file mode 100644
index 000000000..3ec15caaa
--- /dev/null
+++ b/dbaccess/source/core/misc/objectnameapproval.cxx
@@ -0,0 +1,74 @@
+/* -*- 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 <objectnameapproval.hxx>
+
+#include <com/sun/star/lang/DisposedException.hpp>
+#include <com/sun/star/sdb/tools/XConnectionTools.hpp>
+#include <com/sun/star/sdb/CommandType.hpp>
+
+#include <cppuhelper/weakref.hxx>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::sdbc::XConnection;
+ using ::com::sun::star::uno::WeakReference;
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::lang::DisposedException;
+ using ::com::sun::star::sdb::tools::XConnectionTools;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::sdb::tools::XObjectNames;
+ using ::com::sun::star::uno::XInterface;
+
+ namespace CommandType = com::sun::star::sdb::CommandType;
+
+ // ObjectNameApproval_Impl
+ struct ObjectNameApproval_Impl
+ {
+ WeakReference< XConnection > aConnection;
+ sal_Int32 nCommandType;
+ };
+
+ // ObjectNameApproval
+ ObjectNameApproval::ObjectNameApproval( const Reference< XConnection >& _rxConnection, ObjectType _eType )
+ :m_pImpl( new ObjectNameApproval_Impl )
+ {
+ m_pImpl->aConnection = _rxConnection;
+ m_pImpl->nCommandType = _eType == TypeQuery ? CommandType::QUERY : CommandType::TABLE;
+ }
+
+ ObjectNameApproval::~ObjectNameApproval()
+ {
+ }
+
+ void ObjectNameApproval::approveElement( const OUString& _rName )
+ {
+ Reference< XConnection > xConnection( m_pImpl->aConnection );
+ if ( !xConnection.is() )
+ throw DisposedException();
+
+ Reference< XConnectionTools > xConnectionTools( xConnection, UNO_QUERY_THROW );
+ Reference< XObjectNames > xObjectNames( xConnectionTools->getObjectNames(), css::uno::UNO_SET_THROW );
+ xObjectNames->checkNameForCreate( m_pImpl->nCommandType, _rName );
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/sdbcoretools.cxx b/dbaccess/source/core/misc/sdbcoretools.cxx
new file mode 100644
index 000000000..1789aea84
--- /dev/null
+++ b/dbaccess/source/core/misc/sdbcoretools.cxx
@@ -0,0 +1,142 @@
+/* -*- 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 <sdbcoretools.hxx>
+
+#include <com/sun/star/beans/XPropertySet.hpp>
+#include <com/sun/star/container/XChild.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+#include <com/sun/star/sdb/XDocumentDataSource.hpp>
+#include <com/sun/star/task/InteractionRequestStringResolver.hpp>
+#include <com/sun/star/embed/XTransactedObject.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+
+#include <tools/diagnose_ex.h>
+#include <comphelper/interaction.hxx>
+#include <rtl/ref.hxx>
+
+namespace dbaccess
+{
+
+ using namespace ::com::sun::star::uno;
+ using namespace ::com::sun::star::lang;
+ using namespace ::com::sun::star::util;
+ using namespace ::com::sun::star::io;
+ using namespace ::com::sun::star::sdbc;
+ using namespace ::com::sun::star::sdb;
+ using namespace ::com::sun::star::beans;
+ using namespace ::com::sun::star::task;
+ using namespace ::com::sun::star::embed;
+ using namespace ::com::sun::star::container;
+
+ void notifyDataSourceModified(const css::uno::Reference< css::uno::XInterface >& _rxObject)
+ {
+ Reference< XInterface > xDs = getDataSource( _rxObject );
+ Reference<XDocumentDataSource> xDocumentDataSource(xDs,UNO_QUERY);
+ if ( xDocumentDataSource.is() )
+ xDs = xDocumentDataSource->getDatabaseDocument();
+ Reference< XModifiable > xModi( xDs, UNO_QUERY );
+ if ( xModi.is() )
+ xModi->setModified(true);
+ }
+
+ Reference< XInterface > getDataSource( const Reference< XInterface >& _rxDependentObject )
+ {
+ Reference< XInterface > xParent = _rxDependentObject;
+ Reference< XInterface > xReturn;
+ while( xParent.is() )
+ {
+ xReturn = xParent;
+ Reference<XChild> xChild(xParent,UNO_QUERY);
+ xParent.set(xChild.is() ? xChild->getParent() : Reference< XInterface >(),UNO_QUERY);
+ }
+ return xReturn;
+ }
+
+ OUString extractExceptionMessage( const Reference<XComponentContext> & _rContext, const Any& _rError )
+ {
+ OUString sDisplayMessage;
+
+ try
+ {
+ Reference< XInteractionRequestStringResolver > xStringResolver = InteractionRequestStringResolver::create(_rContext);
+
+ ::rtl::Reference pRequest( new ::comphelper::OInteractionRequest( _rError ) );
+ ::rtl::Reference pApprove( new ::comphelper::OInteractionApprove );
+ pRequest->addContinuation( pApprove );
+ Optional< OUString > aMessage = xStringResolver->getStringFromInformationalRequest( pRequest );
+ if ( aMessage.IsPresent )
+ sDisplayMessage = aMessage.Value;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+
+ if ( sDisplayMessage.isEmpty() )
+ {
+ Exception aExcept;
+ _rError >>= aExcept;
+
+ sDisplayMessage = _rError.getValueTypeName() +
+ ":\n" +
+ aExcept.Message;
+ }
+
+ return sDisplayMessage;
+ }
+
+ namespace tools::stor {
+
+ bool storageIsWritable_nothrow( const Reference< XStorage >& _rxStorage )
+ {
+ if ( !_rxStorage.is() )
+ return false;
+
+ sal_Int32 nMode = ElementModes::READ;
+ try
+ {
+ Reference< XPropertySet > xStorageProps( _rxStorage, UNO_QUERY_THROW );
+ xStorageProps->getPropertyValue( "OpenMode" ) >>= nMode;
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return ( nMode & ElementModes::WRITE ) != 0;
+ }
+
+ bool commitStorageIfWriteable( const Reference< XStorage >& _rxStorage )
+ {
+ bool bSuccess = false;
+ Reference< XTransactedObject > xTrans( _rxStorage, UNO_QUERY );
+ if ( xTrans.is() )
+ {
+ if ( storageIsWritable_nothrow( _rxStorage ) )
+ xTrans->commit();
+ bSuccess = true;
+ }
+ return bSuccess;
+ }
+
+}
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/misc/veto.cxx b/dbaccess/source/core/misc/veto.cxx
new file mode 100644
index 000000000..d2596d4e1
--- /dev/null
+++ b/dbaccess/source/core/misc/veto.cxx
@@ -0,0 +1,49 @@
+/* -*- 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 <veto.hxx>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Any;
+
+ // Veto
+ Veto::Veto( const Any& _rDetails )
+ :m_aDetails( _rDetails )
+ {
+ }
+
+ Veto::~Veto()
+ {
+ }
+
+ OUString SAL_CALL Veto::getReason()
+ {
+ return OUString();
+ }
+
+ Any SAL_CALL Veto::getDetails()
+ {
+ return m_aDetails;
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/dbdocrecovery.cxx b/dbaccess/source/core/recovery/dbdocrecovery.cxx
new file mode 100644
index 000000000..db7bb53bd
--- /dev/null
+++ b/dbaccess/source/core/recovery/dbdocrecovery.cxx
@@ -0,0 +1,347 @@
+/* -*- 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 <recovery/dbdocrecovery.hxx>
+#include <sdbcoretools.hxx>
+#include "storagetextstream.hxx"
+#include "subcomponentrecovery.hxx"
+#include "subcomponents.hxx"
+
+#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/io/TextInputStream.hpp>
+#include <com/sun/star/util/XModifiable.hpp>
+
+#include <rtl/ustrbuf.hxx>
+#include <sal/log.hxx>
+#include <tools/diagnose_ex.h>
+
+namespace dbaccess
+{
+
+ using css::uno::Reference;
+ using css::uno::UNO_QUERY;
+ using css::uno::UNO_QUERY_THROW;
+ using css::uno::UNO_SET_THROW;
+ using css::uno::Exception;
+ using css::uno::Sequence;
+ using css::uno::XComponentContext;
+ using css::embed::XStorage;
+ using css::frame::XController;
+ using css::sdb::application::XDatabaseDocumentUI;
+ using css::lang::XComponent;
+ using css::io::XStream;
+ using css::io::TextInputStream;
+ using css::io::XTextInputStream2;
+ using css::util::XModifiable;
+
+ namespace ElementModes = css::embed::ElementModes;
+
+ // helpers
+ namespace
+ {
+ void lcl_getPersistentRepresentation( const MapStringToCompDesc::value_type& i_rComponentDesc, OUStringBuffer& o_rBuffer )
+ {
+ o_rBuffer.append( i_rComponentDesc.first );
+ o_rBuffer.append( '=' );
+ o_rBuffer.append( i_rComponentDesc.second.sName );
+ o_rBuffer.append( ',' );
+ o_rBuffer.append( sal_Unicode( i_rComponentDesc.second.bForEditing ? '1' : '0' ) );
+ }
+
+ bool lcl_extractCompDesc( const OUString& i_rIniLine, OUString& o_rStorName, SubComponentDescriptor& o_rCompDesc )
+ {
+ const sal_Int32 nEqualSignPos = i_rIniLine.indexOf( '=' );
+ if ( nEqualSignPos < 1 )
+ {
+ OSL_FAIL( "lcl_extractCompDesc: invalid map file entry - unexpected pos of '='" );
+ return false;
+ }
+ o_rStorName = i_rIniLine.copy( 0, nEqualSignPos );
+
+ const sal_Int32 nCommaPos = i_rIniLine.lastIndexOf( ',' );
+ if ( nCommaPos != i_rIniLine.getLength() - 2 )
+ {
+ OSL_FAIL( "lcl_extractCompDesc: invalid map file entry - unexpected pos of ','" );
+ return false;
+ }
+ o_rCompDesc.sName = i_rIniLine.copy( nEqualSignPos + 1, nCommaPos - nEqualSignPos - 1 );
+ o_rCompDesc.bForEditing = ( i_rIniLine[ nCommaPos + 1 ] == '1' );
+ return true;
+ }
+
+ constexpr OUStringLiteral sRecoveryDataSubStorageName = u"recovery";
+
+ constexpr OUStringLiteral sObjectMapStreamName = u"storage-component-map.ini";
+
+ void lcl_writeObjectMap_throw( const Reference<XComponentContext> & i_rContext, const Reference< XStorage >& i_rStorage,
+ const MapStringToCompDesc& i_mapStorageToCompDesc )
+ {
+ if ( i_mapStorageToCompDesc.empty() )
+ // nothing to do
+ return;
+
+ StorageTextOutputStream aTextOutput( i_rContext, i_rStorage, sObjectMapStreamName );
+
+ aTextOutput.writeLine( "[storages]" );
+
+ for (auto const& elem : i_mapStorageToCompDesc)
+ {
+ OUStringBuffer aLine;
+ lcl_getPersistentRepresentation(elem, aLine);
+
+ aTextOutput.writeLine( aLine.makeStringAndClear() );
+ }
+
+ aTextOutput.writeLine();
+ }
+
+ bool lcl_isSectionStart( const OUString& i_rIniLine, OUString& o_rSectionName )
+ {
+ const sal_Int32 nLen = i_rIniLine.getLength();
+ if ( i_rIniLine.startsWith("[") && i_rIniLine.endsWith("]") )
+ {
+ o_rSectionName = i_rIniLine.copy( 1, nLen -2 );
+ return true;
+ }
+ return false;
+ }
+
+ void lcl_stripTrailingLineFeed( OUString& io_rLine )
+ {
+ const sal_Int32 nLen = io_rLine.getLength();
+ if ( io_rLine.endsWith("\n") )
+ io_rLine = io_rLine.copy( 0, nLen - 1 );
+ }
+
+ void lcl_readObjectMap_throw( const Reference<XComponentContext> & i_rxContext, const Reference< XStorage >& i_rStorage,
+ MapStringToCompDesc& o_mapStorageToObjectName )
+ {
+ ENSURE_OR_THROW( i_rStorage.is(), "invalid storage" );
+ if ( !i_rStorage->hasByName( sObjectMapStreamName ) )
+ { // nothing to do, though suspicious
+ OSL_FAIL( "lcl_readObjectMap_throw: if there's no map file, then there's expected to be no storage, too!" );
+ return;
+ }
+
+ Reference< XStream > xIniStream( i_rStorage->openStreamElement(
+ sObjectMapStreamName, ElementModes::READ ), UNO_SET_THROW );
+
+ Reference< XTextInputStream2 > xTextInput = TextInputStream::create( i_rxContext );
+ xTextInput->setEncoding( "UTF-8" );
+ xTextInput->setInputStream( xIniStream->getInputStream() );
+
+ OUString sCurrentSection;
+ bool bCurrentSectionIsKnownToBeUnsupported = true;
+ while ( !xTextInput->isEOF() )
+ {
+ OUString sLine = xTextInput->readLine();
+ lcl_stripTrailingLineFeed( sLine );
+
+ if ( sLine.isEmpty() )
+ continue;
+
+ if ( lcl_isSectionStart( sLine, sCurrentSection ) )
+ {
+ bCurrentSectionIsKnownToBeUnsupported = false;
+ continue;
+ }
+
+ if ( bCurrentSectionIsKnownToBeUnsupported )
+ continue;
+
+ // the only section we support so far is "storages"
+ if ( sCurrentSection != "storages" )
+ {
+ bCurrentSectionIsKnownToBeUnsupported = true;
+ continue;
+ }
+
+ OUString sStorageName;
+ SubComponentDescriptor aCompDesc;
+ if ( !lcl_extractCompDesc( sLine, sStorageName, aCompDesc ) )
+ continue;
+ o_mapStorageToObjectName[ sStorageName ] = aCompDesc;
+ }
+ }
+
+ void lcl_markModified( const Reference< XComponent >& i_rSubComponent )
+ {
+ const Reference< XModifiable > xModify( i_rSubComponent, UNO_QUERY );
+ if ( !xModify.is() )
+ {
+ OSL_FAIL( "lcl_markModified: unhandled case!" );
+ return;
+ }
+
+ xModify->setModified( true );
+ }
+ }
+
+ // DatabaseDocumentRecovery_Data
+ struct DatabaseDocumentRecovery_Data
+ {
+ const Reference<XComponentContext> aContext;
+
+ explicit DatabaseDocumentRecovery_Data( const Reference<XComponentContext> & i_rContext )
+ :aContext( i_rContext )
+ {
+ }
+ };
+
+ // DatabaseDocumentRecovery
+ DatabaseDocumentRecovery::DatabaseDocumentRecovery( const Reference<XComponentContext> & i_rContext )
+ :m_pData( new DatabaseDocumentRecovery_Data( i_rContext ) )
+ {
+ }
+
+ DatabaseDocumentRecovery::~DatabaseDocumentRecovery()
+ {
+ }
+
+ void DatabaseDocumentRecovery::saveModifiedSubComponents( const Reference< XStorage >& i_rTargetStorage,
+ const std::vector< Reference< XController > >& i_rControllers )
+ {
+ ENSURE_OR_THROW( i_rTargetStorage.is(), "invalid document storage" );
+
+ // create a sub storage for recovery data
+ if ( i_rTargetStorage->hasByName( sRecoveryDataSubStorageName ) )
+ i_rTargetStorage->removeElement( sRecoveryDataSubStorageName );
+ Reference< XStorage > xRecoveryStorage = i_rTargetStorage->openStorageElement( sRecoveryDataSubStorageName, ElementModes::READWRITE );
+
+ // store recovery data for open sub components of the given controller(s)
+ if ( !i_rControllers.empty() )
+ {
+ ENSURE_OR_THROW( i_rControllers.size() == 1, "can't handle more than one controller" );
+ // At the moment, there can be only one view to a database document. If we ever allow for more than this,
+ // then we need a concept for sub documents opened from different controllers (i.e. two document views,
+ // and the user opens the very same form in both views). And depending on this, we need a concept for
+ // how those are saved to the recovery file.
+
+ MapCompTypeToCompDescs aMapCompDescs;
+
+ for (auto const& controller : i_rControllers)
+ {
+ Reference< XDatabaseDocumentUI > xDatabaseUI(controller, UNO_QUERY_THROW);
+ const Sequence< Reference< XComponent > > aComponents( xDatabaseUI->getSubComponents() );
+
+ for ( auto const & component : aComponents )
+ {
+ SubComponentRecovery aComponentRecovery( m_pData->aContext, xDatabaseUI, component );
+ aComponentRecovery.saveToRecoveryStorage( xRecoveryStorage, aMapCompDescs );
+ }
+ }
+
+ for (auto const& elem : aMapCompDescs)
+ {
+ Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement(
+ SubComponentRecovery::getComponentsStorageName( elem.first ), ElementModes::WRITE | ElementModes::NOCREATE ) );
+ lcl_writeObjectMap_throw( m_pData->aContext, xComponentsStor, elem.second );
+ tools::stor::commitStorageIfWriteable( xComponentsStor );
+ }
+ }
+
+ // commit the recovery storage
+ tools::stor::commitStorageIfWriteable( xRecoveryStorage );
+ }
+
+ void DatabaseDocumentRecovery::recoverSubDocuments( const Reference< XStorage >& i_rDocumentStorage,
+ const Reference< XController >& i_rTargetController )
+ {
+ ENSURE_OR_THROW( i_rDocumentStorage.is(), "illegal document storage" );
+ Reference< XDatabaseDocumentUI > xDocumentUI( i_rTargetController, UNO_QUERY_THROW );
+
+ if ( !i_rDocumentStorage->hasByName( sRecoveryDataSubStorageName ) )
+ // that's allowed
+ return;
+
+ // the "recovery" sub storage
+ Reference< XStorage > xRecoveryStorage = i_rDocumentStorage->openStorageElement( sRecoveryDataSubStorageName, ElementModes::READ );
+
+ // read the map from sub storages to object names
+ MapCompTypeToCompDescs aMapCompDescs;
+ const SubComponentType aKnownTypes[] = { TABLE, QUERY, FORM, REPORT, RELATION_DESIGN };
+ for (SubComponentType aKnownType : aKnownTypes)
+ {
+ if ( !xRecoveryStorage->hasByName( SubComponentRecovery::getComponentsStorageName( aKnownType ) ) )
+ continue;
+
+ Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement(
+ SubComponentRecovery::getComponentsStorageName( aKnownType ), ElementModes::READ ) );
+ lcl_readObjectMap_throw( m_pData->aContext, xComponentsStor, aMapCompDescs[ aKnownType ] );
+ xComponentsStor->dispose();
+ }
+
+ // recover all sub components as indicated by the map
+ for (auto const& elemMapCompDescs : aMapCompDescs)
+ {
+ const SubComponentType eComponentType = elemMapCompDescs.first;
+
+ // the storage for all components of the current type
+ Reference< XStorage > xComponentsStor( xRecoveryStorage->openStorageElement(
+ SubComponentRecovery::getComponentsStorageName( eComponentType ), ElementModes::READ ), UNO_SET_THROW );
+
+ // loop through all components of this type
+ for (auto const& elem : elemMapCompDescs.second)
+ {
+ const OUString sComponentName(elem.second.sName);
+ if ( !xComponentsStor->hasByName(elem.first) )
+ {
+ SAL_WARN( "dbaccess",
+ "DatabaseDocumentRecovery::recoverSubDocuments: inconsistent recovery storage: storage '" <<
+ elem.first <<
+ "' not found in '" <<
+ SubComponentRecovery::getComponentsStorageName( eComponentType ) <<
+ "', but required per map file!" );
+ continue;
+ }
+
+ // the controller needs to have a connection to be able to open sub components
+ if ( !xDocumentUI->isConnected() )
+ xDocumentUI->connect();
+
+ // recover the single component
+ Reference< XStorage > xCompStor( xComponentsStor->openStorageElement( elem.first, ElementModes::READ ) );
+ SubComponentRecovery aComponentRecovery( m_pData->aContext, xDocumentUI, eComponentType );
+ Reference< XComponent > xSubComponent( aComponentRecovery.recoverFromStorage( xCompStor, sComponentName, elem.second.bForEditing ) );
+
+ // at the moment, we only store, during session save, sub components which are modified. So, set this
+ // recovered sub component to "modified", too.
+ lcl_markModified( xSubComponent );
+ }
+
+ xComponentsStor->dispose();
+ }
+
+ xRecoveryStorage->dispose();
+
+ // now that we successfully recovered, removed the "recovery" sub storage
+ try
+ {
+ i_rDocumentStorage->removeElement( sRecoveryDataSubStorageName );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/settingsimport.cxx b/dbaccess/source/core/recovery/settingsimport.cxx
new file mode 100644
index 000000000..821dea045
--- /dev/null
+++ b/dbaccess/source/core/recovery/settingsimport.cxx
@@ -0,0 +1,216 @@
+/* -*- 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 "settingsimport.hxx"
+
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+#include <sax/tools/converter.hxx>
+#include <xmloff/xmltoken.hxx>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::Any;
+ using ::com::sun::star::xml::sax::XAttributeList;
+
+ // SettingsImport
+ SettingsImport::SettingsImport()
+ {
+ }
+
+ SettingsImport::~SettingsImport()
+ {
+ }
+
+ void SettingsImport::startElement( const Reference< XAttributeList >& i_rAttributes )
+ {
+ // find the name of the setting
+ if ( i_rAttributes.is() )
+ {
+ m_sItemName = i_rAttributes->getValueByName( "config:name" );
+ m_sItemType = i_rAttributes->getValueByName( "config:type" );
+ }
+ }
+
+ void SettingsImport::endElement()
+ {
+ }
+
+ void SettingsImport::characters( std::u16string_view i_rCharacters )
+ {
+ m_aCharacters.append( i_rCharacters );
+ }
+
+ void SettingsImport::split( const OUString& i_rElementName, OUString& o_rNamespace, OUString& o_rLocalName )
+ {
+ o_rNamespace.clear();
+ o_rLocalName = i_rElementName;
+ const sal_Int32 nSeparatorPos = i_rElementName.indexOf( ':' );
+ if ( nSeparatorPos > -1 )
+ {
+ o_rNamespace = i_rElementName.copy( 0, nSeparatorPos );
+ o_rLocalName = i_rElementName.copy( nSeparatorPos + 1 );
+ }
+
+ OSL_ENSURE( o_rNamespace == "config", "SettingsImport::split: unexpected namespace!" );
+ // our recovery file is kind of hand-made, so there shouldn't be anything else than "config".
+ // If there is, then just ignore it ...
+ }
+
+ // IgnoringSettingsImport
+ ::rtl::Reference< SettingsImport > IgnoringSettingsImport::nextState( const OUString& )
+ {
+ return this;
+ }
+
+ // OfficeSettingsImport
+ OfficeSettingsImport::OfficeSettingsImport( ::comphelper::NamedValueCollection& o_rSettings )
+ :m_rSettings( o_rSettings )
+ {
+ }
+
+ OfficeSettingsImport::~OfficeSettingsImport()
+ {
+ }
+
+ ::rtl::Reference< SettingsImport > OfficeSettingsImport::nextState( const OUString& i_rElementName )
+ {
+ // separate the namespace part from the element name
+ OUString sNamespace;
+ OUString sLocalName;
+ split( i_rElementName, sNamespace, sLocalName );
+
+ if ( sLocalName == "config-item-set" )
+ return new ConfigItemSetImport( m_rSettings );
+
+ SAL_WARN( "dbaccess", "unknown (or unsupported at this place) element name '"
+ << i_rElementName
+ << "', ignoring");
+ return new IgnoringSettingsImport;
+ }
+
+ // ConfigItemImport
+ ConfigItemImport::ConfigItemImport( ::comphelper::NamedValueCollection& o_rSettings )
+ :m_rSettings( o_rSettings )
+ {
+ }
+
+ ConfigItemImport::~ConfigItemImport()
+ {
+ }
+
+ ::rtl::Reference< SettingsImport > ConfigItemImport::nextState( const OUString& )
+ {
+ OSL_FAIL( "ConfigItemImport::nextState: unexpected: this class is responsible for child-less items only!" );
+ return new IgnoringSettingsImport;
+ }
+
+ void ConfigItemImport::endElement()
+ {
+ SettingsImport::endElement();
+
+ const OUString sItemName( getItemName() );
+ ENSURE_OR_RETURN_VOID( !sItemName.isEmpty(), "no item name -> no item value" );
+ Any aValue;
+ getItemValue( aValue );
+ m_rSettings.put( sItemName, aValue );
+ }
+
+ void ConfigItemImport::getItemValue( css::uno::Any& o_rValue ) const
+ {
+ o_rValue.clear();
+
+ // the characters building up th evalue
+ std::u16string_view sValue = getAccumulatedCharacters();
+
+ const OUString& rItemType( getItemType() );
+ ENSURE_OR_RETURN_VOID( !rItemType.isEmpty(), "no item type -> no item value" );
+
+ if ( ::xmloff::token::IsXMLToken( rItemType, ::xmloff::token::XML_INT ) )
+ {
+ sal_Int32 nValue(0);
+ if (::sax::Converter::convertNumber( nValue, sValue ))
+ {
+ o_rValue <<= nValue;
+ }
+ else
+ {
+ OSL_FAIL( "ConfigItemImport::getItemValue: could not convert an int value!" );
+ }
+ }
+ else if ( ::xmloff::token::IsXMLToken( rItemType, ::xmloff::token::XML_BOOLEAN ) )
+ {
+ bool bValue(false);
+ if (::sax::Converter::convertBool( bValue, sValue ))
+ {
+ o_rValue <<= bValue;
+ }
+ else
+ {
+ OSL_FAIL( "ConfigItemImport::getItemValue: could not convert a boolean value!" );
+ }
+ }
+ else if ( ::xmloff::token::IsXMLToken( rItemType, ::xmloff::token::XML_STRING ) )
+ {
+ o_rValue <<= OUString(sValue);
+ }
+ else
+ {
+ SAL_WARN( "dbaccess", "ConfigItemImport::getItemValue: unsupported item type '"
+ << rItemType << "', ignoring");
+ }
+ }
+
+ // ConfigItemSetImport
+ ConfigItemSetImport::ConfigItemSetImport( ::comphelper::NamedValueCollection& o_rSettings )
+ :ConfigItemImport( o_rSettings )
+ {
+ }
+
+ ConfigItemSetImport::~ConfigItemSetImport()
+ {
+ }
+
+ ::rtl::Reference< SettingsImport > ConfigItemSetImport::nextState( const OUString& i_rElementName )
+ {
+ // separate the namespace part from the element name
+ OUString sNamespace;
+ OUString sLocalName;
+ split( i_rElementName, sNamespace, sLocalName );
+
+ if ( sLocalName == "config-item-set" )
+ return new ConfigItemSetImport( m_aChildSettings );
+ if ( sLocalName == "config-item" )
+ return new ConfigItemImport( m_aChildSettings );
+
+ SAL_WARN( "dbaccess", "unknown element name '"
+ << i_rElementName << "', ignoring");
+ return new IgnoringSettingsImport;
+ }
+
+ void ConfigItemSetImport::getItemValue( Any& o_rValue ) const
+ {
+ o_rValue <<= m_aChildSettings.getPropertyValues();
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/settingsimport.hxx b/dbaccess/source/core/recovery/settingsimport.hxx
new file mode 100644
index 000000000..bc29bd727
--- /dev/null
+++ b/dbaccess/source/core/recovery/settingsimport.hxx
@@ -0,0 +1,163 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/xml/sax/XAttributeList.hpp>
+
+#include <comphelper/namedvaluecollection.hxx>
+#include <rtl/ref.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <salhelper/simplereferenceobject.hxx>
+
+namespace dbaccess
+{
+
+ // SettingsImport
+ /** a simplified version of xmloff/DocumentSettingsContext
+
+ It would be nice if the DocumentSettingsContext would not be that tightly interwoven with the SvXMLImport
+ class, so we could re-use it here ...
+ */
+ class SettingsImport : public salhelper::SimpleReferenceObject
+ {
+ public:
+ SettingsImport();
+
+ // own overridables
+ virtual ::rtl::Reference< SettingsImport > nextState(
+ const OUString& i_rElementName
+ ) = 0;
+ void startElement(
+ const css::uno::Reference< css::xml::sax::XAttributeList >& i_rAttributes
+ );
+ virtual void endElement();
+ void characters( std::u16string_view i_rCharacters );
+
+ protected:
+ virtual ~SettingsImport() override;
+
+ protected:
+ static void split( const OUString& i_rElementName, OUString& o_rNamespace, OUString& o_rLocalName );
+
+ protected:
+ const OUString& getItemName() const { return m_sItemName; }
+ const OUString& getItemType() const { return m_sItemType; }
+ const OUStringBuffer& getAccumulatedCharacters() const { return m_aCharacters; }
+
+ private:
+ // value of the config:name attribute, if any
+ OUString m_sItemName;
+ // value of the config:type attribute, if any
+ OUString m_sItemType;
+ // accumulated characters, if any
+ OUStringBuffer m_aCharacters;
+ };
+
+ // IgnoringSettingsImport
+ class IgnoringSettingsImport : public SettingsImport
+ {
+ public:
+ IgnoringSettingsImport()
+ {
+ }
+
+ // SettingsImport overridables
+ virtual ::rtl::Reference< SettingsImport > nextState(
+ const OUString& i_rElementName
+ ) override;
+
+ private:
+ virtual ~IgnoringSettingsImport() override
+ {
+ }
+ };
+
+ // OfficeSettingsImport
+ class OfficeSettingsImport : public SettingsImport
+ {
+ public:
+ explicit OfficeSettingsImport( ::comphelper::NamedValueCollection& o_rSettings );
+
+ // SettingsImport overridables
+ virtual ::rtl::Reference< SettingsImport > nextState(
+ const OUString& i_rElementName
+ ) override;
+
+ protected:
+ virtual ~OfficeSettingsImport() override;
+
+ private:
+ // the settings collection to which |this| will contribute a single setting
+ ::comphelper::NamedValueCollection& m_rSettings;
+ };
+
+ // ConfigItemSetImport
+ class ConfigItemImport : public SettingsImport
+ {
+ public:
+ explicit ConfigItemImport( ::comphelper::NamedValueCollection& o_rSettings );
+
+ protected:
+ virtual ~ConfigItemImport() override;
+
+ public:
+ // SettingsImport overridables
+ virtual ::rtl::Reference< SettingsImport > nextState(
+ const OUString& i_rElementName
+ ) override;
+ virtual void endElement() override;
+
+ protected:
+ // own overridables
+ /// retrieves the value represented by the element
+ virtual void getItemValue( css::uno::Any& o_rValue ) const;
+
+ private:
+ // the settings collection to which |this| will contribute a single setting
+ ::comphelper::NamedValueCollection& m_rSettings;
+ };
+
+ // ConfigItemSetImport
+ class ConfigItemSetImport : public ConfigItemImport
+ {
+ public:
+ explicit ConfigItemSetImport( ::comphelper::NamedValueCollection& o_rSettings );
+
+ protected:
+ virtual ~ConfigItemSetImport() override;
+
+ public:
+ // SettingsImport overridables
+ virtual ::rtl::Reference< SettingsImport > nextState(
+ const OUString& i_rElementName
+ ) override;
+
+ protected:
+ // ConfigItemImport overridables
+ virtual void getItemValue( css::uno::Any& o_rValue ) const override;
+
+ private:
+ /// the settings represented by our child elements
+ ::comphelper::NamedValueCollection m_aChildSettings;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/storagestream.cxx b/dbaccess/source/core/recovery/storagestream.cxx
new file mode 100644
index 000000000..2831f406b
--- /dev/null
+++ b/dbaccess/source/core/recovery/storagestream.cxx
@@ -0,0 +1,55 @@
+/* -*- 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 "storagestream.hxx"
+
+#include <com/sun/star/embed/ElementModes.hpp>
+
+#include <tools/diagnose_ex.h>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::embed::XStorage;
+ using ::com::sun::star::io::XStream;
+
+ namespace ElementModes = ::com::sun::star::embed::ElementModes;
+
+ // StorageOutputStream
+ StorageOutputStream::StorageOutputStream( const Reference< XStorage >& i_rParentStorage,
+ const OUString& i_rStreamName
+ )
+ {
+ ENSURE_OR_THROW( i_rParentStorage.is(), "illegal stream" );
+
+ const Reference< XStream > xStream(
+ i_rParentStorage->openStreamElement( i_rStreamName, ElementModes::READWRITE ), UNO_SET_THROW );
+ m_xOutputStream.set( xStream->getOutputStream(), UNO_SET_THROW );
+ }
+
+ StorageOutputStream::~StorageOutputStream()
+ {
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/storagestream.hxx b/dbaccess/source/core/recovery/storagestream.hxx
new file mode 100644
index 000000000..64c7e369d
--- /dev/null
+++ b/dbaccess/source/core/recovery/storagestream.hxx
@@ -0,0 +1,51 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/embed/XStorage.hpp>
+
+namespace dbaccess
+{
+
+ // StorageOutputStream
+ /** convenience wrapper around a stream living in a storage
+ */
+ class StorageOutputStream
+ {
+ public:
+ StorageOutputStream(
+ const css::uno::Reference< css::embed::XStorage >& i_rParentStorage,
+ const OUString& i_rStreamName
+ );
+ virtual ~StorageOutputStream();
+
+ protected:
+ const css::uno::Reference< css::io::XOutputStream >&
+ getOutputStream() const { return m_xOutputStream; }
+
+ private:
+ css::uno::Reference< css::io::XOutputStream >
+ m_xOutputStream;
+ };
+
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/storagetextstream.cxx b/dbaccess/source/core/recovery/storagetextstream.cxx
new file mode 100644
index 000000000..32f68da9a
--- /dev/null
+++ b/dbaccess/source/core/recovery/storagetextstream.cxx
@@ -0,0 +1,71 @@
+/* -*- 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 "storagetextstream.hxx"
+
+#include <com/sun/star/io/TextOutputStream.hpp>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::embed::XStorage;
+ using ::com::sun::star::io::TextOutputStream;
+ using ::com::sun::star::io::XTextOutputStream2;
+
+ // StorageTextOutputStream_Data
+ struct StorageTextOutputStream_Data
+ {
+ Reference< XTextOutputStream2 > xTextOutput;
+ };
+
+ constexpr OUStringLiteral sLineFeed = u"\n";
+
+ // StorageTextOutputStream
+ StorageTextOutputStream::StorageTextOutputStream( const Reference<XComponentContext>& i_rContext,
+ const Reference< XStorage >& i_rParentStorage,
+ const OUString& i_rStreamName
+ )
+ :StorageOutputStream( i_rParentStorage, i_rStreamName )
+ ,m_pData( new StorageTextOutputStream_Data )
+ {
+ m_pData->xTextOutput = TextOutputStream::create( i_rContext );
+ m_pData->xTextOutput->setEncoding( "UTF-8" );
+ m_pData->xTextOutput->setOutputStream( getOutputStream() );
+ }
+
+ StorageTextOutputStream::~StorageTextOutputStream()
+ {
+ }
+
+ void StorageTextOutputStream::writeLine( const OUString& i_rLine )
+ {
+ m_pData->xTextOutput->writeString( i_rLine );
+ m_pData->xTextOutput->writeString( sLineFeed );
+ }
+
+ void StorageTextOutputStream::writeLine()
+ {
+ m_pData->xTextOutput->writeString( sLineFeed );
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/storagetextstream.hxx b/dbaccess/source/core/recovery/storagetextstream.hxx
new file mode 100644
index 000000000..46c3e5b2e
--- /dev/null
+++ b/dbaccess/source/core/recovery/storagetextstream.hxx
@@ -0,0 +1,52 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "storagestream.hxx"
+
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+#include <memory>
+
+namespace dbaccess
+{
+
+ // StorageTextStream
+ struct StorageTextOutputStream_Data;
+ class StorageTextOutputStream : public StorageOutputStream
+ {
+ public:
+ StorageTextOutputStream(
+ const css::uno::Reference< css::uno::XComponentContext >& i_rContext,
+ const css::uno::Reference< css::embed::XStorage >& i_rParentStorage,
+ const OUString& i_rStreamName
+ );
+ virtual ~StorageTextOutputStream() override;
+
+ void writeLine( const OUString& i_rLine );
+ void writeLine();
+
+ private:
+ std::unique_ptr< StorageTextOutputStream_Data > m_pData;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/storagexmlstream.cxx b/dbaccess/source/core/recovery/storagexmlstream.cxx
new file mode 100644
index 000000000..e76dabefe
--- /dev/null
+++ b/dbaccess/source/core/recovery/storagexmlstream.cxx
@@ -0,0 +1,151 @@
+/* -*- 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 "storagexmlstream.hxx"
+
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+#include <com/sun/star/xml/sax/Parser.hpp>
+#include <com/sun/star/xml/sax/Writer.hpp>
+
+#include <rtl/ref.hxx>
+#include <tools/diagnose_ex.h>
+#include <xmloff/attrlist.hxx>
+
+#include <stack>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::XComponentContext;
+ using ::com::sun::star::embed::XStorage;
+ using ::com::sun::star::xml::sax::XDocumentHandler;
+ using ::com::sun::star::xml::sax::XWriter;
+ using ::com::sun::star::xml::sax::Writer;
+ using ::com::sun::star::xml::sax::Parser;
+ using ::com::sun::star::xml::sax::InputSource;
+
+ // StorageXMLOutputStream_Data
+ struct StorageXMLOutputStream_Data
+ {
+ Reference< XDocumentHandler > xHandler;
+ std::stack< OUString > aElements;
+ ::rtl::Reference< SvXMLAttributeList > xAttributes;
+ };
+
+ // StorageXMLOutputStream
+ StorageXMLOutputStream::StorageXMLOutputStream( const Reference<XComponentContext>& i_rContext,
+ const Reference< XStorage >& i_rParentStorage,
+ const OUString& i_rStreamName )
+ :StorageOutputStream( i_rParentStorage, i_rStreamName )
+ ,m_pData( new StorageXMLOutputStream_Data )
+ {
+ const Reference< XWriter > xSaxWriter = Writer::create( i_rContext );
+ xSaxWriter->setOutputStream( getOutputStream() );
+
+ m_pData->xHandler.set( xSaxWriter, UNO_QUERY_THROW );
+ m_pData->xHandler->startDocument();
+
+ m_pData->xAttributes = new SvXMLAttributeList;
+ }
+
+ StorageXMLOutputStream::~StorageXMLOutputStream()
+ {
+ }
+
+ void StorageXMLOutputStream::close()
+ {
+ ENSURE_OR_RETURN_VOID( m_pData->xHandler.is(), "illegal document handler" );
+ m_pData->xHandler->endDocument();
+ // do not call the base class, it would call closeOutput on the output stream, which is already done by
+ // endDocument
+ }
+
+ void StorageXMLOutputStream::addAttribute( const OUString& i_rName, const OUString& i_rValue ) const
+ {
+ m_pData->xAttributes->AddAttribute( i_rName, i_rValue );
+ }
+
+ void StorageXMLOutputStream::startElement( const OUString& i_rElementName ) const
+ {
+ ENSURE_OR_RETURN_VOID( m_pData->xHandler.is(), "no document handler" );
+
+ m_pData->xHandler->startElement( i_rElementName, m_pData->xAttributes );
+ m_pData->xAttributes = new SvXMLAttributeList;
+ m_pData->aElements.push( i_rElementName );
+ }
+
+ void StorageXMLOutputStream::endElement() const
+ {
+ ENSURE_OR_RETURN_VOID( m_pData->xHandler.is(), "no document handler" );
+ ENSURE_OR_RETURN_VOID( !m_pData->aElements.empty(), "no element on the stack" );
+
+ const OUString sElementName( m_pData->aElements.top() );
+ m_pData->xHandler->endElement( sElementName );
+ m_pData->aElements.pop();
+ }
+
+ void StorageXMLOutputStream::ignorableWhitespace( const OUString& i_rWhitespace ) const
+ {
+ ENSURE_OR_RETURN_VOID( m_pData->xHandler.is(), "no document handler" );
+
+ m_pData->xHandler->ignorableWhitespace( i_rWhitespace );
+ }
+
+ void StorageXMLOutputStream::characters( const OUString& i_rCharacters ) const
+ {
+ ENSURE_OR_RETURN_VOID( m_pData->xHandler.is(), "no document handler" );
+
+ m_pData->xHandler->characters( i_rCharacters );
+ }
+
+ // StorageXMLInputStream
+ StorageXMLInputStream::StorageXMLInputStream( const Reference<XComponentContext>& i_rContext,
+ const Reference< XStorage >& i_rParentStorage,
+ const OUString& i_rStreamName )
+ {
+ ENSURE_OR_THROW( i_rParentStorage.is(), "illegal stream" );
+
+ const Reference< css::io::XStream > xStream(
+ i_rParentStorage->openStreamElement( i_rStreamName, css::embed::ElementModes::READ ), css::uno::UNO_SET_THROW );
+ m_xInputStream.set( xStream->getInputStream(), css::uno::UNO_SET_THROW );
+
+ m_xParser.set( Parser::create(i_rContext) );
+ }
+
+ void StorageXMLInputStream::import( const Reference< XDocumentHandler >& i_rHandler )
+ {
+ ENSURE_OR_THROW( i_rHandler.is(), "illegal document handler (NULL)" );
+
+ InputSource aInputSource;
+ aInputSource.aInputStream = m_xInputStream;
+
+ m_xParser->setDocumentHandler( i_rHandler );
+ m_xParser->parseStream( aInputSource );
+ }
+
+ StorageXMLInputStream::~StorageXMLInputStream()
+ {
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/storagexmlstream.hxx b/dbaccess/source/core/recovery/storagexmlstream.hxx
new file mode 100644
index 000000000..fd762ae05
--- /dev/null
+++ b/dbaccess/source/core/recovery/storagexmlstream.hxx
@@ -0,0 +1,88 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "storagestream.hxx"
+
+#include <com/sun/star/xml/sax/XParser.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+
+#include <memory>
+
+namespace dbaccess
+{
+
+ // StorageXMLOutputStream
+ struct StorageXMLOutputStream_Data;
+ class StorageXMLOutputStream : public StorageOutputStream
+ {
+ public:
+ StorageXMLOutputStream(
+ const css::uno::Reference< css::uno::XComponentContext >& i_rContext,
+ const css::uno::Reference< css::embed::XStorage >& i_rParentStorage,
+ const OUString& i_rStreamName
+ );
+ virtual ~StorageXMLOutputStream() override;
+
+ void close();
+
+ void addAttribute( const OUString& i_rName, const OUString& i_rValue ) const;
+
+ void startElement( const OUString& i_rElementName ) const;
+ void endElement() const;
+
+ void ignorableWhitespace( const OUString& i_rWhitespace ) const;
+ void characters( const OUString& i_rCharacters ) const;
+
+ private:
+ StorageXMLOutputStream( const StorageXMLOutputStream& ) = delete;
+ StorageXMLOutputStream& operator=( const StorageXMLOutputStream& ) = delete;
+
+ private:
+ std::unique_ptr< StorageXMLOutputStream_Data > m_pData;
+ };
+
+ class StorageXMLInputStream
+ {
+ public:
+ StorageXMLInputStream(
+ const css::uno::Reference< css::uno::XComponentContext >& i_rContext,
+ const css::uno::Reference< css::embed::XStorage >& i_rParentStorage,
+ const OUString& i_rStreamName
+ );
+ ~StorageXMLInputStream();
+
+ void import(
+ const css::uno::Reference< css::xml::sax::XDocumentHandler >& i_rHandler
+ );
+
+ StorageXMLInputStream( const StorageXMLInputStream& ) = delete;
+ StorageXMLInputStream& operator=( const StorageXMLInputStream& ) = delete;
+
+ private:
+ css::uno::Reference< css::xml::sax::XParser > m_xParser;
+ css::uno::Reference< css::io::XInputStream > m_xInputStream;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/subcomponentloader.cxx b/dbaccess/source/core/recovery/subcomponentloader.cxx
new file mode 100644
index 000000000..3393c3d13
--- /dev/null
+++ b/dbaccess/source/core/recovery/subcomponentloader.cxx
@@ -0,0 +1,124 @@
+/* -*- 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 "subcomponentloader.hxx"
+
+#include <com/sun/star/ucb/Command.hpp>
+#include <com/sun/star/frame/XController2.hpp>
+
+#include <tools/diagnose_ex.h>
+
+namespace dbaccess
+{
+
+ using ::com::sun::star::uno::Reference;
+ using ::com::sun::star::uno::UNO_QUERY_THROW;
+ using ::com::sun::star::uno::UNO_SET_THROW;
+ using ::com::sun::star::uno::Exception;
+ using ::com::sun::star::frame::XController;
+ using ::com::sun::star::frame::XFrame;
+ using ::com::sun::star::awt::XWindow;
+ using ::com::sun::star::awt::WindowEvent;
+ using ::com::sun::star::lang::EventObject;
+ using ::com::sun::star::ucb::Command;
+ using ::com::sun::star::ucb::XCommandProcessor;
+ using ::com::sun::star::frame::XController2;
+ using ::com::sun::star::lang::XComponent;
+
+ // SubComponentLoader
+ SubComponentLoader::SubComponentLoader( const Reference< XController >& i_rApplicationController,
+ const Reference< XCommandProcessor >& i_rSubDocumentDefinition )
+ :mxDocDefCommands( i_rSubDocumentDefinition )
+ {
+ // add as window listener to the controller's container window, so we get notified when it is shown
+ Reference< XController2 > xController( i_rApplicationController, UNO_QUERY_THROW );
+ mxAppComponentWindow.set( xController->getComponentWindow(), UNO_SET_THROW );
+
+ osl_atomic_increment( &m_refCount );
+ {
+ mxAppComponentWindow->addWindowListener( this );
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+ SubComponentLoader::SubComponentLoader( const Reference< XController >& i_rApplicationController,
+ const Reference< XComponent >& i_rNonDocumentComponent )
+ :mxNonDocComponent( i_rNonDocumentComponent )
+ {
+ // add as window listener to the controller's container window, so we get notified when it is shown
+ Reference< XController2 > xController( i_rApplicationController, UNO_QUERY_THROW );
+ mxAppComponentWindow.set( xController->getComponentWindow(), UNO_SET_THROW );
+
+ osl_atomic_increment( &m_refCount );
+ {
+ mxAppComponentWindow->addWindowListener( this );
+ }
+ osl_atomic_decrement( &m_refCount );
+ }
+
+ SubComponentLoader::~SubComponentLoader()
+ {
+ }
+
+ void SAL_CALL SubComponentLoader::windowResized( const WindowEvent& )
+ {
+ }
+
+ void SAL_CALL SubComponentLoader::windowMoved( const WindowEvent& )
+ {
+ }
+
+ void SAL_CALL SubComponentLoader::windowShown( const EventObject& )
+ {
+ try
+ {
+ if ( mxDocDefCommands.is() )
+ {
+ Command aCommandOpen;
+ aCommandOpen.Name = "show";
+
+ const sal_Int32 nCommandIdentifier = mxDocDefCommands->createCommandIdentifier();
+ mxDocDefCommands->execute( aCommandOpen, nCommandIdentifier, nullptr );
+ }
+ else
+ {
+ const Reference< XController > xController( mxNonDocComponent, UNO_QUERY_THROW );
+ const Reference< XFrame > xFrame( xController->getFrame(), UNO_SET_THROW );
+ const Reference< XWindow > xWindow( xFrame->getContainerWindow(), UNO_SET_THROW );
+ xWindow->setVisible( true );
+ }
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ mxAppComponentWindow->removeWindowListener( this );
+ }
+
+ void SAL_CALL SubComponentLoader::windowHidden( const EventObject& )
+ {
+ }
+
+ void SAL_CALL SubComponentLoader::disposing( const EventObject& )
+ {
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/subcomponentloader.hxx b/dbaccess/source/core/recovery/subcomponentloader.hxx
new file mode 100644
index 000000000..4ab867880
--- /dev/null
+++ b/dbaccess/source/core/recovery/subcomponentloader.hxx
@@ -0,0 +1,71 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/awt/XWindowListener.hpp>
+#include <com/sun/star/frame/XController.hpp>
+#include <com/sun/star/lang/XComponent.hpp>
+#include <com/sun/star/ucb/XCommandProcessor.hpp>
+
+#include <cppuhelper/implbase.hxx>
+
+namespace dbaccess
+{
+
+ // SubComponentLoader
+ typedef ::cppu::WeakImplHelper< css::awt::XWindowListener
+ > SubComponentLoader_Base;
+ /** is a helper class which loads/opens a given sub component as soon as the main application
+ window becomes visible.
+ */
+ class SubComponentLoader : public SubComponentLoader_Base
+ {
+ public:
+ SubComponentLoader(
+ const css::uno::Reference< css::frame::XController >& i_rApplicationController,
+ const css::uno::Reference< css::ucb::XCommandProcessor >& i_rSubDocumentDefinition
+ );
+
+ SubComponentLoader(
+ const css::uno::Reference< css::frame::XController >& i_rApplicationController,
+ const css::uno::Reference< css::lang::XComponent >& i_rNonDocumentComponent
+ );
+
+ // XWindowListener
+ virtual void SAL_CALL windowResized( const css::awt::WindowEvent& e ) override;
+ virtual void SAL_CALL windowMoved( const css::awt::WindowEvent& e ) override;
+ virtual void SAL_CALL windowShown( const css::lang::EventObject& e ) override;
+ virtual void SAL_CALL windowHidden( const css::lang::EventObject& e ) override;
+
+ // XEventListener
+ virtual void SAL_CALL disposing( const css::lang::EventObject& Source ) override;
+
+ protected:
+ virtual ~SubComponentLoader() override;
+
+ private:
+ const css::uno::Reference< css::ucb::XCommandProcessor > mxDocDefCommands;
+ const css::uno::Reference< css::lang::XComponent > mxNonDocComponent;
+ css::uno::Reference< css::awt::XWindow > mxAppComponentWindow;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/subcomponentrecovery.cxx b/dbaccess/source/core/recovery/subcomponentrecovery.cxx
new file mode 100644
index 000000000..e7ffffd61
--- /dev/null
+++ b/dbaccess/source/core/recovery/subcomponentrecovery.cxx
@@ -0,0 +1,628 @@
+/* -*- 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 "subcomponentrecovery.hxx"
+
+#include <sdbcoretools.hxx>
+#include "storagexmlstream.hxx"
+#include "subcomponentloader.hxx"
+#include "settingsimport.hxx"
+
+#include <com/sun/star/embed/ElementModes.hpp>
+#include <com/sun/star/frame/ModuleManager.hpp>
+#include <com/sun/star/document/XStorageBasedDocument.hpp>
+#include <com/sun/star/ucb/XCommandProcessor.hpp>
+#include <com/sun/star/container/XHierarchicalNameAccess.hpp>
+#include <com/sun/star/sdb/XFormDocumentsSupplier.hpp>
+#include <com/sun/star/sdb/XReportDocumentsSupplier.hpp>
+#include <com/sun/star/xml/sax/XDocumentHandler.hpp>
+
+#include <comphelper/namedvaluecollection.hxx>
+#include <cppuhelper/implbase.hxx>
+#include <connectivity/dbtools.hxx>
+#include <tools/diagnose_ex.h>
+#include <sal/log.hxx>
+#include <xmloff/XMLSettingsExportContext.hxx>
+#include <xmloff/SettingsExportHelper.hxx>
+
+#include <stack>
+
+namespace dbaccess
+{
+
+ using css::uno::Reference;
+ using css::uno::XInterface;
+ using css::uno::UNO_QUERY;
+ using css::uno::UNO_QUERY_THROW;
+ using css::uno::UNO_SET_THROW;
+ using css::uno::Exception;
+ using css::uno::RuntimeException;
+ using css::uno::Any;
+ using css::uno::Sequence;
+ using css::uno::XComponentContext;
+ using css::embed::XStorage;
+ using css::sdb::application::XDatabaseDocumentUI;
+ using css::beans::Pair;
+ using css::frame::ModuleManager;
+ using css::frame::XModuleManager2;
+ using css::lang::XComponent;
+ using css::frame::XModel;
+ using css::frame::XController;
+ using css::beans::XPropertySet;
+ using css::beans::PropertyValue;
+ using css::document::XStorageBasedDocument;
+ using css::ucb::XCommandProcessor;
+ using css::container::XHierarchicalNameAccess;
+ using css::sdb::XFormDocumentsSupplier;
+ using css::sdb::XReportDocumentsSupplier;
+ using css::xml::sax::XLocator;
+ using css::xml::sax::XDocumentHandler;
+ using css::xml::sax::XAttributeList;
+
+ namespace ElementModes = css::embed::ElementModes;
+ namespace DatabaseObject = css::sdb::application::DatabaseObject;
+
+ // helper
+ namespace
+ {
+ OUString lcl_getComponentStorageBaseName( const SubComponentType i_eType )
+ {
+ switch ( i_eType )
+ {
+ case FORM:
+ return "form";
+ case REPORT:
+ return "report";
+ case TABLE:
+ return "table";
+ case QUERY:
+ return "query";
+ default:
+ break;
+ }
+
+ OSL_FAIL( "lcl_getComponentStorageBaseName: unimplemented case!" );
+ return OUString();
+ }
+
+ SubComponentType lcl_databaseObjectToSubComponentType( const sal_Int32 i_nObjectType )
+ {
+ switch ( i_nObjectType )
+ {
+ case DatabaseObject::TABLE: return TABLE;
+ case DatabaseObject::QUERY: return QUERY;
+ case DatabaseObject::FORM: return FORM;
+ case DatabaseObject::REPORT:return REPORT;
+ default:
+ break;
+ }
+ return UNKNOWN;
+ }
+
+ bool lcl_determineReadOnly( const Reference< XComponent >& i_rComponent )
+ {
+ Reference< XModel > xDocument( i_rComponent, UNO_QUERY );
+ if ( !xDocument.is() )
+ {
+ Reference< XController > xController( i_rComponent, UNO_QUERY_THROW );
+ xDocument = xController->getModel();
+ }
+
+ if ( !xDocument.is() )
+ return false;
+
+ ::comphelper::NamedValueCollection aDocArgs( xDocument->getArgs() );
+ return aDocArgs.getOrDefault( "ReadOnly", false );
+ }
+
+ Reference< XCommandProcessor > lcl_getSubComponentDef_nothrow( const Reference< XDatabaseDocumentUI >& i_rAppUI,
+ const SubComponentType i_eType, const OUString& i_rName )
+ {
+ Reference< XController > xController( i_rAppUI, UNO_QUERY_THROW );
+ ENSURE_OR_RETURN( ( i_eType == FORM ) || ( i_eType == REPORT ), "lcl_getSubComponentDef_nothrow: illegal controller", nullptr );
+
+ Reference< XCommandProcessor > xCommandProcessor;
+ try
+ {
+ Reference< XHierarchicalNameAccess > xDefinitionContainer;
+ if ( i_eType == FORM )
+ {
+ Reference< XFormDocumentsSupplier > xSuppForms( xController->getModel(), UNO_QUERY_THROW );
+ xDefinitionContainer.set( xSuppForms->getFormDocuments(), UNO_QUERY_THROW );
+ }
+ else
+ {
+ Reference< XReportDocumentsSupplier > xSuppReports( xController->getModel(), UNO_QUERY_THROW );
+ xDefinitionContainer.set( xSuppReports->getReportDocuments(), UNO_QUERY_THROW );
+ }
+ xCommandProcessor.set( xDefinitionContainer->getByHierarchicalName( i_rName ), UNO_QUERY_THROW );
+ }
+ catch( const Exception& )
+ {
+ DBG_UNHANDLED_EXCEPTION("dbaccess");
+ }
+ return xCommandProcessor;
+ }
+
+ constexpr OUStringLiteral sSettingsStreamName = u"settings.xml";
+ constexpr OUStringLiteral sCurrentQueryDesignName = u"ooo:current-query-design";
+ }
+
+ namespace {
+
+ // SettingsExportContext
+ class SettingsExportContext : public ::xmloff::XMLSettingsExportContext
+ {
+ public:
+ SettingsExportContext( const Reference<XComponentContext>& i_rContext, const StorageXMLOutputStream& i_rDelegator )
+ :m_rContext( i_rContext )
+ ,m_rDelegator( i_rDelegator )
+ ,m_aNamespace( ::xmloff::token::GetXMLToken( ::xmloff::token::XML_NP_CONFIG ) )
+ {
+ }
+
+ virtual ~SettingsExportContext()
+ {
+ }
+
+ public:
+ virtual void AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, const OUString& i_rValue ) override;
+ virtual void AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, enum ::xmloff::token::XMLTokenEnum i_eValue ) override;
+ virtual void StartElement( enum ::xmloff::token::XMLTokenEnum i_eName ) override;
+ virtual void EndElement ( const bool i_bIgnoreWhitespace ) override;
+ virtual void Characters( const OUString& i_rCharacters ) override;
+
+ virtual css::uno::Reference< css::uno::XComponentContext >
+ GetComponentContext() const override;
+
+ private:
+ OUString impl_prefix( const ::xmloff::token::XMLTokenEnum i_eToken )
+ {
+ return m_aNamespace + ":" + ::xmloff::token::GetXMLToken( i_eToken );
+ }
+
+ private:
+ const Reference<XComponentContext>& m_rContext;
+ const StorageXMLOutputStream& m_rDelegator;
+ const OUString m_aNamespace;
+ };
+
+ }
+
+ void SettingsExportContext::AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, const OUString& i_rValue )
+ {
+ m_rDelegator.addAttribute( impl_prefix( i_eName ), i_rValue );
+ }
+
+ void SettingsExportContext::AddAttribute( enum ::xmloff::token::XMLTokenEnum i_eName, enum ::xmloff::token::XMLTokenEnum i_eValue )
+ {
+ m_rDelegator.addAttribute( impl_prefix( i_eName ), ::xmloff::token::GetXMLToken( i_eValue ) );
+ }
+
+ void SettingsExportContext::StartElement( enum ::xmloff::token::XMLTokenEnum i_eName )
+ {
+ m_rDelegator.ignorableWhitespace( " " );
+
+ m_rDelegator.startElement( impl_prefix( i_eName ) );
+ }
+
+ void SettingsExportContext::EndElement( const bool i_bIgnoreWhitespace )
+ {
+ if ( i_bIgnoreWhitespace )
+ m_rDelegator.ignorableWhitespace( " " );
+ m_rDelegator.endElement();
+ }
+
+ void SettingsExportContext::Characters( const OUString& i_rCharacters )
+ {
+ m_rDelegator.characters( i_rCharacters );
+ }
+
+ Reference< css::uno::XComponentContext > SettingsExportContext::GetComponentContext() const
+ {
+ return m_rContext;
+ }
+
+ // SettingsDocumentHandler
+ typedef ::cppu::WeakImplHelper< XDocumentHandler
+ > SettingsDocumentHandler_Base;
+
+ namespace {
+
+ class SettingsDocumentHandler : public SettingsDocumentHandler_Base
+ {
+ public:
+ SettingsDocumentHandler()
+ {
+ }
+
+ protected:
+ virtual ~SettingsDocumentHandler() override
+ {
+ }
+
+ public:
+ // XDocumentHandler
+ virtual void SAL_CALL startDocument( ) override;
+ virtual void SAL_CALL endDocument( ) override;
+ virtual void SAL_CALL startElement( const OUString& aName, const Reference< XAttributeList >& xAttribs ) override;
+ virtual void SAL_CALL endElement( const OUString& aName ) override;
+ virtual void SAL_CALL characters( const OUString& aChars ) override;
+ virtual void SAL_CALL ignorableWhitespace( const OUString& aWhitespaces ) override;
+ virtual void SAL_CALL processingInstruction( const OUString& aTarget, const OUString& aData ) override;
+ virtual void SAL_CALL setDocumentLocator( const Reference< XLocator >& xLocator ) override;
+
+ const ::comphelper::NamedValueCollection& getSettings() const { return m_aSettings; }
+
+ private:
+ std::stack< ::rtl::Reference< SettingsImport > > m_aStates;
+ ::comphelper::NamedValueCollection m_aSettings;
+ };
+
+ }
+
+ void SAL_CALL SettingsDocumentHandler::startDocument( )
+ {
+ }
+
+ void SAL_CALL SettingsDocumentHandler::endDocument( )
+ {
+ }
+
+ void SAL_CALL SettingsDocumentHandler::startElement( const OUString& i_Name, const Reference< XAttributeList >& i_Attribs )
+ {
+ ::rtl::Reference< SettingsImport > pNewState;
+
+ if ( m_aStates.empty() )
+ {
+ if ( i_Name == "office:settings" )
+ {
+ pNewState = new OfficeSettingsImport( m_aSettings );
+ }
+ else
+ {
+ OSL_FAIL( "SettingsDocumentHandler::startElement: invalid settings file!" );
+ // Yes, that's not correct. Somebody could, in theory, give us a document which starts with "foo:settings",
+ // where "foo" is mapped to the proper namespace URL.
+ // However, there's no need to bother with this. The "recovery" sub storage we're recovering from is
+ // not part of ODF, so we can impose any format restrictions on it ...
+ }
+ }
+ else
+ {
+ ::rtl::Reference< SettingsImport > pCurrentState( m_aStates.top() );
+ pNewState = pCurrentState->nextState( i_Name );
+ }
+
+ ENSURE_OR_THROW( pNewState.is(), "no new state - aborting import" );
+ pNewState->startElement( i_Attribs );
+
+ m_aStates.push( pNewState );
+ }
+
+ void SAL_CALL SettingsDocumentHandler::endElement( const OUString& )
+ {
+ ENSURE_OR_THROW( !m_aStates.empty(), "no active element" );
+
+ ::rtl::Reference< SettingsImport > pCurrentState( m_aStates.top() );
+ pCurrentState->endElement();
+ m_aStates.pop();
+ }
+
+ void SAL_CALL SettingsDocumentHandler::characters( const OUString& i_Chars )
+ {
+ ENSURE_OR_THROW( !m_aStates.empty(), "no active element" );
+
+ ::rtl::Reference< SettingsImport > pCurrentState( m_aStates.top() );
+ pCurrentState->characters( i_Chars );
+ }
+
+ void SAL_CALL SettingsDocumentHandler::ignorableWhitespace( const OUString& )
+ {
+ // ignore them - that's why they're called "ignorable"
+ }
+
+ void SAL_CALL SettingsDocumentHandler::processingInstruction( const OUString&, const OUString& )
+ {
+ OSL_FAIL( "SettingsDocumentHandler::processingInstruction: unexpected ..." );
+ }
+
+ void SAL_CALL SettingsDocumentHandler::setDocumentLocator( const Reference< XLocator >& ) {}
+
+ // SubComponentRecovery
+ OUString SubComponentRecovery::getComponentsStorageName( const SubComponentType i_eType )
+ {
+ switch ( i_eType )
+ {
+ case FORM:
+ return "forms";
+ case REPORT:
+ return "reports";
+ case TABLE:
+ return "tables";
+ case QUERY:
+ return "queries";
+ case RELATION_DESIGN:
+ return "relations";
+ default:
+ break;
+ }
+
+ OSL_FAIL( "SubComponentRecovery::getComponentsStorageName: unimplemented case!" );
+ return OUString();
+ }
+
+ void SubComponentRecovery::saveToRecoveryStorage( const Reference< XStorage >& i_rRecoveryStorage,
+ MapCompTypeToCompDescs& io_mapCompDescs )
+ {
+ if ( m_eType == UNKNOWN )
+ // quite fatal, but has already been reported (as assertion) before
+ return;
+
+ // open the sub storage for the given kind of components
+ const OUString& rStorageName( getComponentsStorageName( m_eType ) );
+ const Reference< XStorage > xComponentsStorage( i_rRecoveryStorage->openStorageElement(
+ rStorageName, ElementModes::READWRITE ), UNO_SET_THROW );
+
+ // find a free sub storage name, and create Yet Another Sub Storage
+ const OUString& rBaseName( lcl_getComponentStorageBaseName( m_eType ) );
+ const OUString sStorName = ::dbtools::createUniqueName( xComponentsStorage, rBaseName );
+ const Reference< XStorage > xObjectStor( xComponentsStorage->openStorageElement(
+ sStorName, ElementModes::READWRITE ), UNO_SET_THROW );
+
+ switch ( m_eType )
+ {
+ case FORM:
+ case REPORT:
+ impl_saveSubDocument_throw( xObjectStor );
+ break;
+
+ case QUERY:
+ impl_saveQueryDesign_throw( xObjectStor );
+ break;
+
+ default:
+ // TODO
+ OSL_FAIL( "SubComponentRecoverys::saveToRecoveryStorage: unimplemented case!" );
+ break;
+ }
+
+ // commit the storage(s)
+ tools::stor::commitStorageIfWriteable( xObjectStor );
+ tools::stor::commitStorageIfWriteable( xComponentsStorage );
+
+ // remember the relationship from the component name to the storage name
+ MapStringToCompDesc& rMapCompDescs = io_mapCompDescs[ m_eType ];
+ OSL_ENSURE( rMapCompDescs.find( sStorName ) == rMapCompDescs.end(),
+ "SubComponentRecoverys::saveToRecoveryStorage: object name already used!" );
+ rMapCompDescs[ sStorName ] = m_aCompDesc;
+ }
+
+ void SubComponentRecovery::impl_identifyComponent_throw()
+ {
+ // ask the controller
+ Pair< sal_Int32, OUString > aComponentIdentity = m_xDocumentUI->identifySubComponent( m_xComponent );
+ m_eType = lcl_databaseObjectToSubComponentType( aComponentIdentity.First );
+ m_aCompDesc.sName = aComponentIdentity.Second;
+
+ // what the controller didn't give us is the information whether this is in edit mode or not ...
+ Reference< XModuleManager2 > xModuleManager( ModuleManager::create(m_rContext) );
+ const OUString sModuleIdentifier = xModuleManager->identify( m_xComponent );
+
+ switch ( m_eType )
+ {
+ case TABLE:
+ m_aCompDesc.bForEditing = sModuleIdentifier == "com.sun.star.sdb.TableDesign";
+ break;
+
+ case QUERY:
+ m_aCompDesc.bForEditing = sModuleIdentifier == "com.sun.star.sdb.QueryDesign";
+ break;
+
+ case REPORT:
+ if ( sModuleIdentifier == "com.sun.star.report.ReportDefinition" )
+ {
+ // it's an SRB report designer
+ m_aCompDesc.bForEditing = true;
+ break;
+ }
+ [[fallthrough]];
+
+ case FORM:
+ m_aCompDesc.bForEditing = !lcl_determineReadOnly( m_xComponent );
+ break;
+
+ default:
+ if ( sModuleIdentifier == "com.sun.star.sdb.RelationDesign" )
+ {
+ m_eType = RELATION_DESIGN;
+ m_aCompDesc.bForEditing = true;
+ }
+ else
+ {
+ OSL_FAIL( "SubComponentRecovery::impl_identifyComponent_throw: couldn't classify the given sub component!" );
+ }
+ break;
+ }
+
+ SAL_WARN_IF( m_eType == UNKNOWN, "dbaccess",
+ "SubComponentRecovery::impl_identifyComponent_throw: couldn't classify the component!" );
+ }
+
+ void SubComponentRecovery::impl_saveQueryDesign_throw( const Reference< XStorage >& i_rObjectStorage )
+ {
+ ENSURE_OR_THROW( m_eType == QUERY, "illegal sub component type" );
+ ENSURE_OR_THROW( i_rObjectStorage.is(), "illegal storage" );
+
+ // retrieve the current query design (which might differ from what we can retrieve as ActiveCommand property, since
+ // the latter is updated only upon successful save of the design)
+ Reference< XPropertySet > xDesignerProps( m_xComponent, UNO_QUERY_THROW );
+ Sequence< PropertyValue > aCurrentQueryDesign;
+ OSL_VERIFY( xDesignerProps->getPropertyValue( "CurrentQueryDesign" ) >>= aCurrentQueryDesign );
+
+ // write the query design
+ StorageXMLOutputStream aDesignOutput( m_rContext, i_rObjectStorage, sSettingsStreamName );
+ SettingsExportContext aSettingsExportContext( m_rContext, aDesignOutput );
+
+ static const OUStringLiteral sWhitespace( u" " );
+
+ aDesignOutput.startElement( "office:settings" );
+ aDesignOutput.ignorableWhitespace( sWhitespace );
+
+ XMLSettingsExportHelper aSettingsExporter( aSettingsExportContext );
+ aSettingsExporter.exportAllSettings( aCurrentQueryDesign, sCurrentQueryDesignName );
+
+ aDesignOutput.ignorableWhitespace( sWhitespace );
+ aDesignOutput.endElement();
+ aDesignOutput.close();
+ }
+
+ void SubComponentRecovery::impl_saveSubDocument_throw( const Reference< XStorage >& i_rObjectStorage )
+ {
+ ENSURE_OR_THROW( ( m_eType == FORM ) || ( m_eType == REPORT ), "illegal sub component type" );
+ ENSURE_OR_THROW( i_rObjectStorage.is(), "illegal storage" );
+
+ // store the document into the storage
+ Reference< XStorageBasedDocument > xStorageDocument( m_xComponent, UNO_QUERY_THROW );
+ xStorageDocument->storeToStorage( i_rObjectStorage, Sequence< PropertyValue >() );
+ }
+
+ Reference< XComponent > SubComponentRecovery::impl_recoverSubDocument_throw( const Reference< XStorage >& i_rRecoveryStorage,
+ const OUString& i_rComponentName, const bool i_bForEditing )
+ {
+ Reference< XComponent > xSubComponent;
+ Reference< XCommandProcessor > xDocDefinition;
+
+ ::comphelper::NamedValueCollection aLoadArgs;
+ aLoadArgs.put( "RecoveryStorage", i_rRecoveryStorage );
+
+ // load/create the sub component hidden. We'll show it when the main app window is shown.
+ aLoadArgs.put( "Hidden", true );
+
+ if ( !i_rComponentName.isEmpty() )
+ {
+ xDocDefinition = lcl_getSubComponentDef_nothrow( m_xDocumentUI, m_eType, i_rComponentName );
+ xSubComponent.set( m_xDocumentUI->loadComponentWithArguments(
+ m_eType,
+ i_rComponentName,
+ i_bForEditing,
+ aLoadArgs.getPropertyValues()
+ ),
+ UNO_SET_THROW
+ );
+ }
+ else
+ {
+ Reference< XComponent > xDocDefComponent;
+ xSubComponent.set( m_xDocumentUI->createComponentWithArguments(
+ m_eType,
+ aLoadArgs.getPropertyValues(),
+ xDocDefComponent
+ ),
+ UNO_SET_THROW
+ );
+
+ xDocDefinition.set( xDocDefComponent, UNO_QUERY );
+ OSL_ENSURE( xDocDefinition.is(), "DatabaseDocumentRecovery::recoverSubDocuments: loaded a form/report, but don't have a document definition?!" );
+ }
+
+ if ( xDocDefinition.is() )
+ {
+ Reference< XController > xController( m_xDocumentUI, UNO_QUERY_THROW );
+ rtl::Reference( new SubComponentLoader( xController, xDocDefinition ) );
+ }
+
+ return xSubComponent;
+ }
+
+ Reference< XComponent > SubComponentRecovery::impl_recoverQueryDesign_throw( const Reference< XStorage >& i_rRecoveryStorage,
+ const OUString& i_rComponentName, const bool i_bForEditing )
+ {
+ Reference< XComponent > xSubComponent;
+
+ // first read the settings query design settings from the storage
+ StorageXMLInputStream aDesignInput( m_rContext, i_rRecoveryStorage, sSettingsStreamName );
+
+ ::rtl::Reference< SettingsDocumentHandler > pDocHandler( new SettingsDocumentHandler );
+ aDesignInput.import( pDocHandler );
+
+ const ::comphelper::NamedValueCollection& rSettings( pDocHandler->getSettings() );
+ const Any& aCurrentQueryDesign = rSettings.get( sCurrentQueryDesignName );
+#if OSL_DEBUG_LEVEL > 0
+ Sequence< PropertyValue > aQueryDesignLayout;
+ OSL_VERIFY( aCurrentQueryDesign >>= aQueryDesignLayout );
+#endif
+
+ // then load the query designer
+ ::comphelper::NamedValueCollection aLoadArgs;
+ aLoadArgs.put( "CurrentQueryDesign", aCurrentQueryDesign );
+ aLoadArgs.put( "Hidden", true );
+
+ if ( !i_rComponentName.isEmpty() )
+ {
+ xSubComponent.set( m_xDocumentUI->loadComponentWithArguments(
+ m_eType,
+ i_rComponentName,
+ i_bForEditing,
+ aLoadArgs.getPropertyValues()
+ ),
+ UNO_SET_THROW
+ );
+ }
+ else
+ {
+ Reference< XComponent > xDummy;
+ xSubComponent.set( m_xDocumentUI->createComponentWithArguments(
+ m_eType,
+ aLoadArgs.getPropertyValues(),
+ xDummy
+ ),
+ UNO_SET_THROW
+ );
+ }
+
+ Reference< XController > xController( m_xDocumentUI, UNO_QUERY_THROW );
+ rtl::Reference( new SubComponentLoader( xController, xSubComponent ) );
+
+ return xSubComponent;
+ }
+
+ Reference< XComponent > SubComponentRecovery::recoverFromStorage( const Reference< XStorage >& i_rRecoveryStorage,
+ const OUString& i_rComponentName, const bool i_bForEditing )
+ {
+ Reference< XComponent > xSubComponent;
+ switch ( m_eType )
+ {
+ case FORM:
+ case REPORT:
+ xSubComponent = impl_recoverSubDocument_throw( i_rRecoveryStorage, i_rComponentName, i_bForEditing );
+ break;
+ case QUERY:
+ xSubComponent = impl_recoverQueryDesign_throw( i_rRecoveryStorage, i_rComponentName, i_bForEditing );
+ break;
+ default:
+ OSL_FAIL( "SubComponentRecovery::recoverFromStorage: unimplemented case!" );
+ break;
+ }
+ return xSubComponent;
+ }
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/subcomponentrecovery.hxx b/dbaccess/source/core/recovery/subcomponentrecovery.hxx
new file mode 100644
index 000000000..26b81c63f
--- /dev/null
+++ b/dbaccess/source/core/recovery/subcomponentrecovery.hxx
@@ -0,0 +1,114 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include "subcomponents.hxx"
+
+#include <com/sun/star/sdb/application/XDatabaseDocumentUI.hpp>
+#include <com/sun/star/embed/XStorage.hpp>
+#include <com/sun/star/uno/XComponentContext.hpp>
+
+namespace dbaccess
+{
+
+ // SubComponentRecovery
+ class SubComponentRecovery
+ {
+ public:
+ SubComponentRecovery(
+ const css::uno::Reference< css::uno::XComponentContext >& i_rContext,
+ const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& i_rController,
+ const css::uno::Reference< css::lang::XComponent >& i_rComponent )
+ :m_rContext( i_rContext )
+ ,m_xDocumentUI( i_rController, css::uno::UNO_SET_THROW )
+ ,m_xComponent( i_rComponent )
+ ,m_eType( UNKNOWN )
+ ,m_aCompDesc()
+ {
+ impl_identifyComponent_throw();
+ }
+
+ SubComponentRecovery(
+ const css::uno::Reference< css::uno::XComponentContext >& i_rContext,
+ const css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >& i_rController,
+ const SubComponentType i_eType )
+ :m_rContext( i_rContext )
+ ,m_xDocumentUI( i_rController, css::uno::UNO_SET_THROW )
+ ,m_xComponent()
+ ,m_eType( i_eType )
+ ,m_aCompDesc()
+ {
+ }
+
+ // only to be used after being constructed with a component
+ void saveToRecoveryStorage(
+ const css::uno::Reference< css::embed::XStorage >& i_rRecoveryStorage,
+ MapCompTypeToCompDescs& io_mapCompDescs
+ );
+
+ // only to be used after being constructed with a type
+ css::uno::Reference< css::lang::XComponent >
+ recoverFromStorage(
+ const css::uno::Reference< css::embed::XStorage >& i_rRecoveryStorage,
+ const OUString& i_rComponentName,
+ const bool i_bForEditing
+ );
+
+ static OUString getComponentsStorageName( const SubComponentType i_eType );
+
+ private:
+ void impl_saveSubDocument_throw(
+ const css::uno::Reference< css::embed::XStorage >& i_rObjectStorage
+ );
+
+ void impl_saveQueryDesign_throw(
+ const css::uno::Reference< css::embed::XStorage >& i_rObjectStorage
+ );
+
+ css::uno::Reference< css::lang::XComponent >
+ impl_recoverSubDocument_throw(
+ const css::uno::Reference< css::embed::XStorage >& i_rRecoveryStorage,
+ const OUString& i_rComponentName,
+ const bool i_bForEditing
+ );
+
+ css::uno::Reference< css::lang::XComponent >
+ impl_recoverQueryDesign_throw(
+ const css::uno::Reference< css::embed::XStorage >& i_rRecoveryStorage,
+ const OUString& i_rComponentName,
+ const bool i_bForEditing
+ );
+
+ void impl_identifyComponent_throw();
+
+ private:
+ const css::uno::Reference< css::uno::XComponentContext >&
+ m_rContext;
+ css::uno::Reference< css::sdb::application::XDatabaseDocumentUI >
+ m_xDocumentUI;
+ const css::uno::Reference< css::lang::XComponent >
+ m_xComponent;
+ SubComponentType m_eType;
+ SubComponentDescriptor m_aCompDesc;
+ };
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/recovery/subcomponents.hxx b/dbaccess/source/core/recovery/subcomponents.hxx
new file mode 100644
index 000000000..5e4173605
--- /dev/null
+++ b/dbaccess/source/core/recovery/subcomponents.hxx
@@ -0,0 +1,61 @@
+/* -*- 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 .
+ */
+
+#pragma once
+
+#include <com/sun/star/sdb/application/DatabaseObject.hpp>
+
+#include <rtl/ustring.hxx>
+
+#include <map>
+#include <unordered_map>
+
+namespace dbaccess
+{
+
+ enum SubComponentType
+ {
+ TABLE = css::sdb::application::DatabaseObject::TABLE,
+ QUERY = css::sdb::application::DatabaseObject::QUERY,
+ FORM = css::sdb::application::DatabaseObject::FORM,
+ REPORT = css::sdb::application::DatabaseObject::REPORT,
+
+ RELATION_DESIGN = 1000,
+
+ UNKNOWN = 10001
+ };
+
+ struct SubComponentDescriptor
+ {
+ OUString sName;
+ bool bForEditing;
+
+ SubComponentDescriptor()
+ :sName()
+ ,bForEditing( false )
+ {
+ }
+ };
+
+ typedef std::unordered_map< OUString, SubComponentDescriptor > MapStringToCompDesc;
+ typedef std::map< SubComponentType, MapStringToCompDesc > MapCompTypeToCompDescs;
+
+} // namespace dbaccess
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/dbaccess/source/core/resource/core_resource.cxx b/dbaccess/source/core/resource/core_resource.cxx
new file mode 100644
index 000000000..fdef07e1f
--- /dev/null
+++ b/dbaccess/source/core/resource/core_resource.cxx
@@ -0,0 +1,41 @@
+/* -*- 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 <core_resource.hxx>
+
+#include <unotools/resmgr.hxx>
+
+namespace dbaccess
+{
+ OUString ResourceManager::loadString(TranslateId pResId)
+ {
+ return Translate::get(pResId, Translate::Create("dba"));
+ }
+
+ OUString ResourceManager::loadString(TranslateId pResId, const char* _pPlaceholderAscii1, std::u16string_view _rReplace1,
+ const char* _pPlaceholderAscii2, std::u16string_view _rReplace2)
+ {
+ OUString sString(loadString(pResId));
+ sString = sString.replaceFirst( OUString::createFromAscii(_pPlaceholderAscii1), _rReplace1 );
+ sString = sString.replaceFirst( OUString::createFromAscii(_pPlaceholderAscii2), _rReplace2 );
+ return sString;
+ }
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */