+2002-10-23 Tim Coleman (tim@timcoleman.com)
+ * ITds.cs:
+ * Tds42.cs:
+ * Tds50.cs:
+ * Tds70.cs:
+ * Tds80.cs:
+ New classes added. Functionality
+ is split up because different protocols
+ have slight differences.
+ * Tds.cs:
+ Remove some unnecessary code after
+ the above split, and add in a whole
+ lot more stuff for completeness.
+ * TdsColumnType.cs:
+ Fix Int4. Wrong enum value.
+ * TdsComm.cs:
+ Move the encoder out of constructor
+ because we don't know the charset at
+ that point
+ * TdsConnectionParameters.cs:
+ Small changes
+ * TdsPacketEndTokenResult.cs:
+ Implement ToString ()
+
+
2002-10-22 Tim Coleman (tim@timcoleman.com)
* Tds.cs :
More implementation. Does some
--- /dev/null
+//
+// Mono.Data.TdsClient.Internal.ITds.cs
+//
+// Author:
+// Tim Coleman (tim@timcoleman.com)
+//
+// Copyright (C) 2002 Tim Coleman
+//
+
+using System;
+
+namespace Mono.Data.TdsClient.Internal {
+ internal interface ITds
+ {
+ #region Properties
+
+ string Database {
+ get;
+ }
+
+ bool InUse {
+ get;
+ set;
+ }
+
+ bool IsConnected {
+ get;
+ }
+
+ string ServerVersion {
+ get;
+ }
+
+ #endregion // Properties
+
+ #region Methods
+
+ bool Connect (TdsConnectionParameters connectionParameters);
+
+ void Disconnect ();
+
+ int ExecuteNonQuery (string sql);
+
+ void ExecuteQuery (string sql);
+
+ #endregion
+ }
+}
using System;
using System.Data;
+using System.Data.SqlTypes;
+using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Mono.Data.TdsClient.Internal {
- internal class Tds
+ internal abstract class Tds : ITds
{
#region Fields
+ TdsComm comm;
TdsVersion tdsVersion;
- string applicationName;
- string database = String.Empty;
- string connectDB;
- string charset;
- string hostname;
- string server;
- string language;
- string libraryName;
int packetSize;
- string password;
- int port;
- string progName;
- string user;
-
+ string dataSource;
+ string database;
string databaseProductName;
string databaseProductVersion;
int databaseMajorVersion;
+ string charset;
+ string language;
+
DataTable table = new DataTable ();
+ bool connected = false;
bool moreResults;
bool moreResults2;
Encoding encoder;
TdsServerType serverType;
- TdsComm comm;
- TdsConnectionParameters parms;
- //TdsCommand command;
IsolationLevel isolationLevel;
bool autoCommit;
Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
#region Properties
- //public TdsCommandInternal Command {
- //get { return command; }
- //set { command = value; }
- //}
+ protected string Charset {
+ get { return charset; }
+ }
+
+ protected string Language {
+ get { return language; }
+ }
+
+ protected TdsComm Comm {
+ get { return comm; }
+ }
public string Database {
get { return database; }
- set { database = value; }
}
- public TdsVersion TdsVersion {
- get { return tdsVersion; }
+ public string DataSource {
+ get { return dataSource; }
}
public bool InUse {
set { inUse = value; }
}
+ public bool IsConnected {
+ get { return connected; }
+ set { connected = value; }
+ }
+
+ public int PacketSize {
+ get { return packetSize; }
+ }
+
+ public string ServerVersion {
+ get { return databaseProductVersion; }
+ }
+
+ public TdsVersion TdsVersion {
+ get { return tdsVersion; }
+ }
+
#endregion // Properties
#region Constructors
- public Tds (TdsConnectionParameters parms)
+ public Tds (string dataSource, int port, int packetSize, TdsVersion tdsVersion)
{
- applicationName = parms.ApplicationName;
- connectDB = parms.Database;
- encoder = Encoding.GetEncoding (parms.Encoding);
- charset = parms.Encoding;
- hostname = parms.Hostname;
- server = parms.DataSource;
- language = parms.Language;
- libraryName = parms.LibraryName;
- packetSize = parms.PacketSize;
- password = parms.Password;
- port = parms.Port;
- progName = parms.ProgName;
- tdsVersion = parms.TdsVersion;
- user = parms.User;
-
- IPHostEntry hostEntry = Dns.Resolve (server);
+ this.tdsVersion = tdsVersion;
+ this.packetSize = packetSize;
+ this.dataSource = dataSource;
+
+ IPHostEntry hostEntry = Dns.Resolve (dataSource);
IPAddress[] addresses = hostEntry.AddressList;
IPEndPoint endPoint;
break;
}
- comm = new TdsComm (encoder, socket, packetSize, tdsVersion);
- }
+ comm = new TdsComm (socket, packetSize, tdsVersion);
+ }
#endregion // Constructors
#region Methods
- public void BeginTransaction ()
- {
- SubmitProcedure ("BEGIN TRANSACTION");
- }
- public void ChangeDatabase (string databaseName)
- {
- TdsPacketResult result;
- bool isOkay;
-
- string query = String.Format ("use {0}", databaseName);
- comm.StartPacket (TdsPacketType.Query);
- comm.Append (query);
- comm.SendPacket ();
-
- while (!((result = ProcessSubPacket ()) is TdsPacketEndTokenResult)) {
- if (result is TdsPacketErrorResult) {
- isOkay = false;
- }
- }
- }
-
public void ChangeSettings (bool autoCommit, IsolationLevel isolationLevel)
{
/*string query = SqlStatementForSettings (autoCommit, isolationLevel);
comm.SendPacket ();
bool done = false;
- while (!done) {
+ do {
result = ProcessSubPacket ();
- done = (result is TdsPacketEndTokenResult) && !((TdsPacketEndTokenResult) result).MoreResults;
- if (result is TdsPacketErrorResult) {
- done = true;
- isOkay = false;
- }
- }
+ done = (result is TdsPacketEndTokenResult) && (!((TdsPacketEndTokenResult) result).MoreResults);
+
+ } while (!done);
return isOkay;
}
- public void CommitTransaction ()
- {
- string sql = "IF @@TRANCOUNT>0 COMMIT TRAN";
- SubmitProcedure (sql);
- }
-
[MonoTODO ("fixme")]
public int ExecuteNonQuery (string sql)
{
TdsPacketResult result;
- bool done = false;
if (sql.Length > 0) {
comm.StartPacket (TdsPacketType.Query);
comm.SendPacket ();
}
+ bool done = false;
do {
result = ProcessSubPacket ();
- if (result is TdsPacketMessageResult) {
- Console.WriteLine (((TdsPacketMessageResult) result).Message);
- }
done = (result is TdsPacketEndTokenResult) && (!((TdsPacketEndTokenResult) result).MoreResults);
} while (!done);
- return -1;
+ if (sql.Trim ().ToUpper ().StartsWith ("INSERT") || sql.Trim ().ToUpper ().StartsWith ("UPDATE") || sql.Trim ().ToUpper ().StartsWith ("DELETE"))
+ return ((TdsPacketEndTokenResult) result).RowCount;
+ else
+ return -1;
}
[MonoTODO ("fixme")]
public void ExecuteQuery (string sql)
{
+ TdsPacketResult result = null;
+
if (sql.Length > 0) {
comm.StartPacket (TdsPacketType.Query);
comm.Append (sql);
moreResults2 = true;
comm.SendPacket ();
}
+
+ bool done = false;
+ do {
+ result = ProcessSubPacket ();
+ done = (result is TdsPacketEndTokenResult) && (!((TdsPacketEndTokenResult) result).MoreResults);
+
+ } while (!done);
}
- private object GetCharValue (bool wideChars, bool outputParam)
+ private object GetStringValue (bool wideChars, bool outputParam)
{
object result = null;
bool shortLen = (tdsVersion == TdsVersion.tds70) && (wideChars || !outputParam);
return result;
}
- [MonoTODO]
private object GetDecimalValue (int scale)
{
throw new NotImplementedException ();
}
- [MonoTODO]
private object GetDateTimeValue (TdsColumnType type)
{
throw new NotImplementedException ();
byte[] result;
byte hasValue = comm.GetByte ();
if (hasValue == 0)
- return null;
+ return SqlBinary.Null;
comm.Skip (24);
int len = comm.GetTdsInt ();
- if (len >= 0)
- result = comm.GetBytes (len, true);
- else
+
+ if (len < 0)
throw new TdsException ("");
- return result;
+
+ return new SqlBinary (comm.GetBytes (len, true));
}
private object GetIntValue (TdsColumnType type)
switch (len) {
case 4 :
- result = comm.GetTdsInt ();
- break;
+ return new SqlInt32 (comm.GetTdsInt ());
case 2 :
- result = comm.GetTdsShort ();
- break;
+ return new SqlInt16 (comm.GetTdsShort ());
case 1 :
- result = (byte) comm.GetByte ();
- break;
+ return new SqlByte (comm.GetByte ());
case 0 :
- result = null;
- break;
+ return SqlInt32.Null;
default:
throw new TdsException ("Bad integer length");
}
-
- return result;
}
[MonoTODO]
int bytesRead = 0;
int i = 0;
- bool newTable = (table.Columns.Count > 0);
+ bool newTable = (table.Columns.Count == 0);
while (bytesRead < totalLength) {
int columnNameLength = comm.GetByte ();
string columnName = encoder.GetString (comm.GetBytes (columnNameLength, false), 0, columnNameLength);
bytesRead = bytesRead + 1 + columnNameLength;
+
+ Console.WriteLine ("Column: {0}", columnName);
+
if (newTable)
table.Columns.Add (columnName);
else
bool autoIncrement = (flagData[2] & 0x10) > 0;
string tableName = String.Empty;
TdsColumnType columnType = (TdsColumnType) comm.GetByte ();
+
+ Console.WriteLine (columnType);
+
bytesRead += 1;
if (columnType == TdsColumnType.Text || columnType == TdsColumnType.Image) {
TdsPacketEndTokenResult result = new TdsPacketEndTokenResult (type, status, rowCount);
- Console.WriteLine ("Row count {0}", rowCount);
-
moreResults = result.MoreResults;
// FIXME: Finish the query
blockSize = encoder.GetString (comm.GetBytes (cLen, false), 0, cLen);
comm.Skip (len - 2 - cLen);
}
-
comm.ResizeOutBuf (Int32.Parse (blockSize));
break;
case TdsEnvPacketSubType.CharSet :
cLen = comm.GetByte () & 0xff;
if (tdsVersion == TdsVersion.tds70) {
- this.language = comm.GetString (cLen);
+ //this.language = comm.GetString (cLen); // FIXME
+ comm.GetString (cLen);
comm.Skip (len - 2 - cLen * 2);
}
else {
- this.charset = encoder.GetString (comm.GetBytes (cLen, false), 0, cLen);
+ SetCharset (encoder.GetString (comm.GetBytes (cLen, false), 0, cLen));
comm.Skip (len - 2 - cLen);
- SetCharset (charset);
}
break;
string newDB = tdsVersion == TdsVersion.tds70 ? comm.GetString (cLen) : encoder.GetString (comm.GetBytes (cLen, false), 0, cLen);
cLen = comm.GetByte () & 0xff;
string oldDB = tdsVersion == TdsVersion.tds70 ? comm.GetString (cLen) : encoder.GetString (comm.GetBytes (cLen, false), 0, cLen);
- if (database != String.Empty && database != oldDB)
+ if (database != null && database != oldDB)
throw new TdsException ("Database mismatch.");
database = newDB;
break;
databaseProductVersion = String.Format ("{0}.{1}", databaseMajorVersion, comm.GetByte ());
comm.Skip (1);
}
- Console.WriteLine ("Connected to {0} {1}", databaseProductName, databaseProductVersion);
if (databaseProductName.Length > 1 && -1 != databaseProductName.IndexOf ('\0')) {
int last = databaseProductName.IndexOf ('\0');
message.Line = comm.GetByte ();
comm.GetByte ();
- Console.WriteLine (message.ToString ());
-
lastServerMessage = message;
if (subType == TdsPacketSubType.Error)
- return new TdsPacketErrorResult (subType, message);
- else
- return new TdsPacketMessageResult (subType, message);
+ throw new TdsException (message.ToString ());
+
+ Console.WriteLine (message.ToString ());
+
+ return new TdsPacketMessageResult (subType, message);
}
private TdsPacketOutputParam ProcessOutputParam ()
case TdsColumnType.Char :
case TdsColumnType.VarChar :
comm.GetByte ();
- element = GetCharValue (false, true);
+ element = GetStringValue (false, true);
break;
case TdsColumnType.BigVarBinary :
comm.GetTdsShort ();
break;
case TdsColumnType.BigVarChar :
comm.GetTdsShort ();
- element = GetCharValue (false, false);
+ element = GetStringValue (false, false);
break;
case TdsColumnType.NChar :
case TdsColumnType.NVarChar :
comm.GetByte ();
- element = GetCharValue (true, true);
+ element = GetStringValue (true, true);
break;
case TdsColumnType.Real :
element = ReadFloatN (4);
}
[MonoTODO]
- private TdsPacketResult ProcessSubPacket ()
+ protected TdsPacketResult ProcessSubPacket ()
{
TdsPacketResult result = null;
moreResults = false;
switch (subType) {
case TdsPacketSubType.EnvChange :
-Console.WriteLine ("Environment change");
result = ProcessEnvChange ();
break;
case TdsPacketSubType.Error :
case TdsPacketSubType.Info :
case TdsPacketSubType.Msg50Token :
-Console.WriteLine ("Error/info/message");
result = ProcessMessage (subType);
break;
case TdsPacketSubType.Param :
-Console.WriteLine ("Param");
+Console.WriteLine ("OUTPUT PARAMETER PACKET RECEIVED");
result = ProcessOutputParam ();
break;
case TdsPacketSubType.LoginAck :
-Console.WriteLine ("Login Ack");
result = ProcessLoginAck ();
break;
case TdsPacketSubType.ReturnStatus :
-Console.WriteLine ("Return Status");
+Console.WriteLine ("RETURN STATUS PACKET RECEIVED");
result = ProcessReturnStatus ();
break;
case TdsPacketSubType.ProcId :
-Console.WriteLine ("Proc Id");
+Console.WriteLine ("PROC ID PACKET RECEIVED");
result = ProcessProcId ();
break;
case TdsPacketSubType.Done :
case TdsPacketSubType.DoneProc :
case TdsPacketSubType.DoneInProc :
-Console.WriteLine ("Done");
result = ProcessEndToken (subType);
moreResults2 = ((TdsPacketEndTokenResult) result).MoreResults;
break;
case TdsPacketSubType.ColumnNameToken :
-Console.WriteLine ("Column Name");
+Console.WriteLine ("COLUMN NAME TOKEN PACKET RECEIVED");
result = ProcessColumnNames ();
break;
case TdsPacketSubType.ColumnInfoToken :
-Console.WriteLine ("Column Info");
+Console.WriteLine ("COLUMN INFO TOKEN PACKET RECEIVED");
result = ProcessColumnInfo ();
break;
case TdsPacketSubType.Unknown0xA5 :
case TdsPacketSubType.Unknown0xA7 :
case TdsPacketSubType.Unknown0xA8 :
-Console.WriteLine ("Unknown");
+Console.WriteLine ("UNKNOWN PACKET RECEIVED");
comm.Skip (comm.GetTdsShort ());
result = new TdsPacketUnknown (subType);
break;
case TdsPacketSubType.TableName :
-Console.WriteLine ("Table Name");
+Console.WriteLine ("TABLE NAME PACKET RECEIVED");
result = ProcessTableName ();
break;
case TdsPacketSubType.Order :
-Console.WriteLine ("Order");
+Console.WriteLine ("COLUMN ORDER PACKET RECEIVED");
comm.Skip (comm.GetTdsShort ());
result = new TdsPacketColumnOrderResult ();
break;
case TdsPacketSubType.Control :
-Console.WriteLine ("Control");
+Console.WriteLine ("CONTROL PACKET RECEIVED");
comm.Skip (comm.GetTdsShort ());
result = new TdsPacketControlResult ();
break;
case TdsPacketSubType.Row :
-Console.WriteLine ("Row");
+Console.WriteLine ("ROW RESULT PACKET RECEIVED");
result = LoadRow (new TdsPacketRowResult (null));
break;
case TdsPacketSubType.ColumnMetadata :
-Console.WriteLine ("Column Metadata");
+Console.WriteLine ("COLUMN METADATA PACKET RECEIVED");
result = ProcessTds7Result ();
break;
default:
return tmp;
}
- [MonoTODO]
- public void RollbackTransaction ()
+ protected void SetCharset (string charset)
{
- SubmitProcedure ("IF @@TRANCOUNT>0 ROLLBACK TRAN");
- }
+ if (charset == null || charset.Length > 30)
+ charset = "iso_1";
- [MonoTODO]
- public void SaveTransaction (string savePointName)
- {
- string sql = String.Format ("SAVE TRAN {0}", savePointName);
- SubmitProcedure (sql);
- }
+ if (this.charset != null && this.charset != charset)
+ return;
- private void SetCharset (string charset)
- {
- if (charset == null || charset.Length > 30)
- charset = "iso-8859-1";
- if (this.charset != charset) {
- encoder = Encoding.GetEncoding (charset);
+ if (charset.StartsWith ("cp")) {
+ encoder = Encoding.GetEncoding (Int32.Parse (charset.Substring (2)));
this.charset = charset;
}
+ else {
+ encoder = Encoding.GetEncoding ("iso-8859-1");
+ this.charset = "iso_1";
+ }
+ comm.Encoder = encoder;
+ }
+
+ protected void SetLanguage (string language)
+ {
+ if (language == null || language.Length > 30)
+ language = "us_english";
+
+ this.language = language;
}
public void SubmitProcedure (string sql)
{
TdsPacketResult result;
ExecuteQuery (sql);
- bool done;
+
+ bool done = false;
do {
result = ProcessSubPacket ();
- if (result is TdsPacketMessageResult) {
- Console.WriteLine (((TdsPacketMessageResult) result).Message);
- }
done = (result is TdsPacketEndTokenResult) && (!((TdsPacketEndTokenResult) result).MoreResults);
} while (!done);
}
- public void Close ()
+ public void Disconnect ()
{
}
- public bool Logon (TdsConnectionParameters parms)
- {
- byte pad = (byte) 0;
- byte[] empty = new byte[0];
- bool isOkay = true;
-
- if (tdsVersion == TdsVersion.tds70) {
- Send70Logon (parms);
- } else {
- comm.StartPacket (TdsPacketType.Logon);
-
- // hostname (offset 0)
- byte[] tmp = comm.Append (hostname, 30, pad);
- comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
-
- // username (offset 31 0x1f)
- tmp = comm.Append (user, 30, pad);
- comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
-
- // password (offset 62 0x3e)
- tmp = comm.Append (password, 30, pad);
- comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
-
- // hostproc (offset 93 0x5d)
- comm.Append ("00000116", 8, pad);
-
- // unused (offset 109 0x6d)
- comm.Append (empty, (30-14), pad);
-
- // apptype
- comm.Append ((byte) 0x0);
- comm.Append ((byte) 0xa0);
- comm.Append ((byte) 0x24);
- comm.Append ((byte) 0xcc);
- comm.Append ((byte) 0x50);
- comm.Append ((byte) 0x12);
-
- // hostproc length
- comm.Append ((byte) 8);
-
- // type of int2
- comm.Append ((byte) 3);
-
- // type of int4
- comm.Append ((byte) 1);
-
- // type of char
- comm.Append ((byte) 6);
-
- // type of flt
- comm.Append ((byte) 10);
-
- // type of date
- comm.Append ((byte) 9);
-
- // notify of use db
- comm.Append ((byte) 1);
-
- // disallow dump/load and bulk insert
- comm.Append ((byte) 1);
-
- // sql interface type
- comm.Append ((byte) 0);
-
- // type of network connection
- comm.Append ((byte) 0);
-
-
- // spare [7]
- comm.Append (empty, 7, pad);
- // appname
- tmp = comm.Append (applicationName, 30, pad);
- comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
-
- // server name
- tmp = comm.Append (server, 30, pad);
- comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
-
- // remote passwords
- comm.Append (empty, 2, pad);
- tmp = comm.Append (password, 253, pad);
- comm.Append ((byte) (tmp.Length < 253 ? tmp.Length + 2 : 253 + 2));
-
- // tds version
- comm.Append ((byte) (((byte) tdsVersion) / 10));
- comm.Append ((byte) (((byte) tdsVersion) % 10));
- comm.Append ((byte) 0);
- comm.Append ((byte) 0);
-
- // prog name
- tmp = comm.Append (progName, 10, pad);
- comm.Append ((byte) (tmp.Length < 10 ? tmp.Length : 10));
-
- // prog version
- comm.Append ((byte) 6);
-
- // Tell the server we can handle SQLServer version 6
- comm.Append ((byte) 0);
-
- // Send zero to tell the server we can't handle any other version
- comm.Append ((byte) 0);
- comm.Append ((byte) 0);
-
- // auto convert short
- comm.Append ((byte) 0);
-
- // type of flt4
- comm.Append ((byte) 0x0d);
-
- // type of date4
- comm.Append ((byte) 0x11);
-
- // language
- tmp = comm.Append (language, 30, pad);
- comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
-
- // notify on lang change
- comm.Append ((byte) 1);
-
- // security label hierarchy
- comm.Append ((short) 0);
-
- // security components
- comm.Append (empty, 8, pad);
-
- // security spare
- comm.Append ((short) 0);
-
- // security login role
- comm.Append ((byte) 0);
-
- // charset
- tmp = comm.Append (charset, 30, pad);
- comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
-
- // notify on charset change
- comm.Append ((byte) 1);
-
- // length of tds packets
- tmp = comm.Append (packetSize.ToString (), 6, pad);
- comm.Append ((byte) 3);
-
- // pad out to a longword
- comm.Append (empty, 8, pad);
- }
-
- comm.SendPacket ();
-
- TdsPacketResult result;
-
- while (!((result = ProcessSubPacket()) is TdsPacketEndTokenResult)) {
- if (result is TdsPacketErrorResult) {
- isOkay = false;
- }
- // XXX Should really process some more types of packets.
- }
-
- if (isOkay) {
- // XXX Should we move this to the Connection class?
- //isOkay = initSettings(_database);
- }
-
- // XXX Possible bug. What happend if this is cancelled before the logon
- // takes place? Should isOkay be false?
- return isOkay;
-
- }
-
- // This packet is documented at
- // http://www.freetds.org/tds.htm#login7
- public void Send70Logon (TdsConnectionParameters parms)
- {
- byte[] empty = new byte[0];
- byte pad = (byte) 0;
-
- byte[] magic1 = {0x06, 0x83, 0xf2, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x88, 0xff, 0xff, 0xff, 0x36, 0x04, 0x00, 0x00};
- byte[] magic2 = {0x00, 0x40, 0x33, 0x9a, 0x6b, 0x50};
- byte[] magic3 = {0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50}; // NTLMSSP
- short partialPacketSize = (short) (86 + 2 * (
- hostname.Length +
- user.Length +
- applicationName.Length +
- password.Length +
- server.Length +
- libraryName.Length +
- language.Length +
- connectDB.Length));
- short totalPacketSize = (short) (partialPacketSize + 48);
- comm.StartPacket (TdsPacketType.Logon70);
- comm.Append (totalPacketSize);
- comm.Append (empty, 5, pad);
-
- if (tdsVersion == TdsVersion.tds80)
- comm.Append ((byte) 0x80);
- else
- comm.Append ((byte) 0x70);
-
- comm.Append (empty, 7, pad);
- comm.Append (magic1);
-
- short curPos = 86;
-
- // Hostname
- comm.Append (curPos);
- comm.Append ((short) hostname.Length);
- curPos += (short) (hostname.Length * 2);
-
- // Username
- comm.Append (curPos);
- comm.Append ((short) user.Length);
- curPos += (short) (user.Length * 2);
-
- // Password
- comm.Append (curPos);
- comm.Append ((short) password.Length);
- curPos += (short) (password.Length * 2);
-
- // AppName
- comm.Append (curPos);
- comm.Append ((short) applicationName.Length);
- curPos += (short) (applicationName.Length * 2);
-
- // Server Name
- comm.Append (curPos);
- comm.Append ((short) server.Length);
- curPos += (short) (server.Length * 2);
-
- // Unknown
- comm.Append ((short) 0);
- comm.Append ((short) 0);
-
- // Library Name
- comm.Append (curPos);
- comm.Append ((short) libraryName.Length);
- curPos += (short) (libraryName.Length * 2);
-
- // Character Set
- comm.Append (curPos);
- comm.Append ((short) language.Length);
- curPos += (short) (language.Length * 2);
-
- // Database
- comm.Append (curPos);
- comm.Append ((short) connectDB.Length);
- curPos += (short) (connectDB.Length * 2);
-
- comm.Append (magic2);
- comm.Append (partialPacketSize);
- comm.Append ((short) 48);
- comm.Append (totalPacketSize);
- comm.Append ((short) 0);
-
- string scrambledPwd = Tds7CryptPass (password);
-
- comm.Append (hostname);
- comm.Append (user);
- comm.Append (scrambledPwd);
- comm.Append (applicationName);
- comm.Append (server);
- comm.Append (libraryName);
- comm.Append (language);
- comm.Append (connectDB);
- comm.Append (magic3);
-
- comm.Append ((byte) 0x0);
- comm.Append ((byte) 0x1);
- comm.Append (empty, 3, pad);
- comm.Append ((byte) 0x6);
- comm.Append ((byte) 0x82);
- comm.Append (empty, 22, pad);
- comm.Append ((byte) 0x30);
- comm.Append (empty, 7, pad);
- comm.Append ((byte) 0x30);
- comm.Append (empty, 3, pad);
- }
+ public abstract bool Connect (TdsConnectionParameters connectionParameters);
private string SqlStatementForSettings (bool autoCommit, IsolationLevel isolationLevel)
{
--- /dev/null
+//
+// Mono.Data.TdsClient.Internal.Tds42.cs
+//
+// Author:
+// Tim Coleman (tim@timcoleman.com)
+//
+// Copyright (C) 2002 Tim Coleman
+//
+
+using System;
+
+namespace Mono.Data.TdsClient.Internal {
+ internal class Tds42 : Tds, ITds
+ {
+ #region Fields
+
+ public static readonly TdsVersion Version = TdsVersion.tds42;
+
+ #endregion // Fields
+
+ #region Constructors
+
+ public Tds42 (string server, int port)
+ : this (server, port, 512)
+ {
+ }
+
+ public Tds42 (string server, int port, int packetSize)
+ : base (server, port, packetSize, Version)
+ {
+ }
+
+ #endregion // Constructors
+
+ #region Methods
+
+ public override bool Connect (TdsConnectionParameters connectionParameters)
+ {
+ if (IsConnected)
+ throw new InvalidOperationException ("The connection is already open.");
+
+ SetCharset (connectionParameters.Charset);
+ SetLanguage (connectionParameters.Language);
+
+ byte pad = (byte) 0;
+ byte[] empty = new byte[0];
+ bool isOkay = true;
+
+ Comm.StartPacket (TdsPacketType.Logon);
+
+ // hostname (offset 0)
+ byte[] tmp = Comm.Append (connectionParameters.Hostname, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // username (offset 31 0x1f)
+ tmp = Comm.Append (connectionParameters.User, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // password (offset 62 0x3e)
+ tmp = Comm.Append (connectionParameters.Password, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // hostproc (offset 93 0x5d)
+ Comm.Append ("00000116", 8, pad);
+
+ // unused (offset 109 0x6d)
+ Comm.Append (empty, (30-14), pad);
+
+ // apptype
+ Comm.Append ((byte) 0x0);
+ Comm.Append ((byte) 0xa0);
+ Comm.Append ((byte) 0x24);
+ Comm.Append ((byte) 0xcc);
+ Comm.Append ((byte) 0x50);
+ Comm.Append ((byte) 0x12);
+
+ // hostproc length
+ Comm.Append ((byte) 8);
+
+ // Byte order of 2 byte ints
+ // 2 = <MSB, LSB>, 3 = <LSB, MSB>
+ Comm.Append ((byte) 3);
+
+ // Byte order of 4 byte ints
+ // 0 = <MSB, LSB>, 1 = <LSB, MSB>
+ Comm.Append ((byte) 1);
+
+ // Character representation
+ // (6 = ASCII, 7 = EBCDIC)
+ Comm.Append ((byte) 6);
+
+ // Eight byte floating point representation
+ // 4 = IEEE <MSB, ..., LSB>
+ // 5 = VAX 'D'
+ // 10 = IEEE <LSB, ..., MSB>
+ // 11 = ND5000
+ Comm.Append ((byte) 10);
+
+ // Eight byte date format
+ // 8 = <MSB, ..., LSB>
+ Comm.Append ((byte) 9);
+
+ // notify of use db
+ Comm.Append ((byte) 1);
+
+ // disallow dump/load and bulk insert
+ Comm.Append ((byte) 1);
+
+ // sql interface type
+ Comm.Append ((byte) 0);
+
+ // type of network connection
+ Comm.Append ((byte) 0);
+
+
+ // spare [7]
+ Comm.Append (empty, 7, pad);
+ // appname
+ tmp = Comm.Append (connectionParameters.ApplicationName, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // server name
+ tmp = Comm.Append (DataSource, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // remote passwords
+ Comm.Append (empty, 2, pad);
+ tmp = Comm.Append (connectionParameters.Password, 253, pad);
+ Comm.Append ((byte) (tmp.Length < 253 ? tmp.Length + 2 : 253 + 2));
+
+ // tds version
+ Comm.Append ((byte) (((byte) Version) / 10));
+ Comm.Append ((byte) (((byte) Version) % 10));
+ Comm.Append ((byte) 0);
+ Comm.Append ((byte) 0);
+
+ // prog name
+ tmp = Comm.Append (connectionParameters.ProgName, 10, pad);
+ Comm.Append ((byte) (tmp.Length < 10 ? tmp.Length : 10));
+
+ // prog version
+ Comm.Append ((byte) 6);
+
+ // Tell the server we can handle SQLServer version 6
+ Comm.Append ((byte) 0);
+
+ // Send zero to tell the server we can't handle any other version
+ Comm.Append ((byte) 0);
+ Comm.Append ((byte) 0);
+
+ // auto convert short
+ Comm.Append ((byte) 0);
+
+ // type of flt4
+ Comm.Append ((byte) 0x0d);
+
+ // type of date4
+ Comm.Append ((byte) 0x11);
+
+ // language
+ tmp = Comm.Append (Language, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // notify on lang change
+ Comm.Append ((byte) 1);
+
+ // security label hierarchy
+ Comm.Append ((short) 0);
+
+ // security components
+ Comm.Append (empty, 8, pad);
+
+ // security spare
+ Comm.Append ((short) 0);
+
+ // security login role
+ Comm.Append ((byte) 0);
+
+ // charset
+ tmp = Comm.Append (Charset, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // notify on charset change
+ Comm.Append ((byte) 1);
+
+ // length of tds packets
+ tmp = Comm.Append (PacketSize.ToString (), 6, pad);
+ Comm.Append ((byte) 3);
+
+ // pad out to a longword
+ Comm.Append (empty, 8, pad);
+
+ Comm.SendPacket ();
+
+ TdsPacketResult result;
+
+ while (!((result = ProcessSubPacket()) is TdsPacketEndTokenResult)) {
+ if (result is TdsPacketErrorResult) {
+ isOkay = false;
+ break;
+ }
+ // XXX Should really process some more types of packets.
+ }
+
+ // XXX Possible bug. What happend if this is cancelled before the logon
+ // takes place? Should isOkay be false?
+
+ IsConnected = isOkay;
+ return isOkay;
+ }
+
+ #endregion // Methods
+ }
+}
--- /dev/null
+//
+// Mono.Data.TdsClient.Internal.Tds50.cs
+//
+// Author:
+// Tim Coleman (tim@timcoleman.com)
+//
+// Copyright (C) 2002 Tim Coleman
+//
+
+using System;
+
+namespace Mono.Data.TdsClient.Internal {
+ internal class Tds50 : Tds, ITds
+ {
+ #region Fields
+
+ public static readonly TdsVersion Version = TdsVersion.tds50;
+
+ #endregion // Fields
+
+ #region Constructors
+
+ public Tds50 (string server, int port)
+ : this (server, port, 512)
+ {
+ }
+
+ public Tds50 (string server, int port, int packetSize)
+ : base (server, port, packetSize, Version)
+ {
+ }
+
+ #endregion // Constructors
+
+ #region Methods
+
+ public override bool Connect (TdsConnectionParameters connectionParameters)
+ {
+ if (IsConnected)
+ throw new InvalidOperationException ("The connection is already open.");
+
+ SetCharset (connectionParameters.Charset);
+ SetLanguage (connectionParameters.Language);
+
+ byte pad = (byte) 0;
+ byte[] empty = new byte[0];
+ bool isOkay = true;
+
+ Comm.StartPacket (TdsPacketType.Logon);
+
+ // hostname (offset 0)
+ byte[] tmp = Comm.Append (connectionParameters.Hostname, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // username (offset 31 0x1f)
+ tmp = Comm.Append (connectionParameters.User, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // password (offset 62 0x3e)
+ tmp = Comm.Append (connectionParameters.Password, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // hostproc (offset 93 0x5d)
+ Comm.Append ("00000116", 8, pad);
+
+ // unused (offset 109 0x6d)
+ Comm.Append (empty, (30-14), pad);
+
+ // apptype
+ Comm.Append ((byte) 0x0);
+ Comm.Append ((byte) 0xa0);
+ Comm.Append ((byte) 0x24);
+ Comm.Append ((byte) 0xcc);
+ Comm.Append ((byte) 0x50);
+ Comm.Append ((byte) 0x12);
+
+ // hostproc length
+ Comm.Append ((byte) 8);
+
+ // Byte order of 2 byte ints
+ // 2 = <MSB, LSB>, 3 = <LSB, MSB>
+ Comm.Append ((byte) 3);
+
+ // Byte order of 4 byte ints
+ // 0 = <MSB, LSB>, 1 = <LSB, MSB>
+ Comm.Append ((byte) 1);
+
+ // Character representation
+ // (6 = ASCII, 7 = EBCDIC)
+ Comm.Append ((byte) 6);
+
+ // Eight byte floating point representation
+ // 4 = IEEE <MSB, ..., LSB>
+ // 5 = VAX 'D'
+ // 10 = IEEE <LSB, ..., MSB>
+ // 11 = ND5000
+ Comm.Append ((byte) 10);
+
+ // Eight byte date format
+ // 8 = <MSB, ..., LSB>
+ Comm.Append ((byte) 9);
+
+ // notify of use db
+ Comm.Append ((byte) 1);
+
+ // disallow dump/load and bulk insert
+ Comm.Append ((byte) 1);
+
+ // sql interface type
+ Comm.Append ((byte) 0);
+
+ // type of network connection
+ Comm.Append ((byte) 0);
+
+
+ // spare [7]
+ Comm.Append (empty, 7, pad);
+ // appname
+ tmp = Comm.Append (connectionParameters.ApplicationName, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // server name
+ tmp = Comm.Append (DataSource, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // remote passwords
+ Comm.Append (empty, 2, pad);
+ tmp = Comm.Append (connectionParameters.Password, 253, pad);
+ Comm.Append ((byte) (tmp.Length < 253 ? tmp.Length + 2 : 253 + 2));
+
+ // tds version
+ Comm.Append ((byte) (((byte) Version) / 10));
+ Comm.Append ((byte) (((byte) Version) % 10));
+ Comm.Append ((byte) 0);
+ Comm.Append ((byte) 0);
+
+ // prog name
+ tmp = Comm.Append (connectionParameters.ProgName, 10, pad);
+ Comm.Append ((byte) (tmp.Length < 10 ? tmp.Length : 10));
+
+ // prog version
+ Comm.Append ((byte) 6);
+
+ // Tell the server we can handle SQLServer version 6
+ Comm.Append ((byte) 0);
+
+ // Send zero to tell the server we can't handle any other version
+ Comm.Append ((byte) 0);
+ Comm.Append ((byte) 0);
+
+ // auto convert short
+ Comm.Append ((byte) 0);
+
+ // type of flt4
+ Comm.Append ((byte) 0x0d);
+
+ // type of date4
+ Comm.Append ((byte) 0x11);
+
+ // language
+ tmp = Comm.Append (Language, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // notify on lang change
+ Comm.Append ((byte) 1);
+
+ // security label hierarchy
+ Comm.Append ((short) 0);
+
+ // security components
+ Comm.Append (empty, 8, pad);
+
+ // security spare
+ Comm.Append ((short) 0);
+
+ // security login role
+ Comm.Append ((byte) 0);
+
+ // charset
+ tmp = Comm.Append (Charset, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // notify on charset change
+ Comm.Append ((byte) 1);
+
+ // length of tds packets
+ tmp = Comm.Append (PacketSize.ToString (), 6, pad);
+ Comm.Append ((byte) 3);
+
+ // pad out to a longword
+ Comm.Append (empty, 8, pad);
+
+ Comm.SendPacket ();
+
+ TdsPacketResult result;
+
+ while (!((result = ProcessSubPacket()) is TdsPacketEndTokenResult)) {
+ if (result is TdsPacketErrorResult) {
+ isOkay = false;
+ }
+ // XXX Should really process some more types of packets.
+ }
+
+ IsConnected = isOkay;
+ return isOkay;
+ }
+
+ #endregion // Methods
+ }
+}
--- /dev/null
+//
+// Mono.Data.TdsClient.Internal.Tds70.cs
+//
+// Author:
+// Tim Coleman (tim@timcoleman.com)
+//
+// Copyright (C) 2002 Tim Coleman
+//
+
+using System;
+
+namespace Mono.Data.TdsClient.Internal {
+ internal class Tds70 : Tds, ITds
+ {
+ #region Fields
+
+ public readonly static TdsVersion Version = TdsVersion.tds70;
+
+ #endregion // Fields
+
+ #region Constructors
+
+ public Tds70 (string server, int port)
+ : this (server, port, 512)
+ {
+ }
+
+ public Tds70 (string server, int port, int packetSize)
+ : base (server, port, packetSize, Version)
+ {
+ }
+
+ #endregion // Constructors
+
+ #region Methods
+
+ public override bool Connect (TdsConnectionParameters connectionParameters)
+ {
+ if (IsConnected)
+ throw new InvalidOperationException ("The connection is already open.");
+
+ bool isOkay = true;
+
+ SetLanguage (connectionParameters.Language);
+
+ byte[] empty = new byte[0];
+ byte pad = (byte) 0;
+
+ byte[] magic1 = {0x06, 0x83, 0xf2, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x88, 0xff, 0xff, 0xff, 0x36, 0x04, 0x00, 0x00};
+ byte[] magic2 = {0x00, 0x40, 0x33, 0x9a, 0x6b, 0x50};
+ byte[] magic3 = {0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50}; // NTLMSSP
+ short partialPacketSize = (short) (86 + 2 * (
+ connectionParameters.Hostname.Length +
+ connectionParameters.User.Length +
+ connectionParameters.ApplicationName.Length +
+ connectionParameters.Password.Length +
+ DataSource.Length +
+ connectionParameters.LibraryName.Length +
+ Language.Length +
+ connectionParameters.Database.Length));
+ short totalPacketSize = (short) (partialPacketSize + 48);
+ Comm.StartPacket (TdsPacketType.Logon70);
+ Comm.Append (totalPacketSize);
+ Comm.Append (empty, 5, pad);
+
+ Comm.Append ((byte) 0x70); // TDS VERSION 7
+ Comm.Append (empty, 7, pad);
+ Comm.Append (magic1);
+
+ short curPos = 86;
+
+ // Hostname
+ Comm.Append (curPos);
+ Comm.Append ((short) connectionParameters.Hostname.Length);
+ curPos += (short) (connectionParameters.Hostname.Length * 2);
+
+ // Username
+ Comm.Append (curPos);
+ Comm.Append ((short) connectionParameters.User.Length);
+ curPos += (short) (connectionParameters.User.Length * 2);
+
+ // Password
+ Comm.Append (curPos);
+ Comm.Append ((short) connectionParameters.Password.Length);
+ curPos += (short) (connectionParameters.Password.Length * 2);
+
+ // AppName
+ Comm.Append (curPos);
+ Comm.Append ((short) connectionParameters.ApplicationName.Length);
+ curPos += (short) (connectionParameters.ApplicationName.Length * 2);
+
+ // Server Name
+ Comm.Append (curPos);
+ Comm.Append ((short) DataSource.Length);
+ curPos += (short) (DataSource.Length * 2);
+
+ // Unknown
+ Comm.Append ((short) 0);
+ Comm.Append ((short) 0);
+
+ // Library Name
+ Comm.Append (curPos);
+ Comm.Append ((short) connectionParameters.LibraryName.Length);
+ curPos += (short) (connectionParameters.LibraryName.Length * 2);
+
+ // Language
+ Comm.Append (curPos);
+ Comm.Append ((short) Language.Length);
+ curPos += (short) (Language.Length * 2);
+
+ // Database
+ Comm.Append (curPos);
+ Comm.Append ((short) connectionParameters.Database.Length);
+ curPos += (short) (connectionParameters.Database.Length * 2);
+
+ Comm.Append (magic2);
+ Comm.Append (partialPacketSize);
+ Comm.Append ((short) 48);
+ Comm.Append (totalPacketSize);
+ Comm.Append ((short) 0);
+
+ string scrambledPwd = EncryptPassword (connectionParameters.Password);
+
+ Comm.Append (connectionParameters.Hostname);
+ Comm.Append (connectionParameters.User);
+ Comm.Append (scrambledPwd);
+ Comm.Append (connectionParameters.ApplicationName);
+ Comm.Append (DataSource);
+ Comm.Append (connectionParameters.LibraryName);
+ Comm.Append (Language);
+ Comm.Append (connectionParameters.Database);
+ Comm.Append (magic3);
+
+ Comm.Append ((byte) 0x0);
+ Comm.Append ((byte) 0x1);
+ Comm.Append (empty, 3, pad);
+ Comm.Append ((byte) 0x6);
+ Comm.Append ((byte) 0x82);
+ Comm.Append (empty, 22, pad);
+ Comm.Append ((byte) 0x30);
+ Comm.Append (empty, 7, pad);
+ Comm.Append ((byte) 0x30);
+ Comm.Append (empty, 3, pad);
+ Comm.SendPacket ();
+
+ TdsPacketResult result;
+
+ while (!((result = ProcessSubPacket()) is TdsPacketEndTokenResult)) {
+ if (result is TdsPacketErrorResult) {
+ isOkay = false;
+ break;
+ }
+ // XXX Should really process some more types of packets.
+ }
+
+ IsConnected = isOkay;
+ return isOkay;
+ }
+
+ private static string EncryptPassword (string pass)
+ {
+ int xormask = 0x5a5a;
+ int len = pass.Length;
+ char[] chars = new char[len];
+
+ for (int i = 0; i < len; ++i) {
+ int c = ((int) (pass[i])) ^ xormask;
+ int m1 = (c >> 4) & 0x0f0f;
+ int m2 = (c << 4) & 0xf0f0;
+ chars[i] = (char) (m1 | m2);
+ }
+
+ return new String (chars);
+ }
+
+ #endregion // Methods
+ }
+}
--- /dev/null
+//
+// Mono.Data.TdsClient.Internal.Tds80.cs
+//
+// Author:
+// Tim Coleman (tim@timcoleman.com)
+//
+// Copyright (C) 2002 Tim Coleman
+//
+
+using System;
+
+namespace Mono.Data.TdsClient.Internal {
+ internal class Tds80 : Tds, ITds
+ {
+ #region Fields
+
+ public static readonly TdsVersion Version = TdsVersion.tds80;
+
+ #endregion // Fields
+
+ #region Constructors
+
+ public Tds80 (string server, int port)
+ : this (server, port, 512)
+ {
+ }
+
+ public Tds80 (string server, int port, int packetSize)
+ : base (server, port, packetSize, Version)
+ {
+ }
+
+ #endregion // Constructors
+
+ #region Methods
+
+ public override bool Connect (TdsConnectionParameters connectionParameters)
+ {
+ throw new NotImplementedException ();
+ }
+
+ #endregion // Methods
+ }
+}
Int1 = 0x30,
Bit = 0x32,
Int2 = 0x34,
- Int4 = 0x56,
+ Int4 = 0x38,
DateTime4 = 0x3a,
Real = 0x3b,
Money = 0x3c,
#region Constructors
- public TdsComm (Encoding encoder, Socket socket, int packetSize, TdsVersion tdsVersion)
+ public TdsComm (Socket socket, int packetSize, TdsVersion tdsVersion)
{
- this.encoder = encoder;
this.packetSize = packetSize;
this.tdsVersion = tdsVersion;
#endregion // Constructors
#region Properties
+
+ internal Encoding Encoder {
+ set { encoder = value; }
+ }
public int PacketSize {
get { return packetSize; }
// Appends with padding
public byte[] Append (string s, int len, byte pad)
{
+ if (s == null)
+ return new byte[0];
+
byte[] result = encoder.GetBytes (s);
Append (result, len, pad);
return result;
{
public string ApplicationName = "Mono";
public string Database;
- public string DataSource;
- public string Encoding = "iso-8859-1";
+ public string Charset;
public string Hostname = "localhost";
- public string Language = "us_english";
+ public string Language;
public string LibraryName = "Mono";
- public int PacketSize;
public string Password;
- public int Port = 1433;
public string ProgName = "Mono";
- public TdsVersion TdsVersion = TdsVersion.tds42;
public string User;
}
}
int rowCount;
bool isRetStatSet;
int retStat;
+ TdsPacketSubType type;
#endregion // Fields
{
if (type == TdsPacketSubType.DoneInProc)
throw new TdsException ("");
+ this.type = type;
this.status = status;
this.rowCount = rowCount;
this.isRetStatSet = false;
[MonoTODO]
public override string ToString ()
{
- throw new NotImplementedException ();
+ return String.Format ("token type: {0}, row count: {1}, more results: {2}, was cancelled? {3}, return status: {4}", type, RowCount, MoreResults, Cancelled, (ReturnStatusExists ? ReturnStatus.ToString () : "No return status"));
}
#endregion // Methods
+2002-10-23 Tim Coleman (tim@timcoleman.com)
+ * ITds.cs:
+ * Tds42.cs:
+ * Tds50.cs:
+ * Tds70.cs:
+ * Tds80.cs:
+ New classes added. Functionality
+ is split up because different protocols
+ have slight differences.
+ * Tds.cs:
+ Remove some unnecessary code after
+ the above split, and add in a whole
+ lot more stuff for completeness.
+ * TdsColumnType.cs:
+ Fix Int4. Wrong enum value.
+ * TdsComm.cs:
+ Move the encoder out of constructor
+ because we don't know the charset at
+ that point
+ * TdsConnectionParameters.cs:
+ Small changes
+ * TdsPacketEndTokenResult.cs:
+ Implement ToString ()
+
+
2002-10-22 Tim Coleman (tim@timcoleman.com)
* Tds.cs :
More implementation. Does some
--- /dev/null
+//
+// Mono.Data.TdsClient.Internal.ITds.cs
+//
+// Author:
+// Tim Coleman (tim@timcoleman.com)
+//
+// Copyright (C) 2002 Tim Coleman
+//
+
+using System;
+
+namespace Mono.Data.TdsClient.Internal {
+ internal interface ITds
+ {
+ #region Properties
+
+ string Database {
+ get;
+ }
+
+ bool InUse {
+ get;
+ set;
+ }
+
+ bool IsConnected {
+ get;
+ }
+
+ string ServerVersion {
+ get;
+ }
+
+ #endregion // Properties
+
+ #region Methods
+
+ bool Connect (TdsConnectionParameters connectionParameters);
+
+ void Disconnect ();
+
+ int ExecuteNonQuery (string sql);
+
+ void ExecuteQuery (string sql);
+
+ #endregion
+ }
+}
using System;
using System.Data;
+using System.Data.SqlTypes;
+using System.Diagnostics;
using System.Net;
using System.Net.Sockets;
using System.Text;
namespace Mono.Data.TdsClient.Internal {
- internal class Tds
+ internal abstract class Tds : ITds
{
#region Fields
+ TdsComm comm;
TdsVersion tdsVersion;
- string applicationName;
- string database = String.Empty;
- string connectDB;
- string charset;
- string hostname;
- string server;
- string language;
- string libraryName;
int packetSize;
- string password;
- int port;
- string progName;
- string user;
-
+ string dataSource;
+ string database;
string databaseProductName;
string databaseProductVersion;
int databaseMajorVersion;
+ string charset;
+ string language;
+
DataTable table = new DataTable ();
+ bool connected = false;
bool moreResults;
bool moreResults2;
Encoding encoder;
TdsServerType serverType;
- TdsComm comm;
- TdsConnectionParameters parms;
- //TdsCommand command;
IsolationLevel isolationLevel;
bool autoCommit;
Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
#region Properties
- //public TdsCommandInternal Command {
- //get { return command; }
- //set { command = value; }
- //}
+ protected string Charset {
+ get { return charset; }
+ }
+
+ protected string Language {
+ get { return language; }
+ }
+
+ protected TdsComm Comm {
+ get { return comm; }
+ }
public string Database {
get { return database; }
- set { database = value; }
}
- public TdsVersion TdsVersion {
- get { return tdsVersion; }
+ public string DataSource {
+ get { return dataSource; }
}
public bool InUse {
set { inUse = value; }
}
+ public bool IsConnected {
+ get { return connected; }
+ set { connected = value; }
+ }
+
+ public int PacketSize {
+ get { return packetSize; }
+ }
+
+ public string ServerVersion {
+ get { return databaseProductVersion; }
+ }
+
+ public TdsVersion TdsVersion {
+ get { return tdsVersion; }
+ }
+
#endregion // Properties
#region Constructors
- public Tds (TdsConnectionParameters parms)
+ public Tds (string dataSource, int port, int packetSize, TdsVersion tdsVersion)
{
- applicationName = parms.ApplicationName;
- connectDB = parms.Database;
- encoder = Encoding.GetEncoding (parms.Encoding);
- charset = parms.Encoding;
- hostname = parms.Hostname;
- server = parms.DataSource;
- language = parms.Language;
- libraryName = parms.LibraryName;
- packetSize = parms.PacketSize;
- password = parms.Password;
- port = parms.Port;
- progName = parms.ProgName;
- tdsVersion = parms.TdsVersion;
- user = parms.User;
-
- IPHostEntry hostEntry = Dns.Resolve (server);
+ this.tdsVersion = tdsVersion;
+ this.packetSize = packetSize;
+ this.dataSource = dataSource;
+
+ IPHostEntry hostEntry = Dns.Resolve (dataSource);
IPAddress[] addresses = hostEntry.AddressList;
IPEndPoint endPoint;
break;
}
- comm = new TdsComm (encoder, socket, packetSize, tdsVersion);
- }
+ comm = new TdsComm (socket, packetSize, tdsVersion);
+ }
#endregion // Constructors
#region Methods
- public void BeginTransaction ()
- {
- SubmitProcedure ("BEGIN TRANSACTION");
- }
- public void ChangeDatabase (string databaseName)
- {
- TdsPacketResult result;
- bool isOkay;
-
- string query = String.Format ("use {0}", databaseName);
- comm.StartPacket (TdsPacketType.Query);
- comm.Append (query);
- comm.SendPacket ();
-
- while (!((result = ProcessSubPacket ()) is TdsPacketEndTokenResult)) {
- if (result is TdsPacketErrorResult) {
- isOkay = false;
- }
- }
- }
-
public void ChangeSettings (bool autoCommit, IsolationLevel isolationLevel)
{
/*string query = SqlStatementForSettings (autoCommit, isolationLevel);
comm.SendPacket ();
bool done = false;
- while (!done) {
+ do {
result = ProcessSubPacket ();
- done = (result is TdsPacketEndTokenResult) && !((TdsPacketEndTokenResult) result).MoreResults;
- if (result is TdsPacketErrorResult) {
- done = true;
- isOkay = false;
- }
- }
+ done = (result is TdsPacketEndTokenResult) && (!((TdsPacketEndTokenResult) result).MoreResults);
+
+ } while (!done);
return isOkay;
}
- public void CommitTransaction ()
- {
- string sql = "IF @@TRANCOUNT>0 COMMIT TRAN";
- SubmitProcedure (sql);
- }
-
[MonoTODO ("fixme")]
public int ExecuteNonQuery (string sql)
{
TdsPacketResult result;
- bool done = false;
if (sql.Length > 0) {
comm.StartPacket (TdsPacketType.Query);
comm.SendPacket ();
}
+ bool done = false;
do {
result = ProcessSubPacket ();
- if (result is TdsPacketMessageResult) {
- Console.WriteLine (((TdsPacketMessageResult) result).Message);
- }
done = (result is TdsPacketEndTokenResult) && (!((TdsPacketEndTokenResult) result).MoreResults);
} while (!done);
- return -1;
+ if (sql.Trim ().ToUpper ().StartsWith ("INSERT") || sql.Trim ().ToUpper ().StartsWith ("UPDATE") || sql.Trim ().ToUpper ().StartsWith ("DELETE"))
+ return ((TdsPacketEndTokenResult) result).RowCount;
+ else
+ return -1;
}
[MonoTODO ("fixme")]
public void ExecuteQuery (string sql)
{
+ TdsPacketResult result = null;
+
if (sql.Length > 0) {
comm.StartPacket (TdsPacketType.Query);
comm.Append (sql);
moreResults2 = true;
comm.SendPacket ();
}
+
+ bool done = false;
+ do {
+ result = ProcessSubPacket ();
+ done = (result is TdsPacketEndTokenResult) && (!((TdsPacketEndTokenResult) result).MoreResults);
+
+ } while (!done);
}
- private object GetCharValue (bool wideChars, bool outputParam)
+ private object GetStringValue (bool wideChars, bool outputParam)
{
object result = null;
bool shortLen = (tdsVersion == TdsVersion.tds70) && (wideChars || !outputParam);
return result;
}
- [MonoTODO]
private object GetDecimalValue (int scale)
{
throw new NotImplementedException ();
}
- [MonoTODO]
private object GetDateTimeValue (TdsColumnType type)
{
throw new NotImplementedException ();
byte[] result;
byte hasValue = comm.GetByte ();
if (hasValue == 0)
- return null;
+ return SqlBinary.Null;
comm.Skip (24);
int len = comm.GetTdsInt ();
- if (len >= 0)
- result = comm.GetBytes (len, true);
- else
+
+ if (len < 0)
throw new TdsException ("");
- return result;
+
+ return new SqlBinary (comm.GetBytes (len, true));
}
private object GetIntValue (TdsColumnType type)
switch (len) {
case 4 :
- result = comm.GetTdsInt ();
- break;
+ return new SqlInt32 (comm.GetTdsInt ());
case 2 :
- result = comm.GetTdsShort ();
- break;
+ return new SqlInt16 (comm.GetTdsShort ());
case 1 :
- result = (byte) comm.GetByte ();
- break;
+ return new SqlByte (comm.GetByte ());
case 0 :
- result = null;
- break;
+ return SqlInt32.Null;
default:
throw new TdsException ("Bad integer length");
}
-
- return result;
}
[MonoTODO]
int bytesRead = 0;
int i = 0;
- bool newTable = (table.Columns.Count > 0);
+ bool newTable = (table.Columns.Count == 0);
while (bytesRead < totalLength) {
int columnNameLength = comm.GetByte ();
string columnName = encoder.GetString (comm.GetBytes (columnNameLength, false), 0, columnNameLength);
bytesRead = bytesRead + 1 + columnNameLength;
+
+ Console.WriteLine ("Column: {0}", columnName);
+
if (newTable)
table.Columns.Add (columnName);
else
bool autoIncrement = (flagData[2] & 0x10) > 0;
string tableName = String.Empty;
TdsColumnType columnType = (TdsColumnType) comm.GetByte ();
+
+ Console.WriteLine (columnType);
+
bytesRead += 1;
if (columnType == TdsColumnType.Text || columnType == TdsColumnType.Image) {
TdsPacketEndTokenResult result = new TdsPacketEndTokenResult (type, status, rowCount);
- Console.WriteLine ("Row count {0}", rowCount);
-
moreResults = result.MoreResults;
// FIXME: Finish the query
blockSize = encoder.GetString (comm.GetBytes (cLen, false), 0, cLen);
comm.Skip (len - 2 - cLen);
}
-
comm.ResizeOutBuf (Int32.Parse (blockSize));
break;
case TdsEnvPacketSubType.CharSet :
cLen = comm.GetByte () & 0xff;
if (tdsVersion == TdsVersion.tds70) {
- this.language = comm.GetString (cLen);
+ //this.language = comm.GetString (cLen); // FIXME
+ comm.GetString (cLen);
comm.Skip (len - 2 - cLen * 2);
}
else {
- this.charset = encoder.GetString (comm.GetBytes (cLen, false), 0, cLen);
+ SetCharset (encoder.GetString (comm.GetBytes (cLen, false), 0, cLen));
comm.Skip (len - 2 - cLen);
- SetCharset (charset);
}
break;
string newDB = tdsVersion == TdsVersion.tds70 ? comm.GetString (cLen) : encoder.GetString (comm.GetBytes (cLen, false), 0, cLen);
cLen = comm.GetByte () & 0xff;
string oldDB = tdsVersion == TdsVersion.tds70 ? comm.GetString (cLen) : encoder.GetString (comm.GetBytes (cLen, false), 0, cLen);
- if (database != String.Empty && database != oldDB)
+ if (database != null && database != oldDB)
throw new TdsException ("Database mismatch.");
database = newDB;
break;
databaseProductVersion = String.Format ("{0}.{1}", databaseMajorVersion, comm.GetByte ());
comm.Skip (1);
}
- Console.WriteLine ("Connected to {0} {1}", databaseProductName, databaseProductVersion);
if (databaseProductName.Length > 1 && -1 != databaseProductName.IndexOf ('\0')) {
int last = databaseProductName.IndexOf ('\0');
message.Line = comm.GetByte ();
comm.GetByte ();
- Console.WriteLine (message.ToString ());
-
lastServerMessage = message;
if (subType == TdsPacketSubType.Error)
- return new TdsPacketErrorResult (subType, message);
- else
- return new TdsPacketMessageResult (subType, message);
+ throw new TdsException (message.ToString ());
+
+ Console.WriteLine (message.ToString ());
+
+ return new TdsPacketMessageResult (subType, message);
}
private TdsPacketOutputParam ProcessOutputParam ()
case TdsColumnType.Char :
case TdsColumnType.VarChar :
comm.GetByte ();
- element = GetCharValue (false, true);
+ element = GetStringValue (false, true);
break;
case TdsColumnType.BigVarBinary :
comm.GetTdsShort ();
break;
case TdsColumnType.BigVarChar :
comm.GetTdsShort ();
- element = GetCharValue (false, false);
+ element = GetStringValue (false, false);
break;
case TdsColumnType.NChar :
case TdsColumnType.NVarChar :
comm.GetByte ();
- element = GetCharValue (true, true);
+ element = GetStringValue (true, true);
break;
case TdsColumnType.Real :
element = ReadFloatN (4);
}
[MonoTODO]
- private TdsPacketResult ProcessSubPacket ()
+ protected TdsPacketResult ProcessSubPacket ()
{
TdsPacketResult result = null;
moreResults = false;
switch (subType) {
case TdsPacketSubType.EnvChange :
-Console.WriteLine ("Environment change");
result = ProcessEnvChange ();
break;
case TdsPacketSubType.Error :
case TdsPacketSubType.Info :
case TdsPacketSubType.Msg50Token :
-Console.WriteLine ("Error/info/message");
result = ProcessMessage (subType);
break;
case TdsPacketSubType.Param :
-Console.WriteLine ("Param");
+Console.WriteLine ("OUTPUT PARAMETER PACKET RECEIVED");
result = ProcessOutputParam ();
break;
case TdsPacketSubType.LoginAck :
-Console.WriteLine ("Login Ack");
result = ProcessLoginAck ();
break;
case TdsPacketSubType.ReturnStatus :
-Console.WriteLine ("Return Status");
+Console.WriteLine ("RETURN STATUS PACKET RECEIVED");
result = ProcessReturnStatus ();
break;
case TdsPacketSubType.ProcId :
-Console.WriteLine ("Proc Id");
+Console.WriteLine ("PROC ID PACKET RECEIVED");
result = ProcessProcId ();
break;
case TdsPacketSubType.Done :
case TdsPacketSubType.DoneProc :
case TdsPacketSubType.DoneInProc :
-Console.WriteLine ("Done");
result = ProcessEndToken (subType);
moreResults2 = ((TdsPacketEndTokenResult) result).MoreResults;
break;
case TdsPacketSubType.ColumnNameToken :
-Console.WriteLine ("Column Name");
+Console.WriteLine ("COLUMN NAME TOKEN PACKET RECEIVED");
result = ProcessColumnNames ();
break;
case TdsPacketSubType.ColumnInfoToken :
-Console.WriteLine ("Column Info");
+Console.WriteLine ("COLUMN INFO TOKEN PACKET RECEIVED");
result = ProcessColumnInfo ();
break;
case TdsPacketSubType.Unknown0xA5 :
case TdsPacketSubType.Unknown0xA7 :
case TdsPacketSubType.Unknown0xA8 :
-Console.WriteLine ("Unknown");
+Console.WriteLine ("UNKNOWN PACKET RECEIVED");
comm.Skip (comm.GetTdsShort ());
result = new TdsPacketUnknown (subType);
break;
case TdsPacketSubType.TableName :
-Console.WriteLine ("Table Name");
+Console.WriteLine ("TABLE NAME PACKET RECEIVED");
result = ProcessTableName ();
break;
case TdsPacketSubType.Order :
-Console.WriteLine ("Order");
+Console.WriteLine ("COLUMN ORDER PACKET RECEIVED");
comm.Skip (comm.GetTdsShort ());
result = new TdsPacketColumnOrderResult ();
break;
case TdsPacketSubType.Control :
-Console.WriteLine ("Control");
+Console.WriteLine ("CONTROL PACKET RECEIVED");
comm.Skip (comm.GetTdsShort ());
result = new TdsPacketControlResult ();
break;
case TdsPacketSubType.Row :
-Console.WriteLine ("Row");
+Console.WriteLine ("ROW RESULT PACKET RECEIVED");
result = LoadRow (new TdsPacketRowResult (null));
break;
case TdsPacketSubType.ColumnMetadata :
-Console.WriteLine ("Column Metadata");
+Console.WriteLine ("COLUMN METADATA PACKET RECEIVED");
result = ProcessTds7Result ();
break;
default:
return tmp;
}
- [MonoTODO]
- public void RollbackTransaction ()
+ protected void SetCharset (string charset)
{
- SubmitProcedure ("IF @@TRANCOUNT>0 ROLLBACK TRAN");
- }
+ if (charset == null || charset.Length > 30)
+ charset = "iso_1";
- [MonoTODO]
- public void SaveTransaction (string savePointName)
- {
- string sql = String.Format ("SAVE TRAN {0}", savePointName);
- SubmitProcedure (sql);
- }
+ if (this.charset != null && this.charset != charset)
+ return;
- private void SetCharset (string charset)
- {
- if (charset == null || charset.Length > 30)
- charset = "iso-8859-1";
- if (this.charset != charset) {
- encoder = Encoding.GetEncoding (charset);
+ if (charset.StartsWith ("cp")) {
+ encoder = Encoding.GetEncoding (Int32.Parse (charset.Substring (2)));
this.charset = charset;
}
+ else {
+ encoder = Encoding.GetEncoding ("iso-8859-1");
+ this.charset = "iso_1";
+ }
+ comm.Encoder = encoder;
+ }
+
+ protected void SetLanguage (string language)
+ {
+ if (language == null || language.Length > 30)
+ language = "us_english";
+
+ this.language = language;
}
public void SubmitProcedure (string sql)
{
TdsPacketResult result;
ExecuteQuery (sql);
- bool done;
+
+ bool done = false;
do {
result = ProcessSubPacket ();
- if (result is TdsPacketMessageResult) {
- Console.WriteLine (((TdsPacketMessageResult) result).Message);
- }
done = (result is TdsPacketEndTokenResult) && (!((TdsPacketEndTokenResult) result).MoreResults);
} while (!done);
}
- public void Close ()
+ public void Disconnect ()
{
}
- public bool Logon (TdsConnectionParameters parms)
- {
- byte pad = (byte) 0;
- byte[] empty = new byte[0];
- bool isOkay = true;
-
- if (tdsVersion == TdsVersion.tds70) {
- Send70Logon (parms);
- } else {
- comm.StartPacket (TdsPacketType.Logon);
-
- // hostname (offset 0)
- byte[] tmp = comm.Append (hostname, 30, pad);
- comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
-
- // username (offset 31 0x1f)
- tmp = comm.Append (user, 30, pad);
- comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
-
- // password (offset 62 0x3e)
- tmp = comm.Append (password, 30, pad);
- comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
-
- // hostproc (offset 93 0x5d)
- comm.Append ("00000116", 8, pad);
-
- // unused (offset 109 0x6d)
- comm.Append (empty, (30-14), pad);
-
- // apptype
- comm.Append ((byte) 0x0);
- comm.Append ((byte) 0xa0);
- comm.Append ((byte) 0x24);
- comm.Append ((byte) 0xcc);
- comm.Append ((byte) 0x50);
- comm.Append ((byte) 0x12);
-
- // hostproc length
- comm.Append ((byte) 8);
-
- // type of int2
- comm.Append ((byte) 3);
-
- // type of int4
- comm.Append ((byte) 1);
-
- // type of char
- comm.Append ((byte) 6);
-
- // type of flt
- comm.Append ((byte) 10);
-
- // type of date
- comm.Append ((byte) 9);
-
- // notify of use db
- comm.Append ((byte) 1);
-
- // disallow dump/load and bulk insert
- comm.Append ((byte) 1);
-
- // sql interface type
- comm.Append ((byte) 0);
-
- // type of network connection
- comm.Append ((byte) 0);
-
-
- // spare [7]
- comm.Append (empty, 7, pad);
- // appname
- tmp = comm.Append (applicationName, 30, pad);
- comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
-
- // server name
- tmp = comm.Append (server, 30, pad);
- comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
-
- // remote passwords
- comm.Append (empty, 2, pad);
- tmp = comm.Append (password, 253, pad);
- comm.Append ((byte) (tmp.Length < 253 ? tmp.Length + 2 : 253 + 2));
-
- // tds version
- comm.Append ((byte) (((byte) tdsVersion) / 10));
- comm.Append ((byte) (((byte) tdsVersion) % 10));
- comm.Append ((byte) 0);
- comm.Append ((byte) 0);
-
- // prog name
- tmp = comm.Append (progName, 10, pad);
- comm.Append ((byte) (tmp.Length < 10 ? tmp.Length : 10));
-
- // prog version
- comm.Append ((byte) 6);
-
- // Tell the server we can handle SQLServer version 6
- comm.Append ((byte) 0);
-
- // Send zero to tell the server we can't handle any other version
- comm.Append ((byte) 0);
- comm.Append ((byte) 0);
-
- // auto convert short
- comm.Append ((byte) 0);
-
- // type of flt4
- comm.Append ((byte) 0x0d);
-
- // type of date4
- comm.Append ((byte) 0x11);
-
- // language
- tmp = comm.Append (language, 30, pad);
- comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
-
- // notify on lang change
- comm.Append ((byte) 1);
-
- // security label hierarchy
- comm.Append ((short) 0);
-
- // security components
- comm.Append (empty, 8, pad);
-
- // security spare
- comm.Append ((short) 0);
-
- // security login role
- comm.Append ((byte) 0);
-
- // charset
- tmp = comm.Append (charset, 30, pad);
- comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
-
- // notify on charset change
- comm.Append ((byte) 1);
-
- // length of tds packets
- tmp = comm.Append (packetSize.ToString (), 6, pad);
- comm.Append ((byte) 3);
-
- // pad out to a longword
- comm.Append (empty, 8, pad);
- }
-
- comm.SendPacket ();
-
- TdsPacketResult result;
-
- while (!((result = ProcessSubPacket()) is TdsPacketEndTokenResult)) {
- if (result is TdsPacketErrorResult) {
- isOkay = false;
- }
- // XXX Should really process some more types of packets.
- }
-
- if (isOkay) {
- // XXX Should we move this to the Connection class?
- //isOkay = initSettings(_database);
- }
-
- // XXX Possible bug. What happend if this is cancelled before the logon
- // takes place? Should isOkay be false?
- return isOkay;
-
- }
-
- // This packet is documented at
- // http://www.freetds.org/tds.htm#login7
- public void Send70Logon (TdsConnectionParameters parms)
- {
- byte[] empty = new byte[0];
- byte pad = (byte) 0;
-
- byte[] magic1 = {0x06, 0x83, 0xf2, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x88, 0xff, 0xff, 0xff, 0x36, 0x04, 0x00, 0x00};
- byte[] magic2 = {0x00, 0x40, 0x33, 0x9a, 0x6b, 0x50};
- byte[] magic3 = {0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50}; // NTLMSSP
- short partialPacketSize = (short) (86 + 2 * (
- hostname.Length +
- user.Length +
- applicationName.Length +
- password.Length +
- server.Length +
- libraryName.Length +
- language.Length +
- connectDB.Length));
- short totalPacketSize = (short) (partialPacketSize + 48);
- comm.StartPacket (TdsPacketType.Logon70);
- comm.Append (totalPacketSize);
- comm.Append (empty, 5, pad);
-
- if (tdsVersion == TdsVersion.tds80)
- comm.Append ((byte) 0x80);
- else
- comm.Append ((byte) 0x70);
-
- comm.Append (empty, 7, pad);
- comm.Append (magic1);
-
- short curPos = 86;
-
- // Hostname
- comm.Append (curPos);
- comm.Append ((short) hostname.Length);
- curPos += (short) (hostname.Length * 2);
-
- // Username
- comm.Append (curPos);
- comm.Append ((short) user.Length);
- curPos += (short) (user.Length * 2);
-
- // Password
- comm.Append (curPos);
- comm.Append ((short) password.Length);
- curPos += (short) (password.Length * 2);
-
- // AppName
- comm.Append (curPos);
- comm.Append ((short) applicationName.Length);
- curPos += (short) (applicationName.Length * 2);
-
- // Server Name
- comm.Append (curPos);
- comm.Append ((short) server.Length);
- curPos += (short) (server.Length * 2);
-
- // Unknown
- comm.Append ((short) 0);
- comm.Append ((short) 0);
-
- // Library Name
- comm.Append (curPos);
- comm.Append ((short) libraryName.Length);
- curPos += (short) (libraryName.Length * 2);
-
- // Character Set
- comm.Append (curPos);
- comm.Append ((short) language.Length);
- curPos += (short) (language.Length * 2);
-
- // Database
- comm.Append (curPos);
- comm.Append ((short) connectDB.Length);
- curPos += (short) (connectDB.Length * 2);
-
- comm.Append (magic2);
- comm.Append (partialPacketSize);
- comm.Append ((short) 48);
- comm.Append (totalPacketSize);
- comm.Append ((short) 0);
-
- string scrambledPwd = Tds7CryptPass (password);
-
- comm.Append (hostname);
- comm.Append (user);
- comm.Append (scrambledPwd);
- comm.Append (applicationName);
- comm.Append (server);
- comm.Append (libraryName);
- comm.Append (language);
- comm.Append (connectDB);
- comm.Append (magic3);
-
- comm.Append ((byte) 0x0);
- comm.Append ((byte) 0x1);
- comm.Append (empty, 3, pad);
- comm.Append ((byte) 0x6);
- comm.Append ((byte) 0x82);
- comm.Append (empty, 22, pad);
- comm.Append ((byte) 0x30);
- comm.Append (empty, 7, pad);
- comm.Append ((byte) 0x30);
- comm.Append (empty, 3, pad);
- }
+ public abstract bool Connect (TdsConnectionParameters connectionParameters);
private string SqlStatementForSettings (bool autoCommit, IsolationLevel isolationLevel)
{
--- /dev/null
+//
+// Mono.Data.TdsClient.Internal.Tds42.cs
+//
+// Author:
+// Tim Coleman (tim@timcoleman.com)
+//
+// Copyright (C) 2002 Tim Coleman
+//
+
+using System;
+
+namespace Mono.Data.TdsClient.Internal {
+ internal class Tds42 : Tds, ITds
+ {
+ #region Fields
+
+ public static readonly TdsVersion Version = TdsVersion.tds42;
+
+ #endregion // Fields
+
+ #region Constructors
+
+ public Tds42 (string server, int port)
+ : this (server, port, 512)
+ {
+ }
+
+ public Tds42 (string server, int port, int packetSize)
+ : base (server, port, packetSize, Version)
+ {
+ }
+
+ #endregion // Constructors
+
+ #region Methods
+
+ public override bool Connect (TdsConnectionParameters connectionParameters)
+ {
+ if (IsConnected)
+ throw new InvalidOperationException ("The connection is already open.");
+
+ SetCharset (connectionParameters.Charset);
+ SetLanguage (connectionParameters.Language);
+
+ byte pad = (byte) 0;
+ byte[] empty = new byte[0];
+ bool isOkay = true;
+
+ Comm.StartPacket (TdsPacketType.Logon);
+
+ // hostname (offset 0)
+ byte[] tmp = Comm.Append (connectionParameters.Hostname, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // username (offset 31 0x1f)
+ tmp = Comm.Append (connectionParameters.User, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // password (offset 62 0x3e)
+ tmp = Comm.Append (connectionParameters.Password, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // hostproc (offset 93 0x5d)
+ Comm.Append ("00000116", 8, pad);
+
+ // unused (offset 109 0x6d)
+ Comm.Append (empty, (30-14), pad);
+
+ // apptype
+ Comm.Append ((byte) 0x0);
+ Comm.Append ((byte) 0xa0);
+ Comm.Append ((byte) 0x24);
+ Comm.Append ((byte) 0xcc);
+ Comm.Append ((byte) 0x50);
+ Comm.Append ((byte) 0x12);
+
+ // hostproc length
+ Comm.Append ((byte) 8);
+
+ // Byte order of 2 byte ints
+ // 2 = <MSB, LSB>, 3 = <LSB, MSB>
+ Comm.Append ((byte) 3);
+
+ // Byte order of 4 byte ints
+ // 0 = <MSB, LSB>, 1 = <LSB, MSB>
+ Comm.Append ((byte) 1);
+
+ // Character representation
+ // (6 = ASCII, 7 = EBCDIC)
+ Comm.Append ((byte) 6);
+
+ // Eight byte floating point representation
+ // 4 = IEEE <MSB, ..., LSB>
+ // 5 = VAX 'D'
+ // 10 = IEEE <LSB, ..., MSB>
+ // 11 = ND5000
+ Comm.Append ((byte) 10);
+
+ // Eight byte date format
+ // 8 = <MSB, ..., LSB>
+ Comm.Append ((byte) 9);
+
+ // notify of use db
+ Comm.Append ((byte) 1);
+
+ // disallow dump/load and bulk insert
+ Comm.Append ((byte) 1);
+
+ // sql interface type
+ Comm.Append ((byte) 0);
+
+ // type of network connection
+ Comm.Append ((byte) 0);
+
+
+ // spare [7]
+ Comm.Append (empty, 7, pad);
+ // appname
+ tmp = Comm.Append (connectionParameters.ApplicationName, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // server name
+ tmp = Comm.Append (DataSource, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // remote passwords
+ Comm.Append (empty, 2, pad);
+ tmp = Comm.Append (connectionParameters.Password, 253, pad);
+ Comm.Append ((byte) (tmp.Length < 253 ? tmp.Length + 2 : 253 + 2));
+
+ // tds version
+ Comm.Append ((byte) (((byte) Version) / 10));
+ Comm.Append ((byte) (((byte) Version) % 10));
+ Comm.Append ((byte) 0);
+ Comm.Append ((byte) 0);
+
+ // prog name
+ tmp = Comm.Append (connectionParameters.ProgName, 10, pad);
+ Comm.Append ((byte) (tmp.Length < 10 ? tmp.Length : 10));
+
+ // prog version
+ Comm.Append ((byte) 6);
+
+ // Tell the server we can handle SQLServer version 6
+ Comm.Append ((byte) 0);
+
+ // Send zero to tell the server we can't handle any other version
+ Comm.Append ((byte) 0);
+ Comm.Append ((byte) 0);
+
+ // auto convert short
+ Comm.Append ((byte) 0);
+
+ // type of flt4
+ Comm.Append ((byte) 0x0d);
+
+ // type of date4
+ Comm.Append ((byte) 0x11);
+
+ // language
+ tmp = Comm.Append (Language, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // notify on lang change
+ Comm.Append ((byte) 1);
+
+ // security label hierarchy
+ Comm.Append ((short) 0);
+
+ // security components
+ Comm.Append (empty, 8, pad);
+
+ // security spare
+ Comm.Append ((short) 0);
+
+ // security login role
+ Comm.Append ((byte) 0);
+
+ // charset
+ tmp = Comm.Append (Charset, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // notify on charset change
+ Comm.Append ((byte) 1);
+
+ // length of tds packets
+ tmp = Comm.Append (PacketSize.ToString (), 6, pad);
+ Comm.Append ((byte) 3);
+
+ // pad out to a longword
+ Comm.Append (empty, 8, pad);
+
+ Comm.SendPacket ();
+
+ TdsPacketResult result;
+
+ while (!((result = ProcessSubPacket()) is TdsPacketEndTokenResult)) {
+ if (result is TdsPacketErrorResult) {
+ isOkay = false;
+ break;
+ }
+ // XXX Should really process some more types of packets.
+ }
+
+ // XXX Possible bug. What happend if this is cancelled before the logon
+ // takes place? Should isOkay be false?
+
+ IsConnected = isOkay;
+ return isOkay;
+ }
+
+ #endregion // Methods
+ }
+}
--- /dev/null
+//
+// Mono.Data.TdsClient.Internal.Tds50.cs
+//
+// Author:
+// Tim Coleman (tim@timcoleman.com)
+//
+// Copyright (C) 2002 Tim Coleman
+//
+
+using System;
+
+namespace Mono.Data.TdsClient.Internal {
+ internal class Tds50 : Tds, ITds
+ {
+ #region Fields
+
+ public static readonly TdsVersion Version = TdsVersion.tds50;
+
+ #endregion // Fields
+
+ #region Constructors
+
+ public Tds50 (string server, int port)
+ : this (server, port, 512)
+ {
+ }
+
+ public Tds50 (string server, int port, int packetSize)
+ : base (server, port, packetSize, Version)
+ {
+ }
+
+ #endregion // Constructors
+
+ #region Methods
+
+ public override bool Connect (TdsConnectionParameters connectionParameters)
+ {
+ if (IsConnected)
+ throw new InvalidOperationException ("The connection is already open.");
+
+ SetCharset (connectionParameters.Charset);
+ SetLanguage (connectionParameters.Language);
+
+ byte pad = (byte) 0;
+ byte[] empty = new byte[0];
+ bool isOkay = true;
+
+ Comm.StartPacket (TdsPacketType.Logon);
+
+ // hostname (offset 0)
+ byte[] tmp = Comm.Append (connectionParameters.Hostname, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // username (offset 31 0x1f)
+ tmp = Comm.Append (connectionParameters.User, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // password (offset 62 0x3e)
+ tmp = Comm.Append (connectionParameters.Password, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // hostproc (offset 93 0x5d)
+ Comm.Append ("00000116", 8, pad);
+
+ // unused (offset 109 0x6d)
+ Comm.Append (empty, (30-14), pad);
+
+ // apptype
+ Comm.Append ((byte) 0x0);
+ Comm.Append ((byte) 0xa0);
+ Comm.Append ((byte) 0x24);
+ Comm.Append ((byte) 0xcc);
+ Comm.Append ((byte) 0x50);
+ Comm.Append ((byte) 0x12);
+
+ // hostproc length
+ Comm.Append ((byte) 8);
+
+ // Byte order of 2 byte ints
+ // 2 = <MSB, LSB>, 3 = <LSB, MSB>
+ Comm.Append ((byte) 3);
+
+ // Byte order of 4 byte ints
+ // 0 = <MSB, LSB>, 1 = <LSB, MSB>
+ Comm.Append ((byte) 1);
+
+ // Character representation
+ // (6 = ASCII, 7 = EBCDIC)
+ Comm.Append ((byte) 6);
+
+ // Eight byte floating point representation
+ // 4 = IEEE <MSB, ..., LSB>
+ // 5 = VAX 'D'
+ // 10 = IEEE <LSB, ..., MSB>
+ // 11 = ND5000
+ Comm.Append ((byte) 10);
+
+ // Eight byte date format
+ // 8 = <MSB, ..., LSB>
+ Comm.Append ((byte) 9);
+
+ // notify of use db
+ Comm.Append ((byte) 1);
+
+ // disallow dump/load and bulk insert
+ Comm.Append ((byte) 1);
+
+ // sql interface type
+ Comm.Append ((byte) 0);
+
+ // type of network connection
+ Comm.Append ((byte) 0);
+
+
+ // spare [7]
+ Comm.Append (empty, 7, pad);
+ // appname
+ tmp = Comm.Append (connectionParameters.ApplicationName, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // server name
+ tmp = Comm.Append (DataSource, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // remote passwords
+ Comm.Append (empty, 2, pad);
+ tmp = Comm.Append (connectionParameters.Password, 253, pad);
+ Comm.Append ((byte) (tmp.Length < 253 ? tmp.Length + 2 : 253 + 2));
+
+ // tds version
+ Comm.Append ((byte) (((byte) Version) / 10));
+ Comm.Append ((byte) (((byte) Version) % 10));
+ Comm.Append ((byte) 0);
+ Comm.Append ((byte) 0);
+
+ // prog name
+ tmp = Comm.Append (connectionParameters.ProgName, 10, pad);
+ Comm.Append ((byte) (tmp.Length < 10 ? tmp.Length : 10));
+
+ // prog version
+ Comm.Append ((byte) 6);
+
+ // Tell the server we can handle SQLServer version 6
+ Comm.Append ((byte) 0);
+
+ // Send zero to tell the server we can't handle any other version
+ Comm.Append ((byte) 0);
+ Comm.Append ((byte) 0);
+
+ // auto convert short
+ Comm.Append ((byte) 0);
+
+ // type of flt4
+ Comm.Append ((byte) 0x0d);
+
+ // type of date4
+ Comm.Append ((byte) 0x11);
+
+ // language
+ tmp = Comm.Append (Language, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // notify on lang change
+ Comm.Append ((byte) 1);
+
+ // security label hierarchy
+ Comm.Append ((short) 0);
+
+ // security components
+ Comm.Append (empty, 8, pad);
+
+ // security spare
+ Comm.Append ((short) 0);
+
+ // security login role
+ Comm.Append ((byte) 0);
+
+ // charset
+ tmp = Comm.Append (Charset, 30, pad);
+ Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
+
+ // notify on charset change
+ Comm.Append ((byte) 1);
+
+ // length of tds packets
+ tmp = Comm.Append (PacketSize.ToString (), 6, pad);
+ Comm.Append ((byte) 3);
+
+ // pad out to a longword
+ Comm.Append (empty, 8, pad);
+
+ Comm.SendPacket ();
+
+ TdsPacketResult result;
+
+ while (!((result = ProcessSubPacket()) is TdsPacketEndTokenResult)) {
+ if (result is TdsPacketErrorResult) {
+ isOkay = false;
+ }
+ // XXX Should really process some more types of packets.
+ }
+
+ IsConnected = isOkay;
+ return isOkay;
+ }
+
+ #endregion // Methods
+ }
+}
--- /dev/null
+//
+// Mono.Data.TdsClient.Internal.Tds70.cs
+//
+// Author:
+// Tim Coleman (tim@timcoleman.com)
+//
+// Copyright (C) 2002 Tim Coleman
+//
+
+using System;
+
+namespace Mono.Data.TdsClient.Internal {
+ internal class Tds70 : Tds, ITds
+ {
+ #region Fields
+
+ public readonly static TdsVersion Version = TdsVersion.tds70;
+
+ #endregion // Fields
+
+ #region Constructors
+
+ public Tds70 (string server, int port)
+ : this (server, port, 512)
+ {
+ }
+
+ public Tds70 (string server, int port, int packetSize)
+ : base (server, port, packetSize, Version)
+ {
+ }
+
+ #endregion // Constructors
+
+ #region Methods
+
+ public override bool Connect (TdsConnectionParameters connectionParameters)
+ {
+ if (IsConnected)
+ throw new InvalidOperationException ("The connection is already open.");
+
+ bool isOkay = true;
+
+ SetLanguage (connectionParameters.Language);
+
+ byte[] empty = new byte[0];
+ byte pad = (byte) 0;
+
+ byte[] magic1 = {0x06, 0x83, 0xf2, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x88, 0xff, 0xff, 0xff, 0x36, 0x04, 0x00, 0x00};
+ byte[] magic2 = {0x00, 0x40, 0x33, 0x9a, 0x6b, 0x50};
+ byte[] magic3 = {0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50}; // NTLMSSP
+ short partialPacketSize = (short) (86 + 2 * (
+ connectionParameters.Hostname.Length +
+ connectionParameters.User.Length +
+ connectionParameters.ApplicationName.Length +
+ connectionParameters.Password.Length +
+ DataSource.Length +
+ connectionParameters.LibraryName.Length +
+ Language.Length +
+ connectionParameters.Database.Length));
+ short totalPacketSize = (short) (partialPacketSize + 48);
+ Comm.StartPacket (TdsPacketType.Logon70);
+ Comm.Append (totalPacketSize);
+ Comm.Append (empty, 5, pad);
+
+ Comm.Append ((byte) 0x70); // TDS VERSION 7
+ Comm.Append (empty, 7, pad);
+ Comm.Append (magic1);
+
+ short curPos = 86;
+
+ // Hostname
+ Comm.Append (curPos);
+ Comm.Append ((short) connectionParameters.Hostname.Length);
+ curPos += (short) (connectionParameters.Hostname.Length * 2);
+
+ // Username
+ Comm.Append (curPos);
+ Comm.Append ((short) connectionParameters.User.Length);
+ curPos += (short) (connectionParameters.User.Length * 2);
+
+ // Password
+ Comm.Append (curPos);
+ Comm.Append ((short) connectionParameters.Password.Length);
+ curPos += (short) (connectionParameters.Password.Length * 2);
+
+ // AppName
+ Comm.Append (curPos);
+ Comm.Append ((short) connectionParameters.ApplicationName.Length);
+ curPos += (short) (connectionParameters.ApplicationName.Length * 2);
+
+ // Server Name
+ Comm.Append (curPos);
+ Comm.Append ((short) DataSource.Length);
+ curPos += (short) (DataSource.Length * 2);
+
+ // Unknown
+ Comm.Append ((short) 0);
+ Comm.Append ((short) 0);
+
+ // Library Name
+ Comm.Append (curPos);
+ Comm.Append ((short) connectionParameters.LibraryName.Length);
+ curPos += (short) (connectionParameters.LibraryName.Length * 2);
+
+ // Language
+ Comm.Append (curPos);
+ Comm.Append ((short) Language.Length);
+ curPos += (short) (Language.Length * 2);
+
+ // Database
+ Comm.Append (curPos);
+ Comm.Append ((short) connectionParameters.Database.Length);
+ curPos += (short) (connectionParameters.Database.Length * 2);
+
+ Comm.Append (magic2);
+ Comm.Append (partialPacketSize);
+ Comm.Append ((short) 48);
+ Comm.Append (totalPacketSize);
+ Comm.Append ((short) 0);
+
+ string scrambledPwd = EncryptPassword (connectionParameters.Password);
+
+ Comm.Append (connectionParameters.Hostname);
+ Comm.Append (connectionParameters.User);
+ Comm.Append (scrambledPwd);
+ Comm.Append (connectionParameters.ApplicationName);
+ Comm.Append (DataSource);
+ Comm.Append (connectionParameters.LibraryName);
+ Comm.Append (Language);
+ Comm.Append (connectionParameters.Database);
+ Comm.Append (magic3);
+
+ Comm.Append ((byte) 0x0);
+ Comm.Append ((byte) 0x1);
+ Comm.Append (empty, 3, pad);
+ Comm.Append ((byte) 0x6);
+ Comm.Append ((byte) 0x82);
+ Comm.Append (empty, 22, pad);
+ Comm.Append ((byte) 0x30);
+ Comm.Append (empty, 7, pad);
+ Comm.Append ((byte) 0x30);
+ Comm.Append (empty, 3, pad);
+ Comm.SendPacket ();
+
+ TdsPacketResult result;
+
+ while (!((result = ProcessSubPacket()) is TdsPacketEndTokenResult)) {
+ if (result is TdsPacketErrorResult) {
+ isOkay = false;
+ break;
+ }
+ // XXX Should really process some more types of packets.
+ }
+
+ IsConnected = isOkay;
+ return isOkay;
+ }
+
+ private static string EncryptPassword (string pass)
+ {
+ int xormask = 0x5a5a;
+ int len = pass.Length;
+ char[] chars = new char[len];
+
+ for (int i = 0; i < len; ++i) {
+ int c = ((int) (pass[i])) ^ xormask;
+ int m1 = (c >> 4) & 0x0f0f;
+ int m2 = (c << 4) & 0xf0f0;
+ chars[i] = (char) (m1 | m2);
+ }
+
+ return new String (chars);
+ }
+
+ #endregion // Methods
+ }
+}
--- /dev/null
+//
+// Mono.Data.TdsClient.Internal.Tds80.cs
+//
+// Author:
+// Tim Coleman (tim@timcoleman.com)
+//
+// Copyright (C) 2002 Tim Coleman
+//
+
+using System;
+
+namespace Mono.Data.TdsClient.Internal {
+ internal class Tds80 : Tds, ITds
+ {
+ #region Fields
+
+ public static readonly TdsVersion Version = TdsVersion.tds80;
+
+ #endregion // Fields
+
+ #region Constructors
+
+ public Tds80 (string server, int port)
+ : this (server, port, 512)
+ {
+ }
+
+ public Tds80 (string server, int port, int packetSize)
+ : base (server, port, packetSize, Version)
+ {
+ }
+
+ #endregion // Constructors
+
+ #region Methods
+
+ public override bool Connect (TdsConnectionParameters connectionParameters)
+ {
+ throw new NotImplementedException ();
+ }
+
+ #endregion // Methods
+ }
+}
Int1 = 0x30,
Bit = 0x32,
Int2 = 0x34,
- Int4 = 0x56,
+ Int4 = 0x38,
DateTime4 = 0x3a,
Real = 0x3b,
Money = 0x3c,
#region Constructors
- public TdsComm (Encoding encoder, Socket socket, int packetSize, TdsVersion tdsVersion)
+ public TdsComm (Socket socket, int packetSize, TdsVersion tdsVersion)
{
- this.encoder = encoder;
this.packetSize = packetSize;
this.tdsVersion = tdsVersion;
#endregion // Constructors
#region Properties
+
+ internal Encoding Encoder {
+ set { encoder = value; }
+ }
public int PacketSize {
get { return packetSize; }
// Appends with padding
public byte[] Append (string s, int len, byte pad)
{
+ if (s == null)
+ return new byte[0];
+
byte[] result = encoder.GetBytes (s);
Append (result, len, pad);
return result;
{
public string ApplicationName = "Mono";
public string Database;
- public string DataSource;
- public string Encoding = "iso-8859-1";
+ public string Charset;
public string Hostname = "localhost";
- public string Language = "us_english";
+ public string Language;
public string LibraryName = "Mono";
- public int PacketSize;
public string Password;
- public int Port = 1433;
public string ProgName = "Mono";
- public TdsVersion TdsVersion = TdsVersion.tds42;
public string User;
}
}
int rowCount;
bool isRetStatSet;
int retStat;
+ TdsPacketSubType type;
#endregion // Fields
{
if (type == TdsPacketSubType.DoneInProc)
throw new TdsException ("");
+ this.type = type;
this.status = status;
this.rowCount = rowCount;
this.isRetStatSet = false;
[MonoTODO]
public override string ToString ()
{
- throw new NotImplementedException ();
+ return String.Format ("token type: {0}, row count: {1}, more results: {2}, was cancelled? {3}, return status: {4}", type, RowCount, MoreResults, Cancelled, (ReturnStatusExists ? ReturnStatus.ToString () : "No return status"));
}
#endregion // Methods