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 <statement.hxx>
21 #include <resultset.hxx>
22 #include "dbastrings.hrc"
23 #include <com/sun/star/lang/DisposedException.hpp>
24 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
25 #include <comphelper/sequence.hxx>
26 #include <cppuhelper/queryinterface.hxx>
27 #include <cppuhelper/supportsservice.hxx>
28 #include <cppuhelper/typeprovider.hxx>
29 #include <comphelper/property.hxx>
30 #include <comphelper/types.hxx>
31 #include <tools/debug.hxx>
32 #include <tools/diagnose_ex.h>
33 #include <connectivity/dbexception.hxx>
35 using namespace ::com::sun::star::sdb
;
36 using namespace ::com::sun::star::sdbc
;
37 using namespace ::com::sun::star::beans
;
38 using namespace ::com::sun::star::uno
;
39 using namespace ::com::sun::star::lang
;
40 using namespace ::cppu
;
41 using namespace ::osl
;
42 using namespace dbaccess
;
43 using namespace dbtools
;
46 OStatementBase::OStatementBase(const Reference
< XConnection
> & _xConn
,
47 const Reference
< XInterface
> & _xStatement
)
48 :OSubComponent(m_aMutex
, _xConn
)
49 ,OPropertySetHelper(OComponentHelper::rBHelper
)
50 ,m_bUseBookmarks( false )
51 ,m_bEscapeProcessing( true )
54 OSL_ENSURE(_xStatement
.is() ,"Statement is NULL!");
55 m_xAggregateAsSet
.set(_xStatement
,UNO_QUERY
);
56 m_xAggregateAsCancellable
= Reference
< ::com::sun::star::util::XCancellable
> (m_xAggregateAsSet
, UNO_QUERY
);
59 OStatementBase::~OStatementBase()
63 // com::sun::star::lang::XTypeProvider
64 Sequence
< Type
> OStatementBase::getTypes() throw (RuntimeException
, std::exception
)
66 OTypeCollection
aTypes(cppu::UnoType
<XPropertySet
>::get(),
67 cppu::UnoType
<XWarningsSupplier
>::get(),
68 cppu::UnoType
<XCloseable
>::get(),
69 cppu::UnoType
<XMultipleResults
>::get(),
70 cppu::UnoType
<com::sun::star::util::XCancellable
>::get(),
71 OSubComponent::getTypes() );
72 Reference
< XGeneratedResultSet
> xGRes(m_xAggregateAsSet
, UNO_QUERY
);
74 aTypes
= OTypeCollection(cppu::UnoType
<XGeneratedResultSet
>::get(),aTypes
.getTypes());
75 Reference
< XPreparedBatchExecution
> xPreparedBatchExecution(m_xAggregateAsSet
, UNO_QUERY
);
76 if ( xPreparedBatchExecution
.is() )
77 aTypes
= OTypeCollection(cppu::UnoType
<XPreparedBatchExecution
>::get(),aTypes
.getTypes());
79 return aTypes
.getTypes();
82 // com::sun::star::uno::XInterface
83 Any
OStatementBase::queryInterface( const Type
& rType
) throw (RuntimeException
, std::exception
)
85 Any aIface
= OSubComponent::queryInterface( rType
);
86 if (!aIface
.hasValue())
88 aIface
= ::cppu::queryInterface(
90 static_cast< XPropertySet
* >( this ),
91 static_cast< XWarningsSupplier
* >( this ),
92 static_cast< XCloseable
* >( this ),
93 static_cast< XMultipleResults
* >( this ),
94 static_cast< ::com::sun::star::util::XCancellable
* >( this ));
95 if ( !aIface
.hasValue() )
97 Reference
< XGeneratedResultSet
> xGRes(m_xAggregateAsSet
, UNO_QUERY
);
98 if ( cppu::UnoType
<XGeneratedResultSet
>::get()== rType
&& xGRes
.is() )
99 aIface
= ::cppu::queryInterface(rType
,static_cast< XGeneratedResultSet
* >( this ));
101 if ( !aIface
.hasValue() )
103 Reference
< XPreparedBatchExecution
> xGRes(m_xAggregateAsSet
, UNO_QUERY
);
104 if ( cppu::UnoType
<XPreparedBatchExecution
>::get()== rType
&& xGRes
.is() )
105 aIface
= ::cppu::queryInterface(rType
,static_cast< XPreparedBatchExecution
* >( this ));
111 void OStatementBase::acquire() throw ()
113 OSubComponent::acquire();
116 void OStatementBase::release() throw ()
118 OSubComponent::release();
121 void OStatementBase::disposeResultSet()
123 // free the cursor if alive
124 Reference
< XComponent
> xComp(m_aResultSet
.get(), UNO_QUERY
);
131 void OStatementBase::disposing()
133 OPropertySetHelper::disposing();
135 MutexGuard
aGuard(m_aMutex
);
137 // free pending results
140 // free the original statement
142 MutexGuard
aCancelGuard(m_aCancelMutex
);
143 m_xAggregateAsCancellable
= NULL
;
146 if ( m_xAggregateAsSet
.is() )
150 Reference
< XCloseable
> (m_xAggregateAsSet
, UNO_QUERY
)->close();
152 catch(RuntimeException
& )
153 {// don't care for anymore
156 m_xAggregateAsSet
= NULL
;
158 // free the parent at last
159 OSubComponent::disposing();
163 void OStatementBase::close() throw( SQLException
, RuntimeException
, std::exception
)
166 MutexGuard
aGuard( m_aMutex
);
167 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
172 // OPropertySetHelper
173 Reference
< XPropertySetInfo
> OStatementBase::getPropertySetInfo() throw (RuntimeException
, std::exception
)
175 return createPropertySetInfo( getInfoHelper() ) ;
178 // comphelper::OPropertyArrayUsageHelper
179 ::cppu::IPropertyArrayHelper
* OStatementBase::createArrayHelper( ) const
181 BEGIN_PROPERTY_HELPER(10)
182 DECL_PROP0(CURSORNAME
, OUString
);
183 DECL_PROP0_BOOL(ESCAPE_PROCESSING
);
184 DECL_PROP0(FETCHDIRECTION
, sal_Int32
);
185 DECL_PROP0(FETCHSIZE
, sal_Int32
);
186 DECL_PROP0(MAXFIELDSIZE
, sal_Int32
);
187 DECL_PROP0(MAXROWS
, sal_Int32
);
188 DECL_PROP0(QUERYTIMEOUT
, sal_Int32
);
189 DECL_PROP0(RESULTSETCONCURRENCY
, sal_Int32
);
190 DECL_PROP0(RESULTSETTYPE
, sal_Int32
);
191 DECL_PROP0_BOOL(USEBOOKMARKS
);
192 END_PROPERTY_HELPER();
195 // cppu::OPropertySetHelper
196 ::cppu::IPropertyArrayHelper
& OStatementBase::getInfoHelper()
198 return *getArrayHelper();
201 sal_Bool
OStatementBase::convertFastPropertyValue( Any
& rConvertedValue
, Any
& rOldValue
, sal_Int32 nHandle
, const Any
& rValue
) throw( IllegalArgumentException
)
203 bool bModified(false);
206 case PROPERTY_ID_USEBOOKMARKS
:
207 bModified
= ::comphelper::tryPropertyValue( rConvertedValue
, rOldValue
, rValue
, m_bUseBookmarks
);
210 case PROPERTY_ID_ESCAPE_PROCESSING
:
211 bModified
= ::comphelper::tryPropertyValue( rConvertedValue
, rOldValue
, rValue
, m_bEscapeProcessing
);
215 if ( m_xAggregateAsSet
.is() )
217 // get the property name
219 getInfoHelper().fillPropertyMembersByHandle( &sPropName
, NULL
, nHandle
);
222 Any aCurrentValue
= m_xAggregateAsSet
->getPropertyValue( sPropName
);
223 if ( aCurrentValue
!= rValue
)
225 rOldValue
= aCurrentValue
;
226 rConvertedValue
= rValue
;
235 void OStatementBase::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle
, const Any
& rValue
) throw (Exception
, std::exception
)
239 case PROPERTY_ID_USEBOOKMARKS
:
241 m_bUseBookmarks
= ::comphelper::getBOOL( rValue
);
242 if ( m_xAggregateAsSet
.is() && m_xAggregateAsSet
->getPropertySetInfo()->hasPropertyByName( PROPERTY_USEBOOKMARKS
) )
243 m_xAggregateAsSet
->setPropertyValue( PROPERTY_USEBOOKMARKS
, rValue
);
247 case PROPERTY_ID_ESCAPE_PROCESSING
:
248 m_bEscapeProcessing
= ::comphelper::getBOOL( rValue
);
249 if ( m_xAggregateAsSet
.is() )
250 m_xAggregateAsSet
->setPropertyValue( PROPERTY_ESCAPE_PROCESSING
, rValue
);
254 if ( m_xAggregateAsSet
.is() )
257 getInfoHelper().fillPropertyMembersByHandle( &sPropName
, NULL
, nHandle
);
258 m_xAggregateAsSet
->setPropertyValue( sPropName
, rValue
);
264 void OStatementBase::getFastPropertyValue( Any
& rValue
, sal_Int32 nHandle
) const
268 case PROPERTY_ID_USEBOOKMARKS
:
269 rValue
<<= m_bUseBookmarks
;
272 case PROPERTY_ID_ESCAPE_PROCESSING
:
273 // don't rely on our aggregate - if it implements this wrong, and always returns
274 // TRUE here, then we would loop in impl_doEscapeProcessing_nothrow
275 rValue
<<= m_bEscapeProcessing
;
279 if ( m_xAggregateAsSet
.is() )
282 const_cast< OStatementBase
* >( this )->getInfoHelper().fillPropertyMembersByHandle( &sPropName
, NULL
, nHandle
);
283 rValue
= m_xAggregateAsSet
->getPropertyValue( sPropName
);
290 Any
OStatementBase::getWarnings() throw( SQLException
, RuntimeException
, std::exception
)
292 MutexGuard
aGuard(m_aMutex
);
293 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
295 return Reference
< XWarningsSupplier
>(m_xAggregateAsSet
, UNO_QUERY
)->getWarnings();
298 void OStatementBase::clearWarnings() throw( SQLException
, RuntimeException
, std::exception
)
300 MutexGuard
aGuard(m_aMutex
);
301 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
303 Reference
< XWarningsSupplier
>(m_xAggregateAsSet
, UNO_QUERY
)->clearWarnings();
306 // ::com::sun::star::util::XCancellable
307 void OStatementBase::cancel() throw( RuntimeException
, std::exception
)
309 // no blocking as cancel is typically called from a different thread
310 ClearableMutexGuard
aCancelGuard(m_aCancelMutex
);
311 if (m_xAggregateAsCancellable
.is())
312 m_xAggregateAsCancellable
->cancel();
317 Reference
< XResultSet
> SAL_CALL
OStatementBase::getResultSet( ) throw(SQLException
, RuntimeException
, std::exception
)
319 MutexGuard
aGuard(m_aMutex
);
320 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
322 // first check the meta data
323 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY
)->getMetaData();
324 if (!xMeta
.is() && !xMeta
->supportsMultipleResultSets())
325 throwFunctionSequenceException(*this);
327 return Reference
< XMultipleResults
>(m_xAggregateAsSet
, UNO_QUERY
)->getResultSet();
330 sal_Int32 SAL_CALL
OStatementBase::getUpdateCount( ) throw(SQLException
, RuntimeException
, std::exception
)
332 MutexGuard
aGuard(m_aMutex
);
333 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
335 // first check the meta data
336 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY
)->getMetaData();
337 if (!xMeta
.is() && !xMeta
->supportsMultipleResultSets())
338 throwFunctionSequenceException(*this);
340 return Reference
< XMultipleResults
>(m_xAggregateAsSet
, UNO_QUERY
)->getUpdateCount();
343 sal_Bool SAL_CALL
OStatementBase::getMoreResults( ) throw(SQLException
, RuntimeException
, std::exception
)
345 MutexGuard
aGuard(m_aMutex
);
346 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
348 // first check the meta data
349 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY
)->getMetaData();
350 if (!xMeta
.is() && !xMeta
->supportsMultipleResultSets())
351 throwFunctionSequenceException(*this);
353 // free the previous results
356 return Reference
< XMultipleResults
>(m_xAggregateAsSet
, UNO_QUERY
)->getMoreResults();
359 // XPreparedBatchExecution
360 void SAL_CALL
OStatementBase::addBatch( ) throw(SQLException
, RuntimeException
, std::exception
)
362 MutexGuard
aGuard(m_aMutex
);
363 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
365 // first check the meta data
366 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY
)->getMetaData();
367 if (!xMeta
.is() && !xMeta
->supportsBatchUpdates())
368 throwFunctionSequenceException(*this);
370 Reference
< XPreparedBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY
)->addBatch();
373 void SAL_CALL
OStatementBase::clearBatch( ) throw(SQLException
, RuntimeException
, std::exception
)
375 MutexGuard
aGuard(m_aMutex
);
376 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
378 // first check the meta data
379 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY
)->getMetaData();
380 if (!xMeta
.is() && !xMeta
->supportsBatchUpdates())
381 throwFunctionSequenceException(*this);
383 Reference
< XPreparedBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY
)->clearBatch();
386 Sequence
< sal_Int32
> SAL_CALL
OStatementBase::executeBatch( ) throw(SQLException
, RuntimeException
, std::exception
)
388 MutexGuard
aGuard(m_aMutex
);
389 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
391 // first check the meta data
392 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY
)->getMetaData();
393 if (!xMeta
.is() && !xMeta
->supportsBatchUpdates())
394 throwFunctionSequenceException(*this);
396 // free the previous results
399 return Reference
< XPreparedBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY
)->executeBatch();
402 Reference
< XResultSet
> SAL_CALL
OStatementBase::getGeneratedValues( ) throw (SQLException
, RuntimeException
, std::exception
)
404 MutexGuard
aGuard(m_aMutex
);
405 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
406 Reference
< XGeneratedResultSet
> xGRes(m_xAggregateAsSet
, UNO_QUERY
);
409 return xGRes
->getGeneratedValues( );
410 return Reference
< XResultSet
>();
416 OStatement::OStatement( const Reference
< XConnection
>& _xConn
, const Reference
< XInterface
> & _xStatement
)
417 :OStatementBase( _xConn
, _xStatement
)
418 ,m_bAttemptedComposerCreation( false )
420 m_xAggregateStatement
.set( _xStatement
, UNO_QUERY_THROW
);
423 IMPLEMENT_FORWARD_XINTERFACE2( OStatement
, OStatementBase
, OStatement_IFACE
);
424 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OStatement
, OStatementBase
, OStatement_IFACE
);
427 OUString
OStatement::getImplementationName( ) throw(RuntimeException
, std::exception
)
429 return OUString("com.sun.star.sdb.OStatement");
432 sal_Bool
OStatement::supportsService( const OUString
& _rServiceName
) throw (RuntimeException
, std::exception
)
434 return cppu::supportsService(this, _rServiceName
);
437 Sequence
< OUString
> OStatement::getSupportedServiceNames( ) throw (RuntimeException
, std::exception
)
439 Sequence
< OUString
> aSNS( 1 );
440 aSNS
.getArray()[0] = SERVICE_SDBC_STATEMENT
;
445 Reference
< XResultSet
> OStatement::executeQuery( const OUString
& _rSQL
) throw( SQLException
, RuntimeException
, std::exception
)
447 MutexGuard
aGuard(m_aMutex
);
448 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
451 Reference
< XResultSet
> xResultSet
;
453 OUString
sSQL( impl_doEscapeProcessing_nothrow( _rSQL
) );
455 Reference
< XResultSet
> xInnerResultSet
= m_xAggregateStatement
->executeQuery( sSQL
);
456 Reference
< XConnection
> xConnection( m_xParent
, UNO_QUERY_THROW
);
458 if ( xInnerResultSet
.is() )
460 Reference
< XDatabaseMetaData
> xMeta
= xConnection
->getMetaData();
461 bool bCaseSensitive
= xMeta
.is() && xMeta
->supportsMixedCaseQuotedIdentifiers();
462 xResultSet
= new OResultSet( xInnerResultSet
, *this, bCaseSensitive
);
464 // keep the resultset weak
465 m_aResultSet
= xResultSet
;
471 sal_Int32
OStatement::executeUpdate( const OUString
& _rSQL
) throw( SQLException
, RuntimeException
, std::exception
)
473 MutexGuard
aGuard(m_aMutex
);
474 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
478 OUString
sSQL( impl_doEscapeProcessing_nothrow( _rSQL
) );
479 return m_xAggregateStatement
->executeUpdate( sSQL
);
482 sal_Bool
OStatement::execute( const OUString
& _rSQL
) throw( SQLException
, RuntimeException
, std::exception
)
484 MutexGuard
aGuard(m_aMutex
);
485 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
489 OUString
sSQL( impl_doEscapeProcessing_nothrow( _rSQL
) );
490 return m_xAggregateStatement
->execute( sSQL
);
493 void OStatement::addBatch( const OUString
& _rSQL
) throw( SQLException
, RuntimeException
, std::exception
)
495 MutexGuard
aGuard(m_aMutex
);
496 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
498 // first check the meta data
499 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY
)->getMetaData();
500 if (!xMeta
.is() && !xMeta
->supportsBatchUpdates())
501 throwFunctionSequenceException(*this);
503 OUString
sSQL( impl_doEscapeProcessing_nothrow( _rSQL
) );
504 Reference
< XBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY
)->addBatch( sSQL
);
507 void OStatement::clearBatch( ) throw( SQLException
, RuntimeException
, std::exception
)
509 MutexGuard
aGuard(m_aMutex
);
510 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
511 // first check the meta data
512 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY
)->getMetaData();
513 if (!xMeta
.is() && !xMeta
->supportsBatchUpdates())
514 throwFunctionSequenceException(*this);
516 Reference
< XBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY
)->clearBatch();
519 Sequence
< sal_Int32
> OStatement::executeBatch( ) throw( SQLException
, RuntimeException
, std::exception
)
521 MutexGuard
aGuard(m_aMutex
);
522 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
523 // first check the meta data
524 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY
)->getMetaData();
525 if (!xMeta
.is() && !xMeta
->supportsBatchUpdates())
526 throwFunctionSequenceException(*this);
527 return Reference
< XBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY
)->executeBatch( );
531 Reference
< XConnection
> OStatement::getConnection() throw( SQLException
, RuntimeException
, std::exception
)
533 return Reference
< XConnection
>( m_xParent
, UNO_QUERY
);
536 void SAL_CALL
OStatement::disposing()
538 OStatementBase::disposing();
540 m_xAggregateStatement
.clear();
543 OUString
OStatement::impl_doEscapeProcessing_nothrow( const OUString
& _rSQL
) const
545 if ( !m_bEscapeProcessing
)
549 if ( !impl_ensureComposer_nothrow() )
552 bool bParseable
= false;
553 try { m_xComposer
->setQuery( _rSQL
); bParseable
= true; }
554 catch( const SQLException
& ) { }
557 // if we cannot parse it, silently accept this. The driver is probably able to cope with it then
560 OUString sLowLevelSQL
= m_xComposer
->getQueryWithSubstitution();
563 catch( const Exception
& )
565 DBG_UNHANDLED_EXCEPTION();
571 bool OStatement::impl_ensureComposer_nothrow() const
573 if ( m_bAttemptedComposerCreation
)
574 return m_xComposer
.is();
576 const_cast< OStatement
* >( this )->m_bAttemptedComposerCreation
= true;
579 Reference
< XMultiServiceFactory
> xFactory( m_xParent
, UNO_QUERY_THROW
);
580 const_cast< OStatement
* >( this )->m_xComposer
.set( xFactory
->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
), UNO_QUERY_THROW
);
582 catch( const Exception
& )
584 DBG_UNHANDLED_EXCEPTION();
587 return m_xComposer
.is();
590 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */