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 .
20 #include <connectivity/parameters.hxx>
22 #include <com/sun/star/form/DatabaseParameterEvent.hpp>
23 #include <com/sun/star/form/XDatabaseParameterListener.hpp>
24 #include <com/sun/star/sdbc/XParameters.hpp>
25 #include <com/sun/star/container/XChild.hpp>
26 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
27 #include <com/sun/star/sdb/XParametersSupplier.hpp>
28 #include <com/sun/star/sdb/ParametersRequest.hpp>
29 #include <com/sun/star/sdbc/SQLException.hpp>
30 #include <com/sun/star/task/XInteractionHandler.hpp>
32 #include <connectivity/dbtools.hxx>
33 #include <connectivity/filtermanager.hxx>
34 #include <TConnection.hxx>
36 #include <comphelper/diagnose_ex.hxx>
38 #include <ParameterCont.hxx>
39 #include <o3tl/safeint.hxx>
40 #include <rtl/ustrbuf.hxx>
41 #include <sal/log.hxx>
45 using namespace ::com::sun::star::uno
;
46 using namespace ::com::sun::star::sdb
;
47 using namespace ::com::sun::star::sdbc
;
48 using namespace ::com::sun::star::sdbcx
;
49 using namespace ::com::sun::star::beans
;
50 using namespace ::com::sun::star::task
;
51 using namespace ::com::sun::star::form
;
52 using namespace ::com::sun::star::container
;
54 using namespace ::comphelper
;
55 using namespace ::connectivity
;
57 ParameterManager::ParameterManager( ::osl::Mutex
& _rMutex
, const Reference
< XComponentContext
>& _rxContext
)
59 ,m_aParameterListeners( _rMutex
)
60 ,m_xContext ( _rxContext
)
62 ,m_bUpToDate ( false )
64 OSL_ENSURE( m_xContext
.is(), "ParameterManager::ParameterManager: no service factory!" );
68 void ParameterManager::initialize( const Reference
< XPropertySet
>& _rxComponent
, const Reference
< XAggregation
>& _rxComponentAggregate
)
70 OSL_ENSURE( !m_xComponent
.get().is(), "ParameterManager::initialize: already initialized!" );
72 m_xComponent
= _rxComponent
;
73 m_xAggregatedRowSet
= _rxComponentAggregate
;
74 if ( m_xAggregatedRowSet
.is() )
75 m_xAggregatedRowSet
->queryAggregation( cppu::UnoType
<decltype(m_xInnerParamUpdate
)>::get() ) >>= m_xInnerParamUpdate
;
76 OSL_ENSURE( m_xComponent
.get().is() && m_xInnerParamUpdate
.is(), "ParameterManager::initialize: invalid arguments!" );
77 if ( !m_xComponent
.get().is() || !m_xInnerParamUpdate
.is() )
82 void ParameterManager::dispose( )
84 clearAllParameterInformation();
87 m_xParentComposer
.clear();
88 //m_xComponent.clear();
89 m_xInnerParamUpdate
.clear();
90 m_xAggregatedRowSet
.clear();
94 void ParameterManager::clearAllParameterInformation()
96 m_xInnerParamColumns
.clear();
97 if ( m_pOuterParameters
.is() )
98 m_pOuterParameters
->dispose();
99 m_pOuterParameters
= nullptr;
101 ParameterInformation().swap(m_aParameterInformation
);
102 m_aMasterFields
.clear();
103 m_aDetailFields
.clear();
104 m_sIdentifierQuoteString
.clear();
105 m_sSpecialCharacters
.clear();
106 m_xConnectionMetadata
.clear();
107 std::vector
< bool >().swap(m_aParametersVisited
);
112 void ParameterManager::setAllParametersNull()
114 OSL_PRECOND( isAlive(), "ParameterManager::setAllParametersNull: not initialized, or already disposed!" );
118 for ( sal_Int32 i
= 1; i
<= m_nInnerCount
; ++i
)
119 m_xInnerParamUpdate
->setNull( i
, DataType::VARCHAR
);
123 bool ParameterManager::initializeComposerByComponent( const Reference
< XPropertySet
>& _rxComponent
)
125 OSL_PRECOND( _rxComponent
.is(), "ParameterManager::initializeComposerByComponent: invalid !" );
128 m_xInnerParamColumns
.clear();
131 // create and fill a composer
134 // get a query composer for the 's settings
135 m_xComposer
.reset( getCurrentSettingsComposer( _rxComponent
, m_xContext
, nullptr ), SharedQueryComposer::TakeOwnership
);
137 // see if the composer found parameters
138 Reference
< XParametersSupplier
> xParamSupp( m_xComposer
, UNO_QUERY
);
139 if ( xParamSupp
.is() )
140 m_xInnerParamColumns
= xParamSupp
->getParameters();
142 if ( m_xInnerParamColumns
.is() )
143 m_nInnerCount
= m_xInnerParamColumns
->getCount();
145 catch( const SQLException
& )
149 return m_xInnerParamColumns
.is();
153 void ParameterManager::collectInnerParameters( bool _bSecondRun
)
155 OSL_PRECOND( m_xInnerParamColumns
.is(), "ParameterManager::collectInnerParameters: missing some internal data!" );
156 if ( !m_xInnerParamColumns
.is() )
159 // strip previous index information
162 for (auto & paramInfo
: m_aParameterInformation
)
164 paramInfo
.second
.aInnerIndexes
.clear();
168 // we need to map the parameter names (which is all we get from the 's
169 // MasterFields property) to indices, which are needed by the XParameters
170 // interface of the row set)
171 Reference
<XPropertySet
> xParam
;
172 for ( sal_Int32 i
= 0; i
< m_nInnerCount
; ++i
)
177 m_xInnerParamColumns
->getByIndex( i
) >>= xParam
;
180 xParam
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
) ) >>= sName
;
182 // only append additional parameters when they are not already in the list
183 ParameterInformation::iterator aExistentPos
= m_aParameterInformation
.find( sName
);
184 OSL_ENSURE( !_bSecondRun
|| ( aExistentPos
!= m_aParameterInformation
.end() ),
185 "ParameterManager::collectInnerParameters: the parameter information should already exist in the second run!" );
187 if ( aExistentPos
== m_aParameterInformation
.end() )
189 aExistentPos
= m_aParameterInformation
.emplace(
190 sName
, xParam
).first
;
193 aExistentPos
->second
.xComposerColumn
= xParam
;
195 aExistentPos
->second
.aInnerIndexes
.push_back( i
);
197 catch( const Exception
& )
199 TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::collectInnerParameters" );
205 OUString
ParameterManager::createFilterConditionFromColumnLink(
206 const OUString
&_rMasterColumn
, const Reference
< XPropertySet
> &xDetailField
, OUString
&o_rNewParamName
)
210 // <detail_column> = :<new_param_name>
213 xDetailField
->getPropertyValue(u
"TableName"_ustr
) >>= tblName
;
214 if (!tblName
.isEmpty())
215 sFilter
= ::dbtools::quoteTableName( m_xConnectionMetadata
, tblName
, ::dbtools::EComposeRule::InDataManipulation
) + ".";
219 xDetailField
->getPropertyValue(u
"RealName"_ustr
) >>= colName
;
220 bool isFunction(false);
221 xDetailField
->getPropertyValue(u
"Function"_ustr
) >>= isFunction
;
225 sFilter
+= quoteName( m_sIdentifierQuoteString
, colName
);
228 // generate a parameter name which is not already used
229 o_rNewParamName
= "link_from_";
230 o_rNewParamName
+= convertName2SQLName( _rMasterColumn
, m_sSpecialCharacters
);
231 while ( m_aParameterInformation
.find( o_rNewParamName
) != m_aParameterInformation
.end() )
233 o_rNewParamName
+= "_";
236 return sFilter
+ " =:" + o_rNewParamName
;
240 void ParameterManager::classifyLinks( const Reference
< XNameAccess
>& _rxParentColumns
,
241 const Reference
< XNameAccess
>& _rxColumns
,
242 std::vector
< OUString
>& _out_rAdditionalFilterComponents
,
243 std::vector
< OUString
>& _out_rAdditionalHavingComponents
)
245 OSL_PRECOND( m_aMasterFields
.size() == m_aDetailFields
.size(),
246 "ParameterManager::classifyLinks: master and detail fields should have the same length!" );
247 OSL_ENSURE( _rxColumns
.is(), "ParameterManager::classifyLinks: invalid columns!" );
249 if ( !_rxColumns
.is() )
252 // we may need to strip any links which are invalid, so here go the containers
253 // for temporarily holding the new pairs
254 std::vector
< OUString
> aStrippedMasterFields
;
255 std::vector
< OUString
> aStrippedDetailFields
;
257 bool bNeedExchangeLinks
= false;
259 // classify the links
260 auto pMasterFields
= m_aMasterFields
.begin();
261 auto pDetailFields
= m_aDetailFields
.begin();
262 auto pDetailFieldsEnd
= m_aDetailFields
.end();
263 for ( ; pDetailFields
!= pDetailFieldsEnd
; ++pDetailFields
, ++pMasterFields
)
265 if ( pMasterFields
->isEmpty() || pDetailFields
->isEmpty() )
268 // if not even the master part of the relationship exists in the parent, the
269 // link is invalid as a whole #i63674#
270 if ( !_rxParentColumns
->hasByName( *pMasterFields
) )
272 bNeedExchangeLinks
= true;
276 bool bValidLink
= true;
278 // is there an inner parameter with this name? That is, a parameter which is already part of
279 // the very original statement (not the one we create ourselves, with the additional parameters)
280 ParameterInformation::iterator aPos
= m_aParameterInformation
.find( *pDetailFields
);
281 if ( aPos
!= m_aParameterInformation
.end() )
282 { // there is an inner parameter with this name
283 aPos
->second
.eType
= ParameterClassification::LinkedByParamName
;
284 aStrippedDetailFields
.push_back( *pDetailFields
);
288 // does the detail name denote a column?
289 if ( _rxColumns
->hasByName( *pDetailFields
) )
291 Reference
< XPropertySet
> xDetailField(_rxColumns
->getByName( *pDetailFields
), UNO_QUERY
);
292 assert(xDetailField
.is());
294 OUString sNewParamName
;
295 const OUString sFilterCondition
= createFilterConditionFromColumnLink( *pMasterFields
, xDetailField
, sNewParamName
);
296 OSL_PRECOND( !sNewParamName
.isEmpty(), "ParameterManager::classifyLinks: createFilterConditionFromColumnLink returned nonsense!" );
298 // remember meta information about this new parameter
299 std::pair
< ParameterInformation::iterator
, bool > aInsertionPos
=
300 m_aParameterInformation
.emplace(
301 sNewParamName
, ParameterMetaData( nullptr )
303 OSL_ENSURE( aInsertionPos
.second
, "ParameterManager::classifyLinks: there already was a parameter with this name!" );
304 aInsertionPos
.first
->second
.eType
= ParameterClassification::LinkedByColumnName
;
306 // remember the filter component
307 if (isAggregateColumn(xDetailField
))
308 _out_rAdditionalHavingComponents
.push_back( sFilterCondition
);
310 _out_rAdditionalFilterComponents
.push_back( sFilterCondition
);
312 // remember the new "detail field" for this link
313 aStrippedDetailFields
.push_back( sNewParamName
);
314 bNeedExchangeLinks
= true;
318 // the detail field neither denotes a column name, nor a parameter name
320 bNeedExchangeLinks
= true;
325 aStrippedMasterFields
.push_back( *pMasterFields
);
327 SAL_WARN_IF( aStrippedMasterFields
.size() != aStrippedDetailFields
.size(),
328 "connectivity.commontools",
329 "ParameterManager::classifyLinks: inconsistency in new link pairs!" );
331 if ( bNeedExchangeLinks
)
333 m_aMasterFields
.swap(aStrippedMasterFields
);
334 m_aDetailFields
.swap(aStrippedDetailFields
);
339 void ParameterManager::analyzeFieldLinks( FilterManager
& _rFilterManager
, bool& /* [out] */ _rColumnsInLinkDetails
)
341 OSL_PRECOND( isAlive(), "ParameterManager::analyzeFieldLinks: not initialized, or already disposed!" );
345 _rColumnsInLinkDetails
= false;
348 // the links as determined by the properties
349 Reference
< XPropertySet
> xProp
= m_xComponent
;
350 OSL_ENSURE(xProp
.is(),"Someone already released my component!");
353 Sequence
<OUString
> aTmp
;
354 if (xProp
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MASTERFIELDS
) ) >>= aTmp
)
355 comphelper::sequenceToContainer(m_aMasterFields
, aTmp
);
356 if (xProp
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DETAILFIELDS
) ) >>= aTmp
)
357 comphelper::sequenceToContainer(m_aDetailFields
, aTmp
);
361 // normalize to equal length
362 sal_Int32 nMasterLength
= m_aMasterFields
.size();
363 sal_Int32 nDetailLength
= m_aDetailFields
.size();
365 if ( nMasterLength
> nDetailLength
)
366 m_aMasterFields
.resize( nDetailLength
);
367 else if ( nDetailLength
> nMasterLength
)
368 m_aDetailFields
.resize( nMasterLength
);
371 Reference
< XNameAccess
> xColumns
;
372 if ( !getColumns( xColumns
, true ) )
373 // already asserted in getColumns
376 Reference
< XNameAccess
> xParentColumns
;
377 if ( !getParentColumns( xParentColumns
, true ) )
380 // classify the links - depending on what the detail fields in each link pair denotes
381 std::vector
< OUString
> aAdditionalFilterComponents
;
382 std::vector
< OUString
> aAdditionalHavingComponents
;
383 classifyLinks( xParentColumns
, xColumns
, aAdditionalFilterComponents
, aAdditionalHavingComponents
);
385 // did we find links where the detail field refers to a detail column (instead of a parameter name)?
386 if ( !aAdditionalFilterComponents
.empty() )
388 // build a conjunction of all the filter components
389 OUStringBuffer sAdditionalFilter
;
390 for (auto const& elem
: aAdditionalFilterComponents
)
392 if ( !sAdditionalFilter
.isEmpty() )
393 sAdditionalFilter
.append(" AND ");
395 sAdditionalFilter
.append("( " + elem
+ " )");
398 // now set this filter at the filter manager
399 _rFilterManager
.setFilterComponent( FilterManager::FilterComponent::LinkFilter
, sAdditionalFilter
.makeStringAndClear() );
401 _rColumnsInLinkDetails
= true;
404 if ( !aAdditionalHavingComponents
.empty() )
406 // build a conjunction of all the filter components
407 OUStringBuffer sAdditionalHaving
;
408 for (auto const& elem
: aAdditionalHavingComponents
)
410 if ( !sAdditionalHaving
.isEmpty() )
411 sAdditionalHaving
.append(" AND ");
413 sAdditionalHaving
.append("( " + elem
+ " )");
416 // now set this having clause at the filter manager
417 _rFilterManager
.setFilterComponent( FilterManager::FilterComponent::LinkHaving
, sAdditionalHaving
.makeStringAndClear() );
419 _rColumnsInLinkDetails
= true;
422 catch( const Exception
& )
424 TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::analyzeFieldLinks" );
429 void ParameterManager::createOuterParameters()
431 OSL_PRECOND( !m_pOuterParameters
.is(), "ParameterManager::createOuterParameters: outer parameters not initialized!" );
432 OSL_PRECOND( m_xInnerParamUpdate
.is(), "ParameterManager::createOuterParameters: no write access to the inner parameters!" );
433 if ( !m_xInnerParamUpdate
.is() )
436 m_pOuterParameters
= new param::ParameterWrapperContainer
;
438 #if OSL_DEBUG_LEVEL > 0
439 sal_Int32 nSmallestIndexLinkedByColumnName
= -1;
440 sal_Int32 nLargestIndexNotLinkedByColumnName
= -1;
442 for (auto & aParam
: m_aParameterInformation
)
444 #if OSL_DEBUG_LEVEL > 0
445 if ( aParam
.second
.aInnerIndexes
.size() )
447 if ( aParam
.second
.eType
== ParameterClassification::LinkedByColumnName
)
449 if ( nSmallestIndexLinkedByColumnName
== -1 )
450 nSmallestIndexLinkedByColumnName
= aParam
.second
.aInnerIndexes
[ 0 ];
454 nLargestIndexNotLinkedByColumnName
= aParam
.second
.aInnerIndexes
[ aParam
.second
.aInnerIndexes
.size() - 1 ];
458 if ( aParam
.second
.eType
!= ParameterClassification::FilledExternally
)
461 // check which of the parameters have already been visited (e.g. filled via XParameters)
462 size_t nAlreadyVisited
= 0;
463 for (auto & aIndex
: aParam
.second
.aInnerIndexes
)
465 if ( ( m_aParametersVisited
.size() > o3tl::make_unsigned(aIndex
) ) && m_aParametersVisited
[ aIndex
] )
466 { // exclude this index
471 if ( nAlreadyVisited
== aParam
.second
.aInnerIndexes
.size() )
474 // need a wrapper for this... the "inner parameters" as supplied by a result set don't have a "Value"
475 // property, but the parameter listeners expect such a property. So we need an object "aggregating"
476 // xParam and supplying an additional property ("Value")
477 // (it's no real aggregation of course...)
478 m_pOuterParameters
->push_back( new param::ParameterWrapper( aParam
.second
.xComposerColumn
, m_xInnerParamUpdate
, std::vector(aParam
.second
.aInnerIndexes
) ) );
481 #if OSL_DEBUG_LEVEL > 0
482 OSL_ENSURE( ( nSmallestIndexLinkedByColumnName
== -1 ) || ( nLargestIndexNotLinkedByColumnName
== -1 ) ||
483 ( nSmallestIndexLinkedByColumnName
> nLargestIndexNotLinkedByColumnName
),
484 "ParameterManager::createOuterParameters: inconsistency!" );
486 // for the master-detail links, where the detail field denoted a column name, we created an additional ("artificial")
487 // filter, and *appended* it to all other (potentially) existing filters of the row set. This means that the indexes
488 // for the parameters resulting from the artificial filter should be larger than any other parameter index, and this
489 // is what the assertion checks.
490 // If the assertion fails, then we would need another handling for the "parameters visited" flags, since they're based
491 // on parameter indexes *without* the artificial filter (because this filter is not visible from the outside).
496 void ParameterManager::updateParameterInfo( FilterManager
& _rFilterManager
)
498 OSL_PRECOND( isAlive(), "ParameterManager::updateParameterInfo: not initialized, or already disposed!" );
502 clearAllParameterInformation();
503 cacheConnectionInfo();
505 // check whether the is based on a statement/query which requires parameters
506 Reference
< XPropertySet
> xProp
= m_xComponent
;
507 OSL_ENSURE(xProp
.is(),"Some already released my component!");
510 if ( !initializeComposerByComponent( xProp
) )
511 { // okay, nothing to do
514 } // if ( !initializeComposerByComponent( m_xComponent ) )
516 SAL_WARN_IF( !m_xInnerParamColumns
.is(),
517 "connectivity.commontools",
518 "ParameterManager::updateParameterInfo: initializeComposerByComponent did nonsense (1)!" );
520 // collect all parameters which are defined by the "inner parameters"
521 collectInnerParameters( false );
523 // analyze the master-detail relationships
524 bool bColumnsInLinkDetails
= false;
525 analyzeFieldLinks( _rFilterManager
, bColumnsInLinkDetails
);
527 if ( bColumnsInLinkDetails
)
529 // okay, in this case, analyzeFieldLinks modified the "real" filter at the RowSet, to contain
530 // an additional restriction (which we created ourself)
531 // So we need to update all information about our inner parameter columns
532 Reference
< XPropertySet
> xDirectRowSetProps
;
533 m_xAggregatedRowSet
->queryAggregation( cppu::UnoType
<decltype(xDirectRowSetProps
)>::get() ) >>= xDirectRowSetProps
;
534 OSL_VERIFY( initializeComposerByComponent( xDirectRowSetProps
) );
535 collectInnerParameters( true );
538 if ( !m_nInnerCount
)
539 { // no parameters at all
544 // for what now remains as outer parameters, create the wrappers for the single
546 createOuterParameters();
552 void ParameterManager::fillLinkedParameters( const Reference
< XNameAccess
>& _rxParentColumns
)
554 OSL_PRECOND( isAlive(), "ParameterManager::fillLinkedParameters: not initialized, or already disposed!" );
557 OSL_PRECOND( m_xInnerParamColumns
.is(), "ParameterManager::fillLinkedParameters: no inner parameters found!" );
558 OSL_ENSURE ( _rxParentColumns
.is(), "ParameterManager::fillLinkedParameters: invalid parent columns!" );
562 // the master and detail field( name)s of the
563 auto pMasterFields
= m_aMasterFields
.begin();
564 auto pDetailFields
= m_aDetailFields
.begin();
566 sal_Int32 nMasterLen
= m_aMasterFields
.size();
568 // loop through all master fields. For each of them, get the respective column from the
569 // parent , and forward its current value as parameter value to the (inner) row set
570 for ( sal_Int32 i
= 0; i
< nMasterLen
; ++i
, ++pMasterFields
, ++pDetailFields
)
572 // does the name denote a valid column in the parent?
573 if ( !_rxParentColumns
->hasByName( *pMasterFields
) )
575 SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: invalid master names should have been stripped long before!" );
579 // do we, for this name, know where to place the values?
580 ParameterInformation::const_iterator aParamInfo
= m_aParameterInformation
.find( *pDetailFields
);
581 if ( ( aParamInfo
== m_aParameterInformation
.end() )
582 || ( aParamInfo
->second
.aInnerIndexes
.empty() )
585 SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: nothing known about this detail field!" );
589 // the concrete master field
590 Reference
< XPropertySet
> xMasterField(_rxParentColumns
->getByName( *pMasterFields
),UNO_QUERY
);
592 // the positions where we have to fill in values for the current parameter name
593 for (auto const& aPosition
: aParamInfo
->second
.aInnerIndexes
)
595 // the concrete detail field
596 Reference
< XPropertySet
> xDetailField(m_xInnerParamColumns
->getByIndex(aPosition
),UNO_QUERY
);
597 OSL_ENSURE( xDetailField
.is(), "ParameterManager::fillLinkedParameters: invalid detail field!" );
598 if ( !xDetailField
.is() )
601 // type and scale of the parameter field
602 sal_Int32 nParamType
= DataType::VARCHAR
;
603 OSL_VERIFY( xDetailField
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE
) ) >>= nParamType
);
605 sal_Int32 nScale
= 0;
606 if ( xDetailField
->getPropertySetInfo()->hasPropertyByName( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE
) ) )
607 OSL_VERIFY( xDetailField
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE
) ) >>= nScale
);
609 // transfer the param value
612 m_xInnerParamUpdate
->setObjectWithInfo(
613 aPosition
+ 1, // parameters are based at 1
614 xMasterField
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE
) ),
619 catch( const Exception
& )
621 DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
622 SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: master-detail parameter number " <<
623 sal_Int32( aPosition
+ 1 ) << " could not be filled!" );
628 catch( const Exception
& )
630 DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
635 bool ParameterManager::completeParameters( const Reference
< XInteractionHandler
>& _rxCompletionHandler
, const Reference
< XConnection
>& _rxConnection
)
637 OSL_PRECOND( isAlive(), "ParameterManager::completeParameters: not initialized, or already disposed!" );
638 OSL_ENSURE ( _rxCompletionHandler
.is(), "ParameterManager::completeParameters: invalid interaction handler!" );
640 // two continuations (Ok and Cancel)
641 rtl::Reference
<OInteractionAbort
> pAbort
= new OInteractionAbort
;
642 rtl::Reference
<OParameterContinuation
> pParams
= new OParameterContinuation
;
645 ParametersRequest aRequest
;
646 aRequest
.Parameters
= m_pOuterParameters
.get();
647 aRequest
.Connection
= _rxConnection
;
648 rtl::Reference
<OInteractionRequest
> pRequest
= new OInteractionRequest( Any( aRequest
) );
651 pRequest
->addContinuation( pAbort
);
652 pRequest
->addContinuation( pParams
);
654 // execute the request
657 _rxCompletionHandler
->handle( pRequest
);
659 catch( const Exception
& )
661 TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::completeParameters: caught an exception while calling the handler" );
664 if ( !pParams
->wasSelected() )
665 // canceled by the user (i.e. (s)he canceled the dialog)
670 // transfer the values from the continuation object to the parameter columns
671 const Sequence
< PropertyValue
>& aFinalValues
= pParams
->getValues();
672 for (sal_Int32 i
= 0; i
< aFinalValues
.getLength(); ++i
)
674 Reference
< XPropertySet
> xParamColumn(aRequest
.Parameters
->getByIndex( i
),UNO_QUERY
);
675 if ( xParamColumn
.is() )
679 xParamColumn
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
) ) >>= sName
;
680 OSL_ENSURE( sName
== aFinalValues
[i
].Name
, "ParameterManager::completeParameters: inconsistent parameter names!" );
682 xParamColumn
->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE
), aFinalValues
[i
].Value
);
683 // the property sets are wrapper classes, translating the Value property into a call to
684 // the appropriate XParameters interface
688 catch( const Exception
& )
690 TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::completeParameters: caught an exception while propagating the values" );
696 bool ParameterManager::consultParameterListeners( ::osl::ResettableMutexGuard
& _rClearForNotifies
)
698 bool bCanceled
= false;
700 sal_Int32 nParamsLeft
= m_pOuterParameters
->getParameters().size();
701 // TODO: shouldn't we subtract all the parameters which were already visited?
704 ::comphelper::OInterfaceIteratorHelper3
aIter( m_aParameterListeners
);
705 Reference
< XPropertySet
> xProp
= m_xComponent
;
706 OSL_ENSURE(xProp
.is(),"Some already released my component!");
707 DatabaseParameterEvent
aEvent( xProp
, m_pOuterParameters
);
709 _rClearForNotifies
.clear();
710 while ( aIter
.hasMoreElements() && !bCanceled
)
711 bCanceled
= !aIter
.next()->approveParameter( aEvent
);
712 _rClearForNotifies
.reset();
719 bool ParameterManager::fillParameterValues( const Reference
< XInteractionHandler
>& _rxCompletionHandler
, ::osl::ResettableMutexGuard
& _rClearForNotifies
)
721 OSL_PRECOND( isAlive(), "ParameterManager::fillParameterValues: not initialized, or already disposed!" );
725 if ( m_nInnerCount
== 0 )
726 // no parameters at all
729 // fill the parameters from the master-detail relationship
730 Reference
< XNameAccess
> xParentColumns
;
731 if ( getParentColumns( xParentColumns
, false ) && xParentColumns
->hasElements() && !m_aMasterFields
.empty() )
732 fillLinkedParameters( xParentColumns
);
734 // let the user (via the interaction handler) fill all remaining parameters
735 Reference
< XConnection
> xConnection
;
736 getConnection( xConnection
);
738 if ( _rxCompletionHandler
.is() )
739 return completeParameters( _rxCompletionHandler
, xConnection
);
741 return consultParameterListeners( _rClearForNotifies
);
745 void ParameterManager::getConnection( Reference
< XConnection
>& /* [out] */ _rxConnection
)
747 OSL_PRECOND( isAlive(), "ParameterManager::getConnection: not initialized, or already disposed!" );
751 _rxConnection
.clear();
754 Reference
< XPropertySet
> xProp
= m_xComponent
;
755 OSL_ENSURE(xProp
.is(),"Some already released my component!");
757 xProp
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ACTIVE_CONNECTION
) ) >>= _rxConnection
;
759 catch( const Exception
& )
761 SAL_WARN( "connectivity.commontools", "ParameterManager::getConnection: could not retrieve the connection of the !" );
766 void ParameterManager::cacheConnectionInfo()
770 Reference
< XConnection
> xConnection
;
771 getConnection( xConnection
);
772 Reference
< XDatabaseMetaData
> xMeta
;
773 if ( xConnection
.is() )
774 xMeta
= xConnection
->getMetaData();
777 m_xConnectionMetadata
= xMeta
;
778 m_sIdentifierQuoteString
= xMeta
->getIdentifierQuoteString();
779 m_sSpecialCharacters
= xMeta
->getExtraNameCharacters();
782 catch( const Exception
& )
784 TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::cacheConnectionInfo: caught an exception" );
789 bool ParameterManager::getColumns( Reference
< XNameAccess
>& /* [out] */ _rxColumns
, bool _bFromComposer
)
793 Reference
< XColumnsSupplier
> xColumnSupp
;
794 if ( _bFromComposer
)
795 xColumnSupp
.set(m_xComposer
, css::uno::UNO_QUERY
);
797 xColumnSupp
.set( m_xComponent
.get(),UNO_QUERY
);
798 if ( xColumnSupp
.is() )
799 _rxColumns
= xColumnSupp
->getColumns();
800 OSL_ENSURE( _rxColumns
.is(), "ParameterManager::getColumns: could not retrieve the columns for the detail !" );
802 return _rxColumns
.is();
806 bool ParameterManager::getParentColumns( Reference
< XNameAccess
>& /* [out] */ _out_rxParentColumns
, bool _bFromComposer
)
808 OSL_PRECOND( isAlive(), "ParameterManager::getParentColumns: not initialized, or already disposed!" );
810 _out_rxParentColumns
.clear();
813 // get the parent of the component we're working for
814 Reference
< XChild
> xAsChild( m_xComponent
.get(), UNO_QUERY_THROW
);
815 Reference
< XPropertySet
> xParent( xAsChild
->getParent(), UNO_QUERY
);
819 // the columns supplier: either from a composer, or directly from the
820 Reference
< XColumnsSupplier
> xParentColSupp
;
821 if ( _bFromComposer
)
823 // re-create the parent composer all the time. Else, we'd have to bother with
824 // being a listener at its properties, its loaded state, and event the parent-relationship.
825 m_xParentComposer
.reset(
826 getCurrentSettingsComposer( xParent
, m_xContext
, nullptr ),
827 SharedQueryComposer::TakeOwnership
829 xParentColSupp
.set(m_xParentComposer
, css::uno::UNO_QUERY
);
832 xParentColSupp
.set(xParent
, css::uno::UNO_QUERY
);
834 // get the columns of the parent
835 if ( xParentColSupp
.is() )
836 _out_rxParentColumns
= xParentColSupp
->getColumns();
838 catch( const Exception
& )
840 TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::getParentColumns" );
842 return _out_rxParentColumns
.is();
846 void ParameterManager::addParameterListener( const Reference
< XDatabaseParameterListener
>& _rxListener
)
848 if ( _rxListener
.is() )
849 m_aParameterListeners
.addInterface( _rxListener
);
853 void ParameterManager::removeParameterListener( const Reference
< XDatabaseParameterListener
>& _rxListener
)
855 m_aParameterListeners
.removeInterface( _rxListener
);
859 void ParameterManager::resetParameterValues( )
861 OSL_PRECOND( isAlive(), "ParameterManager::resetParameterValues: not initialized, or already disposed!" );
865 if ( !m_nInnerCount
)
866 // no parameters at all
871 Reference
< XNameAccess
> xColumns
;
872 if ( !getColumns( xColumns
, false ) )
873 // already asserted in getColumns
876 Reference
< XNameAccess
> xParentColumns
;
877 if ( !getParentColumns( xParentColumns
, false ) )
880 // loop through all links pairs
881 auto pMasterFields
= m_aMasterFields
.begin();
882 auto pDetailFields
= m_aDetailFields
.begin();
884 Reference
< XPropertySet
> xMasterField
;
885 Reference
< XPropertySet
> xDetailField
;
888 auto pDetailFieldsEnd
= m_aDetailFields
.end();
889 for ( ; pDetailFields
!= pDetailFieldsEnd
; ++pDetailFields
, ++pMasterFields
)
891 if ( !xParentColumns
->hasByName( *pMasterFields
) )
893 // if this name is unknown in the parent columns, then we don't have a source
894 // for copying the value to the detail columns
895 SAL_WARN( "connectivity.commontools", "ParameterManager::resetParameterValues: this should have been stripped long before!" );
899 // for all inner parameters which are bound to the name as specified by the
900 // slave element of the link, propagate the value from the master column to this
902 ParameterInformation::const_iterator aParamInfo
= m_aParameterInformation
.find( *pDetailFields
);
903 if ( ( aParamInfo
== m_aParameterInformation
.end() )
904 || ( aParamInfo
->second
.aInnerIndexes
.empty() )
907 SAL_WARN( "connectivity.commontools", "ParameterManager::resetParameterValues: nothing known about this detail field!" );
911 xParentColumns
->getByName( *pMasterFields
) >>= xMasterField
;
912 if ( !xMasterField
.is() )
915 for (auto const& aPosition
: aParamInfo
->second
.aInnerIndexes
)
917 Reference
< XPropertySet
> xInnerParameter
;
918 m_xInnerParamColumns
->getByIndex(aPosition
) >>= xInnerParameter
;
919 if ( !xInnerParameter
.is() )
922 OUString sParamColumnRealName
;
923 xInnerParameter
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME
) ) >>= sParamColumnRealName
;
924 if ( xColumns
->hasByName( sParamColumnRealName
) )
925 { // our own columns have a column which's name equals the real name of the param column
926 // -> transfer the value property
927 xColumns
->getByName( sParamColumnRealName
) >>= xDetailField
;
928 if ( xDetailField
.is() )
929 xDetailField
->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE
), xMasterField
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE
) ) );
934 catch( const Exception
& )
936 TOOLS_WARN_EXCEPTION( "connectivity.commontools", "ParameterManager::resetParameterValues" );
942 void ParameterManager::externalParameterVisited( sal_Int32 _nIndex
)
944 if ( m_aParametersVisited
.size() < o3tl::make_unsigned(_nIndex
) )
946 m_aParametersVisited
.reserve( _nIndex
);
947 for ( sal_Int32 i
= m_aParametersVisited
.size(); i
< _nIndex
; ++i
)
948 m_aParametersVisited
.push_back( false );
950 m_aParametersVisited
[ _nIndex
- 1 ] = true;
953 void ParameterManager::setNull( sal_Int32 _nIndex
, sal_Int32 sqlType
)
955 ::osl::MutexGuard
aGuard(m_rMutex
);
956 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
957 if (!m_xInnerParamUpdate
.is())
959 m_xInnerParamUpdate
->setNull(_nIndex
, sqlType
);
960 externalParameterVisited(_nIndex
);
964 void ParameterManager::setObjectNull( sal_Int32 _nIndex
, sal_Int32 sqlType
, const OUString
& typeName
)
966 ::osl::MutexGuard
aGuard(m_rMutex
);
967 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
968 if (!m_xInnerParamUpdate
.is())
970 m_xInnerParamUpdate
->setObjectNull(_nIndex
, sqlType
, typeName
);
971 externalParameterVisited(_nIndex
);
975 void ParameterManager::setBoolean( sal_Int32 _nIndex
, bool x
)
977 ::osl::MutexGuard
aGuard(m_rMutex
);
978 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
979 if (!m_xInnerParamUpdate
.is())
981 m_xInnerParamUpdate
->setBoolean(_nIndex
, x
);
982 externalParameterVisited(_nIndex
);
986 void ParameterManager::setByte( sal_Int32 _nIndex
, sal_Int8 x
)
988 ::osl::MutexGuard
aGuard(m_rMutex
);
989 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
990 if (!m_xInnerParamUpdate
.is())
992 m_xInnerParamUpdate
->setByte(_nIndex
, x
);
993 externalParameterVisited(_nIndex
);
997 void ParameterManager::setShort( sal_Int32 _nIndex
, sal_Int16 x
)
999 ::osl::MutexGuard
aGuard(m_rMutex
);
1000 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1001 if (!m_xInnerParamUpdate
.is())
1003 m_xInnerParamUpdate
->setShort(_nIndex
, x
);
1004 externalParameterVisited(_nIndex
);
1008 void ParameterManager::setInt( sal_Int32 _nIndex
, sal_Int32 x
)
1010 ::osl::MutexGuard
aGuard(m_rMutex
);
1011 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1012 if (!m_xInnerParamUpdate
.is())
1014 m_xInnerParamUpdate
->setInt(_nIndex
, x
);
1015 externalParameterVisited(_nIndex
);
1019 void ParameterManager::setLong( sal_Int32 _nIndex
, sal_Int64 x
)
1021 ::osl::MutexGuard
aGuard(m_rMutex
);
1022 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1023 if (!m_xInnerParamUpdate
.is())
1025 m_xInnerParamUpdate
->setLong(_nIndex
, x
);
1026 externalParameterVisited(_nIndex
);
1030 void ParameterManager::setFloat( sal_Int32 _nIndex
, float x
)
1032 ::osl::MutexGuard
aGuard(m_rMutex
);
1033 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1034 if (!m_xInnerParamUpdate
.is())
1036 m_xInnerParamUpdate
->setFloat(_nIndex
, x
);
1037 externalParameterVisited(_nIndex
);
1041 void ParameterManager::setDouble( sal_Int32 _nIndex
, double x
)
1043 ::osl::MutexGuard
aGuard(m_rMutex
);
1044 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1045 if (!m_xInnerParamUpdate
.is())
1047 m_xInnerParamUpdate
->setDouble(_nIndex
, x
);
1048 externalParameterVisited(_nIndex
);
1052 void ParameterManager::setString( sal_Int32 _nIndex
, const OUString
& x
)
1054 ::osl::MutexGuard
aGuard(m_rMutex
);
1055 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1056 if (!m_xInnerParamUpdate
.is())
1058 m_xInnerParamUpdate
->setString(_nIndex
, x
);
1059 externalParameterVisited(_nIndex
);
1063 void ParameterManager::setBytes( sal_Int32 _nIndex
, const css::uno::Sequence
< sal_Int8
>& x
)
1065 ::osl::MutexGuard
aGuard(m_rMutex
);
1066 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1067 if (!m_xInnerParamUpdate
.is())
1069 m_xInnerParamUpdate
->setBytes(_nIndex
, x
);
1070 externalParameterVisited(_nIndex
);
1074 void ParameterManager::setDate( sal_Int32 _nIndex
, const css::util::Date
& x
)
1076 ::osl::MutexGuard
aGuard(m_rMutex
);
1077 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1078 if (!m_xInnerParamUpdate
.is())
1080 m_xInnerParamUpdate
->setDate(_nIndex
, x
);
1081 externalParameterVisited(_nIndex
);
1085 void ParameterManager::setTime( sal_Int32 _nIndex
, const css::util::Time
& x
)
1087 ::osl::MutexGuard
aGuard(m_rMutex
);
1088 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1089 if (!m_xInnerParamUpdate
.is())
1091 m_xInnerParamUpdate
->setTime(_nIndex
, x
);
1092 externalParameterVisited(_nIndex
);
1096 void ParameterManager::setTimestamp( sal_Int32 _nIndex
, const css::util::DateTime
& x
)
1098 ::osl::MutexGuard
aGuard(m_rMutex
);
1099 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1100 if (!m_xInnerParamUpdate
.is())
1102 m_xInnerParamUpdate
->setTimestamp(_nIndex
, x
);
1103 externalParameterVisited(_nIndex
);
1107 void ParameterManager::setBinaryStream( sal_Int32 _nIndex
, const css::uno::Reference
< css::io::XInputStream
>& x
, sal_Int32 length
)
1109 ::osl::MutexGuard
aGuard(m_rMutex
);
1110 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1111 if (!m_xInnerParamUpdate
.is())
1113 m_xInnerParamUpdate
->setBinaryStream(_nIndex
, x
, length
);
1114 externalParameterVisited(_nIndex
);
1118 void ParameterManager::setCharacterStream( sal_Int32 _nIndex
, const css::uno::Reference
< css::io::XInputStream
>& x
, sal_Int32 length
)
1120 ::osl::MutexGuard
aGuard(m_rMutex
);
1121 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1122 if (!m_xInnerParamUpdate
.is())
1124 m_xInnerParamUpdate
->setCharacterStream(_nIndex
, x
, length
);
1125 externalParameterVisited(_nIndex
);
1129 void ParameterManager::setObject( sal_Int32 _nIndex
, const css::uno::Any
& x
)
1131 ::osl::MutexGuard
aGuard(m_rMutex
);
1132 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1133 if (!m_xInnerParamUpdate
.is())
1135 m_xInnerParamUpdate
->setObject(_nIndex
, x
);
1136 externalParameterVisited(_nIndex
);
1140 void ParameterManager::setObjectWithInfo( sal_Int32 _nIndex
, const css::uno::Any
& x
, sal_Int32 targetSqlType
, sal_Int32 scale
)
1142 ::osl::MutexGuard
aGuard(m_rMutex
);
1143 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1144 if (!m_xInnerParamUpdate
.is())
1146 m_xInnerParamUpdate
->setObjectWithInfo(_nIndex
, x
, targetSqlType
, scale
);
1147 externalParameterVisited(_nIndex
);
1151 void ParameterManager::setRef( sal_Int32 _nIndex
, const css::uno::Reference
< css::sdbc::XRef
>& x
)
1153 ::osl::MutexGuard
aGuard(m_rMutex
);
1154 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1155 if (!m_xInnerParamUpdate
.is())
1157 m_xInnerParamUpdate
->setRef(_nIndex
, x
);
1158 externalParameterVisited(_nIndex
);
1162 void ParameterManager::setBlob( sal_Int32 _nIndex
, const css::uno::Reference
< css::sdbc::XBlob
>& x
)
1164 ::osl::MutexGuard
aGuard(m_rMutex
);
1165 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1166 if (!m_xInnerParamUpdate
.is())
1168 m_xInnerParamUpdate
->setBlob(_nIndex
, x
);
1169 externalParameterVisited(_nIndex
);
1173 void ParameterManager::setClob( sal_Int32 _nIndex
, const css::uno::Reference
< css::sdbc::XClob
>& x
)
1175 ::osl::MutexGuard
aGuard(m_rMutex
);
1176 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1177 if (!m_xInnerParamUpdate
.is())
1179 m_xInnerParamUpdate
->setClob(_nIndex
, x
);
1180 externalParameterVisited(_nIndex
);
1184 void ParameterManager::setArray( sal_Int32 _nIndex
, const css::uno::Reference
< css::sdbc::XArray
>& x
)
1186 ::osl::MutexGuard
aGuard(m_rMutex
);
1187 OSL_ENSURE(m_xInnerParamUpdate
.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!");
1188 if (!m_xInnerParamUpdate
.is())
1190 m_xInnerParamUpdate
->setArray(_nIndex
, x
);
1191 externalParameterVisited(_nIndex
);
1195 void ParameterManager::clearParameters( )
1197 if ( m_xInnerParamUpdate
.is() )
1198 m_xInnerParamUpdate
->clearParameters( );
1201 void SAL_CALL
OParameterContinuation::setParameters( const Sequence
< PropertyValue
>& _rValues
)
1203 m_aValues
= _rValues
;
1210 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */