Version 4.3.0.0.beta1, tag libreoffice-4.3.0.0.beta1
[LibreOffice.git] / connectivity / source / drivers / odbc / OPreparedStatement.cxx
blob70bfc7723bdf0a6ed3666bb6ba96c208db9036a5
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 .
21 #include <stdio.h>
22 #include <string.h>
23 #include <osl/diagnose.h>
24 #include "diagnose_ex.h"
25 #include "odbc/OPreparedStatement.hxx"
26 #include "odbc/OBoundParam.hxx"
27 #include <com/sun/star/sdbc/DataType.hpp>
28 #include "odbc/OTools.hxx"
29 #include "odbc/ODriver.hxx"
30 #include "odbc/OResultSet.hxx"
31 #include "odbc/OResultSetMetaData.hxx"
32 #include <cppuhelper/typeprovider.hxx>
33 #include <comphelper/processfactory.hxx>
34 #include <comphelper/sequence.hxx>
35 #include <com/sun/star/lang/DisposedException.hpp>
36 #include "connectivity/dbtools.hxx"
37 #include <comphelper/types.hxx>
38 #include "connectivity/FValue.hxx"
39 #include "resource/common_res.hrc"
40 #include "connectivity/sqlparse.hxx"
41 #include <boost/scoped_ptr.hpp>
42 #include <boost/type_traits/remove_reference.hpp>
43 #include <boost/type_traits/is_same.hpp>
45 using namespace ::comphelper;
46 using namespace connectivity;
47 using namespace connectivity::odbc;
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::sdbcx;
53 using namespace com::sun::star::container;
54 using namespace com::sun::star::io;
55 using namespace com::sun::star::util;
57 IMPLEMENT_SERVICE_INFO(OPreparedStatement,"com.sun.star.sdbcx.OPreparedStatement","com.sun.star.sdbc.PreparedStatement");
59 namespace
61 // for now, never use wchar,
62 // but most of code is prepared to handle it
63 // in case we make this configurable
64 const bool useWChar = false;
67 OPreparedStatement::OPreparedStatement( OConnection* _pConnection,const OUString& sql)
68 :OStatement_BASE2(_pConnection)
69 ,numParams(0)
70 ,boundParams(NULL)
71 ,m_bPrepared(false)
73 m_sSqlStatement = sql;
74 try
76 if(_pConnection->isParameterSubstitutionEnabled())
78 OSQLParser aParser( comphelper::getComponentContext(_pConnection->getDriver()->getORB()) );
79 OUString sErrorMessage;
80 OUString sNewSql;
81 boost::scoped_ptr<OSQLParseNode> pNode( aParser.parseTree(sErrorMessage,sql) );
82 if ( pNode.get() )
83 { // special handling for parameters
84 OSQLParseNode::substituteParameterNames(pNode.get());
85 pNode->parseNodeToStr( sNewSql, _pConnection );
86 m_sSqlStatement = sNewSql;
90 catch(Exception&)
95 void SAL_CALL OPreparedStatement::acquire() throw()
97 OStatement_BASE2::acquire();
100 void SAL_CALL OPreparedStatement::release() throw()
102 OStatement_BASE2::release();
105 Any SAL_CALL OPreparedStatement::queryInterface( const Type & rType ) throw(RuntimeException, std::exception)
107 Any aRet = OStatement_BASE2::queryInterface(rType);
108 return aRet.hasValue() ? aRet : OPreparedStatement_BASE::queryInterface(rType);
111 ::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL OPreparedStatement::getTypes( ) throw(::com::sun::star::uno::RuntimeException, std::exception)
113 return ::comphelper::concatSequences(OPreparedStatement_BASE::getTypes(),OStatement_BASE2::getTypes());
117 Reference< XResultSetMetaData > SAL_CALL OPreparedStatement::getMetaData( ) throw(SQLException, RuntimeException, std::exception)
119 ::osl::MutexGuard aGuard( m_aMutex );
120 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
123 prepareStatement();
124 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
125 if(!m_xMetaData.is())
126 m_xMetaData = new OResultSetMetaData(getOwnConnection(),m_aStatementHandle);
127 return m_xMetaData;
131 void SAL_CALL OPreparedStatement::close( ) throw(SQLException, RuntimeException, std::exception)
133 ::osl::MutexGuard aGuard( m_aMutex );
134 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
137 // Close/clear our result set
138 clearMyResultSet ();
140 // Reset last warning message
142 try {
143 clearWarnings ();
144 OStatement_BASE2::close();
145 FreeParams();
147 catch (SQLException &) {
148 // If we get an error, ignore
151 // Remove this Statement object from the Connection object's
152 // list
156 sal_Bool SAL_CALL OPreparedStatement::execute( ) throw(SQLException, RuntimeException, std::exception)
158 ::osl::MutexGuard aGuard( m_aMutex );
159 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
162 bool needData = false;
164 // Reset warnings
166 clearWarnings ();
168 // Reset the statement handle, warning and saved Resultset
170 reset();
172 // Call SQLExecute
173 prepareStatement();
175 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
178 SQLRETURN nReturn = N3SQLExecute(m_aStatementHandle);
180 OTools::ThrowException(m_pConnection,nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this);
181 needData = nReturn == SQL_NEED_DATA;
183 // Now loop while more data is needed (i.e. a data-at-
184 // execution parameter was given). For each parameter
185 // that needs data, put the data from the input stream.
187 while (needData) {
189 // Get the parameter number that requires data
191 sal_Int32* paramIndex = 0;
192 nReturn = N3SQLParamData(m_aStatementHandle,(SQLPOINTER*)&paramIndex);
194 // If the parameter index is -1, there is no
195 // more data required
197 if ( !paramIndex || ( *paramIndex == -1 ) )
198 needData = false;
199 else
201 // Now we have the proper parameter
202 // index, get the data from the input
203 // stream and do a SQLPutData
204 putParamData (*paramIndex);
209 catch (const SQLWarning&)
213 // Now determine if there is a result set associated with
214 // the SQL statement that was executed. Get the column
215 // count, and if it is not zero, there is a result set.
218 return getColumnCount() > 0;
222 sal_Int32 SAL_CALL OPreparedStatement::executeUpdate( ) throw(SQLException, RuntimeException, std::exception)
224 ::osl::MutexGuard aGuard( m_aMutex );
225 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
227 sal_Int32 numRows = -1;
229 prepareStatement();
230 // Execute the statement. If execute returns sal_False, a
231 // row count exists.
233 if (!execute())
234 numRows = getUpdateCount ();
235 else
237 // No update count was produced (a ResultSet was). Raise
238 // an exception
239 m_pConnection->throwGenericSQLException(STR_NO_ROWCOUNT,*this);
241 return numRows;
245 void SAL_CALL OPreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x ) throw(SQLException, RuntimeException, std::exception)
247 setParameter(parameterIndex, DataType::CHAR, invalid_scale, x);
251 Reference< XConnection > SAL_CALL OPreparedStatement::getConnection( ) throw(SQLException, RuntimeException, std::exception)
253 ::osl::MutexGuard aGuard( m_aMutex );
254 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
256 return (Reference< XConnection >)m_pConnection;
260 Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery( ) throw(SQLException, RuntimeException, std::exception)
262 ::osl::MutexGuard aGuard( m_aMutex );
263 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
265 Reference< XResultSet > rs = NULL;
267 prepareStatement();
269 if (execute())
270 rs = getResultSet(false);
271 else
273 // No ResultSet was produced. Raise an exception
274 m_pConnection->throwGenericSQLException(STR_NO_RESULTSET,*this);
276 return rs;
280 void SAL_CALL OPreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x ) throw(SQLException, RuntimeException, std::exception)
282 // Set the parameter as if it were an integer
283 setInt (parameterIndex, x ? 1 : 0 );
286 // The MutexGuard must _already_ be taken!
287 void OPreparedStatement::setParameterPre(sal_Int32 parameterIndex)
289 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
290 prepareStatement();
291 checkParameterIndex(parameterIndex);
292 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
296 template <typename T> void OPreparedStatement::setScalarParameter(const sal_Int32 parameterIndex, const sal_Int32 i_nType, const SQLULEN i_nColSize, const T i_Value)
298 ::osl::MutexGuard aGuard( m_aMutex );
299 setParameterPre(parameterIndex);
301 typedef typename boost::remove_reference< T >::type TnoRef;
303 TnoRef *bindBuf = static_cast< TnoRef* >( allocBindBuf(parameterIndex, sizeof(i_Value)) );
304 *bindBuf = i_Value;
306 setParameter(parameterIndex, i_nType, i_nColSize, invalid_scale, bindBuf, sizeof(i_Value), sizeof(i_Value));
310 void OPreparedStatement::setParameter(const sal_Int32 parameterIndex, const sal_Int32 _nType, const sal_Int16 _nScale, const OUString &_sData)
312 ::osl::MutexGuard aGuard( m_aMutex );
313 setParameterPre(parameterIndex);
315 assert (_nType == DataType::VARCHAR || _nType == DataType::CHAR || _nType == DataType::DECIMAL || _nType == DataType::NUMERIC);
317 sal_Int32 nCharLen;
318 sal_Int32 nByteLen;
319 void *pData;
320 if (useWChar)
323 * On Windows, wchar is 16 bits (UTF-16 encoding), the ODBC "W" variants functions take UTF-16 encoded strings
324 * and character lengths are number of UTF-16 codepoints.
325 * Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms716246%28v=vs.85%29.aspx
326 * ODBC Programmer's reference > Developing Applications > Programming Considerations > Unicode > Unicode Function Arguments
327 * http://support.microsoft.com/kb/294169
329 * UnixODBC can be configured at compile-time so that the "W" variants expect
330 * UTF-16 or UTF-32 encoded strings, and character lengths are number of codepoints.
331 * However, UTF-16 is the default, what all/most distributions do
332 * and the established API that most drivers implement.
333 * As wchar is often 32 bits, this differs from C-style strings of wchar!
335 * Our internal OUString storage is always UTF-16, so no conversion to do here.
337 BOOST_STATIC_ASSERT( sizeof(sal_Unicode) == 2 );
338 BOOST_STATIC_ASSERT( sizeof(SQLWCHAR) == 2 );
339 nCharLen = _sData.getLength();
340 nByteLen = nCharLen * sizeof(sal_Unicode);
341 pData = allocBindBuf(parameterIndex, nByteLen);
342 memcpy(pData, _sData.getStr(), nByteLen);
344 else
346 OString sOData( OUStringToOString(_sData, getOwnConnection()->getTextEncoding()) );
347 nCharLen = sOData.getLength();
348 nByteLen = nCharLen;
349 pData = allocBindBuf(parameterIndex, nByteLen);
350 memcpy(pData, sOData.getStr(), nByteLen);
353 setParameter( parameterIndex, _nType, nCharLen, _nScale, pData, nByteLen, nByteLen );
356 void OPreparedStatement::setParameter(const sal_Int32 parameterIndex, const sal_Int32 _nType, const Sequence< sal_Int8 > &x)
358 ::osl::MutexGuard aGuard( m_aMutex );
359 setParameterPre(parameterIndex);
361 assert(_nType == DataType::BINARY || _nType == DataType::VARBINARY);
363 // don't copy the sequence, just point the ODBC directly at the sequence's storage array
364 // Why BINARY/Sequence is treated differently than strings (which are copied), I'm not sure
365 OSL_VERIFY(allocBindBuf(parameterIndex, 0) == NULL);
366 boundParams[parameterIndex-1].setSequence(x); // this ensures that the sequence stays alive
368 setParameter( parameterIndex, _nType, x.getLength(), invalid_scale, x.getConstArray(), x.getLength(), x.getLength() );
371 void OPreparedStatement::setParameter(const sal_Int32 parameterIndex, const sal_Int32 _nType, const SQLULEN _nColumnSize, const sal_Int32 _nScale, const void* const _pData, const SQLULEN _nDataLen, const SQLLEN _nDataAllocLen)
373 SQLSMALLINT fCType, fSqlType;
374 OTools::getBindTypes(useWChar, m_pConnection->useOldDateFormat(), OTools::jdbcTypeToOdbc(_nType), fCType, fSqlType);
376 SQLLEN *pDataLen=boundParams[parameterIndex-1].getBindLengthBuffer();
377 *pDataLen=_nDataLen;
379 SQLRETURN nRetcode;
380 nRetcode = (*(T3SQLBindParameter)m_pConnection->getOdbcFunction(ODBC3SQLBindParameter))(
381 m_aStatementHandle,
382 // checkParameterIndex guarantees this is safe
383 static_cast<SQLUSMALLINT>(parameterIndex),
384 SQL_PARAM_INPUT,
385 fCType,
386 fSqlType,
387 _nColumnSize,
388 _nScale,
389 // we trust the ODBC driver not to touch it because SQL_PARAM_INPUT
390 const_cast<void*>(_pData),
391 _nDataAllocLen,
392 pDataLen);
394 OTools::ThrowException(m_pConnection, nRetcode, m_aStatementHandle, SQL_HANDLE_STMT, *this);
397 void SAL_CALL OPreparedStatement::setByte( const sal_Int32 parameterIndex, const sal_Int8 x ) throw(SQLException, RuntimeException, std::exception)
399 setScalarParameter(parameterIndex, DataType::TINYINT, 3, x);
402 // For older compilers (that do not support partial specialisation of class templates)
403 // uncomment if necessary (safe also on compilers that *do* support partial specialisation)
404 //BOOST_BROKEN_COMPILER_TYPE_TRAITS_SPECIALIZATION(DATE_STRUCT);
405 //BOOST_STATIC_ASSERT((boost::is_same<DATE_STRUCT, boost::remove_reference<DATE_STRUCT&>::type>::value));
406 void SAL_CALL OPreparedStatement::setDate( sal_Int32 parameterIndex, const Date& aData ) throw(SQLException, RuntimeException, std::exception)
408 DATE_STRUCT x(OTools::DateToOdbcDate(aData));
409 setScalarParameter<DATE_STRUCT&>(parameterIndex, DataType::DATE, 10, x);
413 void SAL_CALL OPreparedStatement::setTime( sal_Int32 parameterIndex, const Time& aVal ) throw(SQLException, RuntimeException, std::exception)
415 SQLULEN nColSize;
416 if(aVal.NanoSeconds == 0)
417 nColSize = 8;
418 else if(aVal.NanoSeconds % 100000000 == 0)
419 nColSize = 10;
420 else if(aVal.NanoSeconds % 10000000 == 0)
421 nColSize = 11;
422 else if(aVal.NanoSeconds % 1000000 == 0)
423 nColSize = 12;
424 else if(aVal.NanoSeconds % 100000 == 0)
425 nColSize = 13;
426 else if(aVal.NanoSeconds % 10000 == 0)
427 nColSize = 14;
428 else if(aVal.NanoSeconds % 1000 == 0)
429 nColSize = 15;
430 else if(aVal.NanoSeconds % 100 == 0)
431 nColSize = 16;
432 else if(aVal.NanoSeconds % 10 == 0)
433 nColSize = 17;
434 else
435 nColSize = 18;
436 TIME_STRUCT x(OTools::TimeToOdbcTime(aVal));
437 setScalarParameter<TIME_STRUCT&>(parameterIndex, DataType::TIME, nColSize, x);
441 void SAL_CALL OPreparedStatement::setTimestamp( sal_Int32 parameterIndex, const DateTime& aVal ) throw(SQLException, RuntimeException, std::exception)
443 SQLULEN nColSize;
444 if(aVal.NanoSeconds == 0)
446 if (aVal.Seconds == 0)
447 nColSize=16;
448 else
449 nColSize=19;
451 else if(aVal.NanoSeconds % 100000000 == 0)
452 nColSize = 21;
453 else if(aVal.NanoSeconds % 10000000 == 0)
454 nColSize = 22;
455 else if(aVal.NanoSeconds % 1000000 == 0)
456 nColSize = 23;
457 else if(aVal.NanoSeconds % 100000 == 0)
458 nColSize = 24;
459 else if(aVal.NanoSeconds % 10000 == 0)
460 nColSize = 25;
461 else if(aVal.NanoSeconds % 1000 == 0)
462 nColSize = 26;
463 else if(aVal.NanoSeconds % 100 == 0)
464 nColSize = 27;
465 else if(aVal.NanoSeconds % 10 == 0)
466 nColSize = 28;
467 else
468 nColSize = 29;
470 TIMESTAMP_STRUCT x(OTools::DateTimeToTimestamp(aVal));
471 setScalarParameter<TIMESTAMP_STRUCT&>(parameterIndex, DataType::TIMESTAMP, nColSize, x);
475 void SAL_CALL OPreparedStatement::setDouble( sal_Int32 parameterIndex, double x ) throw(SQLException, RuntimeException, std::exception)
477 setScalarParameter(parameterIndex, DataType::DOUBLE, 15, x);
482 void SAL_CALL OPreparedStatement::setFloat( sal_Int32 parameterIndex, float x ) throw(SQLException, RuntimeException, std::exception)
484 setScalarParameter(parameterIndex, DataType::FLOAT, 15, x);
488 void SAL_CALL OPreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x ) throw(SQLException, RuntimeException, std::exception)
490 setScalarParameter(parameterIndex, DataType::INTEGER, 10, x);
494 void SAL_CALL OPreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x ) throw(SQLException, RuntimeException, std::exception)
498 setScalarParameter(parameterIndex, DataType::BIGINT, 19, x);
500 catch(SQLException&)
502 setString(parameterIndex, ORowSetValue(x));
507 void SAL_CALL OPreparedStatement::setNull( sal_Int32 parameterIndex, const sal_Int32 _nType ) throw(SQLException, RuntimeException, std::exception)
509 ::osl::MutexGuard aGuard( m_aMutex );
510 setParameterPre(parameterIndex);
512 OSL_VERIFY(allocBindBuf(parameterIndex, 0) == NULL);
513 SQLLEN * const lenBuf = getLengthBuf (parameterIndex);
514 *lenBuf = SQL_NULL_DATA;
517 SQLSMALLINT fCType;
518 SQLSMALLINT fSqlType;
520 OTools::getBindTypes( useWChar,
521 m_pConnection->useOldDateFormat(),
522 OTools::jdbcTypeToOdbc(_nType),
523 fCType,
524 fSqlType);
526 SQLRETURN nReturn = N3SQLBindParameter( m_aStatementHandle,
527 static_cast<SQLUSMALLINT>(parameterIndex),
528 SQL_PARAM_INPUT,
529 fCType,
530 fSqlType,
533 NULL,
535 lenBuf
537 OTools::ThrowException(m_pConnection,nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this);
541 void SAL_CALL OPreparedStatement::setClob( sal_Int32 parameterIndex, const Reference< XClob >& x ) throw(SQLException, RuntimeException, std::exception)
543 if ( x.is() )
544 setStream(parameterIndex, x->getCharacterStream(), x->length(), DataType::LONGVARCHAR);
548 void SAL_CALL OPreparedStatement::setBlob( sal_Int32 parameterIndex, const Reference< XBlob >& x ) throw(SQLException, RuntimeException, std::exception)
550 if ( x.is() )
551 setStream(parameterIndex, x->getBinaryStream(), x->length(), DataType::LONGVARBINARY);
555 void SAL_CALL OPreparedStatement::setArray( sal_Int32 /*parameterIndex*/, const Reference< XArray >& /*x*/ ) throw(SQLException, RuntimeException, std::exception)
557 ::dbtools::throwFunctionNotSupportedException( "XParameters::setArray", *this );
561 void SAL_CALL OPreparedStatement::setRef( sal_Int32 /*parameterIndex*/, const Reference< XRef >& /*x*/ ) throw(SQLException, RuntimeException, std::exception)
563 ::dbtools::throwFunctionNotSupportedException( "XParameters::setRef", *this );
566 void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 sqlType, sal_Int32 scale ) throw(SQLException, RuntimeException, std::exception)
568 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
569 ::osl::MutexGuard aGuard( m_aMutex );
571 prepareStatement();
572 // For each known SQL Type, call the appropriate
573 // set routine
575 switch (sqlType)
577 case DataType::CHAR:
578 case DataType::VARCHAR:
579 case DataType::LONGVARCHAR:
580 if(x.hasValue())
582 OUString sStr;
583 x >>= sStr;
584 setParameter(parameterIndex, sqlType, scale, sStr);
586 else
587 setNull(parameterIndex,sqlType);
588 break;
589 case DataType::DECIMAL:
590 case DataType::NUMERIC:
591 if(x.hasValue())
593 ORowSetValue aValue;
594 aValue.fill(x);
595 // TODO: make sure that this calls the string overload
596 setParameter(parameterIndex, sqlType, scale, aValue);
598 else
599 setNull(parameterIndex,sqlType);
600 break;
601 default:
602 ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale);
607 void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& /*typeName*/ ) throw(SQLException, RuntimeException, std::exception)
609 setNull(parameterIndex,sqlType);
613 void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x ) throw(SQLException, RuntimeException, std::exception)
615 if (!::dbtools::implSetObject(this, parameterIndex, x))
616 { // there is no other setXXX call which can handle the value in x
617 throw SQLException();
622 void SAL_CALL OPreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x ) throw(SQLException, RuntimeException, std::exception)
624 setScalarParameter(parameterIndex, DataType::SMALLINT, 5, x);
628 void SAL_CALL OPreparedStatement::setBytes( sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x ) throw(SQLException, RuntimeException, std::exception)
630 setParameter(parameterIndex, DataType::BINARY, x);
635 void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 parameterIndex, const Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ) throw(SQLException, RuntimeException, std::exception)
637 // LEM: It is quite unclear to me what the interface here is.
638 // The XInputStream provides *bytes*, not characters.
639 setStream(parameterIndex, x, length, DataType::LONGVARCHAR);
643 void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ) throw(SQLException, RuntimeException, std::exception)
645 setStream(parameterIndex, x, length, DataType::LONGVARBINARY);
649 void SAL_CALL OPreparedStatement::clearParameters( ) throw(SQLException, RuntimeException, std::exception)
651 ::osl::MutexGuard aGuard( m_aMutex );
652 prepareStatement();
653 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
654 SQLRETURN nRet = N3SQLFreeStmt (m_aStatementHandle, SQL_RESET_PARAMS);
655 nRet = N3SQLFreeStmt (m_aStatementHandle, SQL_UNBIND);
656 OSL_UNUSED(nRet);
659 void SAL_CALL OPreparedStatement::clearBatch( ) throw(SQLException, RuntimeException, std::exception)
661 ::dbtools::throwFunctionNotSupportedException( "XPreparedBatchExecution::clearBatch", *this );
662 // clearParameters( );
663 // m_aBatchList.erase();
667 void SAL_CALL OPreparedStatement::addBatch( ) throw(SQLException, RuntimeException, std::exception)
669 ::dbtools::throwFunctionNotSupportedException( "XPreparedBatchExecution::addBatch", *this );
673 Sequence< sal_Int32 > SAL_CALL OPreparedStatement::executeBatch( ) throw(SQLException, RuntimeException, std::exception)
675 ::dbtools::throwFunctionNotSupportedException( "XPreparedBatchExecution::executeBatch", *this );
676 // not reached, but keep -Werror happy
677 return Sequence< sal_Int32 > ();
682 // methods
686 // initBoundParam
687 // Initialize the bound parameter objects
690 void OPreparedStatement::initBoundParam () throw(SQLException)
692 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
693 // Get the number of parameters
694 numParams = 0;
695 N3SQLNumParams (m_aStatementHandle,&numParams);
697 // There are parameter markers, allocate the bound
698 // parameter objects
700 if (numParams > 0)
702 // Allocate an array of bound parameter objects
704 boundParams = new OBoundParam[numParams];
711 // allocBindBuf
712 // Allocate storage for the permanent data buffer for the bound
713 // parameter.
716 void* OPreparedStatement::allocBindBuf( sal_Int32 index,sal_Int32 bufLen)
718 void* b = NULL;
720 // Sanity check the parameter number
722 if ((index >= 1) && (index <= numParams))
724 b = boundParams[index - 1].allocBindDataBuffer(bufLen);
727 return b;
732 // getLengthBuf
733 // Gets the length buffer for the given parameter index
736 SQLLEN* OPreparedStatement::getLengthBuf (sal_Int32 index)
738 SQLLEN* b = NULL;
740 // Sanity check the parameter number
742 if ((index >= 1) &&
743 (index <= numParams))
745 b = boundParams[index - 1].getBindLengthBuffer ();
748 return b;
753 // putParamData
754 // Puts parameter data from a previously bound input stream. The
755 // input stream was bound using SQL_LEN_DATA_AT_EXEC.
758 void OPreparedStatement::putParamData (sal_Int32 index) throw(SQLException)
760 // Sanity check the parameter index
761 if ((index < 1) ||
762 (index > numParams))
764 return;
767 // We'll transfer up to MAX_PUT_DATA_LENGTH at a time
768 Sequence< sal_Int8 > buf( MAX_PUT_DATA_LENGTH );
770 // Get the information about the input stream
772 Reference< XInputStream> inputStream = boundParams[index - 1].getInputStream ();
773 if ( !inputStream.is() )
775 ::connectivity::SharedResources aResources;
776 const OUString sError( aResources.getResourceString(STR_NO_INPUTSTREAM));
777 throw SQLException (sError, *this,OUString(),0,Any());
780 sal_Int32 maxBytesLeft = boundParams[index - 1].getInputStreamLen ();
782 // Loop while more data from the input stream
783 sal_Int32 haveRead = 0;
789 sal_Int32 toReadThisRound = ::std::min( MAX_PUT_DATA_LENGTH, maxBytesLeft );
791 // Read some data from the input stream
792 haveRead = inputStream->readBytes( buf, toReadThisRound );
793 OSL_ENSURE( haveRead == buf.getLength(), "OPreparedStatement::putParamData: inconsistency!" );
795 if ( !haveRead )
796 // no more data in the stream - the given stream length was a maximum which could not be
797 // fulfilled by the stream
798 break;
800 // Put the data
801 OSL_ENSURE( m_aStatementHandle, "OPreparedStatement::putParamData: StatementHandle is null!" );
802 N3SQLPutData ( m_aStatementHandle, buf.getArray(), buf.getLength() );
804 // decrement the number of bytes still needed
805 maxBytesLeft -= haveRead;
807 while ( maxBytesLeft > 0 );
809 catch (const IOException& ex)
812 // If an I/O exception was generated, turn
813 // it into a SQLException
815 throw SQLException(ex.Message,*this,OUString(),0,Any());
821 // setStream
822 // Sets an input stream as a parameter, using the given SQL type
825 void OPreparedStatement::setStream(
826 sal_Int32 ParameterIndex,
827 const Reference< XInputStream>& x,
828 SQLLEN length,
829 sal_Int32 _nType)
830 throw(SQLException)
832 ::osl::MutexGuard aGuard( m_aMutex );
833 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
836 prepareStatement();
838 checkParameterIndex(ParameterIndex);
839 // Get the buffer needed for the length
841 SQLLEN * const lenBuf = getLengthBuf(ParameterIndex);
843 // Allocate a new buffer for the parameter data. This buffer
844 // will be returned by SQLParamData (it is set to the parameter
845 // number, a sal_Int32)
847 sal_Int32* dataBuf = static_cast<sal_Int32*>( allocBindBuf(ParameterIndex, sizeof(ParameterIndex)) );
848 *dataBuf = ParameterIndex;
850 // Bind the parameter with SQL_LEN_DATA_AT_EXEC
851 *lenBuf = SQL_LEN_DATA_AT_EXEC (length);
853 SQLSMALLINT fCType, fSqlType;
854 OTools::getBindTypes(useWChar, m_pConnection->useOldDateFormat(), OTools::jdbcTypeToOdbc(_nType), fCType, fSqlType);
857 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
858 N3SQLBindParameter(m_aStatementHandle,
859 static_cast<SQLUSMALLINT>(ParameterIndex),
860 SQL_PARAM_INPUT,
861 fCType,
862 fSqlType,
863 length,
864 invalid_scale,
865 dataBuf,
866 sizeof(ParameterIndex),
867 lenBuf);
869 // Save the input stream
870 boundParams[ParameterIndex - 1].setInputStream (x, length);
876 void OPreparedStatement::FreeParams()
878 numParams = 0;
879 delete [] boundParams;
880 boundParams = NULL;
883 void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) throw (Exception, std::exception)
887 switch(nHandle)
889 case PROPERTY_ID_RESULTSETCONCURRENCY:
890 if(!isPrepared())
891 setResultSetConcurrency(comphelper::getINT32(rValue));
892 break;
893 case PROPERTY_ID_RESULTSETTYPE:
894 if(!isPrepared())
895 setResultSetType(comphelper::getINT32(rValue));
896 break;
897 case PROPERTY_ID_FETCHDIRECTION:
898 if(!isPrepared())
899 setFetchDirection(comphelper::getINT32(rValue));
900 break;
901 case PROPERTY_ID_USEBOOKMARKS:
902 if(!isPrepared())
903 setUsingBookmarks(comphelper::getBOOL(rValue));
904 break;
905 default:
906 OStatement_Base::setFastPropertyValue_NoBroadcast(nHandle,rValue);
909 catch(const SQLException&)
911 // throw Exception(e.Message,*this);
915 void OPreparedStatement::prepareStatement()
917 if(!isPrepared())
919 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
920 OString aSql(OUStringToOString(m_sSqlStatement,getOwnConnection()->getTextEncoding()));
921 SQLRETURN nReturn = N3SQLPrepare(m_aStatementHandle,(SDB_ODBC_CHAR *) aSql.getStr(),aSql.getLength());
922 OTools::ThrowException(m_pConnection,nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this);
923 m_bPrepared = true;
924 initBoundParam();
928 void OPreparedStatement::checkParameterIndex(sal_Int32 _parameterIndex)
930 if( _parameterIndex > numParams ||
931 _parameterIndex < 1 ||
932 _parameterIndex > std::numeric_limits<SQLUSMALLINT>::max() )
934 ::connectivity::SharedResources aResources;
935 const OUString sError( aResources.getResourceStringWithSubstitution(STR_WRONG_PARAM_INDEX,
936 "$pos$", OUString::number(_parameterIndex),
937 "$count$", OUString::number(numParams)
939 SQLException aNext(sError,*this, OUString(),0,Any());
941 ::dbtools::throwInvalidIndexException(*this,makeAny(aNext));
945 OResultSet* OPreparedStatement::createResulSet()
947 OResultSet* pReturn = new OResultSet(m_aStatementHandle,this);
948 pReturn->setMetaData(getMetaData());
949 return pReturn;
953 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */