Kaydet (Commit) 2c543077 authored tarafından Lionel Elie Mamane's avatar Lionel Elie Mamane

ODBC PreparedStatement Parameters: redesign setXXX handling

More type-safe way, instead of void* everywhere
void* instead of sal_Int8 for raw memory / multi-use buffers
Fixed more issues than I care to count, but at least:
 - updates to a DECIMAL were truncated to integer because DecimalDigits set to 0
   maybe/probably also NUMERIC
 - setObjectWithInfo(... DataType::LONGVARCHAR ...) was passed as AT_EXEC, but the buffer was already free()d by then -> crash or wrong data

Change-Id: I0e6791a05b96fb345bfe3f911386263e6cfedde9
üst 626da721
......@@ -1058,7 +1058,7 @@ void SAL_CALL OResultSet::updateDouble( sal_Int32 columnIndex, double x ) throw(
void SAL_CALL OResultSet::updateString( sal_Int32 columnIndex, const ::rtl::OUString& x ) throw(SQLException, RuntimeException)
{
sal_Int32 nType = m_aRow[columnIndex].getTypeKind();
SQLSMALLINT nOdbcType = static_cast<SQLSMALLINT>(OTools::jdbcTypeToOdbc(nType));
SQLSMALLINT nOdbcType = OTools::jdbcTypeToOdbc(nType);
m_aRow[columnIndex] = x;
m_aRow[columnIndex].setTypeKind(nType); // OJ: otherwise longvarchar will be recognized by fillNeededData
updateValue(columnIndex,nOdbcType,(void*)&x);
......@@ -1067,7 +1067,7 @@ void SAL_CALL OResultSet::updateString( sal_Int32 columnIndex, const ::rtl::OUSt
void SAL_CALL OResultSet::updateBytes( sal_Int32 columnIndex, const Sequence< sal_Int8 >& x ) throw(SQLException, RuntimeException)
{
sal_Int32 nType = m_aRow[columnIndex].getTypeKind();
SQLSMALLINT nOdbcType = static_cast<SQLSMALLINT>(OTools::jdbcTypeToOdbc(nType));
SQLSMALLINT nOdbcType = OTools::jdbcTypeToOdbc(nType);
m_aRow[columnIndex] = x;
m_aRow[columnIndex].setTypeKind(nType); // OJ: otherwise longvarbinary will be recognized by fillNeededData
updateValue(columnIndex,nOdbcType,(void*)&x);
......
......@@ -150,190 +150,6 @@ void OTools::getValue( OConnection* _pConnection,
_aStatementHandle,SQL_HANDLE_STMT,_xInterface,sal_False);
_bWasNull = pcbValue == SQL_NULL_DATA;
}
// -----------------------------------------------------------------------------
void OTools::bindParameter( OConnection* _pConnection,
SQLHANDLE _hStmt,
sal_Int32 nPos,
sal_Int8*& pDataBuffer,
sal_Int8* pLenBuffer,
SQLSMALLINT _nODBCtype,
sal_Bool _bUseWChar,
sal_Bool _bUseOldTimeDate,
const void* _pValue,
const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _xInterface,
rtl_TextEncoding _nTextEncoding)
throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
{
RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "odbc", "Ocke.Janssen@sun.com", "OTools::bindParameter" );
SQLRETURN nRetcode;
SQLSMALLINT fSqlType;
SQLSMALLINT fCType;
SQLLEN nMaxLen = 0;
SQLLEN* pLen = (SQLLEN*)pLenBuffer;
SQLULEN nColumnSize=0;
SQLSMALLINT nDecimalDigits=0;
bool atExec;
OTools::getBindTypes(_bUseWChar,_bUseOldTimeDate,_nODBCtype,fCType,fSqlType);
OTools::bindData(_nODBCtype,_bUseWChar,pDataBuffer,pLen,_pValue,_nTextEncoding,nColumnSize, atExec);
if ((nColumnSize == 0) && (fSqlType == SQL_CHAR || fSqlType == SQL_VARCHAR || fSqlType == SQL_LONGVARCHAR))
nColumnSize = 1;
if (atExec)
memcpy(pDataBuffer,&nPos,sizeof(nPos));
nRetcode = (*(T3SQLBindParameter)_pConnection->getOdbcFunction(ODBC3SQLBindParameter))(_hStmt,
(SQLUSMALLINT)nPos,
SQL_PARAM_INPUT,
fCType,
fSqlType,
nColumnSize,
nDecimalDigits,
pDataBuffer,
nMaxLen,
pLen);
OTools::ThrowException(_pConnection,nRetcode,_hStmt,SQL_HANDLE_STMT,_xInterface);
}
// -----------------------------------------------------------------------------
void OTools::bindData( SQLSMALLINT _nOdbcType,
sal_Bool _bUseWChar,
sal_Int8 *&_pData,
SQLLEN*& pLen,
const void* _pValue,
rtl_TextEncoding _nTextEncoding,
SQLULEN& _nColumnSize,
bool &atExec)
{
RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "odbc", "Ocke.Janssen@sun.com", "OTools::bindData" );
_nColumnSize = 0;
atExec = false;
switch (_nOdbcType)
{
case SQL_CHAR:
case SQL_VARCHAR:
case SQL_DECIMAL:
if(_bUseWChar)
{
*pLen = SQL_NTS;
::rtl::OUString sStr(*(::rtl::OUString*)_pValue);
_nColumnSize = sStr.getLength();
*((rtl::OUString*)_pData) = sStr;
// Pointer on Char*
_pData = (sal_Int8*)((rtl::OUString*)_pData)->getStr();
}
else
{
::rtl::OString aString(::rtl::OUStringToOString(*(::rtl::OUString*)_pValue,_nTextEncoding));
*pLen = SQL_NTS;
_nColumnSize = aString.getLength();
memcpy(_pData,aString.getStr(),aString.getLength());
((sal_Int8*)_pData)[aString.getLength()] = '\0';
}
break;
case SQL_BIGINT:
*((sal_Int64*)_pData) = *(sal_Int64*)_pValue;
*pLen = sizeof(sal_Int64);
_nColumnSize = *pLen;
break;
case SQL_NUMERIC:
if(_bUseWChar)
{
::rtl::OUString aString = rtl::OUString::valueOf(*(double*)_pValue);
_nColumnSize = aString.getLength();
*pLen = _nColumnSize;
*((rtl::OUString*)_pData) = aString;
// Pointer on Char*
_pData = (sal_Int8*)((rtl::OUString*)_pData)->getStr();
}
else
{
::rtl::OString aString = ::rtl::OString::valueOf(*(double*)_pValue);
_nColumnSize = aString.getLength();
*pLen = _nColumnSize;
memcpy(_pData,aString.getStr(),aString.getLength());
((sal_Int8*)_pData)[_nColumnSize] = '\0';
} break;
case SQL_BIT:
case SQL_TINYINT:
*((sal_Int8*)_pData) = *(sal_Int8*)_pValue;
*pLen = sizeof(sal_Int8);
break;
case SQL_SMALLINT:
*((sal_Int16*)_pData) = *(sal_Int16*)_pValue;
*pLen = sizeof(sal_Int16);
break;
case SQL_INTEGER:
*((sal_Int32*)_pData) = *(sal_Int32*)_pValue;
*pLen = sizeof(sal_Int32);
break;
case SQL_FLOAT:
*((float*)_pData) = *(float*)_pValue;
*pLen = sizeof(float);
break;
case SQL_REAL:
case SQL_DOUBLE:
*((double*)_pData) = *(double*)_pValue;
*pLen = sizeof(double);
break;
case SQL_BINARY:
case SQL_VARBINARY:
{
const ::com::sun::star::uno::Sequence< sal_Int8 >* pSeq = static_cast< const ::com::sun::star::uno::Sequence< sal_Int8 >* >(_pValue);
OSL_ENSURE(pSeq,"OTools::bindData: Sequence is null!");
if(pSeq)
{
_pData = (sal_Int8*)pSeq->getConstArray();
*pLen = pSeq->getLength();
}
}
break;
case SQL_LONGVARBINARY:
{
sal_Int32 nLen = 0;
nLen = ((const ::com::sun::star::uno::Sequence< sal_Int8 > *)_pValue)->getLength();
*pLen = (SQLLEN)SQL_LEN_DATA_AT_EXEC(nLen);
}
atExec = true;
break;
case SQL_LONGVARCHAR:
{
sal_Int32 nLen = 0;
if(_bUseWChar)
nLen = sizeof(sal_Unicode) * ((::rtl::OUString*)_pValue)->getLength();
else
{
::rtl::OString aString(::rtl::OUStringToOString(*(::rtl::OUString*)_pValue,_nTextEncoding));
nLen = aString.getLength();
}
*pLen = (SQLLEN)SQL_LEN_DATA_AT_EXEC(nLen);
atExec = true;
} break;
case SQL_DATE:
*(DATE_STRUCT*)_pData = *(DATE_STRUCT*)_pValue;
*pLen = (SQLLEN)sizeof(DATE_STRUCT);
_nColumnSize = 10;
break;
case SQL_TIME:
*(TIME_STRUCT*)_pData = *(TIME_STRUCT*)_pValue;
*pLen = (SQLLEN)sizeof(TIME_STRUCT);
_nColumnSize = 8;
break;
case SQL_TIMESTAMP:
*(TIMESTAMP_STRUCT*)_pData = *(TIMESTAMP_STRUCT*)_pValue;
*pLen = (SQLLEN)sizeof(TIMESTAMP_STRUCT);
// 20+sub-zero precision; we have hundredths of seconds
_nColumnSize = 22;
break;
}
}
// -------------------------------------------------------------------------
void OTools::bindValue( OConnection* _pConnection,
SQLHANDLE _aStatementHandle,
......@@ -342,7 +158,7 @@ void OTools::bindValue( OConnection* _pConnection,
SQLSMALLINT _nMaxLen,
const void* _pValue,
void* _pData,
SQLLEN *pLen,
SQLLEN * const pLen,
const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _xInterface,
rtl_TextEncoding _nTextEncoding,
sal_Bool _bUseOldTimeDate) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException)
......@@ -779,7 +595,7 @@ void OTools::GetInfo(OConnection* _pConnection,
_aConnectionHandle,SQL_HANDLE_DBC,_xInterface);
}
// -------------------------------------------------------------------------
sal_Int32 OTools::MapOdbcType2Jdbc(sal_Int32 _nType)
sal_Int32 OTools::MapOdbcType2Jdbc(SQLSMALLINT _nType)
{
sal_Int32 nValue = DataType::VARCHAR;
switch(_nType)
......@@ -857,7 +673,7 @@ sal_Int32 OTools::MapOdbcType2Jdbc(sal_Int32 _nType)
// jdbcTypeToOdbc
// Convert the JDBC SQL type to the correct ODBC type
//--------------------------------------------------------------------
sal_Int32 OTools::jdbcTypeToOdbc(sal_Int32 jdbcType)
SQLSMALLINT OTools::jdbcTypeToOdbc(sal_Int32 jdbcType)
{
RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "odbc", "Ocke.Janssen@sun.com", "OTools::jdbcTypeToOdbc" );
// For the most part, JDBC types match ODBC types. We'll
......@@ -876,6 +692,11 @@ sal_Int32 OTools::jdbcTypeToOdbc(sal_Int32 jdbcType)
case DataType::TIMESTAMP:
odbcType = SQL_TIMESTAMP;
break;
// ODBC doesn't have any notion of CLOB or BLOB
case DataType::CLOB:
odbcType = SQL_LONGVARCHAR;
case DataType::BLOB:
odbcType = SQL_LONGVARBINARY;
}
return odbcType;
......
......@@ -20,6 +20,7 @@
#define _CONNECTIVITY_OBOUNPARAM_HXX_
#include <com/sun/star/io/XInputStream.hpp>
#include <com/sun/star/sdbc/DataType.hpp>
#include "odbc/odbcbasedllapi.hxx"
namespace connectivity
......@@ -31,50 +32,29 @@ namespace connectivity
public:
OBoundParam()
: binaryData(NULL)
, paramInputStreamLen(0)
, sqlType(::com::sun::star::sdbc::DataType::SQLNULL)
, outputParameter(false)
{
paramLength = NULL;
binaryData = NULL;
pA1=0;
pA2=0;
pB1=0;
pB2=0;
pC1=0;
pC2=0;
pS1=0;
pS2=0;
}
~OBoundParam()
{
delete [] binaryData;
delete [] paramLength;
free(binaryData);
}
//--------------------------------------------------------------------
// initialize
// Perform an necessary initialization
//--------------------------------------------------------------------
void initialize ()
{
// Allocate storage for the length. Note - the length is
// stored in native format, and will have to be converted
// to a Java sal_Int32. The jdbcodbc 'C' bridge provides an
// interface to do this.
paramLength = new sal_Int8[sizeof(SQLLEN)];
}
//--------------------------------------------------------------------
// allocBindDataBuffer
// Allocates and returns a new bind data buffer of the specified
// length
//--------------------------------------------------------------------
sal_Int8* allocBindDataBuffer (sal_Int32 bufLen)
void* allocBindDataBuffer (sal_Int32 bufLen)
{
if ( binaryData )
delete [] binaryData;
binaryData = new sal_Int8[bufLen];
// Reset the input stream, we are doing a new bind
// Reset the input stream and sequence, we are doing a new bind
setInputStream (NULL, 0);
aSequence.realloc(0);
free(binaryData);
binaryData = (bufLen > 0) ? malloc(bufLen) : NULL;
return binaryData;
}
......@@ -83,7 +63,7 @@ namespace connectivity
// getBindDataBuffer
// Returns the data buffer to be used when binding to a parameter
//--------------------------------------------------------------------
sal_Int8* getBindDataBuffer ()
void* getBindDataBuffer ()
{
return binaryData;
}
......@@ -92,9 +72,9 @@ namespace connectivity
// getBindLengthBuffer
// Returns the length buffer to be used when binding to a parameter
//--------------------------------------------------------------------
sal_Int8* getBindLengthBuffer ()
SQLLEN* getBindLengthBuffer ()
{
return paramLength;
return &paramLength;
}
//--------------------------------------------------------------------
......@@ -176,20 +156,20 @@ namespace connectivity
// Data attributes
//====================================================================
sal_Int8* binaryData; // Storage area to be used
// when binding the parameter
void *binaryData; // Storage area to be used
// when binding the parameter
sal_Int8* paramLength; // Storage area to be used
// for the bound length of the
// parameter. Note that this
// data is in native format.
SQLLEN paramLength; // Storage area to be used
// for the bound length of the
// parameter. Note that this
// data is in native format.
::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream> paramInputStream;
::com::sun::star::uno::Sequence< sal_Int8 > aSequence;
// When an input stream is
// bound to a parameter, the
// input stream is saved
// until needed.
// bound to a parameter, a
// reference to the input stream is saved
// until not needed anymore.
sal_Int32 paramInputStreamLen; // Length of input stream
......@@ -197,16 +177,6 @@ namespace connectivity
// register an OUT parameter
sal_Bool outputParameter; // true for OUTPUT parameters
sal_Int32 pA1; //pointers
sal_Int32 pA2;
sal_Int32 pB1;
sal_Int32 pB2;
sal_Int32 pC1;
sal_Int32 pC2;
sal_Int32 pS1;
sal_Int32 pS2;// reserved for strings(UTFChars)
};
}
}
......
......@@ -46,6 +46,7 @@ namespace connectivity
public OPreparedStatement_BASE
{
protected:
static const short invalid_scale = -1;
struct Parameter
{
::com::sun::star::uno::Any aValue;
......@@ -74,15 +75,20 @@ namespace connectivity
void putParamData (sal_Int32 index) throw(::com::sun::star::sdbc::SQLException);
void setStream (sal_Int32 ParameterIndex,const ::com::sun::star::uno::Reference< ::com::sun::star::io::XInputStream>& x,
SQLLEN length,sal_Int32 SQLtype) throw(::com::sun::star::sdbc::SQLException);
sal_Int8* getLengthBuf (sal_Int32 index);
sal_Int8* allocBindBuf ( sal_Int32 index, sal_Int32 bufLen);
SQLLEN* getLengthBuf (sal_Int32 index);
void* allocBindBuf ( sal_Int32 index, sal_Int32 bufLen);
void initBoundParam () throw(::com::sun::star::sdbc::SQLException);
void setParameter(sal_Int32 parameterIndex,sal_Int32 _nType,sal_Int32 _nSize,void* _pData);
void setParameterPre(sal_Int32 parameterIndex);
template <typename T> void setScalarParameter(sal_Int32 parameterIndex, sal_Int32 _nType, SQLULEN _nColumnSize, const T i_Value);
void setParameter(sal_Int32 parameterIndex, sal_Int32 _nType, SQLULEN _nColumnSize, sal_Int32 _nScale, const void* _pData, SQLULEN _nDataLen, SQLLEN _nDataAllocLen);
void setParameter(sal_Int32 parameterIndex, sal_Int32 _nType, sal_Int32 _nColumnSize, sal_Int32 _nByteSize, void* _pData);
// Wrappers for special cases
void setParameter(sal_Int32 parameterIndex, sal_Int32 _nType, sal_Int16 _nScale, const ::rtl::OUString &_sData);
void setParameter(sal_Int32 parameterIndex, sal_Int32 _nType, const com::sun::star::uno::Sequence< sal_Int8 > &_Data);
sal_Bool isPrepared() const { return m_bPrepared;}
void prepareStatement();
void checkParameterIndex(sal_Int32 _parameterIndex);
void setDecimal( sal_Int32 parameterIndex, const ::rtl::OUString& x );
/**
creates the driver specific resultset (factory)
......
......@@ -138,8 +138,8 @@ namespace connectivity
sal_Bool &_rValue,
const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _xInterface) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
static sal_Int32 MapOdbcType2Jdbc(sal_Int32 _nType);
static sal_Int32 jdbcTypeToOdbc(sal_Int32 jdbcType);
static sal_Int32 MapOdbcType2Jdbc(SQLSMALLINT _nType);
static SQLSMALLINT jdbcTypeToOdbc(sal_Int32 jdbcType);
static DATE_STRUCT DateToOdbcDate(const ::com::sun::star::util::Date& x)
{
......@@ -206,40 +206,6 @@ namespace connectivity
void* _pValue,
SQLLEN _nSize) throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
/**
bindData copies data from pValue to pData
@param _nOdbcType [in] the ODBC sql type
@param _bUseWChar [in] true when Unicode should be used
@param _pData [in/out] data copy destination
@param pLen [out] buffer length of data written to _pData
@param _pValue [in] contains the data to be copied
@param _nTextEncoding [in] the text encoding
@param _nColumnSize [out] columnSize of data written to _pData
@param atExec [out] data was not copied, but setup for data-at-execution;
caller is responsible for writing a token in _pData
*/
static void bindData( SQLSMALLINT _nOdbcType,
sal_Bool _bUseWChar,
sal_Int8 *&_pData,
SQLLEN*& pLen,
const void* _pValue,
rtl_TextEncoding _nTextEncoding,
SQLULEN& _nColumnSize,
bool &atExec);
static void bindParameter( OConnection* _pConnection,
SQLHANDLE _hStmt,
sal_Int32 nPos,
sal_Int8*& pDataBuffer,
sal_Int8* pLenBuffer,
SQLSMALLINT _nODBCtype,
sal_Bool _bUseWChar,
sal_Bool _bUseOldTimeDate,
const void* _pValue,
const ::com::sun::star::uno::Reference< ::com::sun::star::uno::XInterface >& _xInterface,
rtl_TextEncoding _nTextEncoding)
throw(::com::sun::star::sdbc::SQLException, ::com::sun::star::uno::RuntimeException);
static void bindValue( OConnection* _pConnection,
SQLHANDLE _aStatementHandle,
sal_Int32 columnIndex,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment