// Tim Coleman (tim@timcoleman.com)
// Sebastien Pouliot (spouliot@motus.com)
// Daniel Morgan (danielmorgan@verizon.net)
+// Veerapuram Varadhan (vvaradhan@novell.com)
//
// Copyright (C) 2002 Tim Coleman
// Portions (C) 2003 Motus Technologies Inc. (http://www.motus.com)
// Portions (C) 2003,2005 Daniel Morgan
-//
+// Portions (C) 2008,2009 Novell Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining
using Mono.Security.Protocol.Ntlm;
using System;
+using System.IO;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Net.Sockets;
+using System.Globalization;
+using System.Security;
using System.Text;
+using System.Runtime.InteropServices;
-namespace Mono.Data.Tds.Protocol {
- public abstract class Tds : Component, ITds
+namespace Mono.Data.Tds.Protocol
+{
+ public abstract class Tds
{
#region Fields
string databaseProductName;
string databaseProductVersion;
int databaseMajorVersion;
+ CultureInfo locale = CultureInfo.InvariantCulture;
+
+ readonly int lifeTime;
+ readonly DateTime created = DateTime.Now;
string charset;
string language;
- bool connected = false;
+ bool connected;
bool moreResults;
Encoding encoder;
// bool autoCommit;
bool doneProc;
- TdsDataRow currentRow = null;
+ bool pooling = true;
+ TdsDataRow currentRow;
TdsDataColumnCollection columns;
ArrayList tableNames;
ArrayList columnNames;
- TdsMetaParameterCollection parameters;
+ TdsMetaParameterCollection parameters = new TdsMetaParameterCollection ();
bool queryInProgress;
int cancelsRequested;
int recordsAffected = -1;
- long StreamLength = 0;
- long StreamIndex = 0;
- int StreamColumnIndex = 0;
+ long StreamLength;
+ long StreamIndex;
+ int StreamColumnIndex;
- bool sequentialAccess = false;
- bool isRowRead = false;
- bool isResultRead = false;
- bool LoadInProgress = false;
+ bool sequentialAccess;
+ bool isRowRead;
+ bool isResultRead;
+ bool LoadInProgress;
+ byte [] collation;
+
+ internal int poolStatus = 0;
#endregion // Fields
get { return charset; }
}
+ protected CultureInfo Locale {
+ get { return locale; }
+ }
+
public bool DoneProc {
get { return doneProc; }
}
get { return dataSource; }
}
- public bool IsConnected {
- get { return connected; }
+ public virtual bool IsConnected {
+ get { return connected && comm != null && comm.IsConnected (); }
set { connected = value; }
}
+ public bool Pooling {
+ get { return pooling; }
+ set { pooling = value; }
+ }
+
public bool MoreResults {
get { return moreResults; }
set { moreResults = value; }
set { sequentialAccess = value; }
}
+ public byte[] Collation {
+ get {return collation; }
+ }
+
+ public TdsVersion ServerTdsVersion {
+ get {
+ switch (databaseMajorVersion) {
+ case 4: return TdsVersion.tds42;
+ case 5: return TdsVersion.tds50;
+ case 7: return TdsVersion.tds70;
+ case 8: return TdsVersion.tds80;
+ case 9: return TdsVersion.tds90;
+ case 10: return TdsVersion.tds100;
+ default: return tdsVersion; // return client's version
+ }
+ }
+ }
+
private void SkipRow ()
{
SkipToColumnIndex (Columns.Count);
throw new Exception ("Cannot Skip to a colindex less than the curr index");
while (colIndex != StreamColumnIndex) {
- TdsColumnType colType = (TdsColumnType)Columns[StreamColumnIndex]["ColumnType"];
+#if NET_2_0
+ TdsColumnType? colType = Columns[StreamColumnIndex].ColumnType;
+ if (colType == null)
+ throw new Exception ("Column type unset.");
+#else
+ TdsColumnType colType = (TdsColumnType) Columns [StreamColumnIndex]["ColumnType"];
+#endif
if (!(colType == TdsColumnType.Image ||
colType == TdsColumnType.Text ||
colType == TdsColumnType.NText)) {
if (colIndex != StreamColumnIndex)
SkipToColumnIndex (colIndex);
+#if NET_2_0
+ object o = GetColumnValue (Columns[colIndex].ColumnType, false, colIndex);
+#else
object o = GetColumnValue ((TdsColumnType)Columns[colIndex]["ColumnType"], false, colIndex);
+#endif
StreamColumnIndex++;
return o;
}
public long GetSequentialColumnValue (int colIndex, long fieldIndex, byte[] buffer, int bufferIndex, int size)
{
if (colIndex < StreamColumnIndex)
- throw new InvalidOperationException ("Invalid attempt tp read from column ordinal" + colIndex);
+ throw new InvalidOperationException ("Invalid attempt to read from column ordinal" + colIndex);
+ try {
+ if (colIndex != StreamColumnIndex)
+ SkipToColumnIndex (colIndex);
- if (colIndex != StreamColumnIndex)
- SkipToColumnIndex (colIndex);
-
- if (!LoadInProgress)
- BeginLoad ((TdsColumnType)Columns[colIndex]["ColumnType"]);
+ if (!LoadInProgress) {
+#if NET_2_0
+ BeginLoad (Columns[colIndex].ColumnType);
+#else
+ BeginLoad ((TdsColumnType)Columns[colIndex]["ColumnType"]);
+#endif
+ }
- if (buffer == null) {
- return StreamLength;
+ if (buffer == null)
+ return StreamLength;
+ return LoadData (fieldIndex, buffer, bufferIndex, size);
+ } catch (IOException ex) {
+ connected = false;
+ throw new TdsInternalException ("Server closed the connection.", ex);
}
- return LoadData (fieldIndex, buffer, bufferIndex, size);
}
- private void BeginLoad(TdsColumnType colType)
+ private void BeginLoad (
+#if NET_2_0
+ TdsColumnType? colType
+#else
+ TdsColumnType colType
+#endif
+ )
{
if (LoadInProgress)
EndLoad ();
StreamLength = 0;
-
+
+#if NET_2_0
+ if (colType == null)
+ throw new ArgumentNullException ("colType");
+#endif
+
switch (colType) {
case TdsColumnType.Text :
case TdsColumnType.NText:
if (Comm.GetByte () != 0) {
Comm.Skip (24);
StreamLength = Comm.GetTdsInt ();
+ } else {
+ // use -2 to indicate that we're dealing
+ // with a NULL value
+ StreamLength = -2;
}
break;
case TdsColumnType.BigVarChar:
return StreamLength;
if (fieldIndex < StreamIndex)
- throw new InvalidOperationException ("field index less than stream pos");
+ throw new InvalidOperationException (string.Format (
+ "Attempting to read at dataIndex '{0}' is " +
+ "not allowed as this is less than the " +
+ "current position. You must read from " +
+ "dataIndex '{1}' or greater.",
+ fieldIndex, StreamIndex));
if (fieldIndex >= (StreamLength + StreamIndex))
return 0;
- // Skip to the index
- Comm.Skip ((int) (fieldIndex - StreamIndex));
+ // determine number of bytes to skip
+ int skip = (int) (fieldIndex - StreamIndex);
+ // skip bytes
+ Comm.Skip (skip);
+ // update the current position
StreamIndex += (fieldIndex - StreamIndex);
+ // update the remaining length
+ StreamLength -= skip;
- // Load the reqd amt of bytes
+ // Load the reqd amt of bytes
int loadlen = (int) ((size > StreamLength) ? StreamLength : size);
byte[] arr = Comm.GetBytes (loadlen, true);
#region Constructors
public Tds (string dataSource, int port, int packetSize, int timeout, TdsVersion tdsVersion)
+ : this (dataSource, port, packetSize, timeout, 0, tdsVersion)
+ {
+ }
+
+ public Tds (string dataSource, int port, int packetSize, int timeout, int lifeTime, TdsVersion tdsVersion)
{
this.tdsVersion = tdsVersion;
this.packetSize = packetSize;
this.dataSource = dataSource;
+ this.columns = new TdsDataColumnCollection ();
+ this.lifeTime = lifeTime;
+ InitComm (port, timeout);
+ }
+
+ protected virtual void InitComm (int port, int timeout)
+ {
comm = new TdsComm (dataSource, port, packetSize, timeout, tdsVersion);
}
#region Public Methods
+ internal bool Expired {
+ get {
+ if (lifeTime == 0)
+ return false;
+ return DateTime.Now > (created + TimeSpan.FromSeconds (lifeTime));
+ }
+ }
+
internal protected void InitExec ()
{
- // clean up
+ // clean up
moreResults = true;
doneProc = false;
+
+ // Reset "read" status variables - used in case of SequentialAccess
+ isResultRead = false;
+ isRowRead = false;
+ StreamLength = 0;
+ StreamIndex = 0;
+ StreamColumnIndex = 0;
+ LoadInProgress = false;
+
+ // Reset more variables
+ queryInProgress = false;
+ cancelsRequested = 0;
+ cancelsProcessed = 0;
+ recordsAffected = -1;
+
messages.Clear ();
outputParameters.Clear ();
}
if (queryInProgress) {
if (cancelsRequested == cancelsProcessed) {
comm.StartPacket (TdsPacketType.Cancel);
- comm.SendPacket ();
+ try {
+ Comm.SendPacket ();
+ } catch (IOException ex) {
+ connected = false;
+ throw new TdsInternalException ("Server closed the connection.", ex);
+ }
cancelsRequested += 1;
}
- }
+ }
}
public abstract bool Connect (TdsConnectionParameters connectionParameters);
return new TdsTimeoutException (0, 0, message, -2, method, dataSource, "Mono TdsClient Data Provider", 0);
}
- public void Disconnect ()
+ public virtual void Disconnect ()
{
- comm.StartPacket (TdsPacketType.Logoff);
- comm.Append ((byte) 0);
- comm.SendPacket ();
- comm.Close ();
+ try {
+ comm.StartPacket (TdsPacketType.Logoff);
+ comm.Append ((byte) 0);
+ comm.SendPacket ();
+ } catch {
+ // We're closing the socket anyway
+ }
connected = false;
+ comm.Close ();
}
public virtual bool Reset ()
throw new NotSupportedException ();
}
+ internal void ExecBulkCopyMetaData (int timeout, bool wantResults)
+ {
+ moreResults = true;
+ try {
+ Comm.SendPacket ();
+ CheckForData (timeout);
+ if (!wantResults)
+ SkipToEnd ();
+ } catch (IOException ex) {
+ connected = false;
+ throw new TdsInternalException ("Server closed the connection.", ex);
+ }
+ }
+
+ internal void ExecBulkCopy (int timeout, bool wantResults)
+ {
+ moreResults = true;
+ try {
+ Comm.SendPacket ();
+ CheckForData (timeout);
+ if (!wantResults)
+ SkipToEnd ();
+ } catch (IOException ex) {
+ connected = false;
+ throw new TdsInternalException ("Server closed the connection.", ex);
+ }
+ }
+
protected void ExecuteQuery (string sql, int timeout, bool wantResults)
{
InitExec ();
Comm.StartPacket (TdsPacketType.Query);
Comm.Append (sql);
- Comm.SendPacket ();
-
- CheckForData (timeout);
- if (!wantResults)
- SkipToEnd ();
+ try {
+ Comm.SendPacket ();
+ CheckForData (timeout);
+ if (!wantResults)
+ SkipToEnd ();
+ } catch (IOException ex) {
+ connected = false;
+ throw new TdsInternalException ("Server closed the connection.", ex);
+ }
}
protected virtual void ExecRPC (string rpcName, TdsMetaParameterCollection parameters,
Comm.Append (rpcNameBytes);
Comm.Append (mask);
- Comm.SendPacket ();
- CheckForData (timeout);
- if (!wantResults)
- SkipToEnd ();
+ try {
+ Comm.SendPacket ();
+ CheckForData (timeout);
+ if (!wantResults)
+ SkipToEnd ();
+ } catch (IOException ex) {
+ connected = false;
+ throw new TdsInternalException ("Server closed the connection.", ex);
+ }
}
public bool NextResult ()
moreResults = false;
break;
}
-
switch (subType) {
case TdsPacketSubType.ColumnInfo:
case TdsPacketSubType.ColumnMetadata:
- case TdsPacketSubType.RowFormat:
+ case TdsPacketSubType.RowFormat:
byte peek = Comm.Peek ();
done = (peek != (byte) TdsPacketSubType.TableName);
if (done && doneProc && peek == (byte) TdsPacketSubType.Row) {
outputParams = true;
done = false;
}
-
break;
case TdsPacketSubType.TableName:
// done = true;
peek = Comm.Peek ();
done = (peek != (byte) TdsPacketSubType.ColumnDetail);
-
break;
case TdsPacketSubType.ColumnDetail:
done = true;
public void SkipToEnd ()
{
- while (NextResult ()) { /* DO NOTHING */ }
+ try {
+ while (NextResult ()) { /* DO NOTHING */ }
+ } catch (IOException ex) {
+ connected = false;
+ throw new TdsInternalException ("Server closed the connection.", ex);
+ }
}
public virtual void Unprepare (string statementId)
return new TdsInternalErrorMessageEventArgs (new TdsInternalError (theClass, lineNumber, message, number, procedure, server, source, state));
}
- private object GetColumnValue (TdsColumnType colType, bool outParam)
+ private Encoding GetEncodingFromColumnCollation (int lcid, int sortId)
+ {
+ if (sortId != 0)
+ return TdsCharset.GetEncodingFromSortOrder (sortId);
+ else
+ return TdsCharset.GetEncodingFromLCID (lcid);
+ }
+
+ protected object GetColumnValue (
+#if NET_2_0
+ TdsColumnType? colType,
+#else
+ TdsColumnType colType,
+#endif
+ bool outParam)
{
return GetColumnValue (colType, outParam, -1);
}
- private object GetColumnValue (TdsColumnType colType, bool outParam, int ordinal)
+ private object GetColumnValue (
+#if NET_2_0
+ TdsColumnType? colType,
+#else
+ TdsColumnType colType,
+#endif
+ bool outParam, int ordinal)
{
int len;
object element = null;
+ Encoding enc = null;
+ int lcid = 0, sortId = 0;
+#if NET_2_0
+ if (colType == null)
+ throw new ArgumentNullException ("colType");
+#endif
+ if (ordinal > -1 && tdsVersion > TdsVersion.tds70) {
+#if NET_2_0
+ lcid = (int) columns[ordinal].LCID;
+ sortId = (int) columns[ordinal].SortOrder;
+#else
+ lcid = (int) columns[ordinal]["LCID"];
+ sortId = (int) columns[ordinal]["SortOrder"];
+#endif
+ }
+
switch (colType) {
case TdsColumnType.IntN :
if (outParam)
case TdsColumnType.Int1 :
case TdsColumnType.Int2 :
case TdsColumnType.Int4 :
+ case TdsColumnType.BigInt :
element = GetIntValue (colType);
break;
case TdsColumnType.Image :
element = GetImageValue ();
break;
case TdsColumnType.Text :
+ enc = GetEncodingFromColumnCollation (lcid, sortId);
if (outParam)
comm.Skip (1);
- element = GetTextValue (false);
+ element = GetTextValue (false, enc);
break;
case TdsColumnType.NText :
+ enc = GetEncodingFromColumnCollation (lcid, sortId);
if (outParam)
comm.Skip (1);
- element = GetTextValue (true);
+ element = GetTextValue (true, enc);
break;
case TdsColumnType.Char :
case TdsColumnType.VarChar :
+ enc = GetEncodingFromColumnCollation (lcid, sortId);
if (outParam)
comm.Skip (1);
- element = GetStringValue (false, false);
+ element = GetStringValue (colType, false, outParam, enc);
break;
case TdsColumnType.BigVarBinary :
- comm.GetTdsShort ();
+ if (outParam)
+ comm.Skip (1);
+ len = comm.GetTdsShort ();
+ element = comm.GetBytes (len, true);
+ break;
+ /*
+ case TdsColumnType.BigBinary :
+ if (outParam)
+ comm.Skip (2);
len = comm.GetTdsShort ();
element = comm.GetBytes (len, true);
break;
+ */
+ case TdsColumnType.BigBinary :
+ if (outParam)
+ comm.Skip (2);
+ element = GetBinaryValue ();
+ break;
+ case TdsColumnType.BigChar :
case TdsColumnType.BigVarChar :
- comm.Skip (2);
- element = GetStringValue (false, false);
+ enc = GetEncodingFromColumnCollation (lcid, sortId);
+ if (outParam)
+ comm.Skip (2);
+ element = GetStringValue (colType, false, outParam, enc);
break;
case TdsColumnType.NChar :
+ case TdsColumnType.BigNVarChar :
+ enc = GetEncodingFromColumnCollation (lcid, sortId);
+ if (outParam)
+ comm.Skip(2);
+ element = GetStringValue (colType, true, outParam, enc);
+ break;
case TdsColumnType.NVarChar :
+ enc = GetEncodingFromColumnCollation (lcid, sortId);
if (outParam)
comm.Skip (1);
- element = GetStringValue (true, false);
+ element = GetStringValue (colType, true, outParam, enc);
break;
case TdsColumnType.Real :
case TdsColumnType.Float8 :
scale = comm.GetByte ();
}
else {
+#if NET_2_0
+ precision = (byte) columns[ordinal].NumericPrecision;
+ scale = (byte) columns[ordinal].NumericScale;
+#else
precision = (byte) columns[ordinal]["NumericPrecision"];
scale = (byte) columns[ordinal]["NumericScale"];
+#endif
}
element = GetDecimalValue (precision, scale);
+
+ // workaround for fact that TDS 7.0 returns
+ // bigint as decimal (19,0), and client code
+ // expects it to be returned as a long
+ if (scale == 0 && precision <= 19 && tdsVersion == TdsVersion.tds70) {
+ if (!(element is System.DBNull))
+ element = Convert.ToInt64 (element);
+ }
break;
case TdsColumnType.DateTimeN :
if (outParam)
break;
case TdsColumnType.UniqueIdentifier :
if (comm.Peek () != 16) { // If it's null, then what to do?
- /*byte swallowed =*/ comm.GetByte();
+ /*byte swallowed =*/ comm.GetByte();
element = DBNull.Value;
break;
}
+ if (outParam)
+ comm.Skip (1);
+
len = comm.GetByte () & 0xff;
if (len > 0) {
byte[] guidBytes = comm.GetBytes (len, true);
default :
return DBNull.Value;
}
-
return element;
}
{
int len;
object result = DBNull.Value;
- if (tdsVersion == TdsVersion.tds70) {
+
+ if (tdsVersion >= TdsVersion.tds70) {
len = comm.GetTdsShort ();
- if (len != 0xffff && len > 0)
+ if (len != 0xffff && len >= 0)
result = comm.GetBytes (len, true);
- }
- else {
+ } else {
len = (comm.GetByte () & 0xff);
if (len != 0)
result = comm.GetBytes (len, true);
}
+
return result;
}
- private object GetDateTimeValue (TdsColumnType type)
+ private object GetDateTimeValue (
+#if NET_2_0
+ TdsColumnType? type
+#else
+ TdsColumnType type
+#endif
+ )
{
int len = 0;
object result;
-
+
+#if NET_2_0
+ if (type == null)
+ throw new ArgumentNullException ("type");
+#endif
switch (type) {
case TdsColumnType.DateTime4:
len = 4;
case 8 :
result = epoch.AddDays (comm.GetTdsInt ());
int seconds = comm.GetTdsInt ();
- long millis = ((((long) seconds) % 300L) * 1000L) / 300L;
+ long millis = (long) System.Math.Round (((((long) seconds) % 300L) * 1000L) / 300f);
if (seconds != 0 || millis != 0) {
result = ((DateTime) result).AddSeconds (seconds / 300);
result = ((DateTime) result).AddMilliseconds (millis);
}
break;
case 4 :
- // MSDN says small datetime is stored in 2 bytes as no of days
- // *after* 1/1/1900. so, cast to unsigned short
+ // MSDN says small datetime is stored in 2 bytes as no of days
+ // *after* 1/1/1900. so, cast to unsigned short
result = epoch.AddDays ((ushort) comm.GetTdsShort ());
short minutes = comm.GetTdsShort ();
if (minutes != 0)
return result;
}
- private object GetDecimalValue (byte precision, byte scale) {
+ private object GetDecimalValue (byte precision, byte scale)
+ {
if (tdsVersion < TdsVersion.tds70)
return GetDecimalValueTds50 (precision, scale);
else
return GetDecimalValueTds70 (precision, scale);
}
- private object GetDecimalValueTds70 (byte precision, byte scale) {
+ private object GetDecimalValueTds70 (byte precision, byte scale)
+ {
int[] bits = new int[4] {0,0,0,0};
int len = (comm.GetByte() & 0xff) - 1;
return DBNull.Value;
bool positive = (comm.GetByte () == 1);
-
if (len > 16)
throw new OverflowException ();
for (int i = 0, index = 0; i < len && i < 16; i += 4, index += 1)
bits[index] = comm.GetTdsInt ();
-
+
if (bits [3] != 0)
return new TdsBigDecimal (precision, scale, !positive, bits);
else
return new Decimal (bits[0], bits[1], bits[2], !positive, scale);
}
- private object GetDecimalValueTds50 (byte precision, byte scale) {
+ private object GetDecimalValueTds50 (byte precision, byte scale)
+ {
int[] bits = new int[4] {0,0,0,0};
int len = (comm.GetByte() & 0xff);
if (len == 0)
return DBNull.Value;
- byte[] dec_bytes=comm.GetBytes(len,false);
+ byte[] dec_bytes=comm.GetBytes(len,false);
byte[] easy=new byte[4];
}
- private object GetFloatValue (TdsColumnType columnType)
+ private object GetFloatValue (
+#if NET_2_0
+ TdsColumnType? columnType
+#else
+ TdsColumnType columnType
+#endif
+ )
{
+#if NET_2_0
+ if (columnType == null)
+ throw new ArgumentNullException ("columnType");
+#endif
int columnSize = 0;
switch (columnType) {
return (comm.GetBytes (len, true));
}
- private object GetIntValue (TdsColumnType type)
+ private object GetIntValue (
+#if NET_2_0
+ TdsColumnType? type
+#else
+ TdsColumnType type
+#endif
+ )
{
int len;
+#if NET_2_0
+ if (type == null)
+ throw new ArgumentNullException ("type");
+#endif
switch (type) {
+ case TdsColumnType.BigInt :
+ len = 8;
+ break;
case TdsColumnType.IntN :
len = comm.GetByte ();
break;
}
switch (len) {
+ case 8:
+ return (comm.GetTdsInt64 ());
case 4 :
return (comm.GetTdsInt ());
case 2 :
}
}
- [MonoTODO]
- private object GetMoneyValue (TdsColumnType type)
+ private object GetMoneyValue (
+#if NET_2_0
+ TdsColumnType? type
+#else
+ TdsColumnType type
+#endif
+ )
{
int len;
- object result = null;
+#if NET_2_0
+ if (type == null)
+ throw new ArgumentNullException ("type");
+#endif
switch (type) {
case TdsColumnType.SmallMoney :
case TdsColumnType.Money4 :
}
switch (len) {
- case 4:
- return new Decimal (Comm.GetTdsInt (), 0, 0, false, 4);
- case 8:
+ case 4: {
+ int val = Comm.GetTdsInt ();
+ bool negative = val < 0;
+ if (negative)
+ val = ~(val - 1);
+ return new Decimal (val, 0, 0, negative, 4);
+ }
+ case 8: {
int hi = Comm.GetTdsInt ();
int lo = Comm.GetTdsInt ();
- return new Decimal (lo, hi, 0, false, 4);
+ bool negative = hi < 0;
+
+ if (negative) {
+ hi = ~hi;
+ lo = ~(lo - 1);
+ }
+ return new Decimal (lo, hi, 0, negative, 4);
+ }
default:
return DBNull.Value;
}
}
- private object GetStringValue (bool wideChars, bool outputParam)
+ protected object GetStringValue (
+#if NET_2_0
+ TdsColumnType? colType,
+#else
+ TdsColumnType colType,
+#endif
+ bool wideChars, bool outputParam, Encoding encoder)
{
- bool shortLen = (tdsVersion == TdsVersion.tds70) && (wideChars || !outputParam);
+ bool shortLen = false;
+ Encoding enc = encoder;
+
+ if (tdsVersion > TdsVersion.tds70 && outputParam &&
+ (colType == TdsColumnType.BigChar || colType == TdsColumnType.BigNVarChar ||
+ colType == TdsColumnType.BigVarChar || colType == TdsColumnType.NChar ||
+ colType == TdsColumnType.NVarChar)) {
+ // Read collation for SqlServer 2000 and beyond
+ byte[] collation;
+ collation = Comm.GetBytes (5, true);
+ enc = TdsCharset.GetEncoding (collation);
+ shortLen = true;
+ } else {
+ shortLen = (tdsVersion >= TdsVersion.tds70) && (wideChars || !outputParam);
+ }
+
int len = shortLen ? comm.GetTdsShort () : (comm.GetByte () & 0xff);
+ return GetStringValue (wideChars, len, enc);
+ }
+ protected object GetStringValue (bool wideChars, int len, Encoding enc)
+ {
if (tdsVersion < TdsVersion.tds70 && len == 0)
return DBNull.Value;
+
else if (len >= 0) {
object result;
if (wideChars)
- result = comm.GetString (len / 2);
+ result = comm.GetString (len / 2, enc);
else
- result = comm.GetString (len, false);
+ result = comm.GetString (len, false, enc);
if (tdsVersion < TdsVersion.tds70 && ((string) result).Equals (" "))
- result = "";
+ result = string.Empty;
return result;
}
else
return comm.GetTdsShort ();
}
- private object GetTextValue (bool wideChars)
+ private object GetTextValue (bool wideChars, Encoding encoder)
{
string result = null;
byte hasValue = comm.GetByte ();
// this method is called only for Text and NText. Hence will
// return a empty string
if (len == 0)
- return "";
+ return string.Empty;
if (wideChars)
- result = comm.GetString (len / 2);
+ result = comm.GetString (len / 2, encoder);
else
- result = comm.GetString (len, false);
+ result = comm.GetString (len, false, encoder);
len /= 2;
if ((byte) tdsVersion < (byte) TdsVersion.tds70 && result == " ")
- result = "";
+ result = string.Empty;
- return result;
+ return result;
+ }
+
+ internal bool IsBlobType (TdsColumnType columnType)
+ {
+ return (columnType == TdsColumnType.Text || columnType == TdsColumnType.Image || columnType == TdsColumnType.NText);
+ }
+
+ internal bool IsLargeType (TdsColumnType columnType)
+ {
+ return ((byte) columnType > 128);
+ }
+
+ protected bool IsWideType (TdsColumnType columnType)
+ {
+ switch (columnType) {
+ case TdsColumnType.NChar:
+ case TdsColumnType.NText:
+ case TdsColumnType.NVarChar:
+ return true;
+ default:
+ return false;
+ }
}
internal static bool IsFixedSizeColumn (TdsColumnType columnType)
case TdsColumnType.Int1 :
case TdsColumnType.Int2 :
case TdsColumnType.Int4 :
+ case TdsColumnType.BigInt :
case TdsColumnType.Float8 :
case TdsColumnType.DateTime :
case TdsColumnType.Bit :
case TdsColumnType.SmallMoney :
case TdsColumnType.Real :
case TdsColumnType.DateTime4 :
+ /*
+ case TdsColumnType.Decimal:
+ case TdsColumnType.Numeric:
+ */
return true;
- case TdsColumnType.IntN :
- case TdsColumnType.MoneyN :
- case TdsColumnType.VarChar :
- case TdsColumnType.NVarChar :
- case TdsColumnType.DateTimeN :
- case TdsColumnType.FloatN :
- case TdsColumnType.Char :
- case TdsColumnType.NChar :
- case TdsColumnType.NText :
- case TdsColumnType.Image :
- case TdsColumnType.VarBinary :
- case TdsColumnType.Binary :
- case TdsColumnType.Decimal :
- case TdsColumnType.Numeric :
- case TdsColumnType.BitN :
- case TdsColumnType.UniqueIdentifier :
- return false;
default :
return false;
}
int i = 0;
foreach (TdsDataColumn column in columns) {
- object o = GetColumnValue ((TdsColumnType) column["ColumnType"], false, i);
+#if NET_2_0
+ object o = GetColumnValue (column.ColumnType, false, i);
+#else
+ object o = GetColumnValue ((TdsColumnType)column["ColumnType"], false, i);
+#endif
currentRow.Add (o);
if (doneProc)
outputParameters.Add (o);
case TdsColumnType.Float8 :
case TdsColumnType.DateTime :
case TdsColumnType.Money :
+ case TdsColumnType.BigInt :
return 8;
default :
return 0;
}
}
- private int LookupDisplaySize (TdsColumnType columnType)
- {
- switch (columnType) {
- case TdsColumnType.Int1 :
- return 3;
- case TdsColumnType.Int2 :
- return 6;
- case TdsColumnType.Int4 :
- return 11;
- case TdsColumnType.Real :
- return 14;
- case TdsColumnType.Float8 :
- return 24;
- case TdsColumnType.DateTime :
- return 23;
- case TdsColumnType.DateTime4 :
- return 16;
- case TdsColumnType.Bit :
- return 1;
- case TdsColumnType.Money :
- return 21;
- case TdsColumnType.Money4 :
- case TdsColumnType.SmallMoney :
- return 12;
- default:
- return 0;
- }
- }
-
protected internal int ProcessAuthentication ()
{
int pdu_size = Comm.GetTdsShort ();
// 0x0200 Negotiate NTLM
// 0x8000 Negotiate Always Sign
- Type3Message t3 = new Type3Message ();
- t3.Challenge = t2.Nonce;
+ Type3Message t3 = new Type3Message (t2);
t3.Domain = this.connectionParms.DefaultDomain;
t3.Host = this.connectionParms.Hostname;
t3.Username = this.connectionParms.User;
- t3.Password = this.connectionParms.Password;
+ t3.Password = GetPlainPassword(this.connectionParms.Password);
Comm.StartPacket (TdsPacketType.SspAuth); // 0x11
Comm.Append (t3.GetBytes ());
- Comm.SendPacket ();
+ try {
+ Comm.SendPacket ();
+ } catch (IOException ex) {
+ connected = false;
+ throw new TdsInternalException ("Server closed the connection.", ex);
+ }
return 1; // TDS_SUCCEED
}
bool isAlias = ((values[2] & (byte) TdsColumnStatus.Rename) != 0);
if (isAlias) {
- if (tdsVersion == TdsVersion.tds70) {
+ if (tdsVersion >= TdsVersion.tds70) {
columnNameLength = comm.GetByte ();
position += 2 * columnNameLength + 1;
}
byte tableIndex = (byte) (values[1] - (byte) 1);
bool isExpression = ((values[2] & (byte) TdsColumnStatus.IsExpression) != 0);
- columns [index]["IsExpression"] = isExpression;
- columns [index]["IsKey"] = ((values[2] & (byte) TdsColumnStatus.IsKey) != 0);
- columns [index]["IsHidden"] = ((values[2] & (byte) TdsColumnStatus.Hidden) != 0);
- columns [index]["IsAliased"] = isAlias;
-
- columns [index]["BaseColumnName"] = ((isAlias) ? baseColumnName : null);
- columns [index]["BaseTableName"] = ((!isExpression) ? tableNames [tableIndex] : null);
+ TdsDataColumn column = columns [index];
+#if NET_2_0
+ column.IsHidden = ((values[2] & (byte) TdsColumnStatus.Hidden) != 0);
+ column.IsExpression = isExpression;
+ column.IsKey = ((values[2] & (byte) TdsColumnStatus.IsKey) != 0);
+ column.IsAliased = isAlias;
+ column.BaseColumnName = ((isAlias) ? baseColumnName : null);
+ column.BaseTableName = ((!isExpression) ? (string) tableNames [tableIndex] : null);
+#else
+ column ["IsHidden"] = ((values [2] & (byte) TdsColumnStatus.Hidden) != 0);
+ column ["IsExpression"] = isExpression;
+ column ["IsKey"] = ((values [2] & (byte) TdsColumnStatus.IsKey) != 0);
+ column ["IsAliased"] = isAlias;
+ column ["BaseColumnName"] = ((isAlias) ? baseColumnName : null);
+ column ["BaseTableName"] = ((!isExpression) ? tableNames [tableIndex] : null);
+#endif
}
}
- protected abstract TdsDataColumnCollection ProcessColumnInfo ();
+ protected abstract void ProcessColumnInfo ();
protected void ProcessColumnNames ()
{
Comm.Skip (1);
int rowCount = comm.GetTdsInt ();
-
bool validRowCount = IsValidRowCount (status,op);
moreResults = ((status & 0x01) != 0);
bool cancelled = ((status & 0x20) != 0);
protected void ProcessEnvironmentChange ()
{
+ // VARADHAN: TDS 8 Debugging
+ //Console.WriteLine ("In ProcessEnvironmentChange... entry");
int len = GetSubPacketLength ();
TdsEnvPacketSubType type = (TdsEnvPacketSubType) comm.GetByte ();
int cLen;
switch (type) {
case TdsEnvPacketSubType.BlockSize :
string blockSize;
- cLen = comm.GetByte () & 0xff;
+ cLen = comm.GetByte ();
blockSize = comm.GetString (cLen);
- if (tdsVersion == TdsVersion.tds70)
+ if (tdsVersion >= TdsVersion.tds70)
comm.Skip (len - 2 - cLen * 2);
else
comm.Skip (len - 2 - cLen);
comm.ResizeOutBuf (packetSize);
break;
case TdsEnvPacketSubType.CharSet :
- cLen = comm.GetByte () & 0xff;
+ cLen = comm.GetByte ();
if (tdsVersion == TdsVersion.tds70) {
SetCharset (comm.GetString (cLen));
comm.Skip (len - 2 - cLen * 2);
comm.Skip (len - 2 - cLen);
}
+ break;
+ case TdsEnvPacketSubType.Locale :
+ cLen = comm.GetByte ();
+ int lcid = 0;
+ if (tdsVersion >= TdsVersion.tds70) {
+ lcid = (int) Convert.ChangeType (comm.GetString (cLen), typeof (int));
+ comm.Skip (len - 2 - cLen * 2);
+ }
+ else {
+ lcid = (int) Convert.ChangeType (comm.GetString (cLen), typeof (int));
+ comm.Skip (len - 2 - cLen);
+ }
+ locale = new CultureInfo (lcid);
break;
case TdsEnvPacketSubType.Database :
- cLen = comm.GetByte () & 0xff;
+ cLen = comm.GetByte ();
string newDB = comm.GetString (cLen);
cLen = comm.GetByte () & 0xff;
comm.GetString (cLen);
originalDatabase = newDB;
database = newDB;
break;
+ case TdsEnvPacketSubType.CollationInfo:
+ //Console.WriteLine ("ProcessEnvironmentChange::Got collation info");
+ cLen = comm.GetByte ();
+ collation = comm.GetBytes (cLen, true);
+ lcid = TdsCollation.LCID (collation);
+ locale = new CultureInfo (lcid);
+ SetCharset (TdsCharset.GetEncoding (collation));
+ break;
+
default:
comm.Skip (len - 1);
break;
}
+ // VARADHAN: TDS 8 Debugging
+ //Console.WriteLine ("In ProcessEnvironmentChange... exit");
}
protected void ProcessLoginAck ()
{
+ uint srvVersion = 0;
GetSubPacketLength ();
+
+ //Console.WriteLine ("ProcessLoginAck: B4 tdsVersion:{0}", tdsVersion);
+ // Valid only for a Login7 request
+ if (tdsVersion >= TdsVersion.tds70) {
+ comm.Skip (1);
+ srvVersion = (uint)comm.GetTdsInt ();
- if (tdsVersion == TdsVersion.tds70) {
- comm.Skip (5);
+ //Console.WriteLine ("srvVersion: {0}", srvVersion);
+ switch (srvVersion) {
+ case 0x00000007:
+ tdsVersion = TdsVersion.tds70;
+ break;
+ case 0x00000107:
+ tdsVersion = TdsVersion.tds80;
+ break;
+ case 0x01000071:
+ tdsVersion = TdsVersion.tds81;
+ break;
+ case 0x02000972:
+ tdsVersion = TdsVersion.tds90;
+ break;
+ }
+ //Console.WriteLine ("ProcessLoginAck: after tdsVersion:{0}", tdsVersion);
+ }
+
+ if (tdsVersion >= TdsVersion.tds70) {
int nameLength = comm.GetByte ();
databaseProductName = comm.GetString (nameLength);
databaseMajorVersion = comm.GetByte ();
databaseProductVersion = String.Format ("{0}.{1}.{2}", databaseMajorVersion.ToString("00"),
comm.GetByte ().ToString("00"),
(256 * comm.GetByte () + comm.GetByte ()).ToString("0000"));
- }
- else {
+ } else {
comm.Skip (5);
short nameLength = comm.GetByte ();
databaseProductName = comm.GetString (nameLength);
}
connected = true;
+ //Console.WriteLine ("databaseProductVersion:{0}", databaseProductVersion);
}
protected void OnTdsErrorMessage (TdsInternalErrorMessageEventArgs e)
messages.Add (new TdsInternalError (theClass, lineNumber, message, number, procedure, server, source, state));
}
- protected void ProcessOutputParam ()
+ protected virtual void ProcessOutputParam ()
{
GetSubPacketLength ();
- comm.GetString (comm.GetByte () & 0xff);
+ /*string paramName = */comm.GetString (comm.GetByte () & 0xff);
comm.Skip (5);
TdsColumnType colType = (TdsColumnType) comm.GetByte ();
object value = GetColumnValue (colType, true);
-
outputParameters.Add (value);
}
protected virtual TdsPacketSubType ProcessSubPacket ()
{
+ // VARADHAN: TDS 8 Debugging
+ // Console.WriteLine ("In ProcessSubPacket... entry");
+
TdsPacketSubType subType = (TdsPacketSubType) comm.GetByte ();
+ // VARADHAN: TDS 8 Debugging
+ //Console.WriteLine ("Subpacket type: {0}", subType);
switch (subType) {
case TdsPacketSubType.Dynamic2:
comm.Skip (comm.GetTdsInt ());
ProcessAuthentication ();
break;
case TdsPacketSubType.ReturnStatus :
- Comm.Skip (4);
+ ProcessReturnStatus ();
break;
case TdsPacketSubType.ProcId:
Comm.Skip (8);
case TdsPacketSubType.ColumnInfo: // TDS 4.2
case TdsPacketSubType.ColumnMetadata: // TDS 7.0
case TdsPacketSubType.RowFormat: // TDS 5.0
- columns = ProcessColumnInfo ();
+ Columns.Clear ();
+ ProcessColumnInfo ();
break;
case TdsPacketSubType.ColumnDetail:
ProcessColumnDetail ();
break;
}
+ // VARADHAN: TDS 8 Debugging
+ //Console.WriteLine ("In ProcessSubPacket... exit");
return subType;
}
int len;
while (position < totalLength) {
- if (tdsVersion == TdsVersion.tds70) {
+ if (tdsVersion >= TdsVersion.tds70) {
len = comm.GetTdsShort ();
position += 2 * (len + 1);
}
position += len + 1;
}
tableNames.Add (comm.GetString (len));
- }
+ }
}
+ protected void SetCharset (Encoding encoder)
+ {
+ comm.Encoder = encoder;
+ }
+
protected void SetCharset (string charset)
{
if (charset == null || charset.Length > 30)
encoder = Encoding.GetEncoding ("iso-8859-1");
this.charset = "iso_1";
}
- comm.Encoder = encoder;
+ SetCharset (encoder);
}
protected void SetLanguage (string language)
this.language = language;
}
+ protected virtual void ProcessReturnStatus ()
+ {
+ comm.Skip(4);
+ }
+
+ public static string GetPlainPassword(SecureString secPass)
+ {
+ IntPtr plainString = IntPtr.Zero;
+ try
+ {
+ plainString = Marshal.SecureStringToGlobalAllocUnicode(secPass);
+ return Marshal.PtrToStringUni(plainString);
+ }
+ finally
+ {
+ Marshal.ZeroFreeGlobalAllocUnicode(plainString);
+ }
+ }
+
#endregion // Private Methods
#if NET_2_0
Comm.StartPacket (TdsPacketType.Query);
Comm.Append (sql);
- Comm.SendPacket ();
+ try {
+ Comm.SendPacket ();
+ Comm.BeginReadPacket (new AsyncCallback(OnBeginExecuteQueryCallback),
+ ar);
+ } catch (IOException ex) {
+ connected = false;
+ throw new TdsInternalException ("Server closed the connection.", ex);
+ }
- Comm.BeginReadPacket (new AsyncCallback(OnBeginExecuteQueryCallback),
- ar);
return ar;
}