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/sqlparse.hxx>
21 #include <ado/APreparedStatement.hxx>
22 #include <com/sun/star/sdbc/DataType.hpp>
23 #include <ado/AResultSetMetaData.hxx>
24 #include <ado/AResultSet.hxx>
25 #include <ado/ADriver.hxx>
26 #include <com/sun/star/lang/DisposedException.hpp>
27 #include <cppuhelper/typeprovider.hxx>
28 #include <cppuhelper/queryinterface.hxx>
29 #include <comphelper/processfactory.hxx>
30 #include <comphelper/sequence.hxx>
31 #include <comphelper/types.hxx>
32 #include <connectivity/dbexception.hxx>
33 #include <connectivity/dbtools.hxx>
34 #include <strings.hrc>
38 #define CHECK_RETURN(x) \
40 ADOS::ThrowException(*m_pConnection->getConnection(),*this);
46 using namespace connectivity::ado
;
47 using namespace connectivity
;
48 using namespace com::sun::star::uno
;
49 using namespace com::sun::star::lang
;
50 using namespace com::sun::star::beans
;
51 using namespace com::sun::star::sdbc
;
52 using namespace com::sun::star::util
;
54 IMPLEMENT_SERVICE_INFO(OPreparedStatement
,"com.sun.star.sdbcx.APreparedStatement","com.sun.star.sdbc.PreparedStatement");
56 OPreparedStatement::OPreparedStatement( OConnection
* _pConnection
, const OUString
& sql
)
57 : OStatement_Base( _pConnection
)
59 osl_atomic_increment( &m_refCount
);
61 OSQLParser
aParser(comphelper::getComponentContext(_pConnection
->getDriver()->getORB()));
62 OUString sErrorMessage
;
64 std::unique_ptr
<OSQLParseNode
> pNode
= aParser
.parseTree(sErrorMessage
,sql
);
66 { // special handling for parameters
67 // we recursive replace all occurrences of ? in the statement and
68 // replace them with name like "parame" */
69 sal_Int32 nParameterCount
= 0;
70 replaceParameterNodeName(pNode
.get(), "parame", nParameterCount
);
71 pNode
->parseNodeToStr( sNewSql
, _pConnection
);
75 CHECK_RETURN(m_Command
.put_CommandText(sNewSql
))
76 CHECK_RETURN(m_Command
.put_Prepared(VARIANT_TRUE
))
77 m_pParameters
= m_Command
.get_Parameters();
78 m_pParameters
->AddRef();
79 m_pParameters
->Refresh();
81 osl_atomic_decrement( &m_refCount
);
84 OPreparedStatement::~OPreparedStatement()
88 OSL_FAIL( "OPreparedStatement::~OPreparedStatement: not disposed!" );
89 m_pParameters
->Release();
90 m_pParameters
= nullptr;
94 Any SAL_CALL
OPreparedStatement::queryInterface( const Type
& rType
)
96 Any aRet
= OStatement_Base::queryInterface(rType
);
97 return aRet
.hasValue() ? aRet
: ::cppu::queryInterface( rType
,
98 static_cast< XPreparedStatement
*>(this),
99 static_cast< XParameters
*>(this),
100 static_cast< XResultSetMetaDataSupplier
*>(this));
103 css::uno::Sequence
< css::uno::Type
> SAL_CALL
OPreparedStatement::getTypes( )
105 ::cppu::OTypeCollection
aTypes( cppu::UnoType
<XPreparedStatement
>::get(),
106 cppu::UnoType
<XParameters
>::get(),
107 cppu::UnoType
<XResultSetMetaDataSupplier
>::get());
109 return ::comphelper::concatSequences(aTypes
.getTypes(),OStatement_Base::getTypes());
112 Reference
< XResultSetMetaData
> SAL_CALL
OPreparedStatement::getMetaData( )
114 if(!m_xMetaData
.is() && m_RecordSet
.IsValid())
115 m_xMetaData
= new OResultSetMetaData(m_RecordSet
);
119 void OPreparedStatement::disposing()
124 m_pParameters
->Release();
125 m_pParameters
= nullptr;
127 OStatement_Base::disposing();
130 void SAL_CALL
OPreparedStatement::close( )
134 ::osl::MutexGuard
aGuard( m_aMutex
);
135 checkDisposed(OStatement_BASE::rBHelper
.bDisposed
);
142 sal_Bool SAL_CALL
OPreparedStatement::execute( )
144 ::osl::MutexGuard
aGuard( m_aMutex
);
145 checkDisposed(OStatement_BASE::rBHelper
.bDisposed
);
152 ADORecordset
* pSet
=nullptr;
153 CHECK_RETURN(m_Command
.Execute(m_RecordsAffected
,m_Parameters
,adCmdUnknown
,&pSet
))
154 m_RecordSet
= WpADORecordset(pSet
);
156 catch (SQLWarning
& ex
)
158 // Save pointer to warning and save with ResultSet
159 // object once it is created.
163 return m_RecordSet
.IsValid();
166 sal_Int32 SAL_CALL
OPreparedStatement::executeUpdate( )
168 ::osl::MutexGuard
aGuard( m_aMutex
);
169 checkDisposed(OStatement_BASE::rBHelper
.bDisposed
);
172 ADORecordset
* pSet
=nullptr;
173 CHECK_RETURN(m_Command
.Execute(m_RecordsAffected
,m_Parameters
,adCmdUnknown
,&pSet
))
174 if ( VT_ERROR
== m_RecordsAffected
.getType() )
176 ADOS::ThrowException(*m_pConnection
->getConnection(),*this);
177 // to be sure that we get the error really thrown
178 throw SQLException();
180 m_RecordSet
= WpADORecordset(pSet
);
181 return m_RecordsAffected
.getInt32();
184 void OPreparedStatement::setParameter(sal_Int32 parameterIndex
, const DataTypeEnum
& _eType
,
185 sal_Int32 _nSize
,const OLEVariant
& Val
)
187 ::osl::MutexGuard
aGuard( m_aMutex
);
188 checkDisposed(OStatement_BASE::rBHelper
.bDisposed
);
191 sal_Int32 nCount
= 0;
192 m_pParameters
->get_Count(&nCount
);
193 if(nCount
< (parameterIndex
-1))
195 OUString sDefaultName
= "parame" + OUString::number(parameterIndex
);
196 ADOParameter
* pParam
= m_Command
.CreateParameter(sDefaultName
,_eType
,adParamInput
,_nSize
,Val
);
199 m_pParameters
->Append(pParam
);
204 ADOParameter
* pParam
= nullptr;
205 m_pParameters
->get_Item(OLEVariant(sal_Int32(parameterIndex
-1)),&pParam
);
206 WpADOParameter
aParam(pParam
);
209 DataTypeEnum eType
= aParam
.GetADOType();
210 if ( _eType
!= eType
&& _eType
!= adDBTimeStamp
)
212 aParam
.put_Type(_eType
);
214 aParam
.put_Size(_nSize
);
217 if ( adVarBinary
== eType
&& aParam
.GetAttributes() == adParamLong
)
219 aParam
.AppendChunk(Val
);
222 CHECK_RETURN(aParam
.PutValue(Val
));
225 ADOS::ThrowException(*m_pConnection
->getConnection(),*this);
228 void SAL_CALL
OPreparedStatement::setString( sal_Int32 parameterIndex
, const OUString
& x
)
230 setParameter( parameterIndex
, adLongVarWChar
, std::numeric_limits
< sal_Int32
>::max(), x
);
233 Reference
< XConnection
> SAL_CALL
OPreparedStatement::getConnection( )
235 ::osl::MutexGuard
aGuard( m_aMutex
);
236 checkDisposed(OStatement_BASE::rBHelper
.bDisposed
);
238 return static_cast<Reference
< XConnection
>>(m_pConnection
);
241 Reference
< XResultSet
> SAL_CALL
OPreparedStatement::executeQuery( )
243 ::osl::MutexGuard
aGuard( m_aMutex
);
244 checkDisposed(OStatement_BASE::rBHelper
.bDisposed
);
246 // first clear the old things
249 if(m_RecordSet
.IsValid())
253 // then create the new ones
254 m_RecordSet
.Create();
256 aCmd
.setIDispatch(m_Command
);
259 CHECK_RETURN(m_RecordSet
.put_CacheSize(m_nFetchSize
))
260 CHECK_RETURN(m_RecordSet
.put_MaxRecords(m_nMaxRows
))
261 CHECK_RETURN(m_RecordSet
.Open(aCmd
,aCon
,m_eCursorType
,m_eLockType
,adOpenUnspecified
))
262 CHECK_RETURN(m_RecordSet
.get_CacheSize(m_nFetchSize
))
263 CHECK_RETURN(m_RecordSet
.get_MaxRecords(m_nMaxRows
))
264 CHECK_RETURN(m_RecordSet
.get_CursorType(m_eCursorType
))
265 CHECK_RETURN(m_RecordSet
.get_LockType(m_eLockType
))
267 OResultSet
* pSet
= new OResultSet(m_RecordSet
,this);
268 Reference
< XResultSet
> xRs
= pSet
;
270 pSet
->setMetaData(getMetaData());
271 m_xResultSet
= WeakReference
<XResultSet
>(xRs
);
276 void SAL_CALL
OPreparedStatement::setBoolean( sal_Int32 parameterIndex
, sal_Bool x
)
278 setParameter(parameterIndex
,adBoolean
,sizeof(x
),bool(x
));
281 void SAL_CALL
OPreparedStatement::setByte( sal_Int32 parameterIndex
, sal_Int8 x
)
283 setParameter(parameterIndex
,adTinyInt
,sizeof(x
),x
);
286 void SAL_CALL
OPreparedStatement::setDate( sal_Int32 parameterIndex
, const Date
& x
)
288 setParameter(parameterIndex
,adDBDate
,sizeof(x
),x
);
291 void SAL_CALL
OPreparedStatement::setTime( sal_Int32 parameterIndex
, const css::util::Time
& x
)
293 setParameter(parameterIndex
,adDBTime
,sizeof(x
),x
);
296 void SAL_CALL
OPreparedStatement::setTimestamp( sal_Int32 parameterIndex
, const DateTime
& x
)
298 setParameter(parameterIndex
,adDBTimeStamp
,sizeof(x
),x
);
301 void SAL_CALL
OPreparedStatement::setDouble( sal_Int32 parameterIndex
, double x
)
303 setParameter(parameterIndex
,adDouble
,sizeof(x
),x
);
306 void SAL_CALL
OPreparedStatement::setFloat( sal_Int32 parameterIndex
, float x
)
308 setParameter(parameterIndex
,adSingle
,sizeof(x
),x
);
311 void SAL_CALL
OPreparedStatement::setInt( sal_Int32 parameterIndex
, sal_Int32 x
)
313 setParameter(parameterIndex
,adInteger
,sizeof(x
),x
);
316 void SAL_CALL
OPreparedStatement::setLong( sal_Int32 parameterIndex
, sal_Int64 x
)
318 setParameter(parameterIndex
,adBigInt
,sizeof(x
),x
);
321 void SAL_CALL
OPreparedStatement::setNull( sal_Int32 parameterIndex
, sal_Int32
/*sqlType*/ )
325 setParameter(parameterIndex
,adEmpty
,0,aVal
);
328 void SAL_CALL
OPreparedStatement::setClob( sal_Int32
/*parameterIndex*/, const Reference
< XClob
>& /*x*/ )
330 ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::setClob", *this );
333 void SAL_CALL
OPreparedStatement::setBlob( sal_Int32
/*parameterIndex*/, const Reference
< XBlob
>& /*x*/ )
335 ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::setBlob", *this );
338 void SAL_CALL
OPreparedStatement::setArray( sal_Int32
/*parameterIndex*/, const Reference
< XArray
>& /*x*/ )
340 ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::setArray", *this );
343 void SAL_CALL
OPreparedStatement::setRef( sal_Int32
/*parameterIndex*/, const Reference
< XRef
>& /*x*/ )
345 ::dbtools::throwFeatureNotImplementedSQLException( "XRowUpdate::setRef", *this );
348 void SAL_CALL
OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex
, const Any
& x
, sal_Int32 sqlType
, sal_Int32 scale
)
352 case DataType::DECIMAL
:
353 case DataType::NUMERIC
:
354 setString(parameterIndex
,::comphelper::getString(x
));
357 ::dbtools::setObjectWithInfo(this,parameterIndex
,x
,sqlType
,scale
);
362 void SAL_CALL
OPreparedStatement::setObjectNull( sal_Int32 parameterIndex
, sal_Int32 sqlType
, const OUString
& /*typeName*/ )
364 setNull(parameterIndex
,sqlType
);
367 void SAL_CALL
OPreparedStatement::setObject( sal_Int32 parameterIndex
, const Any
& x
)
369 if(!::dbtools::implSetObject(this,parameterIndex
,x
))
371 const OUString
sError( m_pConnection
->getResources().getResourceStringWithSubstitution(
372 STR_UNKNOWN_PARA_TYPE
,
373 "$position$", OUString::number(parameterIndex
)
375 ::dbtools::throwGenericSQLException(sError
,*this);
379 void SAL_CALL
OPreparedStatement::setShort( sal_Int32 parameterIndex
, sal_Int16 x
)
381 setParameter(parameterIndex
,adSmallInt
,sizeof(x
),x
);
384 void SAL_CALL
OPreparedStatement::setBytes( sal_Int32 parameterIndex
, const Sequence
< sal_Int8
>& x
)
386 setParameter(parameterIndex
,adVarBinary
,sizeof(sal_Int8
)*x
.getLength(),x
);
389 void SAL_CALL
OPreparedStatement::setCharacterStream( sal_Int32
/*parameterIndex*/, const Reference
< css::io::XInputStream
>& /*x*/, sal_Int32
/*length*/ )
391 ::dbtools::throwFeatureNotImplementedSQLException( "XParameters::setCharacterStream", *this );
394 void SAL_CALL
OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex
, const Reference
< css::io::XInputStream
>& x
, sal_Int32 length
)
398 Sequence
< sal_Int8
> aData
;
399 x
->readBytes(aData
,length
);
400 setBytes(parameterIndex
,aData
);
404 void SAL_CALL
OPreparedStatement::clearParameters( )
406 ::osl::MutexGuard
aGuard( m_aMutex
);
407 checkDisposed(OStatement_BASE::rBHelper
.bDisposed
);
412 sal_Int32 nCount
= 0;
413 m_pParameters
->get_Count(&nCount
);
416 for(sal_Int32 i
=0;i
<nCount
;++i
)
418 ADOParameter
* pParam
= nullptr;
419 m_pParameters
->get_Item(OLEVariant(i
),&pParam
);
420 WpADOParameter
aParam(pParam
);
423 CHECK_RETURN(aParam
.PutValue(aVal
));
429 void SAL_CALL
OPreparedStatement::acquire() throw()
431 OStatement_Base::acquire();
434 void SAL_CALL
OPreparedStatement::release() throw()
436 OStatement_Base::release();
439 void OPreparedStatement::replaceParameterNodeName(OSQLParseNode
const * _pNode
,
440 const OUString
& _sDefaultName
,
441 sal_Int32
& _rParameterCount
)
443 sal_Int32 nCount
= _pNode
->count();
444 for(sal_Int32 i
=0;i
< nCount
;++i
)
446 OSQLParseNode
* pChildNode
= _pNode
->getChild(i
);
447 if(SQL_ISRULE(pChildNode
,parameter
) && pChildNode
->count() == 1)
449 OSQLParseNode
* pNewNode
= new OSQLParseNode(OUString(":") ,SQLNodeType::Punctuation
,0);
450 delete pChildNode
->replace(pChildNode
->getChild(0),pNewNode
);
451 OUString sParameterName
= _sDefaultName
+ OUString::number(++_rParameterCount
);
452 pChildNode
->append(new OSQLParseNode( sParameterName
,SQLNodeType::Name
,0));
455 replaceParameterNodeName(pChildNode
,_sDefaultName
,_rParameterCount
);
460 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */