private MyCatSchemaCollection GetTable(string sql) { MyCatSchemaCollection c = new MyCatSchemaCollection(); MyCatCommand cmd = new MyCatCommand(sql, connection); MyCatDataReader reader = cmd.ExecuteReader(); // add columns for (int i = 0; i < reader.FieldCount; i++) { c.AddColumn(reader.GetName(i), reader.GetFieldType(i)); } using (reader) { while (reader.Read()) { MyCatSchemaRow row = c.AddRow(); for (int i = 0; i < reader.FieldCount; i++) { row[i] = reader.GetValue(i); } } } return(c); }
public virtual List <MyCatError> ReportWarnings(MyCatConnection connection) { List <MyCatError> warnings = new List <MyCatError>(); MyCatCommand cmd = new MyCatCommand("SHOW WARNINGS", connection); cmd.InternallyCreated = true; using (MyCatDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { warnings.Add(new MyCatError(reader.GetString(0), reader.GetInt32(1), reader.GetString(2))); } } MyCatInfoMessageEventArgs args = new MyCatInfoMessageEventArgs(); args.errors = warnings.ToArray(); if (connection != null) { connection.OnInfoMessage(args); } return(warnings); }
/// <summary> /// Loads the properties from the connected server into a hashtable /// </summary> /// <param name="connection"></param> /// <returns></returns> private Dictionary <string, string> LoadServerProperties(MyCatConnection connection) { // load server properties Dictionary <string, string> hash = new Dictionary <string, string>(); MyCatCommand cmd = new MyCatCommand("SHOW VARIABLES", connection); try { using (MyCatDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { string key = reader.GetString(0); string value = reader.GetString(1); hash[key] = value; } } // Get time zone offset as numerical value timeZoneOffset = TimeZoneInfo.Local.BaseUtcOffset.Hours; return(hash); } catch (Exception ex) { MyCatTrace.LogError(ThreadID, ex.Message); throw; } }
/// <summary> /// Executes a single SQL command and returns the resultset in a <see cref="DataSet"/>. /// The state of the <see cref="MyCatConnection"/> object remains unchanged after execution /// of this method. /// </summary> /// <param name="connection"><see cref="MyCatConnection"/> object to use</param> /// <param name="commandText">Command to execute</param> /// <param name="commandParameters">Parameters to use for the command</param> /// <returns><see cref="DataSet"/> containing the resultset</returns> public static DataSet ExecuteDataset(MyCatConnection connection, string commandText, params MyCatParameter[] commandParameters) { //create a command and prepare it for execution MyCatCommand cmd = new MyCatCommand(); cmd.Connection = connection; cmd.CommandText = commandText; cmd.CommandType = CommandType.Text; if (commandParameters != null) { foreach (MyCatParameter p in commandParameters) { cmd.Parameters.Add(p); } } //create the DataAdapter & DataSet MyCatDataAdapter da = new MyCatDataAdapter(cmd); DataSet ds = new DataSet(); //fill the DataSet using default values for DataTable names, etc. da.Fill(ds); // detach the MyCatParameters from the command object, so they can be used again. cmd.Parameters.Clear(); //return the dataset return(ds); }
/// <summary> /// Execute the load operation /// </summary> /// <returns>The number of rows inserted.</returns> public int Load() { bool openedConnection = false; if (Connection == null) { throw new InvalidOperationException(Resources.ConnectionNotSet); } // next we open up the connetion if it is not already open if (connection.State != ConnectionState.Open) { openedConnection = true; connection.Open(); } try { string sql = BuildSqlCommand(); MyCatCommand cmd = new MyCatCommand(sql, Connection); cmd.CommandTimeout = Timeout; return(cmd.ExecuteNonQuery()); } finally { if (openedConnection) { connection.Close(); } } }
/// <summary> /// Open connection if it was closed. /// Necessary to workaround "connection must be open and valid" error /// with batched updates. /// </summary> /// <param name="state">Row state</param> /// <param name="openedConnections"> list of opened connections /// If connection is opened by this function, the list is updated /// </param> /// <returns>true if connection was opened</returns> private void OpenConnectionIfClosed(DataRowState state, List <MyCatConnection> openedConnections) { MyCatCommand cmd = null; switch (state) { case DataRowState.Added: cmd = InsertCommand; break; case DataRowState.Deleted: cmd = DeleteCommand; break; case DataRowState.Modified: cmd = UpdateCommand; break; default: return; } if (cmd != null && cmd.Connection != null && cmd.Connection.connectionState == ConnectionState.Closed) { cmd.Connection.Open(); openedConnections.Add(cmd.Connection); } }
internal MyCatParameterCollection(MyCatCommand cmd) { indexHashCS = new Dictionary <string, int>(); indexHashCI = new Dictionary <string, int>(StringComparer.CurrentCultureIgnoreCase); containsUnnamedParameters = false; Clear(); }
/// <include file='docs/MyCatConnection.xml' path='docs/CreateCommand/*'/> public new MyCatCommand CreateCommand() { // Return a new instance of a command object. MyCatCommand c = new MyCatCommand(); c.Connection = this; return(c); }
internal void AddToBatch(MyCatCommand command) { if (batch == null) { batch = new List <MyCatCommand>(); } batch.Add(command); }
/// <summary> /// Retrieves parameter information from the stored procedure specified /// in the MyCatCommand and populates the Parameters collection of the /// specified MyCatCommand object. /// This method is not currently supported since stored procedures are /// not available in MyCat. /// </summary> /// <param name="command">The MyCatCommand referencing the stored /// procedure from which the parameter information is to be derived. /// The derived parameters are added to the Parameters collection of the /// MyCatCommand.</param> /// <exception cref="InvalidOperationException">The command text is not /// a valid stored procedure name.</exception> public static void DeriveParameters(MyCatCommand command) { if (command.CommandType != CommandType.StoredProcedure) { throw new InvalidOperationException(Resources.CanNotDeriveParametersForTextCommands); } // retrieve the proc definition from the cache. string spName = command.CommandText; if (spName.IndexOf(".") == -1) { spName = command.Connection.Database + "." + spName; } try { ProcedureCacheEntry entry = command.Connection.ProcedureCache.GetProcedure(command.Connection, spName, null); command.Parameters.Clear(); foreach (MyCatSchemaRow row in entry.parameters.Rows) { MyCatParameter p = new MyCatParameter(); p.ParameterName = String.Format("@{0}", row["PARAMETER_NAME"]); if (row["ORDINAL_POSITION"].Equals(0) && p.ParameterName == "@") { p.ParameterName = "@RETURN_VALUE"; } p.Direction = GetDirection(row); bool unsigned = StoredProcedure.GetFlags(row["DTD_IDENTIFIER"].ToString()).IndexOf("UNSIGNED") != -1; bool real_as_float = entry.procedure.Rows[0]["SQL_MODE"].ToString().IndexOf("REAL_AS_FLOAT") != -1; p.MyCatDbType = MetaData.NameToType(row["DATA_TYPE"].ToString(), unsigned, real_as_float, command.Connection); if (row["CHARACTER_MAXIMUM_LENGTH"] != null) { p.Size = (int)row["CHARACTER_MAXIMUM_LENGTH"]; } #if NET452 || DNX452 || NETSTANDARD1_3 if (row["NUMERIC_PRECISION"] != null) { p.Precision = Convert.ToByte(row["NUMERIC_PRECISION"]); } if (row["NUMERIC_SCALE"] != null) { p.Scale = Convert.ToByte(row["NUMERIC_SCALE"]); } #endif if (p.MyCatDbType == MyCatDbType.Set || p.MyCatDbType == MyCatDbType.Enum) { p.PossibleValues = GetPossibleValues(row); } command.Parameters.Add(p); } } catch (InvalidOperationException ioe) { throw new MyCatException(Resources.UnableToDeriveParameters, ioe); } }
protected virtual void BindParameters() { MyCatParameterCollection parameters = command.Parameters; int index = 0; while (true) { InternalBindParameters(ResolvedCommandText, parameters, null); // if we are not batching, then we are done. This is only really relevant the // first time through if (command.Batch == null) { return; } while (index < command.Batch.Count) { MyCatCommand batchedCmd = command.Batch[index++]; MyCatPacket packet = (MyCatPacket)buffers[buffers.Count - 1]; // now we make a guess if this statement will fit in our current stream long estimatedCmdSize = batchedCmd.EstimatedSize(); if (((packet.Length - 4) + estimatedCmdSize) > Connection.driver.MaxPacketSize) { // it won't, so we setup to start a new run from here parameters = batchedCmd.Parameters; break; } // looks like we might have room for it so we remember the current end of the stream buffers.RemoveAt(buffers.Count - 1); //long originalLength = packet.Length - 4; // and attempt to stream the next command string text = ResolvedCommandText; if (text.StartsWith("(", StringComparison.Ordinal)) { packet.WriteStringNoNull(", "); } else { packet.WriteStringNoNull("; "); } InternalBindParameters(text, batchedCmd.Parameters, packet); if ((packet.Length - 4) > Connection.driver.MaxPacketSize) { //TODO //stream.InternalBuffer.SetLength(originalLength); parameters = batchedCmd.Parameters; break; } } if (index == command.Batch.Count) { return; } } }
internal string CurrentDatabase() { if (Database != null && Database.Length > 0) { return(Database); } MyCatCommand cmd = new MyCatCommand("SELECT database()", this); return(cmd.ExecuteScalar().ToString()); }
/// <summary> /// Reset SQL_SELECT_LIMIT that could have been modified by CommandBehavior. /// </summary> internal void ResetSqlSelectLimit() { // if we are supposed to reset the sql select limit, do that here if (resetSqlSelect) { resetSqlSelect = false; MyCatCommand command = new MyCatCommand("SET SQL_SELECT_LIMIT=DEFAULT", connection); command.internallyCreated = true; command.ExecuteNonQuery(); } }
protected override void ClearBatch() { if (commandBatch.Count > 0) { MyCatCommand cmd = (MyCatCommand)commandBatch[0]; if (cmd.Batch != null) { cmd.Batch.Clear(); } } commandBatch.Clear(); }
/// <include file='docs/MyCatConnection.xml' path='docs/BeginTransaction1/*'/> public new MyCatTransaction BeginTransaction(IsolationLevel iso) { //TODO: check note in help if (State != ConnectionState.Open) { Throw(new InvalidOperationException(Resources.ConnectionNotOpen)); } // First check to see if we are in a current transaction if (driver.HasStatus(ServerStatusFlags.InTransaction)) { Throw(new InvalidOperationException(Resources.NoNestedTransactions)); } MyCatTransaction t = new MyCatTransaction(this, iso); MyCatCommand cmd = new MyCatCommand("", this); cmd.CommandText = "SET SESSION TRANSACTION ISOLATION LEVEL "; switch (iso) { case IsolationLevel.ReadCommitted: cmd.CommandText += "READ COMMITTED"; break; case IsolationLevel.ReadUncommitted: cmd.CommandText += "READ UNCOMMITTED"; break; case IsolationLevel.RepeatableRead: cmd.CommandText += "REPEATABLE READ"; break; case IsolationLevel.Serializable: cmd.CommandText += "SERIALIZABLE"; break; case IsolationLevel.Chaos: Throw(new NotSupportedException(Resources.ChaosNotSupported)); break; case IsolationLevel.Snapshot: Throw(new NotSupportedException(Resources.SnapshotNotSupported)); break; } cmd.ExecuteNonQuery(); cmd.CommandText = "BEGIN"; cmd.ExecuteNonQuery(); return(t); }
private void FindTables(MyCatSchemaCollection schema, string[] restrictions) { StringBuilder sql = new StringBuilder(); StringBuilder where = new StringBuilder(); sql.AppendFormat(CultureInfo.InvariantCulture, "SHOW TABLE STATUS FROM `{0}`", restrictions[1]); if (restrictions != null && restrictions.Length >= 3 && restrictions[2] != null) { where.AppendFormat(CultureInfo.InvariantCulture, " LIKE '{0}'", restrictions[2]); } sql.Append(where.ToString()); string table_type = restrictions[1].ToLower() == "information_schema" ? "SYSTEM VIEW" : "BASE TABLE"; MyCatCommand cmd = new MyCatCommand(sql.ToString(), connection); using (MyCatDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { MyCatSchemaRow row = schema.AddRow(); row["TABLE_CATALOG"] = null; row["TABLE_SCHEMA"] = restrictions[1]; row["TABLE_NAME"] = reader.GetString(0); row["TABLE_TYPE"] = table_type; row["ENGINE"] = GetString(reader, 1); row["VERSION"] = reader.GetValue(2); row["ROW_FORMAT"] = GetString(reader, 3); row["TABLE_ROWS"] = reader.GetValue(4); row["AVG_ROW_LENGTH"] = reader.GetValue(5); row["DATA_LENGTH"] = reader.GetValue(6); row["MAX_DATA_LENGTH"] = reader.GetValue(7); row["INDEX_LENGTH"] = reader.GetValue(8); row["DATA_FREE"] = reader.GetValue(9); row["AUTO_INCREMENT"] = reader.GetValue(10); row["CREATE_TIME"] = reader.GetValue(11); row["UPDATE_TIME"] = reader.GetValue(12); row["CHECK_TIME"] = reader.GetValue(13); row["TABLE_COLLATION"] = GetString(reader, 14); row["CHECKSUM"] = reader.GetValue(15); row["CREATE_OPTIONS"] = GetString(reader, 16); row["TABLE_COMMENT"] = GetString(reader, 17); } } }
private string GetProcedureParameterLine(MyCatSchemaRow isRow) { string sql = "SHOW CREATE {0} `{1}`.`{2}`"; sql = String.Format(sql, isRow["ROUTINE_TYPE"], isRow["ROUTINE_SCHEMA"], isRow["ROUTINE_NAME"]); MyCatCommand cmd = new MyCatCommand(sql, connection); using (MyCatDataReader reader = cmd.ExecuteReader()) { reader.Read(); // if we are not the owner of this proc or have permissions // then we will get null for the body if (reader.IsDBNull(2)) { return(null); } string sql_mode = reader.GetString(1); string body = reader.GetString(2); MyCatTokenizer tokenizer = new MyCatTokenizer(body); tokenizer.AnsiQuotes = sql_mode.IndexOf("ANSI_QUOTES") != -1; tokenizer.BackslashEscapes = sql_mode.IndexOf("NO_BACKSLASH_ESCAPES") == -1; string token = tokenizer.NextToken(); while (token != "(") { token = tokenizer.NextToken(); } int start = tokenizer.StartIndex + 1; token = tokenizer.NextToken(); while (token != ")" || tokenizer.Quoted) { token = tokenizer.NextToken(); // if we see another ( and we are not quoted then we // are in a size element and we need to look for the closing paren if (token == "(" && !tokenizer.Quoted) { while (token != ")" || tokenizer.Quoted) { token = tokenizer.NextToken(); } token = tokenizer.NextToken(); } } return(body.Substring(start, tokenizer.StartIndex - start)); } }
internal void GetParametersFromShowCreate(MyCatSchemaCollection parametersTable, string[] restrictions, MyCatSchemaCollection routines) { // this allows us to pass in a pre-populated routines table // and avoid the querying for them again. // we use this when calling a procedure or function if (routines == null) { routines = GetSchema("procedures", restrictions); } MyCatCommand cmd = connection.CreateCommand(); foreach (MyCatSchemaRow routine in routines.Rows) { string showCreateSql = String.Format("SHOW CREATE {0} `{1}`.`{2}`", routine["ROUTINE_TYPE"], routine["ROUTINE_SCHEMA"], routine["ROUTINE_NAME"]); cmd.CommandText = showCreateSql; try { string nameToRestrict = null; if (restrictions != null && restrictions.Length == 5 && restrictions[4] != null) { nameToRestrict = restrictions[4]; } using (MyCatDataReader reader = cmd.ExecuteReader()) { reader.Read(); string body = reader.GetString(2); #if NETSTANDARD1_3 reader.Dispose(); #else reader.Close(); #endif ParseProcedureBody(parametersTable, body, routine, nameToRestrict); } } #if NETSTANDARD1_3 catch (MyCatNullValueException snex) #else catch (System.Data.SqlTypes.SqlNullValueException snex) #endif { throw new InvalidOperationException( String.Format(Resources.UnableToRetrieveParameters, routine["ROUTINE_NAME"]), snex); } } }
/// <include file='docs/MyCatTransaction.xml' path='docs/Rollback/*'/> public override void Rollback() { if (conn == null || (conn.State != ConnectionState.Open && !conn.SoftClosed)) { throw new InvalidOperationException("Connection must be valid and open to rollback transaction"); } if (!open) { throw new InvalidOperationException("Transaction has already been rolled back or is not pending"); } MyCatCommand cmd = new MyCatCommand("ROLLBACK", conn); cmd.ExecuteNonQuery(); open = false; }
/// <include file='docs/MyCatTransaction.xml' path='docs/Commit/*'/> public override void Commit() { if (conn == null || (conn.State != ConnectionState.Open && !conn.SoftClosed)) { throw new InvalidOperationException("Connection must be valid and open to commit transaction"); } if (!open) { throw new InvalidOperationException("Transaction has already been committed or is not pending"); } MyCatCommand cmd = new MyCatCommand("COMMIT", conn); cmd.ExecuteNonQuery(); open = false; }
internal static void InitCollections(MyCatConnection connection) { defaultCollations = new Dictionary <string, string>(); maxLengths = new Dictionary <string, int>(); MyCatCommand cmd = new MyCatCommand("SHOW CHARSET", connection); using (MyCatDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { defaultCollations.Add(reader.GetString(0), reader.GetString(2)); maxLengths.Add(reader.GetString(0), Convert.ToInt32(reader.GetValue(3))); } } }
/// <summary> /// Creates a clone of this MyCatCommand object. CommandText, Connection, and Transaction properties /// are included as well as the entire parameter list. /// </summary> /// <returns>The cloned MyCatCommand object</returns> public MyCatCommand Clone() { MyCatCommand clone = new MyCatCommand(cmdText, connection, curTransaction); clone.CommandType = CommandType; clone.commandTimeout = commandTimeout; clone.useDefaultTimeout = useDefaultTimeout; clone.batchableCommandText = batchableCommandText; clone.EnableCaching = EnableCaching; clone.CacheAge = CacheAge; PartialClone(clone); foreach (MyCatParameter p in parameters) { clone.Parameters.Add(p.Clone()); } return(clone); }
/* * Because the user should not be able to directly create a * DataReader object, the constructors are * marked as internal. */ internal MyCatDataReader(MyCatCommand cmd, PreparableStatement statement, CommandBehavior behavior) { this.command = cmd; connection = (MyCatConnection)command.Connection; commandBehavior = behavior; driver = connection.driver; affectedRows = -1; this.statement = statement; #if !RT if (cmd.CommandType == CommandType.StoredProcedure && cmd.UpdatedRowSource == UpdateRowSource.FirstReturnedRecord ) { disableZeroAffectedRows = true; } #endif }
protected override int AddToBatch(IDbCommand command) { // the first time each command is asked to be batched, we ask // that command to prepare its batchable command text. We only want // to do this one time for each command MyCatCommand commandToBatch = (MyCatCommand)command; if (commandToBatch.BatchableCommandText == null) { commandToBatch.GetCommandTextForBatching(); } IDbCommand cloneCommand = (IDbCommand)((ICloneable)command).Clone(); commandBatch.Add(cloneCommand); return(commandBatch.Count - 1); }
public virtual MyCatSchemaCollection GetUDF(string[] restrictions) { string sql = "SELECT name,ret,dl FROM mysql.func"; if (restrictions != null) { if (restrictions.Length >= 1 && !String.IsNullOrEmpty(restrictions[0])) { sql += String.Format(" WHERE name LIKE '{0}'", restrictions[0]); } } MyCatSchemaCollection dt = new MyCatSchemaCollection("User-defined Functions"); dt.AddColumn("NAME", typeof(string)); dt.AddColumn("RETURN_TYPE", typeof(int)); dt.AddColumn("LIBRARY_NAME", typeof(string)); MyCatCommand cmd = new MyCatCommand(sql, connection); try { using (MyCatDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { MyCatSchemaRow row = dt.AddRow(); row[0] = reader.GetString(0); row[1] = reader.GetInt32(1); row[2] = reader.GetString(2); } } } catch (MyCatException ex) { if (ex.Number != (int)MyCatErrorCode.TableAccessDenied) { throw; } throw new MyCatException(Resources.UnableToEnumerateUDF, ex); } return(dt); }
public void CancelQuery(int timeout) { MyCatConnectionStringBuilder cb = new MyCatConnectionStringBuilder( Settings.ConnectionString); cb.Pooling = false; cb.AutoEnlist = false; cb.ConnectionTimeout = (uint)timeout; using (MyCatConnection c = new MyCatConnection(cb.ConnectionString)) { c.isKillQueryConnection = true; c.Open(); string commandText = "KILL QUERY " + ServerThread; MyCatCommand cmd = new MyCatCommand(commandText, c); cmd.CommandTimeout = timeout; cmd.ExecuteNonQuery(); } }
public override void Close(MyCatDataReader reader) { base.Close(reader); if (String.IsNullOrEmpty(outSelect)) { return; } if ((reader.CommandBehavior & CommandBehavior.SchemaOnly) != 0) { return; } MyCatCommand cmd = new MyCatCommand(outSelect, command.Connection); using (MyCatDataReader rdr = cmd.ExecuteReader(reader.CommandBehavior)) { ProcessOutputParameters(rdr); } }
private void ClearKillFlag() { // This query will silently crash because of the Kill call that happened before. string dummyStatement = "SELECT * FROM bogus_table LIMIT 0"; /* dummy query used to clear kill flag */ MyCatCommand dummyCommand = new MyCatCommand(dummyStatement, connection); dummyCommand.InternallyCreated = true; try { dummyCommand.ExecuteReader(); // ExecuteReader catches the exception and returns null, which is expected. } catch (MyCatException ex) { if (ex.Number != (int)MyCatErrorCode.NoSuchTable) { throw; } } }
/// <summary> /// GetForeignKeysOnTable retrieves the foreign keys on the given table. /// Since MySQL supports foreign keys on versions prior to 5.0, we can't use /// information schema. MySQL also does not include any type of SHOW command /// for foreign keys so we have to resort to use SHOW CREATE TABLE and parsing /// the output. /// </summary> /// <param name="fkTable">The table to store the key info in.</param> /// <param name="tableToParse">The table to get the foeign key info for.</param> /// <param name="filterName">Only get foreign keys that match this name.</param> /// <param name="includeColumns">Should column information be included in the table.</param> private void GetForeignKeysOnTable(MyCatSchemaCollection fkTable, MyCatSchemaRow tableToParse, string filterName, bool includeColumns) { string sqlMode = GetSqlMode(); if (filterName != null) { filterName = StringUtility.ToLowerInvariant(filterName); } string sql = string.Format("SHOW CREATE TABLE `{0}`.`{1}`", tableToParse["TABLE_SCHEMA"], tableToParse["TABLE_NAME"]); string lowerBody = null, body = null; MyCatCommand cmd = new MyCatCommand(sql, connection); using (MyCatDataReader reader = cmd.ExecuteReader()) { reader.Read(); body = reader.GetString(1); lowerBody = StringUtility.ToLowerInvariant(body); } MyCatTokenizer tokenizer = new MyCatTokenizer(lowerBody); tokenizer.AnsiQuotes = sqlMode.IndexOf("ANSI_QUOTES") != -1; tokenizer.BackslashEscapes = sqlMode.IndexOf("NO_BACKSLASH_ESCAPES") != -1; while (true) { string token = tokenizer.NextToken(); // look for a starting contraint while (token != null && (token != "constraint" || tokenizer.Quoted)) { token = tokenizer.NextToken(); } if (token == null) { break; } ParseConstraint(fkTable, tableToParse, tokenizer, includeColumns); } }
private void LoadTableColumns(MyCatSchemaCollection schemaCollection, string schema, string tableName, string columnRestriction) { string sql = String.Format("SHOW FULL COLUMNS FROM `{0}`.`{1}`", schema, tableName); MyCatCommand cmd = new MyCatCommand(sql, connection); int pos = 1; using (MyCatDataReader reader = cmd.ExecuteReader()) { while (reader.Read()) { string colName = reader.GetString(0); if (columnRestriction != null && colName != columnRestriction) { continue; } MyCatSchemaRow row = schemaCollection.AddRow(); row["TABLE_CATALOG"] = DBNull.Value; row["TABLE_SCHEMA"] = schema; row["TABLE_NAME"] = tableName; row["COLUMN_NAME"] = colName; row["ORDINAL_POSITION"] = pos++; row["COLUMN_DEFAULT"] = reader.GetValue(5); row["IS_NULLABLE"] = reader.GetString(3); row["DATA_TYPE"] = reader.GetString(1); row["CHARACTER_MAXIMUM_LENGTH"] = DBNull.Value; row["CHARACTER_OCTET_LENGTH"] = DBNull.Value; row["NUMERIC_PRECISION"] = DBNull.Value; row["NUMERIC_SCALE"] = DBNull.Value; row["CHARACTER_SET_NAME"] = reader.GetValue(2); row["COLLATION_NAME"] = row["CHARACTER_SET_NAME"]; row["COLUMN_TYPE"] = reader.GetString(1); row["COLUMN_KEY"] = reader.GetString(4); row["EXTRA"] = reader.GetString(6); row["PRIVILEGES"] = reader.GetString(7); row["COLUMN_COMMENT"] = reader.GetString(8); ParseColumnRow(row); } } }