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 <strings.hxx>
24 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
25 #include <com/sun/star/sdbc/XDatabaseMetaData.hpp>
26 #include <com/sun/star/sdbc/SQLException.hpp>
27 #include <cppuhelper/queryinterface.hxx>
28 #include <cppuhelper/supportsservice.hxx>
29 #include <cppuhelper/typeprovider.hxx>
30 #include <comphelper/property.hxx>
31 #include <comphelper/types.hxx>
32 #include <comphelper/diagnose_ex.hxx>
33 #include <connectivity/dbexception.hxx>
34 #include <connection.hxx>
36 using namespace ::com::sun::star::sdb
;
37 using namespace ::com::sun::star::sdbc
;
38 using namespace ::com::sun::star::beans
;
39 using namespace ::com::sun::star::uno
;
40 using namespace ::com::sun::star::lang
;
41 using namespace ::cppu
;
42 using namespace ::osl
;
43 using namespace dbaccess
;
44 using namespace dbtools
;
47 OStatementBase::OStatementBase(const rtl::Reference
< OConnection
> & _xConn
,
48 const Reference
< XInterface
> & _xStatement
)
49 :WeakComponentImplHelper(m_aMutex
)
50 ,OPropertySetHelper(WeakComponentImplHelper::rBHelper
)
51 ,m_xParent(_xConn
.get())
52 ,m_bUseBookmarks( false )
53 ,m_bEscapeProcessing( true )
56 OSL_ENSURE(_xStatement
.is() ,"Statement is NULL!");
57 m_xAggregateAsSet
.set(_xStatement
,UNO_QUERY
);
58 m_xAggregateAsCancellable
.set(m_xAggregateAsSet
, UNO_QUERY
);
61 OStatementBase::~OStatementBase()
65 // css::lang::XTypeProvider
66 Sequence
< Type
> OStatementBase::getTypes()
68 OTypeCollection
aTypes(cppu::UnoType
<XPropertySet
>::get(),
69 cppu::UnoType
<XWarningsSupplier
>::get(),
70 cppu::UnoType
<XCloseable
>::get(),
71 cppu::UnoType
<XMultipleResults
>::get(),
72 cppu::UnoType
<css::util::XCancellable
>::get(),
73 ::cppu::WeakComponentImplHelper
<>::getTypes() );
74 Reference
< XGeneratedResultSet
> xGRes(m_xAggregateAsSet
, UNO_QUERY
);
76 aTypes
= OTypeCollection(cppu::UnoType
<XGeneratedResultSet
>::get(),aTypes
.getTypes());
77 Reference
< XPreparedBatchExecution
> xPreparedBatchExecution(m_xAggregateAsSet
, UNO_QUERY
);
78 if ( xPreparedBatchExecution
.is() )
79 aTypes
= OTypeCollection(cppu::UnoType
<XPreparedBatchExecution
>::get(),aTypes
.getTypes());
81 return aTypes
.getTypes();
84 // css::uno::XInterface
85 Any
OStatementBase::queryInterface( const Type
& rType
)
87 Any aIface
= ::cppu::WeakComponentImplHelper
<>::queryInterface( rType
);
88 if (!aIface
.hasValue())
90 aIface
= ::cppu::queryInterface(
92 static_cast< XPropertySet
* >( this ),
93 static_cast< XWarningsSupplier
* >( this ),
94 static_cast< XCloseable
* >( this ),
95 static_cast< XMultipleResults
* >( this ),
96 static_cast< css::util::XCancellable
* >( this ));
97 if ( !aIface
.hasValue() )
99 Reference
< XGeneratedResultSet
> xGRes(m_xAggregateAsSet
, UNO_QUERY
);
100 if ( cppu::UnoType
<XGeneratedResultSet
>::get()== rType
&& xGRes
.is() )
101 aIface
= ::cppu::queryInterface(rType
,static_cast< XGeneratedResultSet
* >( this ));
103 if ( !aIface
.hasValue() )
105 Reference
< XPreparedBatchExecution
> xGRes(m_xAggregateAsSet
, UNO_QUERY
);
106 if ( cppu::UnoType
<XPreparedBatchExecution
>::get()== rType
&& xGRes
.is() )
107 aIface
= ::cppu::queryInterface(rType
,static_cast< XPreparedBatchExecution
* >( this ));
113 void OStatementBase::acquire() noexcept
115 ::cppu::WeakComponentImplHelper
<>::acquire();
118 void OStatementBase::release() noexcept
120 ::cppu::WeakComponentImplHelper
<>::release();
123 void OStatementBase::disposeResultSet()
125 // free the cursor if alive
126 Reference
< XComponent
> xComp(m_aResultSet
.get(), UNO_QUERY
);
129 m_aResultSet
.clear();
133 void OStatementBase::disposing()
135 OPropertySetHelper::disposing();
137 MutexGuard
aGuard(m_aMutex
);
139 // free pending results
142 // free the original statement
144 MutexGuard
aCancelGuard(m_aCancelMutex
);
145 m_xAggregateAsCancellable
= nullptr;
148 if ( m_xAggregateAsSet
.is() )
152 Reference
< XCloseable
> (m_xAggregateAsSet
, UNO_QUERY_THROW
)->close();
154 catch(RuntimeException
& )
155 {// don't care for anymore
157 catch (SQLException
&)
158 {// don't care for anymore
161 m_xAggregateAsSet
= nullptr;
163 // free the parent at last
164 ::cppu::WeakComponentImplHelper
<>::disposing();
168 void OStatementBase::close()
171 MutexGuard
aGuard( m_aMutex
);
172 ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper
.bDisposed
);
177 // OPropertySetHelper
178 Reference
< XPropertySetInfo
> OStatementBase::getPropertySetInfo()
180 return createPropertySetInfo( getInfoHelper() ) ;
183 // comphelper::OPropertyArrayUsageHelper
184 ::cppu::IPropertyArrayHelper
* OStatementBase::createArrayHelper( ) const
186 return new ::cppu::OPropertyArrayHelper
189 { PROPERTY_CURSORNAME
, PROPERTY_ID_CURSORNAME
, cppu::UnoType
<OUString
>::get(), 0 },
190 { PROPERTY_ESCAPE_PROCESSING
, PROPERTY_ID_ESCAPE_PROCESSING
, cppu::UnoType
<bool>::get(), 0 },
191 { PROPERTY_FETCHDIRECTION
, PROPERTY_ID_FETCHDIRECTION
, cppu::UnoType
<sal_Int32
>::get(), 0 },
192 { PROPERTY_FETCHSIZE
, PROPERTY_ID_FETCHSIZE
, cppu::UnoType
<sal_Int32
>::get(), 0 },
193 { PROPERTY_MAXFIELDSIZE
, PROPERTY_ID_MAXFIELDSIZE
, cppu::UnoType
<sal_Int32
>::get(), 0 },
194 { PROPERTY_MAXROWS
, PROPERTY_ID_MAXROWS
, cppu::UnoType
<sal_Int32
>::get(), 0 },
195 { PROPERTY_QUERYTIMEOUT
, PROPERTY_ID_QUERYTIMEOUT
, cppu::UnoType
<sal_Int32
>::get(), 0 },
196 { PROPERTY_RESULTSETCONCURRENCY
, PROPERTY_ID_RESULTSETCONCURRENCY
, cppu::UnoType
<sal_Int32
>::get(), 0 },
197 { PROPERTY_RESULTSETTYPE
, PROPERTY_ID_RESULTSETTYPE
, cppu::UnoType
<sal_Int32
>::get(), 0 },
198 { PROPERTY_USEBOOKMARKS
, PROPERTY_ID_USEBOOKMARKS
, cppu::UnoType
<bool>::get(), 0 }
203 // cppu::OPropertySetHelper
204 ::cppu::IPropertyArrayHelper
& OStatementBase::getInfoHelper()
206 return *getArrayHelper();
209 sal_Bool
OStatementBase::convertFastPropertyValue(Any
& rConvertedValue
, Any
& rOldValue
, sal_Int32 nHandle
, const Any
& rValue
)
211 bool bModified(false);
214 case PROPERTY_ID_USEBOOKMARKS
:
215 bModified
= ::comphelper::tryPropertyValue( rConvertedValue
, rOldValue
, rValue
, m_bUseBookmarks
);
218 case PROPERTY_ID_ESCAPE_PROCESSING
:
219 bModified
= ::comphelper::tryPropertyValue( rConvertedValue
, rOldValue
, rValue
, m_bEscapeProcessing
);
223 if ( m_xAggregateAsSet
.is() )
225 // get the property name
227 getInfoHelper().fillPropertyMembersByHandle( &sPropName
, nullptr, nHandle
);
230 Any aCurrentValue
= m_xAggregateAsSet
->getPropertyValue( sPropName
);
231 if ( aCurrentValue
!= rValue
)
233 rOldValue
= std::move(aCurrentValue
);
234 rConvertedValue
= rValue
;
243 void OStatementBase::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle
, const Any
& rValue
)
247 case PROPERTY_ID_USEBOOKMARKS
:
249 m_bUseBookmarks
= ::comphelper::getBOOL( rValue
);
250 if ( m_xAggregateAsSet
.is() && m_xAggregateAsSet
->getPropertySetInfo()->hasPropertyByName( PROPERTY_USEBOOKMARKS
) )
251 m_xAggregateAsSet
->setPropertyValue( PROPERTY_USEBOOKMARKS
, rValue
);
255 case PROPERTY_ID_ESCAPE_PROCESSING
:
256 m_bEscapeProcessing
= ::comphelper::getBOOL( rValue
);
257 if ( m_xAggregateAsSet
.is() )
258 m_xAggregateAsSet
->setPropertyValue( PROPERTY_ESCAPE_PROCESSING
, rValue
);
262 if ( m_xAggregateAsSet
.is() )
265 getInfoHelper().fillPropertyMembersByHandle( &sPropName
, nullptr, nHandle
);
266 m_xAggregateAsSet
->setPropertyValue( sPropName
, rValue
);
272 void OStatementBase::getFastPropertyValue( Any
& rValue
, sal_Int32 nHandle
) const
276 case PROPERTY_ID_USEBOOKMARKS
:
277 rValue
<<= m_bUseBookmarks
;
280 case PROPERTY_ID_ESCAPE_PROCESSING
:
281 // don't rely on our aggregate - if it implements this wrong, and always returns
282 // TRUE here, then we would loop in impl_doEscapeProcessing_nothrow
283 rValue
<<= m_bEscapeProcessing
;
287 if ( m_xAggregateAsSet
.is() )
290 const_cast< OStatementBase
* >( this )->getInfoHelper().fillPropertyMembersByHandle( &sPropName
, nullptr, nHandle
);
291 rValue
= m_xAggregateAsSet
->getPropertyValue( sPropName
);
298 Any
OStatementBase::getWarnings()
300 MutexGuard
aGuard(m_aMutex
);
301 ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper
.bDisposed
);
303 return Reference
< XWarningsSupplier
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->getWarnings();
306 void OStatementBase::clearWarnings()
308 MutexGuard
aGuard(m_aMutex
);
309 ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper
.bDisposed
);
311 Reference
< XWarningsSupplier
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->clearWarnings();
314 // css::util::XCancellable
315 void OStatementBase::cancel()
317 // no blocking as cancel is typically called from a different thread
318 MutexGuard
aCancelGuard(m_aCancelMutex
);
319 if (m_xAggregateAsCancellable
.is())
320 m_xAggregateAsCancellable
->cancel();
325 Reference
< XResultSet
> SAL_CALL
OStatementBase::getResultSet( )
327 MutexGuard
aGuard(m_aMutex
);
328 ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper
.bDisposed
);
330 // first check the meta data
331 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
332 if (!xMeta
.is() || !xMeta
->supportsMultipleResultSets())
333 throwFunctionSequenceException(*this);
335 return Reference
< XMultipleResults
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->getResultSet();
338 sal_Int32 SAL_CALL
OStatementBase::getUpdateCount( )
340 MutexGuard
aGuard(m_aMutex
);
341 ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper
.bDisposed
);
343 // first check the meta data
344 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
345 if (!xMeta
.is() || !xMeta
->supportsMultipleResultSets())
346 throwFunctionSequenceException(*this);
348 return Reference
< XMultipleResults
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->getUpdateCount();
351 sal_Bool SAL_CALL
OStatementBase::getMoreResults( )
353 MutexGuard
aGuard(m_aMutex
);
354 ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper
.bDisposed
);
356 // first check the meta data
357 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
358 if (!xMeta
.is() || !xMeta
->supportsMultipleResultSets())
359 throwFunctionSequenceException(*this);
361 // free the previous results
364 return Reference
< XMultipleResults
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->getMoreResults();
367 // XPreparedBatchExecution
368 void SAL_CALL
OStatementBase::addBatch( )
370 MutexGuard
aGuard(m_aMutex
);
371 ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper
.bDisposed
);
373 // first check the meta data
374 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
375 if (!xMeta
.is() || !xMeta
->supportsBatchUpdates())
376 throwFunctionSequenceException(*this);
378 Reference
< XPreparedBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->addBatch();
381 void SAL_CALL
OStatementBase::clearBatch( )
383 MutexGuard
aGuard(m_aMutex
);
384 ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper
.bDisposed
);
386 // first check the meta data
387 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
388 if (!xMeta
.is() || !xMeta
->supportsBatchUpdates())
389 throwFunctionSequenceException(*this);
391 Reference
< XPreparedBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->clearBatch();
394 Sequence
< sal_Int32
> SAL_CALL
OStatementBase::executeBatch( )
396 MutexGuard
aGuard(m_aMutex
);
397 ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper
.bDisposed
);
399 // first check the meta data
400 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
401 if (!xMeta
.is() || !xMeta
->supportsBatchUpdates())
402 throwFunctionSequenceException(*this);
404 // free the previous results
407 return Reference
< XPreparedBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->executeBatch();
410 Reference
< XResultSet
> SAL_CALL
OStatementBase::getGeneratedValues( )
412 MutexGuard
aGuard(m_aMutex
);
413 ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper
.bDisposed
);
414 Reference
< XGeneratedResultSet
> xGRes(m_xAggregateAsSet
, UNO_QUERY
);
417 return xGRes
->getGeneratedValues( );
418 return Reference
< XResultSet
>();
424 OStatement::OStatement( const rtl::Reference
< OConnection
>& _xConn
, const Reference
< XInterface
> & _xStatement
)
425 :OStatementBase( _xConn
, _xStatement
)
426 ,m_bAttemptedComposerCreation( false )
428 m_xAggregateStatement
.set( _xStatement
, UNO_QUERY_THROW
);
431 IMPLEMENT_FORWARD_XINTERFACE2( OStatement
, OStatementBase
, OStatement_IFACE
);
432 IMPLEMENT_FORWARD_XTYPEPROVIDER2( OStatement
, OStatementBase
, OStatement_IFACE
);
435 OUString
OStatement::getImplementationName( )
437 return u
"com.sun.star.sdb.OStatement"_ustr
;
440 sal_Bool
OStatement::supportsService( const OUString
& _rServiceName
)
442 return cppu::supportsService(this, _rServiceName
);
445 Sequence
< OUString
> OStatement::getSupportedServiceNames( )
447 return { SERVICE_SDBC_STATEMENT
};
451 Reference
< XResultSet
> OStatement::executeQuery( const OUString
& _rSQL
)
453 MutexGuard
aGuard(m_aMutex
);
454 ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper
.bDisposed
);
457 Reference
< XResultSet
> xResultSet
;
459 OUString
sSQL( impl_doEscapeProcessing_nothrow( _rSQL
) );
461 Reference
< XResultSet
> xInnerResultSet
= m_xAggregateStatement
->executeQuery( sSQL
);
462 Reference
< XConnection
> xConnection( m_xParent
, UNO_QUERY_THROW
);
464 if ( xInnerResultSet
.is() )
466 Reference
< XDatabaseMetaData
> xMeta
= xConnection
->getMetaData();
467 bool bCaseSensitive
= xMeta
.is() && xMeta
->supportsMixedCaseQuotedIdentifiers();
468 xResultSet
= new OResultSet( xInnerResultSet
, *this, bCaseSensitive
);
470 // keep the resultset weak
471 m_aResultSet
= xResultSet
;
477 sal_Int32
OStatement::executeUpdate( const OUString
& _rSQL
)
479 MutexGuard
aGuard(m_aMutex
);
480 ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper
.bDisposed
);
484 OUString
sSQL( impl_doEscapeProcessing_nothrow( _rSQL
) );
485 return m_xAggregateStatement
->executeUpdate( sSQL
);
488 sal_Bool
OStatement::execute( const OUString
& _rSQL
)
490 MutexGuard
aGuard(m_aMutex
);
491 ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper
.bDisposed
);
495 OUString
sSQL( impl_doEscapeProcessing_nothrow( _rSQL
) );
496 return m_xAggregateStatement
->execute( sSQL
);
499 void OStatement::addBatch( const OUString
& _rSQL
)
501 MutexGuard
aGuard(m_aMutex
);
502 ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper
.bDisposed
);
504 // first check the meta data
505 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
506 if (!xMeta
.is() || !xMeta
->supportsBatchUpdates())
507 throwFunctionSequenceException(*this);
509 OUString
sSQL( impl_doEscapeProcessing_nothrow( _rSQL
) );
510 Reference
< XBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->addBatch( sSQL
);
513 void OStatement::clearBatch( )
515 MutexGuard
aGuard(m_aMutex
);
516 ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper
.bDisposed
);
517 // first check the meta data
518 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
519 if (!xMeta
.is() || !xMeta
->supportsBatchUpdates())
520 throwFunctionSequenceException(*this);
522 Reference
< XBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->clearBatch();
525 Sequence
< sal_Int32
> OStatement::executeBatch( )
527 MutexGuard
aGuard(m_aMutex
);
528 ::connectivity::checkDisposed(WeakComponentImplHelper::rBHelper
.bDisposed
);
529 // first check the meta data
530 Reference
<XDatabaseMetaData
> xMeta
= Reference
< XConnection
> (m_xParent
, UNO_QUERY_THROW
)->getMetaData();
531 if (!xMeta
.is() || !xMeta
->supportsBatchUpdates())
532 throwFunctionSequenceException(*this);
533 return Reference
< XBatchExecution
>(m_xAggregateAsSet
, UNO_QUERY_THROW
)->executeBatch( );
537 Reference
< XConnection
> OStatement::getConnection()
539 return m_xParent
.get();
542 void SAL_CALL
OStatement::disposing()
544 OStatementBase::disposing();
546 m_xAggregateStatement
.clear();
549 OUString
OStatement::impl_doEscapeProcessing_nothrow( const OUString
& _rSQL
) const
551 if ( !m_bEscapeProcessing
)
555 if ( !impl_ensureComposer_nothrow() )
558 bool bParseable
= false;
559 try { m_xComposer
->setQuery( _rSQL
); bParseable
= true; }
560 catch( const SQLException
& ) { }
563 // if we cannot parse it, silently accept this. The driver is probably able to cope with it then
566 OUString sLowLevelSQL
= m_xComposer
->getQueryWithSubstitution();
569 catch( const Exception
& )
571 DBG_UNHANDLED_EXCEPTION("dbaccess");
577 bool OStatement::impl_ensureComposer_nothrow() const
579 if ( m_bAttemptedComposerCreation
)
580 return m_xComposer
.is();
582 const_cast< OStatement
* >( this )->m_bAttemptedComposerCreation
= true;
585 Reference
< XMultiServiceFactory
> xFactory( m_xParent
, UNO_QUERY_THROW
);
586 const_cast< OStatement
* >( this )->m_xComposer
.set( xFactory
->createInstance( SERVICE_NAME_SINGLESELECTQUERYCOMPOSER
), UNO_QUERY_THROW
);
588 catch( const Exception
& )
590 DBG_UNHANDLED_EXCEPTION("dbaccess");
593 return m_xComposer
.is();
596 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */