2 // Npgsql.NpgsqlDataReader.cs
5 // Francisco Jr. (fxjrlists@yahoo.com.br)
7 // Copyright (C) 2002 The Npgsql Development Team
8 // npgsql-general@gborg.postgresql.org
9 // http://gborg.postgresql.org/project/npgsql/projdisplay.php
12 // This library is free software; you can redistribute it and/or
13 // modify it under the terms of the GNU Lesser General Public
14 // License as published by the Free Software Foundation; either
15 // version 2.1 of the License, or (at your option) any later version.
17 // This library is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 // Lesser General Public License for more details.
22 // You should have received a copy of the GNU Lesser General Public
23 // License along with this library; if not, write to the Free Software
24 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28 using System.Collections;
35 public class NpgsqlDataReader : IDataReader, IEnumerable
40 private NpgsqlConnection _connection;
41 private ArrayList _resultsets;
42 private ArrayList _responses;
43 private Int32 _rowIndex;
44 private Int32 _resultsetIndex;
45 private NpgsqlResultSet _currentResultset;
46 private DataTable _currentResultsetSchema;
47 private CommandBehavior _behavior;
48 private Boolean _isClosed;
52 // Logging related values
53 private static readonly String CLASSNAME = "NpgsqlDataReader";
55 internal NpgsqlDataReader( ArrayList resultsets, ArrayList responses, NpgsqlConnection connection, CommandBehavior behavior)
57 _resultsets = resultsets;
58 _responses = responses;
59 _connection = connection;
63 if (_resultsets.Count > 0)
64 _currentResultset = (NpgsqlResultSet)_resultsets[_resultsetIndex];
71 private Boolean CanRead()
73 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CanRead");
74 /*if (_currentResultset == null)
76 return ((_currentResultset != null) && (_currentResultset.Count > 0));
80 private void CheckCanRead()
83 throw new InvalidOperationException("Cannot read data");
92 /// Releases the resources used by the <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see>.
94 protected void Dispose (bool disposing)
96 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Dispose");
106 NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "Depth");
111 public Boolean IsClosed
115 NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "IsClosed");
120 public Int32 RecordsAffected
124 NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "RecordsAffected");
130 String[] ret_string_tokens = ((String)_responses[_resultsetIndex]).Split(null); // whitespace separator.
132 return Int32.Parse(ret_string_tokens[ret_string_tokens.Length - 1]);
139 if ((_behavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection)
147 public Boolean NextResult()
149 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "NextResult");
150 //throw new NotImplementedException();
152 //[FIXME] Should the currentResultset not be modified
153 // in case there aren't any more resultsets?
154 // SqlClient modify to a invalid resultset and throws exceptions
155 // when trying to access any data.
158 if((_resultsetIndex + 1) < _resultsets.Count)
162 _currentResultset = (NpgsqlResultSet)_resultsets[_resultsetIndex];
170 public Boolean Read()
172 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Read");
178 return (_rowIndex < _currentResultset.Count);
181 public DataTable GetSchemaTable()
183 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetSchemaTable");
185 if(_currentResultsetSchema == null)
186 _currentResultsetSchema = GetResultsetSchema();
188 return _currentResultsetSchema;
193 public Int32 FieldCount
198 NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "FieldCount");
200 if (_currentResultset == null) //Executed a non return rows query.
203 return _currentResultset.RowDescription.NumFields;
210 public String GetName(Int32 i)
212 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetName");
214 if (_currentResultset == null)
217 return _currentResultset.RowDescription[i].name;
220 public String GetDataTypeName(Int32 i)
222 // FIXME: have a type name instead of the oid
223 if (_currentResultset == null)
226 return (_currentResultset.RowDescription[i].type_oid).ToString();
229 public Type GetFieldType(Int32 i)
231 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetFieldType");
234 if (_currentResultset == null)
237 return NpgsqlTypesHelper.GetSystemTypeFromTypeOid(_connection.OidToNameMapping, _currentResultset.RowDescription[i].type_oid);
240 public Object GetValue(Int32 i)
242 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetValue");
246 if (i < 0 || _rowIndex < 0)
247 throw new InvalidOperationException("Cannot read data.");
248 return ((NpgsqlAsciiRow)_currentResultset[_rowIndex])[i];
254 public Int32 GetValues(Object[] values)
256 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetValues");
260 // Only the number of elements in the array are filled.
261 // It's also possible to pass an array with more that FieldCount elements.
262 Int32 maxColumnIndex = (values.Length < FieldCount) ? values.Length : FieldCount;
264 for (Int32 i = 0; i < maxColumnIndex; i++)
265 values[i] = GetValue(i);
267 return maxColumnIndex;
271 public Int32 GetOrdinal(String name)
274 return _currentResultset.RowDescription.FieldIndex(name);
277 public Object this [ Int32 i ]
281 NpgsqlEventLog.LogIndexerGet(LogLevel.Debug, CLASSNAME, i);
286 public Object this [ String name ]
290 //throw new NotImplementedException();
291 NpgsqlEventLog.LogIndexerGet(LogLevel.Debug, CLASSNAME, name);
292 return GetValue(_currentResultset.RowDescription.FieldIndex(name));
296 public Boolean GetBoolean(Int32 i)
298 // Should this be done using the GetValue directly and not by converting to String
299 // and parsing from there?
300 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetBoolean");
303 return (Boolean) GetValue(i);
307 public Byte GetByte(Int32 i)
309 throw new NotImplementedException();
312 public Int64 GetBytes(Int32 i, Int64 fieldOffset, Byte[] buffer, Int32 bufferoffset, Int32 length)
317 result = (Byte[]) GetValue(i);
319 // [TODO] Implement blob support.
322 result.CopyTo(buffer, 0);
325 return result.Length;
329 public Char GetChar(Int32 i)
331 throw new NotImplementedException();
334 public Int64 GetChars(Int32 i, Int64 fieldoffset, Char[] buffer, Int32 bufferoffset, Int32 length)
342 str.ToCharArray(bufferoffset, length).CopyTo(buffer, 0);
343 return buffer.GetLength(0);
346 public Guid GetGuid(Int32 i)
348 throw new NotImplementedException();
351 public Int16 GetInt16(Int32 i)
353 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetInt16");
355 return (Int16) GetValue(i);
360 public Int32 GetInt32(Int32 i)
362 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetInt32");
364 return (Int32) GetValue(i);
369 public Int64 GetInt64(Int32 i)
371 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetInt64");
373 return (Int64) GetValue(i);
376 public Single GetFloat(Int32 i)
378 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetFloat");
380 return (Single) GetValue(i);
383 public Double GetDouble(Int32 i)
385 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetDouble");
387 return (Double) GetValue(i);
390 public String GetString(Int32 i)
392 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetString");
394 return (String) GetValue(i);
397 public Decimal GetDecimal(Int32 i)
399 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetDecimal");
401 return (Decimal) GetValue(i);
404 public DateTime GetDateTime(Int32 i)
406 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetDateTime");
408 return (DateTime) GetValue(i);
411 public IDataReader GetData(Int32 i)
413 throw new NotImplementedException();
416 public Boolean IsDBNull(Int32 i)
418 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IsDBNull");
422 return ((NpgsqlAsciiRow)_currentResultset[_rowIndex]).IsNull(i);
425 private DataTable GetResultsetSchema()
428 NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetResultsetSchema");
429 DataTable result = null;
431 NpgsqlRowDescription rd = _currentResultset.RowDescription;
432 Int16 numFields = rd.NumFields;
435 result = new DataTable("SchemaTable");
437 result.Columns.Add ("ColumnName", typeof (string));
438 result.Columns.Add ("ColumnOrdinal", typeof (int));
439 result.Columns.Add ("ColumnSize", typeof (int));
440 result.Columns.Add ("NumericPrecision", typeof (int));
441 result.Columns.Add ("NumericScale", typeof (int));
442 result.Columns.Add ("IsUnique", typeof (bool));
443 result.Columns.Add ("IsKey", typeof (bool));
444 DataColumn dc = result.Columns["IsKey"];
445 dc.AllowDBNull = true; // IsKey can have a DBNull
446 result.Columns.Add ("BaseCatalogName", typeof (string));
447 result.Columns.Add ("BaseColumnName", typeof (string));
448 result.Columns.Add ("BaseSchemaName", typeof (string));
449 result.Columns.Add ("BaseTableName", typeof (string));
450 result.Columns.Add ("DataType", typeof(Type));
451 result.Columns.Add ("AllowDBNull", typeof (bool));
452 result.Columns.Add ("ProviderType", typeof (int));
453 result.Columns.Add ("IsAliased", typeof (bool));
454 result.Columns.Add ("IsExpression", typeof (bool));
455 result.Columns.Add ("IsIdentity", typeof (bool));
456 result.Columns.Add ("IsAutoIncrement", typeof (bool));
457 result.Columns.Add ("IsRowVersion", typeof (bool));
458 result.Columns.Add ("IsHidden", typeof (bool));
459 result.Columns.Add ("IsLong", typeof (bool));
460 result.Columns.Add ("IsReadOnly", typeof (bool));
464 for (Int16 i = 0; i < numFields; i++)
466 row = result.NewRow();
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"] = "";
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;
491 result.Rows.Add(row);
501 IEnumerator IEnumerable.GetEnumerator ()
503 return new System.Data.Common.DbEnumerator (this);