1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <stringconstants.hxx>
22 #include <connectivity/dbexception.hxx>
23 #include <connectivity/PColumn.hxx>
24 #include <connectivity/warningscontainer.hxx>
25 #include "HelperCollections.hxx"
26 #include <core_resource.hxx>
27 #include <strings.hrc>
29 #include <cppuhelper/interfacecontainer.hxx>
30 #include <tools/diagnose_ex.h>
31 #include <osl/diagnose.h>
33 #include <com/sun/star/sdbc/XConnection.hpp>
34 #include <com/sun/star/sdb/XSingleSelectQueryComposer.hpp>
35 #include <com/sun/star/sdbc/XResultSetMetaDataSupplier.hpp>
36 #include <com/sun/star/sdb/SQLContext.hpp>
38 #include <comphelper/property.hxx>
39 #include <unotools/sharedunocomponent.hxx>
40 #include <definitioncolumn.hxx>
42 #include <com/sun/star/beans/PropertyAttribute.hpp>
43 #include <ContainerMediator.hxx>
45 using namespace dbaccess
;
46 using namespace ::com::sun::star::uno
;
47 using namespace ::com::sun::star::sdbc
;
48 using namespace ::com::sun::star::sdbcx
;
49 using namespace ::com::sun::star::sdb
;
50 using namespace ::com::sun::star::lang
;
51 using namespace ::com::sun::star::util
;
52 using namespace ::com::sun::star::beans
;
53 using namespace ::com::sun::star::container
;
54 using namespace ::comphelper
;
55 using namespace ::osl
;
56 using namespace ::cppu
;
57 using namespace ::utl
;
64 OQuery::OQuery( const Reference
< XPropertySet
>& _rxCommandDefinition
65 ,const Reference
< XConnection
>& _rxConn
66 ,const Reference
< XComponentContext
>& _xORB
)
67 :OContentHelper(_xORB
,nullptr,std::make_shared
<OContentHelper_Impl
>())
68 ,OQueryDescriptor_Base(m_aMutex
,*this)
69 ,ODataSettings(OContentHelper::rBHelper
,true)
70 ,m_xCommandDefinition(_rxCommandDefinition
)
71 ,m_xConnection(_rxConn
)
72 ,m_pWarnings( nullptr )
73 ,m_eDoingCurrently(AggregateAction::NONE
)
76 ODataSettings::registerPropertiesFor(this);
78 osl_atomic_increment(&m_refCount
);
79 OSL_ENSURE(m_xCommandDefinition
.is(), "OQuery::OQuery : invalid CommandDefinition object !");
80 if ( m_xCommandDefinition
.is() )
84 ::comphelper::copyProperties(_rxCommandDefinition
,this);
88 TOOLS_WARN_EXCEPTION("dbaccess", "OQueryDescriptor_Base::OQueryDescriptor_Base");
91 m_xCommandDefinition
->addPropertyChangeListener(OUString(), this);
92 // m_xCommandDefinition->addPropertyChangeListener(PROPERTY_NAME, this);
93 m_xCommandPropInfo
= m_xCommandDefinition
->getPropertySetInfo();
95 OSL_ENSURE(m_xConnection
.is(), "OQuery::OQuery : invalid connection !");
96 osl_atomic_decrement(&m_refCount
);
103 css::uno::Sequence
<sal_Int8
> OQuery::getImplementationId()
105 return css::uno::Sequence
<sal_Int8
>();
108 css::uno::Sequence
< css::uno::Type
> OQuery::getTypes()
110 return ::comphelper::concatSequences(
111 OQueryDescriptor_Base::getTypes( ),
112 ODataSettings::getTypes( ),
113 OContentHelper::getTypes( )
117 IMPLEMENT_FORWARD_XINTERFACE3( OQuery
,OContentHelper
,OQueryDescriptor_Base
,ODataSettings
)
119 void OQuery::rebuildColumns()
121 OSL_PRECOND( getColumnCount() == 0, "OQuery::rebuildColumns: column container should be empty!" );
122 // the base class' definition of rebuildColumns promised that clearColumns is called before rebuildColumns
126 m_pColumnMediator
= nullptr;
128 Reference
<XColumnsSupplier
> xColSup(m_xCommandDefinition
,UNO_QUERY
);
129 Reference
< XNameAccess
> xColumnDefinitions
;
132 xColumnDefinitions
= xColSup
->getColumns();
133 if ( xColumnDefinitions
.is() )
134 m_pColumnMediator
= new OContainerMediator( m_pColumns
.get(), xColumnDefinitions
);
137 // fill the columns with columns from the statement
138 Reference
< XMultiServiceFactory
> xFactory( m_xConnection
, UNO_QUERY_THROW
);
139 SharedUNOComponent
< XSingleSelectQueryComposer
, DisposableComponent
> xComposer(
140 Reference
< XSingleSelectQueryComposer
>( xFactory
->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
), UNO_QUERY_THROW
) );
142 Reference
< XNameAccess
> xColumns
;
143 Reference
< XIndexAccess
> xColumnsIndexed
;
146 xComposer
->setQuery( m_sCommand
);
147 Reference
< XColumnsSupplier
> xCols( xComposer
, UNO_QUERY_THROW
);
148 xColumns
.set( xCols
->getColumns(), UNO_SET_THROW
);
149 xColumnsIndexed
.set( xColumns
, UNO_QUERY_THROW
);
151 catch( const SQLException
& ) { }
153 SharedUNOComponent
< XPreparedStatement
, DisposableComponent
> xPreparedStatement
;
154 if ( !xColumns
.is() || ( xColumnsIndexed
->getCount() == 0 ) )
155 { // the QueryComposer could not parse it. Try a lean version.
156 xPreparedStatement
.set( m_xConnection
->prepareStatement( m_sCommand
), UNO_QUERY_THROW
);
157 Reference
< XResultSetMetaDataSupplier
> xResMetaDataSup( xPreparedStatement
, UNO_QUERY_THROW
);
158 Reference
< XResultSetMetaData
> xResultSetMeta( xResMetaDataSup
->getMetaData() );
159 if ( !xResultSetMeta
.is() )
161 OUString
sError( DBA_RES( RID_STR_STATEMENT_WITHOUT_RESULT_SET
) );
162 ::dbtools::throwSQLException( sError
, StandardSQLState::GENERAL_ERROR
, *this );
165 Reference
< XDatabaseMetaData
> xDBMeta( m_xConnection
->getMetaData(), UNO_SET_THROW
);
166 ::rtl::Reference
< OSQLColumns
> aParseColumns(
167 ::connectivity::parse::OParseColumn::createColumnsForResultSet( xResultSetMeta
, xDBMeta
,xColumnDefinitions
) );
168 xColumns
= OPrivateColumns::createWithIntrinsicNames(
169 aParseColumns
, xDBMeta
->supportsMixedCaseQuotedIdentifiers(), *this, m_aMutex
).release();
170 if ( !xColumns
.is() )
171 throw RuntimeException();
174 const Sequence
<OUString
> aColNames
= xColumns
->getElementNames();
175 for ( const OUString
& rName
: aColNames
)
177 Reference
<XPropertySet
> xSource(xColumns
->getByName( rName
),UNO_QUERY
);
178 OUString sLabel
= rName
;
179 if ( xColumnDefinitions
.is() && xColumnDefinitions
->hasByName(rName
) )
181 Reference
<XPropertySet
> xCommandColumn(xColumnDefinitions
->getByName( rName
),UNO_QUERY
);
182 xCommandColumn
->getPropertyValue(PROPERTY_LABEL
) >>= sLabel
;
184 rtl::Reference
<OQueryColumn
> pColumn
= new OQueryColumn( xSource
, m_xConnection
, sLabel
);
185 pColumn
->setParent( *this );
187 implAppendColumn( rName
, pColumn
.get() );
188 Reference
< XPropertySet
> xDest( *pColumn
, UNO_QUERY_THROW
);
189 if ( m_pColumnMediator
.is() )
190 m_pColumnMediator
->notifyElementCreated( rName
, xDest
);
193 catch( const SQLContext
& e
)
196 m_pWarnings
->appendWarning( e
);
198 catch( const SQLWarning
& e
)
201 m_pWarnings
->appendWarning( e
);
203 catch( const SQLException
& e
)
206 m_pWarnings
->appendWarning( e
);
208 catch( const Exception
& )
210 DBG_UNHANDLED_EXCEPTION("dbaccess");
215 OUString SAL_CALL
OQuery::getImplementationName()
217 return "com.sun.star.sdb.dbaccess.OQuery";
219 sal_Bool SAL_CALL
OQuery::supportsService(const OUString
& _rServiceName
)
221 const css::uno::Sequence
< OUString
> aSupported(getSupportedServiceNames());
222 for (const OUString
& s
: aSupported
)
223 if (s
== _rServiceName
)
228 css::uno::Sequence
< OUString
> SAL_CALL
OQuery::getSupportedServiceNames( )
230 return { SERVICE_SDB_DATASETTINGS
, SERVICE_SDB_QUERY
, "com.sun.star.sdb.QueryDefinition" };
233 // css::beans::XPropertyChangeListener
234 void SAL_CALL
OQuery::propertyChange( const PropertyChangeEvent
& _rSource
)
236 sal_Int32 nOwnHandle
= -1;
238 MutexGuard
aGuard(m_aMutex
);
240 OSL_ENSURE(_rSource
.Source
.get() == Reference
< XInterface
>(m_xCommandDefinition
, UNO_QUERY
).get(),
241 "OQuery::propertyChange : where did this call come from ?");
243 if (m_eDoingCurrently
== AggregateAction::SettingProperties
)
244 // we're setting the property ourself, so we will do the necessary notifications later
247 // forward this to our own member holding a copy of the property value
248 if (getArrayHelper()->hasPropertyByName(_rSource
.PropertyName
))
250 Property aOwnProp
= getArrayHelper()->getPropertyByName(_rSource
.PropertyName
);
251 nOwnHandle
= aOwnProp
.Handle
;
252 ODataSettings::setFastPropertyValue_NoBroadcast(nOwnHandle
, _rSource
.NewValue
);
253 // don't use our own setFastPropertyValue_NoBroadcast, this would forward it to the CommandSettings,
255 // and don't use the "real" setPropertyValue, this is too expensive and not sure to succeed
259 OSL_FAIL("OQuery::propertyChange : my CommandDefinition has more properties than I do !");
263 fire(&nOwnHandle
, &_rSource
.NewValue
, &_rSource
.OldValue
, 1, false);
266 void SAL_CALL
OQuery::disposing( const EventObject
& _rSource
)
268 MutexGuard
aGuard(m_aMutex
);
270 OSL_ENSURE(_rSource
.Source
.get() == Reference
< XInterface
>(m_xCommandDefinition
, UNO_QUERY
).get(),
271 "OQuery::disposing : where did this call come from ?");
273 m_xCommandDefinition
->removePropertyChangeListener(OUString(), this);
274 m_xCommandDefinition
= nullptr;
277 // XDataDescriptorFactory
278 Reference
< XPropertySet
> SAL_CALL
OQuery::createDataDescriptor( )
280 return new OQueryDescriptor(*this);
284 void SAL_CALL
OQuery::disposing()
286 MutexGuard
aGuard(m_aMutex
);
287 if (m_xCommandDefinition
.is())
289 m_xCommandDefinition
->removePropertyChangeListener(OUString(), this);
290 m_xCommandDefinition
= nullptr;
294 m_pWarnings
= nullptr;
297 void OQuery::setFastPropertyValue_NoBroadcast( sal_Int32 _nHandle
, const Any
& _rValue
)
299 ODataSettings::setFastPropertyValue_NoBroadcast(_nHandle
, _rValue
);
300 OUString sAggPropName
;
302 if (getInfoHelper().fillPropertyMembersByHandle(&sAggPropName
,&nAttr
,_nHandle
) &&
303 m_xCommandPropInfo
.is() &&
304 m_xCommandPropInfo
->hasPropertyByName(sAggPropName
))
305 { // the base class holds the property values itself, but we have to forward this to our CommandDefinition
307 m_eDoingCurrently
= AggregateAction::SettingProperties
;
308 OAutoActionReset
aAutoReset(*this);
309 m_xCommandDefinition
->setPropertyValue(sAggPropName
, _rValue
);
311 if ( PROPERTY_ID_COMMAND
== _nHandle
)
312 // the columns are out of date if we are based on a new statement...
313 setColumnsOutOfDate();
317 Reference
< XPropertySetInfo
> SAL_CALL
OQuery::getPropertySetInfo( )
319 return createPropertySetInfo( getInfoHelper() ) ;
322 ::cppu::IPropertyArrayHelper
& OQuery::getInfoHelper()
324 return *getArrayHelper();
327 ::cppu::IPropertyArrayHelper
* OQuery::createArrayHelper( ) const
329 Sequence
< Property
> aProps
;
331 describeProperties(aProps
);
332 return new ::cppu::OPropertyArrayHelper(aProps
);
335 rtl::Reference
<OColumn
> OQuery::createColumn(const OUString
& /*_rName*/) const
340 void SAL_CALL
OQuery::rename( const OUString
& newName
)
342 MutexGuard
aGuard(m_aMutex
);
343 Reference
<XRename
> xRename(m_xCommandDefinition
,UNO_QUERY
);
344 OSL_ENSURE(xRename
.is(),"No XRename interface!");
346 xRename
->rename(newName
);
349 void OQuery::registerProperties()
351 // the properties which OCommandBase supplies (it has no own registration, as it's not derived from
352 // an OPropertyStateContainer)
353 registerProperty(PROPERTY_NAME
, PROPERTY_ID_NAME
, PropertyAttribute::BOUND
|PropertyAttribute::CONSTRAINED
,
354 &m_sElementName
, cppu::UnoType
<decltype(m_sElementName
)>::get());
356 registerProperty(PROPERTY_COMMAND
, PROPERTY_ID_COMMAND
, PropertyAttribute::BOUND
,
357 &m_sCommand
, cppu::UnoType
<decltype(m_sCommand
)>::get());
359 registerProperty(PROPERTY_ESCAPE_PROCESSING
, PROPERTY_ID_ESCAPE_PROCESSING
, PropertyAttribute::BOUND
,
360 &m_bEscapeProcessing
, cppu::UnoType
<bool>::get());
362 registerProperty(PROPERTY_UPDATE_TABLENAME
, PROPERTY_ID_UPDATE_TABLENAME
, PropertyAttribute::BOUND
,
363 &m_sUpdateTableName
, cppu::UnoType
<decltype(m_sUpdateTableName
)>::get());
365 registerProperty(PROPERTY_UPDATE_SCHEMANAME
, PROPERTY_ID_UPDATE_SCHEMANAME
, PropertyAttribute::BOUND
,
366 &m_sUpdateSchemaName
, cppu::UnoType
<decltype(m_sUpdateSchemaName
)>::get());
368 registerProperty(PROPERTY_UPDATE_CATALOGNAME
, PROPERTY_ID_UPDATE_CATALOGNAME
, PropertyAttribute::BOUND
,
369 &m_sUpdateCatalogName
, cppu::UnoType
<decltype(m_sUpdateCatalogName
)>::get());
371 registerProperty(PROPERTY_LAYOUTINFORMATION
, PROPERTY_ID_LAYOUTINFORMATION
, PropertyAttribute::BOUND
,
372 &m_aLayoutInformation
, cppu::UnoType
<decltype(m_aLayoutInformation
)>::get());
375 OUString
OQuery::determineContentType() const
377 return "application/vnd.org.openoffice.DatabaseQuery";
380 } // namespace dbaccess
382 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */