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 ();
char[] charBuffer = new char[bufsize];
Decoder unicodeDecoder = Encoding.Unicode.GetDecoder ();
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.Success || ret == OdbcReturn.SuccessWithInfo) {
if (outsize >= bufsize || outsize == (int)OdbcLengthIndicator.NoTotal)
outsize = bufsize;
int charCount = unicodeDecoder.GetChars (buffer, 0, outsize, charBuffer, 0);
string strValue = new String (charBuffer, 0, charCount);
sb.Append (RemoveTrailingNullChar (strValue));
}
} while (ret != OdbcReturn.NoData);
DataValue = sb.ToString ();
charBuffer = null;
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 ();
charBuffer = new char[bufsize];
Decoder defaultDecoder = Encoding.Default.GetDecoder();
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.Success || ret == OdbcReturn.SuccessWithInfo) {
if (outsize >= bufsize || outsize == (int)OdbcLengthIndicator.NoTotal)
outsize = bufsize - 1;
int charCount = defaultDecoder.GetChars(buffer, 0, outsize, charBuffer, 0);
sb1.Append(charBuffer, 0, charCount);
}
} 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;
}