Пример #1
0
        //  Implements SqlClient 2.0-compatible SetValue() semantics + Orcas extensions
        //      Assumes caller already validated basic type against the metadata, other than trimming lengths and 
        //      checking individual field values (TVPs)
        internal static void SetCompatibleValueV200(
            SmiEventSink_Default    sink,
            SmiTypedGetterSetter    setters,
            int                     ordinal,
            SmiMetaData             metaData,
            object                  value,
            ExtendedClrTypeCode     typeCode,
            int                     offset,
            int                     length,
            ParameterPeekAheadValue peekAhead
            ) {
            // Ensure caller validated compatibility for types handled directly in this method
            Debug.Assert(  (ExtendedClrTypeCode.DataTable != typeCode &&
                            ExtendedClrTypeCode.DbDataReader != typeCode &&
                            ExtendedClrTypeCode.IEnumerableOfSqlDataRecord != typeCode) ||
                        CanAccessSetterDirectly(metaData, typeCode), "Un-validated type '" + typeCode + "' for metaData: " + metaData.SqlDbType);

            switch(typeCode) {
                case ExtendedClrTypeCode.DataTable:         
                    SetDataTable_Unchecked(sink, setters, ordinal, metaData, (DataTable)value); 
                    break;
                case ExtendedClrTypeCode.DbDataReader:      
                    SetDbDataReader_Unchecked(sink, setters, ordinal, metaData, (DbDataReader)value); 
                    break;
                case ExtendedClrTypeCode.IEnumerableOfSqlDataRecord:
                    SetIEnumerableOfSqlDataRecord_Unchecked(sink, setters, ordinal, metaData, (IEnumerable<SqlDataRecord>)value, peekAhead); 
                    break;
                case ExtendedClrTypeCode.TimeSpan:
                    SetTimeSpan_Checked(sink, setters, ordinal, metaData, (TimeSpan)value);
                    break;
                case ExtendedClrTypeCode.DateTimeOffset:
                    SetDateTimeOffset_Unchecked(sink, setters, ordinal, (DateTimeOffset)value);
                    break;
                default:
                    SetCompatibleValue(sink, setters, ordinal, metaData, value, typeCode, offset);
                    break;
            }
        }
Пример #2
0
        private static void SetIEnumerableOfSqlDataRecord_Unchecked(
            SmiEventSink_Default        sink,
            SmiTypedGetterSetter        setters,
            int                         ordinal,
            SmiMetaData                 metaData,
            IEnumerable<SqlDataRecord>  value,
            ParameterPeekAheadValue     peekAhead
            ) {
            // Get target gettersetter
            setters = setters.GetTypedGetterSetter(sink, ordinal);
            sink.ProcessMessagesAndThrow();

            IEnumerator<SqlDataRecord> enumerator = null;
            try {
                // Need to copy field metadata to an array to call FillCompatibleITypeSettersFromRecord
                SmiExtendedMetaData[] mdFields = new SmiExtendedMetaData[metaData.FieldMetaData.Count];
                metaData.FieldMetaData.CopyTo(mdFields, 0);

                SmiDefaultFieldsProperty defaults = (SmiDefaultFieldsProperty) metaData.ExtendedProperties[SmiPropertySelector.DefaultFields];

                int recordNumber = 1;   // used only for reporting position when there are errors.

                // obtain enumerator and handle any peekahead values
                if (null != peekAhead && null != peekAhead.FirstRecord) {
                    // hook up to enumerator
                    enumerator = peekAhead.Enumerator;

                    // send the first record that was obtained earlier
                    setters.NewElement(sink);
                    sink.ProcessMessagesAndThrow();
                    FillCompatibleSettersFromRecord(sink, setters, mdFields, peekAhead.FirstRecord, defaults);
                    recordNumber++;
                }
                else {
                    enumerator = value.GetEnumerator();
                }

                using (enumerator) {
                    while(enumerator.MoveNext()) {
                        setters.NewElement(sink);
                        sink.ProcessMessagesAndThrow();

                        SqlDataRecord record = enumerator.Current;

                        if (record.FieldCount != mdFields.Length) {
                            throw SQL.EnumeratedRecordFieldCountChanged(recordNumber);
                        }

                        for(int i=0; i<record.FieldCount; i++) {
                            if (!MetaDataUtilsSmi.IsCompatible(metaData.FieldMetaData[i], record.GetSqlMetaData(i))) {
                                throw SQL.EnumeratedRecordMetaDataChanged(record.GetName(i), recordNumber);
                            }
                        }

                        FillCompatibleSettersFromRecord(sink, setters, mdFields, record, defaults);
                        recordNumber++;
                    }

                    setters.EndElements(sink);
                    sink.ProcessMessagesAndThrow();
                }
            }
            finally {
                // Clean up!
                IDisposable disposable = enumerator as IDisposable;
                if (null != disposable) {
                    disposable.Dispose();
                }
            }
        }
        private void SetUpSmiRequest(SqlInternalConnectionSmi innerConnection)
        {
            this.DisposeSmiRequest();
            if (this.Notification != null)
            {
                throw SQL.NotificationsNotAvailableOnContextConnection();
            }
            SmiParameterMetaData[] parameterMetaData = null;
            ParameterPeekAheadValue[] valueArray = null;
            int parameterCount = this.GetParameterCount(this.Parameters);
            if (0 < parameterCount)
            {
                parameterMetaData = new SmiParameterMetaData[parameterCount];
                valueArray = new ParameterPeekAheadValue[parameterCount];
                for (int j = 0; j < parameterCount; j++)
                {
                    SqlParameter parameter2 = this.Parameters[j];
                    parameter2.Validate(j, System.Data.CommandType.StoredProcedure == this.CommandType);
                    parameterMetaData[j] = parameter2.MetaDataForSmi(out valueArray[j]);
                    if (!innerConnection.IsKatmaiOrNewer)
                    {
                        MetaType metaTypeFromSqlDbType = MetaType.GetMetaTypeFromSqlDbType(parameterMetaData[j].SqlDbType, parameterMetaData[j].IsMultiValued);
                        if (!metaTypeFromSqlDbType.Is90Supported)
                        {
                            throw ADP.VersionDoesNotSupportDataType(metaTypeFromSqlDbType.TypeName);
                        }
                    }
                }
            }
            System.Data.CommandType commandType = this.CommandType;
            this._smiRequestContext = innerConnection.InternalContext;
            this._smiRequest = this._smiRequestContext.CreateRequestExecutor(this.CommandText, commandType, parameterMetaData, this.EventSink);
            this.EventSink.ProcessMessagesAndThrow();
            for (int i = 0; i < parameterCount; i++)
            {
                if ((ParameterDirection.Output == parameterMetaData[i].Direction) || (ParameterDirection.ReturnValue == parameterMetaData[i].Direction))
                {
                    continue;
                }
                SqlParameter parameter = this.Parameters[i];
                object coercedValue = parameter.GetCoercedValue();
                ExtendedClrTypeCode typeCode = MetaDataUtilsSmi.DetermineExtendedTypeCodeForUseWithSqlDbType(parameterMetaData[i].SqlDbType, parameterMetaData[i].IsMultiValued, coercedValue, null, SmiContextFactory.Instance.NegotiatedSmiVersion);
                if ((System.Data.CommandType.StoredProcedure == commandType) && (ExtendedClrTypeCode.Empty == typeCode))
                {
                    this._smiRequest.SetDefault(i);
                    continue;
                }
                int size = parameter.Size;
                if (((size != 0) && (size != -1L)) && !parameter.SizeInferred)
                {
                    switch (parameterMetaData[i].SqlDbType)
                    {
                        case SqlDbType.NText:
                            if (size != 0x3fffffff)
                            {
                                throw SQL.ParameterSizeRestrictionFailure(i);
                            }
                            break;

                        case SqlDbType.NVarChar:
                            if (((size > 0) && (size != 0x3fffffff)) && (parameterMetaData[i].MaxLength == -1L))
                            {
                                throw SQL.ParameterSizeRestrictionFailure(i);
                            }
                            break;

                        case SqlDbType.Text:
                        case SqlDbType.Image:
                            goto Label_01E8;

                        case SqlDbType.Timestamp:
                            if (size < SmiMetaData.DefaultTimestamp.MaxLength)
                            {
                                throw SQL.ParameterSizeRestrictionFailure(i);
                            }
                            break;

                        case SqlDbType.VarBinary:
                        case SqlDbType.VarChar:
                            goto Label_020C;

                        case SqlDbType.Variant:
                            goto Label_0271;

                        case SqlDbType.Xml:
                            if ((coercedValue != null) && (ExtendedClrTypeCode.SqlXml != typeCode))
                            {
                                throw SQL.ParameterSizeRestrictionFailure(i);
                            }
                            break;
                    }
                }
                goto Label_02CF;
            Label_01E8:
                if (size == 0x7fffffff)
                {
                    goto Label_02CF;
                }
                throw SQL.ParameterSizeRestrictionFailure(i);
            Label_020C:
                if (((size <= 0) || (size == 0x7fffffff)) || (parameterMetaData[i].MaxLength != -1L))
                {
                    goto Label_02CF;
                }
                throw SQL.ParameterSizeRestrictionFailure(i);
            Label_0271:
                if (coercedValue != null)
                {
                    MetaType metaTypeFromValue = MetaType.GetMetaTypeFromValue(coercedValue);
                    if (((metaTypeFromValue.IsNCharType && (size < 0xfa0L)) || (metaTypeFromValue.IsBinType && (size < 0x1f40L))) || (metaTypeFromValue.IsAnsiType && (size < 0x1f40L)))
                    {
                        throw SQL.ParameterSizeRestrictionFailure(i);
                    }
                }
            Label_02CF:
                if (innerConnection.IsKatmaiOrNewer)
                {
                    ValueUtilsSmi.SetCompatibleValueV200(this.EventSink, this._smiRequest, i, parameterMetaData[i], coercedValue, typeCode, parameter.Offset, parameter.Size, valueArray[i]);
                }
                else
                {
                    ValueUtilsSmi.SetCompatibleValue(this.EventSink, this._smiRequest, i, parameterMetaData[i], coercedValue, typeCode, parameter.Offset);
                }
            }
        }
Пример #4
0
        // VSTFDevDiv#479681 - Data corruption when sending Katmai Date types to the server via TVP
        // Ensures proper handling on DateTime2 sub type for Sql_Variants and TVPs.
        internal static void SetCompatibleValueV200(
            SmiEventSink_Default sink,
            SmiTypedGetterSetter setters,
            int ordinal,
            SmiMetaData metaData,
            object value,
            ExtendedClrTypeCode typeCode,
            int offset,
            int length,
            ParameterPeekAheadValue peekAhead,
            SqlBuffer.StorageType storageType
            )
        {
            // Ensure caller validated compatibility for types handled directly in this method
            Debug.Assert((ExtendedClrTypeCode.DataTable != typeCode &&
                            ExtendedClrTypeCode.DbDataReader != typeCode &&
                            ExtendedClrTypeCode.IEnumerableOfSqlDataRecord != typeCode) ||
                        CanAccessSetterDirectly(metaData, typeCode), "Un-validated type '" + typeCode + "' for metaData: " + metaData.SqlDbType);

            if (typeCode == ExtendedClrTypeCode.DateTime)
            {
                if (storageType == SqlBuffer.StorageType.DateTime2)
                    SetDateTime2_Checked(sink, setters, ordinal, metaData, (DateTime)value);
                else if (storageType == SqlBuffer.StorageType.Date)
                    SetDate_Checked(sink, setters, ordinal, metaData, (DateTime)value);
                else
                    SetDateTime_Checked(sink, setters, ordinal, metaData, (DateTime)value);
            }
            else
            {
                SetCompatibleValueV200(sink, setters, ordinal, metaData, value, typeCode, offset, length, peekAhead);
            }
        }
Пример #5
0
        private void GetActualFieldsAndProperties(out List<MSS.SmiExtendedMetaData> fields, out SmiMetaDataPropertyCollection props, out ParameterPeekAheadValue peekAhead)
        {
            fields = null;
            props = null;
            peekAhead = null;

            object value = GetCoercedValue();
            if (value is SqlDataReader)
            {
                fields = new List<MSS.SmiExtendedMetaData>(((SqlDataReader)value).GetInternalSmiMetaData());
                if (fields.Count <= 0)
                {
                    throw SQL.NotEnoughColumnsInStructuredType();
                }

                bool[] keyCols = new bool[fields.Count];
                bool hasKey = false;
                for (int i = 0; i < fields.Count; i++)
                {
                    MSS.SmiQueryMetaData qmd = fields[i] as MSS.SmiQueryMetaData;
                    if (null != qmd && !qmd.IsKey.IsNull && qmd.IsKey.Value)
                    {
                        keyCols[i] = true;
                        hasKey = true;
                    }
                }

                // Add unique key property, if any found.
                if (hasKey)
                {
                    props = new SmiMetaDataPropertyCollection();
                    props[MSS.SmiPropertySelector.UniqueKey] = new MSS.SmiUniqueKeyProperty(new List<bool>(keyCols));
                }
            }
            else if (value is IEnumerable<SqlDataRecord>)
            {
                // must grab the first record of the enumerator to get the metadata
                IEnumerator<MSS.SqlDataRecord> enumerator = ((IEnumerable<MSS.SqlDataRecord>)value).GetEnumerator();
                MSS.SqlDataRecord firstRecord = null;
                try
                {
                    // no need for fields if there's no rows or no columns -- we'll be sending a null instance anyway.
                    if (enumerator.MoveNext())
                    {
                        firstRecord = enumerator.Current;
                        int fieldCount = firstRecord.FieldCount;
                        if (0 < fieldCount)
                        {
                            // It's valid!  Grab those fields.
                            bool[] keyCols = new bool[fieldCount];
                            bool[] defaultFields = new bool[fieldCount];
                            bool[] sortOrdinalSpecified = new bool[fieldCount];
                            int maxSortOrdinal = -1;  // largest sort ordinal seen, used to optimize locating holes in the list
                            bool hasKey = false;
                            bool hasDefault = false;
                            int sortCount = 0;
                            SmiOrderProperty.SmiColumnOrder[] sort = new SmiOrderProperty.SmiColumnOrder[fieldCount];
                            fields = new List<MSS.SmiExtendedMetaData>(fieldCount);
                            for (int i = 0; i < fieldCount; i++)
                            {
                                SqlMetaData colMeta = firstRecord.GetSqlMetaData(i);
                                fields.Add(MSS.MetaDataUtilsSmi.SqlMetaDataToSmiExtendedMetaData(colMeta));
                                if (colMeta.IsUniqueKey)
                                {
                                    keyCols[i] = true;
                                    hasKey = true;
                                }

                                if (colMeta.UseServerDefault)
                                {
                                    defaultFields[i] = true;
                                    hasDefault = true;
                                }

                                sort[i].Order = colMeta.SortOrder;
                                if (SortOrder.Unspecified != colMeta.SortOrder)
                                {
                                    // SqlMetaData takes care of checking for negative sort ordinals with specified sort order

                                    // bail early if there's no way sort order could be monotonically increasing
                                    if (fieldCount <= colMeta.SortOrdinal)
                                    {
                                        throw SQL.SortOrdinalGreaterThanFieldCount(i, colMeta.SortOrdinal);
                                    }

                                    // Check to make sure we haven't seen this ordinal before
                                    if (sortOrdinalSpecified[colMeta.SortOrdinal])
                                    {
                                        throw SQL.DuplicateSortOrdinal(colMeta.SortOrdinal);
                                    }

                                    sort[i].SortOrdinal = colMeta.SortOrdinal;
                                    sortOrdinalSpecified[colMeta.SortOrdinal] = true;
                                    if (colMeta.SortOrdinal > maxSortOrdinal)
                                    {
                                        maxSortOrdinal = colMeta.SortOrdinal;
                                    }
                                    sortCount++;
                                }
                            }

                            if (hasKey)
                            {
                                props = new SmiMetaDataPropertyCollection();
                                props[MSS.SmiPropertySelector.UniqueKey] = new MSS.SmiUniqueKeyProperty(new List<bool>(keyCols));
                            }

                            if (hasDefault)
                            {
                                // May have already created props list in unique key handling
                                if (null == props)
                                {
                                    props = new SmiMetaDataPropertyCollection();
                                }

                                props[MSS.SmiPropertySelector.DefaultFields] = new MSS.SmiDefaultFieldsProperty(new List<bool>(defaultFields));
                            }

                            if (0 < sortCount)
                            {
                                // validate monotonically increasing sort order.
                                //  Since we already checked for duplicates, we just need
                                //  to watch for values outside of the sortCount range.
                                if (maxSortOrdinal >= sortCount)
                                {
                                    // there is at least one hole, find the first one
                                    int i;
                                    for (i = 0; i < sortCount; i++)
                                    {
                                        if (!sortOrdinalSpecified[i])
                                        {
                                            break;
                                        }
                                    }
                                    Debug.Assert(i < sortCount, "SqlParameter.GetActualFieldsAndProperties: SortOrdinal hole-finding algorithm failed!");
                                    throw SQL.MissingSortOrdinal(i);
                                }

                                // May have already created props list
                                if (null == props)
                                {
                                    props = new SmiMetaDataPropertyCollection();
                                }

                                props[MSS.SmiPropertySelector.SortOrder] = new MSS.SmiOrderProperty(
                                        new List<SmiOrderProperty.SmiColumnOrder>(sort));
                            }

                            // pack it up so we don't have to rewind to send the first value
                            peekAhead = new ParameterPeekAheadValue();
                            peekAhead.Enumerator = enumerator;
                            peekAhead.FirstRecord = firstRecord;

                            // now that it's all packaged, make sure we don't dispose it.
                            enumerator = null;
                        }
                        else
                        {
                            throw SQL.NotEnoughColumnsInStructuredType();
                        }
                    }
                    else
                    {
                        throw SQL.IEnumerableOfSqlDataRecordHasNoRows();
                    }
                }
                finally
                {
                    if (enumerator != null)
                    {
                        enumerator.Dispose();
                    }
                }
            }
            else if (value is DbDataReader)
            {
                // For ProjectK\CoreCLR, DbDataReader no longer supports GetSchema
                // So instead we will attempt to generate the metadata from the Field Type alone
                var reader = (DbDataReader)value;
                if (reader.FieldCount <= 0)
                {
                    throw SQL.NotEnoughColumnsInStructuredType();
                }

                fields = new List<MSS.SmiExtendedMetaData>(reader.FieldCount);
                for (int i = 0; i < reader.FieldCount; i++)
                {
                    fields.Add(MSS.MetaDataUtilsSmi.SmiMetaDataFromType(reader.GetName(i), reader.GetFieldType(i)));
                }
            }
        }
Пример #6
0
        internal MSS.SmiParameterMetaData MetaDataForSmi(out ParameterPeekAheadValue peekAhead)
        {
            peekAhead = null;
            MetaType mt = ValidateTypeLengths();
            long actualLen = GetActualSize();
            long maxLen = this.Size;

            // GetActualSize returns bytes length, but smi expects char length for 
            //  character types, so adjust
            if (!mt.IsLong)
            {
                if (SqlDbType.NChar == mt.SqlDbType || SqlDbType.NVarChar == mt.SqlDbType)
                {
                    actualLen = actualLen / sizeof(char);
                }

                if (actualLen > maxLen)
                {
                    maxLen = actualLen;
                }
            }

            // Determine maxLength for types that ValidateTypeLengths won't figure out
            if (0 == maxLen)
            {
                if (SqlDbType.Binary == mt.SqlDbType || SqlDbType.VarBinary == mt.SqlDbType)
                {
                    maxLen = MSS.SmiMetaData.MaxBinaryLength;
                }
                else if (SqlDbType.Char == mt.SqlDbType || SqlDbType.VarChar == mt.SqlDbType)
                {
                    maxLen = MSS.SmiMetaData.MaxANSICharacters;
                }
                else if (SqlDbType.NChar == mt.SqlDbType || SqlDbType.NVarChar == mt.SqlDbType)
                {
                    maxLen = MSS.SmiMetaData.MaxUnicodeCharacters;
                }
            }
            else if ((maxLen > MSS.SmiMetaData.MaxBinaryLength && (SqlDbType.Binary == mt.SqlDbType || SqlDbType.VarBinary == mt.SqlDbType))
                  || (maxLen > MSS.SmiMetaData.MaxANSICharacters && (SqlDbType.Char == mt.SqlDbType || SqlDbType.VarChar == mt.SqlDbType))
                  || (maxLen > MSS.SmiMetaData.MaxUnicodeCharacters && (SqlDbType.NChar == mt.SqlDbType || SqlDbType.NVarChar == mt.SqlDbType)))
            {
                maxLen = -1;
            }


            int localeId = LocaleId;
            if (0 == localeId && mt.IsCharType)
            {
                object value = GetCoercedValue();
                if (value is SqlString && !((SqlString)value).IsNull)
                {
                    localeId = ((SqlString)value).LCID;
                }
                else
                {
                    localeId = Locale.GetCurrentCultureLcid();
                }
            }

            SqlCompareOptions compareOpts = CompareInfo;
            if (0 == compareOpts && mt.IsCharType)
            {
                object value = GetCoercedValue();
                if (value is SqlString && !((SqlString)value).IsNull)
                {
                    compareOpts = ((SqlString)value).SqlCompareOptions;
                }
                else
                {
                    compareOpts = MSS.SmiMetaData.GetDefaultForType(mt.SqlDbType).CompareOptions;
                }
            }

            string typeSpecificNamePart1 = null;
            string typeSpecificNamePart2 = null;
            string typeSpecificNamePart3 = null;

            if (SqlDbType.Xml == mt.SqlDbType)
            {
                typeSpecificNamePart1 = this.XmlSchemaCollectionDatabase;
                typeSpecificNamePart2 = this.XmlSchemaCollectionOwningSchema;
                typeSpecificNamePart3 = this.XmlSchemaCollectionName;
            }
            else if (SqlDbType.Udt == mt.SqlDbType || (SqlDbType.Structured == mt.SqlDbType && !ADP.IsEmpty(this.TypeName)))
            {
                // Split the input name. The type name is specified as single 3 part name.
                // NOTE: ParseTypeName throws if format is incorrect
                String[] names;
                if (SqlDbType.Udt == mt.SqlDbType)
                {
                    throw ADP.DbTypeNotSupported(SqlDbType.Udt.ToString());
                }
                else
                {
                    names = ParseTypeName(this.TypeName);
                }

                if (1 == names.Length)
                {
                    typeSpecificNamePart3 = names[0];
                }
                else if (2 == names.Length)
                {
                    typeSpecificNamePart2 = names[0];
                    typeSpecificNamePart3 = names[1];
                }
                else if (3 == names.Length)
                {
                    typeSpecificNamePart1 = names[0];
                    typeSpecificNamePart2 = names[1];
                    typeSpecificNamePart3 = names[2];
                }
                else
                {
                    throw ADP.ArgumentOutOfRange("names");
                }

                if ((!ADP.IsEmpty(typeSpecificNamePart1) && TdsEnums.MAX_SERVERNAME < typeSpecificNamePart1.Length)
                    || (!ADP.IsEmpty(typeSpecificNamePart2) && TdsEnums.MAX_SERVERNAME < typeSpecificNamePart2.Length)
                    || (!ADP.IsEmpty(typeSpecificNamePart3) && TdsEnums.MAX_SERVERNAME < typeSpecificNamePart3.Length))
                {
                    throw ADP.ArgumentOutOfRange("names");
                }
            }

            byte precision = GetActualPrecision();
            byte scale = GetActualScale();

            // precision for decimal types may still need adjustment.
            if (SqlDbType.Decimal == mt.SqlDbType)
            {
                if (0 == precision)
                {
                    precision = TdsEnums.DEFAULT_NUMERIC_PRECISION;
                }
            }

            // Sub-field determination
            List<SmiExtendedMetaData> fields = null;
            MSS.SmiMetaDataPropertyCollection extendedProperties = null;
            if (SqlDbType.Structured == mt.SqlDbType)
            {
                GetActualFieldsAndProperties(out fields, out extendedProperties, out peekAhead);
            }

            return new MSS.SmiParameterMetaData(mt.SqlDbType,
                                            maxLen,
                                            precision,
                                            scale,
                                            localeId,
                                            compareOpts,
                                            SqlDbType.Structured == mt.SqlDbType,
                                            fields,
                                            extendedProperties,
                                            this.ParameterNameFixed,
                                            typeSpecificNamePart1,
                                            typeSpecificNamePart2,
                                            typeSpecificNamePart3,
                                            this.Direction);
        }
 private static void SetIEnumerableOfSqlDataRecord_Unchecked(SmiEventSink_Default sink, SmiTypedGetterSetter setters, int ordinal, SmiMetaData metaData, IEnumerable<SqlDataRecord> value, ParameterPeekAheadValue peekAhead)
 {
     setters = setters.GetTypedGetterSetter(sink, ordinal);
     sink.ProcessMessagesAndThrow();
     IEnumerator<SqlDataRecord> enumerator = null;
     try
     {
         SmiExtendedMetaData[] array = new SmiExtendedMetaData[metaData.FieldMetaData.Count];
         metaData.FieldMetaData.CopyTo(array, 0);
         SmiDefaultFieldsProperty useDefaultValues = (SmiDefaultFieldsProperty) metaData.ExtendedProperties[SmiPropertySelector.DefaultFields];
         int recordNumber = 1;
         if ((peekAhead != null) && (peekAhead.FirstRecord != null))
         {
             enumerator = peekAhead.Enumerator;
             setters.NewElement(sink);
             sink.ProcessMessagesAndThrow();
             FillCompatibleSettersFromRecord(sink, setters, array, peekAhead.FirstRecord, useDefaultValues);
             recordNumber++;
         }
         else
         {
             enumerator = value.GetEnumerator();
         }
         using (enumerator)
         {
             while (enumerator.MoveNext())
             {
                 setters.NewElement(sink);
                 sink.ProcessMessagesAndThrow();
                 SqlDataRecord current = enumerator.Current;
                 if (current.FieldCount != array.Length)
                 {
                     throw SQL.EnumeratedRecordFieldCountChanged(recordNumber);
                 }
                 for (int i = 0; i < current.FieldCount; i++)
                 {
                     if (!MetaDataUtilsSmi.IsCompatible(metaData.FieldMetaData[i], current.GetSqlMetaData(i)))
                     {
                         throw SQL.EnumeratedRecordMetaDataChanged(current.GetName(i), recordNumber);
                     }
                 }
                 FillCompatibleSettersFromRecord(sink, setters, array, current, useDefaultValues);
                 recordNumber++;
             }
             setters.EndElements(sink);
             sink.ProcessMessagesAndThrow();
         }
     }
     finally
     {
         IDisposable disposable = enumerator;
         if (disposable != null)
         {
             disposable.Dispose();
         }
     }
 }
        internal static void SetCompatibleValueV200(SmiEventSink_Default sink, SmiTypedGetterSetter setters, int ordinal, SmiMetaData metaData, object value, ExtendedClrTypeCode typeCode, int offset, int length, ParameterPeekAheadValue peekAhead)
        {
            switch (typeCode)
            {
                case ExtendedClrTypeCode.DataTable:
                    SetDataTable_Unchecked(sink, setters, ordinal, metaData, (DataTable) value);
                    return;

                case ExtendedClrTypeCode.DbDataReader:
                    SetDbDataReader_Unchecked(sink, setters, ordinal, metaData, (DbDataReader) value);
                    return;

                case ExtendedClrTypeCode.IEnumerableOfSqlDataRecord:
                    SetIEnumerableOfSqlDataRecord_Unchecked(sink, setters, ordinal, metaData, (IEnumerable<SqlDataRecord>) value, peekAhead);
                    return;

                case ExtendedClrTypeCode.TimeSpan:
                    SetTimeSpan_Checked(sink, setters, ordinal, metaData, (TimeSpan) value);
                    return;

                case ExtendedClrTypeCode.DateTimeOffset:
                    SetDateTimeOffset_Unchecked(sink, setters, ordinal, (DateTimeOffset) value);
                    return;
            }
            SetCompatibleValue(sink, setters, ordinal, metaData, value, typeCode, offset);
        }
Пример #9
0
        private void GetActualFieldsAndProperties(out List<MSS.SmiExtendedMetaData> fields, out SmiMetaDataPropertyCollection props, out ParameterPeekAheadValue peekAhead) {
            fields = null;
            props = null;
            peekAhead = null;

            object value = GetCoercedValue();
            if (value is DataTable) {
                DataTable dt = value as DataTable;
                if (dt.Columns.Count <= 0) {
                    throw SQL.NotEnoughColumnsInStructuredType();
                }
                fields = new List<MSS.SmiExtendedMetaData>(dt.Columns.Count);
                bool[] keyCols = new bool[dt.Columns.Count];
                bool hasKey = false;

                // set up primary key as unique key list
                //  do this prior to general metadata loop to favor the primary key
                if (null != dt.PrimaryKey && 0 < dt.PrimaryKey.Length) {
                    foreach(DataColumn col in dt.PrimaryKey) {
                        keyCols[col.Ordinal] = true;
                        hasKey = true;
                    }
                }

                for(int i=0; i<dt.Columns.Count; i++) {
                    fields.Add(MSS.MetaDataUtilsSmi.SmiMetaDataFromDataColumn(dt.Columns[i], dt));

                    // DataColumn uniqueness is only for a single column, so don't add
                    //  more than one.  (keyCols.Count first for assumed minimal perf benefit)
                    if (!hasKey && dt.Columns[i].Unique) {
                        keyCols[i] = true;
                        hasKey = true;
                    }
                }

                // Add unique key property, if any found.
                if (hasKey) {
                    props = new SmiMetaDataPropertyCollection();
                    props[MSS.SmiPropertySelector.UniqueKey] = new MSS.SmiUniqueKeyProperty(new List<bool>(keyCols));
                }
            }
            else if (value is SqlDataReader) {
                fields = new List<MSS.SmiExtendedMetaData>(((SqlDataReader)value).GetInternalSmiMetaData());
                if (fields.Count <= 0) {
                    throw SQL.NotEnoughColumnsInStructuredType();
                }

                bool[] keyCols = new bool[fields.Count];
                bool hasKey = false;
                for(int i=0; i<fields.Count; i++) {
                    MSS.SmiQueryMetaData qmd = fields[i] as MSS.SmiQueryMetaData;
                    if (null != qmd && !qmd.IsKey.IsNull && qmd.IsKey.Value) {
                        keyCols[i] = true;
                        hasKey = true;
                    }
                }

                // Add unique key property, if any found.
                if (hasKey) {
                    props = new SmiMetaDataPropertyCollection();
                    props[MSS.SmiPropertySelector.UniqueKey] = new MSS.SmiUniqueKeyProperty(new List<bool>(keyCols));
                }
            }
            else if (value is IEnumerable<SqlDataRecord>) {
                // must grab the first record of the enumerator to get the metadata
                IEnumerator<MSS.SqlDataRecord> enumerator = ((IEnumerable<MSS.SqlDataRecord>) value).GetEnumerator();
                MSS.SqlDataRecord firstRecord = null;
                try {
                    // no need for fields if there's no rows or no columns -- we'll be sending a null instance anyway.
                    if (enumerator.MoveNext()) {
                        firstRecord = enumerator.Current;
                        int fieldCount = firstRecord.FieldCount;
                        if (0 < fieldCount) {
                            // It's valid!  Grab those fields.
                            bool[] keyCols = new bool[fieldCount];
                            bool[] defaultFields = new bool[fieldCount];
                            bool[] sortOrdinalSpecified = new bool[fieldCount];
                            int maxSortOrdinal = -1;  // largest sort ordinal seen, used to optimize locating holes in the list
                            bool hasKey = false;
                            bool hasDefault = false;
                            int sortCount = 0;
                            SmiOrderProperty.SmiColumnOrder[] sort = new SmiOrderProperty.SmiColumnOrder[fieldCount];
                            fields = new List<MSS.SmiExtendedMetaData>(fieldCount);
                            for (int i = 0; i < fieldCount; i++) {
                                SqlMetaData colMeta = firstRecord.GetSqlMetaData(i);
                                fields.Add(MSS.MetaDataUtilsSmi.SqlMetaDataToSmiExtendedMetaData(colMeta));
                                if (colMeta.IsUniqueKey) {
                                    keyCols[i] = true;
                                    hasKey = true;
                                }

                                if (colMeta.UseServerDefault) {
                                    defaultFields[i] = true;
                                    hasDefault = true;
                                }

                                sort[i].Order = colMeta.SortOrder;
                                if (SortOrder.Unspecified != colMeta.SortOrder) {
                                    // SqlMetaData takes care of checking for negative sort ordinals with specified sort order

                                    // bail early if there's no way sort order could be monotonically increasing
                                    if (fieldCount <= colMeta.SortOrdinal) {
                                        throw SQL.SortOrdinalGreaterThanFieldCount(i, colMeta.SortOrdinal);
                                    }

                                    // Check to make sure we haven't seen this ordinal before
                                    if (sortOrdinalSpecified[colMeta.SortOrdinal]) {
                                        throw SQL.DuplicateSortOrdinal(colMeta.SortOrdinal);
                                    }

                                    sort[i].SortOrdinal = colMeta.SortOrdinal;
                                    sortOrdinalSpecified[colMeta.SortOrdinal] = true;
                                    if (colMeta.SortOrdinal > maxSortOrdinal) {
                                        maxSortOrdinal = colMeta.SortOrdinal;
                                    }
                                    sortCount++;
                                }
                            }

                            if (hasKey) {
                                props = new SmiMetaDataPropertyCollection();
                                props[MSS.SmiPropertySelector.UniqueKey] = new MSS.SmiUniqueKeyProperty(new List<bool>(keyCols));
                            }

                            if (hasDefault) {
                                // May have already created props list in unique key handling
                                if (null == props) {
                                    props = new SmiMetaDataPropertyCollection();
                                }

                                props[MSS.SmiPropertySelector.DefaultFields] = new MSS.SmiDefaultFieldsProperty(new List<bool>(defaultFields));
                            }

                            if (0 < sortCount) {
                                // validate monotonically increasing sort order.
                                //  Since we already checked for duplicates, we just need
                                //  to watch for values outside of the sortCount range.
                                if (maxSortOrdinal >= sortCount) {
                                    // there is at least one hole, find the first one
                                    int i;
                                    for (i = 0; i < sortCount; i++) {
                                        if (!sortOrdinalSpecified[i]) {
                                            break;
                                        }
                                    }
                                    Debug.Assert(i < sortCount, "SqlParameter.GetActualFieldsAndProperties: SortOrdinal hole-finding algorithm failed!");
                                    throw SQL.MissingSortOrdinal(i);
                                }

                                // May have already created props list
                                if (null == props) {
                                    props = new SmiMetaDataPropertyCollection();
                                }

                                props[MSS.SmiPropertySelector.SortOrder] = new MSS.SmiOrderProperty(
                                        new List<SmiOrderProperty.SmiColumnOrder>(sort));
                            }

                            // pack it up so we don't have to rewind to send the first value
                            peekAhead = new ParameterPeekAheadValue();
                            peekAhead.Enumerator = enumerator;
                            peekAhead.FirstRecord = firstRecord;

                            // now that it's all packaged, make sure we don't dispose it.
                            enumerator = null;
                        }
                        else {
                            throw SQL.NotEnoughColumnsInStructuredType();
                        }
                    }
                    else {
                        throw SQL.IEnumerableOfSqlDataRecordHasNoRows();
                    }
                }
                finally {
                    if (enumerator != null) {
                        enumerator.Dispose();
                    }
                }
            }
            else if (value is DbDataReader) {
                DataTable schema = ((DbDataReader)value).GetSchemaTable();
                if (schema.Rows.Count <= 0) {
                    throw SQL.NotEnoughColumnsInStructuredType();
                }

                int fieldCount = schema.Rows.Count;
                fields = new List<MSS.SmiExtendedMetaData>(fieldCount);
                bool[] keyCols = new bool[fieldCount];
                bool hasKey = false;
                int ordinalForIsKey = schema.Columns[SchemaTableColumn.IsKey].Ordinal;
                int ordinalForColumnOrdinal = schema.Columns[SchemaTableColumn.ColumnOrdinal].Ordinal;
                // Extract column metadata
                for(int rowOrdinal=0; rowOrdinal<fieldCount; rowOrdinal++) {
                    DataRow row = schema.Rows[rowOrdinal];
                    SmiExtendedMetaData candidateMd = MSS.MetaDataUtilsSmi.SmiMetaDataFromSchemaTableRow(row);

                    // Determine destination ordinal.  Allow for ordinal not specified by assuming rowOrdinal *is* columnOrdinal
                    //  in that case, but don't worry about mix-and-match of the two techniques
                    int columnOrdinal = rowOrdinal;
                    if (!row.IsNull(ordinalForColumnOrdinal)) {
                       columnOrdinal = (int) row[ordinalForColumnOrdinal];
                    }

                    // After this point, things we are creating (keyCols, fields) should be accessed by columnOrdinal
                    //  while the source should just be accessed via "row".

                    // Watch for out-of-range ordinals
                    if (columnOrdinal >= fieldCount || columnOrdinal < 0) {
                        throw SQL.InvalidSchemaTableOrdinals();
                    }

                    // extend empty space if out-of-order ordinal
                    while (columnOrdinal > fields.Count) {
                        fields.Add(null);
                    }

                    // Now add the candidate to the list
                    if (fields.Count == columnOrdinal) {
                        fields.Add(candidateMd);
                    }
                    else {
                        // Disallow two columns using the same ordinal (even if due to mixing null and non-null columnOrdinals)
                        if (fields[columnOrdinal] != null) {
                            throw SQL.InvalidSchemaTableOrdinals();
                        }

                        // Don't use insert, since it shifts all later columns down a notch
                        fields[columnOrdinal] = candidateMd;
                    }

                    // Propogate key information
                    if (!row.IsNull(ordinalForIsKey) && (bool)row[ordinalForIsKey]) {
                        keyCols[columnOrdinal] = true;
                        hasKey = true;
                    }
                }

#if DEBUG
                // Check for holes
                //  Above loop logic prevents holes since:
                //      1) loop processes fieldcount # of columns
                //      2) no ordinals outside continuous range from 0 to fieldcount - 1 are allowed
                //      3) no duplicate ordinals are allowed
                // But assert no holes to be sure.
                foreach (SmiExtendedMetaData md in fields) {
                    Debug.Assert(null != md, "Shouldn't be able to have holes, since original loop algorithm prevents such.");
                }
#endif

                // Add unique key property, if any defined.
                if (hasKey) {
                    props = new SmiMetaDataPropertyCollection();
                    props[MSS.SmiPropertySelector.UniqueKey] = new MSS.SmiUniqueKeyProperty(new List<bool>(keyCols));
                }
            }
        }
 internal SmiParameterMetaData MetaDataForSmi(out ParameterPeekAheadValue peekAhead)
 {
     string xmlSchemaCollectionDatabase;
     SqlCompareOptions compareOptions;
     peekAhead = null;
     MetaType type = this.ValidateTypeLengths(true);
     long actualSize = this.GetActualSize();
     long size = this.Size;
     if (!type.IsLong)
     {
         if ((System.Data.SqlDbType.NChar == type.SqlDbType) || (System.Data.SqlDbType.NVarChar == type.SqlDbType))
         {
             actualSize /= 2L;
         }
         if (actualSize > size)
         {
             size = actualSize;
         }
     }
     if (0L == size)
     {
         if ((System.Data.SqlDbType.Binary == type.SqlDbType) || (System.Data.SqlDbType.VarBinary == type.SqlDbType))
         {
             size = 0x1f40L;
         }
         else if ((System.Data.SqlDbType.Char == type.SqlDbType) || (System.Data.SqlDbType.VarChar == type.SqlDbType))
         {
             size = 0x1f40L;
         }
         else if ((System.Data.SqlDbType.NChar == type.SqlDbType) || (System.Data.SqlDbType.NVarChar == type.SqlDbType))
         {
             size = 0xfa0L;
         }
     }
     else if ((((size > 0x1f40L) && ((System.Data.SqlDbType.Binary == type.SqlDbType) || (System.Data.SqlDbType.VarBinary == type.SqlDbType))) || ((size > 0x1f40L) && ((System.Data.SqlDbType.Char == type.SqlDbType) || (System.Data.SqlDbType.VarChar == type.SqlDbType)))) || ((size > 0xfa0L) && ((System.Data.SqlDbType.NChar == type.SqlDbType) || (System.Data.SqlDbType.NVarChar == type.SqlDbType))))
     {
         size = -1L;
     }
     int localeId = this.LocaleId;
     if ((localeId == 0) && type.IsCharType)
     {
         object coercedValue = this.GetCoercedValue();
         if (coercedValue is SqlString)
         {
             SqlString str7 = (SqlString) coercedValue;
             if (!str7.IsNull)
             {
                 SqlString str6 = (SqlString) coercedValue;
                 localeId = str6.LCID;
                 goto Label_0156;
             }
         }
         localeId = CultureInfo.CurrentCulture.LCID;
     }
 Label_0156:
     compareOptions = this.CompareInfo;
     if ((compareOptions == SqlCompareOptions.None) && type.IsCharType)
     {
         object obj2 = this.GetCoercedValue();
         if (obj2 is SqlString)
         {
             SqlString str5 = (SqlString) obj2;
             if (!str5.IsNull)
             {
                 SqlString str4 = (SqlString) obj2;
                 compareOptions = str4.SqlCompareOptions;
                 goto Label_01B3;
             }
         }
         compareOptions = SmiMetaData.GetDefaultForType(type.SqlDbType).CompareOptions;
     }
 Label_01B3:
     xmlSchemaCollectionDatabase = null;
     string xmlSchemaCollectionOwningSchema = null;
     string xmlSchemaCollectionName = null;
     if (System.Data.SqlDbType.Xml == type.SqlDbType)
     {
         xmlSchemaCollectionDatabase = this.XmlSchemaCollectionDatabase;
         xmlSchemaCollectionOwningSchema = this.XmlSchemaCollectionOwningSchema;
         xmlSchemaCollectionName = this.XmlSchemaCollectionName;
     }
     else if ((System.Data.SqlDbType.Udt == type.SqlDbType) || ((System.Data.SqlDbType.Structured == type.SqlDbType) && !ADP.IsEmpty(this.TypeName)))
     {
         string[] strArray;
         if (System.Data.SqlDbType.Udt == type.SqlDbType)
         {
             strArray = ParseTypeName(this.UdtTypeName, true);
         }
         else
         {
             strArray = ParseTypeName(this.TypeName, false);
         }
         if (1 == strArray.Length)
         {
             xmlSchemaCollectionName = strArray[0];
         }
         else if (2 == strArray.Length)
         {
             xmlSchemaCollectionOwningSchema = strArray[0];
             xmlSchemaCollectionName = strArray[1];
         }
         else
         {
             if (3 != strArray.Length)
             {
                 throw ADP.ArgumentOutOfRange("names");
             }
             xmlSchemaCollectionDatabase = strArray[0];
             xmlSchemaCollectionOwningSchema = strArray[1];
             xmlSchemaCollectionName = strArray[2];
         }
         if (((!ADP.IsEmpty(xmlSchemaCollectionDatabase) && (0xff < xmlSchemaCollectionDatabase.Length)) || (!ADP.IsEmpty(xmlSchemaCollectionOwningSchema) && (0xff < xmlSchemaCollectionOwningSchema.Length))) || (!ADP.IsEmpty(xmlSchemaCollectionName) && (0xff < xmlSchemaCollectionName.Length)))
         {
             throw ADP.ArgumentOutOfRange("names");
         }
     }
     byte actualPrecision = this.GetActualPrecision();
     byte actualScale = this.GetActualScale();
     if ((System.Data.SqlDbType.Decimal == type.SqlDbType) && (actualPrecision == 0))
     {
         actualPrecision = 0x1d;
     }
     List<SmiExtendedMetaData> fields = null;
     SmiMetaDataPropertyCollection props = null;
     if (System.Data.SqlDbType.Structured == type.SqlDbType)
     {
         this.GetActualFieldsAndProperties(out fields, out props, out peekAhead);
     }
     return new SmiParameterMetaData(type.SqlDbType, size, actualPrecision, actualScale, (long) localeId, compareOptions, null, System.Data.SqlDbType.Structured == type.SqlDbType, fields, props, this.ParameterNameFixed, xmlSchemaCollectionDatabase, xmlSchemaCollectionOwningSchema, xmlSchemaCollectionName, this.Direction);
 }
 private void GetActualFieldsAndProperties(out List<SmiExtendedMetaData> fields, out SmiMetaDataPropertyCollection props, out ParameterPeekAheadValue peekAhead)
 {
     fields = null;
     props = null;
     peekAhead = null;
     object coercedValue = this.GetCoercedValue();
     if (coercedValue is DataTable)
     {
         DataTable parent = coercedValue as DataTable;
         if (parent.Columns.Count <= 0)
         {
             throw SQL.NotEnoughColumnsInStructuredType();
         }
         fields = new List<SmiExtendedMetaData>(parent.Columns.Count);
         bool[] collection = new bool[parent.Columns.Count];
         bool flag = false;
         if ((parent.PrimaryKey != null) && (0 < parent.PrimaryKey.Length))
         {
             foreach (DataColumn column in parent.PrimaryKey)
             {
                 collection[column.Ordinal] = true;
                 flag = true;
             }
         }
         for (int i = 0; i < parent.Columns.Count; i++)
         {
             fields.Add(MetaDataUtilsSmi.SmiMetaDataFromDataColumn(parent.Columns[i], parent));
             if (!flag && parent.Columns[i].Unique)
             {
                 collection[i] = true;
                 flag = true;
             }
         }
         if (flag)
         {
             props = new SmiMetaDataPropertyCollection();
             props[SmiPropertySelector.UniqueKey] = new SmiUniqueKeyProperty(new List<bool>(collection));
         }
     }
     else if (coercedValue is SqlDataReader)
     {
         fields = new List<SmiExtendedMetaData>(((SqlDataReader) coercedValue).GetInternalSmiMetaData());
         if (fields.Count <= 0)
         {
             throw SQL.NotEnoughColumnsInStructuredType();
         }
         bool[] flagArray6 = new bool[fields.Count];
         bool flag5 = false;
         for (int j = 0; j < fields.Count; j++)
         {
             SmiQueryMetaData data2 = fields[j] as SmiQueryMetaData;
             if (((data2 != null) && !data2.IsKey.IsNull) && data2.IsKey.Value)
             {
                 flagArray6[j] = true;
                 flag5 = true;
             }
         }
         if (flag5)
         {
             props = new SmiMetaDataPropertyCollection();
             props[SmiPropertySelector.UniqueKey] = new SmiUniqueKeyProperty(new List<bool>(flagArray6));
         }
     }
     else
     {
         if (coercedValue is IEnumerable<SqlDataRecord>)
         {
             IEnumerator<SqlDataRecord> enumerator = ((IEnumerable<SqlDataRecord>) coercedValue).GetEnumerator();
             SqlDataRecord current = null;
             try
             {
                 if (!enumerator.MoveNext())
                 {
                     throw SQL.IEnumerableOfSqlDataRecordHasNoRows();
                 }
                 current = enumerator.Current;
                 int fieldCount = current.FieldCount;
                 if (0 >= fieldCount)
                 {
                     throw SQL.NotEnoughColumnsInStructuredType();
                 }
                 bool[] flagArray5 = new bool[fieldCount];
                 bool[] flagArray4 = new bool[fieldCount];
                 bool[] flagArray = new bool[fieldCount];
                 int sortOrdinal = -1;
                 bool flag4 = false;
                 bool flag3 = false;
                 int num7 = 0;
                 SmiOrderProperty.SmiColumnOrder[] orderArray = new SmiOrderProperty.SmiColumnOrder[fieldCount];
                 fields = new List<SmiExtendedMetaData>(fieldCount);
                 for (int k = 0; k < fieldCount; k++)
                 {
                     SqlMetaData sqlMetaData = current.GetSqlMetaData(k);
                     fields.Add(MetaDataUtilsSmi.SqlMetaDataToSmiExtendedMetaData(sqlMetaData));
                     if (sqlMetaData.IsUniqueKey)
                     {
                         flagArray5[k] = true;
                         flag4 = true;
                     }
                     if (sqlMetaData.UseServerDefault)
                     {
                         flagArray4[k] = true;
                         flag3 = true;
                     }
                     orderArray[k].Order = sqlMetaData.SortOrder;
                     if (SortOrder.Unspecified != sqlMetaData.SortOrder)
                     {
                         if (fieldCount <= sqlMetaData.SortOrdinal)
                         {
                             throw SQL.SortOrdinalGreaterThanFieldCount(k, sqlMetaData.SortOrdinal);
                         }
                         if (flagArray[sqlMetaData.SortOrdinal])
                         {
                             throw SQL.DuplicateSortOrdinal(sqlMetaData.SortOrdinal);
                         }
                         orderArray[k].SortOrdinal = sqlMetaData.SortOrdinal;
                         flagArray[sqlMetaData.SortOrdinal] = true;
                         if (sqlMetaData.SortOrdinal > sortOrdinal)
                         {
                             sortOrdinal = sqlMetaData.SortOrdinal;
                         }
                         num7++;
                     }
                 }
                 if (flag4)
                 {
                     props = new SmiMetaDataPropertyCollection();
                     props[SmiPropertySelector.UniqueKey] = new SmiUniqueKeyProperty(new List<bool>(flagArray5));
                 }
                 if (flag3)
                 {
                     if (props == null)
                     {
                         props = new SmiMetaDataPropertyCollection();
                     }
                     props[SmiPropertySelector.DefaultFields] = new SmiDefaultFieldsProperty(new List<bool>(flagArray4));
                 }
                 if (0 < num7)
                 {
                     if (sortOrdinal >= num7)
                     {
                         int index = 0;
                         while (index < num7)
                         {
                             if (!flagArray[index])
                             {
                                 break;
                             }
                             index++;
                         }
                         throw SQL.MissingSortOrdinal(index);
                     }
                     if (props == null)
                     {
                         props = new SmiMetaDataPropertyCollection();
                     }
                     props[SmiPropertySelector.SortOrder] = new SmiOrderProperty(new List<SmiOrderProperty.SmiColumnOrder>(orderArray));
                 }
                 peekAhead = new ParameterPeekAheadValue();
                 peekAhead.Enumerator = enumerator;
                 peekAhead.FirstRecord = current;
                 enumerator = null;
                 return;
             }
             finally
             {
                 if (enumerator != null)
                 {
                     enumerator.Dispose();
                 }
             }
         }
         if (coercedValue is DbDataReader)
         {
             DataTable schemaTable = ((DbDataReader) coercedValue).GetSchemaTable();
             if (schemaTable.Rows.Count <= 0)
             {
                 throw SQL.NotEnoughColumnsInStructuredType();
             }
             int count = schemaTable.Rows.Count;
             fields = new List<SmiExtendedMetaData>(count);
             bool[] flagArray3 = new bool[count];
             bool flag2 = false;
             int ordinal = schemaTable.Columns[SchemaTableColumn.IsKey].Ordinal;
             int columnIndex = schemaTable.Columns[SchemaTableColumn.ColumnOrdinal].Ordinal;
             for (int m = 0; m < count; m++)
             {
                 DataRow schemaRow = schemaTable.Rows[m];
                 SmiExtendedMetaData item = MetaDataUtilsSmi.SmiMetaDataFromSchemaTableRow(schemaRow);
                 int num2 = m;
                 if (!schemaRow.IsNull(columnIndex))
                 {
                     num2 = (int) schemaRow[columnIndex];
                 }
                 if ((num2 < count) && (num2 >= 0))
                 {
                     goto Label_04B7;
                 }
                 throw SQL.InvalidSchemaTableOrdinals();
             Label_04AF:
                 fields.Add(null);
             Label_04B7:
                 if (num2 > fields.Count)
                 {
                     goto Label_04AF;
                 }
                 if (fields.Count == num2)
                 {
                     fields.Add(item);
                 }
                 else
                 {
                     if (fields[num2] != null)
                     {
                         throw SQL.InvalidSchemaTableOrdinals();
                     }
                     fields[num2] = item;
                 }
                 if (!schemaRow.IsNull(ordinal) && ((bool) schemaRow[ordinal]))
                 {
                     flagArray3[num2] = true;
                     flag2 = true;
                 }
             }
             if (flag2)
             {
                 props = new SmiMetaDataPropertyCollection();
                 props[SmiPropertySelector.UniqueKey] = new SmiUniqueKeyProperty(new List<bool>(flagArray3));
             }
         }
     }
 }