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 <comphelper/processfactory.hxx>
29 #include <comphelper/sequence.hxx>
30 #include "connectivity/dbexception.hxx"
31 #include "connectivity/dbtools.hxx"
32 #include "resource/ado_res.hrc"
36 #define CHECK_RETURN(x) \
38 ADOS::ThrowException(*m_pConnection->getConnection(),*this);
44 using namespace connectivity::ado
;
45 using namespace connectivity
;
46 using namespace com::sun::star::uno
;
47 using namespace com::sun::star::lang
;
48 using namespace com::sun::star::beans
;
49 using namespace com::sun::star::sdbc
;
50 using namespace com::sun::star::util
;
52 IMPLEMENT_SERVICE_INFO(OPreparedStatement
,"com.sun.star.sdbcx.APreparedStatement","com.sun.star.sdbc.PreparedStatement");
54 OPreparedStatement::OPreparedStatement( OConnection
* _pConnection
,const OTypeInfoMap
& _TypeInfo
,const OUString
& sql
)
55 : OStatement_Base( _pConnection
)
56 ,m_aTypeInfo(_TypeInfo
)
58 osl_atomic_increment( &m_refCount
);
60 OSQLParser
aParser(comphelper::getComponentContext(_pConnection
->getDriver()->getORB()));
61 OUString sErrorMessage
;
63 OSQLParseNode
* pNode
= aParser
.parseTree(sErrorMessage
,sql
);
65 { // special handling for parameters
66 // we recursive replace all occurrences of ? in the statement and
67 // replace them with name like "parame" */
68 sal_Int32 nParameterCount
= 0;
69 OUString
sDefaultName( "parame" );
70 replaceParameterNodeName(pNode
,sDefaultName
,nParameterCount
);
71 pNode
->parseNodeToStr( sNewSql
, _pConnection
);
76 CHECK_RETURN(m_Command
.put_CommandText(sNewSql
))
77 CHECK_RETURN(m_Command
.put_Prepared(VARIANT_TRUE
))
78 m_pParameters
= m_Command
.get_Parameters();
79 m_pParameters
->AddRef();
80 m_pParameters
->Refresh();
82 osl_atomic_decrement( &m_refCount
);
85 OPreparedStatement::~OPreparedStatement()
89 OSL_FAIL( "OPreparedStatement::~OPreparedStatement: not disposed!" );
90 m_pParameters
->Release();
95 Any SAL_CALL
OPreparedStatement::queryInterface( const Type
& rType
) throw(RuntimeException
)
97 Any aRet
= OStatement_Base::queryInterface(rType
);
98 return aRet
.hasValue() ? aRet
: ::cppu::queryInterface( rType
,
99 static_cast< XPreparedStatement
*>(this),
100 static_cast< XParameters
*>(this),
101 static_cast< XPreparedBatchExecution
*>(this),
102 static_cast< XResultSetMetaDataSupplier
*>(this));
105 ::com::sun::star::uno::Sequence
< ::com::sun::star::uno::Type
> SAL_CALL
OPreparedStatement::getTypes( ) throw(::com::sun::star::uno::RuntimeException
)
107 ::cppu::OTypeCollection
aTypes( ::getCppuType( (const ::com::sun::star::uno::Reference
< XPreparedStatement
> *)0 ),
108 ::getCppuType( (const ::com::sun::star::uno::Reference
< XParameters
> *)0 ),
109 ::getCppuType( (const ::com::sun::star::uno::Reference
< XResultSetMetaDataSupplier
> *)0 ),
110 ::getCppuType( (const ::com::sun::star::uno::Reference
< XPreparedBatchExecution
> *)0 ));
112 return ::comphelper::concatSequences(aTypes
.getTypes(),OStatement_Base::getTypes());
115 Reference
< XResultSetMetaData
> SAL_CALL
OPreparedStatement::getMetaData( ) throw(SQLException
, RuntimeException
)
117 if(!m_xMetaData
.is() && m_RecordSet
.IsValid())
118 m_xMetaData
= new OResultSetMetaData(m_RecordSet
);
122 void OPreparedStatement::disposing()
127 m_pParameters
->Release();
128 m_pParameters
= NULL
;
130 OStatement_Base::disposing();
133 void SAL_CALL
OPreparedStatement::close( ) throw(SQLException
, RuntimeException
)
137 ::osl::MutexGuard
aGuard( m_aMutex
);
138 checkDisposed(OStatement_BASE::rBHelper
.bDisposed
);
145 sal_Bool SAL_CALL
OPreparedStatement::execute( ) throw(SQLException
, RuntimeException
)
147 ::osl::MutexGuard
aGuard( m_aMutex
);
148 checkDisposed(OStatement_BASE::rBHelper
.bDisposed
);
155 ADORecordset
* pSet
=NULL
;
156 CHECK_RETURN(m_Command
.Execute(m_RecordsAffected
,m_Parameters
,adCmdUnknown
,&pSet
))
157 m_RecordSet
= WpADORecordset(pSet
);
159 catch (SQLWarning
& ex
)
161 // Save pointer to warning and save with ResultSet
162 // object once it is created.
166 return m_RecordSet
.IsValid();
169 sal_Int32 SAL_CALL
OPreparedStatement::executeUpdate( ) throw(SQLException
, RuntimeException
)
171 ::osl::MutexGuard
aGuard( m_aMutex
);
172 checkDisposed(OStatement_BASE::rBHelper
.bDisposed
);
175 ADORecordset
* pSet
=NULL
;
176 CHECK_RETURN(m_Command
.Execute(m_RecordsAffected
,m_Parameters
,adCmdUnknown
,&pSet
))
177 if ( VT_ERROR
== m_RecordsAffected
.getType() )
179 ADOS::ThrowException(*m_pConnection
->getConnection(),*this);
180 // to be sure that we get the error really thrown
181 throw SQLException();
183 m_RecordSet
= WpADORecordset(pSet
);
184 return static_cast<sal_Int32
>(m_RecordsAffected
);
187 void OPreparedStatement::setParameter(sal_Int32 parameterIndex
, const DataTypeEnum
& _eType
,
188 const sal_Int32
& _nSize
,const OLEVariant
& _Val
) throw(SQLException
, RuntimeException
)
190 ::osl::MutexGuard
aGuard( m_aMutex
);
191 checkDisposed(OStatement_BASE::rBHelper
.bDisposed
);
194 sal_Int32 nCount
= 0;
195 m_pParameters
->get_Count(&nCount
);
196 if(nCount
< (parameterIndex
-1))
198 OUString
sDefaultName( "parame" );
199 sDefaultName
+= OUString::number(parameterIndex
);
200 ADOParameter
* pParam
= m_Command
.CreateParameter(sDefaultName
,_eType
,adParamInput
,_nSize
,_Val
);
203 m_pParameters
->Append(pParam
);
204 #if OSL_DEBUG_LEVEL > 0
205 ADOParameter
* pParam
= NULL
;
206 m_pParameters
->get_Item(OLEVariant(sal_Int32(parameterIndex
-1)),&pParam
);
207 WpADOParameter
aParam(pParam
);
210 DataTypeEnum eType
= aParam
.GetADOType();
218 ADOParameter
* pParam
= NULL
;
219 m_pParameters
->get_Item(OLEVariant(sal_Int32(parameterIndex
-1)),&pParam
);
220 WpADOParameter
aParam(pParam
);
223 #if OSL_DEBUG_LEVEL > 0
224 OUString sParam
= aParam
.GetName();
226 #endif // OSL_DEBUG_LEVEL
228 DataTypeEnum eType
= aParam
.GetADOType();
229 if ( _eType
!= eType
&& _eType
!= adDBTimeStamp
)
231 aParam
.put_Type(_eType
);
233 aParam
.put_Size(_nSize
);
236 if ( adVarBinary
== eType
&& aParam
.GetAttributes() == adParamLong
)
238 aParam
.AppendChunk(_Val
);
241 CHECK_RETURN(aParam
.PutValue(_Val
));
244 ADOS::ThrowException(*m_pConnection
->getConnection(),*this);
247 void SAL_CALL
OPreparedStatement::setString( sal_Int32 parameterIndex
, const OUString
& x
) throw(SQLException
, RuntimeException
)
249 setParameter( parameterIndex
, adLongVarWChar
, ::std::numeric_limits
< sal_Int32
>::max(), x
);
252 Reference
< XConnection
> SAL_CALL
OPreparedStatement::getConnection( ) throw(SQLException
, RuntimeException
)
254 ::osl::MutexGuard
aGuard( m_aMutex
);
255 checkDisposed(OStatement_BASE::rBHelper
.bDisposed
);
257 return (Reference
< XConnection
>)m_pConnection
;
260 Reference
< XResultSet
> SAL_CALL
OPreparedStatement::executeQuery( ) throw(SQLException
, RuntimeException
)
262 ::osl::MutexGuard
aGuard( m_aMutex
);
263 checkDisposed(OStatement_BASE::rBHelper
.bDisposed
);
265 // first clear the old things
268 if(m_RecordSet
.IsValid())
272 // the create the new onces
273 m_RecordSet
.Create();
275 aCmd
.setIDispatch(m_Command
);
278 CHECK_RETURN(m_RecordSet
.put_CacheSize(m_nFetchSize
))
279 CHECK_RETURN(m_RecordSet
.put_MaxRecords(m_nMaxRows
))
280 CHECK_RETURN(m_RecordSet
.Open(aCmd
,aCon
,m_eCursorType
,m_eLockType
,adOpenUnspecified
))
281 CHECK_RETURN(m_RecordSet
.get_CacheSize(m_nFetchSize
))
282 CHECK_RETURN(m_RecordSet
.get_MaxRecords(m_nMaxRows
))
283 CHECK_RETURN(m_RecordSet
.get_CursorType(m_eCursorType
))
284 CHECK_RETURN(m_RecordSet
.get_LockType(m_eLockType
))
286 OResultSet
* pSet
= new OResultSet(m_RecordSet
,this);
287 Reference
< XResultSet
> xRs
= pSet
;
289 pSet
->setMetaData(getMetaData());
290 m_xResultSet
= WeakReference
<XResultSet
>(xRs
);
295 void SAL_CALL
OPreparedStatement::setBoolean( sal_Int32 parameterIndex
, sal_Bool x
) throw(SQLException
, RuntimeException
)
297 setParameter(parameterIndex
,adBoolean
,sizeof(x
),bool(x
));
300 void SAL_CALL
OPreparedStatement::setByte( sal_Int32 parameterIndex
, sal_Int8 x
) throw(SQLException
, RuntimeException
)
302 setParameter(parameterIndex
,adTinyInt
,sizeof(x
),x
);
305 void SAL_CALL
OPreparedStatement::setDate( sal_Int32 parameterIndex
, const Date
& x
) throw(SQLException
, RuntimeException
)
307 setParameter(parameterIndex
,adDBDate
,sizeof(x
),x
);
310 void SAL_CALL
OPreparedStatement::setTime( sal_Int32 parameterIndex
, const Time
& x
) throw(SQLException
, RuntimeException
)
312 setParameter(parameterIndex
,adDBTime
,sizeof(x
),x
);
315 void SAL_CALL
OPreparedStatement::setTimestamp( sal_Int32 parameterIndex
, const DateTime
& x
) throw(SQLException
, RuntimeException
)
317 setParameter(parameterIndex
,adDBTimeStamp
,sizeof(x
),x
);
320 void SAL_CALL
OPreparedStatement::setDouble( sal_Int32 parameterIndex
, double x
) throw(SQLException
, RuntimeException
)
322 setParameter(parameterIndex
,adDouble
,sizeof(x
),x
);
325 void SAL_CALL
OPreparedStatement::setFloat( sal_Int32 parameterIndex
, float x
) throw(SQLException
, RuntimeException
)
327 setParameter(parameterIndex
,adSingle
,sizeof(x
),x
);
330 void SAL_CALL
OPreparedStatement::setInt( sal_Int32 parameterIndex
, sal_Int32 x
) throw(SQLException
, RuntimeException
)
332 setParameter(parameterIndex
,adInteger
,sizeof(x
),x
);
335 void SAL_CALL
OPreparedStatement::setLong( sal_Int32 parameterIndex
, sal_Int64 x
) throw(SQLException
, RuntimeException
)
337 setParameter(parameterIndex
,adBigInt
,sizeof(x
),x
);
340 void SAL_CALL
OPreparedStatement::setNull( sal_Int32 parameterIndex
, sal_Int32
/*sqlType*/ ) throw(SQLException
, RuntimeException
)
344 setParameter(parameterIndex
,adEmpty
,0,aVal
);
347 void SAL_CALL
OPreparedStatement::setClob( sal_Int32
/*parameterIndex*/, const Reference
< XClob
>& /*x*/ ) throw(SQLException
, RuntimeException
)
349 ::dbtools::throwFeatureNotImplementedException( "XRowUpdate::setClob", *this );
352 void SAL_CALL
OPreparedStatement::setBlob( sal_Int32
/*parameterIndex*/, const Reference
< XBlob
>& /*x*/ ) throw(SQLException
, RuntimeException
)
354 ::dbtools::throwFeatureNotImplementedException( "XRowUpdate::setBlob", *this );
357 void SAL_CALL
OPreparedStatement::setArray( sal_Int32
/*parameterIndex*/, const Reference
< XArray
>& /*x*/ ) throw(SQLException
, RuntimeException
)
359 ::dbtools::throwFeatureNotImplementedException( "XRowUpdate::setArray", *this );
362 void SAL_CALL
OPreparedStatement::setRef( sal_Int32
/*parameterIndex*/, const Reference
< XRef
>& /*x*/ ) throw(SQLException
, RuntimeException
)
364 ::dbtools::throwFeatureNotImplementedException( "XRowUpdate::setRef", *this );
367 void SAL_CALL
OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex
, const Any
& x
, sal_Int32 sqlType
, sal_Int32 scale
) throw(SQLException
, RuntimeException
)
371 case DataType::DECIMAL
:
372 case DataType::NUMERIC
:
373 setString(parameterIndex
,::comphelper::getString(x
));
376 ::dbtools::setObjectWithInfo(this,parameterIndex
,x
,sqlType
,scale
);
381 void SAL_CALL
OPreparedStatement::setObjectNull( sal_Int32 parameterIndex
, sal_Int32 sqlType
, const OUString
& /*typeName*/ ) throw(SQLException
, RuntimeException
)
383 setNull(parameterIndex
,sqlType
);
386 void SAL_CALL
OPreparedStatement::setObject( sal_Int32 parameterIndex
, const Any
& x
) throw(SQLException
, RuntimeException
)
388 if(!::dbtools::implSetObject(this,parameterIndex
,x
))
390 const OUString
sError( m_pConnection
->getResources().getResourceStringWithSubstitution(
391 STR_UNKNOWN_PARA_TYPE
,
392 "$position$", OUString::number(parameterIndex
)
394 ::dbtools::throwGenericSQLException(sError
,*this);
398 void SAL_CALL
OPreparedStatement::setShort( sal_Int32 parameterIndex
, sal_Int16 x
) throw(SQLException
, RuntimeException
)
400 setParameter(parameterIndex
,adSmallInt
,sizeof(x
),x
);
403 void SAL_CALL
OPreparedStatement::setBytes( sal_Int32 parameterIndex
, const Sequence
< sal_Int8
>& x
) throw(SQLException
, RuntimeException
)
405 setParameter(parameterIndex
,adVarBinary
,sizeof(sal_Int8
)*x
.getLength(),x
);
408 void SAL_CALL
OPreparedStatement::setCharacterStream( sal_Int32
/*parameterIndex*/, const Reference
< ::com::sun::star::io::XInputStream
>& /*x*/, sal_Int32
/*length*/ ) throw(SQLException
, RuntimeException
)
410 ::dbtools::throwFeatureNotImplementedException( "XParameters::setCharacterStream", *this );
413 void SAL_CALL
OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex
, const Reference
< ::com::sun::star::io::XInputStream
>& x
, sal_Int32 length
) throw(SQLException
, RuntimeException
)
417 Sequence
< sal_Int8
> aData
;
418 x
->readBytes(aData
,length
);
419 setBytes(parameterIndex
,aData
);
423 void SAL_CALL
OPreparedStatement::clearParameters( ) throw(SQLException
, RuntimeException
)
425 ::osl::MutexGuard
aGuard( m_aMutex
);
426 checkDisposed(OStatement_BASE::rBHelper
.bDisposed
);
431 sal_Int32 nCount
= 0;
432 m_pParameters
->get_Count(&nCount
);
435 for(sal_Int32 i
=0;i
<nCount
;++i
)
437 ADOParameter
* pParam
= NULL
;
438 m_pParameters
->get_Item(OLEVariant(i
),&pParam
);
439 WpADOParameter
aParam(pParam
);
442 OUString sParam
= aParam
.GetName();
443 CHECK_RETURN(aParam
.PutValue(aVal
));
449 void SAL_CALL
OPreparedStatement::clearBatch( ) throw(SQLException
, RuntimeException
)
453 void SAL_CALL
OPreparedStatement::addBatch( ) throw(SQLException
, RuntimeException
)
457 Sequence
< sal_Int32
> SAL_CALL
OPreparedStatement::executeBatch( ) throw(SQLException
, RuntimeException
)
459 return Sequence
< sal_Int32
> ();
462 void SAL_CALL
OPreparedStatement::acquire() throw()
464 OStatement_Base::acquire();
467 void SAL_CALL
OPreparedStatement::release() throw()
469 OStatement_Base::release();
472 void OPreparedStatement::replaceParameterNodeName(OSQLParseNode
* _pNode
,
473 const OUString
& _sDefaultName
,
474 sal_Int32
& _rParameterCount
)
476 sal_Int32 nCount
= _pNode
->count();
477 for(sal_Int32 i
=0;i
< nCount
;++i
)
479 OSQLParseNode
* pChildNode
= _pNode
->getChild(i
);
480 if(SQL_ISRULE(pChildNode
,parameter
) && pChildNode
->count() == 1)
482 OSQLParseNode
* pNewNode
= new OSQLParseNode(OUString(":") ,SQL_NODE_PUNCTUATION
,0);
483 delete pChildNode
->replace(pChildNode
->getChild(0),pNewNode
);
484 OUString sParameterName
= _sDefaultName
;
485 sParameterName
+= OUString::number(++_rParameterCount
);
486 pChildNode
->append(new OSQLParseNode( sParameterName
,SQL_NODE_NAME
,0));
489 replaceParameterNodeName(pChildNode
,_sDefaultName
,_rParameterCount
);
494 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */