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 <stringconstants.hxx>
23 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
24 #include <com/sun/star/sdbc/SQLException.hpp>
25 #include <cppuhelper/queryinterface.hxx>
26 #include <cppuhelper/supportsservice.hxx>
27 #include <cppuhelper/typeprovider.hxx>
28 #include <comphelper/property.hxx>
29 #include <comphelper/types.hxx>
30 #include <tools/diagnose_ex.h>
31 #include <connectivity/dbexception.hxx>
33 using namespace ::com::sun::star::sdb
;
34 using namespace ::com::sun::star::sdbc
;
35 using namespace ::com::sun::star::beans
;
36 using namespace ::com::sun::star::uno
;
37 using namespace ::com::sun::star::lang
;
38 using namespace ::cppu
;
39 using namespace ::osl
;
40 using namespace dbaccess
;
41 using namespace dbtools
;
44 OStatementBase::OStatementBase(const Reference
< XConnection
> & _xConn
,
45 const Reference
< XInterface
> & _xStatement
)
46 :OSubComponent(m_aMutex
, _xConn
)
47 ,OPropertySetHelper(OComponentHelper::rBHelper
)
48 ,m_bUseBookmarks( false )
49 ,m_bEscapeProcessing( true )
52 OSL_ENSURE(_xStatement
.is() ,"Statement is NULL!");
53 m_xAggregateAsSet
.set(_xStatement
,UNO_QUERY
);
54 m_xAggregateAsCancellable
.set(m_xAggregateAsSet
, UNO_QUERY
);
57 OStatementBase::~OStatementBase()
61 // css::lang::XTypeProvider
62 Sequence
< Type
> OStatementBase::getTypes()
64 OTypeCollection
aTypes(cppu::UnoType
<XPropertySet
>::get(),
65 cppu::UnoType
<XWarningsSupplier
>::get(),
66 cppu::UnoType
<XCloseable
>::get(),
67 cppu::UnoType
<XMultipleResults
>::get(),
68 cppu::UnoType
<css::util::XCancellable
>::get(),
69 OSubComponent::getTypes() );
70 Reference
< XGeneratedResultSet
> xGRes(m_xAggregateAsSet
, UNO_QUERY
);
72 aTypes
= OTypeCollection(cppu::UnoType
<XGeneratedResultSet
>::get(),aTypes
.getTypes());
73 Reference
< XPreparedBatchExecution
> xPreparedBatchExecution(m_xAggregateAsSet
, UNO_QUERY
);
74 if ( xPreparedBatchExecution
.is() )
75 aTypes
= OTypeCollection(cppu::UnoType
<XPreparedBatchExecution
>::get(),aTypes
.getTypes());
77 return aTypes
.getTypes();
80 // css::uno::XInterface
81 Any
OStatementBase::queryInterface( const Type
& rType
)
83 Any aIface
= OSubComponent::queryInterface( rType
);
84 if (!aIface
.hasValue())
86 aIface
= ::cppu::queryInterface(
88 static_cast< XPropertySet
* >( this ),
89 static_cast< XWarningsSupplier
* >( this ),
90 static_cast< XCloseable
* >( this ),
91 static_cast< XMultipleResults
* >( this ),
92 static_cast< css::util::XCancellable
* >( this ));
93 if ( !aIface
.hasValue() )
95 Reference
< XGeneratedResultSet
> xGRes(m_xAggregateAsSet
, UNO_QUERY
);
96 if ( cppu::UnoType
<XGeneratedResultSet
>::get()== rType
&& xGRes
.is() )
97 aIface
= ::cppu::queryInterface(rType
,static_cast< XGeneratedResultSet
* >( this ));
99 if ( !aIface
.hasValue() )
101 Reference
< XPreparedBatchExecution
> xGRes(m_xAggregateAsSet
, UNO_QUERY
);
102 if ( cppu::UnoType
<XPreparedBatchExecution
>::get()== rType
&& xGRes
.is() )
103 aIface
= ::cppu::queryInterface(rType
,static_cast< XPreparedBatchExecution
* >( this ));
109 void OStatementBase::acquire() throw ()
111 OSubComponent::acquire();
114 void OStatementBase::release() throw ()
116 OSubComponent::release();
119 void OStatementBase::disposeResultSet()
121 // free the cursor if alive
122 Reference
< XComponent
> xComp(m_aResultSet
.get(), UNO_QUERY
);
125 m_aResultSet
= nullptr;
129 void OStatementBase::disposing()
131 OPropertySetHelper::disposing();
133 MutexGuard
aGuard(m_aMutex
);
135 // free pending results
138 // free the original statement
140 MutexGuard
aCancelGuard(m_aCancelMutex
);
141 m_xAggregateAsCancellable
= nullptr;
144 if ( m_xAggregateAsSet
.is() )
148 Reference
< XCloseable
> (m_xAggregateAsSet
, UNO_QUERY_THROW
)->close();
150 catch(RuntimeException
& )
151 {// don't care for anymore
154 m_xAggregateAsSet
= nullptr;
156 // free the parent at last
157 OSubComponent::disposing();
161 void OStatementBase::close()
164 MutexGuard
aGuard( m_aMutex
);
165 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
170 // OPropertySetHelper
171 Reference
< XPropertySetInfo
> OStatementBase::getPropertySetInfo()
173 return createPropertySetInfo( getInfoHelper() ) ;
176 // comphelper::OPropertyArrayUsageHelper
177 ::cppu::IPropertyArrayHelper
* OStatementBase::createArrayHelper( ) const
179 BEGIN_PROPERTY_HELPER(10)
180 DECL_PROP0(CURSORNAME
, OUString
);
181 DECL_PROP0_BOOL(ESCAPE_PROCESSING
);
182 DECL_PROP0(FETCHDIRECTION
, sal_Int32
);
183 DECL_PROP0(FETCHSIZE
, sal_Int32
);
184 DECL_PROP0(MAXFIELDSIZE
, sal_Int32
);
185 DECL_PROP0(MAXROWS
, sal_Int32
);
186 DECL_PROP0(QUERYTIMEOUT
, sal_Int32
);
187 DECL_PROP0(RESULTSETCONCURRENCY
, sal_Int32
);
188 DECL_PROP0(RESULTSETTYPE
, sal_Int32
);
189 DECL_PROP0_BOOL(USEBOOKMARKS
);
190 END_PROPERTY_HELPER();
193 // cppu::OPropertySetHelper
194 ::cppu::IPropertyArrayHelper
& OStatementBase::getInfoHelper()
196 return *getArrayHelper();
199 sal_Bool
OStatementBase::convertFastPropertyValue(Any
& rConvertedValue
, Any
& rOldValue
, sal_Int32 nHandle
, const Any
& rValue
)
201 bool bModified(false);
204 case PROPERTY_ID_USEBOOKMARKS
:
205 bModified
= ::comphelper::tryPropertyValue( rConvertedValue
, rOldValue
, rValue
, m_bUseBookmarks
);
208 case PROPERTY_ID_ESCAPE_PROCESSING
:
209 bModified
= ::comphelper::tryPropertyValue( rConvertedValue
, rOldValue
, rValue
, m_bEscapeProcessing
);
213 if ( m_xAggregateAsSet
.is() )
215 // get the property name
217 getInfoHelper().fillPropertyMembersByHandle( &sPropName
, nullptr, nHandle
);
220 Any aCurrentValue
= m_xAggregateAsSet
->getPropertyValue( sPropName
);
221 if ( aCurrentValue
!= rValue
)
223 rOldValue
= aCurrentValue
;
224 rConvertedValue
= rValue
;
233 void OStatementBase::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle
, const Any
& rValue
)
237 case PROPERTY_ID_USEBOOKMARKS
:
239 m_bUseBookmarks
= ::comphelper::getBOOL( rValue
);
240 if ( m_xAggregateAsSet
.is() && m_xAggregateAsSet
->getPropertySetInfo()->hasPropertyByName( PROPERTY_USEBOOKMARKS
) )
241 m_xAggregateAsSet
->setPropertyValue( PROPERTY_USEBOOKMARKS
, rValue
);
245 case PROPERTY_ID_ESCAPE_PROCESSING
:
246 m_bEscapeProcessing
= ::comphelper::getBOOL( rValue
);
247 if ( m_xAggregateAsSet
.is() )
248 m_xAggregateAsSet
->setPropertyValue( PROPERTY_ESCAPE_PROCESSING
, rValue
);
252 if ( m_xAggregateAsSet
.is() )
255 getInfoHelper().fillPropertyMembersByHandle( &sPropName
, nullptr, nHandle
);
256 m_xAggregateAsSet
->setPropertyValue( sPropName
, rValue
);
262 void OStatementBase::getFastPropertyValue( Any
& rValue
, sal_Int32 nHandle
) const
266 case PROPERTY_ID_USEBOOKMARKS
:
267 rValue
<<= m_bUseBookmarks
;
270 case PROPERTY_ID_ESCAPE_PROCESSING
:
271 // don't rely on our aggregate - if it implements this wrong, and always returns
272 // TRUE here, then we would loop in impl_doEscapeProcessing_nothrow
273 rValue
<<= m_bEscapeProcessing
;
277 if ( m_xAggregateAsSet
.is() )
280 const_cast< OStatementBase
* >( this )->getInfoHelper().fillPropertyMembersByHandle( &sPropName
, nullptr, nHandle
);
281 rValue
= m_xAggregateAsSet
->getPropertyValue( sPropName
);
288 Any
OStatementBase::getWarnings()
290 MutexGuard
aGuard(m_aMutex
);
291 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
293 return Reference
< XWarningsSupplier
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->getWarnings();
296 void OStatementBase::clearWarnings()
298 MutexGuard
aGuard(m_aMutex
);
299 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
301 Reference
< XWarningsSupplier
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->clearWarnings();
304 // css::util::XCancellable
305 void OStatementBase::cancel()
307 // no blocking as cancel is typically called from a different thread
308 MutexGuard
aCancelGuard(m_aCancelMutex
);
309 if (m_xAggregateAsCancellable
.is())
310 m_xAggregateAsCancellable
->cancel();
315 Reference
< XResultSet
> SAL_CALL
OStatementBase::getResultSet( )
317 MutexGuard
aGuard(m_aMutex
);
318 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
320 // first check the meta data
321 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
322 if (!xMeta
.is() || !xMeta
->supportsMultipleResultSets())
323 throwFunctionSequenceException(*this);
325 return Reference
< XMultipleResults
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->getResultSet();
328 sal_Int32 SAL_CALL
OStatementBase::getUpdateCount( )
330 MutexGuard
aGuard(m_aMutex
);
331 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
333 // first check the meta data
334 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
335 if (!xMeta
.is() || !xMeta
->supportsMultipleResultSets())
336 throwFunctionSequenceException(*this);
338 return Reference
< XMultipleResults
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->getUpdateCount();
341 sal_Bool SAL_CALL
OStatementBase::getMoreResults( )
343 MutexGuard
aGuard(m_aMutex
);
344 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
346 // first check the meta data
347 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
348 if (!xMeta
.is() || !xMeta
->supportsMultipleResultSets())
349 throwFunctionSequenceException(*this);
351 // free the previous results
354 return Reference
< XMultipleResults
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->getMoreResults();
357 // XPreparedBatchExecution
358 void SAL_CALL
OStatementBase::addBatch( )
360 MutexGuard
aGuard(m_aMutex
);
361 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
363 // first check the meta data
364 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
365 if (!xMeta
.is() || !xMeta
->supportsBatchUpdates())
366 throwFunctionSequenceException(*this);
368 Reference
< XPreparedBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->addBatch();
371 void SAL_CALL
OStatementBase::clearBatch( )
373 MutexGuard
aGuard(m_aMutex
);
374 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
376 // first check the meta data
377 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
378 if (!xMeta
.is() || !xMeta
->supportsBatchUpdates())
379 throwFunctionSequenceException(*this);
381 Reference
< XPreparedBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->clearBatch();
384 Sequence
< sal_Int32
> SAL_CALL
OStatementBase::executeBatch( )
386 MutexGuard
aGuard(m_aMutex
);
387 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
389 // first check the meta data
390 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
391 if (!xMeta
.is() || !xMeta
->supportsBatchUpdates())
392 throwFunctionSequenceException(*this);
394 // free the previous results
397 return Reference
< XPreparedBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->executeBatch();
400 Reference
< XResultSet
> SAL_CALL
OStatementBase::getGeneratedValues( )
402 MutexGuard
aGuard(m_aMutex
);
403 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
404 Reference
< XGeneratedResultSet
> xGRes(m_xAggregateAsSet
, UNO_QUERY
);
407 return xGRes
->getGeneratedValues( );
408 return Reference
< XResultSet
>();
414 OStatement::OStatement( const Reference
< XConnection
>& _xConn
, const Reference
< XInterface
> & _xStatement
)
415 :OStatementBase( _xConn
, _xStatement
)
416 ,m_bAttemptedComposerCreation( false )
418 m_xAggregateStatement
.set( _xStatement
, UNO_QUERY_THROW
);
421 IMPLEMENT_FORWARD_XINTERFACE2( OStatement
, OStatementBase
, OStatement_IFACE
);
422 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OStatement
, OStatementBase
, OStatement_IFACE
);
425 OUString
OStatement::getImplementationName( )
427 return "com.sun.star.sdb.OStatement";
430 sal_Bool
OStatement::supportsService( const OUString
& _rServiceName
)
432 return cppu::supportsService(this, _rServiceName
);
435 Sequence
< OUString
> OStatement::getSupportedServiceNames( )
437 return { SERVICE_SDBC_STATEMENT
};
441 Reference
< XResultSet
> OStatement::executeQuery( const OUString
& _rSQL
)
443 MutexGuard
aGuard(m_aMutex
);
444 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
447 Reference
< XResultSet
> xResultSet
;
449 OUString
sSQL( impl_doEscapeProcessing_nothrow( _rSQL
) );
451 Reference
< XResultSet
> xInnerResultSet
= m_xAggregateStatement
->executeQuery( sSQL
);
452 Reference
< XConnection
> xConnection( m_xParent
, UNO_QUERY_THROW
);
454 if ( xInnerResultSet
.is() )
456 Reference
< XDatabaseMetaData
> xMeta
= xConnection
->getMetaData();
457 bool bCaseSensitive
= xMeta
.is() && xMeta
->supportsMixedCaseQuotedIdentifiers();
458 xResultSet
= new OResultSet( xInnerResultSet
, *this, bCaseSensitive
);
460 // keep the resultset weak
461 m_aResultSet
= xResultSet
;
467 sal_Int32
OStatement::executeUpdate( const OUString
& _rSQL
)
469 MutexGuard
aGuard(m_aMutex
);
470 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
474 OUString
sSQL( impl_doEscapeProcessing_nothrow( _rSQL
) );
475 return m_xAggregateStatement
->executeUpdate( sSQL
);
478 sal_Bool
OStatement::execute( const OUString
& _rSQL
)
480 MutexGuard
aGuard(m_aMutex
);
481 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
485 OUString
sSQL( impl_doEscapeProcessing_nothrow( _rSQL
) );
486 return m_xAggregateStatement
->execute( sSQL
);
489 void OStatement::addBatch( const OUString
& _rSQL
)
491 MutexGuard
aGuard(m_aMutex
);
492 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
494 // first check the meta data
495 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
496 if (!xMeta
.is() || !xMeta
->supportsBatchUpdates())
497 throwFunctionSequenceException(*this);
499 OUString
sSQL( impl_doEscapeProcessing_nothrow( _rSQL
) );
500 Reference
< XBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->addBatch( sSQL
);
503 void OStatement::clearBatch( )
505 MutexGuard
aGuard(m_aMutex
);
506 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
507 // first check the meta data
508 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
509 if (!xMeta
.is() || !xMeta
->supportsBatchUpdates())
510 throwFunctionSequenceException(*this);
512 Reference
< XBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->clearBatch();
515 Sequence
< sal_Int32
> OStatement::executeBatch( )
517 MutexGuard
aGuard(m_aMutex
);
518 ::connectivity::checkDisposed(OComponentHelper::rBHelper
.bDisposed
);
519 // first check the meta data
520 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
521 if (!xMeta
.is() || !xMeta
->supportsBatchUpdates())
522 throwFunctionSequenceException(*this);
523 return Reference
< XBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->executeBatch( );
527 Reference
< XConnection
> OStatement::getConnection()
529 return Reference
< XConnection
>( m_xParent
, UNO_QUERY
);
532 void SAL_CALL
OStatement::disposing()
534 OStatementBase::disposing();
536 m_xAggregateStatement
.clear();
539 OUString
OStatement::impl_doEscapeProcessing_nothrow( const OUString
& _rSQL
) const
541 if ( !m_bEscapeProcessing
)
545 if ( !impl_ensureComposer_nothrow() )
548 bool bParseable
= false;
549 try { m_xComposer
->setQuery( _rSQL
); bParseable
= true; }
550 catch( const SQLException
& ) { }
553 // if we cannot parse it, silently accept this. The driver is probably able to cope with it then
556 OUString sLowLevelSQL
= m_xComposer
->getQueryWithSubstitution();
559 catch( const Exception
& )
561 DBG_UNHANDLED_EXCEPTION("dbaccess");
567 bool OStatement::impl_ensureComposer_nothrow() const
569 if ( m_bAttemptedComposerCreation
)
570 return m_xComposer
.is();
572 const_cast< OStatement
* >( this )->m_bAttemptedComposerCreation
= true;
575 Reference
< XMultiServiceFactory
> xFactory( m_xParent
, UNO_QUERY_THROW
);
576 const_cast< OStatement
* >( this )->m_xComposer
.set( xFactory
->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
), UNO_QUERY_THROW
);
578 catch( const Exception
& )
580 DBG_UNHANDLED_EXCEPTION("dbaccess");
583 return m_xComposer
.is();
586 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */