Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Query / ResultAssembly / BridgeDataRecord.cs / 1305376 / BridgeDataRecord.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- namespace System.Data.Query.ResultAssembly { using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.Common; using System.Data.Common.CommandTrees; using System.Data.Common.Internal.Materialization; using System.Data.Metadata.Edm; using System.Data.Query.PlanCompiler; using System.Diagnostics; using System.Text; using System.Threading; ////// DbDataRecord functionality for the bridge. /// sealed internal class BridgeDataRecord : DbDataRecord, IExtendedDataRecord { #region state ////// How deep down the hierarchy are we? /// internal readonly int Depth; ////// Where the data comes from /// private readonly ShaperShaper; /// /// The current record that we're responsible for; this will change from row to row /// on the source data reader. Will be set to null when parent the enumerator has /// returned false. /// private RecordState _source; ////// Current state of the record; /// private Status _status; private enum Status { Open = 0, ClosedImplicitly = 1, ClosedExplicitly = 2, }; ////// the column ordinal of the last column read, used to enforce sequential access /// private int _lastColumnRead; ////// the last data offset of a chunking read returned, used to enforce sequential access /// private long _lastDataOffsetRead; ////// the last ordinal that IsDBNull was called for; used to avoid re-reading the value; /// private int _lastOrdinalCheckedForNull; ////// value, of the last column that IsDBNull was called for; used to avoid re-reading the value; /// private object _lastValueCheckedForNull; ////// Set to the current data record when we hand them out. (For data reader columns, /// we use it's attached data record) The Close, GetValue and Read methods ensures /// that this is implicitly closed when we move past it. /// private BridgeDataReader _currentNestedReader; private BridgeDataRecord _currentNestedRecord; #endregion #region constructors internal BridgeDataRecord(Shapershaper, int depth) : base() { Debug.Assert(null != shaper, "null shaper?"); Shaper = shaper; Depth = depth; // Rest of state is set through the SetRecordSource method. } #endregion #region state management /// /// Called by our owning datareader when it is explicitly closed; will /// not be called for nested structures, they go through the ClosedImplicitly. /// path instead. /// internal void CloseExplicitly() { _status = Status.ClosedExplicitly; _source = null; // can't have data any longer once we're closed. CloseNestedObjectImplicitly(); } ////// Called by our parent object to ensure that we're marked as implicitly /// closed; will not be called for root level data readers. /// internal void CloseImplicitly() { _status = Status.ClosedImplicitly; _source = null; // can't have data any longer once we're closed. CloseNestedObjectImplicitly(); } ////// Ensure that whatever column we're currently processing is implicitly closed; /// private void CloseNestedObjectImplicitly() { // it would be nice to use Interlocked.Exchange to avoid multi-thread `race condition risk // when the the bridge is being misused by the user accessing it with multiple threads. // but this is called frequently enough to have a performance impact BridgeDataRecord currentNestedRecord = _currentNestedRecord; if (null != currentNestedRecord) { _currentNestedRecord = null; currentNestedRecord.CloseImplicitly(); } BridgeDataReader currentNestedReader = _currentNestedReader; if (null != currentNestedReader) { _currentNestedReader = null; currentNestedReader.CloseImplicitly(); } } ////// Should be called after each Read on the data reader. /// internal void SetRecordSource(RecordState newSource, bool hasData) { Debug.Assert(null == _currentNestedRecord, "didn't close the nested record?"); Debug.Assert(null == _currentNestedReader, "didn't close the nested reader?"); // A peculiar behavior of IEnumerator is that when MoveNext() returns // false, the Current still points to the last value, which is not // what we really want to reflect here. if (hasData) { Debug.Assert(null != newSource, "hasData but null newSource?"); // this shouldn't happen... _source = newSource; } else { _source = null; } _status = Status.Open; _lastColumnRead = -1; _lastDataOffsetRead = -1; _lastOrdinalCheckedForNull = -1; _lastValueCheckedForNull = null; } #endregion #region assertion helpers ////// Ensures that the reader is actually open, and throws an exception if not /// private void AssertReaderIsOpen() { if (IsExplicitlyClosed) { throw EntityUtil.ClosedDataReaderError(); } if (IsImplicitlyClosed) { throw EntityUtil.ImplicitlyClosedDataReaderError(); } } ////// Helper method. /// private void AssertReaderIsOpenWithData() { AssertReaderIsOpen(); if (!HasData) { throw EntityUtil.NoData(); } } ////// Ensures that sequential access rules are being obeyed for non-chunking /// getter methods, throws the appropriate exception if not. Also ensures /// that the last column/chunk is set appropriately. /// /// private void AssertSequentialAccess(int ordinal) { Debug.Assert(null != _source, "null _source?"); // we should have already called AssertReaderIsOpen. if (ordinal < 0 || ordinal >= _source.ColumnCount) { throw EntityUtil.ArgumentOutOfRange("ordinal"); } if (_lastColumnRead >= ordinal) { throw EntityUtil.NonSequentialColumnAccess(ordinal, _lastColumnRead + 1); } _lastColumnRead = ordinal; // SQLBUDT #442001 -- we need to mark things that are not using GetBytes/GetChars // in a way that prevents them from being read a second time // using those methods. Pointing past any potential data is // how we do that. _lastDataOffsetRead = long.MaxValue; } ////// Ensures that sequential access rules are being obeyed for chunking /// getter methods, throws the appropriate exception if not. Also ensures /// that the last column/chunk is set appropriately. /// /// /// /// private void AssertSequentialAccess(int ordinal, long dataOffset, string methodName) { Debug.Assert(null != _source, "null _source?"); // we should have already called AssertReaderIsOpen. if (ordinal < 0 || ordinal >= _source.ColumnCount) { throw EntityUtil.ArgumentOutOfRange("ordinal"); } if (_lastColumnRead > ordinal || (_lastColumnRead == ordinal && _lastDataOffsetRead == long.MaxValue)) { throw EntityUtil.NonSequentialColumnAccess(ordinal, _lastColumnRead + 1); } if (_lastColumnRead == ordinal) { if (_lastDataOffsetRead >= dataOffset) { throw EntityUtil.NonSequentialChunkAccess(dataOffset, _lastDataOffsetRead + 1, methodName); } // _lastDataOffsetRead will be set by GetBytes/GetChars, since we need to set it // to the last offset that was actually read, which isn't necessarily what was // requested. } else { // Doin' a new thang... _lastColumnRead = ordinal; _lastDataOffsetRead = -1; } } ////// True when the record has data (SetRecordSource was called with true) /// internal bool HasData { get { bool result = (_source != null); return result; } } ////// True so long as we haven't been closed either implicity or explictly /// internal bool IsClosed { get { return (_status != Status.Open); } } ////// Determine whether we have been explicitly closed by our owning /// data reader; only data records that are responsible for processing /// data reader requests can be explicitly closed; /// internal bool IsExplicitlyClosed { get { return (_status == Status.ClosedExplicitly); } } ////// Determine whether the parent data reader or record moved on from /// where we can be considered open, (because the consumer of the /// parent data reader/record called either the GetValue() or Read() /// methods on the parent); /// internal bool IsImplicitlyClosed { get { return (_status == Status.ClosedImplicitly); } } #endregion #region metadata properties and methods ////// implementation of DbDataRecord.DataRecordInfo property /// public DataRecordInfo DataRecordInfo { get { AssertReaderIsOpen(); DataRecordInfo result = _source.DataRecordInfo; return result; } } ////// implementation of DbDataRecord.FieldCount property /// override public int FieldCount { get { AssertReaderIsOpen(); return _source.ColumnCount; } } ////// Helper method to get the edm TypeUsage for the specified column; /// /// If the column requested is a record, we'll pick up whatever the /// current record says it is, otherwise we'll take whatever was stored /// on our record state. /// /// ///private TypeUsage GetTypeUsage(int ordinal) { // Some folks are picky about the exception we throw if (ordinal < 0 || ordinal >= _source.ColumnCount) { throw EntityUtil.ArgumentOutOfRange("ordinal"); } TypeUsage result; // RecordState recordState = _source.CurrentColumnValues[ordinal] as RecordState; if (null != recordState) { result = recordState.DataRecordInfo.RecordType; } else { result = _source.GetTypeUsage(ordinal); } return result; } /// /// implementation of DbDataRecord.GetDataTypeName() method /// /// ///override public string GetDataTypeName(int ordinal) { AssertReaderIsOpenWithData(); return TypeHelpers.GetFullName(GetTypeUsage(ordinal)); } /// /// implementation of DbDataRecord.GetFieldType() method /// /// ///override public Type GetFieldType(int ordinal) { AssertReaderIsOpenWithData(); return BridgeDataReader.GetClrTypeFromTypeMetadata(GetTypeUsage(ordinal)); } /// /// implementation of DbDataRecord.GetName() method /// /// ///override public string GetName(int ordinal) { AssertReaderIsOpen(); return _source.GetName(ordinal); } /// /// implementation of DbDataRecord.GetOrdinal() method /// /// ///override public int GetOrdinal(string name) { AssertReaderIsOpen(); return _source.GetOrdinal(name); } #endregion #region general getter methods and indexer properties /// /// implementation for DbDataRecord[ordinal] indexer property /// /// ///override public object this[int ordinal] { get { return GetValue(ordinal); } } /// /// implementation for DbDataRecord[name] indexer property /// /// ///override public object this[string name] { get { return GetValue(GetOrdinal(name)); } } /// /// implementation for DbDataRecord.GetValue() method /// /// This method is used by most of the column getters on this /// class to retrieve the value from the source reader. Therefore, /// it asserts all the good things, like that the reader is open, /// and that it has data, and that you're not trying to circumvent /// sequential access requirements. /// /// ///override public Object GetValue(int ordinal) { AssertReaderIsOpenWithData(); AssertSequentialAccess(ordinal); object result = null; if (ordinal == _lastOrdinalCheckedForNull) { result = _lastValueCheckedForNull; } else { _lastOrdinalCheckedForNull = -1; _lastValueCheckedForNull = null; CloseNestedObjectImplicitly(); result = _source.CurrentColumnValues[ordinal]; // If we've got something that's nested, then make sure we // update the current nested record with it so we can be certain // to close it implicitly when we move past it. if (_source.IsNestedObject(ordinal)) { result = GetNestedObjectValue(result); } } return result; } /// /// For nested objects (records/readers) we have a bit more work to do; this /// method extracts it all out from the main GetValue method so it doesn't /// have to be so big. /// /// ///private object GetNestedObjectValue(object result) { if (result != DBNull.Value) { RecordState recordState = result as RecordState; if (null != recordState) { if (recordState.IsNull) { result = DBNull.Value; } else { BridgeDataRecord nestedRecord = new BridgeDataRecord(Shaper, Depth + 1); nestedRecord.SetRecordSource(recordState, true); result = nestedRecord; _currentNestedRecord = nestedRecord; _currentNestedReader = null; } } else { Coordinator coordinator = result as Coordinator ; if (null != coordinator) { BridgeDataReader nestedReader = new BridgeDataReader(Shaper, coordinator.TypedCoordinatorFactory, Depth + 1); result = nestedReader; _currentNestedRecord = null; _currentNestedReader = nestedReader; } else { Debug.Fail("unexpected type of nested object result: " + result.GetType().ToString()); } } } return result; } /// /// implementation for DbDataRecord.GetValues() method /// /// ///override public int GetValues(object[] values) { EntityUtil.CheckArgumentNull(values, "values"); int copy = Math.Min(values.Length, FieldCount); for (int i = 0; i < copy; ++i) { values[i] = GetValue(i); } return copy; } #endregion #region simple scalar value getter methods /// /// implementation of DbDataRecord.GetBoolean() method /// /// ///override public bool GetBoolean(int ordinal) { return (bool)GetValue(ordinal); } /// /// implementation of DbDataRecord.GetByte() method /// /// ///override public byte GetByte(int ordinal) { return (byte)GetValue(ordinal); } /// /// implementation of DbDataRecord.GetChar() method /// /// ///override public char GetChar(int ordinal) { return (char)GetValue(ordinal); } /// /// implementation of DbDataRecord.GetDateTime() method /// /// ///override public DateTime GetDateTime(int ordinal) { return (DateTime)GetValue(ordinal); } /// /// implementation of DbDataRecord.GetDecimal() method /// /// ///override public Decimal GetDecimal(int ordinal) { return (Decimal)GetValue(ordinal); } /// /// implementation of DbDataRecord.GetDouble() method /// /// ///override public double GetDouble(int ordinal) { return (double)GetValue(ordinal); } /// /// implementation of DbDataRecord.GetFloat() method /// /// ///override public float GetFloat(int ordinal) { return (float)GetValue(ordinal); } /// /// implementation of DbDataRecord.GetGuid() method /// /// ///override public Guid GetGuid(int ordinal) { return (Guid)GetValue(ordinal); } /// /// implementation of DbDataRecord.GetInt16() method /// /// ///override public Int16 GetInt16(int ordinal) { return (Int16)GetValue(ordinal); } /// /// implementation of DbDataRecord.GetInt32() method /// /// ///override public Int32 GetInt32(int ordinal) { return (Int32)GetValue(ordinal); } /// /// implementation of DbDataRecord.GetInt64() method /// /// ///override public Int64 GetInt64(int ordinal) { return (Int64)GetValue(ordinal); } /// /// implementation of DbDataRecord.GetString() method /// /// ///override public String GetString(int ordinal) { return (String)GetValue(ordinal); } /// /// implementation of DbDataRecord.IsDBNull() method /// /// ///override public bool IsDBNull(int ordinal) { // This seems like a hack, but the the problem is that I need // to make sure I don't monkey with caching things, and if I // call IsDBNull directly on the store reader, I'll potentially // lose data because I'm expecting SequentialAccess rules. object columnValue = GetValue(ordinal); // Need to backup one because we technically didn't read the // value yet but the GetValue method advanced our pointer to // what the value was. Another hack, but it's way less code // than trying to avoid advancing to begin with. _lastColumnRead--; _lastDataOffsetRead = -1; // So as to avoid reconstructing nested records, readers, and // rereading data from the iterator source cache, we just cache // the value we read and the ordinal it came from, so if someone // is doing the right thing(TM) and calling IsDBNull before calling // GetValue, we won't construct another one. _lastValueCheckedForNull = columnValue; _lastOrdinalCheckedForNull = ordinal; bool result = (DBNull.Value == columnValue); return result; } #endregion #region chunking scalar value getter methods /// /// implementation for DbDataRecord.GetBytes() method /// /// /// /// /// /// ///override public long GetBytes(int ordinal, long dataOffset, byte[] buffer, int bufferOffset, int length) { AssertReaderIsOpenWithData(); AssertSequentialAccess(ordinal, dataOffset, "GetBytes"); long result = _source.GetBytes(ordinal, dataOffset, buffer, bufferOffset, length); if (buffer != null) { _lastDataOffsetRead = dataOffset + result - 1; // just what was read, nothing more. } return result; } /// /// implementation for DbDataRecord.GetChars() method /// /// /// /// /// /// ///override public long GetChars(int ordinal, long dataOffset, char[] buffer, int bufferOffset, int length) { AssertReaderIsOpenWithData(); AssertSequentialAccess(ordinal, dataOffset, "GetChars"); long result = _source.GetChars(ordinal, dataOffset, buffer, bufferOffset, length); if (buffer != null) { _lastDataOffsetRead = dataOffset + result - 1; // just what was read, nothing more. } return result; } #endregion #region complex type getters /// /// implementation for DbDataRecord.GetData() method /// /// ///override protected DbDataReader GetDbDataReader(int ordinal) { return (DbDataReader)GetValue(ordinal); } /// /// implementation for DbDataRecord.GetDataRecord() method /// /// ///public DbDataRecord GetDataRecord(int ordinal) { return (DbDataRecord)GetValue(ordinal); } /// /// Used to return a nested result /// /// ///public DbDataReader GetDataReader(int ordinal) { return this.GetDbDataReader(ordinal); } #endregion } } // 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
- ListView.cs
- TypeForwardedFromAttribute.cs
- SqlProcedureAttribute.cs
- TypedTableBaseExtensions.cs
- TracingConnectionListener.cs
- Stack.cs
- CodePageEncoding.cs
- RemoteCryptoTokenProvider.cs
- unsafenativemethodsother.cs
- MessageQueueTransaction.cs
- WebServiceFault.cs
- SqlDataSourceWizardForm.cs
- SystemSounds.cs
- RuntimeEnvironment.cs
- Substitution.cs
- ComponentCache.cs
- PageCatalogPart.cs
- ArrayList.cs
- TraceListener.cs
- InputLangChangeRequestEvent.cs
- GradientSpreadMethodValidation.cs
- TypeHelpers.cs
- ExtendedPropertyCollection.cs
- Menu.cs
- ContentType.cs
- TimeZone.cs
- MouseGestureConverter.cs
- Int32Rect.cs
- RegisteredDisposeScript.cs
- ExtenderControl.cs
- LockRenewalTask.cs
- ImageEditor.cs
- EntityDataSourceView.cs
- NameTable.cs
- SQlBooleanStorage.cs
- SqlDataSourceQueryConverter.cs
- TraceContext.cs
- ConfigUtil.cs
- BitmapEffectGroup.cs
- CodeTypeReferenceCollection.cs
- ContextProperty.cs
- CodeDirectoryCompiler.cs
- HttpHandler.cs
- SoapConverter.cs
- DurableInstance.cs
- PrintPreviewDialog.cs
- TreeBuilderBamlTranslator.cs
- TypeAccessException.cs
- Publisher.cs
- ButtonBase.cs
- XmlWriter.cs
- IntellisenseTextBox.designer.cs
- MsmqHostedTransportManager.cs
- CatalogZoneBase.cs
- XXXInfos.cs
- UpnEndpointIdentity.cs
- Stopwatch.cs
- BuiltInExpr.cs
- DeadCharTextComposition.cs
- ListSortDescription.cs
- UInt32.cs
- HtmlSelectionListAdapter.cs
- EventData.cs
- SolidColorBrush.cs
- DbConnectionFactory.cs
- HtmlInputSubmit.cs
- CharAnimationUsingKeyFrames.cs
- DataMemberListEditor.cs
- EventHandlersStore.cs
- _CookieModule.cs
- ChangeToolStripParentVerb.cs
- InputProcessorProfiles.cs
- ContainerFilterService.cs
- Debug.cs
- TypeLoadException.cs
- QilIterator.cs
- LinkButton.cs
- PublishLicense.cs
- DesignerGenericWebPart.cs
- ModuleElement.cs
- Blend.cs
- EntityDataSourceContextCreatingEventArgs.cs
- SafeFileMapViewHandle.cs
- StylusDevice.cs
- SoundPlayer.cs
- QilFunction.cs
- ThicknessAnimation.cs
- ClientData.cs
- SByte.cs
- FrameworkReadOnlyPropertyMetadata.cs
- FixedSchema.cs
- Int32AnimationBase.cs
- DataSourceControlBuilder.cs
- ConstNode.cs
- Method.cs
- TimeSpanValidatorAttribute.cs
- SeekStoryboard.cs
- PersistenceTypeAttribute.cs
- TextParagraph.cs
- RecognitionResult.cs