nss: upgrade to release 3.73
[LibreOffice.git] / dbaccess / source / core / api / statement.cxx
blob812d91c64a47b8ccf430ecd5e4a4326444a1d0fc
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 <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);
71 if ( xGRes.is() )
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(
87 rType,
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 ));
106 return aIface;
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);
123 if (xComp.is())
124 xComp->dispose();
125 m_aResultSet = nullptr;
128 // OComponentHelper
129 void OStatementBase::disposing()
131 OPropertySetHelper::disposing();
133 MutexGuard aGuard(m_aMutex);
135 // free pending results
136 disposeResultSet();
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();
160 // XCloseable
161 void OStatementBase::close()
164 MutexGuard aGuard( m_aMutex );
165 ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
167 dispose();
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);
202 switch (nHandle)
204 case PROPERTY_ID_USEBOOKMARKS:
205 bModified = ::comphelper::tryPropertyValue( rConvertedValue, rOldValue, rValue, m_bUseBookmarks );
206 break;
208 case PROPERTY_ID_ESCAPE_PROCESSING:
209 bModified = ::comphelper::tryPropertyValue( rConvertedValue, rOldValue, rValue, m_bEscapeProcessing );
210 break;
212 default:
213 if ( m_xAggregateAsSet.is() )
215 // get the property name
216 OUString sPropName;
217 getInfoHelper().fillPropertyMembersByHandle( &sPropName, nullptr, nHandle );
219 // now set the value
220 Any aCurrentValue = m_xAggregateAsSet->getPropertyValue( sPropName );
221 if ( aCurrentValue != rValue )
223 rOldValue = aCurrentValue;
224 rConvertedValue = rValue;
225 bModified = true;
228 break;
230 return bModified;
233 void OStatementBase::setFastPropertyValue_NoBroadcast( sal_Int32 nHandle, const Any& rValue )
235 switch ( nHandle )
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 );
243 break;
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 );
249 break;
251 default:
252 if ( m_xAggregateAsSet.is() )
254 OUString sPropName;
255 getInfoHelper().fillPropertyMembersByHandle( &sPropName, nullptr, nHandle );
256 m_xAggregateAsSet->setPropertyValue( sPropName, rValue );
258 break;
262 void OStatementBase::getFastPropertyValue( Any& rValue, sal_Int32 nHandle ) const
264 switch (nHandle)
266 case PROPERTY_ID_USEBOOKMARKS:
267 rValue <<= m_bUseBookmarks;
268 break;
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;
274 break;
276 default:
277 if ( m_xAggregateAsSet.is() )
279 OUString sPropName;
280 const_cast< OStatementBase* >( this )->getInfoHelper().fillPropertyMembersByHandle( &sPropName, nullptr, nHandle );
281 rValue = m_xAggregateAsSet->getPropertyValue( sPropName );
283 break;
287 // XWarningsSupplier
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();
311 // else do nothing
314 // XMultipleResults
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
352 disposeResultSet();
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
395 disposeResultSet();
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);
406 if ( xGRes.is() )
407 return xGRes->getGeneratedValues( );
408 return Reference< XResultSet >();
412 // OStatement
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 );
424 // XServiceInfo
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 };
440 // XStatement
441 Reference< XResultSet > OStatement::executeQuery( const OUString& _rSQL )
443 MutexGuard aGuard(m_aMutex);
444 ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
446 disposeResultSet();
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;
464 return xResultSet;
467 sal_Int32 OStatement::executeUpdate( const OUString& _rSQL )
469 MutexGuard aGuard(m_aMutex);
470 ::connectivity::checkDisposed(OComponentHelper::rBHelper.bDisposed);
472 disposeResultSet();
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);
483 disposeResultSet();
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();
535 m_xComposer.clear();
536 m_xAggregateStatement.clear();
539 OUString OStatement::impl_doEscapeProcessing_nothrow( const OUString& _rSQL ) const
541 if ( !m_bEscapeProcessing )
542 return _rSQL;
545 if ( !impl_ensureComposer_nothrow() )
546 return _rSQL;
548 bool bParseable = false;
549 try { m_xComposer->setQuery( _rSQL ); bParseable = true; }
550 catch( const SQLException& ) { }
552 if ( !bParseable )
553 // if we cannot parse it, silently accept this. The driver is probably able to cope with it then
554 return _rSQL;
556 OUString sLowLevelSQL = m_xComposer->getQueryWithSubstitution();
557 return sLowLevelSQL;
559 catch( const Exception& )
561 DBG_UNHANDLED_EXCEPTION("dbaccess");
564 return _rSQL;
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: */