(DISTFILES): Comment out a few missing files.
[mono-project.git] / mcs / class / Mono.Data.MySql / Mono.Data.MySql / MySqlDataReader.cs
blobd5d4693822b06b35d338f9fc73dde4e34d617b89
1 //
2 // Mono.Data.MySql.MySqlDataReader.cs
3 //
4 // Author:
5 // Rodrigo Moya (rodrigo@ximian.com)
6 // Daniel Morgan (danmorg@sc.rr.com)
7 //
8 // (C) Ximian, Inc 2002
9 // (C) Daniel Morgan 2002
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
20 //
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
23 //
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System;
34 using System.Collections;
35 using System.ComponentModel;
36 using System.Data;
37 using System.Data.Common;
38 using System.Runtime.InteropServices;
40 namespace Mono.Data.MySql {
41 /// <summary>
42 /// Provides a means of reading one or more forward-only streams
43 /// of result sets obtained by executing a command
44 /// at a SQL database.
45 /// </summary>
46 public sealed class MySqlDataReader : MarshalByRefObject,
47 IEnumerable, IDataReader, IDisposable, IDataRecord
50 #region Fields
52 private MySqlCommand cmd;
54 // field meta data
55 private string[] fieldName;
56 private MySqlEnumFieldTypes[] fieldType; // MySQL data type
57 private DbType[] fieldDbType; // DbType translated from MySQL type
58 private uint[] fieldLength;
59 private uint[] fieldMaxLength;
60 private uint[] fieldFlags;
61 // field data value
62 private object[] dataValue;
64 private bool open = false;
66 private int recordsAffected = -1;
67 private int currentQuery = 0;
69 private int currentRow = -1;
70 private IntPtr res = IntPtr.Zero;
71 private IntPtr row = IntPtr.Zero;
73 private int numFields;
74 private int numRows;
76 private CommandBehavior cmdBehavior;
78 private bool disposed = false;
80 #endregion // Fields
82 #region Constructors
84 internal MySqlDataReader (MySqlCommand sqlCmd, CommandBehavior behavior) {
86 cmd = sqlCmd;
87 open = true;
88 // cmd.OpenReader(this);
89 cmdBehavior = behavior;
92 #endregion // Fields
94 #region Public Methods
96 [MonoTODO]
97 public void Close() {
98 open = false;
100 // free MySqlDataReader resources in SqlCommand
101 // and allow SqlConnection to be used again
102 //cmd.CloseReader();
104 // TODO: get parameters from result
106 Dispose(true);
109 public DataTable GetSchemaTable() {
111 DataTable dataTableSchema = null;
112 // Only Results from SQL SELECT Queries
113 // get a DataTable for schema of the result
114 // otherwise, DataTable is null reference
115 if(numFields > 0) {
117 dataTableSchema = new DataTable ("SchemaTable");
119 dataTableSchema.Columns.Add ("ColumnName", typeof (string));
120 dataTableSchema.Columns.Add ("ColumnOrdinal", typeof (int));
121 dataTableSchema.Columns.Add ("ColumnSize", typeof (int));
122 dataTableSchema.Columns.Add ("NumericPrecision", typeof (int));
123 dataTableSchema.Columns.Add ("NumericScale", typeof (int));
124 dataTableSchema.Columns.Add ("IsUnique", typeof (bool));
125 dataTableSchema.Columns.Add ("IsKey", typeof (bool));
126 DataColumn dc = dataTableSchema.Columns["IsKey"];
127 dc.AllowDBNull = true; // IsKey can have a DBNull
128 dataTableSchema.Columns.Add ("BaseCatalogName", typeof (string));
129 dataTableSchema.Columns.Add ("BaseColumnName", typeof (string));
130 dataTableSchema.Columns.Add ("BaseSchemaName", typeof (string));
131 dataTableSchema.Columns.Add ("BaseTableName", typeof (string));
132 dataTableSchema.Columns.Add ("DataType", typeof(Type));
133 dataTableSchema.Columns.Add ("AllowDBNull", typeof (bool));
134 dataTableSchema.Columns.Add ("ProviderType", typeof (int));
135 dataTableSchema.Columns.Add ("IsAliased", typeof (bool));
136 dataTableSchema.Columns.Add ("IsExpression", typeof (bool));
137 dataTableSchema.Columns.Add ("IsIdentity", typeof (bool));
138 dataTableSchema.Columns.Add ("IsAutoIncrement", typeof (bool));
139 dataTableSchema.Columns.Add ("IsRowVersion", typeof (bool));
140 dataTableSchema.Columns.Add ("IsHidden", typeof (bool));
141 dataTableSchema.Columns.Add ("IsLong", typeof (bool));
142 dataTableSchema.Columns.Add ("IsReadOnly", typeof (bool));
144 DataRow schemaRow;
146 Type typ;
148 for (int i = 0; i < numFields; i += 1 ) {
150 schemaRow = dataTableSchema.NewRow ();
152 schemaRow["ColumnName"] = fieldName[i];
153 schemaRow["ColumnOrdinal"] = i + 1;
155 schemaRow["ColumnSize"] = (int) fieldMaxLength[i];
156 schemaRow["NumericPrecision"] = 0;
157 schemaRow["NumericScale"] = 0;
159 if((cmdBehavior & CommandBehavior.KeyInfo) == CommandBehavior.KeyInfo) {
160 // TODO: need to get KeyInfo
161 schemaRow["IsUnique"] = false;
162 schemaRow["IsKey"] = false;
164 else {
165 schemaRow["IsUnique"] = false;
166 schemaRow["IsKey"] = DBNull.Value;
168 schemaRow["BaseCatalogName"] = "";
170 schemaRow["BaseColumnName"] = fieldName[i];
171 schemaRow["BaseSchemaName"] = "";
172 schemaRow["BaseTableName"] = "";
174 typ = MySqlHelper.DbTypeToSystemType (fieldDbType[i]);
175 schemaRow["DataType"] = typ;
177 schemaRow["AllowDBNull"] = false;
179 schemaRow["ProviderType"] = (int) fieldType[i];
180 schemaRow["IsAliased"] = false;
181 schemaRow["IsExpression"] = false;
182 schemaRow["IsIdentity"] = false;
183 schemaRow["IsAutoIncrement"] = false;
184 schemaRow["IsRowVersion"] = false;
185 schemaRow["IsHidden"] = false;
186 schemaRow["IsLong"] = false;
187 schemaRow["IsReadOnly"] = false;
189 dataTableSchema.Rows.Add (schemaRow);
193 return dataTableSchema;
196 private void ClearFields () {
197 numRows = 0;
198 numFields = 0;
199 fieldName = null;
200 fieldType = null;
201 fieldLength = null;
202 fieldMaxLength = null;
203 fieldFlags = null;
204 dataValue = null;
207 public bool NextResult () {
209 // reset
210 recordsAffected = -1;
211 currentRow = -1;
213 bool resultReturned;
214 res = cmd.NextResult (out resultReturned);
215 if (resultReturned == false)
216 return false; // no result returned
218 if ((cmdBehavior & CommandBehavior.SingleResult) == CommandBehavior.SingleResult)
219 if (currentQuery > 0) {
220 if(res == IntPtr.Zero)
221 recordsAffected = (int) MySql.AffectedRows(cmd.Connection.NativeMySqlInitStruct);
222 ClearFields();
223 return true; // result returned
226 if((cmdBehavior & CommandBehavior.SchemaOnly) == CommandBehavior.SchemaOnly) {
227 ClearFields ();
228 return false; // no result returned
231 if(res == IntPtr.Zero) {
232 // no result set returned
233 recordsAffected = (int) MySql.AffectedRows (cmd.Connection.NativeMySqlInitStruct);
234 ClearFields();
236 else {
237 dataValue = null;
239 // get meta data about result set
240 numRows = MySql.NumRows(res);
241 numFields = MySql.NumFields(res);
242 // get meta data about each field
243 fieldName = new string[numFields];
244 fieldType = new MySqlEnumFieldTypes[numFields];
245 fieldLength = new uint[numFields];
246 fieldMaxLength = new uint[numFields];
247 fieldFlags = new uint[numFields];
249 fieldDbType = new DbType[numFields];
251 // marshal each meta data field
252 // into field* arrays
253 MySqlMarshalledField marshField = null;
254 for (int i = 0; i < numFields; i++) {
255 // marshal field
256 marshField = (MySqlMarshalledField) Marshal.PtrToStructure(MySql.FetchField(res),
257 typeof(MySqlMarshalledField));
259 // copy memebers in marshalField to fields[i]
260 fieldName[i] = marshField.Name;
261 int myType = marshField.FieldType;
262 fieldType[i] = (MySqlEnumFieldTypes) myType;
263 fieldLength[i] = marshField.Length;
264 fieldMaxLength[i] = marshField.MaxLength;
265 fieldFlags[i] = marshField.Flags;
267 fieldDbType[i] = MySqlHelper.MySqlTypeToDbType((MySqlEnumFieldTypes)fieldType[i]);
268 marshField = null;
271 return true; // result returned
274 public bool Read() {
276 dataValue = null;
278 if(currentRow < numRows - 1) {
280 currentRow++;
282 if(numFields > 0 && currentRow > 0)
283 if((cmdBehavior & CommandBehavior.SingleRow) ==
284 CommandBehavior.SingleRow) {
286 currentRow = numRows - 1;
287 return false; // EOF
290 row = MySql.FetchRow (res);
291 if (row == IntPtr.Zero) {
292 MySql.FreeResult (res);
293 res = IntPtr.Zero;
294 return false; // EOF
296 else {
297 dataValue = new object[numFields];
298 for (int col = 0; col < numFields; col++) {
299 GetDataValue (row, col);
302 return true; // not EOF
304 return false; // EOF
307 void GetDataValue (IntPtr row, int col) {
308 // marshal column data value
309 string objValue = cmd.GetColumnData(row, col);
311 // tranlate from native MySql c type
312 // to a .NET type here
313 dataValue[col] = MySqlHelper.ConvertDbTypeToSystem (fieldType[col],
314 fieldDbType[col], objValue);
316 // TODO: for CommandBehavior.SequentialAccess -
317 // used for reading Large OBjects
318 //if((cmdBehavior & CommandBehavior.SequentialAccess) ==
319 // CommandBehavior.SequentialAccess) {
323 [MonoTODO]
324 public byte GetByte (int i) {
325 throw new NotImplementedException ();
328 // TODO: CommandBehavior.SequentialAccess
329 // and handling LOBs
330 [MonoTODO]
331 public long GetBytes (int i, long fieldOffset,
332 byte[] buffer, int bufferOffset,
333 int length) {
335 throw new NotImplementedException ();
338 [MonoTODO]
339 public char GetChar (int i) {
340 throw new NotImplementedException ();
343 // TODO: CommandBehavior.SequentialAccess
344 // and handling LOBs
345 [MonoTODO]
346 public long GetChars (int i, long fieldOffset,
347 char[] buffer, int bufferOffset,
348 int length) {
350 throw new NotImplementedException ();
353 [MonoTODO]
354 public IDataReader GetData (int i) {
355 throw new NotImplementedException ();
358 public string GetDataTypeName (int i) {
359 return MySqlHelper.GetMySqlTypeName (fieldType[i]);
362 public DateTime GetDateTime(int i) {
363 return (DateTime) dataValue[i];
366 public decimal GetDecimal(int i) {
367 return (decimal) dataValue[i];
370 public double GetDouble(int i) {
371 return (double) dataValue[i];
374 public Type GetFieldType(int i) {
375 return MySqlHelper.DbTypeToSystemType (fieldDbType[i]);
378 public float GetFloat(int i) {
379 return (float) dataValue[i];
382 public Guid GetGuid(int i) {
383 throw new NotImplementedException ();
386 public short GetInt16(int i) {
387 return (short) dataValue[i];
390 public int GetInt32(int i) {
391 return (int) dataValue[i];
394 public long GetInt64(int i) {
395 return (long) dataValue[i];
398 public string GetName(int i) {
399 return fieldName[i];
402 public int GetOrdinal (string name) {
404 int i;
406 for(i = 0; i < numFields; i++) {
407 if(fieldName[i].Equals (name))
408 return i;
411 for(i = 0; i < numFields; i++) {
412 string ta;
413 string n;
415 ta = fieldName[i].ToUpper ();
416 n = name.ToUpper ();
418 if(ta.Equals (n)) {
419 return i;
423 throw new MissingFieldException ("Missing field: " + name);
426 public string GetString (int i) {
427 return (string) dataValue[i];
430 public object GetValue (int i) {
431 return dataValue[i];
434 public int GetValues(object[] values)
436 Array.Copy (dataValue, values, dataValue.Length);
437 return dataValue.Length;
440 public bool IsDBNull(int i) {
441 if(dataValue[i] == DBNull.Value)
442 return true;
443 return false;
446 public bool GetBoolean(int i) {
447 return (bool) dataValue[i];
450 IEnumerator IEnumerable.GetEnumerator () {
451 return new DbEnumerator (this);
454 #endregion // Public Methods
456 #region Destructors
458 private void Dispose(bool disposing) {
459 if(!this.disposed) {
460 if(disposing) {
461 // release any managed resources
462 cmd = null;
463 fieldName = null;
464 fieldType = null;
465 fieldDbType = null;
466 fieldLength = null;
467 fieldMaxLength = null;
468 fieldFlags = null;
469 dataValue = null;
471 // release any unmanaged resources
473 // clear unmanaged MySQL result set
474 row = IntPtr.Zero;
475 if(res != IntPtr.Zero) {
476 MySql.FreeResult(res);
477 res = IntPtr.Zero;
480 // close any handles
481 this.disposed = true;
485 void IDisposable.Dispose() {
486 Dispose(true);
489 // aka Finalize
490 ~MySqlDataReader() {
491 Dispose (false);
494 #endregion // Destructors
496 #region Properties
498 public int Depth {
499 get {
500 return 0; // always return zero, unless
501 // this provider will allow
502 // nesting of a row
506 public bool IsClosed {
507 get {
508 if(open == false)
509 return true;
510 else
511 return false;
515 public int RecordsAffected {
516 get {
517 return recordsAffected;
521 public int FieldCount {
522 get {
523 return numFields;
527 public object this[string name] {
528 get {
529 int i;
531 for(i = 0; i < numFields; i++) {
532 if(fieldName[i].Equals(name))
533 return dataValue[i];
536 for(i = 0; i < numFields; i++) {
537 string ta;
538 string n;
540 ta = fieldName[i].ToUpper();
541 n = name.ToUpper();
543 if(ta.Equals(n)) {
544 return dataValue[i];
548 throw new MissingFieldException("Missing field: " + name);
552 public object this[int i] {
553 get {
554 return dataValue[i];
558 #endregion // Properties