/// <summary>
/// Creates or Modifies the schema of the given DataTable based on the schema of
/// the reader and the arguments passed.
/// </summary>
internal static int[] BuildSchema(IDataReader reader, DataTable table,
SchemaType schemaType,
MissingSchemaAction missingSchAction,
MissingMappingAction missingMapAction,
DataTableMappingCollection dtMapping
)
{
int readerIndex = 0;
// FIXME : this fails if query has fewer columns than a table
int[] mapping = new int[table.Columns.Count]; // mapping the reader indexes to the datatable indexes
for (int i = 0; i < mapping.Length; i++)
{
mapping[i] = -1;
}
ArrayList primaryKey = new ArrayList();
ArrayList sourceColumns = new ArrayList();
bool createPrimaryKey = true;
DataTable schemaTable = reader.GetSchemaTable();
DataColumn ColumnNameCol = schemaTable.Columns["ColumnName"];
DataColumn DataTypeCol = schemaTable.Columns["DataType"];
DataColumn IsAutoIncrementCol = schemaTable.Columns["IsAutoIncrement"];
DataColumn AllowDBNullCol = schemaTable.Columns["AllowDBNull"];
DataColumn IsReadOnlyCol = schemaTable.Columns["IsReadOnly"];
DataColumn IsKeyCol = schemaTable.Columns["IsKey"];
DataColumn IsUniqueCol = schemaTable.Columns["IsUnique"];
DataColumn ColumnSizeCol = schemaTable.Columns["ColumnSize"];
foreach (DataRow schemaRow in schemaTable.Rows)
{
// generate a unique column name in the source table.
string sourceColumnName;
string realSourceColumnName;
if (ColumnNameCol == null || schemaRow.IsNull(ColumnNameCol) ||
(string)schemaRow [ColumnNameCol] == String.Empty)
{
sourceColumnName = DefaultSourceColumnName;
realSourceColumnName = DefaultSourceColumnName + "1";
}
else
{
sourceColumnName = (string)schemaRow [ColumnNameCol];
realSourceColumnName = sourceColumnName;
}
for (int i = 1; sourceColumns.Contains(realSourceColumnName); i += 1)
{
realSourceColumnName = String.Format("{0}{1}", sourceColumnName, i);
}
sourceColumns.Add(realSourceColumnName);
// generate DataSetColumnName from DataTableMapping, if any
DataTableMapping tableMapping = null;
//FIXME : The sourcetable name shud get passed as a parameter..
int index = dtMapping.IndexOfDataSetTable(table.TableName);
string srcTable = (index != -1 ? dtMapping[index].SourceTable : table.TableName);
tableMapping = DataTableMappingCollection.GetTableMappingBySchemaAction(dtMapping, ADP.IsEmpty(srcTable) ? " " : srcTable, table.TableName, missingMapAction);
if (tableMapping != null)
{
table.TableName = tableMapping.DataSetTable;
// check to see if the column mapping exists
DataColumnMapping columnMapping = DataColumnMappingCollection.GetColumnMappingBySchemaAction(tableMapping.ColumnMappings, realSourceColumnName, missingMapAction);
if (columnMapping != null)
{
Type columnType = schemaRow[DataTypeCol] as Type;
DataColumn col = columnType != null?columnMapping.GetDataColumnBySchemaAction(
table,
columnType,
missingSchAction) : null;
if (col != null)
{
// if the column is not in the table - add it.
if (table.Columns.IndexOf(col) == -1)
{
if (missingSchAction == MissingSchemaAction.Add ||
missingSchAction == MissingSchemaAction.AddWithKey)
{
table.Columns.Add(col);
}
int[] tmp = new int[mapping.Length + 1];
Array.Copy(mapping, 0, tmp, 0, col.Ordinal);
Array.Copy(mapping, col.Ordinal, tmp, col.Ordinal + 1, mapping.Length - col.Ordinal);
mapping = tmp;
}
if (missingSchAction == MissingSchemaAction.AddWithKey)
{
object value = (AllowDBNullCol != null) ? schemaRow[AllowDBNullCol] : null;
bool allowDBNull = value is bool?(bool)value : true;
value = (IsKeyCol != null) ? schemaRow[IsKeyCol] : null;
bool isKey = value is bool?(bool)value : false;
value = (IsAutoIncrementCol != null) ? schemaRow[IsAutoIncrementCol] : null;
bool isAutoIncrement = value is bool?(bool)value : false;
value = (IsReadOnlyCol != null) ? schemaRow[IsReadOnlyCol] : null;
bool isReadOnly = value is bool?(bool)value : false;
value = (IsUniqueCol != null) ? schemaRow[IsUniqueCol] : null;
bool isUnique = value is bool?(bool)value : false;
col.AllowDBNull = allowDBNull;
// fill woth key info
if (isAutoIncrement && DataColumn.CanAutoIncrement(columnType))
{
col.AutoIncrement = true;
if (!allowDBNull)
{
col.AllowDBNull = false;
}
}
if (columnType == DbTypes.TypeOfString)
{
col.MaxLength = (ColumnSizeCol != null) ? (int)schemaRow[ColumnSizeCol] : 0;
}
if (isReadOnly)
{
col.ReadOnly = true;
}
if (!allowDBNull && (!isReadOnly || isKey))
{
col.AllowDBNull = false;
}
if (isUnique && !isKey && !columnType.IsArray)
{
col.Unique = true;
if (!allowDBNull)
{
col.AllowDBNull = false;
}
}
// This might not be set by all DataProviders
bool isHidden = false;
if (schemaTable.Columns.Contains("IsHidden"))
{
value = schemaRow["IsHidden"];
isHidden = ((value is bool) ? (bool)value : false);
}
if (isKey && !isHidden)
{
primaryKey.Add(col);
if (allowDBNull)
{
createPrimaryKey = false;
}
}
}
// add the ordinal of the column as a key and the index of the column in the datareader as a value.
mapping[col.Ordinal] = readerIndex++;
}
}
}
}
if (primaryKey.Count > 0)
{
DataColumn[] colKey = (DataColumn[])(primaryKey.ToArray(typeof(DataColumn)));
if (createPrimaryKey)
{
table.PrimaryKey = colKey;
}
else
{
UniqueConstraint uConstraint = new UniqueConstraint(colKey);
for (int i = 0; i < table.Constraints.Count; i++)
{
if (table.Constraints[i].Equals(uConstraint))
{
uConstraint = null;
break;
}
}
if (uConstraint != null)
{
table.Constraints.Add(uConstraint);
}
}
}
return(mapping);
}