2 // Mono.Data.MySql.MySqlDataReader.cs
5 // Rodrigo Moya (rodrigo@ximian.com)
6 // Daniel Morgan (danmorg@sc.rr.com)
8 // (C) Ximian, Inc 2002
9 // (C) Daniel Morgan 2002
12 // *** uncomment #define to get debug messages, comment for production ***
13 //#define DEBUG_MySqlDataReader
16 using System.Collections;
17 using System.ComponentModel;
19 using System.Runtime.InteropServices;
21 namespace Mono.Data.MySql {
23 /// Provides a means of reading one or more forward-only streams
24 /// of result sets obtained by executing a command
25 /// at a SQL database.
27 //public sealed class MySqlDataReader : MarshalByRefObject,
28 // IEnumerable, IDataReader, IDisposable, IDataRecord
29 public sealed class MySqlDataReader : IEnumerable,
30 IDataReader, IDataRecord {
34 private MySqlCommand cmd;
35 private DataTable table = null;
39 int[] fieldType; // MySQL data type
40 DbType[] fieldDbType; // DbType translated from MySQL type
42 uint[] fieldMaxLength;
45 private object[] dataValue;
47 private bool open = false;
49 private int recordsAffected = -1;
50 private int currentQuery = 0;
52 private int currentRow = -1;
55 private int numFields;
58 private CommandBehavior cmdBehavior;
64 internal MySqlDataReader (MySqlCommand sqlCmd, CommandBehavior behavior) {
68 // cmd.OpenReader(this);
69 cmdBehavior = behavior;
74 #region Public Methods
80 // free MySqlDataReader resources in SqlCommand
81 // and allow SqlConnection to be used again
84 // TODO: get parameters from result
86 // clear unmanaged MySQL result set
87 if(res != IntPtr.Zero) {
88 MySql.FreeResult(res);
94 public DataTable GetSchemaTable() {
96 DataTable dataTableSchema = null;
97 // Only Results from SQL SELECT Queries
98 // get a DataTable for schema of the result
99 // otherwise, DataTable is null reference
102 dataTableSchema = new DataTable ();
104 dataTableSchema.Columns.Add ("ColumnName", typeof (string));
105 dataTableSchema.Columns.Add ("ColumnOrdinal", typeof (int));
106 dataTableSchema.Columns.Add ("ColumnSize", typeof (int));
107 dataTableSchema.Columns.Add ("NumericPrecision", typeof (int));
108 dataTableSchema.Columns.Add ("NumericScale", typeof (int));
109 dataTableSchema.Columns.Add ("IsUnique", typeof (bool));
110 dataTableSchema.Columns.Add ("IsKey", typeof (bool));
111 DataColumn dc = dataTableSchema.Columns["IsKey"];
112 dc.AllowDBNull = true; // IsKey can have a DBNull
113 dataTableSchema.Columns.Add ("BaseCatalogName", typeof (string));
114 dataTableSchema.Columns.Add ("BaseColumnName", typeof (string));
115 dataTableSchema.Columns.Add ("BaseSchemaName", typeof (string));
116 dataTableSchema.Columns.Add ("BaseTableName", typeof (string));
117 dataTableSchema.Columns.Add ("DataType", typeof(Type));
118 dataTableSchema.Columns.Add ("AllowDBNull", typeof (bool));
119 dataTableSchema.Columns.Add ("ProviderType", typeof (int));
120 dataTableSchema.Columns.Add ("IsAliased", typeof (bool));
121 dataTableSchema.Columns.Add ("IsExpression", typeof (bool));
122 dataTableSchema.Columns.Add ("IsIdentity", typeof (bool));
123 dataTableSchema.Columns.Add ("IsAutoIncrement", typeof (bool));
124 dataTableSchema.Columns.Add ("IsRowVersion", typeof (bool));
125 dataTableSchema.Columns.Add ("IsHidden", typeof (bool));
126 dataTableSchema.Columns.Add ("IsLong", typeof (bool));
127 dataTableSchema.Columns.Add ("IsReadOnly", typeof (bool));
133 for (int i = 0; i < numFields; i += 1 ) {
135 schemaRow = dataTableSchema.NewRow ();
137 schemaRow["ColumnName"] = fieldName[i];
138 schemaRow["ColumnOrdinal"] = i + 1;
140 schemaRow["ColumnSize"] = (int) fieldMaxLength[i];
141 schemaRow["NumericPrecision"] = 0;
142 schemaRow["NumericScale"] = 0;
143 // TODO: need to get KeyInfo
144 if((cmdBehavior & CommandBehavior.KeyInfo) == CommandBehavior.KeyInfo) {
145 // bool IsUnique, IsKey;
146 // GetKeyInfo(field[i].Name, out IsUnique, out IsKey);
149 schemaRow["IsUnique"] = false;
150 schemaRow["IsKey"] = DBNull.Value;
152 schemaRow["BaseCatalogName"] = "";
154 schemaRow["BaseColumnName"] = fieldName[i];
155 schemaRow["BaseSchemaName"] = "";
156 schemaRow["BaseTableName"] = "";
158 // do translation from MySQL type
159 // to .NET Type and then convert the result
161 MySqlEnumFieldTypes fieldEnum;
163 fieldEnum = (MySqlEnumFieldTypes) fieldType[i];
164 dbType = MySqlHelper.MySqlTypeToDbType(fieldEnum);
165 typ = MySqlHelper.DbTypeToSystemType (dbType);
166 string st = typ.ToString();
\r
167 schemaRow["DataType"] = typ;
\r
169 schemaRow["AllowDBNull"] = false;
171 schemaRow["ProviderType"] = (int) fieldType[i];
172 schemaRow["IsAliased"] = false;
173 schemaRow["IsExpression"] = false;
174 schemaRow["IsIdentity"] = false;
175 schemaRow["IsAutoIncrement"] = false;
176 schemaRow["IsRowVersion"] = false;
177 schemaRow["IsHidden"] = false;
178 schemaRow["IsLong"] = false;
179 schemaRow["IsReadOnly"] = false;
181 schemaRow.AcceptChanges();
183 dataTableSchema.Rows.Add (schemaRow);
186 #if DEBUG_MySqlCommand
187 Console.WriteLine("********** DEBUG Table Schema BEGIN ************");
188 foreach (DataRow myRow in dataTableSchema.Rows) {
\r
189 foreach (DataColumn myCol in dataTableSchema.Columns)
\r
190 Console.WriteLine(myCol.ColumnName + " = " + myRow[myCol]);
\r
191 Console.WriteLine();
\r
193 Console.WriteLine("********** DEBUG Table Schema END ************");
194 #endif // DEBUG_MySqlCommand
198 return dataTableSchema;
202 public bool NextResult() {
204 bool resultReturned = false;
208 recordsAffected = -1;
210 // store the result set
211 res = MySql.StoreResult(cmd.Connection.NativeMySqlInitStruct);
213 if(res.Equals(IntPtr.Zero)) {
214 // no result set returned
215 recordsAffected = (int) MySql.AffectedRows(cmd.Connection.NativeMySqlInitStruct);
222 fieldMaxLength = null;
229 // get meta data about result set
230 numRows = MySql.NumRows(res);
231 numFields = MySql.NumFields(res);
232 // get meta data about each field
233 fieldName = new string[numFields];
234 fieldType = new int[numFields];
235 fieldLength = new uint[numFields];
236 fieldMaxLength = new uint[numFields];
237 fieldFlags = new uint[numFields];
239 fieldDbType = new DbType[numFields];
241 // marshal each meta data field
242 // into field* arrays
243 for (int i = 0; i < numFields; i++) {
245 MySqlMarshalledField marshField = null;
246 marshField = (MySqlMarshalledField) Marshal.PtrToStructure(MySql.FetchField(res),
247 typeof(MySqlMarshalledField));
249 // copy memebers in marshalField to fields[i]
250 fieldName[i] = marshField.Name;
251 fieldType[i] = marshField.FieldType;
252 fieldLength[i] = marshField.Length;
253 fieldMaxLength[i] = marshField.MaxLength;
254 fieldFlags[i] = marshField.Flags;
256 fieldDbType[i] = MySqlHelper.MySqlTypeToDbType((MySqlEnumFieldTypes)fieldType[i]);
259 // TODO: for CommandBehavior.SingleRow
\r
260 // use IRow, otherwise, IRowset
\r
262 if((cmdBehavior & CommandBehavior.SingleRow) == CommandBehavior.SingleRow)
\r
265 // TODO: for CommandBehavior.SchemaInfo
266 if((cmdBehavior & CommandBehavior.SchemaOnly) == CommandBehavior.SchemaOnly)
269 // TODO: for CommandBehavior.SingleResult
270 if((cmdBehavior & CommandBehavior.SingleResult) == CommandBehavior.SingleResult)
274 // TODO: for CommandBehavior.SequentialAccess - used for reading Large OBjects
275 //if((cmdBehavior & CommandBehavior.SequentialAccess) == CommandBehavior.SequentialAccess) {
279 return resultReturned;
285 if(currentRow < numRows - 1) {
291 dataValue = new object[numFields];
294 row = MySql.FetchRow(res);
295 if(row.Equals(IntPtr.Zero)) {
296 MySql.FreeResult(res);
301 for (int i = 0; i < numFields; i++) {
302 // marshal column data value
303 string objValue = cmd.GetColumnData(row, i);
305 // tranlate from native MySql c type
306 // to a .NET type here
307 dataValue[i] = MySqlHelper.ConvertDbTypeToSystem (fieldDbType[i], objValue);
316 public byte GetByte(int i) {
317 throw new NotImplementedException ();
321 public long GetBytes(int i, long fieldOffset,
322 byte[] buffer, int bufferOffset,
325 throw new NotImplementedException ();
329 public char GetChar(int i) {
330 throw new NotImplementedException ();
334 public long GetChars(int i, long fieldOffset,
335 char[] buffer, int bufferOffset,
338 throw new NotImplementedException ();
342 public IDataReader GetData(int i) {
343 throw new NotImplementedException ();
347 public string GetDataTypeName(int i) {
348 return MySqlHelper.GetMySqlTypeName((MySqlEnumFieldTypes)fieldType[i]);
352 public DateTime GetDateTime(int i) {
353 return (DateTime) dataValue[i];
357 public decimal GetDecimal(int i) {
358 return (decimal) dataValue[i];
362 public double GetDouble(int i) {
363 return (double) dataValue[i];
367 public Type GetFieldType(int i) {
368 MySqlEnumFieldTypes fieldEnum;
372 fieldEnum = (MySqlEnumFieldTypes) fieldType[i];
373 dbType = MySqlHelper.MySqlTypeToDbType(fieldEnum);
374 typ = MySqlHelper.DbTypeToSystemType (dbType);
380 public float GetFloat(int i) {
381 return (float) dataValue[i];
385 public Guid GetGuid(int i) {
386 throw new NotImplementedException ();
390 public short GetInt16(int i) {
391 return (short) dataValue[i];
395 public int GetInt32(int i) {
396 return (int) dataValue[i];
400 public long GetInt64(int i) {
401 return (long) dataValue[i];
405 public string GetName(int i) {
410 public int GetOrdinal(string name) {
414 for(i = 0; i < numFields; i++) {
415 if(fieldName[i].Equals(name))
419 for(i = 0; i < numFields; i++) {
423 ta = fieldName[i].ToUpper();
431 throw new MissingFieldException("Missing field: " + name);
435 public string GetString(int i) {
436 return (string) dataValue[i];
440 public object GetValue(int i) {
441 // FIXME: this returns a native type
442 // need to return a .NET type
443 if(MySqlFieldHelper.IsNotNull(fieldFlags[i]) == true)
450 public int GetValues(object[] values)
452 Array.Copy (dataValue, values, dataValue.Length);
453 return dataValue.Length;
457 public bool IsDBNull(int i) {
458 return !MySqlFieldHelper.IsNotNull(fieldFlags[i]);
462 public bool GetBoolean(int i) {
463 return (bool) dataValue[i];
467 public IEnumerator GetEnumerator() {
468 throw new NotImplementedException ();
471 #endregion // Public Methods
476 public void Dispose () {
480 //~MySqlDataReader() {
483 #endregion // Destructors
490 return 0; // always return zero, unless
491 // this provider will allow
496 public bool IsClosed {
506 public int RecordsAffected {
509 return recordsAffected;
513 public int FieldCount {
520 public object this[string name] {
525 for(i = 0; i < numFields; i++) {
526 if(fieldName[i].Equals(name))
530 for(i = 0; i < numFields; i++) {
534 ta = fieldName[i].ToUpper();
542 throw new MissingFieldException("Missing field: " + name);
546 public object this[int i] {
553 #endregion // Properties