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/sdbc/XParameters.hpp>
24 #include <com/sun/star/container/XChild.hpp>
25 #include <com/sun/star/sdbcx/XColumnsSupplier.hpp>
26 #include <com/sun/star/container/XEnumerationAccess.hpp>
27 #include <com/sun/star/sdb/XParametersSupplier.hpp>
28 #include <com/sun/star/sdb/XInteractionSupplyParameters.hpp>
29 #include <com/sun/star/sdb/ParametersRequest.hpp>
31 #include <connectivity/dbtools.hxx>
32 #include <connectivity/filtermanager.hxx>
33 #include "TConnection.hxx"
35 #include <tools/diagnose_ex.h>
37 #include <comphelper/uno3.hxx>
38 #include <comphelper/proparrhlp.hxx>
39 #include <comphelper/broadcasthelper.hxx>
40 #include <connectivity/ParameterCont.hxx>
41 #include <rtl/ustrbuf.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::lang
;
50 using namespace ::com::sun::star::beans
;
51 using namespace ::com::sun::star::task
;
52 using namespace ::com::sun::star::form
;
53 using namespace ::com::sun::star::container
;
55 using namespace ::comphelper
;
56 using namespace ::connectivity
;
58 ParameterManager::ParameterManager( ::osl::Mutex
& _rMutex
, const Reference
< XComponentContext
>& _rxContext
)
60 ,m_aParameterListeners( _rMutex
)
61 ,m_xContext ( _rxContext
)
62 ,m_pOuterParameters ( NULL
)
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() )
84 void ParameterManager::dispose( )
86 clearAllParameterInformation();
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
= NULL
;
103 ParameterInformation aEmptyInfo
;
104 m_aParameterInformation
.swap( aEmptyInfo
);
105 m_aMasterFields
.realloc( 0 );
106 m_aDetailFields
.realloc( 0 );
107 m_sIdentifierQuoteString
.clear();
108 m_sSpecialCharacters
.clear();
109 m_xConnectionMetadata
.clear();
110 ::std::vector
< bool > aEmptyArray
;
111 m_aParametersVisited
.swap( aEmptyArray
);
116 void ParameterManager::setAllParametersNull()
118 OSL_PRECOND( isAlive(), "ParameterManager::setAllParametersNull: not initialized, or already disposed!" );
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 !" );
132 m_xInnerParamColumns
.clear();
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() )
163 // strip previous index information
166 for ( ParameterInformation::iterator aParamInfo
= m_aParameterInformation
.begin();
167 aParamInfo
!= m_aParameterInformation
.end();
171 aParamInfo
->second
.aInnerIndexes
.clear();
175 // we need to map the parameter names (which is all we get from the 's
176 // MasterFields property) to indices, which are needed by the XParameters
177 // interface of the row set)
178 Reference
<XPropertySet
> xParam
;
179 for ( sal_Int32 i
= 0; i
< m_nInnerCount
; ++i
)
184 m_xInnerParamColumns
->getByIndex( i
) >>= xParam
;
187 xParam
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
) ) >>= sName
;
189 // only append additional parameters when they are not already in the list
190 ParameterInformation::iterator aExistentPos
= m_aParameterInformation
.find( sName
);
191 OSL_ENSURE( !_bSecondRun
|| ( aExistentPos
!= m_aParameterInformation
.end() ),
192 "ParameterManager::collectInnerParameters: the parameter information should already exist in the second run!" );
194 if ( aExistentPos
== m_aParameterInformation
.end() )
196 aExistentPos
= m_aParameterInformation
.insert( ParameterInformation::value_type(
197 sName
, xParam
) ).first
;
200 aExistentPos
->second
.xComposerColumn
= xParam
;
202 aExistentPos
->second
.aInnerIndexes
.push_back( i
);
204 catch( const Exception
& )
206 SAL_WARN( "connectivity.commontools", "ParameterManager::collectInnerParameters: caught an exception!" );
212 OUString
ParameterManager::createFilterConditionFromColumnLink(
213 const OUString
&_rMasterColumn
, const Reference
< XPropertySet
> &xDetailField
, OUString
&o_rNewParamName
)
217 // <detail_column> = :<new_param_name>
220 xDetailField
->getPropertyValue("TableName") >>= tblName
;
221 if (!tblName
.isEmpty())
222 sFilter
= ::dbtools::quoteTableName( m_xConnectionMetadata
, tblName
, ::dbtools::eInDataManipulation
) + ".";
226 xDetailField
->getPropertyValue("RealName") >>= colName
;
227 sFilter
+= quoteName( m_sIdentifierQuoteString
, colName
) + " = :";
230 // generate a parameter name which is not already used
231 o_rNewParamName
= "link_from_";
232 o_rNewParamName
+= convertName2SQLName( _rMasterColumn
, m_sSpecialCharacters
);
233 while ( m_aParameterInformation
.find( o_rNewParamName
) != m_aParameterInformation
.end() )
235 o_rNewParamName
+= "_";
238 return sFilter
+= o_rNewParamName
;
242 void ParameterManager::classifyLinks( const Reference
< XNameAccess
>& _rxParentColumns
,
243 const Reference
< XNameAccess
>& _rxColumns
, ::std::vector
< OUString
>& _out_rAdditionalFilterComponents
)
245 OSL_PRECOND( m_aMasterFields
.getLength() == m_aDetailFields
.getLength(),
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 temporarirly holding the new pairs
254 ::std::vector
< OUString
> aStrippedMasterFields
;
255 ::std::vector
< OUString
> aStrippedDetailFields
;
257 bool bNeedExchangeLinks
= false;
259 // classify the links
260 const OUString
* pMasterFields
= m_aMasterFields
.getConstArray();
261 const OUString
* pDetailFields
= m_aDetailFields
.getConstArray();
262 const OUString
* pDetailFieldsEnd
= pDetailFields
+ m_aDetailFields
.getLength();
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
270 // #i63674# / 2006-03-28 / frank.schoenheit@sun.com
271 if ( !_rxParentColumns
->hasByName( *pMasterFields
) )
273 bNeedExchangeLinks
= true;
277 bool bValidLink
= true;
279 // is there an inner parameter with this name? That is, a parameter which is already part of
280 // the very original statement (not the one we create ourselve, with the additional parameters)
281 ParameterInformation::iterator aPos
= m_aParameterInformation
.find( *pDetailFields
);
282 if ( aPos
!= m_aParameterInformation
.end() )
283 { // there is an inner parameter with this name
284 aPos
->second
.eType
= eLinkedByParamName
;
285 aStrippedDetailFields
.push_back( *pDetailFields
);
289 // does the detail name denote a column?
290 if ( _rxColumns
->hasByName( *pDetailFields
) )
292 Reference
< XPropertySet
> xDetailField(_rxColumns
->getByName( *pDetailFields
), UNO_QUERY
);
293 assert(xDetailField
.is());
295 OUString sNewParamName
;
296 const OUString sFilterCondition
= createFilterConditionFromColumnLink( *pMasterFields
, xDetailField
, sNewParamName
);
297 OSL_PRECOND( !sNewParamName
.isEmpty(), "ParameterManager::classifyLinks: createFilterConditionFromColumnLink returned nonsense!" );
299 // remember meta information about this new parameter
300 ::std::pair
< ParameterInformation::iterator
, bool > aInsertionPos
=
301 m_aParameterInformation
.insert(
302 ParameterInformation::value_type( sNewParamName
, ParameterMetaData( NULL
) )
304 OSL_ENSURE( aInsertionPos
.second
, "ParameterManager::classifyLinks: there already was a parameter with this name!" );
305 aInsertionPos
.first
->second
.eType
= eLinkedByColumnName
;
307 // remember the filter component
308 _out_rAdditionalFilterComponents
.push_back( sFilterCondition
);
310 // remember the new "detail field" for this link
311 aStrippedDetailFields
.push_back( sNewParamName
);
312 bNeedExchangeLinks
= true;
316 // the detail field neither denotes a column name, nor a parameter name
318 bNeedExchangeLinks
= true;
323 aStrippedMasterFields
.push_back( *pMasterFields
);
325 SAL_WARN_IF( aStrippedMasterFields
.size() != aStrippedDetailFields
.size(),
326 "connectivity.commontools",
327 "ParameterManager::classifyLinks: inconsistency in new link pairs!" );
329 if ( bNeedExchangeLinks
)
331 m_aMasterFields
= Sequence
< OUString
>( aStrippedMasterFields
.data(), aStrippedMasterFields
.size() );
332 m_aDetailFields
= Sequence
< OUString
>( aStrippedDetailFields
.data(), aStrippedDetailFields
.size() );
337 void ParameterManager::analyzeFieldLinks( FilterManager
& _rFilterManager
, bool& /* [out] */ _rColumnsInLinkDetails
)
339 OSL_PRECOND( isAlive(), "ParameterManager::analyzeFieldLinks: not initialized, or already disposed!" );
343 _rColumnsInLinkDetails
= false;
346 // the links as determined by the properties
347 Reference
< XPropertySet
> xProp
= m_xComponent
;
348 OSL_ENSURE(xProp
.is(),"Some already released my component!");
351 xProp
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_MASTERFIELDS
) ) >>= m_aMasterFields
;
352 xProp
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_DETAILFIELDS
) ) >>= m_aDetailFields
;
356 // normalize to equal length
357 sal_Int32 nMasterLength
= m_aMasterFields
.getLength();
358 sal_Int32 nDetailLength
= m_aDetailFields
.getLength();
360 if ( nMasterLength
> nDetailLength
)
361 m_aMasterFields
.realloc( nDetailLength
);
362 else if ( nDetailLength
> nMasterLength
)
363 m_aDetailFields
.realloc( nMasterLength
);
366 Reference
< XNameAccess
> xColumns
;
367 if ( !getColumns( xColumns
, true ) )
368 // already asserted in getColumns
371 Reference
< XNameAccess
> xParentColumns
;
372 if ( !getParentColumns( xParentColumns
, true ) )
375 // classify the links - depending on what the detail fields in each link pair denotes
376 ::std::vector
< OUString
> aAdditionalFilterComponents
;
377 classifyLinks( xParentColumns
, xColumns
, aAdditionalFilterComponents
);
379 // did we find links where the detail field refers to a detail column (instead of a parameter name)?
380 if ( !aAdditionalFilterComponents
.empty() )
382 // build a conjunction of all the filter components
383 OUStringBuffer sAdditionalFilter
;
384 for ( ::std::vector
< OUString
>::const_iterator aComponent
= aAdditionalFilterComponents
.begin();
385 aComponent
!= aAdditionalFilterComponents
.end();
389 if ( !sAdditionalFilter
.isEmpty() )
390 sAdditionalFilter
.append(" AND ");
392 sAdditionalFilter
.appendAscii("( ",((sal_Int32
)(sizeof("( ")-1)));
393 sAdditionalFilter
.append(*aComponent
);
394 sAdditionalFilter
.appendAscii(" )",((sal_Int32
)(sizeof(" )")-1)));
397 // now set this filter at the 's filter manager
398 _rFilterManager
.setFilterComponent( FilterManager::fcLinkFilter
, sAdditionalFilter
.makeStringAndClear() );
400 _rColumnsInLinkDetails
= true;
403 catch( const Exception
& )
405 SAL_WARN( "connectivity.commontools", "ParameterManager::analyzeFieldLinks: caught an exception!" );
410 void ParameterManager::createOuterParameters()
412 OSL_PRECOND( !m_pOuterParameters
.is(), "ParameterManager::createOuterParameters: outer parameters not initialized!" );
413 OSL_PRECOND( m_xInnerParamUpdate
.is(), "ParameterManager::createOuterParameters: no write access to the inner parameters!" );
414 if ( !m_xInnerParamUpdate
.is() )
417 m_pOuterParameters
= new param::ParameterWrapperContainer
;
419 #if OSL_DEBUG_LEVEL > 0
420 sal_Int32 nSmallestIndexLinkedByColumnName
= -1;
421 sal_Int32 nLargestIndexNotLinkedByColumnName
= -1;
423 for ( ParameterInformation::iterator aParam
= m_aParameterInformation
.begin();
424 aParam
!= m_aParameterInformation
.end();
428 #if OSL_DEBUG_LEVEL > 0
429 if ( aParam
->second
.aInnerIndexes
.size() )
431 if ( aParam
->second
.eType
== eLinkedByColumnName
)
433 if ( nSmallestIndexLinkedByColumnName
== -1 )
434 nSmallestIndexLinkedByColumnName
= aParam
->second
.aInnerIndexes
[ 0 ];
438 nLargestIndexNotLinkedByColumnName
= aParam
->second
.aInnerIndexes
[ aParam
->second
.aInnerIndexes
.size() - 1 ];
442 if ( aParam
->second
.eType
!= eFilledExternally
)
445 // check which of the parameters have already been visited (e.g. filled via XParameters)
446 size_t nAlreadyVisited
= 0;
447 for ( ::std::vector
< sal_Int32
>::iterator aIndex
= aParam
->second
.aInnerIndexes
.begin();
448 aIndex
!= aParam
->second
.aInnerIndexes
.end();
452 if ( ( m_aParametersVisited
.size() > (size_t)*aIndex
) && m_aParametersVisited
[ *aIndex
] )
453 { // exclude this index
458 if ( nAlreadyVisited
== aParam
->second
.aInnerIndexes
.size() )
461 // need a wrapper for this .... the "inner parameters" as supplied by a result set don't have a "Value"
462 // property, but the parameter listeners expect such a property. So we need an object "aggregating"
463 // xParam and supplying an additional property ("Value")
464 // (it's no real aggregation of course ...)
465 m_pOuterParameters
->push_back( new param::ParameterWrapper( aParam
->second
.xComposerColumn
, m_xInnerParamUpdate
, aParam
->second
.aInnerIndexes
) );
468 #if OSL_DEBUG_LEVEL > 0
469 OSL_ENSURE( ( nSmallestIndexLinkedByColumnName
== -1 ) || ( nLargestIndexNotLinkedByColumnName
== -1 ) ||
470 ( nSmallestIndexLinkedByColumnName
> nLargestIndexNotLinkedByColumnName
),
471 "ParameterManager::createOuterParameters: inconsistency!" );
473 // for the master-detail links, where the detail field denoted a column name, we created an additional ("artificial")
474 // filter, and *appended* it to all other (potentially) existing filters of the row set. This means that the indexes
475 // for the parameters resulting from the artificial filter should be larger than any other parameter index, and this
476 // is what the assertion checks.
477 // If the assertion fails, then we would need another handling for the "parameters visited" flags, since they're based
478 // on parameter indexes *without* the artificial filter (because this filter is not visible from the outside).
483 void ParameterManager::updateParameterInfo( FilterManager
& _rFilterManager
)
485 OSL_PRECOND( isAlive(), "ParameterManager::updateParameterInfo: not initialized, or already disposed!" );
489 clearAllParameterInformation();
490 cacheConnectionInfo();
492 // check whether the is based on a statement/query which requires parameters
493 Reference
< XPropertySet
> xProp
= m_xComponent
;
494 OSL_ENSURE(xProp
.is(),"Some already released my component!");
497 if ( !initializeComposerByComponent( xProp
) )
498 { // okay, nothing to do
501 } // if ( !initializeComposerByComponent( m_xComponent ) )
503 SAL_WARN_IF( !m_xInnerParamColumns
.is(),
504 "connectivity.commontools",
505 "ParameterManager::updateParameterInfo: initializeComposerByComponent did nonsense (1)!" );
507 // collect all parameters which are defined by the "inner parameters"
508 collectInnerParameters( false );
510 // analyze the master-detail relationships
511 bool bColumnsInLinkDetails
= false;
512 analyzeFieldLinks( _rFilterManager
, bColumnsInLinkDetails
);
514 if ( bColumnsInLinkDetails
)
516 // okay, in this case, analyzeFieldLinks modified the "real" filter at the RowSet, to contain
517 // an additional restriction (which we created ourself)
518 // So we need to update all information about our inner parameter columns
519 Reference
< XPropertySet
> xDirectRowSetProps
;
520 m_xAggregatedRowSet
->queryAggregation( cppu::UnoType
<decltype(xDirectRowSetProps
)>::get() ) >>= xDirectRowSetProps
;
521 OSL_VERIFY( initializeComposerByComponent( xDirectRowSetProps
) );
522 collectInnerParameters( true );
525 if ( !m_nInnerCount
)
526 { // no parameters at all
531 // for what now remains as outer parameters, create the wrappers for the single
533 createOuterParameters();
539 void ParameterManager::fillLinkedParameters( const Reference
< XNameAccess
>& _rxParentColumns
)
541 OSL_PRECOND( isAlive(), "ParameterManager::fillLinkedParameters: not initialized, or already disposed!" );
544 OSL_PRECOND( m_xInnerParamColumns
.is(), "ParameterManager::fillLinkedParameters: no inner parameters found!" );
545 OSL_ENSURE ( _rxParentColumns
.is(), "ParameterManager::fillLinkedParameters: invalid parent columns!" );
549 // the master and detail field( name)s of the
550 const OUString
* pMasterFields
= m_aMasterFields
.getConstArray();
551 const OUString
* pDetailFields
= m_aDetailFields
.getConstArray();
553 sal_Int32 nMasterLen
= m_aMasterFields
.getLength();
555 // loop through all master fields. For each of them, get the respective column from the
556 // parent , and forward its current value as parameter value to the (inner) row set
557 for ( sal_Int32 i
= 0; i
< nMasterLen
; ++i
, ++pMasterFields
, ++pDetailFields
)
559 // does the name denote a valid column in the parent?
560 if ( !_rxParentColumns
->hasByName( *pMasterFields
) )
562 SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: invalid master names should have been stripped long before!" );
566 // do we, for this name, know where to place the values?
567 ParameterInformation::const_iterator aParamInfo
= m_aParameterInformation
.find( *pDetailFields
);
568 if ( ( aParamInfo
== m_aParameterInformation
.end() )
569 || ( aParamInfo
->second
.aInnerIndexes
.empty() )
572 SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: nothing known about this detail field!" );
576 // the concrete master field
577 Reference
< XPropertySet
> xMasterField(_rxParentColumns
->getByName( *pMasterFields
),UNO_QUERY
);
579 // the positions where we have to fill in values for the current parameter name
580 for ( ::std::vector
< sal_Int32
>::const_iterator aPosition
= aParamInfo
->second
.aInnerIndexes
.begin();
581 aPosition
!= aParamInfo
->second
.aInnerIndexes
.end();
585 // the concrete detail field
586 Reference
< XPropertySet
> xDetailField(m_xInnerParamColumns
->getByIndex( *aPosition
),UNO_QUERY
);
587 OSL_ENSURE( xDetailField
.is(), "ParameterManager::fillLinkedParameters: invalid detail field!" );
588 if ( !xDetailField
.is() )
591 // type and scale of the parameter field
592 sal_Int32 nParamType
= DataType::VARCHAR
;
593 OSL_VERIFY( xDetailField
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_TYPE
) ) >>= nParamType
);
595 sal_Int32 nScale
= 0;
596 if ( xDetailField
->getPropertySetInfo()->hasPropertyByName( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE
) ) )
597 OSL_VERIFY( xDetailField
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_SCALE
) ) >>= nScale
);
599 // transfer the param value
602 m_xInnerParamUpdate
->setObjectWithInfo(
603 *aPosition
+ 1, // parameters are based at 1
604 xMasterField
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE
) ),
609 catch( const Exception
& )
611 DBG_UNHANDLED_EXCEPTION();
612 SAL_WARN( "connectivity.commontools", "ParameterManager::fillLinkedParameters: master-detail parameter number " <<
613 sal_Int32( *aPosition
+ 1 ) << " could not be filled!" );
618 catch( const Exception
& )
620 DBG_UNHANDLED_EXCEPTION();
625 bool ParameterManager::completeParameters( const Reference
< XInteractionHandler
>& _rxCompletionHandler
, const Reference
< XConnection
>& _rxConnection
)
627 OSL_PRECOND( isAlive(), "ParameterManager::completeParameters: not initialized, or already disposed!" );
628 OSL_ENSURE ( _rxCompletionHandler
.is(), "ParameterManager::completeParameters: invalid interaction handler!" );
630 // two continuations (Ok and Cancel)
631 OInteractionAbort
* pAbort
= new OInteractionAbort
;
632 OParameterContinuation
* pParams
= new OParameterContinuation
;
635 ParametersRequest aRequest
;
636 aRequest
.Parameters
= m_pOuterParameters
.get();
637 aRequest
.Connection
= _rxConnection
;
638 OInteractionRequest
* pRequest
= new OInteractionRequest( makeAny( aRequest
) );
639 Reference
< XInteractionRequest
> xRequest( pRequest
);
642 pRequest
->addContinuation( pAbort
);
643 pRequest
->addContinuation( pParams
);
645 // execute the request
648 _rxCompletionHandler
->handle( xRequest
);
650 catch( const Exception
& )
652 SAL_WARN( "connectivity.commontools", "ParameterManager::completeParameters: caught an exception while calling the handler!" );
655 if ( !pParams
->wasSelected() )
656 // canceled by the user (i.e. (s)he canceled the dialog)
661 // transfer the values from the continuation object to the parameter columns
662 Sequence
< PropertyValue
> aFinalValues
= pParams
->getValues();
663 const PropertyValue
* pFinalValues
= aFinalValues
.getConstArray();
664 for ( sal_Int32 i
= 0; i
< aFinalValues
.getLength(); ++i
, ++pFinalValues
)
666 Reference
< XPropertySet
> xParamColumn(aRequest
.Parameters
->getByIndex( i
),UNO_QUERY
);
667 if ( xParamColumn
.is() )
671 xParamColumn
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_NAME
) ) >>= sName
;
672 OSL_ENSURE( sName
== pFinalValues
->Name
, "ParameterManager::completeParameters: inconsistent parameter names!" );
674 xParamColumn
->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE
), pFinalValues
->Value
);
675 // the property sets are wrapper classes, translating the Value property into a call to
676 // the appropriate XParameters interface
680 catch( const Exception
& )
682 SAL_WARN( "connectivity.commontools", "ParameterManager::completeParameters: caught an exception while propagating the values!" );
688 bool ParameterManager::consultParameterListeners( ::osl::ResettableMutexGuard
& _rClearForNotifies
)
690 bool bCanceled
= false;
692 sal_Int32 nParamsLeft
= m_pOuterParameters
->getParameters().size();
693 // TODO: shouldn't we subtract all the parameters which were already visited?
696 ::cppu::OInterfaceIteratorHelper
aIter( m_aParameterListeners
);
697 Reference
< XPropertySet
> xProp
= m_xComponent
;
698 OSL_ENSURE(xProp
.is(),"Some already released my component!");
699 DatabaseParameterEvent
aEvent( xProp
.get(), m_pOuterParameters
.get() );
701 _rClearForNotifies
.clear();
702 while ( aIter
.hasMoreElements() && !bCanceled
)
703 bCanceled
= !static_cast< XDatabaseParameterListener
* >( aIter
.next() )->approveParameter( aEvent
);
704 _rClearForNotifies
.reset();
711 bool ParameterManager::fillParameterValues( const Reference
< XInteractionHandler
>& _rxCompletionHandler
, ::osl::ResettableMutexGuard
& _rClearForNotifies
)
713 OSL_PRECOND( isAlive(), "ParameterManager::fillParameterValues: not initialized, or already disposed!" );
717 if ( m_nInnerCount
== 0 )
718 // no parameters at all
721 // fill the parameters from the master-detail relationship
722 Reference
< XNameAccess
> xParentColumns
;
723 if ( getParentColumns( xParentColumns
, false ) && xParentColumns
->hasElements() && m_aMasterFields
.getLength() )
724 fillLinkedParameters( xParentColumns
);
726 // let the user (via the interaction handler) fill all remaining parameters
727 Reference
< XConnection
> xConnection
;
728 getConnection( xConnection
);
730 if ( _rxCompletionHandler
.is() )
731 return completeParameters( _rxCompletionHandler
, xConnection
);
733 return consultParameterListeners( _rClearForNotifies
);
737 bool ParameterManager::getConnection( Reference
< XConnection
>& /* [out] */ _rxConnection
)
739 OSL_PRECOND( isAlive(), "ParameterManager::getConnection: not initialized, or already disposed!" );
743 _rxConnection
.clear();
746 Reference
< XPropertySet
> xProp
= m_xComponent
;
747 OSL_ENSURE(xProp
.is(),"Some already released my component!");
749 xProp
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ACTIVE_CONNECTION
) ) >>= _rxConnection
;
751 catch( const Exception
& )
753 SAL_WARN( "connectivity.commontools", "ParameterManager::getConnection: could not retrieve the connection of the !" );
755 return _rxConnection
.is();
759 void ParameterManager::cacheConnectionInfo()
763 Reference
< XConnection
> xConnection
;
764 getConnection( xConnection
);
765 Reference
< XDatabaseMetaData
> xMeta
;
766 if ( xConnection
.is() )
767 xMeta
= xConnection
->getMetaData();
770 m_xConnectionMetadata
= xMeta
;
771 m_sIdentifierQuoteString
= xMeta
->getIdentifierQuoteString();
772 m_sSpecialCharacters
= xMeta
->getExtraNameCharacters();
775 catch( const Exception
& )
777 SAL_WARN( "connectivity.commontools", "ParameterManager::cacheConnectionInfo: caught an exception!" );
782 bool ParameterManager::getColumns( Reference
< XNameAccess
>& /* [out] */ _rxColumns
, bool _bFromComposer
)
786 Reference
< XColumnsSupplier
> xColumnSupp
;
787 if ( _bFromComposer
)
788 xColumnSupp
.set(m_xComposer
, css::uno::UNO_QUERY
);
790 xColumnSupp
.set( m_xComponent
.get(),UNO_QUERY
);
791 if ( xColumnSupp
.is() )
792 _rxColumns
= xColumnSupp
->getColumns();
793 OSL_ENSURE( _rxColumns
.is(), "ParameterManager::getColumns: could not retrieve the columns for the detail !" );
795 return _rxColumns
.is();
799 bool ParameterManager::getParentColumns( Reference
< XNameAccess
>& /* [out] */ _out_rxParentColumns
, bool _bFromComposer
)
801 OSL_PRECOND( isAlive(), "ParameterManager::getParentColumns: not initialized, or already disposed!" );
803 _out_rxParentColumns
.clear();
806 // get the parent of the component we're working for
807 Reference
< XChild
> xAsChild( m_xComponent
.get(), UNO_QUERY_THROW
);
808 Reference
< XPropertySet
> xParent( xAsChild
->getParent(), UNO_QUERY
);
812 // the columns supplier: either from a composer, or directly from the
813 Reference
< XColumnsSupplier
> xParentColSupp
;
814 if ( _bFromComposer
)
816 // re-create the parent composer all the time. Else, we'd have to bother with
817 // being a listener at its properties, its loaded state, and event the parent-relationship.
818 m_xParentComposer
.reset(
819 getCurrentSettingsComposer( xParent
, m_xContext
),
820 SharedQueryComposer::TakeOwnership
822 xParentColSupp
.set(m_xParentComposer
, css::uno::UNO_QUERY
);
825 xParentColSupp
.set(xParent
, css::uno::UNO_QUERY
);
827 // get the columns of the parent
828 if ( xParentColSupp
.is() )
829 _out_rxParentColumns
= xParentColSupp
->getColumns();
831 catch( const Exception
& )
833 SAL_WARN( "connectivity.commontools", "ParameterManager::getParentColumns: caught an exception!" );
835 return _out_rxParentColumns
.is();
839 void ParameterManager::addParameterListener( const Reference
< XDatabaseParameterListener
>& _rxListener
)
841 if ( _rxListener
.is() )
842 m_aParameterListeners
.addInterface( _rxListener
);
846 void ParameterManager::removeParameterListener( const Reference
< XDatabaseParameterListener
>& _rxListener
)
848 m_aParameterListeners
.removeInterface( _rxListener
);
852 void ParameterManager::resetParameterValues( )
854 OSL_PRECOND( isAlive(), "ParameterManager::resetParameterValues: not initialized, or already disposed!" );
858 if ( !m_nInnerCount
)
859 // no parameters at all
864 Reference
< XNameAccess
> xColumns
;
865 if ( !getColumns( xColumns
, false ) )
866 // already asserted in getColumns
869 Reference
< XNameAccess
> xParentColumns
;
870 if ( !getParentColumns( xParentColumns
, false ) )
873 // loop through all links pairs
874 const OUString
* pMasterFields
= m_aMasterFields
.getConstArray();
875 const OUString
* pDetailFields
= m_aDetailFields
.getConstArray();
877 Reference
< XPropertySet
> xMasterField
;
878 Reference
< XPropertySet
> xDetailField
;
881 const OUString
* pDetailFieldsEnd
= pDetailFields
+ m_aDetailFields
.getLength();
882 for ( ; pDetailFields
< pDetailFieldsEnd
; ++pDetailFields
, ++pMasterFields
)
884 if ( !xParentColumns
->hasByName( *pMasterFields
) )
886 // if this name is unknown in the parent columns, then we don't have a source
887 // for copying the value to the detail columns
888 SAL_WARN( "connectivity.commontools", "ParameterManager::resetParameterValues: this should have been stripped long before!" );
892 // for all inner parameters which are bound to the name as specified by the
893 // slave element of the link, propagate the value from the master column to this
895 ParameterInformation::const_iterator aParamInfo
= m_aParameterInformation
.find( *pDetailFields
);
896 if ( ( aParamInfo
== m_aParameterInformation
.end() )
897 || ( aParamInfo
->second
.aInnerIndexes
.empty() )
900 SAL_WARN( "connectivity.commontools", "ParameterManager::resetParameterValues: nothing known about this detail field!" );
904 xParentColumns
->getByName( *pMasterFields
) >>= xMasterField
;
905 if ( !xMasterField
.is() )
908 for ( ::std::vector
< sal_Int32
>::const_iterator aPosition
= aParamInfo
->second
.aInnerIndexes
.begin();
909 aPosition
!= aParamInfo
->second
.aInnerIndexes
.end();
913 Reference
< XPropertySet
> xInnerParameter
;
914 m_xInnerParamColumns
->getByIndex( *aPosition
) >>= xInnerParameter
;
915 if ( !xInnerParameter
.is() )
918 OUString sParamColumnRealName
;
919 xInnerParameter
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_REALNAME
) ) >>= sParamColumnRealName
;
920 if ( xColumns
->hasByName( sParamColumnRealName
) )
921 { // our own columns have a column which's name equals the real name of the param column
922 // -> transfer the value property
923 xColumns
->getByName( sParamColumnRealName
) >>= xDetailField
;
924 if ( xDetailField
.is() )
925 xDetailField
->setPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE
), xMasterField
->getPropertyValue( OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_VALUE
) ) );
930 catch( const Exception
& )
932 SAL_WARN( "connectivity.commontools", "ParameterManager::resetParameterValues: caught an exception!" );
938 void ParameterManager::externalParameterVisited( sal_Int32 _nIndex
)
940 if ( m_aParametersVisited
.size() < (size_t)_nIndex
)
942 m_aParametersVisited
.reserve( _nIndex
);
943 for ( sal_Int32 i
= m_aParametersVisited
.size(); i
< _nIndex
; ++i
)
944 m_aParametersVisited
.push_back( false );
946 m_aParametersVisited
[ _nIndex
- 1 ] = true;
949 #define VISIT_PARAMETER( method ) \
950 ::osl::MutexGuard aGuard( m_rMutex ); \
951 OSL_ENSURE( m_xInnerParamUpdate.is(), "ParameterManager::XParameters::setXXX: no XParameters access to the RowSet!" ); \
952 if ( !m_xInnerParamUpdate.is() ) \
954 m_xInnerParamUpdate->method; \
955 externalParameterVisited( _nIndex ) \
958 void ParameterManager::setNull( sal_Int32 _nIndex, sal_Int32 sqlType )
960 VISIT_PARAMETER( setNull( _nIndex
, sqlType
) );
964 void ParameterManager::setObjectNull( sal_Int32 _nIndex
, sal_Int32 sqlType
, const OUString
& typeName
)
966 VISIT_PARAMETER( setObjectNull( _nIndex
, sqlType
, typeName
) );
970 void ParameterManager::setBoolean( sal_Int32 _nIndex
, bool x
)
972 VISIT_PARAMETER( setBoolean( _nIndex
, x
) );
976 void ParameterManager::setByte( sal_Int32 _nIndex
, sal_Int8 x
)
978 VISIT_PARAMETER( setByte( _nIndex
, x
) );
982 void ParameterManager::setShort( sal_Int32 _nIndex
, sal_Int16 x
)
984 VISIT_PARAMETER( setShort( _nIndex
, x
) );
988 void ParameterManager::setInt( sal_Int32 _nIndex
, sal_Int32 x
)
990 VISIT_PARAMETER( setInt( _nIndex
, x
) );
994 void ParameterManager::setLong( sal_Int32 _nIndex
, sal_Int64 x
)
996 VISIT_PARAMETER( setLong( _nIndex
, x
) );
1000 void ParameterManager::setFloat( sal_Int32 _nIndex
, float x
)
1002 VISIT_PARAMETER( setFloat( _nIndex
, x
) );
1006 void ParameterManager::setDouble( sal_Int32 _nIndex
, double x
)
1008 VISIT_PARAMETER( setDouble( _nIndex
, x
) );
1012 void ParameterManager::setString( sal_Int32 _nIndex
, const OUString
& x
)
1014 VISIT_PARAMETER( setString( _nIndex
, x
) );
1018 void ParameterManager::setBytes( sal_Int32 _nIndex
, const ::com::sun::star::uno::Sequence
< sal_Int8
>& x
)
1020 VISIT_PARAMETER( setBytes( _nIndex
, x
) );
1024 void ParameterManager::setDate( sal_Int32 _nIndex
, const ::com::sun::star::util::Date
& x
)
1026 VISIT_PARAMETER( setDate( _nIndex
, x
) );
1030 void ParameterManager::setTime( sal_Int32 _nIndex
, const ::com::sun::star::util::Time
& x
)
1032 VISIT_PARAMETER( setTime( _nIndex
, x
) );
1036 void ParameterManager::setTimestamp( sal_Int32 _nIndex
, const ::com::sun::star::util::DateTime
& x
)
1038 VISIT_PARAMETER( setTimestamp( _nIndex
, x
) );
1042 void ParameterManager::setBinaryStream( sal_Int32 _nIndex
, const ::com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
>& x
, sal_Int32 length
)
1044 VISIT_PARAMETER( setBinaryStream( _nIndex
, x
, length
) );
1048 void ParameterManager::setCharacterStream( sal_Int32 _nIndex
, const ::com::sun::star::uno::Reference
< ::com::sun::star::io::XInputStream
>& x
, sal_Int32 length
)
1050 VISIT_PARAMETER( setCharacterStream( _nIndex
, x
, length
) );
1054 void ParameterManager::setObject( sal_Int32 _nIndex
, const ::com::sun::star::uno::Any
& x
)
1056 VISIT_PARAMETER( setObject( _nIndex
, x
) );
1060 void ParameterManager::setObjectWithInfo( sal_Int32 _nIndex
, const ::com::sun::star::uno::Any
& x
, sal_Int32 targetSqlType
, sal_Int32 scale
)
1062 VISIT_PARAMETER( setObjectWithInfo( _nIndex
, x
, targetSqlType
, scale
) );
1066 void ParameterManager::setRef( sal_Int32 _nIndex
, const ::com::sun::star::uno::Reference
< ::com::sun::star::sdbc::XRef
>& x
)
1068 VISIT_PARAMETER( setRef( _nIndex
, x
) );
1072 void ParameterManager::setBlob( sal_Int32 _nIndex
, const ::com::sun::star::uno::Reference
< ::com::sun::star::sdbc::XBlob
>& x
)
1074 VISIT_PARAMETER( setBlob( _nIndex
, x
) );
1078 void ParameterManager::setClob( sal_Int32 _nIndex
, const ::com::sun::star::uno::Reference
< ::com::sun::star::sdbc::XClob
>& x
)
1080 VISIT_PARAMETER( setClob( _nIndex
, x
) );
1084 void ParameterManager::setArray( sal_Int32 _nIndex
, const ::com::sun::star::uno::Reference
< ::com::sun::star::sdbc::XArray
>& x
)
1086 VISIT_PARAMETER( setArray( _nIndex
, x
) );
1090 void ParameterManager::clearParameters( )
1092 if ( m_xInnerParamUpdate
.is() )
1093 m_xInnerParamUpdate
->clearParameters( );
1096 void SAL_CALL
OParameterContinuation::setParameters( const Sequence
< PropertyValue
>& _rValues
) throw( RuntimeException
, std::exception
)
1098 m_aValues
= _rValues
;
1105 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */