// 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; } }
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); } } }
// 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); } }
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))); } } }
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); }
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)); } } } }