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