2 // Npgsql.NpgsqlDataReader.cs
\r
5 // Francisco Jr. (fxjrlists@yahoo.com.br)
\r
7 // Copyright (C) 2002 The Npgsql Development Team
\r
10 // This library is free software; you can redistribute it and/or
\r
11 // modify it under the terms of the GNU Lesser General Public
\r
12 // License as published by the Free Software Foundation; either
\r
13 // version 2.1 of the License, or (at your option) any later version.
\r
15 // This library is distributed in the hope that it will be useful,
\r
16 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
\r
18 // Lesser General Public License for more details.
\r
20 // You should have received a copy of the GNU Lesser General Public
\r
21 // License along with this library; if not, write to the Free Software
\r
22 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
\r
26 using System.Collections;
\r
31 public class NpgsqlDataReader : IDataReader, IEnumerable
\r
33 private NpgsqlConnection _connection;
\r
34 private ArrayList _resultsets;
\r
35 private ArrayList _responses;
\r
36 private Int32 _rowIndex;
\r
37 private Int32 _resultsetIndex;
\r
38 private NpgsqlResultSet _currentResultset;
\r
39 private DataTable _currentResultsetSchema;
\r
42 // Logging related values
\r
43 private static readonly String CLASSNAME = "NpgsqlDataReader";
\r
45 internal NpgsqlDataReader( ArrayList resultsets, ArrayList responses, NpgsqlConnection connection)
\r
47 _resultsets = resultsets;
\r
48 _responses = responses;
\r
49 _connection = connection;
\r
51 _resultsetIndex = 0;
\r
53 _currentResultset = (NpgsqlResultSet)_resultsets[_resultsetIndex];
\r
59 private Boolean CanRead()
\r
61 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".CanRead() ", LogLevel.Debug);
\r
62 /*if (_currentResultset == null)
\r
64 return (_currentResultset != null);
\r
69 public void Dispose()
\r
78 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".get_Depth() ", LogLevel.Debug);
\r
83 public Boolean IsClosed
\r
87 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".get_IsClosed()", LogLevel.Debug);
\r
92 public Int32 RecordsAffected
\r
96 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".get_RecordsAffected()", LogLevel.Debug);
\r
98 /*if (_currentResultset == null)
\r
99 return 0; //[FIXME] Get the actual number of rows deleted, updated or inserted.
\r
106 String[] ret_string_tokens = ((String)_responses[_resultsetIndex]).Split(null); // whitespace separator.
\r
108 return Int32.Parse(ret_string_tokens[ret_string_tokens.Length - 1]);
\r
113 public void Close()
\r
118 public Boolean NextResult()
\r
120 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".NextResult()", LogLevel.Debug);
\r
121 //throw new NotImplementedException();
\r
123 //[FIXME] Should the currentResultset not be modified
\r
124 // in case there aren't any more resultsets?
\r
125 // SqlClient modify to a invalid resultset and throws exceptions
\r
126 // when trying to access any data.
\r
129 if((_resultsetIndex + 1) < _resultsets.Count)
\r
133 _currentResultset = (NpgsqlResultSet)_resultsets[_resultsetIndex];
\r
141 public Boolean Read()
\r
143 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".Read()", LogLevel.Debug);
\r
149 return (_rowIndex < _currentResultset.Count);
\r
152 public DataTable GetSchemaTable()
\r
154 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".GetSchemaTable()", LogLevel.Debug);
\r
155 //throw new NotImplementedException();
\r
158 return null; //[FIXME] Should we return null or throw an exception??
\r
160 if(_currentResultsetSchema == null)
\r
161 _currentResultsetSchema = GetResultsetSchema();
\r
163 return _currentResultsetSchema;
\r
168 public Int32 FieldCount
\r
173 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".get_FieldCount()", LogLevel.Debug);
\r
174 //return ((_currentResultset == null) ? 0 : _currentResultset.RowDescription.NumFields);
\r
176 return _currentResultset.RowDescription.NumFields;
\r
184 public String GetName(Int32 i)
\r
186 //throw new NotImplementedException();
\r
187 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".GetName(Int32)", LogLevel.Debug);
\r
190 return _currentResultset.RowDescription[i].name;
\r
192 return String.Empty;
\r
195 public String GetDataTypeName(Int32 i)
\r
197 // FIXME: have a type name instead of the oid
\r
198 return (_currentResultset.RowDescription[i].type_oid).ToString();
\r
201 public Type GetFieldType(Int32 i)
\r
203 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".GetFieldType(Int32)", LogLevel.Debug);
\r
206 return Type.GetType(PGUtil.GetSystemTypeFromDbType(_currentResultset.RowDescription[i].type_oid));
\r
209 public Object GetValue(Int32 i)
\r
211 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".GetValue(Int32)", LogLevel.Debug);
\r
212 if (i < 0 || _rowIndex < 0)
\r
213 throw new InvalidOperationException("Cannot read data.");
\r
214 return ((NpgsqlAsciiRow)_currentResultset[_rowIndex])[i];
\r
217 public Int32 GetValues(Object[] values)
\r
219 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".GetValues(Object[])", LogLevel.Debug);
\r
221 // Only the number of elements in the array are filled.
\r
222 // It's also possible to pass an array with more that FieldCount elements.
\r
223 Int32 maxColumnIndex = (values.Length < FieldCount) ? values.Length : FieldCount;
\r
225 for (Int32 i = 0; i < maxColumnIndex; i++)
\r
226 values[i] = GetValue(i);
\r
228 return maxColumnIndex;
\r
232 public Int32 GetOrdinal(String name)
\r
234 return _currentResultset.RowDescription.FieldIndex(name);
\r
237 public Object this [ Int32 i ]
\r
241 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".this[Int32]", LogLevel.Debug);
\r
242 return GetValue(i);
\r
246 public Object this [ String name ]
\r
250 //throw new NotImplementedException();
\r
251 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".this[String]", LogLevel.Debug);
\r
252 return GetValue(_currentResultset.RowDescription.FieldIndex(name));
\r
256 public Boolean GetBoolean(Int32 i)
\r
258 // Should this be done using the GetValue directly and not by converting to String
\r
259 // and parsing from there?
\r
260 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".GetBoolean(Int32)", LogLevel.Debug);
\r
262 switch ((String) this[i])
\r
271 throw new System.InvalidCastException();
\r
277 public Byte GetByte(Int32 i)
\r
279 throw new NotImplementedException();
\r
282 public Int64 GetBytes(Int32 i, Int64 fieldOffset, Byte[] buffer, Int32 bufferoffset, Int32 length)
\r
284 throw new NotImplementedException();
\r
287 public Char GetChar(Int32 i)
\r
289 throw new NotImplementedException();
\r
292 public Int64 GetChars(Int32 i, Int64 fieldoffset, Char[] buffer, Int32 bufferoffset, Int32 length)
\r
296 str = GetString(i);
\r
297 if (buffer == null)
\r
300 str.ToCharArray(bufferoffset, length).CopyTo(buffer, 0);
\r
301 return buffer.GetLength(0);
\r
304 public Guid GetGuid(Int32 i)
\r
306 throw new NotImplementedException();
\r
309 public Int16 GetInt16(Int32 i)
\r
311 // Should this be done using the GetValue directly and not by converting to String
\r
312 // and parsing from there?
\r
313 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".GetInt16(Int32)", LogLevel.Debug);
\r
316 return Int16.Parse((String) this[i]);
\r
317 } catch (System.FormatException)
\r
319 throw new System.InvalidCastException();
\r
325 public Int32 GetInt32(Int32 i)
\r
327 // Should this be done using the GetValue directly and not by converting to String
\r
328 // and parsing from there?
\r
329 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".GetInt32(Int32)", LogLevel.Debug);
\r
332 return Int32.Parse((String) this[i]);
\r
333 } catch (System.FormatException)
\r
335 throw new System.InvalidCastException();
\r
341 public Int64 GetInt64(Int32 i)
\r
343 // Should this be done using the GetValue directly and not by converting to String
\r
344 // and parsing from there?
\r
345 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".GetInt64(Int32)", LogLevel.Debug);
\r
348 return Int64.Parse((String) this[i]);
\r
349 } catch (System.FormatException)
\r
351 throw new System.InvalidCastException();
\r
355 public Single GetFloat(Int32 i)
\r
357 // Should this be done using the GetValue directly and not by converting to String
\r
358 // and parsing from there?
\r
359 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".GetFloat(Int32)", LogLevel.Debug);
\r
362 return Single.Parse((String) this[i]);
\r
363 } catch (System.FormatException)
\r
365 throw new System.InvalidCastException();
\r
369 public Double GetDouble(Int32 i)
\r
371 // Should this be done using the GetValue directly and not by converting to String
\r
372 // and parsing from there?
\r
373 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".GetDouble(Int32)", LogLevel.Debug);
\r
376 return Double.Parse((String) this[i]);
\r
377 } catch (System.FormatException)
\r
379 throw new System.InvalidCastException();
\r
383 public String GetString(Int32 i)
\r
385 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".GetString(Int32)", LogLevel.Debug);
\r
386 return (String) GetValue(i);
\r
389 public Decimal GetDecimal(Int32 i)
\r
391 // Should this be done using the GetValue directly and not by converting to String
\r
392 // and parsing from there?
\r
393 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".GetDecimal(Int32)", LogLevel.Debug);
\r
396 return Decimal.Parse((String) this[i]);
\r
397 } catch (System.FormatException)
\r
399 throw new System.InvalidCastException();
\r
403 public DateTime GetDateTime(Int32 i)
\r
405 // Should this be done using the GetValue directly and not by converting to String
\r
406 // and parsing from there?
\r
407 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".GetInt32(Int32)", LogLevel.Debug);
\r
409 return DateTime.ParseExact((string) this[i], "dd/MM/yyyy", null);
410 } catch (System.FormatException) {
\r
411 throw new System.InvalidCastException();
\r
415 public IDataReader GetData(Int32 i)
\r
417 throw new NotImplementedException();
\r
420 public Boolean IsDBNull(Int32 i)
\r
422 //throw new NotImplementedException();
\r
424 return ((NpgsqlAsciiRow)_currentResultset[_rowIndex]).IsNull(i);
\r
427 private DataTable GetResultsetSchema()
\r
429 DataTable result = null;
\r
430 NpgsqlEventLog.LogMsg("Entering " + CLASSNAME + ".GetResultsetSchema()", LogLevel.Debug);
\r
431 // [FIXME] For now, just support fields name.
\r
433 NpgsqlRowDescription rd = _currentResultset.RowDescription;
\r
434 Int16 numFields = rd.NumFields;
\r
435 if(numFields > 0) {
\r
436 result = new DataTable("SchemaTable");
\r
438 result.Columns.Add ("ColumnName", typeof (string));
439 result.Columns.Add ("ColumnOrdinal", typeof (int));
440 result.Columns.Add ("ColumnSize", typeof (int));
441 result.Columns.Add ("NumericPrecision", typeof (int));
442 result.Columns.Add ("NumericScale", typeof (int));
443 result.Columns.Add ("IsUnique", typeof (bool));
444 result.Columns.Add ("IsKey", typeof (bool));
445 DataColumn dc = result.Columns["IsKey"];
446 dc.AllowDBNull = true; // IsKey can have a DBNull
447 result.Columns.Add ("BaseCatalogName", typeof (string));
448 result.Columns.Add ("BaseColumnName", typeof (string));
449 result.Columns.Add ("BaseSchemaName", typeof (string));
450 result.Columns.Add ("BaseTableName", typeof (string));
451 result.Columns.Add ("DataType", typeof(Type));
452 result.Columns.Add ("AllowDBNull", typeof (bool));
453 result.Columns.Add ("ProviderType", typeof (int));
454 result.Columns.Add ("IsAliased", typeof (bool));
455 result.Columns.Add ("IsExpression", typeof (bool));
456 result.Columns.Add ("IsIdentity", typeof (bool));
457 result.Columns.Add ("IsAutoIncrement", typeof (bool));
458 result.Columns.Add ("IsRowVersion", typeof (bool));
459 result.Columns.Add ("IsHidden", typeof (bool));
460 result.Columns.Add ("IsLong", typeof (bool));
461 result.Columns.Add ("IsReadOnly", typeof (bool));
465 for (Int16 i = 0; i < numFields; i++) {
\r
466 row = result.NewRow();
\r
468 row["ColumnName"] = GetName(i);
469 row["ColumnOrdinal"] = i + 1;
470 row["ColumnSize"] = (int) rd[i].type_size;
471 row["NumericPrecision"] = 0;
472 row["NumericScale"] = 0;
473 row["IsUnique"] = false;
474 row["IsKey"] = DBNull.Value;
475 row["BaseCatalogName"] = "";
476 row["BaseColumnName"] = GetName(i);
477 row["BaseSchemaName"] = "";
478 row["BaseTableName"] = "";
\r
479 row["DataType"] = GetFieldType(i);
480 row["AllowDBNull"] = false;
481 row["ProviderType"] = (int) rd[i].type_oid;
482 row["IsAliased"] = false;
483 row["IsExpression"] = false;
484 row["IsIdentity"] = false;
485 row["IsAutoIncrement"] = false;
486 row["IsRowVersion"] = false;
487 row["IsHidden"] = false;
488 row["IsLong"] = false;
489 row["IsReadOnly"] = false;
\r
491 result.Rows.Add(row);
\r
499 IEnumerator IEnumerable.GetEnumerator () {
500 return new System.Data.Common.DbEnumerator (this);