bump product version to 6.3.0.0.beta1
[LibreOffice.git] / connectivity / source / commontools / parameters.cxx
blob3458ed7cc34e9a861969d2eeb4259a6d7ba09b8d
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/container/XEnumerationAccess.hpp>
28 #include <com/sun/star/sdb/XParametersSupplier.hpp>
29 #include <com/sun/star/sdb/XInteractionSupplyParameters.hpp>
30 #include <com/sun/star/sdb/ParametersRequest.hpp>
31 #include <com/sun/star/sdbc/SQLException.hpp>
32 #include <com/sun/star/task/XInteractionHandler.hpp>
34 #include <connectivity/dbtools.hxx>
35 #include <connectivity/filtermanager.hxx>
36 #include <TConnection.hxx>
38 #include <tools/diagnose_ex.h>
40 #include <connectivity/ParameterCont.hxx>
41 #include <rtl/ustrbuf.hxx>
42 #include <sal/log.hxx>
44 namespace dbtools
46 using namespace ::com::sun::star::uno;
47 using namespace ::com::sun::star::sdb;
48 using namespace ::com::sun::star::sdbc;
49 using namespace ::com::sun::star::sdbcx;
50 using namespace ::com::sun::star::lang;
51 using namespace ::com::sun::star::beans;
52 using namespace ::com::sun::star::task;
53 using namespace ::com::sun::star::form;
54 using namespace ::com::sun::star::container;
56 using namespace ::comphelper;
57 using namespace ::connectivity;
59 ParameterManager::ParameterManager( ::osl::Mutex& _rMutex, const Reference< XComponentContext >& _rxContext )
60 :m_rMutex ( _rMutex )
61 ,m_aParameterListeners( _rMutex )
62 ,m_xContext ( _rxContext )
63 ,m_nInnerCount ( 0 )
64 ,m_bUpToDate ( false )
66 OSL_ENSURE( m_xContext.is(), "ParameterManager::ParameterManager: no service factory!" );
70 void ParameterManager::initialize( const Reference< XPropertySet >& _rxComponent, const Reference< XAggregation >& _rxComponentAggregate )
72 OSL_ENSURE( !m_xComponent.get().is(), "ParameterManager::initialize: already initialized!" );
74 m_xComponent = _rxComponent;
75 m_xAggregatedRowSet = _rxComponentAggregate;
76 if ( m_xAggregatedRowSet.is() )
77 m_xAggregatedRowSet->queryAggregation( cppu::UnoType<decltype(m_xInnerParamUpdate)>::get() ) >>= m_xInnerParamUpdate;
78 OSL_ENSURE( m_xComponent.get().is() && m_xInnerParamUpdate.is(), "ParameterManager::initialize: invalid arguments!" );
79 if ( !m_xComponent.get().is() || !m_xInnerParamUpdate.is() )
80 return;
84 void ParameterManager::dispose( )
86 clearAllParameterInformation();
88 m_xComposer.clear();
89 m_xParentComposer.clear();
90 //m_xComponent.clear();
91 m_xInnerParamUpdate.clear();
92 m_xAggregatedRowSet.clear();
96 void ParameterManager::clearAllParameterInformation()
98 m_xInnerParamColumns.clear();
99 if ( m_pOuterParameters.is() )
100 m_pOuterParameters->dispose();
101 m_pOuterParameters = nullptr;
102 m_nInnerCount = 0;
103 ParameterInformation aEmptyInfo;
104 m_aParameterInformation.swap( aEmptyInfo );
105 m_aMasterFields.clear();
106 m_aDetailFields.clear();
107 m_sIdentifierQuoteString.clear();
108 m_sSpecialCharacters.clear();
109 m_xConnectionMetadata.clear();
110 std::vector< bool > aEmptyArray;
111 m_aParametersVisited.swap( aEmptyArray );
112 m_bUpToDate = false;
116 void ParameterManager::setAllParametersNull()
118 OSL_PRECOND( isAlive(), "ParameterManager::setAllParametersNull: not initialized, or already disposed!" );
119 if ( !isAlive() )
120 return;
122 for ( sal_Int32 i = 1; i <= m_nInnerCount; ++i )
123 m_xInnerParamUpdate->setNull( i, DataType::VARCHAR );
127 bool ParameterManager::initializeComposerByComponent( const Reference< XPropertySet >& _rxComponent )
129 OSL_PRECOND( _rxComponent.is(), "ParameterManager::initializeComposerByComponent: invalid !" );
131 m_xComposer.clear();
132 m_xInnerParamColumns.clear();
133 m_nInnerCount = 0;
135 // create and fill a composer
138 // get a query composer for the 's settings
139 m_xComposer.reset( getCurrentSettingsComposer( _rxComponent, m_xContext ), SharedQueryComposer::TakeOwnership );
141 // see if the composer found parameters
142 Reference< XParametersSupplier > xParamSupp( m_xComposer, UNO_QUERY );
143 if ( xParamSupp.is() )
144 m_xInnerParamColumns = xParamSupp->getParameters();
146 if ( m_xInnerParamColumns.is() )
147 m_nInnerCount = m_xInnerParamColumns->getCount();
149 catch( const SQLException& )
153 return m_xInnerParamColumns.is();
157 void ParameterManager::collectInnerParameters( bool _bSecondRun )
159 OSL_PRECOND( m_xInnerParamColumns.is(), "ParameterManager::collectInnerParameters: missing some internal data!" );
160 if ( !m_xInnerParamColumns.is() )
161 return;
163 // strip previous index information
164 if ( _bSecondRun )
166 for (auto & paramInfo : m_aParameterInformation)
168 paramInfo.second.aInnerIndexes.clear();
172 // we need to map the parameter names (which is all we get from the 's
173 // MasterFields property) to indices, which are needed by the XParameters
174 // interface of the row set)
175 Reference<XPropertySet> xParam;
176 for ( sal_Int32 i = 0; i < m_nInnerCount; ++i )
180 xParam.clear();
181 m_xInnerParamColumns->getByIndex( i ) >>= xParam;
183 OUString sName;
184 xParam->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME) ) >>= sName;
186 // only append additional parameters when they are not already in the list
187 ParameterInformation::iterator aExistentPos = m_aParameterInformation.find( sName );
188 OSL_ENSURE( !_bSecondRun || ( aExistentPos != m_aParameterInformation.end() ),
189 "ParameterManager::collectInnerParameters: the parameter information should already exist in the second run!" );
191 if ( aExistentPos == m_aParameterInformation.end() )
193 aExistentPos = m_aParameterInformation.emplace(
194 sName, xParam ).first;
196 else
197 aExistentPos->second.xComposerColumn = xParam;
199 aExistentPos->second.aInnerIndexes.push_back( i );
201 catch( const Exception& )
203 css::uno::Any ex( cppu::getCaughtException() );
204 SAL_WARN( "connectivity.commontools", "ParameterManager::collectInnerParameters: caught an exception! " << exceptionToString(ex) );
210 OUString ParameterManager::createFilterConditionFromColumnLink(
211 const OUString &_rMasterColumn, const Reference < XPropertySet > &xDetailField, OUString &o_rNewParamName )
213 OUString sFilter;
214 // format is:
215 // <detail_column> = :<new_param_name>
217 OUString tblName;
218 xDetailField->getPropertyValue("TableName") >>= tblName;
219 if (!tblName.isEmpty())
220 sFilter = ::dbtools::quoteTableName( m_xConnectionMetadata, tblName, ::dbtools::EComposeRule::InDataManipulation ) + ".";
223 OUString colName;
224 xDetailField->getPropertyValue("RealName") >>= colName;
225 bool isFunction(false);
226 xDetailField->getPropertyValue("Function") >>= isFunction;
227 if (isFunction)
228 sFilter += colName;
229 else
230 sFilter += quoteName( m_sIdentifierQuoteString, colName );
233 // generate a parameter name which is not already used
234 o_rNewParamName = "link_from_";
235 o_rNewParamName += convertName2SQLName( _rMasterColumn, m_sSpecialCharacters );
236 while ( m_aParameterInformation.find( o_rNewParamName ) != m_aParameterInformation.end() )
238 o_rNewParamName += "_";
241 return sFilter += " =:" + o_rNewParamName;
245 void ParameterManager::classifyLinks( const Reference< XNameAccess >& _rxParentColumns,
246 const Reference< XNameAccess >& _rxColumns,
247 std::vector< OUString >& _out_rAdditionalFilterComponents,
248 std::vector< OUString >& _out_rAdditionalHavingComponents )
250 OSL_PRECOND( m_aMasterFields.size() == m_aDetailFields.size(),
251 "ParameterManager::classifyLinks: master and detail fields should have the same length!" );
252 OSL_ENSURE( _rxColumns.is(), "ParameterManager::classifyLinks: invalid columns!" );
254 if ( !_rxColumns.is() )
255 return;
257 // we may need to strip any links which are invalid, so here go the containers
258 // for temporarily holding the new pairs
259 std::vector< OUString > aStrippedMasterFields;
260 std::vector< OUString > aStrippedDetailFields;
262 bool bNeedExchangeLinks = false;
264 // classify the links
265 auto pMasterFields = m_aMasterFields.begin();
266 auto pDetailFields = m_aDetailFields.begin();
267 auto pDetailFieldsEnd = m_aDetailFields.end();
268 for ( ; pDetailFields != pDetailFieldsEnd; ++pDetailFields, ++pMasterFields )
270 if ( pMasterFields->isEmpty() || pDetailFields->isEmpty() )
271 continue;
273 // if not even the master part of the relationship exists in the parent, the
274 // link is invalid as a whole #i63674#
275 if ( !_rxParentColumns->hasByName( *pMasterFields ) )
277 bNeedExchangeLinks = true;
278 continue;
281 bool bValidLink = true;
283 // is there an inner parameter with this name? That is, a parameter which is already part of
284 // the very original statement (not the one we create ourselves, with the additional parameters)
285 ParameterInformation::iterator aPos = m_aParameterInformation.find( *pDetailFields );
286 if ( aPos != m_aParameterInformation.end() )
287 { // there is an inner parameter with this name
288 aPos->second.eType = ParameterClassification::LinkedByParamName;
289 aStrippedDetailFields.push_back( *pDetailFields );
291 else
293 // does the detail name denote a column?
294 if ( _rxColumns->hasByName( *pDetailFields ) )
296 Reference< XPropertySet > xDetailField(_rxColumns->getByName( *pDetailFields ), UNO_QUERY);
297 assert(xDetailField.is());
299 OUString sNewParamName;
300 const OUString sFilterCondition = createFilterConditionFromColumnLink( *pMasterFields, xDetailField, sNewParamName );
301 OSL_PRECOND( !sNewParamName.isEmpty(), "ParameterManager::classifyLinks: createFilterConditionFromColumnLink returned nonsense!" );
303 // remember meta information about this new parameter
304 std::pair< ParameterInformation::iterator, bool > aInsertionPos =
305 m_aParameterInformation.emplace(
306 sNewParamName, ParameterMetaData( nullptr )
308 OSL_ENSURE( aInsertionPos.second, "ParameterManager::classifyLinks: there already was a parameter with this name!" );
309 aInsertionPos.first->second.eType = ParameterClassification::LinkedByColumnName;
311 // remember the filter component
312 if (isAggregateColumn(xDetailField))
313 _out_rAdditionalHavingComponents.push_back( sFilterCondition );
314 else
315 _out_rAdditionalFilterComponents.push_back( sFilterCondition );
317 // remember the new "detail field" for this link
318 aStrippedDetailFields.push_back( sNewParamName );
319 bNeedExchangeLinks = true;
321 else
323 // the detail field neither denotes a column name, nor a parameter name
324 bValidLink = false;
325 bNeedExchangeLinks = true;
329 if ( bValidLink )
330 aStrippedMasterFields.push_back( *pMasterFields );
332 SAL_WARN_IF( aStrippedMasterFields.size() != aStrippedDetailFields.size(),
333 "connectivity.commontools",
334 "ParameterManager::classifyLinks: inconsistency in new link pairs!" );
336 if ( bNeedExchangeLinks )
338 m_aMasterFields.swap(aStrippedMasterFields);
339 m_aDetailFields.swap(aStrippedDetailFields);
344 void ParameterManager::analyzeFieldLinks( FilterManager& _rFilterManager, bool& /* [out] */ _rColumnsInLinkDetails )
346 OSL_PRECOND( isAlive(), "ParameterManager::analyzeFieldLinks: not initialized, or already disposed!" );
347 if ( !isAlive() )
348 return;
350 _rColumnsInLinkDetails = false;
353 // the links as determined by the properties
354 Reference< XPropertySet > xProp = m_xComponent;
355 OSL_ENSURE(xProp.is(),"Someone already released my component!");
356 if ( xProp.is() )
358 Sequence<OUString> aTmp;
359 if (xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MASTERFIELDS) ) >>= aTmp)
360 comphelper::sequenceToContainer(m_aMasterFields, aTmp);
361 if (xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DETAILFIELDS) ) >>= aTmp)
362 comphelper::sequenceToContainer(m_aDetailFields, aTmp);
366 // normalize to equal length
367 sal_Int32 nMasterLength = m_aMasterFields.size();
368 sal_Int32 nDetailLength = m_aDetailFields.size();
370 if ( nMasterLength > nDetailLength )
371 m_aMasterFields.resize( nDetailLength );
372 else if ( nDetailLength > nMasterLength )
373 m_aDetailFields.resize( nMasterLength );
376 Reference< XNameAccess > xColumns;
377 if ( !getColumns( xColumns, true ) )
378 // already asserted in getColumns
379 return;
381 Reference< XNameAccess > xParentColumns;
382 if ( !getParentColumns( xParentColumns, true ) )
383 return;
385 // classify the links - depending on what the detail fields in each link pair denotes
386 std::vector< OUString > aAdditionalFilterComponents;
387 std::vector< OUString > aAdditionalHavingComponents;
388 classifyLinks( xParentColumns, xColumns, aAdditionalFilterComponents, aAdditionalHavingComponents );
390 // did we find links where the detail field refers to a detail column (instead of a parameter name)?
391 if ( !aAdditionalFilterComponents.empty() )
393 // build a conjunction of all the filter components
394 OUStringBuffer sAdditionalFilter;
395 for (auto const& elem : aAdditionalFilterComponents)
397 if ( !sAdditionalFilter.isEmpty() )
398 sAdditionalFilter.append(" AND ");
400 sAdditionalFilter.append("( ");
401 sAdditionalFilter.append(elem);
402 sAdditionalFilter.append(" )");
405 // now set this filter at the filter manager
406 _rFilterManager.setFilterComponent( FilterManager::FilterComponent::LinkFilter, sAdditionalFilter.makeStringAndClear() );
408 _rColumnsInLinkDetails = true;
411 if ( !aAdditionalHavingComponents.empty() )
413 // build a conjunction of all the filter components
414 OUStringBuffer sAdditionalHaving;
415 for (auto const& elem : aAdditionalHavingComponents)
417 if ( !sAdditionalHaving.isEmpty() )
418 sAdditionalHaving.append(" AND ");
420 sAdditionalHaving.append("( ");
421 sAdditionalHaving.append(elem);
422 sAdditionalHaving.append(" )");
425 // now set this having clause at the filter manager
426 _rFilterManager.setFilterComponent( FilterManager::FilterComponent::LinkHaving, sAdditionalHaving.makeStringAndClear() );
428 _rColumnsInLinkDetails = true;
431 catch( const Exception& )
433 css::uno::Any ex( cppu::getCaughtException() );
434 SAL_WARN( "connectivity.commontools", "ParameterManager::analyzeFieldLinks: caught an exception! " << exceptionToString(ex) );
439 void ParameterManager::createOuterParameters()
441 OSL_PRECOND( !m_pOuterParameters.is(), "ParameterManager::createOuterParameters: outer parameters not initialized!" );
442 OSL_PRECOND( m_xInnerParamUpdate.is(), "ParameterManager::createOuterParameters: no write access to the inner parameters!" );
443 if ( !m_xInnerParamUpdate.is() )
444 return;
446 m_pOuterParameters = new param::ParameterWrapperContainer;
448 #if OSL_DEBUG_LEVEL > 0
449 sal_Int32 nSmallestIndexLinkedByColumnName = -1;
450 sal_Int32 nLargestIndexNotLinkedByColumnName = -1;
451 #endif
452 for (auto & aParam : m_aParameterInformation)
454 #if OSL_DEBUG_LEVEL > 0
455 if ( aParam.second.aInnerIndexes.size() )
457 if ( aParam.second.eType == ParameterClassification::LinkedByColumnName )
459 if ( nSmallestIndexLinkedByColumnName == -1 )
460 nSmallestIndexLinkedByColumnName = aParam.second.aInnerIndexes[ 0 ];
462 else
464 nLargestIndexNotLinkedByColumnName = aParam.second.aInnerIndexes[ aParam.second.aInnerIndexes.size() - 1 ];
467 #endif
468 if ( aParam.second.eType != ParameterClassification::FilledExternally )
469 continue;
471 // check which of the parameters have already been visited (e.g. filled via XParameters)
472 size_t nAlreadyVisited = 0;
473 for (auto & aIndex : aParam.second.aInnerIndexes)
475 if ( ( m_aParametersVisited.size() > static_cast<size_t>(aIndex) ) && m_aParametersVisited[ aIndex ] )
476 { // exclude this index
477 aIndex = -1;
478 ++nAlreadyVisited;
481 if ( nAlreadyVisited == aParam.second.aInnerIndexes.size() )
482 continue;
484 // need a wrapper for this .... the "inner parameters" as supplied by a result set don't have a "Value"
485 // property, but the parameter listeners expect such a property. So we need an object "aggregating"
486 // xParam and supplying an additional property ("Value")
487 // (it's no real aggregation of course ...)
488 m_pOuterParameters->push_back( new param::ParameterWrapper( aParam.second.xComposerColumn, m_xInnerParamUpdate, aParam.second.aInnerIndexes ) );
491 #if OSL_DEBUG_LEVEL > 0
492 OSL_ENSURE( ( nSmallestIndexLinkedByColumnName == -1 ) || ( nLargestIndexNotLinkedByColumnName == -1 ) ||
493 ( nSmallestIndexLinkedByColumnName > nLargestIndexNotLinkedByColumnName ),
494 "ParameterManager::createOuterParameters: inconsistency!" );
496 // for the master-detail links, where the detail field denoted a column name, we created an additional ("artificial")
497 // filter, and *appended* it to all other (potentially) existing filters of the row set. This means that the indexes
498 // for the parameters resulting from the artificial filter should be larger than any other parameter index, and this
499 // is what the assertion checks.
500 // If the assertion fails, then we would need another handling for the "parameters visited" flags, since they're based
501 // on parameter indexes *without* the artificial filter (because this filter is not visible from the outside).
502 #endif
506 void ParameterManager::updateParameterInfo( FilterManager& _rFilterManager )
508 OSL_PRECOND( isAlive(), "ParameterManager::updateParameterInfo: not initialized, or already disposed!" );
509 if ( !isAlive() )
510 return;
512 clearAllParameterInformation();
513 cacheConnectionInfo();
515 // check whether the is based on a statement/query which requires parameters
516 Reference< XPropertySet > xProp = m_xComponent;
517 OSL_ENSURE(xProp.is(),"Some already released my component!");
518 if ( xProp.is() )
520 if ( !initializeComposerByComponent( xProp ) )
521 { // okay, nothing to do
522 m_bUpToDate = true;
523 return;
524 } // if ( !initializeComposerByComponent( m_xComponent ) )
526 SAL_WARN_IF( !m_xInnerParamColumns.is(),
527 "connectivity.commontools",
528 "ParameterManager::updateParameterInfo: initializeComposerByComponent did nonsense (1)!" );
530 // collect all parameters which are defined by the "inner parameters"
531 collectInnerParameters( false );
533 // analyze the master-detail relationships
534 bool bColumnsInLinkDetails = false;
535 analyzeFieldLinks( _rFilterManager, bColumnsInLinkDetails );
537 if ( bColumnsInLinkDetails )
539 // okay, in this case, analyzeFieldLinks modified the "real" filter at the RowSet, to contain
540 // an additional restriction (which we created ourself)
541 // So we need to update all information about our inner parameter columns
542 Reference< XPropertySet > xDirectRowSetProps;
543 m_xAggregatedRowSet->queryAggregation( cppu::UnoType<decltype(xDirectRowSetProps)>::get() ) >>= xDirectRowSetProps;
544 OSL_VERIFY( initializeComposerByComponent( xDirectRowSetProps ) );
545 collectInnerParameters( true );
548 if ( !m_nInnerCount )
549 { // no parameters at all
550 m_bUpToDate = true;
551 return;
554 // for what now remains as outer parameters, create the wrappers for the single
555 // parameter columns
556 createOuterParameters();
558 m_bUpToDate = true;
562 void ParameterManager::fillLinkedParameters( const Reference< XNameAccess >& _rxParentColumns )
564 OSL_PRECOND( isAlive(), "ParameterManager::fillLinkedParameters: not initialized, or already disposed!" );
565 if ( !isAlive() )
566 return;
567 OSL_PRECOND( m_xInnerParamColumns.is(), "ParameterManager::fillLinkedParameters: no inner parameters found!" );
568 OSL_ENSURE ( _rxParentColumns.is(), "ParameterManager::fillLinkedParameters: invalid parent columns!" );
572 // the master and detail field( name)s of the
573 auto pMasterFields = m_aMasterFields.begin();
574 auto pDetailFields = m_aDetailFields.begin();
576 sal_Int32 nMasterLen = m_aMasterFields.size();
578 // loop through all master fields. For each of them, get the respective column from the
579 // parent , and forward its current value as parameter value to the (inner) row set
580 for ( sal_Int32 i = 0; i < nMasterLen; ++i, ++pMasterFields, ++pDetailFields )
582 // does the name denote a valid column in the parent?
583 if ( !_rxParentColumns->hasByName( *pMasterFields ) )
585 SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: invalid master names should have been stripped long before!" );
586 continue;
589 // do we, for this name, know where to place the values?
590 ParameterInformation::const_iterator aParamInfo = m_aParameterInformation.find( *pDetailFields );
591 if ( ( aParamInfo == m_aParameterInformation.end() )
592 || ( aParamInfo->second.aInnerIndexes.empty() )
595 SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: nothing known about this detail field!" );
596 continue;
599 // the concrete master field
600 Reference< XPropertySet > xMasterField(_rxParentColumns->getByName( *pMasterFields ),UNO_QUERY);
602 // the positions where we have to fill in values for the current parameter name
603 for (auto const& aPosition : aParamInfo->second.aInnerIndexes)
605 // the concrete detail field
606 Reference< XPropertySet > xDetailField(m_xInnerParamColumns->getByIndex(aPosition),UNO_QUERY);
607 OSL_ENSURE( xDetailField.is(), "ParameterManager::fillLinkedParameters: invalid detail field!" );
608 if ( !xDetailField.is() )
609 continue;
611 // type and scale of the parameter field
612 sal_Int32 nParamType = DataType::VARCHAR;
613 OSL_VERIFY( xDetailField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE) ) >>= nParamType );
615 sal_Int32 nScale = 0;
616 if ( xDetailField->getPropertySetInfo()->hasPropertyByName( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE) ) )
617 OSL_VERIFY( xDetailField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE) ) >>= nScale );
619 // transfer the param value
622 m_xInnerParamUpdate->setObjectWithInfo(
623 aPosition + 1, // parameters are based at 1
624 xMasterField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE) ),
625 nParamType,
626 nScale
629 catch( const Exception& )
631 DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
632 SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: master-detail parameter number " <<
633 sal_Int32( aPosition + 1 ) << " could not be filled!" );
638 catch( const Exception& )
640 DBG_UNHANDLED_EXCEPTION("connectivity.commontools");
645 bool ParameterManager::completeParameters( const Reference< XInteractionHandler >& _rxCompletionHandler, const Reference< XConnection >& _rxConnection )
647 OSL_PRECOND( isAlive(), "ParameterManager::completeParameters: not initialized, or already disposed!" );
648 OSL_ENSURE ( _rxCompletionHandler.is(), "ParameterManager::completeParameters: invalid interaction handler!" );
650 // two continuations (Ok and Cancel)
651 OInteractionAbort* pAbort = new OInteractionAbort;
652 OParameterContinuation* pParams = new OParameterContinuation;
654 // the request
655 ParametersRequest aRequest;
656 aRequest.Parameters = m_pOuterParameters.get();
657 aRequest.Connection = _rxConnection;
658 OInteractionRequest* pRequest = new OInteractionRequest( makeAny( aRequest ) );
659 Reference< XInteractionRequest > xRequest( pRequest );
661 // some knittings
662 pRequest->addContinuation( pAbort );
663 pRequest->addContinuation( pParams );
665 // execute the request
668 _rxCompletionHandler->handle( xRequest );
670 catch( const Exception& )
672 css::uno::Any ex( cppu::getCaughtException() );
673 SAL_WARN( "connectivity.commontools", "ParameterManager::completeParameters: caught an exception while calling the handler! " << exceptionToString(ex) );
676 if ( !pParams->wasSelected() )
677 // canceled by the user (i.e. (s)he canceled the dialog)
678 return false;
682 // transfer the values from the continuation object to the parameter columns
683 const Sequence< PropertyValue >& aFinalValues = pParams->getValues();
684 const PropertyValue* pFinalValues = aFinalValues.getConstArray();
685 for ( sal_Int32 i = 0; i < aFinalValues.getLength(); ++i, ++pFinalValues )
687 Reference< XPropertySet > xParamColumn(aRequest.Parameters->getByIndex( i ),UNO_QUERY);
688 if ( xParamColumn.is() )
690 #ifdef DBG_UTIL
691 OUString sName;
692 xParamColumn->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME) ) >>= sName;
693 OSL_ENSURE( sName == pFinalValues->Name, "ParameterManager::completeParameters: inconsistent parameter names!" );
694 #endif
695 xParamColumn->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE), pFinalValues->Value );
696 // the property sets are wrapper classes, translating the Value property into a call to
697 // the appropriate XParameters interface
701 catch( const Exception& )
703 css::uno::Any ex( cppu::getCaughtException() );
704 SAL_WARN( "connectivity.commontools", "ParameterManager::completeParameters: caught an exception while propagating the values! " << exceptionToString(ex) );
706 return true;
710 bool ParameterManager::consultParameterListeners( ::osl::ResettableMutexGuard& _rClearForNotifies )
712 bool bCanceled = false;
714 sal_Int32 nParamsLeft = m_pOuterParameters->getParameters().size();
715 // TODO: shouldn't we subtract all the parameters which were already visited?
716 if ( nParamsLeft )
718 ::comphelper::OInterfaceIteratorHelper2 aIter( m_aParameterListeners );
719 Reference< XPropertySet > xProp = m_xComponent;
720 OSL_ENSURE(xProp.is(),"Some already released my component!");
721 DatabaseParameterEvent aEvent( xProp.get(), m_pOuterParameters.get() );
723 _rClearForNotifies.clear();
724 while ( aIter.hasMoreElements() && !bCanceled )
725 bCanceled = !static_cast< XDatabaseParameterListener* >( aIter.next() )->approveParameter( aEvent );
726 _rClearForNotifies.reset();
729 return !bCanceled;
733 bool ParameterManager::fillParameterValues( const Reference< XInteractionHandler >& _rxCompletionHandler, ::osl::ResettableMutexGuard& _rClearForNotifies )
735 OSL_PRECOND( isAlive(), "ParameterManager::fillParameterValues: not initialized, or already disposed!" );
736 if ( !isAlive() )
737 return true;
739 if ( m_nInnerCount == 0 )
740 // no parameters at all
741 return true;
743 // fill the parameters from the master-detail relationship
744 Reference< XNameAccess > xParentColumns;
745 if ( getParentColumns( xParentColumns, false ) && xParentColumns->hasElements() && !m_aMasterFields.empty() )
746 fillLinkedParameters( xParentColumns );
748 // let the user (via the interaction handler) fill all remaining parameters
749 Reference< XConnection > xConnection;
750 getConnection( xConnection );
752 if ( _rxCompletionHandler.is() )
753 return completeParameters( _rxCompletionHandler, xConnection );
755 return consultParameterListeners( _rClearForNotifies );
759 void ParameterManager::getConnection( Reference< XConnection >& /* [out] */ _rxConnection )
761 OSL_PRECOND( isAlive(), "ParameterManager::getConnection: not initialized, or already disposed!" );
762 if ( !isAlive() )
763 return;
765 _rxConnection.clear();
768 Reference< XPropertySet > xProp = m_xComponent;
769 OSL_ENSURE(xProp.is(),"Some already released my component!");
770 if ( xProp.is() )
771 xProp->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ACTIVE_CONNECTION) ) >>= _rxConnection;
773 catch( const Exception& )
775 SAL_WARN( "connectivity.commontools", "ParameterManager::getConnection: could not retrieve the connection of the !" );
780 void ParameterManager::cacheConnectionInfo()
784 Reference< XConnection > xConnection;
785 getConnection( xConnection );
786 Reference< XDatabaseMetaData > xMeta;
787 if ( xConnection.is() )
788 xMeta = xConnection->getMetaData();
789 if ( xMeta.is() )
791 m_xConnectionMetadata = xMeta;
792 m_sIdentifierQuoteString = xMeta->getIdentifierQuoteString();
793 m_sSpecialCharacters = xMeta->getExtraNameCharacters();
796 catch( const Exception& )
798 css::uno::Any ex( cppu::getCaughtException() );
799 SAL_WARN( "connectivity.commontools", "ParameterManager::cacheConnectionInfo: caught an exception! " << exceptionToString(ex) );
804 bool ParameterManager::getColumns( Reference< XNameAccess >& /* [out] */ _rxColumns, bool _bFromComposer )
806 _rxColumns.clear();
808 Reference< XColumnsSupplier > xColumnSupp;
809 if ( _bFromComposer )
810 xColumnSupp.set(m_xComposer, css::uno::UNO_QUERY);
811 else
812 xColumnSupp.set( m_xComponent.get(),UNO_QUERY);
813 if ( xColumnSupp.is() )
814 _rxColumns = xColumnSupp->getColumns();
815 OSL_ENSURE( _rxColumns.is(), "ParameterManager::getColumns: could not retrieve the columns for the detail !" );
817 return _rxColumns.is();
821 bool ParameterManager::getParentColumns( Reference< XNameAccess >& /* [out] */ _out_rxParentColumns, bool _bFromComposer )
823 OSL_PRECOND( isAlive(), "ParameterManager::getParentColumns: not initialized, or already disposed!" );
825 _out_rxParentColumns.clear();
828 // get the parent of the component we're working for
829 Reference< XChild > xAsChild( m_xComponent.get(), UNO_QUERY_THROW );
830 Reference< XPropertySet > xParent( xAsChild->getParent(), UNO_QUERY );
831 if ( !xParent.is() )
832 return false;
834 // the columns supplier: either from a composer, or directly from the
835 Reference< XColumnsSupplier > xParentColSupp;
836 if ( _bFromComposer )
838 // re-create the parent composer all the time. Else, we'd have to bother with
839 // being a listener at its properties, its loaded state, and event the parent-relationship.
840 m_xParentComposer.reset(
841 getCurrentSettingsComposer( xParent, m_xContext ),
842 SharedQueryComposer::TakeOwnership
844 xParentColSupp.set(m_xParentComposer, css::uno::UNO_QUERY);
846 else
847 xParentColSupp.set(xParent, css::uno::UNO_QUERY);
849 // get the columns of the parent
850 if ( xParentColSupp.is() )
851 _out_rxParentColumns = xParentColSupp->getColumns();
853 catch( const Exception& )
855 css::uno::Any ex( cppu::getCaughtException() );
856 SAL_WARN( "connectivity.commontools", "ParameterManager::getParentColumns: caught an exception! " << exceptionToString(ex) );
858 return _out_rxParentColumns.is();
862 void ParameterManager::addParameterListener( const Reference< XDatabaseParameterListener >& _rxListener )
864 if ( _rxListener.is() )
865 m_aParameterListeners.addInterface( _rxListener );
869 void ParameterManager::removeParameterListener( const Reference< XDatabaseParameterListener >& _rxListener )
871 m_aParameterListeners.removeInterface( _rxListener );
875 void ParameterManager::resetParameterValues( )
877 OSL_PRECOND( isAlive(), "ParameterManager::resetParameterValues: not initialized, or already disposed!" );
878 if ( !isAlive() )
879 return;
881 if ( !m_nInnerCount )
882 // no parameters at all
883 return;
887 Reference< XNameAccess > xColumns;
888 if ( !getColumns( xColumns, false ) )
889 // already asserted in getColumns
890 return;
892 Reference< XNameAccess > xParentColumns;
893 if ( !getParentColumns( xParentColumns, false ) )
894 return;
896 // loop through all links pairs
897 auto pMasterFields = m_aMasterFields.begin();
898 auto pDetailFields = m_aDetailFields.begin();
900 Reference< XPropertySet > xMasterField;
901 Reference< XPropertySet > xDetailField;
903 // now really ....
904 auto pDetailFieldsEnd = m_aDetailFields.end();
905 for ( ; pDetailFields != pDetailFieldsEnd; ++pDetailFields, ++pMasterFields )
907 if ( !xParentColumns->hasByName( *pMasterFields ) )
909 // if this name is unknown in the parent columns, then we don't have a source
910 // for copying the value to the detail columns
911 SAL_WARN( "connectivity.commontools", "ParameterManager::resetParameterValues: this should have been stripped long before!" );
912 continue;
915 // for all inner parameters which are bound to the name as specified by the
916 // slave element of the link, propagate the value from the master column to this
917 // parameter column
918 ParameterInformation::const_iterator aParamInfo = m_aParameterInformation.find( *pDetailFields );
919 if ( ( aParamInfo == m_aParameterInformation.end() )
920 || ( aParamInfo->second.aInnerIndexes.empty() )
923 SAL_WARN( "connectivity.commontools", "ParameterManager::resetParameterValues: nothing known about this detail field!" );
924 continue;
927 xParentColumns->getByName( *pMasterFields ) >>= xMasterField;
928 if ( !xMasterField.is() )
929 continue;
931 for (auto const& aPosition : aParamInfo->second.aInnerIndexes)
933 Reference< XPropertySet > xInnerParameter;
934 m_xInnerParamColumns->getByIndex(aPosition) >>= xInnerParameter;
935 if ( !xInnerParameter.is() )
936 continue;
938 OUString sParamColumnRealName;
939 xInnerParameter->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME) ) >>= sParamColumnRealName;
940 if ( xColumns->hasByName( sParamColumnRealName ) )
941 { // our own columns have a column which's name equals the real name of the param column
942 // -> transfer the value property
943 xColumns->getByName( sParamColumnRealName ) >>= xDetailField;
944 if ( xDetailField.is() )
945 xDetailField->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE), xMasterField->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE) ) );
950 catch( const Exception& )
952 css::uno::Any ex( cppu::getCaughtException() );
953 SAL_WARN( "connectivity.commontools", "ParameterManager::resetParameterValues: caught an exception! " << exceptionToString(ex) );
959 void ParameterManager::externalParameterVisited( sal_Int32 _nIndex )
961 if ( m_aParametersVisited.size() < static_cast<size_t>(_nIndex) )
963 m_aParametersVisited.reserve( _nIndex );
964 for ( sal_Int32 i = m_aParametersVisited.size(); i < _nIndex; ++i )
965 m_aParametersVisited.push_back( false );
967 m_aParametersVisited[ _nIndex - 1 ] = true;
970 #define VISIT_PARAMETER( method ) \
971 ::osl::MutexGuard aGuard( m_rMutex ); \
972 OSL_ENSURE( m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!" ); \
973 if ( !m_xInnerParamUpdate.is() ) \
974 return; \
975 m_xInnerParamUpdate->method; \
976 externalParameterVisited( _nIndex ) \
979 void ParameterManager::setNull( sal_Int32 _nIndex, sal_Int32 sqlType )
981 VISIT_PARAMETER( setNull( _nIndex, sqlType ) );
985 void ParameterManager::setObjectNull( sal_Int32 _nIndex, sal_Int32 sqlType, const OUString& typeName )
987 VISIT_PARAMETER( setObjectNull( _nIndex, sqlType, typeName ) );
991 void ParameterManager::setBoolean( sal_Int32 _nIndex, bool x )
993 VISIT_PARAMETER( setBoolean( _nIndex, x ) );
997 void ParameterManager::setByte( sal_Int32 _nIndex, sal_Int8 x )
999 VISIT_PARAMETER( setByte( _nIndex, x ) );
1003 void ParameterManager::setShort( sal_Int32 _nIndex, sal_Int16 x )
1005 VISIT_PARAMETER( setShort( _nIndex, x ) );
1009 void ParameterManager::setInt( sal_Int32 _nIndex, sal_Int32 x )
1011 VISIT_PARAMETER( setInt( _nIndex, x ) );
1015 void ParameterManager::setLong( sal_Int32 _nIndex, sal_Int64 x )
1017 VISIT_PARAMETER( setLong( _nIndex, x ) );
1021 void ParameterManager::setFloat( sal_Int32 _nIndex, float x )
1023 VISIT_PARAMETER( setFloat( _nIndex, x ) );
1027 void ParameterManager::setDouble( sal_Int32 _nIndex, double x )
1029 VISIT_PARAMETER( setDouble( _nIndex, x ) );
1033 void ParameterManager::setString( sal_Int32 _nIndex, const OUString& x )
1035 VISIT_PARAMETER( setString( _nIndex, x ) );
1039 void ParameterManager::setBytes( sal_Int32 _nIndex, const css::uno::Sequence< sal_Int8 >& x )
1041 VISIT_PARAMETER( setBytes( _nIndex, x ) );
1045 void ParameterManager::setDate( sal_Int32 _nIndex, const css::util::Date& x )
1047 VISIT_PARAMETER( setDate( _nIndex, x ) );
1051 void ParameterManager::setTime( sal_Int32 _nIndex, const css::util::Time& x )
1053 VISIT_PARAMETER( setTime( _nIndex, x ) );
1057 void ParameterManager::setTimestamp( sal_Int32 _nIndex, const css::util::DateTime& x )
1059 VISIT_PARAMETER( setTimestamp( _nIndex, x ) );
1063 void ParameterManager::setBinaryStream( sal_Int32 _nIndex, const css::uno::Reference< css::io::XInputStream>& x, sal_Int32 length )
1065 VISIT_PARAMETER( setBinaryStream( _nIndex, x, length ) );
1069 void ParameterManager::setCharacterStream( sal_Int32 _nIndex, const css::uno::Reference< css::io::XInputStream>& x, sal_Int32 length )
1071 VISIT_PARAMETER( setCharacterStream( _nIndex, x, length ) );
1075 void ParameterManager::setObject( sal_Int32 _nIndex, const css::uno::Any& x )
1077 VISIT_PARAMETER( setObject( _nIndex, x ) );
1081 void ParameterManager::setObjectWithInfo( sal_Int32 _nIndex, const css::uno::Any& x, sal_Int32 targetSqlType, sal_Int32 scale )
1083 VISIT_PARAMETER( setObjectWithInfo( _nIndex, x, targetSqlType, scale ) );
1087 void ParameterManager::setRef( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XRef>& x )
1089 VISIT_PARAMETER( setRef( _nIndex, x ) );
1093 void ParameterManager::setBlob( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XBlob>& x )
1095 VISIT_PARAMETER( setBlob( _nIndex, x ) );
1099 void ParameterManager::setClob( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XClob>& x )
1101 VISIT_PARAMETER( setClob( _nIndex, x ) );
1105 void ParameterManager::setArray( sal_Int32 _nIndex, const css::uno::Reference< css::sdbc::XArray>& x )
1107 VISIT_PARAMETER( setArray( _nIndex, x ) );
1111 void ParameterManager::clearParameters( )
1113 if ( m_xInnerParamUpdate.is() )
1114 m_xInnerParamUpdate->clearParameters( );
1117 void SAL_CALL OParameterContinuation::setParameters( const Sequence< PropertyValue >& _rValues )
1119 m_aValues = _rValues;
1123 } // namespace frm
1126 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */