bump product version to 7.2.5.1
[LibreOffice.git] / connectivity / source / drivers / odbc / OPreparedStatement.cxx
blobaa01e2ea936a4bbb78548f43dba5e7d15d1d27c2
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 <string.h>
22 #include <osl/diagnose.h>
23 #include <odbc/OPreparedStatement.hxx>
24 #include <odbc/OBoundParam.hxx>
25 #include <com/sun/star/io/IOException.hpp>
26 #include <com/sun/star/sdbc/DataType.hpp>
27 #include <odbc/OTools.hxx>
28 #include <odbc/OResultSet.hxx>
29 #include <odbc/OResultSetMetaData.hxx>
30 #include <comphelper/sequence.hxx>
31 #include <connectivity/dbtools.hxx>
32 #include <comphelper/types.hxx>
33 #include <connectivity/FValue.hxx>
34 #include <strings.hrc>
35 #include <memory>
36 #include <type_traits>
38 using namespace ::comphelper;
39 using namespace connectivity;
40 using namespace connectivity::odbc;
41 using namespace com::sun::star::uno;
42 using namespace com::sun::star::lang;
43 using namespace com::sun::star::beans;
44 using namespace com::sun::star::sdbc;
45 using namespace com::sun::star::sdbcx;
46 using namespace com::sun::star::container;
47 using namespace com::sun::star::io;
48 using namespace com::sun::star::util;
50 IMPLEMENT_SERVICE_INFO(OPreparedStatement,"com.sun.star.sdbcx.OPreparedStatement","com.sun.star.sdbc.PreparedStatement");
52 namespace
54 // for now, never use wchar,
55 // but most of code is prepared to handle it
56 // in case we make this configurable
57 const bool bUseWChar = false;
60 OPreparedStatement::OPreparedStatement( OConnection* _pConnection,const OUString& sql)
61 :OStatement_BASE2(_pConnection)
62 ,numParams(0)
63 ,m_bPrepared(false)
65 m_sSqlStatement = sql;
68 OPreparedStatement::~OPreparedStatement()
72 void SAL_CALL OPreparedStatement::acquire() noexcept
74 OStatement_BASE2::acquire();
77 void SAL_CALL OPreparedStatement::release() noexcept
79 OStatement_BASE2::release();
82 Any SAL_CALL OPreparedStatement::queryInterface( const Type & rType )
84 Any aRet = OStatement_BASE2::queryInterface(rType);
85 return aRet.hasValue() ? aRet : OPreparedStatement_BASE::queryInterface(rType);
88 css::uno::Sequence< css::uno::Type > SAL_CALL OPreparedStatement::getTypes( )
90 return ::comphelper::concatSequences(OPreparedStatement_BASE::getTypes(),OStatement_BASE2::getTypes());
94 Reference< XResultSetMetaData > SAL_CALL OPreparedStatement::getMetaData( )
96 ::osl::MutexGuard aGuard( m_aMutex );
97 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
100 prepareStatement();
101 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
102 if(!m_xMetaData.is())
103 m_xMetaData = new OResultSetMetaData(getOwnConnection(),m_aStatementHandle);
104 return m_xMetaData;
108 void SAL_CALL OPreparedStatement::close( )
110 ::osl::MutexGuard aGuard( m_aMutex );
111 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
114 // Close/clear our result set
115 clearMyResultSet ();
117 // Reset last warning message
119 try {
120 clearWarnings ();
121 OStatement_BASE2::close();
122 FreeParams();
124 catch (SQLException &) {
125 // If we get an error, ignore
128 // Remove this Statement object from the Connection object's
129 // list
133 sal_Bool SAL_CALL OPreparedStatement::execute( )
135 ::osl::MutexGuard aGuard( m_aMutex );
136 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
138 // Reset warnings
140 clearWarnings ();
142 // Reset the statement handle, warning and saved Resultset
144 reset();
146 // Call SQLExecute
147 prepareStatement();
149 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
152 SQLRETURN nReturn = N3SQLExecute(m_aStatementHandle);
154 OTools::ThrowException(m_pConnection.get(),nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this);
155 bool needData = nReturn == SQL_NEED_DATA;
157 // Now loop while more data is needed (i.e. a data-at-
158 // execution parameter was given). For each parameter
159 // that needs data, put the data from the input stream.
161 while (needData) {
163 // Get the parameter number that requires data
165 sal_Int32* paramIndex = nullptr;
166 N3SQLParamData(m_aStatementHandle, reinterpret_cast<SQLPOINTER*>(&paramIndex));
168 // If the parameter index is -1, there is no
169 // more data required
171 if ( !paramIndex || ( *paramIndex == -1 ) )
172 needData = false;
173 else
175 // Now we have the proper parameter
176 // index, get the data from the input
177 // stream and do a SQLPutData
178 putParamData (*paramIndex);
183 catch (const SQLWarning&)
187 // Now determine if there is a result set associated with
188 // the SQL statement that was executed. Get the column
189 // count, and if it is not zero, there is a result set.
192 return getColumnCount() > 0;
196 sal_Int32 SAL_CALL OPreparedStatement::executeUpdate( )
198 ::osl::MutexGuard aGuard( m_aMutex );
199 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
201 sal_Int32 numRows = -1;
203 prepareStatement();
204 // Execute the statement. If execute returns sal_False, a
205 // row count exists.
207 if (!execute())
208 numRows = getUpdateCount ();
209 else
211 // No update count was produced (a ResultSet was). Raise
212 // an exception
213 m_pConnection->throwGenericSQLException(STR_NO_ROWCOUNT,*this);
215 return numRows;
219 void SAL_CALL OPreparedStatement::setString( sal_Int32 parameterIndex, const OUString& x )
221 setParameter(parameterIndex, DataType::CHAR, invalid_scale, x);
225 Reference< XConnection > SAL_CALL OPreparedStatement::getConnection( )
227 ::osl::MutexGuard aGuard( m_aMutex );
228 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
230 return m_pConnection;
234 Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery( )
236 ::osl::MutexGuard aGuard( m_aMutex );
237 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
239 Reference< XResultSet > rs;
241 prepareStatement();
243 if (execute())
244 rs = getResultSet(false);
245 else
247 // No ResultSet was produced. Raise an exception
248 m_pConnection->throwGenericSQLException(STR_NO_RESULTSET,*this);
250 return rs;
254 void SAL_CALL OPreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x )
256 // Set the parameter as if it were an integer
257 setInt (parameterIndex, x ? 1 : 0 );
260 // The MutexGuard must _already_ be taken!
261 void OPreparedStatement::setParameterPre(sal_Int32 parameterIndex)
263 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
264 prepareStatement();
265 checkParameterIndex(parameterIndex);
266 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
270 template <typename T> void OPreparedStatement::setScalarParameter(const sal_Int32 parameterIndex, const sal_Int32 i_nType, const SQLULEN i_nColSize, const T i_Value)
272 setScalarParameter(parameterIndex, i_nType, i_nColSize, invalid_scale, i_Value);
276 template <typename T> void OPreparedStatement::setScalarParameter(const sal_Int32 parameterIndex, const sal_Int32 i_nType, const SQLULEN i_nColSize, sal_Int32 i_nScale, const T i_Value)
278 ::osl::MutexGuard aGuard( m_aMutex );
279 setParameterPre(parameterIndex);
281 typedef typename std::remove_reference<T>::type TnoRef;
283 TnoRef *bindBuf = static_cast< TnoRef* >( allocBindBuf(parameterIndex, sizeof(i_Value)) );
284 *bindBuf = i_Value;
286 setParameter(parameterIndex, i_nType, i_nColSize, i_nScale, bindBuf, sizeof(i_Value), sizeof(i_Value));
290 void OPreparedStatement::setParameter(const sal_Int32 parameterIndex, const sal_Int32 _nType, const sal_Int16 _nScale, const OUString &_sData)
292 ::osl::MutexGuard aGuard( m_aMutex );
293 setParameterPre(parameterIndex);
295 assert (_nType == DataType::VARCHAR || _nType == DataType::CHAR || _nType == DataType::DECIMAL || _nType == DataType::NUMERIC);
297 sal_Int32 nCharLen;
298 sal_Int32 nByteLen;
299 void *pData;
300 if (bUseWChar)
303 * On Windows, wchar is 16 bits (UTF-16 encoding), the ODBC "W" variants functions take UTF-16 encoded strings
304 * and character lengths are number of UTF-16 codepoints.
305 * Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms716246%28v=vs.85%29.aspx
306 * ODBC Programmer's reference > Developing Applications > Programming Considerations > Unicode > Unicode Function Arguments
307 * http://support.microsoft.com/kb/294169
309 * UnixODBC can be configured at compile-time so that the "W" variants expect
310 * UTF-16 or UTF-32 encoded strings, and character lengths are number of codepoints.
311 * However, UTF-16 is the default, what all/most distributions do
312 * and the established API that most drivers implement.
313 * As wchar is often 32 bits, this differs from C-style strings of wchar!
315 * On MacOS X, the "W" variants use wchar_t, which is UCS4
317 * Our internal OUString storage is always UTF-16, so no conversion to do here.
319 static_assert(sizeof (SQLWCHAR) == 2 || sizeof (SQLWCHAR) == 4, "must be 2 or 4");
320 if (sizeof (SQLWCHAR) == 2)
322 nCharLen = _sData.getLength();
323 nByteLen = 2 * nCharLen;
324 pData = allocBindBuf(parameterIndex, nByteLen);
325 memcpy(pData, _sData.getStr(), nByteLen);
327 else
329 pData = allocBindBuf(parameterIndex, _sData.getLength() * 4);
330 sal_uInt32* pCursor = static_cast<sal_uInt32*>(pData);
331 nCharLen = 0;
332 for (sal_Int32 i = 0; i != _sData.getLength();)
334 *pCursor++ = _sData.iterateCodePoints(&i);
335 nCharLen += 1;
337 nByteLen = 4 * nCharLen;
340 else
342 assert(getOwnConnection()->getTextEncoding() != RTL_TEXTENCODING_UCS2 &&
343 getOwnConnection()->getTextEncoding() != RTL_TEXTENCODING_UCS4);
344 OString sOData(
345 OUStringToOString(_sData, getOwnConnection()->getTextEncoding()));
346 nCharLen = nByteLen = sOData.getLength();
347 pData = allocBindBuf(parameterIndex, nByteLen);
348 memcpy(pData, sOData.getStr(), nByteLen);
351 setParameter( parameterIndex, _nType, nCharLen, _nScale, pData, nByteLen, nByteLen );
354 void OPreparedStatement::setParameter(const sal_Int32 parameterIndex, const sal_Int32 _nType, const Sequence< sal_Int8 > &x)
356 ::osl::MutexGuard aGuard( m_aMutex );
357 setParameterPre(parameterIndex);
359 assert(_nType == DataType::BINARY || _nType == DataType::VARBINARY);
361 // don't copy the sequence, just point the ODBC directly at the sequence's storage array
362 // Why BINARY/Sequence is treated differently than strings (which are copied), I'm not sure
363 OSL_VERIFY(allocBindBuf(parameterIndex, 0) == nullptr);
364 boundParams[parameterIndex-1].setSequence(x); // this ensures that the sequence stays alive
366 setParameter( parameterIndex, _nType, x.getLength(), invalid_scale, x.getConstArray(), x.getLength(), x.getLength() );
369 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)
371 SQLSMALLINT fCType, fSqlType;
372 OTools::getBindTypes(bUseWChar, m_pConnection->useOldDateFormat(), OTools::jdbcTypeToOdbc(_nType), fCType, fSqlType);
374 SQLLEN& rDataLen = boundParams[parameterIndex-1].getBindLengthBuffer();
375 rDataLen = _nDataLen;
377 SQLRETURN nRetcode;
378 nRetcode = (*reinterpret_cast<T3SQLBindParameter>(m_pConnection->getOdbcFunction(ODBC3SQLFunctionId::BindParameter)))(
379 m_aStatementHandle,
380 // checkParameterIndex guarantees this is safe
381 static_cast<SQLUSMALLINT>(parameterIndex),
382 SQL_PARAM_INPUT,
383 fCType,
384 fSqlType,
385 _nColumnSize,
386 _nScale,
387 // we trust the ODBC driver not to touch it because SQL_PARAM_INPUT
388 const_cast<void*>(_pData),
389 _nDataAllocLen,
390 &rDataLen);
392 OTools::ThrowException(m_pConnection.get(), nRetcode, m_aStatementHandle, SQL_HANDLE_STMT, *this);
395 void SAL_CALL OPreparedStatement::setByte( const sal_Int32 parameterIndex, const sal_Int8 x )
397 setScalarParameter(parameterIndex, DataType::TINYINT, 3, 0, x);
400 void SAL_CALL OPreparedStatement::setDate( sal_Int32 parameterIndex, const Date& aData )
402 DATE_STRUCT x(OTools::DateToOdbcDate(aData));
403 setScalarParameter<DATE_STRUCT&>(parameterIndex, DataType::DATE, 10, x);
406 void SAL_CALL OPreparedStatement::setTime( sal_Int32 parameterIndex, const css::util::Time& aVal )
408 SQLULEN nColSize;
409 if(aVal.NanoSeconds == 0)
410 nColSize = 8;
411 else if(aVal.NanoSeconds % 100000000 == 0)
412 nColSize = 10;
413 else if(aVal.NanoSeconds % 10000000 == 0)
414 nColSize = 11;
415 else if(aVal.NanoSeconds % 1000000 == 0)
416 nColSize = 12;
417 else if(aVal.NanoSeconds % 100000 == 0)
418 nColSize = 13;
419 else if(aVal.NanoSeconds % 10000 == 0)
420 nColSize = 14;
421 else if(aVal.NanoSeconds % 1000 == 0)
422 nColSize = 15;
423 else if(aVal.NanoSeconds % 100 == 0)
424 nColSize = 16;
425 else if(aVal.NanoSeconds % 10 == 0)
426 nColSize = 17;
427 else
428 nColSize = 18;
429 TIME_STRUCT x(OTools::TimeToOdbcTime(aVal));
430 setScalarParameter<TIME_STRUCT&>(parameterIndex, DataType::TIME, nColSize, (nColSize == 8)? 0 : nColSize-9, x);
434 void SAL_CALL OPreparedStatement::setTimestamp( sal_Int32 parameterIndex, const DateTime& aVal )
436 SQLULEN nColSize;
437 if(aVal.NanoSeconds == 0)
439 if (aVal.Seconds == 0)
440 nColSize=16;
441 else
442 nColSize=19;
444 else if(aVal.NanoSeconds % 100000000 == 0)
445 nColSize = 21;
446 else if(aVal.NanoSeconds % 10000000 == 0)
447 nColSize = 22;
448 else if(aVal.NanoSeconds % 1000000 == 0)
449 nColSize = 23;
450 else if(aVal.NanoSeconds % 100000 == 0)
451 nColSize = 24;
452 else if(aVal.NanoSeconds % 10000 == 0)
453 nColSize = 25;
454 else if(aVal.NanoSeconds % 1000 == 0)
455 nColSize = 26;
456 else if(aVal.NanoSeconds % 100 == 0)
457 nColSize = 27;
458 else if(aVal.NanoSeconds % 10 == 0)
459 nColSize = 28;
460 else
461 nColSize = 29;
463 TIMESTAMP_STRUCT x(OTools::DateTimeToTimestamp(aVal));
464 setScalarParameter<TIMESTAMP_STRUCT&>(parameterIndex, DataType::TIMESTAMP, nColSize, (nColSize <= 19)? 0 : nColSize-20, x);
468 void SAL_CALL OPreparedStatement::setDouble( sal_Int32 parameterIndex, double x )
470 setScalarParameter(parameterIndex, DataType::DOUBLE, 15, x);
474 void SAL_CALL OPreparedStatement::setFloat( sal_Int32 parameterIndex, float x )
476 setScalarParameter(parameterIndex, DataType::FLOAT, 15, x);
480 void SAL_CALL OPreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x )
482 setScalarParameter(parameterIndex, DataType::INTEGER, 10, 0, x);
486 void SAL_CALL OPreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x )
490 setScalarParameter(parameterIndex, DataType::BIGINT, 19, 0, x);
492 catch(SQLException&)
494 setString(parameterIndex, ORowSetValue(x));
499 void SAL_CALL OPreparedStatement::setNull( sal_Int32 parameterIndex, const sal_Int32 _nType )
501 ::osl::MutexGuard aGuard( m_aMutex );
502 setParameterPre(parameterIndex);
504 OSL_VERIFY(allocBindBuf(parameterIndex, 0) == nullptr);
505 SQLLEN * const lenBuf = getLengthBuf (parameterIndex);
506 *lenBuf = SQL_NULL_DATA;
509 SQLSMALLINT fCType;
510 SQLSMALLINT fSqlType;
512 OTools::getBindTypes( bUseWChar,
513 m_pConnection->useOldDateFormat(),
514 OTools::jdbcTypeToOdbc(_nType),
515 fCType,
516 fSqlType);
518 SQLRETURN nReturn = N3SQLBindParameter( m_aStatementHandle,
519 static_cast<SQLUSMALLINT>(parameterIndex),
520 SQL_PARAM_INPUT,
521 fCType,
522 fSqlType,
525 nullptr,
527 lenBuf
529 OTools::ThrowException(m_pConnection.get(),nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this);
533 void SAL_CALL OPreparedStatement::setClob( sal_Int32 parameterIndex, const Reference< XClob >& x )
535 if ( x.is() )
536 setStream(parameterIndex, x->getCharacterStream(), x->length(), DataType::LONGVARCHAR);
540 void SAL_CALL OPreparedStatement::setBlob( sal_Int32 parameterIndex, const Reference< XBlob >& x )
542 if ( x.is() )
543 setStream(parameterIndex, x->getBinaryStream(), x->length(), DataType::LONGVARBINARY);
547 void SAL_CALL OPreparedStatement::setArray( sal_Int32 /*parameterIndex*/, const Reference< XArray >& /*x*/ )
549 ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setArray", *this );
553 void SAL_CALL OPreparedStatement::setRef( sal_Int32 /*parameterIndex*/, const Reference< XRef >& /*x*/ )
555 ::dbtools::throwFunctionNotSupportedSQLException( "XParameters::setRef", *this );
558 void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 sqlType, sal_Int32 scale )
560 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
561 ::osl::MutexGuard aGuard( m_aMutex );
563 prepareStatement();
564 // For each known SQL Type, call the appropriate
565 // set routine
567 switch (sqlType)
569 case DataType::CHAR:
570 case DataType::VARCHAR:
571 case DataType::LONGVARCHAR:
572 if(x.hasValue())
574 OUString sStr;
575 x >>= sStr;
576 setParameter(parameterIndex, sqlType, scale, sStr);
578 else
579 setNull(parameterIndex,sqlType);
580 break;
581 case DataType::DECIMAL:
582 case DataType::NUMERIC:
583 if(x.hasValue())
585 ORowSetValue aValue;
586 aValue.fill(x);
587 // TODO: make sure that this calls the string overload
588 setParameter(parameterIndex, sqlType, scale, aValue);
590 else
591 setNull(parameterIndex,sqlType);
592 break;
593 default:
594 ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale);
599 void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const OUString& /*typeName*/ )
601 setNull(parameterIndex,sqlType);
605 void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x )
607 if (!::dbtools::implSetObject(this, parameterIndex, x))
608 { // there is no other setXXX call which can handle the value in x
609 throw SQLException();
614 void SAL_CALL OPreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x )
616 setScalarParameter(parameterIndex, DataType::SMALLINT, 5, 0, x);
620 void SAL_CALL OPreparedStatement::setBytes( sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x )
622 setParameter(parameterIndex, DataType::BINARY, x);
626 void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
628 // LEM: It is quite unclear to me what the interface here is.
629 // The XInputStream provides *bytes*, not characters.
630 setStream(parameterIndex, x, length, DataType::LONGVARCHAR);
634 void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const Reference< css::io::XInputStream >& x, sal_Int32 length )
636 setStream(parameterIndex, x, length, DataType::LONGVARBINARY);
640 void SAL_CALL OPreparedStatement::clearParameters( )
642 ::osl::MutexGuard aGuard( m_aMutex );
643 prepareStatement();
644 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
645 N3SQLFreeStmt (m_aStatementHandle, SQL_RESET_PARAMS);
646 N3SQLFreeStmt (m_aStatementHandle, SQL_UNBIND);
649 void SAL_CALL OPreparedStatement::clearBatch( )
651 ::dbtools::throwFunctionNotSupportedSQLException( "XPreparedBatchExecution::clearBatch", *this );
652 // clearParameters( );
653 // m_aBatchVector.erase();
657 void SAL_CALL OPreparedStatement::addBatch( )
659 ::dbtools::throwFunctionNotSupportedSQLException( "XPreparedBatchExecution::addBatch", *this );
663 Sequence< sal_Int32 > SAL_CALL OPreparedStatement::executeBatch( )
665 ::dbtools::throwFunctionNotSupportedSQLException( "XPreparedBatchExecution::executeBatch", *this );
666 // not reached, but keep -Werror happy
667 return Sequence< sal_Int32 > ();
671 // methods
674 // initBoundParam
675 // Initialize the bound parameter objects
678 void OPreparedStatement::initBoundParam ()
680 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
681 // Get the number of parameters
682 numParams = 0;
683 N3SQLNumParams (m_aStatementHandle,&numParams);
685 // There are parameter markers, allocate the bound
686 // parameter objects
688 if (numParams > 0)
690 boundParams.reset(new OBoundParam[numParams]);
695 // allocBindBuf
696 // Allocate storage for the permanent data buffer for the bound
697 // parameter.
700 void* OPreparedStatement::allocBindBuf( sal_Int32 index,sal_Int32 bufLen)
702 void* b = nullptr;
704 // Sanity check the parameter number
706 if ((index >= 1) && (index <= numParams))
708 b = boundParams[index - 1].allocBindDataBuffer(bufLen);
711 return b;
715 // getLengthBuf
716 // Gets the length buffer for the given parameter index
719 SQLLEN* OPreparedStatement::getLengthBuf (sal_Int32 index)
721 SQLLEN* b = nullptr;
723 // Sanity check the parameter number
725 if ((index >= 1) &&
726 (index <= numParams))
728 b = &boundParams[index - 1].getBindLengthBuffer ();
731 return b;
735 // putParamData
736 // Puts parameter data from a previously bound input stream. The
737 // input stream was bound using SQL_LEN_DATA_AT_EXEC.
738 void OPreparedStatement::putParamData (sal_Int32 index)
740 // Sanity check the parameter index
741 if ((index < 1) ||
742 (index > numParams))
744 return;
747 // We'll transfer up to MAX_PUT_DATA_LENGTH at a time
748 Sequence< sal_Int8 > buf( MAX_PUT_DATA_LENGTH );
750 // Get the information about the input stream
752 Reference< XInputStream> inputStream = boundParams[index - 1].getInputStream ();
753 if ( !inputStream.is() )
755 ::connectivity::SharedResources aResources;
756 const OUString sError( aResources.getResourceString(STR_NO_INPUTSTREAM));
757 throw SQLException (sError, *this,OUString(),0,Any());
760 sal_Int32 maxBytesLeft = boundParams[index - 1].getInputStreamLen ();
762 // Loop while more data from the input stream
763 sal_Int32 haveRead = 0;
769 sal_Int32 toReadThisRound = std::min( MAX_PUT_DATA_LENGTH, maxBytesLeft );
771 // Read some data from the input stream
772 haveRead = inputStream->readBytes( buf, toReadThisRound );
773 OSL_ENSURE( haveRead == buf.getLength(), "OPreparedStatement::putParamData: inconsistency!" );
775 if ( !haveRead )
776 // no more data in the stream - the given stream length was a maximum which could not be
777 // fulfilled by the stream
778 break;
780 // Put the data
781 OSL_ENSURE( m_aStatementHandle, "OPreparedStatement::putParamData: StatementHandle is null!" );
782 N3SQLPutData ( m_aStatementHandle, buf.getArray(), buf.getLength() );
784 // decrement the number of bytes still needed
785 maxBytesLeft -= haveRead;
787 while ( maxBytesLeft > 0 );
789 catch (const IOException& ex)
792 // If an I/O exception was generated, turn
793 // it into a SQLException
795 throw SQLException(ex.Message,*this,OUString(),0,Any());
799 // setStream
800 // Sets an input stream as a parameter, using the given SQL type
801 void OPreparedStatement::setStream(
802 sal_Int32 ParameterIndex,
803 const Reference< XInputStream>& x,
804 SQLLEN length,
805 sal_Int32 _nType)
807 ::osl::MutexGuard aGuard( m_aMutex );
808 checkDisposed(OStatement_BASE::rBHelper.bDisposed);
811 prepareStatement();
813 checkParameterIndex(ParameterIndex);
814 // Get the buffer needed for the length
816 SQLLEN * const lenBuf = getLengthBuf(ParameterIndex);
818 // Allocate a new buffer for the parameter data. This buffer
819 // will be returned by SQLParamData (it is set to the parameter
820 // number, a sal_Int32)
822 sal_Int32* dataBuf = static_cast<sal_Int32*>( allocBindBuf(ParameterIndex, sizeof(ParameterIndex)) );
823 *dataBuf = ParameterIndex;
825 // Bind the parameter with SQL_LEN_DATA_AT_EXEC
826 *lenBuf = SQL_LEN_DATA_AT_EXEC (length);
828 SQLSMALLINT fCType, fSqlType;
829 OTools::getBindTypes(bUseWChar, m_pConnection->useOldDateFormat(), OTools::jdbcTypeToOdbc(_nType), fCType, fSqlType);
832 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
833 N3SQLBindParameter(m_aStatementHandle,
834 static_cast<SQLUSMALLINT>(ParameterIndex),
835 SQL_PARAM_INPUT,
836 fCType,
837 fSqlType,
838 length,
839 invalid_scale,
840 dataBuf,
841 sizeof(ParameterIndex),
842 lenBuf);
844 // Save the input stream
845 boundParams[ParameterIndex - 1].setInputStream (x, length);
849 void OPreparedStatement::FreeParams()
851 numParams = 0;
852 boundParams.reset();
855 void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue)
859 switch(nHandle)
861 case PROPERTY_ID_RESULTSETCONCURRENCY:
862 if(!isPrepared())
863 setResultSetConcurrency(comphelper::getINT32(rValue));
864 break;
865 case PROPERTY_ID_RESULTSETTYPE:
866 if(!isPrepared())
867 setResultSetType(comphelper::getINT32(rValue));
868 break;
869 case PROPERTY_ID_FETCHDIRECTION:
870 if(!isPrepared())
871 setFetchDirection(comphelper::getINT32(rValue));
872 break;
873 case PROPERTY_ID_USEBOOKMARKS:
874 if(!isPrepared())
875 setUsingBookmarks(comphelper::getBOOL(rValue));
876 break;
877 default:
878 OStatement_Base::setFastPropertyValue_NoBroadcast(nHandle,rValue);
881 catch(const SQLException&)
883 // throw Exception(e.Message,*this);
887 void OPreparedStatement::prepareStatement()
889 if(!isPrepared())
891 OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!");
892 OString aSql(OUStringToOString(m_sSqlStatement,getOwnConnection()->getTextEncoding()));
893 SQLRETURN nReturn = N3SQLPrepare(m_aStatementHandle, reinterpret_cast<SDB_ODBC_CHAR *>(const_cast<char *>(aSql.getStr())), aSql.getLength());
894 OTools::ThrowException(m_pConnection.get(),nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this);
895 m_bPrepared = true;
896 initBoundParam();
900 void OPreparedStatement::checkParameterIndex(sal_Int32 _parameterIndex)
902 if( _parameterIndex > numParams ||
903 _parameterIndex < 1 ||
904 _parameterIndex > std::numeric_limits<SQLUSMALLINT>::max() )
906 ::connectivity::SharedResources aResources;
907 const OUString sError( aResources.getResourceStringWithSubstitution(STR_WRONG_PARAM_INDEX,
908 "$pos$", OUString::number(_parameterIndex),
909 "$count$", OUString::number(numParams)
911 SQLException aNext(sError,*this, OUString(),0,Any());
913 ::dbtools::throwInvalidIndexException(*this,makeAny(aNext));
917 rtl::Reference<OResultSet> OPreparedStatement::createResultSet()
919 rtl::Reference<OResultSet> pReturn = new OResultSet(m_aStatementHandle,this);
920 pReturn->setMetaData(getMetaData());
921 return pReturn;
925 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */