//------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // // [....] // [....] //------------------------------------------------------------------------------ namespace System.Data.SqlClient { using System; using System.Data; using System.Data.Sql; using System.Data.SqlTypes; using System.IO; using System.Runtime.InteropServices; using System.Threading; using System.Diagnostics; // for Conditional compilation using System.Diagnostics.CodeAnalysis; using System.Xml; using Microsoft.SqlServer.Server; using System.Data.ProviderBase; using System.Data.Common; using System.Threading.Tasks; // SqlServer provider's implementation of ISqlReader. // Supports ISqlReader and ISqlResultSet objects. // // User should never be able to create one of these themselves, nor subclass. // This is accomplished by having no public override constructors. internal sealed class SqlDataReaderSmi : SqlDataReader { // // IDBRecord properties // public override int FieldCount { get { ThrowIfClosed( "FieldCount" ); return InternalFieldCount; } } public override int VisibleFieldCount { get { ThrowIfClosed("VisibleFieldCount"); if (FNotInResults()) { return 0; } return _visibleColumnCount; } } // // IDBRecord Metadata Methods // public override String GetName(int ordinal) { EnsureCanGetMetaData( "GetName" ); return _currentMetaData[ordinal].Name; } public override String GetDataTypeName(int ordinal) { EnsureCanGetMetaData( "GetDataTypeName" ); SmiExtendedMetaData md = _currentMetaData[ordinal]; if ( SqlDbType.Udt == md.SqlDbType ) { return md.TypeSpecificNamePart1 + "." + md.TypeSpecificNamePart2 + "." + md.TypeSpecificNamePart3; } else { return md.TypeName; } } public override Type GetFieldType(int ordinal) { EnsureCanGetMetaData( "GetFieldType" ); if (SqlDbType.Udt == _currentMetaData[ordinal].SqlDbType) { return _currentMetaData[ordinal].Type; } else { return MetaType.GetMetaTypeFromSqlDbType( _currentMetaData[ordinal].SqlDbType, _currentMetaData[ordinal].IsMultiValued).ClassType ; } } override public Type GetProviderSpecificFieldType(int ordinal) { EnsureCanGetMetaData( "GetProviderSpecificFieldType" ); if (SqlDbType.Udt == _currentMetaData[ordinal].SqlDbType) { return _currentMetaData[ordinal].Type; } else { return MetaType.GetMetaTypeFromSqlDbType( _currentMetaData[ordinal].SqlDbType, _currentMetaData[ordinal].IsMultiValued).SqlType ; } } public override int Depth { get{ ThrowIfClosed( "Depth" ); return 0; } } // public override Object GetValue(int ordinal) { EnsureCanGetCol( "GetValue", ordinal); SmiQueryMetaData metaData = _currentMetaData[ordinal]; if (_currentConnection.IsKatmaiOrNewer) { return ValueUtilsSmi.GetValue200(_readerEventSink, (SmiTypedGetterSetter)_currentColumnValuesV3, ordinal, metaData, _currentConnection.InternalContext); } else { return ValueUtilsSmi.GetValue(_readerEventSink, _currentColumnValuesV3, ordinal, metaData, _currentConnection.InternalContext); } } public override T GetFieldValue(int ordinal) { EnsureCanGetCol( "GetFieldValue", ordinal); SmiQueryMetaData metaData = _currentMetaData[ordinal]; if (_typeofINullable.IsAssignableFrom(typeof(T))) { // If its a SQL Type or Nullable UDT if (_currentConnection.IsKatmaiOrNewer) { return (T)ValueUtilsSmi.GetSqlValue200(_readerEventSink, (SmiTypedGetterSetter)_currentColumnValuesV3, ordinal, metaData, _currentConnection.InternalContext); } else { return (T)ValueUtilsSmi.GetSqlValue(_readerEventSink, _currentColumnValuesV3, ordinal, metaData, _currentConnection.InternalContext); } } else { // Otherwise Its a CLR or non-Nullable UDT if (_currentConnection.IsKatmaiOrNewer) { return (T)ValueUtilsSmi.GetValue200(_readerEventSink, (SmiTypedGetterSetter)_currentColumnValuesV3, ordinal, metaData, _currentConnection.InternalContext); } else { return (T)ValueUtilsSmi.GetValue(_readerEventSink, _currentColumnValuesV3, ordinal, metaData, _currentConnection.InternalContext); } } } public override Task GetFieldValueAsync(int ordinal, CancellationToken cancellationToken) { // As per Async spec, Context Connections do not support async return ADP.CreatedTaskWithException(ADP.ExceptionWithStackTrace(SQL.NotAvailableOnContextConnection())); } override internal SqlBuffer.StorageType GetVariantInternalStorageType(int ordinal) { Debug.Assert(null != _currentColumnValuesV3, "Attempting to get variant internal storage type without calling GetValue first"); if (IsDBNull(ordinal)) return SqlBuffer.StorageType.Empty; SmiMetaData valueMetaData = _currentColumnValuesV3.GetVariantType(_readerEventSink, ordinal); if (valueMetaData == null) return SqlBuffer.StorageType.Empty; else return ValueUtilsSmi.SqlDbTypeToStorageType(valueMetaData.SqlDbType); } public override int GetValues(object[] values) { EnsureCanGetCol( "GetValues", 0); if (null == values) { throw ADP.ArgumentNull("values"); } int copyLength = (values.Length < _visibleColumnCount) ? values.Length : _visibleColumnCount; for(int i=0; i IsDBNullAsync(int ordinal, CancellationToken cancellationToken) { // As per Async spec, Context Connections do not support async return ADP.CreatedTaskWithException(ADP.ExceptionWithStackTrace(SQL.NotAvailableOnContextConnection())); } public override bool GetBoolean(int ordinal) { EnsureCanGetCol( "GetBoolean", ordinal); return ValueUtilsSmi.GetBoolean(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override byte GetByte(int ordinal) { EnsureCanGetCol( "GetByte", ordinal); return ValueUtilsSmi.GetByte(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override long GetBytes(int ordinal, long fieldOffset, byte[] buffer, int bufferOffset, int length) { EnsureCanGetCol( "GetBytes", ordinal); return ValueUtilsSmi.GetBytes(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal], fieldOffset, buffer, bufferOffset, length, true); } // XmlReader support code calls this method. internal override long GetBytesInternal(int ordinal, long fieldOffset, byte[] buffer, int bufferOffset, int length) { EnsureCanGetCol( "GetBytes", ordinal); return ValueUtilsSmi.GetBytesInternal(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal], fieldOffset, buffer, bufferOffset, length, false); } public override char GetChar(int ordinal) { throw ADP.NotSupported(); } public override long GetChars(int ordinal, long fieldOffset, char[] buffer, int bufferOffset, int length) { EnsureCanGetCol( "GetChars", ordinal); SmiExtendedMetaData metaData = _currentMetaData[ordinal]; if (IsCommandBehavior(CommandBehavior.SequentialAccess)) { if (metaData.SqlDbType == SqlDbType.Xml) { return GetStreamingXmlChars(ordinal, fieldOffset, buffer, bufferOffset, length); } } return ValueUtilsSmi.GetChars(_readerEventSink, _currentColumnValuesV3, ordinal, metaData, fieldOffset, buffer, bufferOffset, length); } public override Guid GetGuid(int ordinal) { EnsureCanGetCol( "GetGuid", ordinal); return ValueUtilsSmi.GetGuid(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override Int16 GetInt16(int ordinal) { EnsureCanGetCol( "GetInt16", ordinal); return ValueUtilsSmi.GetInt16(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override Int32 GetInt32(int ordinal) { EnsureCanGetCol( "GetInt32", ordinal); return ValueUtilsSmi.GetInt32(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override Int64 GetInt64(int ordinal) { EnsureCanGetCol( "GetInt64", ordinal); return ValueUtilsSmi.GetInt64(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override Single GetFloat(int ordinal) { EnsureCanGetCol( "GetFloat", ordinal); return ValueUtilsSmi.GetSingle(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override Double GetDouble(int ordinal) { EnsureCanGetCol( "GetDouble", ordinal); return ValueUtilsSmi.GetDouble(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override String GetString(int ordinal) { EnsureCanGetCol( "GetString", ordinal); return ValueUtilsSmi.GetString(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override Decimal GetDecimal(int ordinal) { EnsureCanGetCol( "GetDecimal", ordinal); return ValueUtilsSmi.GetDecimal(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override DateTime GetDateTime(int ordinal) { EnsureCanGetCol( "GetDateTime", ordinal); return ValueUtilsSmi.GetDateTime(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } // // IDataReader properties // // Logically closed test. I.e. is this object closed as far as external access is concerned? public override bool IsClosed { get { return IsReallyClosed(); } } public override int RecordsAffected { get { return base.Command.InternalRecordsAffected; } } // // IDataReader methods // internal override void CloseReaderFromConnection() { // Context Connections do not support async - so there is no threading issues with closing from the connection CloseInternal(closeConnection: false); } public override void Close() { // Connection should be open at this point, so we can do multiple checks of HasEvents, and we may need to close the connection afterwards CloseInternal(closeConnection: IsCommandBehavior(CommandBehavior.CloseConnection)); } private void CloseInternal(bool closeConnection) { IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#", ObjectID); bool processFinallyBlock = true; try { if(!IsClosed) { _hasRows = false; // Process the remaining events. This makes sure that environment changes are applied and any errors are picked up. while(_eventStream.HasEvents) { _eventStream.ProcessEvent( _readerEventSink ); _readerEventSink.ProcessMessagesAndThrow(true); } // Close the request executor _requestExecutor.Close(_readerEventSink); _readerEventSink.ProcessMessagesAndThrow(true); } } catch (Exception e) { processFinallyBlock = ADP.IsCatchableExceptionType(e); throw; } finally { if (processFinallyBlock) { _isOpen = false; if ((closeConnection) && (Connection != null)) { Connection.Close(); } Bid.ScopeLeave(ref hscp); } } } // Move to the next resultset public override unsafe bool NextResult() { ThrowIfClosed( "NextResult" ); bool hasAnotherResult = InternalNextResult(false); return hasAnotherResult; } public override Task NextResultAsync(CancellationToken cancellationToken) { // Async not supported on Context Connections return ADP.CreatedTaskWithException(ADP.ExceptionWithStackTrace(SQL.NotAvailableOnContextConnection())); } internal unsafe bool InternalNextResult(bool ignoreNonFatalMessages) { IntPtr hscp = IntPtr.Zero; if (Bid.AdvancedOn) { Bid.ScopeEnter(out hscp, " %d#", ObjectID); } try { _hasRows = false; if( PositionState.AfterResults != _currentPosition ) { // Consume any remaning rows in the current result. while( InternalRead(ignoreNonFatalMessages) ) { // This space intentionally left blank } // reset resultset metadata - it will be created again if there is a pending resultset ResetResultSet(); // Process the events until metadata is found or all of the // available events have been consumed. If there is another // result, the metadata for it will be available after the last // read on the prior result. while(null == _currentMetaData && _eventStream.HasEvents) { _eventStream.ProcessEvent( _readerEventSink ); _readerEventSink.ProcessMessagesAndThrow(ignoreNonFatalMessages); } } return PositionState.AfterResults != _currentPosition; } finally { if (Bid.AdvancedOn) { Bid.ScopeLeave(ref hscp); } } } public override bool Read() { ThrowIfClosed( "Read" ); bool hasAnotherRow = InternalRead(false); return hasAnotherRow; } public override Task ReadAsync(CancellationToken cancellationToken) { // Async not supported on Context Connections return ADP.CreatedTaskWithException(ADP.ExceptionWithStackTrace(SQL.NotAvailableOnContextConnection())); } internal unsafe bool InternalRead(bool ignoreNonFatalErrors) { IntPtr hscp = IntPtr.Zero; if (Bid.AdvancedOn) { Bid.ScopeEnter(out hscp, " %d#", ObjectID); } try { // Don't move unless currently in results. if( FInResults() ) { // Set current row to null so we can see if we get a new one _currentColumnValues = null; _currentColumnValuesV3 = null; // Reset blobs if (_currentStream != null) { _currentStream.SetClosed(); _currentStream = null; } if (_currentTextReader != null) { _currentTextReader.SetClosed(); _currentTextReader = null; } // NOTE: SQLBUDT #386118 -- may indicate that we want to break this loop when we get a MessagePosted callback, but we can't prove that. while( null == _currentColumnValues && // Did we find a row? null == _currentColumnValuesV3 && // Did we find a V3 row? FInResults() && // Was the batch terminated due to a serious error? PositionState.AfterRows != _currentPosition && // Have we seen a statement completed event? _eventStream.HasEvents ) { // Have we processed all events? _eventStream.ProcessEvent( _readerEventSink ); _readerEventSink.ProcessMessagesAndThrow(ignoreNonFatalErrors); } } return PositionState.OnRow == _currentPosition; } finally { if (Bid.AdvancedOn) { Bid.ScopeLeave(ref hscp); } } } public override DataTable GetSchemaTable() { ThrowIfClosed( "GetSchemaTable" ); if ( null == _schemaTable && FInResults() ) { DataTable schemaTable = new DataTable( "SchemaTable" ); schemaTable.Locale = System.Globalization.CultureInfo.InvariantCulture; schemaTable.MinimumCapacity = InternalFieldCount; DataColumn ColumnName = 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 ProviderSpecificDataType = new DataColumn(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(System.Type)); DataColumn ProviderType = new DataColumn(SchemaTableColumn.ProviderType, typeof(System.Int32)); DataColumn NonVersionedProviderType = new DataColumn(SchemaTableColumn.NonVersionedProviderType, typeof(System.Int32)); DataColumn IsLong = new DataColumn(SchemaTableColumn.IsLong, typeof(System.Boolean)); DataColumn AllowDBNull = new DataColumn(SchemaTableColumn.AllowDBNull, typeof(System.Boolean)); DataColumn IsReadOnly = new DataColumn(SchemaTableOptionalColumn.IsReadOnly, typeof(System.Boolean)); DataColumn IsRowVersion = new DataColumn(SchemaTableOptionalColumn.IsRowVersion, typeof(System.Boolean)); DataColumn IsUnique = new DataColumn(SchemaTableColumn.IsUnique, typeof(System.Boolean)); DataColumn IsKey = new DataColumn(SchemaTableColumn.IsKey, typeof(System.Boolean)); DataColumn IsAutoIncrement = new DataColumn(SchemaTableOptionalColumn.IsAutoIncrement, typeof(System.Boolean)); DataColumn IsHidden = new DataColumn(SchemaTableOptionalColumn.IsHidden, typeof(System.Boolean)); DataColumn BaseCatalogName = new DataColumn(SchemaTableOptionalColumn.BaseCatalogName, typeof(System.String)); 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)); // unique to SqlClient DataColumn BaseServerName = new DataColumn(SchemaTableOptionalColumn.BaseServerName, typeof(System.String)); DataColumn IsAliased = new DataColumn(SchemaTableColumn.IsAliased, typeof(System.Boolean)); DataColumn IsExpression = new DataColumn(SchemaTableColumn.IsExpression, typeof(System.Boolean)); DataColumn IsIdentity = new DataColumn("IsIdentity", typeof(System.Boolean)); // UDT specific. Holds UDT typename ONLY if the type of the column is UDT, otherwise the data type DataColumn DataTypeName = new DataColumn("DataTypeName", typeof(System.String)); DataColumn UdtAssemblyQualifiedName = new DataColumn("UdtAssemblyQualifiedName", typeof(System.String)); // Xml metadata specific DataColumn XmlSchemaCollectionDatabase = new DataColumn("XmlSchemaCollectionDatabase", typeof(System.String)); DataColumn XmlSchemaCollectionOwningSchema = new DataColumn("XmlSchemaCollectionOwningSchema", typeof(System.String)); DataColumn XmlSchemaCollectionName = new DataColumn("XmlSchemaCollectionName", typeof(System.String)); // SparseColumnSet DataColumn IsColumnSet = new DataColumn("IsColumnSet", typeof(System.Boolean)); Ordinal.DefaultValue = 0; IsLong.DefaultValue = false; DataColumnCollection columns = schemaTable.Columns; // must maintain order for backward compatibility columns.Add(ColumnName); columns.Add(Ordinal); columns.Add(Size); columns.Add(Precision); columns.Add(Scale); columns.Add(IsUnique); columns.Add(IsKey); columns.Add(BaseServerName); columns.Add(BaseCatalogName); columns.Add(BaseColumnName); columns.Add(BaseSchemaName); columns.Add(BaseTableName); columns.Add(DataType); columns.Add(AllowDBNull); columns.Add(ProviderType); columns.Add(IsAliased); columns.Add(IsExpression); columns.Add(IsIdentity); columns.Add(IsAutoIncrement); columns.Add(IsRowVersion); columns.Add(IsHidden); columns.Add(IsLong); columns.Add(IsReadOnly); columns.Add(ProviderSpecificDataType); columns.Add(DataTypeName); columns.Add(XmlSchemaCollectionDatabase); columns.Add(XmlSchemaCollectionOwningSchema); columns.Add(XmlSchemaCollectionName); columns.Add(UdtAssemblyQualifiedName); columns.Add(NonVersionedProviderType); columns.Add(IsColumnSet); for (int i = 0; i < InternalFieldCount; i++) { SmiQueryMetaData colMetaData = _currentMetaData[i]; long maxLength = colMetaData.MaxLength; MetaType metaType = MetaType.GetMetaTypeFromSqlDbType(colMetaData.SqlDbType, colMetaData.IsMultiValued); if ( SmiMetaData.UnlimitedMaxLengthIndicator == maxLength ) { metaType = MetaType.GetMaxMetaTypeFromMetaType( metaType ); maxLength = (metaType.IsSizeInCharacters && !metaType.IsPlp) ? (0x7fffffff / 2) : 0x7fffffff; } DataRow schemaRow = schemaTable.NewRow(); // NOTE: there is an impedence mismatch here - the server always // treats numeric data as variable length and sends a maxLength // based upon the precision, whereas TDS always sends 17 for // the max length; rather than push this logic into the server, // I've elected to make a fixup here instead. if (SqlDbType.Decimal == colMetaData.SqlDbType) { // maxLength = TdsEnums.MAX_NUMERIC_LEN; // SQLBUDT 339686 } else if (SqlDbType.Variant == colMetaData.SqlDbType) { // maxLength = 8009; // SQLBUDT 340726 } schemaRow[ColumnName] = colMetaData.Name; schemaRow[Ordinal] = i; schemaRow[Size] = maxLength; schemaRow[ProviderType] = (int) colMetaData.SqlDbType; // SqlDbType schemaRow[NonVersionedProviderType] = (int) colMetaData.SqlDbType; // SqlDbType if (colMetaData.SqlDbType != SqlDbType.Udt) { schemaRow[DataType] = metaType.ClassType; // com+ type schemaRow[ProviderSpecificDataType] = metaType.SqlType; } else { schemaRow[UdtAssemblyQualifiedName] = colMetaData.Type.AssemblyQualifiedName; schemaRow[DataType] = colMetaData.Type; schemaRow[ProviderSpecificDataType] = colMetaData.Type; } // NOTE: there is also an impedence mismatch here - the server // has different ideas about what the precision value should be // than does the client bits. I tried fixing up the default // meta data values in SmiMetaData, however, it caused the // server suites to fall over dead. Rather than attempt to // bake it into the server, I'm fixing it up in the client. byte precision = 0xff; // default for everything, except certain numeric types. // switch (colMetaData.SqlDbType) { case SqlDbType.BigInt: case SqlDbType.DateTime: case SqlDbType.Decimal: case SqlDbType.Int: case SqlDbType.Money: case SqlDbType.SmallDateTime: case SqlDbType.SmallInt: case SqlDbType.SmallMoney: case SqlDbType.TinyInt: precision = colMetaData.Precision; break; case SqlDbType.Float: precision = 15; break; case SqlDbType.Real: precision = 7; break; default: precision = 0xff; // everything else is unknown; break; } schemaRow[Precision] = precision; // if ( SqlDbType.Decimal == colMetaData.SqlDbType || SqlDbType.Time == colMetaData.SqlDbType || SqlDbType.DateTime2 == colMetaData.SqlDbType || SqlDbType.DateTimeOffset == colMetaData.SqlDbType) { schemaRow[Scale] = colMetaData.Scale; } else { schemaRow[Scale] = MetaType.GetMetaTypeFromSqlDbType( colMetaData.SqlDbType, colMetaData.IsMultiValued).Scale; } schemaRow[AllowDBNull] = colMetaData.AllowsDBNull; if ( !( colMetaData.IsAliased.IsNull ) ) { schemaRow[IsAliased] = colMetaData.IsAliased.Value; } if ( !( colMetaData.IsKey.IsNull ) ) { schemaRow[IsKey] = colMetaData.IsKey.Value; } if ( !( colMetaData.IsHidden.IsNull ) ) { schemaRow[IsHidden] = colMetaData.IsHidden.Value; } if ( !( colMetaData.IsExpression.IsNull ) ) { schemaRow[IsExpression] = colMetaData.IsExpression.Value; } schemaRow[IsReadOnly] = colMetaData.IsReadOnly; schemaRow[IsIdentity] = colMetaData.IsIdentity; schemaRow[IsColumnSet] = colMetaData.IsColumnSet; schemaRow[IsAutoIncrement] = colMetaData.IsIdentity; schemaRow[IsLong] = metaType.IsLong; // mark unique for timestamp columns if ( SqlDbType.Timestamp == colMetaData.SqlDbType ) { schemaRow[IsUnique] = true; schemaRow[IsRowVersion] = true; } else { schemaRow[IsUnique] = false; schemaRow[IsRowVersion] = false; } if ( !ADP.IsEmpty( colMetaData.ColumnName ) ) { schemaRow[BaseColumnName] = colMetaData.ColumnName; } else if (!ADP.IsEmpty( colMetaData.Name)) { // Use projection name if base column name is not present schemaRow[BaseColumnName] = colMetaData.Name; } if ( !ADP.IsEmpty(colMetaData.TableName ) ) { schemaRow[BaseTableName] = colMetaData.TableName; } if (!ADP.IsEmpty(colMetaData.SchemaName)) { schemaRow[BaseSchemaName] = colMetaData.SchemaName; } if (!ADP.IsEmpty(colMetaData.CatalogName)) { schemaRow[BaseCatalogName] = colMetaData.CatalogName; } if (!ADP.IsEmpty(colMetaData.ServerName)) { schemaRow[BaseServerName] = colMetaData.ServerName; } if ( SqlDbType.Udt == colMetaData.SqlDbType ) { schemaRow[DataTypeName] = colMetaData.TypeSpecificNamePart1 + "." + colMetaData.TypeSpecificNamePart2 + "." + colMetaData.TypeSpecificNamePart3; } else { schemaRow[DataTypeName] = metaType.TypeName; } // Add Xml metadata if ( SqlDbType.Xml == colMetaData.SqlDbType ) { schemaRow[XmlSchemaCollectionDatabase] = colMetaData.TypeSpecificNamePart1; schemaRow[XmlSchemaCollectionOwningSchema] = colMetaData.TypeSpecificNamePart2; schemaRow[XmlSchemaCollectionName] = colMetaData.TypeSpecificNamePart3; } schemaTable.Rows.Add(schemaRow); schemaRow.AcceptChanges(); } // mark all columns as readonly foreach(DataColumn column in columns) { column.ReadOnly = true; // MDAC 70943 } _schemaTable = schemaTable; } return _schemaTable; } // // ISqlRecord methods // public override SqlBinary GetSqlBinary(int ordinal) { EnsureCanGetCol( "GetSqlBinary", ordinal); return ValueUtilsSmi.GetSqlBinary(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override SqlBoolean GetSqlBoolean(int ordinal) { EnsureCanGetCol( "GetSqlBoolean", ordinal); return ValueUtilsSmi.GetSqlBoolean(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override SqlByte GetSqlByte(int ordinal) { EnsureCanGetCol( "GetSqlByte", ordinal); return ValueUtilsSmi.GetSqlByte(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override SqlInt16 GetSqlInt16(int ordinal) { EnsureCanGetCol( "GetSqlInt16", ordinal); return ValueUtilsSmi.GetSqlInt16(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override SqlInt32 GetSqlInt32(int ordinal) { EnsureCanGetCol( "GetSqlInt32", ordinal); return ValueUtilsSmi.GetSqlInt32(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override SqlInt64 GetSqlInt64(int ordinal) { EnsureCanGetCol( "GetSqlInt64", ordinal); return ValueUtilsSmi.GetSqlInt64(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override SqlSingle GetSqlSingle(int ordinal) { EnsureCanGetCol( "GetSqlSingle", ordinal); return ValueUtilsSmi.GetSqlSingle(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override SqlDouble GetSqlDouble(int ordinal) { EnsureCanGetCol( "GetSqlDouble", ordinal); return ValueUtilsSmi.GetSqlDouble(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override SqlMoney GetSqlMoney(int ordinal) { EnsureCanGetCol( "GetSqlMoney", ordinal); return ValueUtilsSmi.GetSqlMoney(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override SqlDateTime GetSqlDateTime(int ordinal) { EnsureCanGetCol( "GetSqlDateTime", ordinal); return ValueUtilsSmi.GetSqlDateTime(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override SqlDecimal GetSqlDecimal(int ordinal) { EnsureCanGetCol( "GetSqlDecimal", ordinal); return ValueUtilsSmi.GetSqlDecimal(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override SqlString GetSqlString(int ordinal) { EnsureCanGetCol( "GetSqlString", ordinal); return ValueUtilsSmi.GetSqlString(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override SqlGuid GetSqlGuid(int ordinal) { EnsureCanGetCol( "GetSqlGuid", ordinal); return ValueUtilsSmi.GetSqlGuid(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal]); } public override SqlChars GetSqlChars(int ordinal) { EnsureCanGetCol( "GetSqlChars", ordinal); return ValueUtilsSmi.GetSqlChars(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal], _currentConnection.InternalContext); } public override SqlBytes GetSqlBytes(int ordinal) { EnsureCanGetCol( "GetSqlBytes", ordinal); return ValueUtilsSmi.GetSqlBytes(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal], _currentConnection.InternalContext); } public override SqlXml GetSqlXml(int ordinal) { EnsureCanGetCol( "GetSqlXml", ordinal); return ValueUtilsSmi.GetSqlXml(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal], _currentConnection.InternalContext); } public override TimeSpan GetTimeSpan(int ordinal) { EnsureCanGetCol("GetTimeSpan", ordinal); return ValueUtilsSmi.GetTimeSpan(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal], _currentConnection.IsKatmaiOrNewer); } public override DateTimeOffset GetDateTimeOffset(int ordinal) { EnsureCanGetCol("GetDateTimeOffset", ordinal); return ValueUtilsSmi.GetDateTimeOffset(_readerEventSink, _currentColumnValuesV3, ordinal, _currentMetaData[ordinal], _currentConnection.IsKatmaiOrNewer); } public override object GetSqlValue(int ordinal) { EnsureCanGetCol( "GetSqlValue", ordinal); SmiMetaData metaData = _currentMetaData[ordinal]; if (_currentConnection.IsKatmaiOrNewer) { return ValueUtilsSmi.GetSqlValue200(_readerEventSink, (SmiTypedGetterSetter)_currentColumnValuesV3, ordinal, metaData, _currentConnection.InternalContext); } return ValueUtilsSmi.GetSqlValue(_readerEventSink, _currentColumnValuesV3, ordinal, metaData, _currentConnection.InternalContext); ; } public override int GetSqlValues(object[] values) { EnsureCanGetCol( "GetSqlValues", 0); if (null == values) { throw ADP.ArgumentNull("values"); } int copyLength = (values.Length < _visibleColumnCount) ? values.Length : _visibleColumnCount; for(int i=0; i