Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / whidbey / NetFxQFE / ndp / fx / src / DataOracleClient / System / Data / OracleClient / OracleDataReader.cs / 1 / OracleDataReader.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //----------------------------------------------------------------------------- namespace System.Data.OracleClient { using System; using System.Collections; using System.Data; using System.Data.Common; using System.Data.ProviderBase; using System.Data.SqlTypes; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; //--------------------------------------------------------------------- // OracleDataReader // // 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 public class OracleDataReader : DbDataReader { private const int _prefetchMemory = 65536; // maximum amount of data to prefetch private OracleConnection _connection; private int _connectionCloseCount; // The close count of the connection; used to decide if we're zombied private OciStatementHandle _statementHandle; // the OCI statement handle we'll use to get data from; it must be non-null // for the data reader to be considered open private string _statementText; // the text of the statement we executed; in Oracle9i, you can ask for this from the Statement handle. private CommandBehavior _commandBehavior; private OracleColumn[] _columnInfo; private NativeBuffer_RowBuffer _buffer; private int _rowBufferLength; // length of one buffered row. private int _rowsToPrefetch; // maximum number of rows we should prefetch (fits into _prefetchMemory) private int _rowsTotal = 0; // number of rows that we've fetched so far. private bool _isLastBuffer; // true when we're pre-fetching, and we got end of data from the fetch. (There are still rows in the buffer) private bool _endOfData; // true when we've reached the end of the results private bool _closeConnectionToo; // true when we're created with CommandBehavior.CloseConnection private bool _keyInfoRequested; // true when we're created with CommandBehavior.KeyInfo private byte _hasRows; // true when there is at least one row to be read. private const byte x_hasRows_Unknown = 0; private const byte x_hasRows_False = 1; private const byte x_hasRows_True = 2; private static int _objectTypeCount; // Bid counter internal readonly int ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); private FieldNameLookup _fieldNameLookup; // optimizes searching by strings private DataTable _schemaTable; private int _recordsAffected; private OracleDataReader[] _refCursorDataReaders; private int _nextRefCursor; // Construct from a command and a statement handle internal OracleDataReader( OracleCommand command, OciStatementHandle statementHandle, string statementText, CommandBehavior commandBehavior ) { OracleConnection.VerifyExecutePermission(); _commandBehavior = commandBehavior; _statementHandle = statementHandle; _connection = (OracleConnection)command.Connection; _connectionCloseCount = _connection.CloseCount; _columnInfo = null; if (OCI.STMT.OCI_STMT_SELECT == command.StatementType) { FillColumnInfo(); _recordsAffected = -1; // Don't know this until we read the last row if (IsCommandBehavior(CommandBehavior.SchemaOnly)) _endOfData = true; } else { _statementHandle.GetAttribute(OCI.ATTR.OCI_ATTR_ROW_COUNT, out _recordsAffected, ErrorHandle); _endOfData = true; _hasRows = x_hasRows_False; } _statementText = statementText; _closeConnectionToo = IsCommandBehavior(CommandBehavior.CloseConnection); if (CommandType.Text == command.CommandType) _keyInfoRequested = IsCommandBehavior(CommandBehavior.KeyInfo); } internal OracleDataReader( OracleConnection connection, OciStatementHandle statementHandle ){ OracleConnection.VerifyExecutePermission(); _commandBehavior = CommandBehavior.Default; _statementHandle = statementHandle; _connection = connection; _connectionCloseCount = _connection.CloseCount; _recordsAffected = -1; // REF CURSORS must be a select statement, yes? FillColumnInfo(); } // Construct from a command and an array of ref cursor parameter ordinals internal OracleDataReader( OracleCommand command, ArrayList refCursorParameterOrdinals, string statementText, CommandBehavior commandBehavior ) { OracleConnection.VerifyExecutePermission(); _commandBehavior = commandBehavior; _statementText = statementText; _closeConnectionToo = IsCommandBehavior(CommandBehavior.CloseConnection); if (CommandType.Text == command.CommandType) _keyInfoRequested = IsCommandBehavior(CommandBehavior.KeyInfo); ArrayList refCursorDataReaders = new ArrayList(); int currentRecordsAffected = 0; OracleDataReader currentDataReader = null; for (int i=0; i < refCursorParameterOrdinals.Count; i++) { int refCursorParameterOrdinal = (int)refCursorParameterOrdinals[i]; OracleParameter resultParameter = command.Parameters[refCursorParameterOrdinal]; if (OracleType.Cursor == resultParameter.OracleType) { currentDataReader = (OracleDataReader)resultParameter.Value; currentDataReader._recordsAffected = currentRecordsAffected; refCursorDataReaders.Add(currentDataReader); resultParameter.Value = DBNull.Value; // Remove this from the output parameter list to avoid confusion. } else { Debug.Assert(0 < resultParameter.CommandSetResult, "non-ref cursor, non recordsaffected parameter?"); currentRecordsAffected += (int)resultParameter.Value; } } _refCursorDataReaders = new OracleDataReader[refCursorDataReaders.Count]; refCursorDataReaders.CopyTo(_refCursorDataReaders); // Set the first ref cursor as the result set _nextRefCursor = 0; NextResultInternal(); } override public int Depth { get { AssertReaderIsOpen("Depth"); return 0; } } private OciErrorHandle ErrorHandle { // Every OCI call needs an error handle, so make it available // internally. get { return _connection.ErrorHandle; } } override public int FieldCount { get { AssertReaderIsOpen(); if (null == _columnInfo) return 0; return _columnInfo.Length; } } override public bool HasRows { get { AssertReaderIsOpen(); bool result = (x_hasRows_True == _hasRows); if (x_hasRows_Unknown == _hasRows) { result = ReadInternal(); if (null != _buffer) _buffer.MovePrevious(); // back up over the row in the buffer so the next read will return the row we read _hasRows = (result) ? x_hasRows_True : x_hasRows_False; } return result; } } override public bool IsClosed { // We rely upon the statement handle not being null as long as the // data reader is open; once the data reader is closed, the first // thing that happens is the statement handle is nulled out. get { return (null == _statementHandle) || (null == _connection) || (_connectionCloseCount != _connection.CloseCount); } } private bool IsValidRow { get { return !(_endOfData || null == _buffer || !_buffer.CurrentPositionIsValid); } } override public int RecordsAffected { get { return _recordsAffected; } } override public object this[int i] { get { return GetValue(i); } } override public object this[string name] { get { int ordinal = GetOrdinal(name); return GetValue(ordinal); } } private void AssertReaderHasColumns() { if (0 >= FieldCount) { throw ADP.DataReaderNoData(); } } private void AssertReaderHasData() { if (!IsValidRow) { throw ADP.DataReaderNoData(); } } private void AssertReaderIsOpen(string methodName) { if (IsClosed) { throw ADP.DataReaderClosed(methodName); } } private void AssertReaderIsOpen() { // perform all the checks to make sure that the data reader and it's // connection are still open, and throw if they aren't if (null != _connection && (_connectionCloseCount != _connection.CloseCount)) Close(); if (null == _statementHandle) throw ADP.ClosedDataReaderError(); if (null == _connection || ConnectionState.Open != _connection.State) throw ADP.ClosedConnectionError(); } private object SetSchemaValue(string value) { if (ADP.IsEmpty(value)) return DBNull.Value; return value; } private void Cleanup() { // release everything; we can't do anything from here on out. if (null != _buffer) { _buffer.Dispose(); _buffer = null; } if (null != _columnInfo) { // Only cleanup the column info when it's not the data reader // that owns all the ref cursor data readers; if (null == _refCursorDataReaders) { int i = _columnInfo.Length; while (--i >= 0) { if (null != _columnInfo[i]) { _columnInfo[i].Dispose(); _columnInfo[i] = null; } } } _columnInfo = null; } } override public void Close() { IntPtr hscp; Bid.ScopeEnter(out hscp, "%d#\n", ObjectID); try { // Note that we do this first, which triggers IsClosed to return true. OciHandle.SafeDispose(ref _statementHandle); Cleanup(); if (null != _refCursorDataReaders) { int i = _refCursorDataReaders.Length; while (--i >= 0) { OracleDataReader refCursorDataReader = _refCursorDataReaders[i]; _refCursorDataReaders[i] = null; if (null != refCursorDataReader) refCursorDataReader.Dispose(); } _refCursorDataReaders = null; } // If we were asked to close the connection when we're closed, then we need to // do that now. if (_closeConnectionToo && null != _connection) _connection.Close(); _connection = null; _fieldNameLookup = null; _schemaTable = null; } finally { Bid.ScopeLeave(ref hscp); } } private DataTable CreateSchemaTable(int columnCount) { DataTable schemaTable = new DataTable("SchemaTable"); schemaTable.Locale = System.Globalization.CultureInfo.InvariantCulture; schemaTable.MinimumCapacity = columnCount; // DataColumn name = new DataColumn(SchemaTableColumn.ColumnName, typeof(System.String)); DataColumn ordinal = new DataColumn(SchemaTableColumn.ColumnOrdinal, typeof(System.Int32)); DataColumn size = new DataColumn(SchemaTableColumn.ColumnSize, typeof(System.Int32)); DataColumn precision = new DataColumn(SchemaTableColumn.NumericPrecision, typeof(System.Int16)); DataColumn scale = new DataColumn(SchemaTableColumn.NumericScale, typeof(System.Int16)); DataColumn dataType = new DataColumn(SchemaTableColumn.DataType, typeof(System.Type)); DataColumn providerType = new DataColumn(SchemaTableColumn.ProviderType, typeof(System.Int32)); DataColumn isLong = new DataColumn(SchemaTableColumn.IsLong, typeof(System.Boolean)); DataColumn isNullable = new DataColumn(SchemaTableColumn.AllowDBNull, typeof(System.Boolean)); DataColumn isAliased = new DataColumn(SchemaTableColumn.IsAliased, typeof(System.Boolean)); DataColumn isExpression = new DataColumn(SchemaTableColumn.IsExpression, typeof(System.Boolean)); DataColumn isKey = new DataColumn(SchemaTableColumn.IsKey, typeof(System.Boolean)); DataColumn isUnique = new DataColumn(SchemaTableColumn.IsUnique, typeof(System.Boolean)); DataColumn baseSchemaName = new DataColumn(SchemaTableColumn.BaseSchemaName, typeof(System.String)); DataColumn baseTableName = new DataColumn(SchemaTableColumn.BaseTableName, typeof(System.String)); DataColumn baseColumnName = new DataColumn(SchemaTableColumn.BaseColumnName, typeof(System.String)); ordinal.DefaultValue = 0; isLong.DefaultValue = false; DataColumnCollection columns = schemaTable.Columns; columns.Add(name); columns.Add(ordinal); columns.Add(size); columns.Add(precision); columns.Add(scale); columns.Add(dataType); columns.Add(providerType); columns.Add(isLong); columns.Add(isNullable); columns.Add(isAliased); columns.Add(isExpression); columns.Add(isKey); columns.Add(isUnique); columns.Add(baseSchemaName); columns.Add(baseTableName); columns.Add(baseColumnName); // mark all columns as readonly for (int i=0; i < columns.Count; i++) { columns[i].ReadOnly = true; } return schemaTable; } internal void FillColumnInfo() { // Gather the column information for the statement handle int columnCount; bool cannotPrefetch = false; // Count the number of columns _statementHandle.GetAttribute(OCI.ATTR.OCI_ATTR_PARAM_COUNT, out columnCount, ErrorHandle); _columnInfo = new OracleColumn[columnCount]; // Create column objects for each column, have them get their // descriptions and determine their location in a row buffer. _rowBufferLength = 0; for (int i = 0; i < columnCount; i++) { _columnInfo[i] = new OracleColumn(_statementHandle, i, ErrorHandle, _connection); if (_columnInfo[i].Describe(ref _rowBufferLength, _connection, ErrorHandle)) cannotPrefetch = true; } if (cannotPrefetch || 0 == _rowBufferLength) _rowsToPrefetch = 1; else _rowsToPrefetch = (_prefetchMemory + _rowBufferLength - 1) / _rowBufferLength; // at least one row... Debug.Assert(1 <= _rowsToPrefetch, "bad prefetch rows value!"); } private void FillSchemaTable(DataTable schemaTable) { Debug.Assert(null != _columnInfo, "FillSchemaTable: no columnInfo"); DataColumn ProviderSpecificDataType = new DataColumn(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(System.Type)); schemaTable.Columns.Add(ProviderSpecificDataType); int columnCount = FieldCount; OracleSqlParser parser; DbSqlParserColumnCollection parsedColumns = null; int parsedColumnsCount = 0; if (_keyInfoRequested) { parser = new OracleSqlParser(); parser.Parse(_statementText, _connection); parsedColumns = parser.Columns; parsedColumnsCount = parsedColumns.Count; } for (int i = 0; i < columnCount; ++i) { OracleColumn column = _columnInfo[i]; DataRow newRow = schemaTable.NewRow(); newRow[SchemaTableColumn.ColumnName] = column.ColumnName; newRow[SchemaTableColumn.ColumnOrdinal] = column.Ordinal; if (column.IsLong | column.IsLob) newRow[SchemaTableColumn.ColumnSize] = Int32.MaxValue; //MDAC 82554 else newRow[SchemaTableColumn.ColumnSize] = column.SchemaTableSize; newRow[SchemaTableColumn.NumericPrecision] = column.Precision; newRow[SchemaTableColumn.NumericScale] = column.Scale; newRow[SchemaTableColumn.DataType] = column.GetFieldType(); newRow[ProviderSpecificDataType] = column.GetFieldOracleType(); newRow[SchemaTableColumn.ProviderType] = column.OracleType; newRow[SchemaTableColumn.IsLong] = column.IsLong | column.IsLob; newRow[SchemaTableColumn.AllowDBNull] = column.IsNullable; if (_keyInfoRequested && parsedColumnsCount == columnCount) { DbSqlParserColumn parsedColumn = parsedColumns[i]; newRow[SchemaTableColumn.IsAliased] = parsedColumn.IsAliased; newRow[SchemaTableColumn.IsExpression] = parsedColumn.IsExpression; newRow[SchemaTableColumn.IsKey] = parsedColumn.IsKey; newRow[SchemaTableColumn.IsUnique] = parsedColumn.IsUnique; newRow[SchemaTableColumn.BaseSchemaName] = SetSchemaValue(OracleSqlParser.CatalogCase(parsedColumn.SchemaName)); newRow[SchemaTableColumn.BaseTableName] = SetSchemaValue(OracleSqlParser.CatalogCase(parsedColumn.TableName)); newRow[SchemaTableColumn.BaseColumnName] = SetSchemaValue(OracleSqlParser.CatalogCase(parsedColumn.ColumnName)); } else { newRow[SchemaTableColumn.IsAliased] = DBNull.Value; // don't know newRow[SchemaTableColumn.IsExpression] = DBNull.Value; // don't know newRow[SchemaTableColumn.IsKey] = DBNull.Value; // don't know newRow[SchemaTableColumn.IsUnique] = DBNull.Value; // don't know newRow[SchemaTableColumn.BaseSchemaName] = DBNull.Value; // don't know newRow[SchemaTableColumn.BaseTableName] = DBNull.Value; // don't know newRow[SchemaTableColumn.BaseColumnName] = DBNull.Value; // don't know } schemaTable.Rows.Add(newRow); newRow.AcceptChanges(); } } override public string GetDataTypeName(int i) { AssertReaderIsOpen(); if (null == _columnInfo) throw ADP.NoData(); return _columnInfo[i].GetDataTypeName(); } override public Type GetProviderSpecificFieldType(int i) { if (null == _columnInfo) { AssertReaderIsOpen(); throw ADP.NoData(); } return _columnInfo[i].GetFieldOracleType(); } override public IEnumerator GetEnumerator() { return new DbEnumerator((IDataReader)this, IsCommandBehavior(CommandBehavior.CloseConnection)); } override public Type GetFieldType(int i) { if (null == _columnInfo) { AssertReaderIsOpen(); throw ADP.NoData(); } return _columnInfo[i].GetFieldType(); } override public string GetName(int i) { if (null == _columnInfo) { AssertReaderIsOpen(); throw ADP.NoData(); } return _columnInfo[i].ColumnName; } override public int GetOrdinal(string name) { AssertReaderIsOpen("GetOrdinal"); AssertReaderHasColumns(); if (null == _fieldNameLookup) { _fieldNameLookup = new FieldNameLookup(this, -1); } return _fieldNameLookup.GetOrdinal(name); } override public DataTable GetSchemaTable() { DataTable schemaTable = _schemaTable; if (null == schemaTable) { AssertReaderIsOpen("GetSchemaTable"); if (0 < FieldCount) { schemaTable = CreateSchemaTable(FieldCount); FillSchemaTable(schemaTable); _schemaTable = schemaTable; } else if (0 > FieldCount) { throw ADP.DataReaderNoData(); } } return schemaTable; } override public object GetValue(int i) { AssertReaderIsOpen(); AssertReaderHasData(); object value = _columnInfo[i].GetValue(_buffer); return value; } override public int GetValues(object[] values) { if (null == values) throw ADP.ArgumentNull("values"); AssertReaderIsOpen(); AssertReaderHasData(); int copy = Math.Min(values.Length, FieldCount); for (int i = 0; i < copy; ++i) { values[i] = _columnInfo[i].GetValue(_buffer); } return copy; } override public bool GetBoolean(int i) { // The Get methods all defer to the OracleColumn object // to perform the work. throw ADP.NotSupported(); // Oracle doesn't really have boolean values } override public byte GetByte(int i) { throw ADP.NotSupported(); // Oracle doesn't really have single-byte values } override public long GetBytes( int i, long fieldOffset, byte[] buffer2, int bufferoffset, int length ) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetBytes(_buffer, fieldOffset, buffer2, bufferoffset, length); } override public char GetChar(int i) { throw ADP.NotSupported(); // Oracle doesn't really have single-char values } override public long GetChars( int i, long fieldOffset, char[] buffer2, int bufferoffset, int length ) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetChars(_buffer, fieldOffset, buffer2, bufferoffset, length); } override public DateTime GetDateTime(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetDateTime(_buffer); } override public decimal GetDecimal(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetDecimal(_buffer); } override public double GetDouble(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetDouble(_buffer); } override public float GetFloat(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetFloat(_buffer); } override public Guid GetGuid(int i) { throw ADP.NotSupported(); // Oracle doesn't really have GUID values. } override public short GetInt16(int i) { throw ADP.NotSupported(); // Oracle doesn't really have GUID values. } override public int GetInt32(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetInt32(_buffer); } override public long GetInt64(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetInt64(_buffer); } override public Object GetProviderSpecificValue(int i) { return GetOracleValue(i); } override public int GetProviderSpecificValues(object[] values) { return GetOracleValues(values); } override public string GetString(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetString(_buffer); } public TimeSpan GetTimeSpan(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetTimeSpan(_buffer); } public OracleBFile GetOracleBFile(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleBFile(_buffer); } public OracleBinary GetOracleBinary(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleBinary(_buffer); } public OracleDateTime GetOracleDateTime(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleDateTime(_buffer); } public OracleLob GetOracleLob(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleLob(_buffer); } public OracleMonthSpan GetOracleMonthSpan(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleMonthSpan(_buffer); } public OracleNumber GetOracleNumber(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleNumber(_buffer); } public OracleString GetOracleString(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleString(_buffer); } public OracleTimeSpan GetOracleTimeSpan(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleTimeSpan(_buffer); } public object GetOracleValue(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleValue(_buffer); } public int GetOracleValues(object[] values) { if (null == values) throw ADP.ArgumentNull("values"); AssertReaderIsOpen(); AssertReaderHasData(); int copy = Math.Min(values.Length, FieldCount); for (int i = 0; i < copy; ++i) { values[i] = GetOracleValue(i); } return copy; } private bool IsCommandBehavior(CommandBehavior condition) { return (condition == (condition & _commandBehavior)); } override public bool IsDBNull(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].IsDBNull(_buffer); } override public bool NextResult() { IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); try { AssertReaderIsOpen("NextResult"); _fieldNameLookup = null; _schemaTable = null; return NextResultInternal(); } finally { Bid.ScopeLeave(ref hscp); } } private bool NextResultInternal() { Cleanup(); if (null == _refCursorDataReaders || _nextRefCursor >= _refCursorDataReaders.Length) { _endOfData = true; // force current result to be done. _hasRows = x_hasRows_False; return false; } if (_nextRefCursor > 0) { _refCursorDataReaders[_nextRefCursor-1].Dispose(); _refCursorDataReaders[_nextRefCursor-1] = null; } // Note that we do this first, which triggers IsClosed to return true. OciStatementHandle oldStatementHandle = _statementHandle; _statementHandle = _refCursorDataReaders[_nextRefCursor]._statementHandle; OciHandle.SafeDispose(ref oldStatementHandle); _connection = _refCursorDataReaders[_nextRefCursor]._connection; _connectionCloseCount = _refCursorDataReaders[_nextRefCursor]._connectionCloseCount; _hasRows = _refCursorDataReaders[_nextRefCursor]._hasRows; _recordsAffected = _refCursorDataReaders[_nextRefCursor]._recordsAffected; _columnInfo = _refCursorDataReaders[_nextRefCursor]._columnInfo; _rowBufferLength = _refCursorDataReaders[_nextRefCursor]._rowBufferLength; _rowsToPrefetch = _refCursorDataReaders[_nextRefCursor]._rowsToPrefetch; _nextRefCursor++; _endOfData = false; _isLastBuffer = false; _rowsTotal = 0; return true; } override public bool Read() { IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); try { AssertReaderIsOpen("Read"); bool result = ReadInternal(); if (result) _hasRows = x_hasRows_True; return result; } finally { Bid.ScopeLeave(ref hscp); } } private bool ReadInternal() { if (_endOfData) return false; int rc; int columnCount = _columnInfo.Length; int i; NativeBuffer_RowBuffer buffer = _buffer; bool mustRelease = false; bool[] mustReleaseBindHandle = new bool[columnCount]; SafeHandle[] bindHandle = new SafeHandle[columnCount]; RuntimeHelpers.PrepareConstrainedRegions(); try { // Define each of the column buffers to Oracle, but only if it hasn't // been defined before. if (null == buffer) { int templen = (_rowsToPrefetch > 1) ? _rowBufferLength : 0; // Only tell oracle about the buffer length if we intend to fetch more rows buffer = new NativeBuffer_RowBuffer(_rowBufferLength, _rowsToPrefetch); buffer.DangerousAddRef(ref mustRelease); for (i = 0; i < columnCount; ++i) _columnInfo[i].Bind(_statementHandle, buffer, ErrorHandle, templen); _buffer = buffer; } else { buffer.DangerousAddRef(ref mustRelease); } // If we still have more data in the buffers we've pre-fetched, then // we'll use it; we don't want to go to the server more than we absolutely // have to. if (buffer.MoveNext()) return true; // If we've read the last buffer, and we've exhausted it, then we're // really at the end of the data. if ( _isLastBuffer ) { _endOfData = true; return false; } // Reset the buffer back to the beginning. buffer.MoveFirst(); // For LONG and LOB data, we have to do work to prepare for each row (that's // why we don't prefetch rows that have these data types) if (1 == _rowsToPrefetch) { for (i = 0; i < columnCount; ++i) _columnInfo[i].Rebind(_connection, ref mustReleaseBindHandle[i], ref bindHandle[i]); } // Now fetch the rows required. Debug.Assert(0 < _rowsToPrefetch, "fetching 0 rows will cancel the cursor"); rc = TracedNativeMethods.OCIStmtFetch( _statementHandle, // stmtp ErrorHandle, // errhp _rowsToPrefetch, // crows OCI.FETCH.OCI_FETCH_NEXT, // orientation OCI.MODE.OCI_DEFAULT // mode ); // Keep track of how many rows we actually fetched so far. int previousRowsTotal = _rowsTotal; _statementHandle.GetAttribute(OCI.ATTR.OCI_ATTR_ROW_COUNT, out _rowsTotal, ErrorHandle); if (0 == rc) return true; if ((int)OCI.RETURNCODE.OCI_SUCCESS_WITH_INFO == rc) { _connection.CheckError(ErrorHandle, rc); return true; } if ((int)OCI.RETURNCODE.OCI_NO_DATA == rc) { int rowsFetched = _rowsTotal - previousRowsTotal; if (0 == rowsFetched) { if (0 == _rowsTotal) _hasRows = x_hasRows_False; _endOfData = true; return false; } buffer.NumberOfRows = rowsFetched; _isLastBuffer = true; return true; } _endOfData = true; _connection.CheckError(ErrorHandle, rc); return false; } finally { if (1 == _rowsToPrefetch) { for (i = 0; i < columnCount; ++i) { if (mustReleaseBindHandle[i]) { bindHandle[i].DangerousRelease(); } } } if (mustRelease) { buffer.DangerousRelease(); } } } } } // 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.Collections; using System.Data; using System.Data.Common; using System.Data.ProviderBase; using System.Data.SqlTypes; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; //--------------------------------------------------------------------- // OracleDataReader // // 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 public class OracleDataReader : DbDataReader { private const int _prefetchMemory = 65536; // maximum amount of data to prefetch private OracleConnection _connection; private int _connectionCloseCount; // The close count of the connection; used to decide if we're zombied private OciStatementHandle _statementHandle; // the OCI statement handle we'll use to get data from; it must be non-null // for the data reader to be considered open private string _statementText; // the text of the statement we executed; in Oracle9i, you can ask for this from the Statement handle. private CommandBehavior _commandBehavior; private OracleColumn[] _columnInfo; private NativeBuffer_RowBuffer _buffer; private int _rowBufferLength; // length of one buffered row. private int _rowsToPrefetch; // maximum number of rows we should prefetch (fits into _prefetchMemory) private int _rowsTotal = 0; // number of rows that we've fetched so far. private bool _isLastBuffer; // true when we're pre-fetching, and we got end of data from the fetch. (There are still rows in the buffer) private bool _endOfData; // true when we've reached the end of the results private bool _closeConnectionToo; // true when we're created with CommandBehavior.CloseConnection private bool _keyInfoRequested; // true when we're created with CommandBehavior.KeyInfo private byte _hasRows; // true when there is at least one row to be read. private const byte x_hasRows_Unknown = 0; private const byte x_hasRows_False = 1; private const byte x_hasRows_True = 2; private static int _objectTypeCount; // Bid counter internal readonly int ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); private FieldNameLookup _fieldNameLookup; // optimizes searching by strings private DataTable _schemaTable; private int _recordsAffected; private OracleDataReader[] _refCursorDataReaders; private int _nextRefCursor; // Construct from a command and a statement handle internal OracleDataReader( OracleCommand command, OciStatementHandle statementHandle, string statementText, CommandBehavior commandBehavior ) { OracleConnection.VerifyExecutePermission(); _commandBehavior = commandBehavior; _statementHandle = statementHandle; _connection = (OracleConnection)command.Connection; _connectionCloseCount = _connection.CloseCount; _columnInfo = null; if (OCI.STMT.OCI_STMT_SELECT == command.StatementType) { FillColumnInfo(); _recordsAffected = -1; // Don't know this until we read the last row if (IsCommandBehavior(CommandBehavior.SchemaOnly)) _endOfData = true; } else { _statementHandle.GetAttribute(OCI.ATTR.OCI_ATTR_ROW_COUNT, out _recordsAffected, ErrorHandle); _endOfData = true; _hasRows = x_hasRows_False; } _statementText = statementText; _closeConnectionToo = IsCommandBehavior(CommandBehavior.CloseConnection); if (CommandType.Text == command.CommandType) _keyInfoRequested = IsCommandBehavior(CommandBehavior.KeyInfo); } internal OracleDataReader( OracleConnection connection, OciStatementHandle statementHandle ){ OracleConnection.VerifyExecutePermission(); _commandBehavior = CommandBehavior.Default; _statementHandle = statementHandle; _connection = connection; _connectionCloseCount = _connection.CloseCount; _recordsAffected = -1; // REF CURSORS must be a select statement, yes? FillColumnInfo(); } // Construct from a command and an array of ref cursor parameter ordinals internal OracleDataReader( OracleCommand command, ArrayList refCursorParameterOrdinals, string statementText, CommandBehavior commandBehavior ) { OracleConnection.VerifyExecutePermission(); _commandBehavior = commandBehavior; _statementText = statementText; _closeConnectionToo = IsCommandBehavior(CommandBehavior.CloseConnection); if (CommandType.Text == command.CommandType) _keyInfoRequested = IsCommandBehavior(CommandBehavior.KeyInfo); ArrayList refCursorDataReaders = new ArrayList(); int currentRecordsAffected = 0; OracleDataReader currentDataReader = null; for (int i=0; i < refCursorParameterOrdinals.Count; i++) { int refCursorParameterOrdinal = (int)refCursorParameterOrdinals[i]; OracleParameter resultParameter = command.Parameters[refCursorParameterOrdinal]; if (OracleType.Cursor == resultParameter.OracleType) { currentDataReader = (OracleDataReader)resultParameter.Value; currentDataReader._recordsAffected = currentRecordsAffected; refCursorDataReaders.Add(currentDataReader); resultParameter.Value = DBNull.Value; // Remove this from the output parameter list to avoid confusion. } else { Debug.Assert(0 < resultParameter.CommandSetResult, "non-ref cursor, non recordsaffected parameter?"); currentRecordsAffected += (int)resultParameter.Value; } } _refCursorDataReaders = new OracleDataReader[refCursorDataReaders.Count]; refCursorDataReaders.CopyTo(_refCursorDataReaders); // Set the first ref cursor as the result set _nextRefCursor = 0; NextResultInternal(); } override public int Depth { get { AssertReaderIsOpen("Depth"); return 0; } } private OciErrorHandle ErrorHandle { // Every OCI call needs an error handle, so make it available // internally. get { return _connection.ErrorHandle; } } override public int FieldCount { get { AssertReaderIsOpen(); if (null == _columnInfo) return 0; return _columnInfo.Length; } } override public bool HasRows { get { AssertReaderIsOpen(); bool result = (x_hasRows_True == _hasRows); if (x_hasRows_Unknown == _hasRows) { result = ReadInternal(); if (null != _buffer) _buffer.MovePrevious(); // back up over the row in the buffer so the next read will return the row we read _hasRows = (result) ? x_hasRows_True : x_hasRows_False; } return result; } } override public bool IsClosed { // We rely upon the statement handle not being null as long as the // data reader is open; once the data reader is closed, the first // thing that happens is the statement handle is nulled out. get { return (null == _statementHandle) || (null == _connection) || (_connectionCloseCount != _connection.CloseCount); } } private bool IsValidRow { get { return !(_endOfData || null == _buffer || !_buffer.CurrentPositionIsValid); } } override public int RecordsAffected { get { return _recordsAffected; } } override public object this[int i] { get { return GetValue(i); } } override public object this[string name] { get { int ordinal = GetOrdinal(name); return GetValue(ordinal); } } private void AssertReaderHasColumns() { if (0 >= FieldCount) { throw ADP.DataReaderNoData(); } } private void AssertReaderHasData() { if (!IsValidRow) { throw ADP.DataReaderNoData(); } } private void AssertReaderIsOpen(string methodName) { if (IsClosed) { throw ADP.DataReaderClosed(methodName); } } private void AssertReaderIsOpen() { // perform all the checks to make sure that the data reader and it's // connection are still open, and throw if they aren't if (null != _connection && (_connectionCloseCount != _connection.CloseCount)) Close(); if (null == _statementHandle) throw ADP.ClosedDataReaderError(); if (null == _connection || ConnectionState.Open != _connection.State) throw ADP.ClosedConnectionError(); } private object SetSchemaValue(string value) { if (ADP.IsEmpty(value)) return DBNull.Value; return value; } private void Cleanup() { // release everything; we can't do anything from here on out. if (null != _buffer) { _buffer.Dispose(); _buffer = null; } if (null != _columnInfo) { // Only cleanup the column info when it's not the data reader // that owns all the ref cursor data readers; if (null == _refCursorDataReaders) { int i = _columnInfo.Length; while (--i >= 0) { if (null != _columnInfo[i]) { _columnInfo[i].Dispose(); _columnInfo[i] = null; } } } _columnInfo = null; } } override public void Close() { IntPtr hscp; Bid.ScopeEnter(out hscp, "%d#\n", ObjectID); try { // Note that we do this first, which triggers IsClosed to return true. OciHandle.SafeDispose(ref _statementHandle); Cleanup(); if (null != _refCursorDataReaders) { int i = _refCursorDataReaders.Length; while (--i >= 0) { OracleDataReader refCursorDataReader = _refCursorDataReaders[i]; _refCursorDataReaders[i] = null; if (null != refCursorDataReader) refCursorDataReader.Dispose(); } _refCursorDataReaders = null; } // If we were asked to close the connection when we're closed, then we need to // do that now. if (_closeConnectionToo && null != _connection) _connection.Close(); _connection = null; _fieldNameLookup = null; _schemaTable = null; } finally { Bid.ScopeLeave(ref hscp); } } private DataTable CreateSchemaTable(int columnCount) { DataTable schemaTable = new DataTable("SchemaTable"); schemaTable.Locale = System.Globalization.CultureInfo.InvariantCulture; schemaTable.MinimumCapacity = columnCount; // DataColumn name = new DataColumn(SchemaTableColumn.ColumnName, typeof(System.String)); DataColumn ordinal = new DataColumn(SchemaTableColumn.ColumnOrdinal, typeof(System.Int32)); DataColumn size = new DataColumn(SchemaTableColumn.ColumnSize, typeof(System.Int32)); DataColumn precision = new DataColumn(SchemaTableColumn.NumericPrecision, typeof(System.Int16)); DataColumn scale = new DataColumn(SchemaTableColumn.NumericScale, typeof(System.Int16)); DataColumn dataType = new DataColumn(SchemaTableColumn.DataType, typeof(System.Type)); DataColumn providerType = new DataColumn(SchemaTableColumn.ProviderType, typeof(System.Int32)); DataColumn isLong = new DataColumn(SchemaTableColumn.IsLong, typeof(System.Boolean)); DataColumn isNullable = new DataColumn(SchemaTableColumn.AllowDBNull, typeof(System.Boolean)); DataColumn isAliased = new DataColumn(SchemaTableColumn.IsAliased, typeof(System.Boolean)); DataColumn isExpression = new DataColumn(SchemaTableColumn.IsExpression, typeof(System.Boolean)); DataColumn isKey = new DataColumn(SchemaTableColumn.IsKey, typeof(System.Boolean)); DataColumn isUnique = new DataColumn(SchemaTableColumn.IsUnique, typeof(System.Boolean)); DataColumn baseSchemaName = new DataColumn(SchemaTableColumn.BaseSchemaName, typeof(System.String)); DataColumn baseTableName = new DataColumn(SchemaTableColumn.BaseTableName, typeof(System.String)); DataColumn baseColumnName = new DataColumn(SchemaTableColumn.BaseColumnName, typeof(System.String)); ordinal.DefaultValue = 0; isLong.DefaultValue = false; DataColumnCollection columns = schemaTable.Columns; columns.Add(name); columns.Add(ordinal); columns.Add(size); columns.Add(precision); columns.Add(scale); columns.Add(dataType); columns.Add(providerType); columns.Add(isLong); columns.Add(isNullable); columns.Add(isAliased); columns.Add(isExpression); columns.Add(isKey); columns.Add(isUnique); columns.Add(baseSchemaName); columns.Add(baseTableName); columns.Add(baseColumnName); // mark all columns as readonly for (int i=0; i < columns.Count; i++) { columns[i].ReadOnly = true; } return schemaTable; } internal void FillColumnInfo() { // Gather the column information for the statement handle int columnCount; bool cannotPrefetch = false; // Count the number of columns _statementHandle.GetAttribute(OCI.ATTR.OCI_ATTR_PARAM_COUNT, out columnCount, ErrorHandle); _columnInfo = new OracleColumn[columnCount]; // Create column objects for each column, have them get their // descriptions and determine their location in a row buffer. _rowBufferLength = 0; for (int i = 0; i < columnCount; i++) { _columnInfo[i] = new OracleColumn(_statementHandle, i, ErrorHandle, _connection); if (_columnInfo[i].Describe(ref _rowBufferLength, _connection, ErrorHandle)) cannotPrefetch = true; } if (cannotPrefetch || 0 == _rowBufferLength) _rowsToPrefetch = 1; else _rowsToPrefetch = (_prefetchMemory + _rowBufferLength - 1) / _rowBufferLength; // at least one row... Debug.Assert(1 <= _rowsToPrefetch, "bad prefetch rows value!"); } private void FillSchemaTable(DataTable schemaTable) { Debug.Assert(null != _columnInfo, "FillSchemaTable: no columnInfo"); DataColumn ProviderSpecificDataType = new DataColumn(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(System.Type)); schemaTable.Columns.Add(ProviderSpecificDataType); int columnCount = FieldCount; OracleSqlParser parser; DbSqlParserColumnCollection parsedColumns = null; int parsedColumnsCount = 0; if (_keyInfoRequested) { parser = new OracleSqlParser(); parser.Parse(_statementText, _connection); parsedColumns = parser.Columns; parsedColumnsCount = parsedColumns.Count; } for (int i = 0; i < columnCount; ++i) { OracleColumn column = _columnInfo[i]; DataRow newRow = schemaTable.NewRow(); newRow[SchemaTableColumn.ColumnName] = column.ColumnName; newRow[SchemaTableColumn.ColumnOrdinal] = column.Ordinal; if (column.IsLong | column.IsLob) newRow[SchemaTableColumn.ColumnSize] = Int32.MaxValue; //MDAC 82554 else newRow[SchemaTableColumn.ColumnSize] = column.SchemaTableSize; newRow[SchemaTableColumn.NumericPrecision] = column.Precision; newRow[SchemaTableColumn.NumericScale] = column.Scale; newRow[SchemaTableColumn.DataType] = column.GetFieldType(); newRow[ProviderSpecificDataType] = column.GetFieldOracleType(); newRow[SchemaTableColumn.ProviderType] = column.OracleType; newRow[SchemaTableColumn.IsLong] = column.IsLong | column.IsLob; newRow[SchemaTableColumn.AllowDBNull] = column.IsNullable; if (_keyInfoRequested && parsedColumnsCount == columnCount) { DbSqlParserColumn parsedColumn = parsedColumns[i]; newRow[SchemaTableColumn.IsAliased] = parsedColumn.IsAliased; newRow[SchemaTableColumn.IsExpression] = parsedColumn.IsExpression; newRow[SchemaTableColumn.IsKey] = parsedColumn.IsKey; newRow[SchemaTableColumn.IsUnique] = parsedColumn.IsUnique; newRow[SchemaTableColumn.BaseSchemaName] = SetSchemaValue(OracleSqlParser.CatalogCase(parsedColumn.SchemaName)); newRow[SchemaTableColumn.BaseTableName] = SetSchemaValue(OracleSqlParser.CatalogCase(parsedColumn.TableName)); newRow[SchemaTableColumn.BaseColumnName] = SetSchemaValue(OracleSqlParser.CatalogCase(parsedColumn.ColumnName)); } else { newRow[SchemaTableColumn.IsAliased] = DBNull.Value; // don't know newRow[SchemaTableColumn.IsExpression] = DBNull.Value; // don't know newRow[SchemaTableColumn.IsKey] = DBNull.Value; // don't know newRow[SchemaTableColumn.IsUnique] = DBNull.Value; // don't know newRow[SchemaTableColumn.BaseSchemaName] = DBNull.Value; // don't know newRow[SchemaTableColumn.BaseTableName] = DBNull.Value; // don't know newRow[SchemaTableColumn.BaseColumnName] = DBNull.Value; // don't know } schemaTable.Rows.Add(newRow); newRow.AcceptChanges(); } } override public string GetDataTypeName(int i) { AssertReaderIsOpen(); if (null == _columnInfo) throw ADP.NoData(); return _columnInfo[i].GetDataTypeName(); } override public Type GetProviderSpecificFieldType(int i) { if (null == _columnInfo) { AssertReaderIsOpen(); throw ADP.NoData(); } return _columnInfo[i].GetFieldOracleType(); } override public IEnumerator GetEnumerator() { return new DbEnumerator((IDataReader)this, IsCommandBehavior(CommandBehavior.CloseConnection)); } override public Type GetFieldType(int i) { if (null == _columnInfo) { AssertReaderIsOpen(); throw ADP.NoData(); } return _columnInfo[i].GetFieldType(); } override public string GetName(int i) { if (null == _columnInfo) { AssertReaderIsOpen(); throw ADP.NoData(); } return _columnInfo[i].ColumnName; } override public int GetOrdinal(string name) { AssertReaderIsOpen("GetOrdinal"); AssertReaderHasColumns(); if (null == _fieldNameLookup) { _fieldNameLookup = new FieldNameLookup(this, -1); } return _fieldNameLookup.GetOrdinal(name); } override public DataTable GetSchemaTable() { DataTable schemaTable = _schemaTable; if (null == schemaTable) { AssertReaderIsOpen("GetSchemaTable"); if (0 < FieldCount) { schemaTable = CreateSchemaTable(FieldCount); FillSchemaTable(schemaTable); _schemaTable = schemaTable; } else if (0 > FieldCount) { throw ADP.DataReaderNoData(); } } return schemaTable; } override public object GetValue(int i) { AssertReaderIsOpen(); AssertReaderHasData(); object value = _columnInfo[i].GetValue(_buffer); return value; } override public int GetValues(object[] values) { if (null == values) throw ADP.ArgumentNull("values"); AssertReaderIsOpen(); AssertReaderHasData(); int copy = Math.Min(values.Length, FieldCount); for (int i = 0; i < copy; ++i) { values[i] = _columnInfo[i].GetValue(_buffer); } return copy; } override public bool GetBoolean(int i) { // The Get methods all defer to the OracleColumn object // to perform the work. throw ADP.NotSupported(); // Oracle doesn't really have boolean values } override public byte GetByte(int i) { throw ADP.NotSupported(); // Oracle doesn't really have single-byte values } override public long GetBytes( int i, long fieldOffset, byte[] buffer2, int bufferoffset, int length ) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetBytes(_buffer, fieldOffset, buffer2, bufferoffset, length); } override public char GetChar(int i) { throw ADP.NotSupported(); // Oracle doesn't really have single-char values } override public long GetChars( int i, long fieldOffset, char[] buffer2, int bufferoffset, int length ) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetChars(_buffer, fieldOffset, buffer2, bufferoffset, length); } override public DateTime GetDateTime(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetDateTime(_buffer); } override public decimal GetDecimal(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetDecimal(_buffer); } override public double GetDouble(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetDouble(_buffer); } override public float GetFloat(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetFloat(_buffer); } override public Guid GetGuid(int i) { throw ADP.NotSupported(); // Oracle doesn't really have GUID values. } override public short GetInt16(int i) { throw ADP.NotSupported(); // Oracle doesn't really have GUID values. } override public int GetInt32(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetInt32(_buffer); } override public long GetInt64(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetInt64(_buffer); } override public Object GetProviderSpecificValue(int i) { return GetOracleValue(i); } override public int GetProviderSpecificValues(object[] values) { return GetOracleValues(values); } override public string GetString(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetString(_buffer); } public TimeSpan GetTimeSpan(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetTimeSpan(_buffer); } public OracleBFile GetOracleBFile(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleBFile(_buffer); } public OracleBinary GetOracleBinary(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleBinary(_buffer); } public OracleDateTime GetOracleDateTime(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleDateTime(_buffer); } public OracleLob GetOracleLob(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleLob(_buffer); } public OracleMonthSpan GetOracleMonthSpan(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleMonthSpan(_buffer); } public OracleNumber GetOracleNumber(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleNumber(_buffer); } public OracleString GetOracleString(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleString(_buffer); } public OracleTimeSpan GetOracleTimeSpan(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleTimeSpan(_buffer); } public object GetOracleValue(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].GetOracleValue(_buffer); } public int GetOracleValues(object[] values) { if (null == values) throw ADP.ArgumentNull("values"); AssertReaderIsOpen(); AssertReaderHasData(); int copy = Math.Min(values.Length, FieldCount); for (int i = 0; i < copy; ++i) { values[i] = GetOracleValue(i); } return copy; } private bool IsCommandBehavior(CommandBehavior condition) { return (condition == (condition & _commandBehavior)); } override public bool IsDBNull(int i) { AssertReaderIsOpen(); AssertReaderHasData(); return _columnInfo[i].IsDBNull(_buffer); } override public bool NextResult() { IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); try { AssertReaderIsOpen("NextResult"); _fieldNameLookup = null; _schemaTable = null; return NextResultInternal(); } finally { Bid.ScopeLeave(ref hscp); } } private bool NextResultInternal() { Cleanup(); if (null == _refCursorDataReaders || _nextRefCursor >= _refCursorDataReaders.Length) { _endOfData = true; // force current result to be done. _hasRows = x_hasRows_False; return false; } if (_nextRefCursor > 0) { _refCursorDataReaders[_nextRefCursor-1].Dispose(); _refCursorDataReaders[_nextRefCursor-1] = null; } // Note that we do this first, which triggers IsClosed to return true. OciStatementHandle oldStatementHandle = _statementHandle; _statementHandle = _refCursorDataReaders[_nextRefCursor]._statementHandle; OciHandle.SafeDispose(ref oldStatementHandle); _connection = _refCursorDataReaders[_nextRefCursor]._connection; _connectionCloseCount = _refCursorDataReaders[_nextRefCursor]._connectionCloseCount; _hasRows = _refCursorDataReaders[_nextRefCursor]._hasRows; _recordsAffected = _refCursorDataReaders[_nextRefCursor]._recordsAffected; _columnInfo = _refCursorDataReaders[_nextRefCursor]._columnInfo; _rowBufferLength = _refCursorDataReaders[_nextRefCursor]._rowBufferLength; _rowsToPrefetch = _refCursorDataReaders[_nextRefCursor]._rowsToPrefetch; _nextRefCursor++; _endOfData = false; _isLastBuffer = false; _rowsTotal = 0; return true; } override public bool Read() { IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); try { AssertReaderIsOpen("Read"); bool result = ReadInternal(); if (result) _hasRows = x_hasRows_True; return result; } finally { Bid.ScopeLeave(ref hscp); } } private bool ReadInternal() { if (_endOfData) return false; int rc; int columnCount = _columnInfo.Length; int i; NativeBuffer_RowBuffer buffer = _buffer; bool mustRelease = false; bool[] mustReleaseBindHandle = new bool[columnCount]; SafeHandle[] bindHandle = new SafeHandle[columnCount]; RuntimeHelpers.PrepareConstrainedRegions(); try { // Define each of the column buffers to Oracle, but only if it hasn't // been defined before. if (null == buffer) { int templen = (_rowsToPrefetch > 1) ? _rowBufferLength : 0; // Only tell oracle about the buffer length if we intend to fetch more rows buffer = new NativeBuffer_RowBuffer(_rowBufferLength, _rowsToPrefetch); buffer.DangerousAddRef(ref mustRelease); for (i = 0; i < columnCount; ++i) _columnInfo[i].Bind(_statementHandle, buffer, ErrorHandle, templen); _buffer = buffer; } else { buffer.DangerousAddRef(ref mustRelease); } // If we still have more data in the buffers we've pre-fetched, then // we'll use it; we don't want to go to the server more than we absolutely // have to. if (buffer.MoveNext()) return true; // If we've read the last buffer, and we've exhausted it, then we're // really at the end of the data. if ( _isLastBuffer ) { _endOfData = true; return false; } // Reset the buffer back to the beginning. buffer.MoveFirst(); // For LONG and LOB data, we have to do work to prepare for each row (that's // why we don't prefetch rows that have these data types) if (1 == _rowsToPrefetch) { for (i = 0; i < columnCount; ++i) _columnInfo[i].Rebind(_connection, ref mustReleaseBindHandle[i], ref bindHandle[i]); } // Now fetch the rows required. Debug.Assert(0 < _rowsToPrefetch, "fetching 0 rows will cancel the cursor"); rc = TracedNativeMethods.OCIStmtFetch( _statementHandle, // stmtp ErrorHandle, // errhp _rowsToPrefetch, // crows OCI.FETCH.OCI_FETCH_NEXT, // orientation OCI.MODE.OCI_DEFAULT // mode ); // Keep track of how many rows we actually fetched so far. int previousRowsTotal = _rowsTotal; _statementHandle.GetAttribute(OCI.ATTR.OCI_ATTR_ROW_COUNT, out _rowsTotal, ErrorHandle); if (0 == rc) return true; if ((int)OCI.RETURNCODE.OCI_SUCCESS_WITH_INFO == rc) { _connection.CheckError(ErrorHandle, rc); return true; } if ((int)OCI.RETURNCODE.OCI_NO_DATA == rc) { int rowsFetched = _rowsTotal - previousRowsTotal; if (0 == rowsFetched) { if (0 == _rowsTotal) _hasRows = x_hasRows_False; _endOfData = true; return false; } buffer.NumberOfRows = rowsFetched; _isLastBuffer = true; return true; } _endOfData = true; _connection.CheckError(ErrorHandle, rc); return false; } finally { if (1 == _rowsToPrefetch) { for (i = 0; i < columnCount; ++i) { if (mustReleaseBindHandle[i]) { bindHandle[i].DangerousRelease(); } } } if (mustRelease) { buffer.DangerousRelease(); } } } } } // 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
- DataGridViewCheckBoxCell.cs
- UntrustedRecipientException.cs
- MenuCommandService.cs
- PrintDialog.cs
- BindingManagerDataErrorEventArgs.cs
- ContainerControlDesigner.cs
- ToolStripItemImageRenderEventArgs.cs
- CodeTypeReferenceCollection.cs
- basecomparevalidator.cs
- WrappedReader.cs
- DataGridViewCellStateChangedEventArgs.cs
- MethodCallTranslator.cs
- PathGradientBrush.cs
- Clause.cs
- TdsParserSafeHandles.cs
- ForceCopyBuildProvider.cs
- ChangePassword.cs
- XPathBuilder.cs
- XamlSerializer.cs
- PatternMatcher.cs
- SqlProviderServices.cs
- CrossAppDomainChannel.cs
- DispatcherProcessingDisabled.cs
- SoapWriter.cs
- Schema.cs
- Vector3DValueSerializer.cs
- ConfigurationSection.cs
- TableLayoutColumnStyleCollection.cs
- RoutedEvent.cs
- ObjectStateEntryBaseUpdatableDataRecord.cs
- PrintPageEvent.cs
- ScaleTransform3D.cs
- LocatorGroup.cs
- ImageCollectionCodeDomSerializer.cs
- SourceExpressionException.cs
- DataControlButton.cs
- WCFModelStrings.Designer.cs
- DateTimeValueSerializerContext.cs
- DbMetaDataCollectionNames.cs
- IntellisenseTextBox.cs
- PropertyConverter.cs
- PLINQETWProvider.cs
- XamlPointCollectionSerializer.cs
- CustomCredentialPolicy.cs
- HttpListenerRequest.cs
- _ConnectionGroup.cs
- StringResourceManager.cs
- BooleanFacetDescriptionElement.cs
- X509CertificateRecipientClientCredential.cs
- PropertyChangeTracker.cs
- HMACSHA512.cs
- TraceUtils.cs
- MobileControlsSectionHandler.cs
- WorkflowMarkupSerializationException.cs
- TraceContext.cs
- RowParagraph.cs
- SafeLocalMemHandle.cs
- AesCryptoServiceProvider.cs
- HotSpotCollectionEditor.cs
- OrderedDictionaryStateHelper.cs
- SubclassTypeValidator.cs
- HttpWebRequest.cs
- Stack.cs
- ModuleConfigurationInfo.cs
- MemberCollection.cs
- ISCIIEncoding.cs
- EventTrigger.cs
- DataProviderNameConverter.cs
- PageVisual.cs
- UdpTransportSettingsElement.cs
- SolidColorBrush.cs
- TextTreeInsertUndoUnit.cs
- Helpers.cs
- ArrangedElement.cs
- DiscriminatorMap.cs
- LinkArea.cs
- RegisteredHiddenField.cs
- ContainerParagraph.cs
- Domain.cs
- UnauthorizedWebPart.cs
- DeferredTextReference.cs
- HttpCapabilitiesEvaluator.cs
- DBConnection.cs
- SerialErrors.cs
- IIS7ConfigurationLoader.cs
- QuinticEase.cs
- CodeGeneratorOptions.cs
- FilteredXmlReader.cs
- JsonCollectionDataContract.cs
- WebPartAddingEventArgs.cs
- StringAnimationUsingKeyFrames.cs
- DiscardableAttribute.cs
- PointLight.cs
- Stroke2.cs
- HtmlControl.cs
- Error.cs
- XmlStreamNodeWriter.cs
- ParameterToken.cs
- Grid.cs
- Quaternion.cs