Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / whidbey / NetFXspW7 / ndp / fx / src / DataOracleClient / System / Data / OracleClient / OracleColumn.cs / 1 / OracleColumn.cs
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// [....]
//-----------------------------------------------------------------------------
namespace System.Data.OracleClient
{
using System;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.IO;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Text;
//---------------------------------------------------------------------
// OracleColumn
//
// Contains all the information about a single column in a result set,
// and implements the methods necessary to describe column to Oracle
// and to extract the column data from the native buffer used to fetch
// it.
//
sealed internal class OracleColumn {
private OciParameterDescriptor _describeHandle; // the Describe handle
private int _ordinal; // the ordinal position in the rowset (0..n-1)
private string _columnName; // the name of the column
private MetaType _metaType;
private byte _precision; // precision of the column (OracleNumber only)
private byte _scale; // scale of the column (OracleNumber only)
private int _byteSize; // how many bytes we need in the row buffer
private bool _isNullable; // whether the value is nullable or not.
private int _indicatorOffset; // offset from the start of the row buffer to the indicator binding (see OCI.INDICATOR)
private int _lengthOffset; // offset from the start of the row buffer to the length binding
private int _valueOffset; // offset from the start of the row buffer to the value binding
private NativeBuffer_RowBuffer _rowBuffer; // the row buffer we're bound to (reused for all rows fetched)
private NativeBuffer_LongColumnData _longBuffer;// the out-of-line buffer used for piecewise binding; must be reset for each new fetch.
private int _longLength; // the length of the data we actually fetched into _longBuffer
private OCI.Callback.OCICallbackDefine _callback;// the piecewise binding callback for this column
private OciLobLocator _lobLocator; // the descriptor allocated for LOB columns
private OracleConnection _connection; // the connection the column is on (LOB columns only)
private int _connectionCloseCount; // The close count of the connection; used to decide if we're zombied
private bool _bindAsUTF16; // true whenever we're binding character data as Unicode...
// Construct by getting the specified describe handle from the specified statement handle
internal OracleColumn(OciStatementHandle statementHandle, int ordinal, OciErrorHandle errorHandle, OracleConnection connection) {
_ordinal = ordinal;
_describeHandle = statementHandle.GetDescriptor(_ordinal, errorHandle);;
_connection = connection;
_connectionCloseCount = connection.CloseCount;
}
internal string ColumnName { get { return _columnName; } }
internal bool IsNullable { get { return _isNullable; } }
internal bool IsLob { get { return _metaType.IsLob; } }
internal bool IsLong { get { return _metaType.IsLong; } }
internal OracleType OracleType { get { return _metaType.OracleType; } }
internal int Ordinal { get { return _ordinal; } }
internal byte Precision { get { return _precision; } }
internal byte Scale { get { return _scale; } }
// This is the value used for the SchemaTable, which must be Chars...
internal int SchemaTableSize { get { return (_bindAsUTF16 && !_metaType.IsLong)?_byteSize/2:_byteSize; } }
private int _callback_GetColumnPiecewise(
IntPtr octxp,
IntPtr defnp,
uint iter,
IntPtr bufpp, // dvoid**
IntPtr alenp, // ub4**
IntPtr piecep, // ub1*
IntPtr indpp, // dvoid**
IntPtr rcodep // ub2**
) {
// Callback routine for Dynamic Binding column values from Oracle: tell
// Oracle where to stuff the data.
if (Bid.AdvancedOn)
Bid.Trace(""
+" octxp=0x%-07Ix"
+" defnp=0x%-07Ix"
+" iter=%-2d"
+" bufpp=0x%-07Ix"
+" alenp=0x%-07Ix"
+" piecep=0x%-07Ix"
+" indpp=0x%-07Ix"
+" rcodep=0x%-07Ix\n",
octxp,
defnp,
unchecked((int)iter), // tracing -- I don't care about overflow.
bufpp,
alenp,
piecep,
indpp,
rcodep
);
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE: THIS IS A CALLBACK FUNCTION FROM AN OCI PINVOKE!
// Namely, OCIStmtFetch. We expect that you will have called
// DangerousAddRef on the _rowBuffer and the _longBuffer
// SafeHandles, to prevent any Handle Recycling from occurring.
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// RFC50002189 - chunk length is saved as part of chunk's buffer
// later, when the LONG field value is requested, TotalLength is used
// to sum the lengths and the result is writtent into buffer[_lengthOffset], as before the change
IntPtr lengthPtr;
IntPtr indicatorPtr = (-1 != _indicatorOffset) ? _rowBuffer.DangerousGetDataPtr(_indicatorOffset) : IntPtr.Zero;
IntPtr valuePtr = _longBuffer.GetChunk(out lengthPtr);
Marshal.WriteIntPtr(bufpp, valuePtr); // *bufpp
Marshal.WriteIntPtr(indpp, indicatorPtr); // *indpp
Marshal.WriteIntPtr(alenp, lengthPtr); // *alenp
// provide the size of allocated buffer, in bytes, to Oracle driver
// on output, we will receive from Oracle driver the length of filled buffer, in bytes
Marshal.WriteInt32(lengthPtr, NativeBuffer_LongColumnData.MaxChunkSize); // **alenp
GC.KeepAlive(this);
return (int)OCI.RETURNCODE.OCI_CONTINUE;
}
internal void Bind(OciStatementHandle statementHandle, NativeBuffer_RowBuffer buffer, OciErrorHandle errorHandle, int rowBufferLength) {
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE: You must have called DangerousAddRef on the buffer before
// calling this method, or you run the risk of allowing Handle
// Recycling to occur!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Binds the buffer for the column to the statement handle specified.
OciDefineHandle defineHandle = null;
IntPtr h;
OCI.MODE mode = OCI.MODE.OCI_DEFAULT;
int bindByteSize;
OCI.DATATYPE ociType = _metaType.OciType;
_rowBuffer = buffer;
if (_metaType.IsLong) {
mode = OCI.MODE.OCI_DYNAMIC_FETCH;
bindByteSize = Int32.MaxValue;
}
else {
bindByteSize = _byteSize;
}
IntPtr indicatorLocation = IntPtr.Zero;
IntPtr lengthLocation = IntPtr.Zero;
IntPtr valueLocation = _rowBuffer.DangerousGetDataPtr(_valueOffset);
if (-1 != _indicatorOffset) {
indicatorLocation = _rowBuffer.DangerousGetDataPtr(_indicatorOffset);
}
if (-1 != _lengthOffset && !_metaType.IsLong) {
lengthLocation = _rowBuffer.DangerousGetDataPtr(_lengthOffset);
}
try {
int rc = TracedNativeMethods.OCIDefineByPos(
statementHandle, // hndlp
out h, // defnpp
errorHandle, // errhp
checked((uint)_ordinal+1), // position
valueLocation, // valuep
bindByteSize, // value_sz
ociType, // htype
indicatorLocation, // indp,
lengthLocation, // rlenp,
IntPtr.Zero, // rcodep,
mode // mode
);
if (rc != 0) {
_connection.CheckError(errorHandle, rc);
}
defineHandle = new OciDefineHandle(statementHandle, h);
if (0 != rowBufferLength) {
uint valOffset = checked((uint)rowBufferLength);
uint indOffset = (-1 != _indicatorOffset) ? valOffset : 0;
uint lenOffset = (-1 != _lengthOffset && !_metaType.IsLong) ? valOffset : 0;
rc = TracedNativeMethods.OCIDefineArrayOfStruct(
defineHandle,
errorHandle,
valOffset,
indOffset,
lenOffset,
0 // never use rcodep above...
);
if (rc != 0) {
_connection.CheckError(errorHandle, rc);
}
}
if (_metaType.UsesNationalCharacterSet) {
Debug.Assert(!_metaType.IsLong, "LONG data may never be bound as NCHAR");
// NOTE: the order is important here; setting charsetForm will
// reset charsetId (I found this out the hard way...)
defineHandle.SetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_FORM, (int)OCI.CHARSETFORM.SQLCS_NCHAR, errorHandle);
}
if (!_connection.UnicodeEnabled) {
if (_bindAsUTF16) {
// NOTE: the order is important here; setting charsetForm will
// reset charsetId (I found this out the hard way...)
defineHandle.SetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_ID, (short)OCI.CHARSETID.OCI_UTF16ID, errorHandle);
}
}
if (_metaType.IsLong) {
// Initialize the longBuffer in the rowBuffer to null
_rowBuffer.WriteIntPtr(_valueOffset, IntPtr.Zero);
_callback = new OCI.Callback.OCICallbackDefine(_callback_GetColumnPiecewise);
rc = TracedNativeMethods.OCIDefineDynamic(
defineHandle, // defnp
errorHandle, // errhp
IntPtr.Zero, // dvoid *octxp,
_callback // OCICallbackDefine ocbfp
);
if (rc != 0) {
_connection.CheckError(errorHandle, rc);
}
}
}
finally {
// We don't need these any longer, get rid of it.
NativeBuffer.SafeDispose(ref _longBuffer);
OciHandle.SafeDispose(ref defineHandle);
}
}
internal bool Describe(ref int offset, OracleConnection connection, OciErrorHandle errorHandle) {
// Gets all of the column description information from the describe
// handle. In addition, we'll determine the position of the column
// in the rowbuffer, based upon the offset parameter, which is passed
// by ref so we can adjust the end position accordingly.
short tempub2;
byte tempub1;
OCI.DATATYPE ociType;
bool needSize = false;
bool cannotPrefetch = false;
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_NAME, out _columnName,errorHandle, _connection);
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_DATA_TYPE, out tempub2, errorHandle);
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_IS_NULL, out tempub1, errorHandle);
_isNullable = (0 != tempub1);
ociType = (OCI.DATATYPE)tempub2;
switch (ociType) {
case OCI.DATATYPE.CHAR:
case OCI.DATATYPE.VARCHAR2:
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_DATA_SIZE, out _byteSize, errorHandle);
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_FORM,out tempub1, errorHandle);
OCI.CHARSETFORM charsetForm = (OCI.CHARSETFORM)tempub1;
_bindAsUTF16 = connection.ServerVersionAtLeastOracle8;
// SQLBUVSTS 217686: the _byteSize we have is size, in bytes, of the string in its server representation. This size can be
// less than the buffer size we need to fetch the UTF16 chars for the same string which can result in
// either silent data truncation or ORA-01406 exception of Oracle.
// To calculate the byte size for UTF16 characters, we query for the size in UTF16 characters using
// OCI_ATTR_CHAR_SIZE and double it (1 UTF16 char == 2 bytes).
int charSize;
// according to Oracle's documentation, OCI_ATTR_CHAR_SIZE is supported only if both client and server >= 9
if (connection.ServerVersionAtLeastOracle9i && OCI.ClientVersionAtLeastOracle9i) {
// we can query for the char size since both client and server versions are >= 9
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_CHAR_SIZE, out tempub2, errorHandle);
charSize = tempub2;
}
else {
// if either client or server is 8 or less, we cannot use OCI_ATTR_CHAR_SIZE attribute
// in that case, we assume the worse scenario: max number of characters is same or less as number of bytes used to encode it
// (which is true in all NLS languages and UTF* encodings).
// we could query for OCI_ATTR_CHARSET_ID and calculate the max size with better efficiency, but this would
// complicate the calcs thus making the fix risky and prone for regressions.
charSize = _byteSize;
}
if (charsetForm == OCI.CHARSETFORM.SQLCS_NCHAR) {
// National Character Set
_metaType = MetaType.GetMetaTypeForType((OCI.DATATYPE.CHAR == ociType) ? OracleType.NChar : OracleType.NVarChar);
}
else {
// Database Character Set
_metaType = MetaType.GetMetaTypeForType((OCI.DATATYPE.CHAR == ociType) ? OracleType.Char : OracleType.VarChar);
if (_bindAsUTF16) {
// we deal only with UTF16 so get the size required to store same number of UTF16 chars
_byteSize *= ADP.CharSize;
}
}
// To fetch the data, we have to specify size in bytes.
// To be on the safe side and avoid regressions, select the max between the size as it
// is encoded on the server and the size we've calculated above.
_byteSize = Math.Max(_byteSize, charSize * ADP.CharSize);
needSize = true;
break;
case OCI.DATATYPE.DATE:
_metaType = MetaType.GetMetaTypeForType(OracleType.DateTime);
_byteSize = _metaType.BindSize;
needSize = true;
break;
case OCI.DATATYPE.TIMESTAMP:
_metaType = MetaType.GetMetaTypeForType(OracleType.Timestamp);
_byteSize = _metaType.BindSize;
needSize = true;
break;
case OCI.DATATYPE.TIMESTAMP_LTZ:
_metaType = MetaType.GetMetaTypeForType(OracleType.TimestampLocal);
_byteSize = _metaType.BindSize;
needSize = true;
break;
case OCI.DATATYPE.TIMESTAMP_TZ:
_metaType = MetaType.GetMetaTypeForType(OracleType.TimestampWithTZ);
_byteSize = _metaType.BindSize;
needSize = true;
break;
case OCI.DATATYPE.INTERVAL_YM:
_metaType = MetaType.GetMetaTypeForType(OracleType.IntervalYearToMonth);
_byteSize = _metaType.BindSize;
break;
case OCI.DATATYPE.INTERVAL_DS:
_metaType = MetaType.GetMetaTypeForType(OracleType.IntervalDayToSecond);
_byteSize = _metaType.BindSize;
break;
case OCI.DATATYPE.NUMBER:
_metaType = MetaType.GetMetaTypeForType(OracleType.Number);
_byteSize = _metaType.BindSize;
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_PRECISION, out _precision, errorHandle);
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_SCALE, out _scale, errorHandle);
break;
case OCI.DATATYPE.RAW:
_metaType = MetaType.GetMetaTypeForType(OracleType.Raw);
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_DATA_SIZE, out _byteSize, errorHandle);
needSize = true;
break;
case OCI.DATATYPE.ROWID:
case OCI.DATATYPE.ROWID_DESC:
case OCI.DATATYPE.UROWID:
_metaType = MetaType.GetMetaTypeForType(OracleType.RowId);
_byteSize = _metaType.BindSize;
if (connection.UnicodeEnabled) {
_bindAsUTF16 = true;
_byteSize *= ADP.CharSize; // Since Oracle reported the number of characters and UTF16 characters are two bytes each, have to adjust the buffer size
}
needSize = true;
break;
case OCI.DATATYPE.BFILE:
_metaType = MetaType.GetMetaTypeForType(OracleType.BFile);
_byteSize = _metaType.BindSize;
cannotPrefetch = true;
break;
case OCI.DATATYPE.BLOB:
_metaType = MetaType.GetMetaTypeForType(OracleType.Blob);
_byteSize = _metaType.BindSize;
cannotPrefetch = true;
break;
case OCI.DATATYPE.CLOB:
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_FORM, out tempub1, errorHandle);
_metaType = MetaType.GetMetaTypeForType((OCI.CHARSETFORM.SQLCS_NCHAR == (OCI.CHARSETFORM)tempub1) ? OracleType.NClob : OracleType.Clob);
_byteSize = _metaType.BindSize;
cannotPrefetch = true;
break;
case OCI.DATATYPE.LONG:
_metaType = MetaType.GetMetaTypeForType(OracleType.LongVarChar);
_byteSize = _metaType.BindSize;
needSize = true;
cannotPrefetch = true;
_bindAsUTF16 = connection.ServerVersionAtLeastOracle8; // MDAC #79471 - Oracle7 servers don't do Unicode
break;
case OCI.DATATYPE.LONGRAW:
_metaType = MetaType.GetMetaTypeForType(OracleType.LongRaw);
_byteSize = _metaType.BindSize;
needSize = true;
cannotPrefetch = true;
break;
default:
throw ADP.TypeNotSupported(ociType);
}
if (_isNullable) {
_indicatorOffset= offset; offset += IntPtr.Size;
}
else {
_indicatorOffset = -1;
}
if (needSize) {
_lengthOffset = offset; offset += IntPtr.Size;
}
else {
_lengthOffset = -1;
}
_valueOffset = offset;
if (OCI.DATATYPE.LONG == ociType || OCI.DATATYPE.LONGRAW == ociType) {
offset += IntPtr.Size;
}
else {
offset += _byteSize;
}
offset = (offset + (IntPtr.Size-1)) & ~(IntPtr.Size-1); // align buffer;
// We don't need this any longer, get rid of it.
OciHandle.SafeDispose(ref _describeHandle);
return cannotPrefetch;
}
internal void Dispose() {
NativeBuffer.SafeDispose(ref _longBuffer);
OciLobLocator.SafeDispose(ref _lobLocator);
OciHandle.SafeDispose(ref _describeHandle);
_columnName = null;
_metaType = null;
_callback = null;
_connection = null;
}
internal void FixupLongValueLength(NativeBuffer buffer) {
if (null != _longBuffer) {
Debug.Assert(_metaType.IsLong, "dangling long buffer?");
// Determine the actual length of the LONG/LONG RAW data read, if we
// haven't done so already.
if (-1 == _longLength) {
// Our "piecewise" fetching of LONG/LONG RAW data will extend the
// buffer by a chunk, and ask Oracle to fill it.
// Oracle calls ours _callback_GetColumnPiecewise for each new buffer.
// We create different chunk for each callback call, each chunk has its own
// length.
// Before the fix of RFC50002189, we assumed that native Oracle driver will fill each
// non-last chunk fully (with size = request one == ChunkSize),so we calculated the total
// length as fixed chunk size * (num of chunks - 1) + last chunk size!
// This assumption was wrong (RFC50002189) - Oracle driver can fill less data than the chunk size.
// The fix for RFC50002189 includes:
// * remember each chunk size separately, as part of the chunk
// * calculate and fixup the total length here (as before) and update the buffer[_lengthOffset]
_longLength = _longBuffer.TotalLengthInBytes;
// Of course, we have to convert for character data to number of
// Unicode Characters read, not number of bytes
if (_bindAsUTF16) {
Debug.Assert(0 == (_longLength & 0x1), "odd length unicode data?");
_longLength /= 2;
}
Debug.Assert(_longLength >= 0, "invalid size for LONG data?");
// Finally, we write the length back to the row buffer so we don't
// have to have two code paths to construct the managed object.
buffer.WriteInt32(_lengthOffset, _longLength);
}
}
}
internal string GetDataTypeName() {
// Returns the name of the back-end data type.
return _metaType.DataTypeName;
}
internal Type GetFieldType() {
// Returns the actual clr type that the column is.
return _metaType.BaseType;
}
internal Type GetFieldOracleType() {
// Returns the actual oracletype that the column is.
return _metaType.NoConvertType;
}
internal object GetValue(NativeBuffer_RowBuffer buffer) {
// Returns an object that contains the value of the column in the
// specified row buffer. This method returns CLS-typed objects.
if (IsDBNull(buffer)) {
return DBNull.Value;
}
//Debug.WriteLine(String.Format("{0}: {1}", _columnName, buffer.ReadInt16(_indicatorOffset+2)));
switch (_metaType.OciType) {
case OCI.DATATYPE.BFILE: {
object value;
using (OracleBFile bfile = GetOracleBFile(buffer)) {
value = bfile.Value; // reading the LOB is MUCH more expensive than constructing an object we'll throw away
}
return value;
}
case OCI.DATATYPE.RAW:
case OCI.DATATYPE.LONGRAW: {
long length = GetBytes(buffer, 0, null, 0, 0);
byte[] value = new byte[length];
GetBytes( buffer, 0, value, 0, (int)length );
return value;
}
case OCI.DATATYPE.DATE:
case OCI.DATATYPE.INT_TIMESTAMP:
case OCI.DATATYPE.INT_TIMESTAMP_TZ:
case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
return GetDateTime( buffer );
case OCI.DATATYPE.BLOB:
case OCI.DATATYPE.CLOB: {
object value;
using (OracleLob lob = GetOracleLob(buffer)) {
value = lob.Value; // reading the LOB is MUCH more expensive than constructing an object we'll throw away
}
return value;
}
case OCI.DATATYPE.INT_INTERVAL_YM:
return GetInt32( buffer );
case OCI.DATATYPE.VARNUM:
return GetDecimal( buffer );
case OCI.DATATYPE.CHAR:
case OCI.DATATYPE.VARCHAR2:
case OCI.DATATYPE.LONG:
return GetString( buffer );
case OCI.DATATYPE.INT_INTERVAL_DS:
return GetTimeSpan( buffer );
}
throw ADP.TypeNotSupported(_metaType.OciType);
}
internal object GetOracleValue(NativeBuffer_RowBuffer buffer) {
// Returns an object that contains the value of the column in the
// specified row buffer. This method returns Oracle-typed objects.
//Debug.WriteLine(String.Format("{0}: {1}", _columnName, buffer.ReadInt16(_indicatorOffset+2)));
switch (_metaType.OciType) {
case OCI.DATATYPE.BFILE:
return GetOracleBFile( buffer );
case OCI.DATATYPE.RAW:
case OCI.DATATYPE.LONGRAW:
return GetOracleBinary( buffer );
case OCI.DATATYPE.DATE:
case OCI.DATATYPE.INT_TIMESTAMP:
case OCI.DATATYPE.INT_TIMESTAMP_TZ:
case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
return GetOracleDateTime( buffer );
case OCI.DATATYPE.BLOB:
case OCI.DATATYPE.CLOB:
return GetOracleLob( buffer );
case OCI.DATATYPE.INT_INTERVAL_YM:
return GetOracleMonthSpan( buffer );
case OCI.DATATYPE.VARNUM:
return GetOracleNumber( buffer );
case OCI.DATATYPE.CHAR:
case OCI.DATATYPE.VARCHAR2:
case OCI.DATATYPE.LONG:
return GetOracleString( buffer );
case OCI.DATATYPE.INT_INTERVAL_DS:
return GetOracleTimeSpan( buffer );
}
throw ADP.TypeNotSupported(_metaType.OciType);
}
//---------------------------------------------------------------------
// Get
//
// Returns an the value of the column in the specified row buffer as
// the appropriate type
//
internal long GetBytes( NativeBuffer_RowBuffer buffer, long fieldOffset, byte[] destinationBuffer, int destinationOffset, int length ) {
if (length < 0) { // MDAC 71007
throw ADP.InvalidDataLength(length);
}
if ((destinationOffset < 0) || (null != destinationBuffer && destinationOffset >= destinationBuffer.Length)) { // MDAC 71013
throw ADP.InvalidDestinationBufferIndex(destinationBuffer.Length, destinationOffset, "bufferoffset"); // NOTE: Name matches public object model OracleDataReader.GetBytes()
}
if (0 > fieldOffset || UInt32.MaxValue < fieldOffset) {
throw ADP.InvalidSourceOffset("fieldOffset", 0, UInt32.MaxValue);
}
int byteCount;
if (IsLob) {
OracleType lobType = _metaType.OracleType;
if (OracleType.Blob != lobType && OracleType.BFile != lobType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
using (OracleLob lob = new OracleLob(_lobLocator)) {
uint valueLength = (uint)lob.Length;
uint sourceOffset = (uint) fieldOffset;
if (sourceOffset > valueLength) { // MDAC 72830
throw ADP.InvalidSourceBufferIndex((int)valueLength, (int)sourceOffset, "fieldOffset"); // NOTE: Name matches public object model OracleDataReader.GetBytes()
}
byteCount = (int)(valueLength - sourceOffset);
if (null != destinationBuffer) {
byteCount = Math.Min(byteCount, length);
if (0 < byteCount) {
lob.Seek(sourceOffset,SeekOrigin.Begin);
lob.Read(destinationBuffer, destinationOffset, byteCount);
}
}
}
}
else {
if (OracleType.Raw != OracleType && OracleType.LongRaw != OracleType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
FixupLongValueLength(buffer);
int valueLength = OracleBinary.GetLength(buffer, _lengthOffset, _metaType);
int sourceOffset = (int) fieldOffset;
byteCount = valueLength - sourceOffset;
if (null != destinationBuffer) {
byteCount = Math.Min(byteCount, length);
if (0 < byteCount) {
OracleBinary.GetBytes(buffer,
_valueOffset,
_metaType,
sourceOffset,
destinationBuffer,
destinationOffset,
byteCount);
}
}
}
return Math.Max(0,byteCount);
}
internal long GetChars(NativeBuffer_RowBuffer buffer, long fieldOffset, char[] destinationBuffer, int destinationOffset, int length) {
if (length < 0) { // MDAC 71007
throw ADP.InvalidDataLength(length);
}
if ((destinationOffset < 0) || (null != destinationBuffer && destinationOffset >= destinationBuffer.Length)) { // MDAC 71013
throw ADP.InvalidDestinationBufferIndex(destinationBuffer.Length, destinationOffset, "bufferoffset"); // NOTE: Name matches public object model OracleDataReader.GetChars()
}
if (0 > fieldOffset || UInt32.MaxValue < fieldOffset) {
throw ADP.InvalidSourceOffset("fieldOffset", 0, UInt32.MaxValue);
}
int charCount;
if (IsLob) {
OracleType lobType = _metaType.OracleType;
if (OracleType.Clob != lobType
&& OracleType.NClob != lobType
&& OracleType.BFile != lobType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
using (OracleLob lob = new OracleLob(_lobLocator)) {
string s = (string)lob.Value;
int valueLength = s.Length;
int sourceOffset = (int) fieldOffset;
if (sourceOffset < 0) { // MDAC 72830
throw ADP.InvalidSourceBufferIndex(valueLength, sourceOffset, "fieldOffset"); // NOTE: Name matches public object model OracleDataReader.GetChars()
}
charCount = (int)(valueLength - sourceOffset);
if (null != destinationBuffer) {
charCount = Math.Min(charCount, length);
if (0 < charCount) {
char[] result = s.ToCharArray(sourceOffset, charCount);
Buffer.BlockCopy(result, 0, destinationBuffer, destinationOffset, charCount);
}
}
}
}
else {
if (OracleType.Char != OracleType
&& OracleType.VarChar != OracleType
&& OracleType.LongVarChar != OracleType
&& OracleType.NChar != OracleType
&& OracleType.NVarChar != OracleType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
FixupLongValueLength(buffer);
int valueLength = OracleString.GetLength(buffer, _lengthOffset, _metaType);
int sourceOffset = (int) fieldOffset;
charCount = valueLength - sourceOffset;
if (null != destinationBuffer) {
charCount = Math.Min(charCount, length);
if (0 < charCount) {
OracleString.GetChars(buffer,
_valueOffset,
_lengthOffset,
_metaType,
_connection,
_bindAsUTF16,
sourceOffset,
destinationBuffer,
destinationOffset,
charCount);
}
}
}
return Math.Max(0,charCount);
}
internal DateTime GetDateTime(NativeBuffer_RowBuffer buffer) {
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
if (typeof(DateTime) != _metaType.BaseType) {
throw ADP.InvalidCast();
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
DateTime result = OracleDateTime.MarshalToDateTime(buffer, _valueOffset, _lengthOffset, _metaType, _connection);
return result;
}
internal decimal GetDecimal(NativeBuffer_RowBuffer buffer) {
if (typeof(decimal) != _metaType.BaseType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
decimal result = OracleNumber.MarshalToDecimal(buffer, _valueOffset, _connection);
return result;
}
internal double GetDouble(NativeBuffer_RowBuffer buffer) {
if (typeof(decimal) != _metaType.BaseType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
decimal decimalValue = OracleNumber.MarshalToDecimal(buffer, _valueOffset, _connection);
double result = (double)decimalValue;
return result;
}
internal float GetFloat(NativeBuffer_RowBuffer buffer) {
if (typeof(decimal) != _metaType.BaseType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
decimal decimalValue = OracleNumber.MarshalToDecimal(buffer, _valueOffset, _connection);
float result = (float)decimalValue;
return result;
}
internal int GetInt32(NativeBuffer_RowBuffer buffer) {
if (typeof(int) != _metaType.BaseType
&& typeof(decimal) != _metaType.BaseType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
int result;
if (typeof(int) == _metaType.BaseType) {
result = OracleMonthSpan.MarshalToInt32(buffer, _valueOffset);
}
else {
result = OracleNumber.MarshalToInt32(buffer, _valueOffset, _connection);
}
return result;
}
internal Int64 GetInt64(NativeBuffer_RowBuffer buffer) {
if (typeof(decimal) != _metaType.BaseType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
Int64 result = OracleNumber.MarshalToInt64(buffer, _valueOffset, _connection);
return result;
}
internal string GetString(NativeBuffer_RowBuffer buffer) {
if (IsLob) {
OracleType lobType = _metaType.OracleType;
if (OracleType.Clob != lobType && OracleType.NClob != lobType && OracleType.BFile != lobType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
string result;
using (OracleLob lob = new OracleLob(_lobLocator)) {
result = (string)lob.Value;
}
return result;
}
else {
if (typeof(string) != _metaType.BaseType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
FixupLongValueLength(buffer);
string result = OracleString.MarshalToString(buffer, _valueOffset, _lengthOffset, _metaType, _connection, _bindAsUTF16, false);
return result;
}
}
internal TimeSpan GetTimeSpan(NativeBuffer_RowBuffer buffer) {
if (typeof(TimeSpan) != _metaType.BaseType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
TimeSpan result = OracleTimeSpan.MarshalToTimeSpan(buffer, _valueOffset);
return result;
}
internal OracleBFile GetOracleBFile(NativeBuffer_RowBuffer buffer) {
Debug.Assert(null == _longBuffer, "dangling long buffer?");
if (typeof(OracleBFile) != _metaType.NoConvertType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
return OracleBFile.Null;
}
OracleBFile result = new OracleBFile(_lobLocator);
return result;
}
internal OracleBinary GetOracleBinary(NativeBuffer_RowBuffer buffer) {
if (typeof(OracleBinary) != _metaType.NoConvertType) {
throw ADP.InvalidCast();
}
FixupLongValueLength(buffer);
if (IsDBNull(buffer)) {
return OracleBinary.Null;
}
OracleBinary result = new OracleBinary(buffer, _valueOffset, _lengthOffset, _metaType);
return result;
}
internal OracleDateTime GetOracleDateTime(NativeBuffer_RowBuffer buffer) {
if (typeof(OracleDateTime) != _metaType.NoConvertType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
return OracleDateTime.Null;
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
OracleDateTime result = new OracleDateTime(buffer, _valueOffset, _lengthOffset, _metaType, _connection);
return result;
}
internal OracleLob GetOracleLob(NativeBuffer_RowBuffer buffer) {
if (typeof(OracleLob) != _metaType.NoConvertType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
return OracleLob.Null;
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
OracleLob result = new OracleLob(_lobLocator);
return result;
}
internal OracleMonthSpan GetOracleMonthSpan(NativeBuffer_RowBuffer buffer) {
if (typeof(OracleMonthSpan) != _metaType.NoConvertType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
return OracleMonthSpan.Null;
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
OracleMonthSpan result = new OracleMonthSpan(buffer, _valueOffset);
return result;
}
internal OracleNumber GetOracleNumber(NativeBuffer_RowBuffer buffer) {
if (typeof(OracleNumber) != _metaType.NoConvertType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
return OracleNumber.Null;
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
OracleNumber result = new OracleNumber(buffer, _valueOffset);
return result;
}
internal OracleString GetOracleString(NativeBuffer_RowBuffer buffer) {
if (typeof(OracleString) != _metaType.NoConvertType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
return OracleString.Null;
}
FixupLongValueLength(buffer);
OracleString result = new OracleString(buffer, _valueOffset, _lengthOffset, _metaType, _connection, _bindAsUTF16, false);
return result;
}
internal OracleTimeSpan GetOracleTimeSpan(NativeBuffer_RowBuffer buffer) {
if (typeof(OracleTimeSpan) != _metaType.NoConvertType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
return OracleTimeSpan.Null;
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
OracleTimeSpan result = new OracleTimeSpan(buffer, _valueOffset);
return result;
}
internal bool IsDBNull(NativeBuffer_RowBuffer buffer) {
// Returns true if the column value in the buffer is null.
return (_isNullable && buffer.ReadInt16(_indicatorOffset) == (Int16)OCI.INDICATOR.ISNULL);
}
internal void Rebind(OracleConnection connection, ref bool mustRelease, ref SafeHandle handleToBind) {
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE: You must have called DangerousAddRef on the buffer before
// calling this method, or you run the risk of allowing Handle
// Recycling to occur!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Here's the hook that gets called whenever we're about to fetch
// a new row, allowing us to reset any information that we shouldn't
// carry forward.
handleToBind = null;
switch (_metaType.OciType) {
case OCI.DATATYPE.LONG:
case OCI.DATATYPE.LONGRAW:
_rowBuffer.WriteInt32(_lengthOffset, 0);
_longLength = -1; // reset the length to unknown;
if (null != _longBuffer) {
_longBuffer.Reset(); // free all the memory we allocated, except the initial one
}
else {
_longBuffer = new NativeBuffer_LongColumnData();
}
handleToBind = _longBuffer;
break;
case OCI.DATATYPE.BLOB:
case OCI.DATATYPE.CLOB:
case OCI.DATATYPE.BFILE:
OciLobLocator.SafeDispose(ref _lobLocator);
_lobLocator = new OciLobLocator(connection, _metaType.OracleType);
handleToBind = _lobLocator.Descriptor;
break;
}
// We need to add-ref the handle so it can't be released somehow
// by another thread while we're fetching. Only after we do that
// can we write it to the buffer for the Oracle to use during the
// Fetch. The caller is required to provide storage for the
// handleToBind and ensure that the DangerousRelease is called
// in it's CER.
if (null != handleToBind) {
handleToBind.DangerousAddRef(ref mustRelease);
_rowBuffer.WriteIntPtr(_valueOffset, handleToBind.DangerousGetHandle());
}
}
};
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// [....]
//-----------------------------------------------------------------------------
namespace System.Data.OracleClient
{
using System;
using System.Data;
using System.Data.Common;
using System.Diagnostics;
using System.IO;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Text;
//---------------------------------------------------------------------
// OracleColumn
//
// Contains all the information about a single column in a result set,
// and implements the methods necessary to describe column to Oracle
// and to extract the column data from the native buffer used to fetch
// it.
//
sealed internal class OracleColumn {
private OciParameterDescriptor _describeHandle; // the Describe handle
private int _ordinal; // the ordinal position in the rowset (0..n-1)
private string _columnName; // the name of the column
private MetaType _metaType;
private byte _precision; // precision of the column (OracleNumber only)
private byte _scale; // scale of the column (OracleNumber only)
private int _byteSize; // how many bytes we need in the row buffer
private bool _isNullable; // whether the value is nullable or not.
private int _indicatorOffset; // offset from the start of the row buffer to the indicator binding (see OCI.INDICATOR)
private int _lengthOffset; // offset from the start of the row buffer to the length binding
private int _valueOffset; // offset from the start of the row buffer to the value binding
private NativeBuffer_RowBuffer _rowBuffer; // the row buffer we're bound to (reused for all rows fetched)
private NativeBuffer_LongColumnData _longBuffer;// the out-of-line buffer used for piecewise binding; must be reset for each new fetch.
private int _longLength; // the length of the data we actually fetched into _longBuffer
private OCI.Callback.OCICallbackDefine _callback;// the piecewise binding callback for this column
private OciLobLocator _lobLocator; // the descriptor allocated for LOB columns
private OracleConnection _connection; // the connection the column is on (LOB columns only)
private int _connectionCloseCount; // The close count of the connection; used to decide if we're zombied
private bool _bindAsUTF16; // true whenever we're binding character data as Unicode...
// Construct by getting the specified describe handle from the specified statement handle
internal OracleColumn(OciStatementHandle statementHandle, int ordinal, OciErrorHandle errorHandle, OracleConnection connection) {
_ordinal = ordinal;
_describeHandle = statementHandle.GetDescriptor(_ordinal, errorHandle);;
_connection = connection;
_connectionCloseCount = connection.CloseCount;
}
internal string ColumnName { get { return _columnName; } }
internal bool IsNullable { get { return _isNullable; } }
internal bool IsLob { get { return _metaType.IsLob; } }
internal bool IsLong { get { return _metaType.IsLong; } }
internal OracleType OracleType { get { return _metaType.OracleType; } }
internal int Ordinal { get { return _ordinal; } }
internal byte Precision { get { return _precision; } }
internal byte Scale { get { return _scale; } }
// This is the value used for the SchemaTable, which must be Chars...
internal int SchemaTableSize { get { return (_bindAsUTF16 && !_metaType.IsLong)?_byteSize/2:_byteSize; } }
private int _callback_GetColumnPiecewise(
IntPtr octxp,
IntPtr defnp,
uint iter,
IntPtr bufpp, // dvoid**
IntPtr alenp, // ub4**
IntPtr piecep, // ub1*
IntPtr indpp, // dvoid**
IntPtr rcodep // ub2**
) {
// Callback routine for Dynamic Binding column values from Oracle: tell
// Oracle where to stuff the data.
if (Bid.AdvancedOn)
Bid.Trace(""
+" octxp=0x%-07Ix"
+" defnp=0x%-07Ix"
+" iter=%-2d"
+" bufpp=0x%-07Ix"
+" alenp=0x%-07Ix"
+" piecep=0x%-07Ix"
+" indpp=0x%-07Ix"
+" rcodep=0x%-07Ix\n",
octxp,
defnp,
unchecked((int)iter), // tracing -- I don't care about overflow.
bufpp,
alenp,
piecep,
indpp,
rcodep
);
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE: THIS IS A CALLBACK FUNCTION FROM AN OCI PINVOKE!
// Namely, OCIStmtFetch. We expect that you will have called
// DangerousAddRef on the _rowBuffer and the _longBuffer
// SafeHandles, to prevent any Handle Recycling from occurring.
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// RFC50002189 - chunk length is saved as part of chunk's buffer
// later, when the LONG field value is requested, TotalLength is used
// to sum the lengths and the result is writtent into buffer[_lengthOffset], as before the change
IntPtr lengthPtr;
IntPtr indicatorPtr = (-1 != _indicatorOffset) ? _rowBuffer.DangerousGetDataPtr(_indicatorOffset) : IntPtr.Zero;
IntPtr valuePtr = _longBuffer.GetChunk(out lengthPtr);
Marshal.WriteIntPtr(bufpp, valuePtr); // *bufpp
Marshal.WriteIntPtr(indpp, indicatorPtr); // *indpp
Marshal.WriteIntPtr(alenp, lengthPtr); // *alenp
// provide the size of allocated buffer, in bytes, to Oracle driver
// on output, we will receive from Oracle driver the length of filled buffer, in bytes
Marshal.WriteInt32(lengthPtr, NativeBuffer_LongColumnData.MaxChunkSize); // **alenp
GC.KeepAlive(this);
return (int)OCI.RETURNCODE.OCI_CONTINUE;
}
internal void Bind(OciStatementHandle statementHandle, NativeBuffer_RowBuffer buffer, OciErrorHandle errorHandle, int rowBufferLength) {
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE: You must have called DangerousAddRef on the buffer before
// calling this method, or you run the risk of allowing Handle
// Recycling to occur!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Binds the buffer for the column to the statement handle specified.
OciDefineHandle defineHandle = null;
IntPtr h;
OCI.MODE mode = OCI.MODE.OCI_DEFAULT;
int bindByteSize;
OCI.DATATYPE ociType = _metaType.OciType;
_rowBuffer = buffer;
if (_metaType.IsLong) {
mode = OCI.MODE.OCI_DYNAMIC_FETCH;
bindByteSize = Int32.MaxValue;
}
else {
bindByteSize = _byteSize;
}
IntPtr indicatorLocation = IntPtr.Zero;
IntPtr lengthLocation = IntPtr.Zero;
IntPtr valueLocation = _rowBuffer.DangerousGetDataPtr(_valueOffset);
if (-1 != _indicatorOffset) {
indicatorLocation = _rowBuffer.DangerousGetDataPtr(_indicatorOffset);
}
if (-1 != _lengthOffset && !_metaType.IsLong) {
lengthLocation = _rowBuffer.DangerousGetDataPtr(_lengthOffset);
}
try {
int rc = TracedNativeMethods.OCIDefineByPos(
statementHandle, // hndlp
out h, // defnpp
errorHandle, // errhp
checked((uint)_ordinal+1), // position
valueLocation, // valuep
bindByteSize, // value_sz
ociType, // htype
indicatorLocation, // indp,
lengthLocation, // rlenp,
IntPtr.Zero, // rcodep,
mode // mode
);
if (rc != 0) {
_connection.CheckError(errorHandle, rc);
}
defineHandle = new OciDefineHandle(statementHandle, h);
if (0 != rowBufferLength) {
uint valOffset = checked((uint)rowBufferLength);
uint indOffset = (-1 != _indicatorOffset) ? valOffset : 0;
uint lenOffset = (-1 != _lengthOffset && !_metaType.IsLong) ? valOffset : 0;
rc = TracedNativeMethods.OCIDefineArrayOfStruct(
defineHandle,
errorHandle,
valOffset,
indOffset,
lenOffset,
0 // never use rcodep above...
);
if (rc != 0) {
_connection.CheckError(errorHandle, rc);
}
}
if (_metaType.UsesNationalCharacterSet) {
Debug.Assert(!_metaType.IsLong, "LONG data may never be bound as NCHAR");
// NOTE: the order is important here; setting charsetForm will
// reset charsetId (I found this out the hard way...)
defineHandle.SetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_FORM, (int)OCI.CHARSETFORM.SQLCS_NCHAR, errorHandle);
}
if (!_connection.UnicodeEnabled) {
if (_bindAsUTF16) {
// NOTE: the order is important here; setting charsetForm will
// reset charsetId (I found this out the hard way...)
defineHandle.SetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_ID, (short)OCI.CHARSETID.OCI_UTF16ID, errorHandle);
}
}
if (_metaType.IsLong) {
// Initialize the longBuffer in the rowBuffer to null
_rowBuffer.WriteIntPtr(_valueOffset, IntPtr.Zero);
_callback = new OCI.Callback.OCICallbackDefine(_callback_GetColumnPiecewise);
rc = TracedNativeMethods.OCIDefineDynamic(
defineHandle, // defnp
errorHandle, // errhp
IntPtr.Zero, // dvoid *octxp,
_callback // OCICallbackDefine ocbfp
);
if (rc != 0) {
_connection.CheckError(errorHandle, rc);
}
}
}
finally {
// We don't need these any longer, get rid of it.
NativeBuffer.SafeDispose(ref _longBuffer);
OciHandle.SafeDispose(ref defineHandle);
}
}
internal bool Describe(ref int offset, OracleConnection connection, OciErrorHandle errorHandle) {
// Gets all of the column description information from the describe
// handle. In addition, we'll determine the position of the column
// in the rowbuffer, based upon the offset parameter, which is passed
// by ref so we can adjust the end position accordingly.
short tempub2;
byte tempub1;
OCI.DATATYPE ociType;
bool needSize = false;
bool cannotPrefetch = false;
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_NAME, out _columnName,errorHandle, _connection);
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_DATA_TYPE, out tempub2, errorHandle);
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_IS_NULL, out tempub1, errorHandle);
_isNullable = (0 != tempub1);
ociType = (OCI.DATATYPE)tempub2;
switch (ociType) {
case OCI.DATATYPE.CHAR:
case OCI.DATATYPE.VARCHAR2:
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_DATA_SIZE, out _byteSize, errorHandle);
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_FORM,out tempub1, errorHandle);
OCI.CHARSETFORM charsetForm = (OCI.CHARSETFORM)tempub1;
_bindAsUTF16 = connection.ServerVersionAtLeastOracle8;
// SQLBUVSTS 217686: the _byteSize we have is size, in bytes, of the string in its server representation. This size can be
// less than the buffer size we need to fetch the UTF16 chars for the same string which can result in
// either silent data truncation or ORA-01406 exception of Oracle.
// To calculate the byte size for UTF16 characters, we query for the size in UTF16 characters using
// OCI_ATTR_CHAR_SIZE and double it (1 UTF16 char == 2 bytes).
int charSize;
// according to Oracle's documentation, OCI_ATTR_CHAR_SIZE is supported only if both client and server >= 9
if (connection.ServerVersionAtLeastOracle9i && OCI.ClientVersionAtLeastOracle9i) {
// we can query for the char size since both client and server versions are >= 9
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_CHAR_SIZE, out tempub2, errorHandle);
charSize = tempub2;
}
else {
// if either client or server is 8 or less, we cannot use OCI_ATTR_CHAR_SIZE attribute
// in that case, we assume the worse scenario: max number of characters is same or less as number of bytes used to encode it
// (which is true in all NLS languages and UTF* encodings).
// we could query for OCI_ATTR_CHARSET_ID and calculate the max size with better efficiency, but this would
// complicate the calcs thus making the fix risky and prone for regressions.
charSize = _byteSize;
}
if (charsetForm == OCI.CHARSETFORM.SQLCS_NCHAR) {
// National Character Set
_metaType = MetaType.GetMetaTypeForType((OCI.DATATYPE.CHAR == ociType) ? OracleType.NChar : OracleType.NVarChar);
}
else {
// Database Character Set
_metaType = MetaType.GetMetaTypeForType((OCI.DATATYPE.CHAR == ociType) ? OracleType.Char : OracleType.VarChar);
if (_bindAsUTF16) {
// we deal only with UTF16 so get the size required to store same number of UTF16 chars
_byteSize *= ADP.CharSize;
}
}
// To fetch the data, we have to specify size in bytes.
// To be on the safe side and avoid regressions, select the max between the size as it
// is encoded on the server and the size we've calculated above.
_byteSize = Math.Max(_byteSize, charSize * ADP.CharSize);
needSize = true;
break;
case OCI.DATATYPE.DATE:
_metaType = MetaType.GetMetaTypeForType(OracleType.DateTime);
_byteSize = _metaType.BindSize;
needSize = true;
break;
case OCI.DATATYPE.TIMESTAMP:
_metaType = MetaType.GetMetaTypeForType(OracleType.Timestamp);
_byteSize = _metaType.BindSize;
needSize = true;
break;
case OCI.DATATYPE.TIMESTAMP_LTZ:
_metaType = MetaType.GetMetaTypeForType(OracleType.TimestampLocal);
_byteSize = _metaType.BindSize;
needSize = true;
break;
case OCI.DATATYPE.TIMESTAMP_TZ:
_metaType = MetaType.GetMetaTypeForType(OracleType.TimestampWithTZ);
_byteSize = _metaType.BindSize;
needSize = true;
break;
case OCI.DATATYPE.INTERVAL_YM:
_metaType = MetaType.GetMetaTypeForType(OracleType.IntervalYearToMonth);
_byteSize = _metaType.BindSize;
break;
case OCI.DATATYPE.INTERVAL_DS:
_metaType = MetaType.GetMetaTypeForType(OracleType.IntervalDayToSecond);
_byteSize = _metaType.BindSize;
break;
case OCI.DATATYPE.NUMBER:
_metaType = MetaType.GetMetaTypeForType(OracleType.Number);
_byteSize = _metaType.BindSize;
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_PRECISION, out _precision, errorHandle);
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_SCALE, out _scale, errorHandle);
break;
case OCI.DATATYPE.RAW:
_metaType = MetaType.GetMetaTypeForType(OracleType.Raw);
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_DATA_SIZE, out _byteSize, errorHandle);
needSize = true;
break;
case OCI.DATATYPE.ROWID:
case OCI.DATATYPE.ROWID_DESC:
case OCI.DATATYPE.UROWID:
_metaType = MetaType.GetMetaTypeForType(OracleType.RowId);
_byteSize = _metaType.BindSize;
if (connection.UnicodeEnabled) {
_bindAsUTF16 = true;
_byteSize *= ADP.CharSize; // Since Oracle reported the number of characters and UTF16 characters are two bytes each, have to adjust the buffer size
}
needSize = true;
break;
case OCI.DATATYPE.BFILE:
_metaType = MetaType.GetMetaTypeForType(OracleType.BFile);
_byteSize = _metaType.BindSize;
cannotPrefetch = true;
break;
case OCI.DATATYPE.BLOB:
_metaType = MetaType.GetMetaTypeForType(OracleType.Blob);
_byteSize = _metaType.BindSize;
cannotPrefetch = true;
break;
case OCI.DATATYPE.CLOB:
_describeHandle.GetAttribute(OCI.ATTR.OCI_ATTR_CHARSET_FORM, out tempub1, errorHandle);
_metaType = MetaType.GetMetaTypeForType((OCI.CHARSETFORM.SQLCS_NCHAR == (OCI.CHARSETFORM)tempub1) ? OracleType.NClob : OracleType.Clob);
_byteSize = _metaType.BindSize;
cannotPrefetch = true;
break;
case OCI.DATATYPE.LONG:
_metaType = MetaType.GetMetaTypeForType(OracleType.LongVarChar);
_byteSize = _metaType.BindSize;
needSize = true;
cannotPrefetch = true;
_bindAsUTF16 = connection.ServerVersionAtLeastOracle8; // MDAC #79471 - Oracle7 servers don't do Unicode
break;
case OCI.DATATYPE.LONGRAW:
_metaType = MetaType.GetMetaTypeForType(OracleType.LongRaw);
_byteSize = _metaType.BindSize;
needSize = true;
cannotPrefetch = true;
break;
default:
throw ADP.TypeNotSupported(ociType);
}
if (_isNullable) {
_indicatorOffset= offset; offset += IntPtr.Size;
}
else {
_indicatorOffset = -1;
}
if (needSize) {
_lengthOffset = offset; offset += IntPtr.Size;
}
else {
_lengthOffset = -1;
}
_valueOffset = offset;
if (OCI.DATATYPE.LONG == ociType || OCI.DATATYPE.LONGRAW == ociType) {
offset += IntPtr.Size;
}
else {
offset += _byteSize;
}
offset = (offset + (IntPtr.Size-1)) & ~(IntPtr.Size-1); // align buffer;
// We don't need this any longer, get rid of it.
OciHandle.SafeDispose(ref _describeHandle);
return cannotPrefetch;
}
internal void Dispose() {
NativeBuffer.SafeDispose(ref _longBuffer);
OciLobLocator.SafeDispose(ref _lobLocator);
OciHandle.SafeDispose(ref _describeHandle);
_columnName = null;
_metaType = null;
_callback = null;
_connection = null;
}
internal void FixupLongValueLength(NativeBuffer buffer) {
if (null != _longBuffer) {
Debug.Assert(_metaType.IsLong, "dangling long buffer?");
// Determine the actual length of the LONG/LONG RAW data read, if we
// haven't done so already.
if (-1 == _longLength) {
// Our "piecewise" fetching of LONG/LONG RAW data will extend the
// buffer by a chunk, and ask Oracle to fill it.
// Oracle calls ours _callback_GetColumnPiecewise for each new buffer.
// We create different chunk for each callback call, each chunk has its own
// length.
// Before the fix of RFC50002189, we assumed that native Oracle driver will fill each
// non-last chunk fully (with size = request one == ChunkSize),so we calculated the total
// length as fixed chunk size * (num of chunks - 1) + last chunk size!
// This assumption was wrong (RFC50002189) - Oracle driver can fill less data than the chunk size.
// The fix for RFC50002189 includes:
// * remember each chunk size separately, as part of the chunk
// * calculate and fixup the total length here (as before) and update the buffer[_lengthOffset]
_longLength = _longBuffer.TotalLengthInBytes;
// Of course, we have to convert for character data to number of
// Unicode Characters read, not number of bytes
if (_bindAsUTF16) {
Debug.Assert(0 == (_longLength & 0x1), "odd length unicode data?");
_longLength /= 2;
}
Debug.Assert(_longLength >= 0, "invalid size for LONG data?");
// Finally, we write the length back to the row buffer so we don't
// have to have two code paths to construct the managed object.
buffer.WriteInt32(_lengthOffset, _longLength);
}
}
}
internal string GetDataTypeName() {
// Returns the name of the back-end data type.
return _metaType.DataTypeName;
}
internal Type GetFieldType() {
// Returns the actual clr type that the column is.
return _metaType.BaseType;
}
internal Type GetFieldOracleType() {
// Returns the actual oracletype that the column is.
return _metaType.NoConvertType;
}
internal object GetValue(NativeBuffer_RowBuffer buffer) {
// Returns an object that contains the value of the column in the
// specified row buffer. This method returns CLS-typed objects.
if (IsDBNull(buffer)) {
return DBNull.Value;
}
//Debug.WriteLine(String.Format("{0}: {1}", _columnName, buffer.ReadInt16(_indicatorOffset+2)));
switch (_metaType.OciType) {
case OCI.DATATYPE.BFILE: {
object value;
using (OracleBFile bfile = GetOracleBFile(buffer)) {
value = bfile.Value; // reading the LOB is MUCH more expensive than constructing an object we'll throw away
}
return value;
}
case OCI.DATATYPE.RAW:
case OCI.DATATYPE.LONGRAW: {
long length = GetBytes(buffer, 0, null, 0, 0);
byte[] value = new byte[length];
GetBytes( buffer, 0, value, 0, (int)length );
return value;
}
case OCI.DATATYPE.DATE:
case OCI.DATATYPE.INT_TIMESTAMP:
case OCI.DATATYPE.INT_TIMESTAMP_TZ:
case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
return GetDateTime( buffer );
case OCI.DATATYPE.BLOB:
case OCI.DATATYPE.CLOB: {
object value;
using (OracleLob lob = GetOracleLob(buffer)) {
value = lob.Value; // reading the LOB is MUCH more expensive than constructing an object we'll throw away
}
return value;
}
case OCI.DATATYPE.INT_INTERVAL_YM:
return GetInt32( buffer );
case OCI.DATATYPE.VARNUM:
return GetDecimal( buffer );
case OCI.DATATYPE.CHAR:
case OCI.DATATYPE.VARCHAR2:
case OCI.DATATYPE.LONG:
return GetString( buffer );
case OCI.DATATYPE.INT_INTERVAL_DS:
return GetTimeSpan( buffer );
}
throw ADP.TypeNotSupported(_metaType.OciType);
}
internal object GetOracleValue(NativeBuffer_RowBuffer buffer) {
// Returns an object that contains the value of the column in the
// specified row buffer. This method returns Oracle-typed objects.
//Debug.WriteLine(String.Format("{0}: {1}", _columnName, buffer.ReadInt16(_indicatorOffset+2)));
switch (_metaType.OciType) {
case OCI.DATATYPE.BFILE:
return GetOracleBFile( buffer );
case OCI.DATATYPE.RAW:
case OCI.DATATYPE.LONGRAW:
return GetOracleBinary( buffer );
case OCI.DATATYPE.DATE:
case OCI.DATATYPE.INT_TIMESTAMP:
case OCI.DATATYPE.INT_TIMESTAMP_TZ:
case OCI.DATATYPE.INT_TIMESTAMP_LTZ:
return GetOracleDateTime( buffer );
case OCI.DATATYPE.BLOB:
case OCI.DATATYPE.CLOB:
return GetOracleLob( buffer );
case OCI.DATATYPE.INT_INTERVAL_YM:
return GetOracleMonthSpan( buffer );
case OCI.DATATYPE.VARNUM:
return GetOracleNumber( buffer );
case OCI.DATATYPE.CHAR:
case OCI.DATATYPE.VARCHAR2:
case OCI.DATATYPE.LONG:
return GetOracleString( buffer );
case OCI.DATATYPE.INT_INTERVAL_DS:
return GetOracleTimeSpan( buffer );
}
throw ADP.TypeNotSupported(_metaType.OciType);
}
//---------------------------------------------------------------------
// Get
//
// Returns an the value of the column in the specified row buffer as
// the appropriate type
//
internal long GetBytes( NativeBuffer_RowBuffer buffer, long fieldOffset, byte[] destinationBuffer, int destinationOffset, int length ) {
if (length < 0) { // MDAC 71007
throw ADP.InvalidDataLength(length);
}
if ((destinationOffset < 0) || (null != destinationBuffer && destinationOffset >= destinationBuffer.Length)) { // MDAC 71013
throw ADP.InvalidDestinationBufferIndex(destinationBuffer.Length, destinationOffset, "bufferoffset"); // NOTE: Name matches public object model OracleDataReader.GetBytes()
}
if (0 > fieldOffset || UInt32.MaxValue < fieldOffset) {
throw ADP.InvalidSourceOffset("fieldOffset", 0, UInt32.MaxValue);
}
int byteCount;
if (IsLob) {
OracleType lobType = _metaType.OracleType;
if (OracleType.Blob != lobType && OracleType.BFile != lobType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
using (OracleLob lob = new OracleLob(_lobLocator)) {
uint valueLength = (uint)lob.Length;
uint sourceOffset = (uint) fieldOffset;
if (sourceOffset > valueLength) { // MDAC 72830
throw ADP.InvalidSourceBufferIndex((int)valueLength, (int)sourceOffset, "fieldOffset"); // NOTE: Name matches public object model OracleDataReader.GetBytes()
}
byteCount = (int)(valueLength - sourceOffset);
if (null != destinationBuffer) {
byteCount = Math.Min(byteCount, length);
if (0 < byteCount) {
lob.Seek(sourceOffset,SeekOrigin.Begin);
lob.Read(destinationBuffer, destinationOffset, byteCount);
}
}
}
}
else {
if (OracleType.Raw != OracleType && OracleType.LongRaw != OracleType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
FixupLongValueLength(buffer);
int valueLength = OracleBinary.GetLength(buffer, _lengthOffset, _metaType);
int sourceOffset = (int) fieldOffset;
byteCount = valueLength - sourceOffset;
if (null != destinationBuffer) {
byteCount = Math.Min(byteCount, length);
if (0 < byteCount) {
OracleBinary.GetBytes(buffer,
_valueOffset,
_metaType,
sourceOffset,
destinationBuffer,
destinationOffset,
byteCount);
}
}
}
return Math.Max(0,byteCount);
}
internal long GetChars(NativeBuffer_RowBuffer buffer, long fieldOffset, char[] destinationBuffer, int destinationOffset, int length) {
if (length < 0) { // MDAC 71007
throw ADP.InvalidDataLength(length);
}
if ((destinationOffset < 0) || (null != destinationBuffer && destinationOffset >= destinationBuffer.Length)) { // MDAC 71013
throw ADP.InvalidDestinationBufferIndex(destinationBuffer.Length, destinationOffset, "bufferoffset"); // NOTE: Name matches public object model OracleDataReader.GetChars()
}
if (0 > fieldOffset || UInt32.MaxValue < fieldOffset) {
throw ADP.InvalidSourceOffset("fieldOffset", 0, UInt32.MaxValue);
}
int charCount;
if (IsLob) {
OracleType lobType = _metaType.OracleType;
if (OracleType.Clob != lobType
&& OracleType.NClob != lobType
&& OracleType.BFile != lobType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
using (OracleLob lob = new OracleLob(_lobLocator)) {
string s = (string)lob.Value;
int valueLength = s.Length;
int sourceOffset = (int) fieldOffset;
if (sourceOffset < 0) { // MDAC 72830
throw ADP.InvalidSourceBufferIndex(valueLength, sourceOffset, "fieldOffset"); // NOTE: Name matches public object model OracleDataReader.GetChars()
}
charCount = (int)(valueLength - sourceOffset);
if (null != destinationBuffer) {
charCount = Math.Min(charCount, length);
if (0 < charCount) {
char[] result = s.ToCharArray(sourceOffset, charCount);
Buffer.BlockCopy(result, 0, destinationBuffer, destinationOffset, charCount);
}
}
}
}
else {
if (OracleType.Char != OracleType
&& OracleType.VarChar != OracleType
&& OracleType.LongVarChar != OracleType
&& OracleType.NChar != OracleType
&& OracleType.NVarChar != OracleType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
FixupLongValueLength(buffer);
int valueLength = OracleString.GetLength(buffer, _lengthOffset, _metaType);
int sourceOffset = (int) fieldOffset;
charCount = valueLength - sourceOffset;
if (null != destinationBuffer) {
charCount = Math.Min(charCount, length);
if (0 < charCount) {
OracleString.GetChars(buffer,
_valueOffset,
_lengthOffset,
_metaType,
_connection,
_bindAsUTF16,
sourceOffset,
destinationBuffer,
destinationOffset,
charCount);
}
}
}
return Math.Max(0,charCount);
}
internal DateTime GetDateTime(NativeBuffer_RowBuffer buffer) {
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
if (typeof(DateTime) != _metaType.BaseType) {
throw ADP.InvalidCast();
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
DateTime result = OracleDateTime.MarshalToDateTime(buffer, _valueOffset, _lengthOffset, _metaType, _connection);
return result;
}
internal decimal GetDecimal(NativeBuffer_RowBuffer buffer) {
if (typeof(decimal) != _metaType.BaseType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
decimal result = OracleNumber.MarshalToDecimal(buffer, _valueOffset, _connection);
return result;
}
internal double GetDouble(NativeBuffer_RowBuffer buffer) {
if (typeof(decimal) != _metaType.BaseType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
decimal decimalValue = OracleNumber.MarshalToDecimal(buffer, _valueOffset, _connection);
double result = (double)decimalValue;
return result;
}
internal float GetFloat(NativeBuffer_RowBuffer buffer) {
if (typeof(decimal) != _metaType.BaseType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
decimal decimalValue = OracleNumber.MarshalToDecimal(buffer, _valueOffset, _connection);
float result = (float)decimalValue;
return result;
}
internal int GetInt32(NativeBuffer_RowBuffer buffer) {
if (typeof(int) != _metaType.BaseType
&& typeof(decimal) != _metaType.BaseType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
int result;
if (typeof(int) == _metaType.BaseType) {
result = OracleMonthSpan.MarshalToInt32(buffer, _valueOffset);
}
else {
result = OracleNumber.MarshalToInt32(buffer, _valueOffset, _connection);
}
return result;
}
internal Int64 GetInt64(NativeBuffer_RowBuffer buffer) {
if (typeof(decimal) != _metaType.BaseType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
Int64 result = OracleNumber.MarshalToInt64(buffer, _valueOffset, _connection);
return result;
}
internal string GetString(NativeBuffer_RowBuffer buffer) {
if (IsLob) {
OracleType lobType = _metaType.OracleType;
if (OracleType.Clob != lobType && OracleType.NClob != lobType && OracleType.BFile != lobType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
string result;
using (OracleLob lob = new OracleLob(_lobLocator)) {
result = (string)lob.Value;
}
return result;
}
else {
if (typeof(string) != _metaType.BaseType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
FixupLongValueLength(buffer);
string result = OracleString.MarshalToString(buffer, _valueOffset, _lengthOffset, _metaType, _connection, _bindAsUTF16, false);
return result;
}
}
internal TimeSpan GetTimeSpan(NativeBuffer_RowBuffer buffer) {
if (typeof(TimeSpan) != _metaType.BaseType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
throw ADP.DataReaderNoData();
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
TimeSpan result = OracleTimeSpan.MarshalToTimeSpan(buffer, _valueOffset);
return result;
}
internal OracleBFile GetOracleBFile(NativeBuffer_RowBuffer buffer) {
Debug.Assert(null == _longBuffer, "dangling long buffer?");
if (typeof(OracleBFile) != _metaType.NoConvertType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
return OracleBFile.Null;
}
OracleBFile result = new OracleBFile(_lobLocator);
return result;
}
internal OracleBinary GetOracleBinary(NativeBuffer_RowBuffer buffer) {
if (typeof(OracleBinary) != _metaType.NoConvertType) {
throw ADP.InvalidCast();
}
FixupLongValueLength(buffer);
if (IsDBNull(buffer)) {
return OracleBinary.Null;
}
OracleBinary result = new OracleBinary(buffer, _valueOffset, _lengthOffset, _metaType);
return result;
}
internal OracleDateTime GetOracleDateTime(NativeBuffer_RowBuffer buffer) {
if (typeof(OracleDateTime) != _metaType.NoConvertType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
return OracleDateTime.Null;
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
OracleDateTime result = new OracleDateTime(buffer, _valueOffset, _lengthOffset, _metaType, _connection);
return result;
}
internal OracleLob GetOracleLob(NativeBuffer_RowBuffer buffer) {
if (typeof(OracleLob) != _metaType.NoConvertType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
return OracleLob.Null;
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
OracleLob result = new OracleLob(_lobLocator);
return result;
}
internal OracleMonthSpan GetOracleMonthSpan(NativeBuffer_RowBuffer buffer) {
if (typeof(OracleMonthSpan) != _metaType.NoConvertType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
return OracleMonthSpan.Null;
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
OracleMonthSpan result = new OracleMonthSpan(buffer, _valueOffset);
return result;
}
internal OracleNumber GetOracleNumber(NativeBuffer_RowBuffer buffer) {
if (typeof(OracleNumber) != _metaType.NoConvertType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
return OracleNumber.Null;
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
OracleNumber result = new OracleNumber(buffer, _valueOffset);
return result;
}
internal OracleString GetOracleString(NativeBuffer_RowBuffer buffer) {
if (typeof(OracleString) != _metaType.NoConvertType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
return OracleString.Null;
}
FixupLongValueLength(buffer);
OracleString result = new OracleString(buffer, _valueOffset, _lengthOffset, _metaType, _connection, _bindAsUTF16, false);
return result;
}
internal OracleTimeSpan GetOracleTimeSpan(NativeBuffer_RowBuffer buffer) {
if (typeof(OracleTimeSpan) != _metaType.NoConvertType) {
throw ADP.InvalidCast();
}
if (IsDBNull(buffer)) {
return OracleTimeSpan.Null;
}
Debug.Assert(null == _longBuffer, "dangling long buffer?");
OracleTimeSpan result = new OracleTimeSpan(buffer, _valueOffset);
return result;
}
internal bool IsDBNull(NativeBuffer_RowBuffer buffer) {
// Returns true if the column value in the buffer is null.
return (_isNullable && buffer.ReadInt16(_indicatorOffset) == (Int16)OCI.INDICATOR.ISNULL);
}
internal void Rebind(OracleConnection connection, ref bool mustRelease, ref SafeHandle handleToBind) {
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// NOTE: You must have called DangerousAddRef on the buffer before
// calling this method, or you run the risk of allowing Handle
// Recycling to occur!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Here's the hook that gets called whenever we're about to fetch
// a new row, allowing us to reset any information that we shouldn't
// carry forward.
handleToBind = null;
switch (_metaType.OciType) {
case OCI.DATATYPE.LONG:
case OCI.DATATYPE.LONGRAW:
_rowBuffer.WriteInt32(_lengthOffset, 0);
_longLength = -1; // reset the length to unknown;
if (null != _longBuffer) {
_longBuffer.Reset(); // free all the memory we allocated, except the initial one
}
else {
_longBuffer = new NativeBuffer_LongColumnData();
}
handleToBind = _longBuffer;
break;
case OCI.DATATYPE.BLOB:
case OCI.DATATYPE.CLOB:
case OCI.DATATYPE.BFILE:
OciLobLocator.SafeDispose(ref _lobLocator);
_lobLocator = new OciLobLocator(connection, _metaType.OracleType);
handleToBind = _lobLocator.Descriptor;
break;
}
// We need to add-ref the handle so it can't be released somehow
// by another thread while we're fetching. Only after we do that
// can we write it to the buffer for the Oracle to use during the
// Fetch. The caller is required to provide storage for the
// handleToBind and ensure that the DangerousRelease is called
// in it's CER.
if (null != handleToBind) {
handleToBind.DangerousAddRef(ref mustRelease);
_rowBuffer.WriteIntPtr(_valueOffset, handleToBind.DangerousGetHandle());
}
}
};
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- HtmlDocument.cs
- ObjectView.cs
- TypeListConverter.cs
- WindowsTab.cs
- SerialErrors.cs
- HotCommands.cs
- HtmlTableCell.cs
- SubMenuStyle.cs
- DataGridViewColumnHeaderCell.cs
- WebPartMinimizeVerb.cs
- DbModificationCommandTree.cs
- CodeIndexerExpression.cs
- ThemeDirectoryCompiler.cs
- RawStylusInputReport.cs
- StringArrayConverter.cs
- AccessText.cs
- EpmCustomContentDeSerializer.cs
- JsonReader.cs
- DataControlField.cs
- NameValueSectionHandler.cs
- XmlDomTextWriter.cs
- ImageProxy.cs
- UnmanagedBitmapWrapper.cs
- MetadataArtifactLoaderResource.cs
- FaultHandlingFilter.cs
- Menu.cs
- MessageQueuePermissionAttribute.cs
- SelectionHighlightInfo.cs
- OciHandle.cs
- FindCriteria.cs
- DataTableTypeConverter.cs
- ActivityTypeDesigner.xaml.cs
- Int32RectValueSerializer.cs
- AVElementHelper.cs
- XmlSchemaCompilationSettings.cs
- SafeSecurityHandles.cs
- SecurityDescriptor.cs
- SymDocumentType.cs
- GridItemProviderWrapper.cs
- PackagingUtilities.cs
- PreservationFileWriter.cs
- StrongBox.cs
- OleDbError.cs
- _HTTPDateParse.cs
- AuthorizationRule.cs
- WebMessageEncodingElement.cs
- HtmlControlPersistable.cs
- DefaultValueConverter.cs
- TextEndOfParagraph.cs
- _Semaphore.cs
- SecurityPermission.cs
- Vector3DValueSerializer.cs
- COAUTHIDENTITY.cs
- DynamicVirtualDiscoSearcher.cs
- PublishLicense.cs
- PointCollection.cs
- MatrixConverter.cs
- XmlAggregates.cs
- MethodMessage.cs
- DateTimeValueSerializerContext.cs
- ApplicationInfo.cs
- Unit.cs
- UndoUnit.cs
- VisualBrush.cs
- UnknownBitmapEncoder.cs
- DataShape.cs
- XmlRawWriter.cs
- ValueOfAction.cs
- XmlSchemaSimpleTypeUnion.cs
- FrugalMap.cs
- PageContent.cs
- StateMachineWorkflowDesigner.cs
- RayHitTestParameters.cs
- TypeTypeConverter.cs
- Schedule.cs
- _BaseOverlappedAsyncResult.cs
- ModelUIElement3D.cs
- CurrencyWrapper.cs
- IDictionary.cs
- ExtenderHelpers.cs
- ArrayTypeMismatchException.cs
- CompiledRegexRunnerFactory.cs
- MessageVersion.cs
- ChtmlImageAdapter.cs
- SessionStateUtil.cs
- assemblycache.cs
- CompensationHandlingFilter.cs
- DataGridParentRows.cs
- EnvelopeVersion.cs
- NetworkStream.cs
- ToolboxItemSnapLineBehavior.cs
- StringStorage.cs
- ClientBuildManagerCallback.cs
- BinaryObjectReader.cs
- Symbol.cs
- SectionInput.cs
- GenericParameterDataContract.cs
- EventHandlers.cs
- TextBoxRenderer.cs
- CodeTypeConstructor.cs