using System.ComponentModel;
using System.Data;
using System.Data.Common;
-#if NET_2_0
-using System.Data.ProviderBase;
-#endif // NET_2_0
using System.Text;
namespace System.Data.Odbc
{
#if NET_2_0
- public sealed class OdbcDataReader : DbDataReaderBase
+ public sealed class OdbcDataReader : DbDataReader
#else
public sealed class OdbcDataReader : MarshalByRefObject, IDataReader, IDisposable, IDataRecord, IEnumerable
#endif
private int currentRow;
private OdbcColumn[] cols;
private IntPtr hstmt;
-#if ONLY_1_1
+ private int _recordsAffected = -1;
+ bool disposed = false;
+ private DataTable _dataTableSchema;
private CommandBehavior behavior;
-#endif // ONLY_1_1
#endregion
#region Constructors
internal OdbcDataReader (OdbcCommand command, CommandBehavior behavior)
-#if NET_2_0
- : base (behavior)
-#endif // NET_2_0
{
this.command = command;
-#if ONLY_1_1
- this.CommandBehavior=behavior;
-#endif // ONLY_1_1
+ this.CommandBehavior = behavior;
open = true;
currentRow = -1;
- hstmt=command.hStmt;
+ hstmt = command.hStmt;
// Init columns array;
- short colcount=0;
- libodbc.SQLNumResultCols(hstmt, ref colcount);
- cols=new OdbcColumn[colcount];
+ short colcount = 0;
+ libodbc.SQLNumResultCols (hstmt, ref colcount);
+ cols = new OdbcColumn [colcount];
GetSchemaTable ();
}
+ internal OdbcDataReader (OdbcCommand command, CommandBehavior behavior,
+ int recordAffected) : this (command, behavior)
+ {
+ _recordsAffected = recordAffected;
+ }
+
+
#endregion
#region Properties
-#if ONLY_1_1
private CommandBehavior CommandBehavior
{
get { return behavior; }
set { value = behavior; }
}
-#endif // ONLY_1_1
-#if NET_2_0
- [MonoTODO]
- public override int VisibleFieldCount
- {
- get { throw new NotImplementedException (); }
- }
-
- [MonoTODO]
- protected override bool IsValidRow
- {
- get { throw new NotImplementedException (); }
- }
-
-#endif // NET_2_0
public
#if NET_2_0
override
#if NET_2_0
override
#endif // NET_2_0
- object this[int index] {
+ object this [int index] {
get {
return (object) GetValue (index);
}
}
- [MonoTODO]
public
#if NET_2_0
override
#endif // NET_2_0
int RecordsAffected {
get {
- return -1;
+ return _recordsAffected;
}
}
#region Methods
- private int ColIndex(string colname)
+ private int ColIndex (string colname)
{
- int i=0;
+ int i = 0;
foreach (OdbcColumn col in cols)
{
if (col != null) {
}
// Dynamically load column descriptions as needed.
- private OdbcColumn GetColumn(int ordinal)
+ private OdbcColumn GetColumn (int ordinal)
{
- if (cols[ordinal]==null)
- {
- short bufsize=255;
- byte[] colname_buffer=new byte[bufsize];
+ 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 new OdbcException(new OdbcError("SQLDescribeCol",OdbcHandleType.Stmt,hstmt));
- colname=System.Text.Encoding.Default.GetString(colname_buffer);
- colname=colname.Replace((char) 0,' ').Trim();
- OdbcColumn c=new OdbcColumn(colname, (SQL_TYPE) dt);
- c.AllowDBNull=(Nullable!=0);
- c.Digits=DecDigits;
- if (c.IsStringType)
- c.MaxLength=(int)ColSize;
- cols[ordinal]=c;
+ 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 new OdbcException (new OdbcError ("SQLDescribeCol", OdbcHandleType.Stmt, hstmt));
+ colname = System.Text.Encoding.Default.GetString (colname_buffer);
+ colname = colname.Replace ((char) 0, ' ').Trim ();
+ 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];
+ return cols [ordinal];
}
public
void Close ()
{
// FIXME : have to implement output parameter binding
- OdbcReturn ret = libodbc.SQLFreeStmt (hstmt, libodbc.SQLFreeStmtOptions.Close);
- if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
- throw new OdbcException(new OdbcError("SQLCloseCursor",OdbcHandleType.Stmt,hstmt));
-
open = false;
currentRow = -1;
- ret = libodbc.SQLFreeHandle( (ushort) OdbcHandleType.Stmt, hstmt);\r
- if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
- throw new OdbcException(new OdbcError("SQLFreeHandle",OdbcHandleType.Stmt,hstmt));
+ this.command.FreeIfNotPrepared ();
- if ((this.CommandBehavior & CommandBehavior.CloseConnection)==CommandBehavior.CloseConnection)
- this.command.Connection.Close();
+ if ((this.CommandBehavior & CommandBehavior.CloseConnection) == CommandBehavior.CloseConnection) {
+ this.command.Connection.Close ();
+ }
}
~OdbcDataReader ()
{
- if (open)
- Close ();
+ this.Dispose (false);
}
public
length = buffer == null ? 0 : length;
ret=libodbc.SQLGetData (hstmt, (ushort) (ordinal+1), SQL_C_TYPE.BINARY, tbuff, length,
- ref outsize);
+ ref outsize);
if (ret == OdbcReturn.NoData)
return 0;
[MonoTODO]
[EditorBrowsableAttribute (EditorBrowsableState.Never)]
- public
+#if ONLY_1_1
+ public
+#endif
#if NET_2_0
new
-#endif // NET_2_0
+#endif
IDataReader GetData (int ordinal)
{
throw new NotImplementedException ();
#endif // NET_2_0
string GetDataTypeName (int index)
{
- return GetColumn(index).OdbcType.ToString();
+ return GetColumn (index).OdbcType.ToString ();
}
- public DateTime GetDate(int ordinal) {
- return GetDateTime(ordinal);
+ public DateTime GetDate (int ordinal) {
+ return GetDateTime (ordinal);
}
public
#endif // NET_2_0
DateTime GetDateTime (int ordinal)
{
- return (DateTime) GetValue(ordinal);
+ return (DateTime) GetValue (ordinal);
}
- [MonoTODO]
public
#if NET_2_0
override
#endif // NET_2_0
decimal GetDecimal (int ordinal)
{
- throw new NotImplementedException ();
+ return (decimal) GetValue (ordinal);
}
public
#endif // NET_2_0
double GetDouble (int ordinal)
{
- return (double) GetValue(ordinal);
+ return (double) GetValue (ordinal);
}
public
#endif // NET_2_0
float GetFloat (int ordinal)
{
- return (float) GetValue(ordinal);
+ return (float) GetValue (ordinal);
}
[MonoTODO]
#endif // NET_2_0
short GetInt16 (int ordinal)
{
- return (short) GetValue(ordinal);
+ return (short) GetValue (ordinal);
}
public
#endif // NET_2_0
int GetInt32 (int ordinal)
{
- return (int) GetValue(ordinal);
+ return (int) GetValue (ordinal);
}
public
#endif // NET_2_0
long GetInt64 (int ordinal)
{
- return (long) GetValue(ordinal);
+ return (long) GetValue (ordinal);
}
public
// * Map OdbcType to System.Type and assign to DataType.
// This will eliminate the need for IsStringType in
// OdbcColumn.
- // * Cache this DataTable so that it is not contacting
- // datasource everytime for the same result set.
+ 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)
{
- string [] keys = GetPrimaryKeys ();
-
dataTableSchema = new DataTable ();
dataTableSchema.Columns.Add ("ColumnName", typeof (string));
dataTableSchema.Columns.Add ("IsReadOnly", typeof (bool));
DataRow schemaRow;
-
+
for (int i = 0; i < cols.Length; i += 1 )
{
+ string baseTableName = String.Empty;
+ bool isKey = false;
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["IsUnique"] = false;
- schemaRow["IsKey"] = DBNull.Value;
-
- for (int j=0; j < keys.Length; j++) {
- if (keys [j] == col.ColumnName) {
- schemaRow ["IsUnique"] = true;
- schemaRow ["IsKey"] = true;
- }
- }
-
- schemaRow["BaseCatalogName"] = "";
- schemaRow["BaseColumnName"] = "";
- schemaRow["BaseSchemaName"] = "";
- schemaRow["BaseTableName"] = "";
-
- try {
- schemaRow["BaseColumnName"] = GetColumnAttributeStr (i+1, FieldIdentifier.BaseColumnName);
- schemaRow["BaseTableName"] = GetColumnAttributeStr (i+1, FieldIdentifier.BaseTableName);
- } catch (Exception e) {
- // ignore these properties as they are optional.
- }
-
-
+ 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;
- schemaRow["DataType"] = col.DataType;
-
- schemaRow["AllowDBNull"] = col.AllowDBNull;
-
- schemaRow["ProviderType"] = (int) col.OdbcType;
- // TODO: all of these
- schemaRow["IsAliased"] = false;
- schemaRow["IsExpression"] = false;
- schemaRow["IsIdentity"] = false;
- schemaRow["IsAutoIncrement"] = GetColumnAttribute (i+1, FieldIdentifier.AutoUniqueValue) == 1;
- schemaRow["IsRowVersion"] = false;
- schemaRow["IsHidden"] = false;
- schemaRow["IsLong"] = false;
- schemaRow["IsReadOnly"] = false;
// FIXME: according to Brian,
// this does not work on MS .NET
// however, we need it for Mono
// for now
- schemaRow.AcceptChanges();
+ // schemaRow.AcceptChanges();
}
- dataTableSchema.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;
+ return (_dataTableSchema = dataTableSchema);
}
public
#endif // NET_2_0
string GetString (int ordinal)
{
- return (string) GetValue(ordinal);
+ return (string) GetValue (ordinal);
}
[MonoTODO]
if (currentRow == -1)
throw new IndexOutOfRangeException ();
- if (ordinal>cols.Length-1 || ordinal<0)
+ if (ordinal > cols.Length-1 || ordinal < 0)
throw new IndexOutOfRangeException ();
OdbcReturn ret;
- int outsize=0, bufsize;
+ int outsize = 0, bufsize;
byte[] buffer;
- OdbcColumn col=GetColumn(ordinal);
- object DataValue=null;
- ushort ColIndex=Convert.ToUInt16(ordinal+1);
+ OdbcColumn col = GetColumn (ordinal);
+ object DataValue = null;
+ ushort ColIndex = Convert.ToUInt16 (ordinal+1);
// Check cached values
- if (col.Value==null)
- {
+ 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.Numeric:
- case OdbcType.Decimal:
- bufsize=50;
- buffer=new byte[bufsize]; // According to sqlext.h, use SQL_CHAR for decimal.
- ret=libodbc.SQLGetData(hstmt, ColIndex, col.SqlCType, buffer, bufsize, ref outsize);
- if (outsize!=-1) {
- byte[] temp = new byte[outsize];
- for (int i=0;i<outsize;i++)
- temp[i]=buffer[i];
- DataValue=Decimal.Parse(System.Text.Encoding.Default.GetString(temp));
+ 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 i = 0;i<outsize;i++)
+ temp[i] = buffer[i];
+ DataValue = Decimal.Parse(System.Text.Encoding.Default.GetString(temp));
+ }
+ break;
+ case OdbcType.TinyInt:
+ short short_data = 0;
+ ret = libodbc.SQLGetData (hstmt, ColIndex, col.SqlCType, ref short_data, 0, ref outsize);
+ DataValue = System.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.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;
+ if (ret != OdbcReturn.NoData && outsize!=-1) {
+ if (outsize < bufsize)
+ sb.Append (System.Text.Encoding.Unicode.GetString(buffer,0,outsize));
+ else
+ sb.Append (System.Text.Encoding.Unicode.GetString(buffer,0,bufsize));
}
- break;
- case OdbcType.TinyInt:
- short short_data=0;
- ret=libodbc.SQLGetData(hstmt, ColIndex, col.SqlCType, ref short_data, 0, ref outsize);
- DataValue=System.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.NVarChar:
- bufsize=col.MaxLength*2+1; // Unicode is double byte
- buffer=new byte[bufsize];
- ret=libodbc.SQLGetData(hstmt, ColIndex, col.SqlCType, buffer, bufsize, ref outsize);
- if (outsize!=-1)
- DataValue=System.Text.Encoding.Unicode.GetString(buffer,0,outsize);
- break;
- case OdbcType.VarChar:
- bufsize=col.MaxLength+1;
- buffer=new byte[bufsize]; // According to sqlext.h, use SQL_CHAR for both char and varchar
- ret=libodbc.SQLGetData(hstmt, ColIndex, col.SqlCType, buffer, bufsize, ref outsize);
- if (outsize!=-1)
- DataValue=System.Text.Encoding.Default.GetString(buffer,0,outsize);
- 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
- DataValue=new DateTime(ts_data.year,ts_data.month,ts_data.day,ts_data.hour,
- ts_data.minute,ts_data.second,Convert.ToInt32(ts_data.fraction));
- break;
- case OdbcType.Binary :
- case OdbcType.Image :
- bufsize = col.MaxLength + 1;
- buffer = new byte [bufsize];
- long read = GetBytes (ordinal, 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=System.Text.Encoding.Default.GetString(buffer, 0, outsize);
- break;
+ } 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;
+ if (ret != OdbcReturn.NoData && outsize!=-1) {
+ if (outsize < bufsize)
+ sb1.Append (System.Text.Encoding.Default.GetString(buffer,0,outsize));
+ else
+ sb1.Append (System.Text.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
+ 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 : 255);
+ buffer= new byte [bufsize];
+ ArrayList al = new ArrayList ();
+ 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);
+ }
+ } while (ret != OdbcReturn.NoData);
+ DataValue = al.ToArray (typeof (byte));
+ break;
+ case OdbcType.Binary :
+ bufsize = col.MaxLength;
+ buffer = new byte [bufsize];
+ long read = GetBytes (ordinal, 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 = System.Text.Encoding.Default.GetString(buffer, 0, outsize);
+ break;
}
- if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
+ if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo) && (ret!=OdbcReturn.NoData))
throw new OdbcException(new OdbcError("SQLGetData",OdbcHandleType.Stmt,hstmt));
if (outsize==-1) // This means SQL_NULL_DATA
- col.Value=DBNull.Value;
+ col.Value = DBNull.Value;
else
- col.Value=DataValue;
+ col.Value = DataValue;
}
return col.Value;
}
// copy values
for (int i = 0; i < values.Length; i++) {
if (i < FieldCount) {
- values[i] = GetValue(i);
+ values[i] = GetValue (i);
}
else {
values[i] = null;
#if ONLY_1_1
- [MonoTODO]
- IDataReader IDataRecord.GetData (int ordinal)
+ void IDisposable.Dispose ()
{
- throw new NotImplementedException ();
+ Dispose (true);
+ GC.SuppressFinalize (this);
}
- [MonoTODO]
- void IDisposable.Dispose ()
+ IEnumerator IEnumerable.GetEnumerator ()
{
+ return new DbEnumerator (this);
}
+#endif // ONLY_1_1
- IEnumerator IEnumerable.GetEnumerator ()
+
+#if NET_2_0
+ public override IEnumerator GetEnumerator ()
{
return new DbEnumerator (this);
}
-#endif // ONLY_1_1
+#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
#endif // NET_2_0
bool IsDBNull (int ordinal)
{
- return (GetValue(ordinal) is DBNull);
+ return (GetValue (ordinal) is DBNull);
}
/// <remarks>
short colcount = 0;
libodbc.SQLNumResultCols (hstmt, ref colcount);
cols = new OdbcColumn [colcount];
+ _dataTableSchema = null; // force fresh creation
GetSchemaTable ();
}
return (ret==OdbcReturn.Success);
/// <remarks>
/// Load the next row in the current result set.
/// </remarks>
- public bool NextRow ()
+ private bool NextRow ()
{
OdbcReturn ret=libodbc.SQLFetch (hstmt);
if (ret != OdbcReturn.Success)
{
OdbcReturn ret = OdbcReturn.Error;
byte [] buffer = new byte [255];
- int outsize = 0;
+ short outsize = 0;
int val = 0;
- ret = libodbc.SQLColAttribute (hstmt, column, fieldId,
- buffer, buffer.Length,
+ ret = libodbc.SQLColAttribute (hstmt, (short)column, fieldId,
+ buffer, (short)buffer.Length,
ref outsize, ref val);
if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
throw new OdbcException (new OdbcError ("SQLColAttribute",
{
OdbcReturn ret = OdbcReturn.Error;
byte [] buffer = new byte [255];
- int outsize = 0;
+ short outsize = 0;
int val = 0;
- ret = libodbc.SQLColAttribute (hstmt, column, fieldId,
- buffer, buffer.Length,
+ ret = libodbc.SQLColAttribute (hstmt, (short)column, fieldId,
+ buffer, (short)buffer.Length,
ref outsize, ref val);
if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
throw new OdbcException (new OdbcError ("SQLColAttribute",
return value;
}
- private string [] GetPrimaryKeys ()
+ private string [] GetPrimaryKeys (string catalog, string schema, string table)
{
if (cols.Length <= 0)
return new string [0];
- string [] keys = new string [cols.Length];
- IntPtr handle = IntPtr.Zero;
- OdbcReturn ret = OdbcReturn.Error;
+ ArrayList keys = null;
try {
- ret=libodbc.SQLAllocHandle(OdbcHandleType.Stmt,
- command.Connection.hDbc, ref handle);
+ 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 new OdbcException(new OdbcError("SQLAllocHandle",
- OdbcHandleType.Dbc,
- command.Connection.hDbc));
-
- string tableName = GetColumnAttributeStr (1, FieldIdentifier.TableName);
- string schemaName = GetColumnAttributeStr (1, FieldIdentifier.SchemaName);
- string catalogName = GetColumnAttributeStr (1, FieldIdentifier.CatelogName);
- ret = libodbc.SQLPrimaryKeys (handle, catalogName, -3,
- schemaName, -3,
- tableName, -3);
- if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
- throw new OdbcException (new OdbcError ("SQLPrimaryKeys", OdbcHandleType.Stmt, handle));
-
- int length = 0;
- byte [] primaryKey = new byte [255];
+ OdbcHandleType.Dbc,
+ command.Connection.hDbc));
+
+ ret = libodbc.SQLPrimaryKeys (handle, catalog, -3,
+ schema, -3,
+ table, -3);
+ if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
+ throw new OdbcException (new OdbcError ("SQLPrimaryKeys", OdbcHandleType.Stmt, handle));
- ret = libodbc.SQLBindCol (handle, 4, SQL_C_TYPE.CHAR, primaryKey, primaryKey.Length, ref length);
- if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
- throw new OdbcException (new OdbcError ("SQLBindCol", OdbcHandleType.Stmt, handle));
+ int length = 0;
+ byte [] primaryKey = new byte [255];
- int i = 0;
- while (true) {
- ret = libodbc.SQLFetch (handle);
- if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
- break;
- string pkey = Encoding.Default.GetString (primaryKey);
- keys [i++] = pkey;
+ ret = libodbc.SQLBindCol (handle, 4, SQL_C_TYPE.CHAR, primaryKey, primaryKey.Length, ref length);
+ if (ret != OdbcReturn.Success && ret != OdbcReturn.SuccessWithInfo)
+ throw new OdbcException (new OdbcError ("SQLBindCol", OdbcHandleType.Stmt, handle));
+
+ int i = 0;
+ 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 new OdbcException(new OdbcError("SQLFreeStmt",OdbcHandleType.Stmt,handle));
+
+ ret = libodbc.SQLFreeHandle( (ushort) OdbcHandleType.Stmt, handle);
+ if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
+ throw new OdbcException(new OdbcError("SQLFreeHandle",OdbcHandleType.Stmt,handle));
}
- } catch (OdbcException){
- // FIXME: Try using SQLStatistics
+ }
+ 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 new OdbcException(new OdbcError("SQLAllocHandle",
+ OdbcHandleType.Dbc,
+ command.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 new OdbcException (new OdbcError ("SQLStatistics", 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 new OdbcException (new OdbcError ("SQLBindCol", 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 new OdbcException (new OdbcError ("SQLBindCol", OdbcHandleType.Stmt, handle));
+
+ int i = 0;
+ 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);
throw new OdbcException(new OdbcError("SQLFreeStmt",OdbcHandleType.Stmt,handle));
ret = libodbc.SQLFreeHandle( (ushort) OdbcHandleType.Stmt, handle);
- if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
- throw new OdbcException(new OdbcError("SQLFreeHandle",OdbcHandleType.Stmt,handle));
+ if ((ret!=OdbcReturn.Success) && (ret!=OdbcReturn.SuccessWithInfo))
+ throw new OdbcException(new OdbcError("SQLFreeHandle",OdbcHandleType.Stmt,handle));
}
-
- }
-
- return keys;
- }
-
+ }
+ return keys;
+ }
+
public
#if NET_2_0
override
return NextRow ();
}
-#if NET_2_0
- [MonoTODO]
- public override object GetProviderSpecificValue (int i)
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- public override int GetProviderSpecificValues (object[] values)
- {
- throw new NotImplementedException ();
- }
-
- [MonoTODO]
- public override Type GetFieldProviderSpecificType (int i)
- {
- throw new NotImplementedException ();
- }
-
-#endif // NET_2_0
-
-
#endregion
}
}