OdbcDataReader.cs :  » 2.6.4-mono-.net-core » System.Data » System » Data » Odbc » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » 2.6.4 mono .net core » System.Data 
System.Data » System » Data » Odbc » OdbcDataReader.cs
//
// System.Data.Odbc.OdbcDataReader
//
// Author:
//   Brian Ritchie (brianlritchie@hotmail.com) 
//   Daniel Morgan <danmorg@sc.rr.com>
//   Sureshkumar T <tsureshkumar@novell.com> (2004)
//
// Copyright (C) Brian Ritchie, 2002
// Copyright (C) Daniel Morgan, 2002
//

//
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Globalization;
using System.Text;

namespace System.Data.Odbc{
#if NET_2_0
  public sealed class OdbcDataReader : DbDataReader
#else
  public sealed class OdbcDataReader : MarshalByRefObject, IDataReader, IDisposable, IDataRecord, IEnumerable
#endif
  {
    #region Fields
    
    private OdbcCommand command;
    private bool open;
    private int currentRow;
    private OdbcColumn[] cols;
    private IntPtr hstmt;
    private int _recordsAffected = -1;
    bool disposed;
    private DataTable _dataTableSchema;
    private CommandBehavior behavior;

    #endregion

    #region Constructors

    internal OdbcDataReader (OdbcCommand command, CommandBehavior behavior)
    {
      this.command = command;
      this.CommandBehavior = behavior;
      open = true;
      currentRow = -1;
      hstmt = command.hStmt;
      // Init columns array;
      short colcount = 0;
      libodbc.SQLNumResultCols (hstmt, ref colcount);
      cols = new OdbcColumn [colcount];
      GetColumns ();
    }

    internal OdbcDataReader (OdbcCommand command, CommandBehavior behavior,
           int recordAffected) : this (command, behavior)
    {
      _recordsAffected = recordAffected;
    }
    

    #endregion

    #region Properties

    private CommandBehavior CommandBehavior {
      get { return behavior; }
      set { behavior = value; }
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    int Depth {
      get {
        return 0; // no nested selects supported
      }
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    int FieldCount {
      get {
        if (IsClosed)
          throw new InvalidOperationException ("The reader is closed.");
        return cols.Length;
      }
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    bool IsClosed {
      get {
        return !open;
      }
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    object this [string value] {
      get {
        int pos = GetOrdinal (value);
        return this [pos];
      }
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    object this [int i] {
      get {
        return GetValue (i);
      }
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    int RecordsAffected {
      get {
        return _recordsAffected;
      }
    }

    [MonoTODO]
    public
#if NET_2_0
    override
#endif // NET_2_0
    bool HasRows {
      get { throw new NotImplementedException(); }
    }

    private OdbcConnection Connection {
      get {
        if (command != null)
          return command.Connection;
        return null;
      }
    }

    #endregion

    #region Methods
    
    private int ColIndex (string colname)
    {
      int i = 0;
      foreach (OdbcColumn col in cols) {
        if (col != null) {
          if (col.ColumnName == colname)
            return i;
          if (String.Compare (col.ColumnName, colname, true) == 0)
            return i;
        }
        i++;
      }
      return -1;
    }

    // Dynamically load column descriptions as needed.
    private OdbcColumn GetColumn (int ordinal)
    {
      if (cols [ordinal] == null) {
        short bufsize = 255;
        byte [] colname_buffer = new byte [bufsize];
        string colname;
        short colname_size = 0;
        uint ColSize = 0;
        short DecDigits = 0, Nullable = 0, dt = 0;
        OdbcReturn ret = libodbc.SQLDescribeCol (hstmt, Convert.ToUInt16 (ordinal + 1), 
                   colname_buffer, bufsize, ref colname_size, ref dt, ref ColSize, 
                   ref DecDigits, ref Nullable);
        if ((ret != OdbcReturn.Success) && (ret != OdbcReturn.SuccessWithInfo))
          throw Connection.CreateOdbcException (OdbcHandleType.Stmt, hstmt);
        colname = RemoveTrailingNullChar (Encoding.Unicode.GetString (colname_buffer));
        OdbcColumn c = new OdbcColumn (colname, (SQL_TYPE) dt);
        c.AllowDBNull = (Nullable != 0);
        c.Digits = DecDigits;
        if (c.IsVariableSizeType)
          c.MaxLength = (int) ColSize;
        cols [ordinal] = c;
      }
      return cols [ordinal];
    }
    
    // Load all column descriptions
    private void GetColumns ()
    {
      for(int i = 0; i < cols.Length; i++)
        GetColumn (i);
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    void Close ()
    {
      // FIXME : have to implement output parameter binding
      open = false;
      currentRow = -1;

      this.command.FreeIfNotPrepared ();

      if ((this.CommandBehavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection)
        this.command.Connection.Close ();
    }

#if ONLY_1_1
    ~OdbcDataReader ()
    {
      this.Dispose (false);
    }
#endif

    public 
#if NET_2_0
    override
#endif // NET_2_0
    bool GetBoolean (int i)
    {
      return (bool) GetValue (i);
    }

    public 
#if NET_2_0
    override
#endif // NET_2_0
    byte GetByte (int i)
    {
      return Convert.ToByte (GetValue (i));
    }

    public 
#if NET_2_0
    override
#endif // NET_2_0
    long GetBytes (int i, long dataIndex, byte[] buffer, int bufferIndex, int length)
    {
      if (IsClosed)
        throw new InvalidOperationException ("Reader is not open.");
      if (currentRow == -1)
        throw new InvalidOperationException ("No data available.");

      OdbcReturn ret = OdbcReturn.Error;
      bool copyBuffer = false;
      int returnVal = 0, outsize = 0;
      byte [] tbuff = new byte [length+1];

      if (buffer == null)
        length = 0;
      ret=libodbc.SQLGetData (hstmt, (ushort) (i + 1), SQL_C_TYPE.BINARY, tbuff, length, 
            ref outsize);

      if (ret == OdbcReturn.NoData)
        return 0;

      if ( (ret != OdbcReturn.Success) && (ret != OdbcReturn.SuccessWithInfo))
        throw Connection.CreateOdbcException (OdbcHandleType.Stmt, hstmt);

      OdbcException odbcException = null;
      if ( (ret == OdbcReturn.SuccessWithInfo))
        odbcException = Connection.CreateOdbcException (
          OdbcHandleType.Stmt, hstmt);

      if (buffer == null)
        return outsize; //if buffer is null,return length of the field

      if (ret == OdbcReturn.SuccessWithInfo) {
        if (outsize == (int) OdbcLengthIndicator.NoTotal)
          copyBuffer = true;
        else if (outsize == (int) OdbcLengthIndicator.NullData) {
          copyBuffer = false;
          returnVal = -1;
        } else {
          string sqlstate = odbcException.Errors [0].SQLState;
          //SQLState: String Data, Right truncated
          if (sqlstate != libodbc.SQLSTATE_RIGHT_TRUNC)
            throw odbcException;
          copyBuffer = true;
        }
      } else {
        copyBuffer = outsize == -1 ? false : true;
        returnVal = outsize;
      }

      if (copyBuffer) {
        if (outsize == (int) OdbcLengthIndicator.NoTotal) {
          int j = 0;
          while (tbuff [j] != libodbc.C_NULL) {
            buffer [bufferIndex + j] = tbuff [j];
            j++;
          }
          returnVal = j;
        } else {
          int read_bytes = Math.Min (outsize, length);
          for (int j = 0; j < read_bytes; j++)
            buffer [bufferIndex + j] = tbuff [j];
          returnVal = read_bytes;
        }
      }
      return returnVal;
    }
    
    [MonoTODO]
    public 
#if NET_2_0
    override
#endif // NET_2_0
    char GetChar (int i)
    {
      throw new NotImplementedException ();
    }

    [MonoTODO]
    public 
#if NET_2_0
    override
#endif // NET_2_0
    long GetChars (int i, long dataIndex, char[] buffer, int bufferIndex, int length)
    {
      if (IsClosed)
        throw new InvalidOperationException ("The reader is closed.");
      if (currentRow == -1)
        throw new InvalidOperationException ("No data available.");
      if (i < 0 || i >= FieldCount)
        throw new IndexOutOfRangeException ();
      throw new NotImplementedException ();
    }

    [MonoTODO]
    [EditorBrowsableAttribute (EditorBrowsableState.Never)]
#if ONLY_1_1
    public
#endif
#if NET_2_0
    new
#endif
    IDataReader GetData (int i)
    {
      throw new NotImplementedException ();
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    string GetDataTypeName (int i)
    {
      if (IsClosed)
        throw new InvalidOperationException ("The reader is closed.");
      if (i < 0 || i >= FieldCount)
        throw new IndexOutOfRangeException ();
      return GetColumnAttributeStr (i + 1, FieldIdentifier.TypeName);
    }

    public DateTime GetDate (int i)
    {
      return GetDateTime (i);
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    DateTime GetDateTime (int i)
    {
      return (DateTime) GetValue (i);
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    decimal GetDecimal (int i)
    {
      return (decimal) GetValue (i);
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    double GetDouble (int i)
    {
      return (double) GetValue (i);
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    Type GetFieldType (int i)
    {
      if (IsClosed)
        throw new InvalidOperationException ("The reader is closed.");
      return GetColumn (i).DataType;
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    float GetFloat (int i)
    {
      return (float) GetValue (i);
    }

    [MonoTODO]
    public
#if NET_2_0
    override
#endif // NET_2_0
    Guid GetGuid (int i)
    {
      throw new NotImplementedException ();
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    short GetInt16 (int i)
    {
      return (short) GetValue (i);
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    int GetInt32 (int i)
    {
      return (int) GetValue (i);
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    long GetInt64 (int i)
    {
      return (long) GetValue (i);
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    string GetName (int i)
    {
      if (IsClosed)
        throw new InvalidOperationException ("The reader is closed.");
      return GetColumn (i).ColumnName;
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    int GetOrdinal (string value)
    {
      if (IsClosed)
        throw new InvalidOperationException ("The reader is closed.");
      if (value == null)
        throw new ArgumentNullException ("fieldName");

      int i = ColIndex (value);
      if (i == -1)
        throw new IndexOutOfRangeException ();
      return i;
    }

    [MonoTODO]
    public
#if NET_2_0
    override
#endif // NET_2_0
    DataTable GetSchemaTable ()
    {
      if (IsClosed)
        throw new InvalidOperationException ("The reader is closed.");

      // FIXME : 
      // * Map OdbcType to System.Type and assign to DataType.
      //   This will eliminate the need for IsStringType in
      //   OdbcColumn

      if (_dataTableSchema != null)
        return _dataTableSchema;
      
      DataTable dataTableSchema = null;
      // Only Results from SQL SELECT Queries 
      // get a DataTable for schema of the result
      // otherwise, DataTable is null reference
      if (cols.Length > 0) {
        dataTableSchema = new DataTable ();
        
        dataTableSchema.Columns.Add ("ColumnName", typeof (string));
        dataTableSchema.Columns.Add ("ColumnOrdinal", typeof (int));
        dataTableSchema.Columns.Add ("ColumnSize", typeof (int));
        dataTableSchema.Columns.Add ("NumericPrecision", typeof (int));
        dataTableSchema.Columns.Add ("NumericScale", typeof (int));
        dataTableSchema.Columns.Add ("IsUnique", typeof (bool));
        dataTableSchema.Columns.Add ("IsKey", typeof (bool));
        DataColumn dc = dataTableSchema.Columns["IsKey"];
        dc.AllowDBNull = true; // IsKey can have a DBNull
        dataTableSchema.Columns.Add ("BaseCatalogName", typeof (string));
        dataTableSchema.Columns.Add ("BaseColumnName", typeof (string));
        dataTableSchema.Columns.Add ("BaseSchemaName", typeof (string));
        dataTableSchema.Columns.Add ("BaseTableName", typeof (string));
        dataTableSchema.Columns.Add ("DataType", typeof(Type));
        dataTableSchema.Columns.Add ("AllowDBNull", typeof (bool));
        dataTableSchema.Columns.Add ("ProviderType", typeof (int));
        dataTableSchema.Columns.Add ("IsAliased", typeof (bool));
        dataTableSchema.Columns.Add ("IsExpression", typeof (bool));
        dataTableSchema.Columns.Add ("IsIdentity", typeof (bool));
        dataTableSchema.Columns.Add ("IsAutoIncrement", typeof (bool));
        dataTableSchema.Columns.Add ("IsRowVersion", typeof (bool));
        dataTableSchema.Columns.Add ("IsHidden", typeof (bool));
        dataTableSchema.Columns.Add ("IsLong", typeof (bool));
        dataTableSchema.Columns.Add ("IsReadOnly", typeof (bool));

        DataRow schemaRow;

        for (int i = 0; i < cols.Length; i += 1 ) {
          OdbcColumn col=GetColumn(i);

          schemaRow = dataTableSchema.NewRow ();
          dataTableSchema.Rows.Add (schemaRow);

          schemaRow ["ColumnName"]   = col.ColumnName;
          schemaRow ["ColumnOrdinal"]   = i;
          schemaRow ["ColumnSize"]   = col.MaxLength;
          schemaRow ["NumericPrecision"]   = GetColumnAttribute (i+1, FieldIdentifier.Precision);
          schemaRow ["NumericScale"]   = GetColumnAttribute (i+1, FieldIdentifier.Scale);
          schemaRow ["BaseTableName"]     = GetColumnAttributeStr (i+1, FieldIdentifier.TableName);
          schemaRow ["BaseSchemaName"]    = GetColumnAttributeStr (i+1, FieldIdentifier.SchemaName);
          schemaRow ["BaseCatalogName"]   = GetColumnAttributeStr (i+1, FieldIdentifier.CatelogName);
          schemaRow ["BaseColumnName"]   = GetColumnAttributeStr (i+1, FieldIdentifier.BaseColumnName);
          schemaRow ["DataType"]     = col.DataType;
          schemaRow ["IsUnique"]     = false;
          schemaRow ["IsKey"]     = DBNull.Value;
          schemaRow ["AllowDBNull"]   = GetColumnAttribute (i+1, FieldIdentifier.Nullable) != libodbc.SQL_NO_NULLS;
          schemaRow ["ProviderType"]   = (int) col.OdbcType;
          schemaRow ["IsAutoIncrement"]   = GetColumnAttribute (i+1, FieldIdentifier.AutoUniqueValue) == libodbc.SQL_TRUE;
          schemaRow ["IsExpression"]   = schemaRow.IsNull ("BaseTableName") || (string) schemaRow ["BaseTableName"] == String.Empty;
          schemaRow ["IsAliased"]   = (string) schemaRow ["BaseColumnName"] != (string) schemaRow ["ColumnName"];
          schemaRow ["IsReadOnly"]   = ((bool) schemaRow ["IsExpression"]
                     || GetColumnAttribute (i+1, FieldIdentifier.Updatable) == libodbc.SQL_ATTR_READONLY);

          // FIXME: all of these
          schemaRow ["IsIdentity"]   = false;
          schemaRow ["IsRowVersion"]   = false;
          schemaRow ["IsHidden"]     = false;
          schemaRow ["IsLong"]     = false;

          // FIXME: according to Brian, 
          // this does not work on MS .NET
          // however, we need it for Mono 
          // for now
          // schemaRow.AcceptChanges();
        }

        // set primary keys
        DataRow [] rows = dataTableSchema.Select ("BaseTableName <> ''",
                    "BaseCatalogName, BaseSchemaName, BaseTableName ASC");

        string lastTableName = String.Empty,
          lastSchemaName = String.Empty,
          lastCatalogName = String.Empty;
        string [] keys = null; // assumed to be sorted.
        foreach (DataRow row in rows) {
          string tableName = (string) row ["BaseTableName"];
          string schemaName = (string) row ["BaseSchemaName"];
          string catalogName = (string) row ["BaseCatalogName"];

          if (tableName != lastTableName || schemaName != lastSchemaName
              || catalogName != lastCatalogName)
            keys = GetPrimaryKeys (catalogName, schemaName, tableName);
        
          if (keys != null &&
              Array.BinarySearch (keys, (string) row ["BaseColumnName"]) >= 0) {
            row ["IsKey"] = true;
            row ["IsUnique"] = true;
            row ["AllowDBNull"] = false;
            GetColumn ( ColIndex ( (string) row ["ColumnName"])).AllowDBNull = false;
          }
          lastTableName = tableName;
          lastSchemaName = schemaName;
          lastCatalogName = catalogName;
        }
        dataTableSchema.AcceptChanges ();
      }
      return (_dataTableSchema = dataTableSchema);
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    string GetString (int i)
    {
      object ret = GetValue (i);

      if (ret != null && ret.GetType () != typeof (string))
        return Convert.ToString (ret);
      else
        return (string) GetValue (i);
    }

    [MonoTODO]
    public TimeSpan GetTime (int i)
    {
      throw new NotImplementedException ();
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    object GetValue (int i)
    {
      if (IsClosed)
        throw new InvalidOperationException ("The reader is closed.");
      if (currentRow == -1)
        throw new InvalidOperationException ("No data available.");
      if (i > cols.Length-1 || i < 0)
        throw new IndexOutOfRangeException ();

      OdbcReturn ret;
      int outsize = 0, bufsize;
      byte[] buffer;
      OdbcColumn col = GetColumn (i);
      object DataValue = null;
      ushort ColIndex = Convert.ToUInt16 (i + 1);

      // Check cached values
      if (col.Value == null) {
        // odbc help file
        // mk:@MSITStore:C:\program%20files\Microsoft%20Data%20Access%20SDK\Docs\odbc.chm::/htm/odbcc_data_types.htm
        switch (col.OdbcType) {
        case OdbcType.Bit:
          short bit_data = 0;
          ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref bit_data, 0, ref outsize);
          if (outsize != (int) OdbcLengthIndicator.NullData)
            DataValue = bit_data == 0 ? "False" : "True";
          break;
        case OdbcType.Numeric:
        case OdbcType.Decimal:
          bufsize = 50;
          buffer = new byte [bufsize];  // According to sqlext.h, use SQL_CHAR for decimal.
          // FIXME : use Numeric.
          ret = libodbc.SQLGetData (hstmt, ColIndex, SQL_C_TYPE.CHAR, buffer, bufsize, ref outsize);
          if (outsize!=-1) {
            byte [] temp = new byte [outsize];
            for (int j = 0; j < outsize; j++)
              temp [j] = buffer [j];
            DataValue = Decimal.Parse (Encoding.Default.GetString (temp),
              CultureInfo.InvariantCulture);
          }
          break;
        case OdbcType.TinyInt:
          short short_data = 0;
          ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref short_data, 0, ref outsize);
          DataValue = Convert.ToByte (short_data);
          break;
        case OdbcType.Int:
          int int_data = 0;
          ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref int_data, 0, ref outsize);
          DataValue = int_data;
          break;

        case OdbcType.SmallInt:
          short sint_data = 0;
          ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref sint_data, 0, ref outsize);
          DataValue = sint_data;
          break;

        case OdbcType.BigInt:
          long long_data = 0;
          ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref long_data, 0, ref outsize);
          DataValue = long_data;
          break;
        case OdbcType.NChar:
          bufsize = 255;
          buffer = new byte [bufsize];
          ret = libodbc.SQLGetData (hstmt, ColIndex, SQL_C_TYPE.WCHAR, buffer, bufsize, ref outsize);
          if (outsize != (int) OdbcLengthIndicator.NullData)
            if (!(ret == OdbcReturn.SuccessWithInfo
                   && outsize == (int) OdbcLengthIndicator.NoTotal))
              DataValue = Encoding.Unicode.GetString (buffer, 0, outsize);
          break;
        case OdbcType.NText:
        case OdbcType.NVarChar:
          bufsize = (col.MaxLength < 127 ? (col.MaxLength*2+1) : 255);
          buffer = new byte[bufsize];  // According to sqlext.h, use SQL_CHAR for both char and varchar
          StringBuilder sb = new StringBuilder ();
          do {
            ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, buffer, bufsize, ref outsize);
            if (ret == OdbcReturn.Error)
              break;
            // Fix for strance ODBC drivers (like psqlODBC)
            if (ret == OdbcReturn.Success && outsize==-1)
              ret = OdbcReturn.NoData;

            if (ret != OdbcReturn.NoData && outsize > 0) {
              string value = null;

              if (outsize < bufsize)
                value = Encoding.Unicode.GetString (buffer, 0, outsize);
              else
                value = Encoding.Unicode.GetString (buffer, 0, bufsize);

              sb.Append (RemoveTrailingNullChar (value));
            }
          } while (ret != OdbcReturn.NoData);
          DataValue = sb.ToString ();
          break;
        case OdbcType.Text:
        case OdbcType.VarChar:
          bufsize = (col.MaxLength < 255 ? (col.MaxLength+1) : 255);
          buffer = new byte[bufsize];  // According to sqlext.h, use SQL_CHAR for both char and varchar
          StringBuilder sb1 = new StringBuilder ();
          do { 
            ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, buffer, bufsize, ref outsize);
            if (ret == OdbcReturn.Error)
              break;
            // Fix for strance ODBC drivers (like psqlODBC)
            if (ret == OdbcReturn.Success && outsize==-1)
              ret = OdbcReturn.NoData;
            if (ret != OdbcReturn.NoData && outsize > 0) {
              if (outsize < bufsize)
                sb1.Append (Encoding.Default.GetString (buffer, 0, outsize));
              else
                sb1.Append (Encoding.Default.GetString (buffer, 0, bufsize - 1));
            }
          } while (ret != OdbcReturn.NoData);
          DataValue = sb1.ToString ();
          break;
        case OdbcType.Real:
          float float_data = 0;
          ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref float_data, 0, ref outsize);
          DataValue = float_data;
          break;
        case OdbcType.Double:
          double double_data = 0;
          ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref double_data, 0, ref outsize);
          DataValue = double_data;
          break;
        case OdbcType.Timestamp:
        case OdbcType.DateTime:
        case OdbcType.Date:
        case OdbcType.Time:
          OdbcTimestamp ts_data = new OdbcTimestamp();
          ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref ts_data, 0, ref outsize);
          if (outsize != -1) {// This means SQL_NULL_DATA
            if (col.OdbcType == OdbcType.Time) {
              // libodbc returns value in first three fields for OdbcType.Time 
              DataValue = new System.TimeSpan (ts_data.year, ts_data.month, ts_data.day);
            } else {
              DataValue = new DateTime(ts_data.year, ts_data.month,
                                       ts_data.day, ts_data.hour, ts_data.minute,
                                       ts_data.second);
              if (ts_data.fraction != 0)
                DataValue = ((DateTime) DataValue).AddTicks ((long)ts_data.fraction / 100);
            }
          }
          break;
        case OdbcType.VarBinary :
        case OdbcType.Image :
          bufsize = (col.MaxLength < 255 && col.MaxLength > 0 ? col.MaxLength : 255);
          buffer= new byte [bufsize];
          ArrayList al = new ArrayList ();
          //get the size of data to be returned.
          ret = libodbc.SQLGetData (hstmt, ColIndex, SQL_C_TYPE.BINARY, buffer, 0, ref outsize);
          if (outsize != (int) OdbcLengthIndicator.NullData) {
            do {
              ret = libodbc.SQLGetData (hstmt, ColIndex, SQL_C_TYPE.BINARY, buffer, bufsize, ref outsize);
              if (ret == OdbcReturn.Error)
                break;
              if (ret != OdbcReturn.NoData && outsize != -1) {
                if (outsize < bufsize) {
                  byte [] tmparr = new byte [outsize];
                  Array.Copy (buffer, 0, tmparr, 0, outsize);
                  al.AddRange (tmparr);
                } else
                  al.AddRange (buffer);
              } else {
                break;
              }
            } while (ret != OdbcReturn.NoData);
          }
          DataValue = al.ToArray (typeof (byte));
          break;
        case OdbcType.Binary :
          bufsize = col.MaxLength;
          buffer = new byte [bufsize];
          long read = GetBytes (i, 0, buffer, 0, bufsize);
          ret = OdbcReturn.Success;
          DataValue = buffer;
          break;
        default:
          bufsize = 255;
          buffer = new byte[bufsize];
          ret = libodbc.SQLGetData (hstmt, ColIndex, SQL_C_TYPE.CHAR, buffer, bufsize, ref outsize);
          if (outsize != (int) OdbcLengthIndicator.NullData)
            if (! (ret == OdbcReturn.SuccessWithInfo
                   && outsize == (int) OdbcLengthIndicator.NoTotal))
              DataValue = Encoding.Default.GetString (buffer, 0, outsize);
          break;
        }

        if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo) && (ret!=OdbcReturn.NoData))
          throw Connection.CreateOdbcException (OdbcHandleType.Stmt, hstmt);

        if (outsize == -1) // This means SQL_NULL_DATA 
          col.Value = DBNull.Value;
        else
          col.Value = DataValue;
      }
      return col.Value;
    }
    
    public 
#if NET_2_0
    override
#endif // NET_2_0
    int GetValues (object [] values)
    {
      int numValues = 0;

      if (IsClosed)
        throw new InvalidOperationException ("The reader is closed.");
      if (currentRow == -1)
        throw new InvalidOperationException ("No data available.");

      // copy values
      for (int i = 0; i < values.Length; i++) {
        if (i < FieldCount) {
          values [i] = GetValue (i);
        } else {
          values [i] = null;
        }
      }

      // get number of object instances in array
      if (values.Length < FieldCount)
        numValues = values.Length;
      else if (values.Length == FieldCount)
        numValues = FieldCount;
      else
        numValues = FieldCount;

      return numValues;
    }

#if ONLY_1_1
    void IDisposable.Dispose ()
    {
      Dispose (true);
      GC.SuppressFinalize (this);
    }

    IEnumerator IEnumerable.GetEnumerator ()
    {
      return new DbEnumerator (this);
    }
#endif // ONLY_1_1

#if NET_2_0
    public override IEnumerator GetEnumerator ()
    {
      return new DbEnumerator (this);
    }
#endif

#if NET_2_0
    protected override
#endif
    void Dispose (bool disposing)
    {
      if (disposed)
        return;

      if (disposing) {
        // dispose managed resources
        Close ();
      }

      command = null;
      cols = null;
      _dataTableSchema = null;
      disposed = true;
    }

    public
#if NET_2_0
    override
#endif // NET_2_0
    bool IsDBNull (int i)
    {
      return (GetValue (i) is DBNull);
    }

    /// <remarks>
    /// Move to the next result set.
    /// </remarks>
    public
#if NET_2_0
    override
#endif // NET_2_0
    bool NextResult ()
    {
      OdbcReturn ret = OdbcReturn.Success;
      ret = libodbc.SQLMoreResults (hstmt);
      if (ret == OdbcReturn.Success) {
        short colcount = 0;
        libodbc.SQLNumResultCols (hstmt, ref colcount);
        cols = new OdbcColumn [colcount];
        _dataTableSchema = null; // force fresh creation
        GetColumns ();
      }
      return (ret == OdbcReturn.Success);
    }

    /// <remarks>
    /// Load the next row in the current result set.
    /// </remarks>
    private bool NextRow ()
    {
      OdbcReturn ret = libodbc.SQLFetch (hstmt);
      if (ret != OdbcReturn.Success)
        currentRow = -1;
      else
        currentRow++;

      // Clear cached values from last record
      foreach (OdbcColumn col in cols) {
        if (col != null)
          col.Value = null;
      }
      return (ret == OdbcReturn.Success);
    }

    private int GetColumnAttribute (int column, FieldIdentifier fieldId)
    {
      OdbcReturn ret = OdbcReturn.Error;
      byte [] buffer = new byte [255];
      short outsize = 0;
      int val = 0;
      ret = libodbc.SQLColAttribute (hstmt, (short)column, fieldId, 
              buffer, (short)buffer.Length, 
              ref outsize, ref val);
      if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
        throw Connection.CreateOdbcException (
          OdbcHandleType.Stmt, hstmt);
      return val;
    }

    private string GetColumnAttributeStr (int column, FieldIdentifier fieldId)
    {
      OdbcReturn ret = OdbcReturn.Error;
      byte [] buffer = new byte [255];
      short outsize = 0;
      int val = 0;
      ret = libodbc.SQLColAttribute (hstmt, (short)column, fieldId,
              buffer, (short)buffer.Length,
              ref outsize, ref val);
      if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
        throw Connection.CreateOdbcException (
          OdbcHandleType.Stmt, hstmt);
      string value = string.Empty;
      if (outsize > 0)
        value = Encoding.Unicode.GetString (buffer, 0, outsize);
      return value;
    }

    private string [] GetPrimaryKeys (string catalog, string schema, string table)
    {
      if (cols.Length <= 0)
        return new string [0];

      ArrayList keys = null;
      try {
        keys = GetPrimaryKeysBySQLPrimaryKey (catalog, schema, table);
      } catch (OdbcException) {
        try {
          keys = GetPrimaryKeysBySQLStatistics (catalog, schema, table);
        } catch (OdbcException) {
        }
      }
      if (keys == null)
        return null;
      keys.Sort ();
      return (string []) keys.ToArray (typeof (string));
    }

    private ArrayList GetPrimaryKeysBySQLPrimaryKey (string catalog, string schema, string table)
    {
      ArrayList keys = new ArrayList ();
      IntPtr handle = IntPtr.Zero;
      OdbcReturn ret;
      try {
        ret=libodbc.SQLAllocHandle(OdbcHandleType.Stmt, 
                 command.Connection.hDbc, ref handle);
        if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
          throw Connection.CreateOdbcException (
            OdbcHandleType.Dbc, Connection.hDbc);

        ret = libodbc.SQLPrimaryKeys (handle, catalog, -3,
          schema, -3, table, -3);
        if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
          throw Connection.CreateOdbcException (OdbcHandleType.Stmt, handle);

        int length = 0;
        byte [] primaryKey = new byte [255];

        ret = libodbc.SQLBindCol (handle, 4, SQL_C_TYPE.CHAR, primaryKey, primaryKey.Length, ref length);
        if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
          throw Connection.CreateOdbcException (OdbcHandleType.Stmt, handle);

        while (true) {
          ret = libodbc.SQLFetch (handle);
          if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
            break;
          string pkey = Encoding.Default.GetString (primaryKey, 0, length);
          keys.Add (pkey);
        }
      } finally {
        if (handle != IntPtr.Zero) {
          ret = libodbc.SQLFreeStmt (handle, libodbc.SQLFreeStmtOptions.Close);
          if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
            throw Connection.CreateOdbcException (OdbcHandleType.Stmt, handle);

          ret = libodbc.SQLFreeHandle( (ushort) OdbcHandleType.Stmt, handle);
          if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
            throw Connection.CreateOdbcException (OdbcHandleType.Stmt, handle);
        }
      }
      return keys;
    }
    
    private unsafe ArrayList GetPrimaryKeysBySQLStatistics (string catalog, string schema, string table)
    {
      ArrayList keys = new ArrayList ();
      IntPtr handle = IntPtr.Zero;
      OdbcReturn ret;
      try {
        ret=libodbc.SQLAllocHandle(OdbcHandleType.Stmt, 
                 command.Connection.hDbc, ref handle);
        if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
          throw Connection.CreateOdbcException (
            OdbcHandleType.Dbc, Connection.hDbc);

        ret = libodbc.SQLStatistics (handle, catalog, -3,  
                   schema, -3, 
                   table, -3,
                   libodbc.SQL_INDEX_UNIQUE,
                   libodbc.SQL_QUICK);
        if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
          throw Connection.CreateOdbcException (OdbcHandleType.Stmt, handle);

        // NON_UNIQUE
        int  nonUniqueLength = 0;
        short nonUnique = libodbc.SQL_FALSE;
        ret = libodbc.SQLBindCol (handle, 4, SQL_C_TYPE.SHORT, ref (short) nonUnique, sizeof (short), ref nonUniqueLength);
        if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
          throw Connection.CreateOdbcException (OdbcHandleType.Stmt, handle);

        // COLUMN_NAME
        int length = 0;
        byte [] colName = new byte [255];
        ret = libodbc.SQLBindCol (handle, 9, SQL_C_TYPE.CHAR, colName, colName.Length, ref length);
        if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
          throw Connection.CreateOdbcException (OdbcHandleType.Stmt, handle);
      
        while (true) {
          ret = libodbc.SQLFetch (handle);
          if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
            break;
          if (nonUnique == libodbc.SQL_TRUE) {
            string pkey = Encoding.Default.GetString (colName, 0, length);
            keys.Add (pkey);
            break;
          }
        }
      } finally {
        if (handle != IntPtr.Zero) {
          ret = libodbc.SQLFreeStmt (handle, libodbc.SQLFreeStmtOptions.Close);
          if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
            throw Connection.CreateOdbcException (OdbcHandleType.Stmt, handle);

          ret = libodbc.SQLFreeHandle ((ushort) OdbcHandleType.Stmt, handle);
          if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
            throw Connection.CreateOdbcException (OdbcHandleType.Stmt, handle);
        }
      }
      return keys;
    }
    
    public
#if NET_2_0
    override
#endif // NET_2_0
    bool Read ()
    {
      return NextRow ();
    }

    static string RemoveTrailingNullChar (string value)
    {
      return value.TrimEnd ('\0');
    }

    #endregion
  }
}
www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.