diff options
Diffstat (limited to 'connectivity/source/drivers/odbcbase/OPreparedStatement.cxx')
-rw-r--r-- | connectivity/source/drivers/odbcbase/OPreparedStatement.cxx | 973 |
1 files changed, 973 insertions, 0 deletions
diff --git a/connectivity/source/drivers/odbcbase/OPreparedStatement.cxx b/connectivity/source/drivers/odbcbase/OPreparedStatement.cxx new file mode 100644 index 000000000000..758b2fb38def --- /dev/null +++ b/connectivity/source/drivers/odbcbase/OPreparedStatement.cxx @@ -0,0 +1,973 @@ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_connectivity.hxx" + +#include <stdio.h> +#include <string.h> +#include <osl/diagnose.h> +#include "odbc/OPreparedStatement.hxx" +#include "odbc/OBoundParam.hxx" +#include <com/sun/star/sdbc/DataType.hpp> +#include "odbc/OTools.hxx" +#include "odbc/ODriver.hxx" +#include "odbc/OResultSet.hxx" +#include "odbc/OResultSetMetaData.hxx" +#include <cppuhelper/typeprovider.hxx> +#include <comphelper/sequence.hxx> +#include <com/sun/star/lang/DisposedException.hpp> +#include "connectivity/dbtools.hxx" +#include <comphelper/types.hxx> +#include "connectivity/FValue.hxx" +#include "resource/common_res.hrc" +#include "connectivity/sqlparse.hxx" + +using namespace ::comphelper; +using namespace connectivity; +using namespace connectivity::odbc; +using namespace com::sun::star::uno; +using namespace com::sun::star::lang; +using namespace com::sun::star::beans; +using namespace com::sun::star::sdbc; +using namespace com::sun::star::sdbcx; +using namespace com::sun::star::container; +using namespace com::sun::star::io; +using namespace com::sun::star::util; + +IMPLEMENT_SERVICE_INFO(OPreparedStatement,"com.sun.star.sdbcx.OPreparedStatement","com.sun.star.sdbc.PreparedStatement"); + + +OPreparedStatement::OPreparedStatement( OConnection* _pConnection,const ::rtl::OUString& sql) + :OStatement_BASE2(_pConnection) + ,numParams(0) + ,boundParams(NULL) + ,m_bPrepared(sal_False) +{ + m_sSqlStatement = sql; + try + { + if(_pConnection->isParameterSubstitutionEnabled()) + { + OSQLParser aParser(_pConnection->getDriver()->getORB()); + ::rtl::OUString sErrorMessage; + ::rtl::OUString sNewSql; + ::std::auto_ptr<OSQLParseNode> pNode( aParser.parseTree(sErrorMessage,sql) ); + if ( pNode.get() ) + { // special handling for parameters + OSQLParseNode::substituteParameterNames(pNode.get()); + pNode->parseNodeToStr( sNewSql, _pConnection ); + m_sSqlStatement = sNewSql; + } + } + } + catch(Exception&) + { + } +} +// ----------------------------------------------------------------------------- +void SAL_CALL OPreparedStatement::acquire() throw() +{ + OStatement_BASE2::acquire(); +} +// ----------------------------------------------------------------------------- +void SAL_CALL OPreparedStatement::release() throw() +{ + OStatement_BASE2::release(); +} +// ----------------------------------------------------------------------------- +Any SAL_CALL OPreparedStatement::queryInterface( const Type & rType ) throw(RuntimeException) +{ + Any aRet = OStatement_BASE2::queryInterface(rType); + return aRet.hasValue() ? aRet : OPreparedStatement_BASE::queryInterface(rType); +} +// ------------------------------------------------------------------------- +::com::sun::star::uno::Sequence< ::com::sun::star::uno::Type > SAL_CALL OPreparedStatement::getTypes( ) throw(::com::sun::star::uno::RuntimeException) +{ + return ::comphelper::concatSequences(OPreparedStatement_BASE::getTypes(),OStatement_BASE2::getTypes()); +} +// ------------------------------------------------------------------------- + +Reference< XResultSetMetaData > SAL_CALL OPreparedStatement::getMetaData( ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + prepareStatement(); + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + if(!m_xMetaData.is()) + m_xMetaData = new OResultSetMetaData(getOwnConnection(),m_aStatementHandle); + return m_xMetaData; +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::close( ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + // Close/clear our result set + clearMyResultSet (); + + // Reset last warning message + + try { + clearWarnings (); + OStatement_BASE2::close(); + FreeParams(); + } + catch (SQLException &) { + // If we get an error, ignore + } + + // Remove this Statement object from the Connection object's + // list +} +// ------------------------------------------------------------------------- + +sal_Bool SAL_CALL OPreparedStatement::execute( ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + sal_Bool needData = sal_False; + + // Reset warnings + + clearWarnings (); + + // Reset the statement handle, warning and saved Resultset + + reset(); + + // Call SQLExecute + prepareStatement(); + + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + try + { + SQLRETURN nReturn = N3SQLExecute(m_aStatementHandle); + + OTools::ThrowException(m_pConnection,nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this); + needData = nReturn == SQL_NEED_DATA; + + // Now loop while more data is needed (i.e. a data-at- + // execution parameter was given). For each parameter + // that needs data, put the data from the input stream. + + while (needData) { + + // Get the parameter number that requires data + + sal_Int32* paramIndex = 0; + nReturn = N3SQLParamData(m_aStatementHandle,(SQLPOINTER*)¶mIndex); + + // If the parameter index is -1, there is no + // more data required + + if ( !paramIndex || ( *paramIndex == -1 ) ) + needData = sal_False; + else + { + // Now we have the proper parameter + // index, get the data from the input + // stream and do a SQLPutData + putParamData (*paramIndex); + } + } + + } + catch (const SQLWarning&) + { + } + + // Now loop while more data is needed (i.e. a data-at- + // execution parameter was given). For each parameter + // that needs data, put the data from the input stream. + + while (needData) { + + // Get the parameter number that requires data + + sal_Int32* paramIndex = 0; + N3SQLParamData (m_aStatementHandle,(SQLPOINTER*)¶mIndex); + + // If the parameter index is -1, there is no more + // data required + + if (*paramIndex == -1) { + needData = sal_False; + } + else { + // Now we have the proper parameter index, + // get the data from the input stream + // and do a SQLPutData + putParamData(*paramIndex); + } + } + + // Now determine if there is a result set associated with + // the SQL statement that was executed. Get the column + // count, and if it is not zero, there is a result set. + + + return getColumnCount() > 0; +} +// ------------------------------------------------------------------------- + +sal_Int32 SAL_CALL OPreparedStatement::executeUpdate( ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + sal_Int32 numRows = -1; + + prepareStatement(); + // Execute the statement. If execute returns sal_False, a + // row count exists. + + if (!execute()) + numRows = getUpdateCount (); + else + { + // No update count was produced (a ResultSet was). Raise + // an exception + m_pConnection->throwGenericSQLException(STR_NO_ROWCOUNT,*this); + } + return numRows; +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setString( sal_Int32 parameterIndex, const ::rtl::OUString& x ) throw(SQLException, RuntimeException) +{ + ::rtl::OString aString(::rtl::OUStringToOString(x,getOwnConnection()->getTextEncoding())); + setParameter(parameterIndex,DataType::CHAR,aString.getLength(),(void*)&x); +} +// ------------------------------------------------------------------------- + +Reference< XConnection > SAL_CALL OPreparedStatement::getConnection( ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + return (Reference< XConnection >)m_pConnection; +} +// ------------------------------------------------------------------------- + +Reference< XResultSet > SAL_CALL OPreparedStatement::executeQuery( ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + Reference< XResultSet > rs = NULL; + + prepareStatement(); + + if (execute()) + rs = getResultSet(sal_False); + else + { + // No ResultSet was produced. Raise an exception + m_pConnection->throwGenericSQLException(STR_NO_RESULTSET,*this); + } + return rs; +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setBoolean( sal_Int32 parameterIndex, sal_Bool x ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + sal_Int32 value = 0; + + // If the parameter is sal_True, set the value to 1 + if (x) { + value = 1; + } + + // Set the parameter as if it were an integer + setInt (parameterIndex, value); +} +// ------------------------------------------------------------------------- +void OPreparedStatement::setParameter(sal_Int32 parameterIndex,sal_Int32 _nType,sal_Int32 _nSize,void* _pData) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + prepareStatement(); + // Allocate a buffer to be used in binding. This will be + // a 'permanent' buffer that the bridge will fill in with + // the bound data in native format. + + + checkParameterIndex(parameterIndex); + sal_Int32 nRealSize = _nSize; + SQLSMALLINT fSqlType = static_cast<SQLSMALLINT>(OTools::jdbcTypeToOdbc(_nType)); + switch(fSqlType) + { + case SQL_CHAR: + case SQL_VARCHAR: + case SQL_DECIMAL: + case SQL_NUMERIC: + ++nRealSize; + break; + case SQL_BINARY: + case SQL_VARBINARY: + nRealSize=1; //dummy buffer, binary data isn't copied + break; + default: + break; + } + + sal_Int8* bindBuf = allocBindBuf(parameterIndex, nRealSize); + + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + OTools::bindParameter( m_pConnection, + m_aStatementHandle, + parameterIndex, + bindBuf, + getLengthBuf(parameterIndex), + fSqlType, + sal_False, + m_pConnection->useOldDateFormat(), + _pData, + (Reference <XInterface>)*this, + getOwnConnection()->getTextEncoding()); +} +// ----------------------------------------------------------------------------- +void SAL_CALL OPreparedStatement::setByte( sal_Int32 parameterIndex, sal_Int8 x ) throw(SQLException, RuntimeException) +{ + setParameter(parameterIndex,DataType::TINYINT,sizeof(sal_Int8),&x); +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setDate( sal_Int32 parameterIndex, const Date& aData ) throw(SQLException, RuntimeException) +{ + DATE_STRUCT x = OTools::DateToOdbcDate(aData); + setParameter(parameterIndex,DataType::DATE,sizeof(DATE_STRUCT),&x); +} +// ------------------------------------------------------------------------- + + +void SAL_CALL OPreparedStatement::setTime( sal_Int32 parameterIndex, const Time& aVal ) throw(SQLException, RuntimeException) +{ + TIME_STRUCT x = OTools::TimeToOdbcTime(aVal); + setParameter(parameterIndex,DataType::TIME,sizeof(TIME_STRUCT),&x); +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setTimestamp( sal_Int32 parameterIndex, const DateTime& aVal ) throw(SQLException, RuntimeException) +{ + TIMESTAMP_STRUCT x = OTools::DateTimeToTimestamp(aVal); + setParameter(parameterIndex,DataType::TIMESTAMP,sizeof(TIMESTAMP_STRUCT),&x); +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setDouble( sal_Int32 parameterIndex, double x ) throw(SQLException, RuntimeException) +{ + setParameter(parameterIndex,DataType::DOUBLE,sizeof(double),&x); +} + +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setFloat( sal_Int32 parameterIndex, float x ) throw(SQLException, RuntimeException) +{ + setParameter(parameterIndex,DataType::FLOAT,sizeof(float),&x); +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setInt( sal_Int32 parameterIndex, sal_Int32 x ) throw(SQLException, RuntimeException) +{ + setParameter(parameterIndex,DataType::INTEGER,sizeof(sal_Int32),&x); +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setLong( sal_Int32 parameterIndex, sal_Int64 x ) throw(SQLException, RuntimeException) +{ + try + { + setParameter(parameterIndex,DataType::BIGINT,sizeof(sal_Int64),&x); + } + catch(SQLException&) + { + setString(parameterIndex,ORowSetValue(x)); + } +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setNull( sal_Int32 parameterIndex, sal_Int32 sqlType ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + prepareStatement(); + // Get the buffer needed for the length + checkParameterIndex(parameterIndex); + + sal_Int8* lenBuf = getLengthBuf (parameterIndex); + *(SQLLEN*)lenBuf = SQL_NULL_DATA; + + + SQLLEN prec = 0; + SQLULEN nColumnSize = 0; + if (sqlType == SQL_CHAR || sqlType == SQL_VARCHAR || sqlType == SQL_LONGVARCHAR) + { + prec = 1; + nColumnSize = 1; + } + + SQLSMALLINT fCType = 0; + SQLSMALLINT fSqlType = 0; + + SQLSMALLINT nDecimalDigits = 0; + OTools::getBindTypes( sal_False, + m_pConnection->useOldDateFormat(), + (SQLSMALLINT)sqlType, + fCType, + fSqlType); + + SQLRETURN nReturn = N3SQLBindParameter( m_aStatementHandle, + (SQLUSMALLINT)parameterIndex, + (SQLSMALLINT)SQL_PARAM_INPUT, + fCType, + fSqlType, + nColumnSize, + nDecimalDigits, + NULL, + prec, + (SQLLEN*)lenBuf + ); + OTools::ThrowException(m_pConnection,nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this); +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setClob( sal_Int32 parameterIndex, const Reference< XClob >& x ) throw(SQLException, RuntimeException) +{ + if ( x.is() ) + setStream(parameterIndex, x->getCharacterStream(), (SQLLEN)x->length(), DataType::LONGVARCHAR); +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setBlob( sal_Int32 parameterIndex, const Reference< XBlob >& x ) throw(SQLException, RuntimeException) +{ + if ( x.is() ) + setStream(parameterIndex, x->getBinaryStream(), (SQLLEN)x->length(), DataType::LONGVARCHAR); +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setArray( sal_Int32 /*parameterIndex*/, const Reference< XArray >& /*x*/ ) throw(SQLException, RuntimeException) +{ + ::dbtools::throwFunctionNotSupportedException( "XParameters::setArray", *this ); +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setRef( sal_Int32 /*parameterIndex*/, const Reference< XRef >& /*x*/ ) throw(SQLException, RuntimeException) +{ + ::dbtools::throwFunctionNotSupportedException( "XParameters::setRef", *this ); +} +// ------------------------------------------------------------------------- +void OPreparedStatement::setDecimal( sal_Int32 parameterIndex, const ::rtl::OUString& x ) +{ + ::rtl::OString aString(::rtl::OUStringToOString(x,getOwnConnection()->getTextEncoding())); + setParameter(parameterIndex,DataType::DECIMAL,aString.getLength(),(void*)&x); +} +// ------------------------------------------------------------------------- +void SAL_CALL OPreparedStatement::setObjectWithInfo( sal_Int32 parameterIndex, const Any& x, sal_Int32 sqlType, sal_Int32 scale ) throw(SQLException, RuntimeException) +{ + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + ::osl::MutexGuard aGuard( m_aMutex ); + + prepareStatement(); + // For each known SQL Type, call the appropriate + // set routine + + switch (sqlType) + { + case DataType::VARCHAR: + case DataType::LONGVARCHAR: + if(x.hasValue()) + { + ::rtl::OUString sStr; + x >>= sStr; + ::rtl::OString aString(::rtl::OUStringToOString(sStr,getOwnConnection()->getTextEncoding())); + setParameter(parameterIndex,sqlType,aString.getLength(),&aString); + } + else + setNull(parameterIndex,sqlType); + break; + case DataType::DECIMAL: + { + ORowSetValue aValue; + aValue.fill(x); + setDecimal(parameterIndex,aValue); + } + break; + case DataType::NUMERIC: + { + ORowSetValue aValue; + aValue.fill(x); + setString(parameterIndex,aValue); + } + break; + default: + ::dbtools::setObjectWithInfo(this,parameterIndex,x,sqlType,scale); + } +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setObjectNull( sal_Int32 parameterIndex, sal_Int32 sqlType, const ::rtl::OUString& /*typeName*/ ) throw(SQLException, RuntimeException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + setNull(parameterIndex,sqlType); +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setObject( sal_Int32 parameterIndex, const Any& x ) throw(SQLException, RuntimeException) +{ + if (!::dbtools::implSetObject(this, parameterIndex, x)) + { // there is no other setXXX call which can handle the value in x + throw SQLException(); + } +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setShort( sal_Int32 parameterIndex, sal_Int16 x ) throw(SQLException, RuntimeException) +{ + setParameter(parameterIndex,DataType::SMALLINT,sizeof(sal_Int16),&x); +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setBytes( sal_Int32 parameterIndex, const Sequence< sal_Int8 >& x ) throw(SQLException, RuntimeException) +{ + setParameter(parameterIndex,DataType::BINARY,x.getLength(),(void*)&x); + boundParams[parameterIndex-1].setSequence(x); // this assures that the sequence stays alive +} +// ------------------------------------------------------------------------- + + +void SAL_CALL OPreparedStatement::setCharacterStream( sal_Int32 parameterIndex, const Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ) throw(SQLException, RuntimeException) +{ + setStream(parameterIndex, x, length, DataType::LONGVARCHAR); +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::setBinaryStream( sal_Int32 parameterIndex, const Reference< ::com::sun::star::io::XInputStream >& x, sal_Int32 length ) throw(SQLException, RuntimeException) +{ + setStream(parameterIndex, x, length, DataType::LONGVARBINARY); +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::clearParameters( ) throw(SQLException, RuntimeException) +{ + prepareStatement(); + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + SQLRETURN nRet = N3SQLFreeStmt (m_aStatementHandle, SQL_RESET_PARAMS); + nRet = N3SQLFreeStmt (m_aStatementHandle, SQL_UNBIND); +} +// ------------------------------------------------------------------------- +void SAL_CALL OPreparedStatement::clearBatch( ) throw(SQLException, RuntimeException) +{ + // clearParameters( ); + // m_aBatchList.erase(); +} +// ------------------------------------------------------------------------- + +void SAL_CALL OPreparedStatement::addBatch( ) throw(SQLException, RuntimeException) +{ +} +// ------------------------------------------------------------------------- + +Sequence< sal_Int32 > SAL_CALL OPreparedStatement::executeBatch( ) throw(SQLException, RuntimeException) +{ + return Sequence< sal_Int32 > (); +} +// ------------------------------------------------------------------------- + +//==================================================================== +// methods +//==================================================================== + +//-------------------------------------------------------------------- +// initBoundParam +// Initialize the bound parameter objects +//-------------------------------------------------------------------- + +void OPreparedStatement::initBoundParam () throw(SQLException) +{ + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + // Get the number of parameters + numParams = 0; + N3SQLNumParams (m_aStatementHandle,&numParams); + + // There are parameter markers, allocate the bound + // parameter objects + + if (numParams > 0) + { + // Allocate an array of bound parameter objects + + boundParams = new OBoundParam[numParams]; + + // Allocate and initialize each bound parameter + + for (sal_Int32 i = 0; i < numParams; i++) + { + boundParams[i] = OBoundParam(); + boundParams[i].initialize (); + } + } +} +// ------------------------------------------------------------------------- + +//-------------------------------------------------------------------- +// allocBindBuf +// Allocate storage for the permanent data buffer for the bound +// parameter. +//-------------------------------------------------------------------- + +sal_Int8* OPreparedStatement::allocBindBuf( sal_Int32 index,sal_Int32 bufLen) +{ + sal_Int8* b = NULL; + + // Sanity check the parameter number + + if ((index >= 1) && + (index <= numParams) && bufLen > 0 ) + { + b = boundParams[index - 1].allocBindDataBuffer(bufLen); + } + + return b; +} +// ------------------------------------------------------------------------- + +//-------------------------------------------------------------------- +// getDataBuf +// Gets the data buffer for the given parameter index +//-------------------------------------------------------------------- + +sal_Int8* OPreparedStatement::getDataBuf (sal_Int32 index) +{ + sal_Int8* b = NULL; + + // Sanity check the parameter number + + if ((index >= 1) && + (index <= numParams)) + { + b = boundParams[index - 1].getBindDataBuffer (); + } + + return b; +} +// ------------------------------------------------------------------------- + +//-------------------------------------------------------------------- +// getLengthBuf +// Gets the length buffer for the given parameter index +//-------------------------------------------------------------------- + +sal_Int8* OPreparedStatement::getLengthBuf (sal_Int32 index) +{ + sal_Int8* b = NULL; + + // Sanity check the parameter number + + if ((index >= 1) && + (index <= numParams)) + { + b = boundParams[index - 1].getBindLengthBuffer (); + } + + return b; +} +// ------------------------------------------------------------------------- + +//-------------------------------------------------------------------- +// getParamLength +// Returns the length of the given parameter number. When each +// parameter was bound, a 4-sal_Int8 buffer was given to hold the +// length (stored in native format). Get the buffer, convert the +// buffer from native format, and return it. If the length is -1, +// the column is considered to be NULL. +//-------------------------------------------------------------------- + +sal_Int32 OPreparedStatement::getParamLength ( sal_Int32 index) +{ + sal_Int32 paramLen = SQL_NULL_DATA; + + // Sanity check the parameter number + + if ((index >= 1) && + (index <= numParams)) { + + // Now get the length of the parameter from the + // bound param array. -1 is returned if it is NULL. + long n = 0; + memcpy (&n, boundParams[index -1].getBindLengthBuffer (), sizeof (n)); + paramLen = n; + } + return paramLen; +} +// ------------------------------------------------------------------------- + +//-------------------------------------------------------------------- +// putParamData +// Puts parameter data from a previously bound input stream. The +// input stream was bound using SQL_LEN_DATA_AT_EXEC. +//-------------------------------------------------------------------- + +void OPreparedStatement::putParamData (sal_Int32 index) throw(SQLException) +{ + // Sanity check the parameter index + if ((index < 1) || + (index > numParams)) + { + return; + } + + // We'll transfer up to MAX_PUT_DATA_LENGTH at a time + Sequence< sal_Int8 > buf( MAX_PUT_DATA_LENGTH ); + + // Get the information about the input stream + + Reference< XInputStream> inputStream = boundParams[index - 1].getInputStream (); + if ( !inputStream.is() ) + { + ::connectivity::SharedResources aResources; + const ::rtl::OUString sError( aResources.getResourceString(STR_NO_INPUTSTREAM)); + throw SQLException (sError, *this,::rtl::OUString(),0,Any()); + } + + sal_Int32 maxBytesLeft = boundParams[index - 1].getInputStreamLen (); + + // Loop while more data from the input stream + sal_Int32 haveRead = 0; + try + { + + do + { + sal_Int32 toReadThisRound = ::std::min( MAX_PUT_DATA_LENGTH, maxBytesLeft ); + + // Read some data from the input stream + haveRead = inputStream->readBytes( buf, toReadThisRound ); + OSL_ENSURE( haveRead == buf.getLength(), "OPreparedStatement::putParamData: inconsistency!" ); + + if ( !haveRead ) + // no more data in the stream - the given stream length was a maximum which could not be + // fulfilled by the stream + break; + + // Put the data + OSL_ENSURE( m_aStatementHandle, "OPreparedStatement::putParamData: StatementHandle is null!" ); + N3SQLPutData ( m_aStatementHandle, buf.getArray(), buf.getLength() ); + + // decrement the number of bytes still needed + maxBytesLeft -= haveRead; + } + while ( maxBytesLeft > 0 ); + } + catch (const IOException& ex) + { + + // If an I/O exception was generated, turn + // it into a SQLException + + throw SQLException(ex.Message,*this,::rtl::OUString(),0,Any()); + } +} +// ------------------------------------------------------------------------- +//-------------------------------------------------------------------- +// getPrecision +// Given a SQL type, return the maximum precision for the column. +// Returns -1 if not known +//-------------------------------------------------------------------- + +sal_Int32 OPreparedStatement::getPrecision ( sal_Int32 sqlType) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + sal_Int32 prec = -1; + const TTypeInfoVector& rTypeInfo = m_pConnection->getTypeInfo(); + if ( !rTypeInfo.empty() ) + { + m_pConnection->buildTypeInfo(); + } + + if ( !rTypeInfo.empty() ) + { + OTypeInfo aInfo; + aInfo.nType = (sal_Int16)sqlType; + TTypeInfoVector::const_iterator aIter = ::std::find(rTypeInfo.begin(),rTypeInfo.end(),aInfo); + if(aIter != rTypeInfo.end()) + prec = (*aIter).nPrecision; + } + return prec; +} + +//-------------------------------------------------------------------- +// setStream +// Sets an input stream as a parameter, using the given SQL type +//-------------------------------------------------------------------- + +void OPreparedStatement::setStream( + sal_Int32 ParameterIndex, + const Reference< XInputStream>& x, + SQLLEN length, + sal_Int32 SQLtype) + throw(SQLException) +{ + ::osl::MutexGuard aGuard( m_aMutex ); + checkDisposed(OStatement_BASE::rBHelper.bDisposed); + + + prepareStatement(); + + checkParameterIndex(ParameterIndex); + // Get the buffer needed for the length + + sal_Int8* lenBuf = getLengthBuf(ParameterIndex); + + // Allocate a new buffer for the parameter data. This buffer + // will be returned by SQLParamData (it is set to the parameter + // number, a 4-sal_Int8 integer) + + sal_Int8* dataBuf = allocBindBuf (ParameterIndex, 4); + + // Bind the parameter with SQL_LEN_DATA_AT_EXEC + SQLSMALLINT Ctype = SQL_C_CHAR; + SQLLEN atExec = SQL_LEN_DATA_AT_EXEC (length); + memcpy (dataBuf, &ParameterIndex, sizeof(ParameterIndex)); + memcpy (lenBuf, &atExec, sizeof (atExec)); + + if ((SQLtype == SQL_BINARY) || (SQLtype == SQL_VARBINARY) || (SQLtype == SQL_LONGVARBINARY)) + Ctype = SQL_C_BINARY; + + + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + N3SQLBindParameter(m_aStatementHandle, + (SQLUSMALLINT)ParameterIndex, + (SQLUSMALLINT)SQL_PARAM_INPUT, + Ctype, + (SQLSMALLINT)SQLtype, + (SQLULEN)length, + 0, + dataBuf, + sizeof(ParameterIndex), + (SQLLEN*)lenBuf); + + // Save the input stream + boundParams[ParameterIndex - 1].setInputStream (x, length); +} +// ------------------------------------------------------------------------- + +// ------------------------------------------------------------------------- + +void OPreparedStatement::FreeParams() +{ + numParams = 0; + delete [] boundParams; + boundParams = NULL; +} +// ------------------------------------------------------------------------- +void OPreparedStatement::setFastPropertyValue_NoBroadcast(sal_Int32 nHandle,const Any& rValue) throw (Exception) +{ + try + { + switch(nHandle) + { + case PROPERTY_ID_RESULTSETCONCURRENCY: + if(!isPrepared()) + setResultSetConcurrency(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_RESULTSETTYPE: + if(!isPrepared()) + setResultSetType(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_FETCHDIRECTION: + if(!isPrepared()) + setFetchDirection(comphelper::getINT32(rValue)); + break; + case PROPERTY_ID_USEBOOKMARKS: + if(!isPrepared()) + setUsingBookmarks(comphelper::getBOOL(rValue)); + break; + default: + OStatement_Base::setFastPropertyValue_NoBroadcast(nHandle,rValue); + } + } + catch(const SQLException&) + { + // throw Exception(e.Message,*this); + } +} +// ----------------------------------------------------------------------------- +void OPreparedStatement::prepareStatement() +{ + if(!isPrepared()) + { + OSL_ENSURE(m_aStatementHandle,"StatementHandle is null!"); + ::rtl::OString aSql(::rtl::OUStringToOString(m_sSqlStatement,getOwnConnection()->getTextEncoding())); + SQLRETURN nReturn = N3SQLPrepare(m_aStatementHandle,(SDB_ODBC_CHAR *) aSql.getStr(),aSql.getLength()); + OTools::ThrowException(m_pConnection,nReturn,m_aStatementHandle,SQL_HANDLE_STMT,*this); + m_bPrepared = sal_True; + initBoundParam(); + } +} +// ----------------------------------------------------------------------------- +void OPreparedStatement::checkParameterIndex(sal_Int32 _parameterIndex) +{ + if( !_parameterIndex || _parameterIndex > numParams) + { + ::connectivity::SharedResources aResources; + const ::rtl::OUString sError( aResources.getResourceStringWithSubstitution(STR_WRONG_PARAM_INDEX, + "$pos$", ::rtl::OUString::valueOf(_parameterIndex), + "$count$", ::rtl::OUString::valueOf((sal_Int32)numParams) + )); + SQLException aNext(sError,*this, ::rtl::OUString(),0,Any()); + + ::dbtools::throwInvalidIndexException(*this,makeAny(aNext)); + } +} +// ----------------------------------------------------------------------------- +OResultSet* OPreparedStatement::createResulSet() +{ + OResultSet* pReturn = new OResultSet(m_aStatementHandle,this); + pReturn->setMetaData(getMetaData()); + return pReturn; +} +// ----------------------------------------------------------------------------- |