using System;
using System.Data;
using System.Collections;
-using NpgsqlTypes;
+using NpgsqlTypes;
namespace Npgsql
{
-
- public class NpgsqlDataReader : IDataReader, IEnumerable
+ /// <summary>
+ /// Provides a means of reading a forward-only stream of rows from a PostgreSQL backend. This class cannot be inherited.
+ /// </summary>
+ public sealed class NpgsqlDataReader : IDataReader, IEnumerable
{
-
-
-
private NpgsqlConnection _connection;
private ArrayList _resultsets;
private ArrayList _responses;
private DataTable _currentResultsetSchema;
private CommandBehavior _behavior;
private Boolean _isClosed;
-
// Logging related values
_connection = connection;
_rowIndex = -1;
_resultsetIndex = 0;
-
+
if (_resultsets.Count > 0)
_currentResultset = (NpgsqlResultSet)_resultsets[_resultsetIndex];
-
+
_behavior = behavior;
_isClosed = false;
+ }
+ private Boolean HaveResultSet()
+ {
+ return (_currentResultset != null);
}
- private Boolean CanRead()
+ private Boolean HaveRow()
{
- //NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CanRead");
- /*if (_currentResultset == null)
- return false;*/
- return ((_currentResultset != null) &&
- (_currentResultset.Count > 0) &&
- (_rowIndex < _currentResultset.Count));
+ return (HaveResultSet() && _rowIndex >= 0 && _rowIndex < _currentResultset.Count);
+ }
+ private void CheckHaveResultSet()
+ {
+ if (! HaveResultSet())
+ {
+ throw new InvalidOperationException("Cannot read data. No result set.");
+ }
}
- private void CheckCanRead()
+ private void CheckHaveRow()
{
- if (!CanRead())
- throw new InvalidOperationException("Cannot read data");
+ CheckHaveResultSet();
+
+ if (_rowIndex < 0)
+ {
+ throw new InvalidOperationException("DataReader positioned before beginning of result set. Did you call Read()?");
+ }
+ else if (_rowIndex >= _currentResultset.Count)
+ {
+ throw new InvalidOperationException("DataReader positioned beyond end of result set.");
+ }
}
+
+ /// <summary>
+ /// Releases the resources used by the <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see>.
+ /// </summary>
public void Dispose()
{
Dispose(true);
}
-
+
/// <summary>
/// Releases the resources used by the <see cref="Npgsql.NpgsqlCommand">NpgsqlCommand</see>.
/// </summary>
this.Close();
}
}
+
+ /// <summary>
+ /// Gets a value indicating the depth of nesting for the current row. Always returns zero.
+ /// </summary>
public Int32 Depth
{
get
}
}
+ /// <summary>
+ /// Gets a value indicating whether the data reader is closed.
+ /// </summary>
public Boolean IsClosed
{
get
}
}
+ /// <summary>
+ /// Gets the number of rows changed, inserted, or deleted by execution of the SQL statement.
+ /// </summary>
public Int32 RecordsAffected
{
get
{
NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "RecordsAffected");
-
- if (CanRead())
+ if (HaveResultSet())
+ {
return -1;
+ }
String[] _returnStringTokens = ((String)_responses[_resultsetIndex]).Split(null); // whitespace separator.
- return Int32.Parse(_returnStringTokens[_returnStringTokens.Length - 1]);
+ try
+ {
+ return Int32.Parse(_returnStringTokens[_returnStringTokens.Length - 1]);
+ }
+ catch (FormatException)
+ {
+ return -1;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Indicates if NpgsqlDatareader has rows to be read.
+ /// </summary>
+
+ public Boolean HasRows
+ {
+ get
+ {
+ return _currentResultset.Count > 0;
}
}
+ /// <summary>
+ /// Closes the data reader object.
+ /// </summary>
public void Close()
{
- if ((_behavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection)
+ if ((_behavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection)
{
_connection.Close();
- _isClosed = true;
+
}
+ _isClosed = true;
}
+ /// <summary>
+ /// Advances the data reader to the next result, when multiple result sets were returned by the PostgreSQL backend.
+ /// </summary>
+ /// <returns>True if the reader was advanced, otherwise false.</returns>
public Boolean NextResult()
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "NextResult");
-
+
if((_resultsetIndex + 1) < _resultsets.Count)
{
_resultsetIndex++;
}
+ /// <summary>
+ /// Advances the data reader to the next row.
+ /// </summary>
+ /// <returns>True if the reader was advanced, otherwise false.</returns>
public Boolean Read()
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Read");
- _rowIndex++;
-
- if (!CanRead())
- return false;
- else
- return true;
+ CheckHaveResultSet();
+ if (_rowIndex < _currentResultset.Count)
+ {
+ _rowIndex++;
+ return (_rowIndex < _currentResultset.Count);
+ }
+ else
+ {
+ return false;
+ }
}
+ /// <summary>
+ /// Returns a System.Data.DataTable that describes the column metadata of the DataReader.
+ /// </summary>
public DataTable GetSchemaTable()
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetSchemaTable");
_currentResultsetSchema = GetResultsetSchema();
return _currentResultsetSchema;
-
}
-
+ /// <summary>
+ /// Gets the number of columns in the current row.
+ /// </summary>
public Int32 FieldCount
{
get
{
NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "FieldCount");
-
- if (_currentResultset == null) //Executed a non return rows query.
+
+ if (! HaveResultSet()) //Executed a non return rows query.
return -1;
else
return _currentResultset.RowDescription.NumFields;
}
- public String GetName(Int32 i)
+ /// <summary>
+ /// Return the column name of the column at index <param name="Index"></param>.
+ /// </summary>
+ public String GetName(Int32 Index)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetName");
- if (_currentResultset == null)
- return String.Empty;
+ CheckHaveResultSet();
+
+ return _currentResultset.RowDescription[Index].name;
+ }
+
+ /// <summary>
+ /// Return the data type OID of the column at index <param name="Index"></param>.
+ /// </summary>
+ public String GetDataTypeOID(Int32 Index)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetDataTypeName");
+
+ CheckHaveResultSet();
+
+ NpgsqlBackendTypeInfo TI = GetTypeInfo(Index);
+
+ return _currentResultset.RowDescription[Index].type_oid.ToString();
+ }
+
+ /// <summary>
+ /// Return the data type name of the column at index <param name="Index"></param>.
+ /// </summary>
+ public String GetDataTypeName(Int32 Index)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetDataTypeName");
+
+ CheckHaveResultSet();
+
+ NpgsqlBackendTypeInfo TI = GetTypeInfo(Index);
+
+ if (TI == null)
+ {
+ return _currentResultset.RowDescription[Index].type_oid.ToString();
+ }
else
- return _currentResultset.RowDescription[i].name;
+ {
+ return TI.Name;
+ }
}
- public String GetDataTypeName(Int32 i)
+ /// <summary>
+ /// Return the data type of the column at index <param name="Index"></param>.
+ /// </summary>
+ public Type GetFieldType(Int32 Index)
{
- // FIXME: have a type name instead of the oid
- if (_currentResultset == null)
- return String.Empty;
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetFieldType");
+
+ CheckHaveResultSet();
+
+ NpgsqlBackendTypeInfo TI = GetTypeInfo(Index);
+
+ if (TI == null)
+ {
+ return typeof(String); //Default type is string.
+ }
else
- return (_currentResultset.RowDescription[i].type_oid).ToString();
+ {
+ return TI.Type;
+ }
}
- public Type GetFieldType(Int32 i)
+ /// <summary>
+ /// Return the data DbType of the column at index <param name="Index"></param>.
+ /// </summary>
+ public DbType GetFieldDbType(Int32 Index)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetFieldType");
+ CheckHaveResultSet();
+
+ NpgsqlBackendTypeInfo TI = GetTypeInfo(Index);
- if (_currentResultset == null)
- return null;
+ if (TI == null)
+ {
+ return DbType.String;
+ }
else
- return NpgsqlTypesHelper.GetSystemTypeFromTypeOid(_connection.OidToNameMapping, _currentResultset.RowDescription[i].type_oid);
+ {
+ //return TI.DBType;
+ return DbType.String;
+ }
}
- public Object GetValue(Int32 i)
+ /// <summary>
+ /// Return the data NpgsqlDbType of the column at index <param name="Index"></param>.
+ /// </summary>
+ public NpgsqlDbType GetFieldNpgsqlDbType(Int32 Index)
{
- NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetValue");
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetFieldType");
- CheckCanRead();
+ CheckHaveResultSet();
- if (i < 0)
- throw new InvalidOperationException("Cannot read data. Column less than 0 specified.");
- if (_rowIndex < 0)
- throw new InvalidOperationException("Cannot read data. DataReader not initialized. Maybe you forgot to call Read()?");
- return ((NpgsqlAsciiRow)_currentResultset[_rowIndex])[i];
+ NpgsqlBackendTypeInfo TI = GetTypeInfo(Index);
+ if (TI == null)
+ {
+ return NpgsqlDbType.Text;
+ }
+ else
+ {
+ return TI.NpgsqlDbType;
+ }
}
- public Int32 GetValues(Object[] values)
+ /// <summary>
+ /// Return the value of the column at index <param name="Index"></param>.
+ /// </summary>
+ public Object GetValue(Int32 Index)
+ {
+ NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetValue");
+
+ if (Index < 0 || Index >= _currentResultset.RowDescription.NumFields)
+ {
+ throw new IndexOutOfRangeException("Column index out of range");
+ }
+
+ CheckHaveRow();
+
+ return ((NpgsqlAsciiRow)_currentResultset[_rowIndex])[Index];
+ }
+
+ /// <summary>
+ /// Copy values from each column in the current row into <param name="Values"></param>.
+ /// </summary>
+ /// <returns>The number of column values copied.</returns>
+ public Int32 GetValues(Object[] Values)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetValues");
- CheckCanRead();
+ CheckHaveRow();
// Only the number of elements in the array are filled.
// It's also possible to pass an array with more that FieldCount elements.
- Int32 maxColumnIndex = (values.Length < FieldCount) ? values.Length : FieldCount;
+ Int32 maxColumnIndex = (Values.Length < FieldCount) ? Values.Length : FieldCount;
for (Int32 i = 0; i < maxColumnIndex; i++)
- values[i] = GetValue(i);
+ {
+ Values[i] = GetValue(i);
+ }
return maxColumnIndex;
}
- public Int32 GetOrdinal(String name)
+ /// <summary>
+ /// Return the column name of the column named <param name="Name"></param>.
+ /// </summary>
+ public Int32 GetOrdinal(String Name)
{
- CheckCanRead();
- return _currentResultset.RowDescription.FieldIndex(name);
+ CheckHaveResultSet();
+ return _currentResultset.RowDescription.FieldIndex(Name);
}
+ /// <summary>
+ /// Gets the value of a column in its native format.
+ /// </summary>
public Object this [ Int32 i ]
{
get
}
}
+ /// <summary>
+ /// Gets the value of a column in its native format.
+ /// </summary>
public Object this [ String name ]
{
get
{
- //throw new NotImplementedException();
NpgsqlEventLog.LogIndexerGet(LogLevel.Debug, CLASSNAME, name);
return GetValue(_currentResultset.RowDescription.FieldIndex(name));
}
}
+ /// <summary>
+ /// Gets the value of a column as Boolean.
+ /// </summary>
public Boolean GetBoolean(Int32 i)
{
// Should this be done using the GetValue directly and not by converting to String
// and parsing from there?
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetBoolean");
-
return (Boolean) GetValue(i);
-
}
+ /// <summary>
+ /// Gets the value of a column as Byte. Not implemented.
+ /// </summary>
public Byte GetByte(Int32 i)
{
throw new NotImplementedException();
}
+ /// <summary>
+ /// Gets raw data from a column.
+ /// </summary>
public Int64 GetBytes(Int32 i, Int64 fieldOffset, Byte[] buffer, Int32 bufferoffset, Int32 length)
{
result = (Byte[]) GetValue(i);
+ if (buffer == null)
+ return result.Length;
+
+
+ // We just support read all the field for while. So, any fieldOffset value other than 0 will not read
+ // anything and return 0.
+
+ if (fieldOffset != 0)
+ return 0;
+
// [TODO] Implement blob support.
- if (buffer != null)
- {
- result.CopyTo(buffer, 0);
- }
+
+ result.CopyTo(buffer, 0);
+
return result.Length;
}
+ /// <summary>
+ /// Gets the value of a column as Char. Not implemented.
+ /// </summary>
public Char GetChar(Int32 i)
{
throw new NotImplementedException();
}
+ /// <summary>
+ /// Gets raw data from a column.
+ /// </summary>
public Int64 GetChars(Int32 i, Int64 fieldoffset, Char[] buffer, Int32 bufferoffset, Int32 length)
{
String str;
return buffer.GetLength(0);
}
+ /// <summary>
+ /// Gets the value of a column converted to a Guid. Not implemented.
+ /// </summary>
public Guid GetGuid(Int32 i)
{
throw new NotImplementedException();
}
+ /// <summary>
+ /// Gets the value of a column as Int16.
+ /// </summary>
public Int16 GetInt16(Int32 i)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetInt16");
return (Int16) GetValue(i);
-
}
-
+ /// <summary>
+ /// Gets the value of a column as Int32.
+ /// </summary>
public Int32 GetInt32(Int32 i)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetInt32");
return (Int32) GetValue(i);
-
}
-
+ /// <summary>
+ /// Gets the value of a column as Int64.
+ /// </summary>
public Int64 GetInt64(Int32 i)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetInt64");
return (Int64) GetValue(i);
}
+ /// <summary>
+ /// Gets the value of a column as Single.
+ /// </summary>
public Single GetFloat(Int32 i)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetFloat");
-
+
return (Single) GetValue(i);
}
+ /// <summary>
+ /// Gets the value of a column as Double.
+ /// </summary>
public Double GetDouble(Int32 i)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetDouble");
-
+
return (Double) GetValue(i);
}
+ /// <summary>
+ /// Gets the value of a column as String.
+ /// </summary>
public String GetString(Int32 i)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetString");
return (String) GetValue(i);
}
+ /// <summary>
+ /// Gets the value of a column as Decimal.
+ /// </summary>
public Decimal GetDecimal(Int32 i)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetDecimal");
return (Decimal) GetValue(i);
}
+ /// <summary>
+ /// Gets the value of a column as DateTime.
+ /// </summary>
public DateTime GetDateTime(Int32 i)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetDateTime");
return (DateTime) GetValue(i);
}
+ /// <summary>
+ /// Not implemented.
+ /// </summary>
public IDataReader GetData(Int32 i)
{
throw new NotImplementedException();
}
+ /// <summary>
+ /// Report whether the value in a column is DBNull.
+ /// </summary>
public Boolean IsDBNull(Int32 i)
{
NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IsDBNull");
- CheckCanRead();
+ return (GetValue(i) == DBNull.Value);
+ }
- return ((NpgsqlAsciiRow)_currentResultset[_rowIndex]).IsNull(i);
+ internal NpgsqlBackendTypeInfo GetTypeInfo(Int32 FieldIndex)
+ {
+ return _currentResultset.RowDescription[FieldIndex].type_info;
}
private DataTable GetResultsetSchema()
}
-
-
IEnumerator IEnumerable.GetEnumerator ()
{
return new System.Data.Common.DbEnumerator (this);