Use correct object
[LibreOffice.git] / connectivity / source / commontools / parameters.cxx
blob62710654e507125cd6daed9f09bb629b93324feb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
43 namespace dbtools
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 )
58 :m_rMutex ( _rMutex )
59 ,m_aParameterListeners( _rMutex )
60 ,m_xContext ( _rxContext )
61 ,m_nInnerCount ( 0 )
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() )
78 return;
82 void ParameterManager::dispose( )
84 clearAllParameterInformation();
86 m_xComposer.clear();
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;
100 m_nInnerCount = 0;
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);
108 m_bUpToDate = false;
112 void ParameterManager::setAllParametersNull()
114 OSL_PRECOND( isAlive(), "ParameterManager::setAllParametersNull: not initialized, or already disposed!" );
115 if ( !isAlive() )
116 return;
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 !" );
127 m_xComposer.clear();
128 m_xInnerParamColumns.clear();
129 m_nInnerCount = 0;
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() )
157 return;
159 // strip previous index information
160 if ( _bSecondRun )
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 )
176 xParam.clear();
177 m_xInnerParamColumns->getByIndex( i ) >>= xParam;
179 OUString sName;
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;
192 else
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 )
208 OUString sFilter;
209 // format is:
210 // <detail_column> = :<new_param_name>
212 OUString tblName;
213 xDetailField->getPropertyValue(u"TableName"_ustr) >>= tblName;
214 if (!tblName.isEmpty())
215 sFilter = ::dbtools::quoteTableName( m_xConnectionMetadata, tblName, ::dbtools::EComposeRule::InDataManipulation ) + ".";
218 OUString colName;
219 xDetailField->getPropertyValue(u"RealName"_ustr) >>= colName;
220 bool isFunction(false);
221 xDetailField->getPropertyValue(u"Function"_ustr) >>= isFunction;
222 if (isFunction)
223 sFilter += colName;
224 else
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() )
250 return;
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() )
266 continue;
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;
273 continue;
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 );
286 else
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 );
309 else
310 _out_rAdditionalFilterComponents.push_back( sFilterCondition );
312 // remember the new "detail field" for this link
313 aStrippedDetailFields.push_back( sNewParamName );
314 bNeedExchangeLinks = true;
316 else
318 // the detail field neither denotes a column name, nor a parameter name
319 bValidLink = false;
320 bNeedExchangeLinks = true;
324 if ( bValidLink )
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!" );
342 if ( !isAlive() )
343 return;
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!");
351 if ( xProp.is() )
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
374 return;
376 Reference< XNameAccess > xParentColumns;
377 if ( !getParentColumns( xParentColumns, true ) )
378 return;
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() )
434 return;
436 m_pOuterParameters = new param::ParameterWrapperContainer;
438 #if OSL_DEBUG_LEVEL > 0
439 sal_Int32 nSmallestIndexLinkedByColumnName = -1;
440 sal_Int32 nLargestIndexNotLinkedByColumnName = -1;
441 #endif
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 ];
452 else
454 nLargestIndexNotLinkedByColumnName = aParam.second.aInnerIndexes[ aParam.second.aInnerIndexes.size() - 1 ];
457 #endif
458 if ( aParam.second.eType != ParameterClassification::FilledExternally )
459 continue;
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
467 aIndex = -1;
468 ++nAlreadyVisited;
471 if ( nAlreadyVisited == aParam.second.aInnerIndexes.size() )
472 continue;
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).
492 #endif
496 void ParameterManager::updateParameterInfo( FilterManager& _rFilterManager )
498 OSL_PRECOND( isAlive(), "ParameterManager::updateParameterInfo: not initialized, or already disposed!" );
499 if ( !isAlive() )
500 return;
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!");
508 if ( xProp.is() )
510 if ( !initializeComposerByComponent( xProp ) )
511 { // okay, nothing to do
512 m_bUpToDate = true;
513 return;
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
540 m_bUpToDate = true;
541 return;
544 // for what now remains as outer parameters, create the wrappers for the single
545 // parameter columns
546 createOuterParameters();
548 m_bUpToDate = true;
552 void ParameterManager::fillLinkedParameters( const Reference< XNameAccess >& _rxParentColumns )
554 OSL_PRECOND( isAlive(), "ParameterManager::fillLinkedParameters: not initialized, or already disposed!" );
555 if ( !isAlive() )
556 return;
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!" );
576 continue;
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!" );
586 continue;
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() )
599 continue;
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) ),
615 nParamType,
616 nScale
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;
644 // the request
645 ParametersRequest aRequest;
646 aRequest.Parameters = m_pOuterParameters.get();
647 aRequest.Connection = _rxConnection;
648 rtl::Reference<OInteractionRequest> pRequest = new OInteractionRequest( Any( aRequest ) );
650 // some knittings
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)
666 return false;
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() )
677 #ifdef DBG_UTIL
678 OUString sName;
679 xParamColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME) ) >>= sName;
680 OSL_ENSURE( sName == aFinalValues[i].Name, "ParameterManager::completeParameters: inconsistent parameter names!" );
681 #endif
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" );
692 return true;
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?
702 if ( nParamsLeft )
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();
715 return !bCanceled;
719 bool ParameterManager::fillParameterValues( const Reference< XInteractionHandler >& _rxCompletionHandler, ::osl::ResettableMutexGuard& _rClearForNotifies )
721 OSL_PRECOND( isAlive(), "ParameterManager::fillParameterValues: not initialized, or already disposed!" );
722 if ( !isAlive() )
723 return true;
725 if ( m_nInnerCount == 0 )
726 // no parameters at all
727 return true;
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!" );
748 if ( !isAlive() )
749 return;
751 _rxConnection.clear();
754 Reference< XPropertySet > xProp = m_xComponent;
755 OSL_ENSURE(xProp.is(),"Some already released my component!");
756 if ( xProp.is() )
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();
775 if ( xMeta.is() )
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 )
791 _rxColumns.clear();
793 Reference< XColumnsSupplier > xColumnSupp;
794 if ( _bFromComposer )
795 xColumnSupp.set(m_xComposer, css::uno::UNO_QUERY);
796 else
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 );
816 if ( !xParent.is() )
817 return false;
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);
831 else
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!" );
862 if ( !isAlive() )
863 return;
865 if ( !m_nInnerCount )
866 // no parameters at all
867 return;
871 Reference< XNameAccess > xColumns;
872 if ( !getColumns( xColumns, false ) )
873 // already asserted in getColumns
874 return;
876 Reference< XNameAccess > xParentColumns;
877 if ( !getParentColumns( xParentColumns, false ) )
878 return;
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;
887 // now really ....
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!" );
896 continue;
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
901 // parameter column
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!" );
908 continue;
911 xParentColumns->getByName( *pMasterFields ) >>= xMasterField;
912 if ( !xMasterField.is() )
913 continue;
915 for (auto const& aPosition : aParamInfo->second.aInnerIndexes)
917 Reference< XPropertySet > xInnerParameter;
918 m_xInnerParamColumns->getByIndex(aPosition) >>= xInnerParameter;
919 if ( !xInnerParameter.is() )
920 continue;
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())
958 return;
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())
969 return;
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())
980 return;
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())
991 return;
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())
1002 return;
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())
1013 return;
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())
1024 return;
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())
1035 return;
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())
1046 return;
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())
1057 return;
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())
1068 return;
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())
1079 return;
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())
1090 return;
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())
1101 return;
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())
1112 return;
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())
1123 return;
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())
1134 return;
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())
1145 return;
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())
1156 return;
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())
1167 return;
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())
1178 return;
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())
1189 return;
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;
1207 } // namespace frm
1210 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */