private void EnsureSchemaTable() { if (_currentSchemaTable != null || FieldCount == 0) { return; } var formats = CurrentResultSet?.Formats; if (formats == null) { return; } var table = new DataTable("SchemaTable"); var columns = table.Columns; var columnName = columns.Add(SchemaTableColumn.ColumnName, typeof(string)); var columnOrdinal = columns.Add(SchemaTableColumn.ColumnOrdinal, typeof(int)); var columnSize = columns.Add(SchemaTableColumn.ColumnSize, typeof(int)); var numericPrecision = columns.Add(SchemaTableColumn.NumericPrecision, typeof(int)); var numericScale = columns.Add(SchemaTableColumn.NumericScale, typeof(int)); var isUnique = columns.Add(SchemaTableColumn.IsUnique, typeof(bool)); var isKey = columns.Add(SchemaTableColumn.IsKey, typeof(bool)); var baseServerName = columns.Add(SchemaTableOptionalColumn.BaseServerName, typeof(string)); var baseCatalogName = columns.Add(SchemaTableOptionalColumn.BaseCatalogName, typeof(string)); var baseColumnName = columns.Add(SchemaTableColumn.BaseColumnName, typeof(string)); var baseSchemaName = columns.Add(SchemaTableColumn.BaseSchemaName, typeof(string)); var baseTableName = columns.Add(SchemaTableColumn.BaseTableName, typeof(string)); var dataType = columns.Add(SchemaTableColumn.DataType, typeof(Type)); var allowDBNull = columns.Add(SchemaTableColumn.AllowDBNull, typeof(bool)); var providerType = columns.Add(SchemaTableColumn.ProviderType, typeof(int)); var isAliased = columns.Add(SchemaTableColumn.IsAliased, typeof(bool)); var isExpression = columns.Add(SchemaTableColumn.IsExpression, typeof(bool)); var isIdentity = columns.Add("IsIdentity", typeof(bool)); var isAutoIncrement = columns.Add(SchemaTableOptionalColumn.IsAutoIncrement, typeof(bool)); var isRowVersion = columns.Add(SchemaTableOptionalColumn.IsRowVersion, typeof(bool)); var isHidden = columns.Add(SchemaTableOptionalColumn.IsHidden, typeof(bool)); var isLong = columns.Add(SchemaTableColumn.IsLong, typeof(bool)); var isReadOnly = columns.Add(SchemaTableOptionalColumn.IsReadOnly, typeof(bool)); columns.Add(SchemaTableOptionalColumn.ProviderSpecificDataType, typeof(Type)); var dataTypeName = columns.Add("DataTypeName", typeof(string)); //do we need these? columns.Add("XmlSchemaCollectionDatabase", typeof(string)); columns.Add("XmlSchemaCollectionOwningSchema", typeof(string)); columns.Add("XmlSchemaCollectionName", typeof(string)); columns.Add("UdtAssemblyQualifiedName"); columns.Add(SchemaTableColumn.NonVersionedProviderType, typeof(int)); //means "is column [a sparse] set", not "is column set [to a value]" columns.Add("IsColumnSet", typeof(bool)); string baseCatalogNameValue = null; string baseSchemaNameValue = null; string baseTableNameValue = null; for (var i = 0; i < formats.Length; i++) { var column = formats[i]; var row = table.NewRow(); var aseDbType = TypeMap.GetAseDbType(column); row[columnName] = column.DisplayColumnName; row[columnOrdinal] = i; row[columnSize] = column.Length ?? -1; row[numericPrecision] = column.Precision ?? -1; row[numericScale] = column.Scale ?? -1; row[isUnique] = false; // This gets set below. row[isKey] = false; // This gets set below - no idea why TDS_ROW_KEY is never set. row[baseServerName] = string.Empty; row[baseCatalogName] = column.CatalogName; row[baseColumnName] = column.ColumnName; row[baseSchemaName] = column.SchemaName; row[baseTableName] = column.TableName; row[dataType] = TypeMap.GetNetType(column); row[allowDBNull] = column.RowStatus.HasFlag(RowFormatItemStatus.TDS_ROW_NULLALLOWED); row[providerType] = aseDbType; row[isAliased] = !string.IsNullOrWhiteSpace(column.ColumnLabel); row[isExpression] = false; // It doesn't seem to matter that this isn't supported. The column gets flagged as TDS_ROW_UPDATABLE|TDS_ROW_NULLALLOWED so it doesn't cause an issue when an insert/update ignores it. row[isIdentity] = column.RowStatus.HasFlag(RowFormatItemStatus.TDS_ROW_IDENTITY); row[isAutoIncrement] = column.RowStatus.HasFlag(RowFormatItemStatus.TDS_ROW_IDENTITY); row[isRowVersion] = column.RowStatus.HasFlag(RowFormatItemStatus.TDS_ROW_VERSION); row[isHidden] = column.RowStatus.HasFlag(RowFormatItemStatus.TDS_ROW_HIDDEN); row[isLong] = LongTdsTypes.Contains(column.DataType); row[isReadOnly] = !column.RowStatus.HasFlag(RowFormatItemStatus.TDS_ROW_UPDATABLE); row[dataTypeName] = $"{aseDbType}"; table.Rows.Add(row); if (string.IsNullOrEmpty(baseTableNameValue)) { baseTableNameValue = column.TableName; baseSchemaNameValue = column.SchemaName; baseCatalogNameValue = column.CatalogName; } } // Try to load the key info //if ((_behavior & CommandBehavior.KeyInfo) == CommandBehavior.KeyInfo) { if (_command.Connection == null) { throw new InvalidOperationException("Invalid AseCommand.Connection"); } if (_command.Connection.State != ConnectionState.Open) { throw new InvalidOperationException("Invalid AseCommand.Connection.ConnectionState"); } using (var command = _command.Connection.CreateCommand()) { command.CommandText = $"{baseCatalogNameValue}..sp_oledb_getindexinfo"; command.CommandType = CommandType.StoredProcedure; var tableName = command.CreateParameter(); tableName.ParameterName = "@table_name"; tableName.AseDbType = AseDbType.VarChar; tableName.Value = baseTableNameValue; command.Parameters.Add(tableName); var tableOwner = command.CreateParameter(); tableOwner.ParameterName = "@table_owner"; tableOwner.AseDbType = AseDbType.VarChar; tableOwner.Value = baseSchemaNameValue; command.Parameters.Add(tableOwner); var tableQualifier = command.CreateParameter(); tableQualifier.ParameterName = "@table_qualifier"; tableQualifier.AseDbType = AseDbType.VarChar; tableQualifier.Value = baseCatalogNameValue; command.Parameters.Add(tableQualifier); try { using (var keyInfoDataReader = command.ExecuteReader()) { while (keyInfoDataReader.Read()) { var keyColumnName = keyInfoDataReader["COLUMN_NAME"].ToString(); var keySchemaName = keyInfoDataReader["TABLE_SCHEMA"].ToString(); var keyCatalogName = keyInfoDataReader["TABLE_CATALOG"].ToString(); foreach (DataRow row in table.Rows) { // Use the base column name in case the column is aliased. if ( string.Equals(keyColumnName, row[baseColumnName].ToString(), StringComparison.OrdinalIgnoreCase) && string.Equals(keySchemaName, row[baseSchemaName].ToString(), StringComparison.OrdinalIgnoreCase) && string.Equals(keyCatalogName, row[baseCatalogName].ToString(), StringComparison.OrdinalIgnoreCase)) { row[isKey] = (bool)keyInfoDataReader["PRIMARY_KEY"]; row[isUnique] = (bool)keyInfoDataReader["UNIQUE"]; } } } } } catch { // ignored } } } _currentSchemaTable = table; }