2 // Mono.Data.TdsClient.Internal.Tds.cs
5 // Tim Coleman (tim@timcoleman.com)
7 // Copyright (C) 2002 Tim Coleman
13 using System.Net.Sockets;
16 namespace Mono.Data.TdsClient.Internal {
21 TdsVersion tdsVersion;
23 string applicationName;
24 string database = String.Empty;
27 string hostname = "tux";
36 string databaseProductName;
37 string databaseProductVersion;
38 int databaseMajorVersion;
40 DataTable table = new DataTable ();
45 TdsMessage lastServerMessage;
48 TdsServerType serverType;
50 TdsConnectionParameters parms;
52 IsolationLevel isolationLevel;
54 Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.IP);
60 //public TdsCommandInternal Command {
61 //get { return command; }
62 //set { command = value; }
65 public string Database {
66 get { return database; }
67 set { database = value; }
70 public TdsVersion TdsVersion {
71 get { return tdsVersion; }
74 #endregion // Properties
78 public Tds (TdsConnectionParameters parms)
80 applicationName = parms.ApplicationName;
81 connectDB = parms.Database;
82 encoder = Encoding.GetEncoding (parms.Encoding);
83 charset = parms.Encoding;
85 language = parms.Language;
86 libraryName = parms.LibraryName;
87 packetSize = parms.PacketSize;
88 password = parms.Password;
89 progName = parms.ProgName;
90 tdsVersion = parms.TdsVersion;
93 IPHostEntry hostEntry = Dns.GetHostByName (parms.Host);
94 IPAddress[] addresses = hostEntry.AddressList;
98 foreach (IPAddress address in addresses) {
99 endPoint = new IPEndPoint (address, parms.Port);
100 socket.Connect (endPoint);
102 if (socket.Connected)
106 comm = new TdsComm (encoder, socket, packetSize, tdsVersion);
109 #endregion // Constructors
113 public void ChangeDatabase (string databaseName)
115 string query = String.Format ("use {0}", databaseName);
116 comm.StartPacket (TdsPacketType.Query);
121 public void ChangeSettings (bool autoCommit, IsolationLevel isolationLevel)
123 /*string query = SqlStatementForSettings (autoCommit, isolationLevel);
125 ChangeSettings (query);
129 private bool ChangeSettings (string query)
131 TdsPacketResult result;
133 if (query.Length == 0)
136 comm.StartPacket (TdsPacketType.Query);
142 result = ProcessSubPacket ();
143 done = (result is TdsPacketEndTokenResult) && !((TdsPacketEndTokenResult) result).MoreResults;
144 if (result is TdsPacketErrorResult) {
153 private object GetCharValue (bool wideChars, bool outputParam)
155 object result = null;
156 bool shortLen = (tdsVersion == TdsVersion.tds70) && (wideChars || !outputParam);
157 int len = shortLen ? comm.GetTdsShort () : (comm.GetByte () & 0xff);
159 if ((tdsVersion < TdsVersion.tds70 && len == 0) || (tdsVersion == TdsVersion.tds70 && len == 0xffff))
163 result = comm.GetString (len / 2);
165 result = encoder.GetString (comm.GetBytes (len, false), 0, len);
167 if ((byte) tdsVersion < (byte) TdsVersion.tds70 && result == " ")
171 throw new TdsException ("");
176 private object GetDecimalValue (int scale)
178 throw new NotImplementedException ();
182 private object GetDateTimeValue (TdsColumnType type)
184 throw new NotImplementedException ();
187 private object GetImageValue ()
190 byte hasValue = comm.GetByte ();
195 int len = comm.GetTdsInt ();
197 result = comm.GetBytes (len, true);
199 throw new TdsException ("");
203 private object GetIntValue (TdsColumnType type)
209 case TdsColumnType.IntN :
210 len = comm.GetByte ();
212 case TdsColumnType.Int4 :
215 case TdsColumnType.Int2 :
218 case TdsColumnType.Int1 :
222 throw new TdsException ("");
227 result = comm.GetTdsInt ();
230 result = comm.GetTdsShort ();
233 result = (byte) comm.GetByte ();
239 throw new TdsException ("Bad integer length");
246 private object GetMoneyValue (TdsColumnType type)
252 case TdsColumnType.SmallMoney :
253 case TdsColumnType.Money4 :
256 case TdsColumnType.Money :
259 case TdsColumnType.MoneyN :
260 len = comm.GetByte ();
263 throw new TdsException ("not a money value");
269 throw new NotImplementedException ();
275 private int GetSubPacketLength ()
277 return comm.GetTdsShort ();
280 private object GetTextValue (bool wideChars)
283 byte hasValue = comm.GetByte ();
289 int len = comm.GetTdsInt ();
293 result = comm.GetString (len / 2);
295 result = encoder.GetString (comm.GetBytes (len, false), 0, len);
297 if ((byte) tdsVersion < (byte) TdsVersion.tds70 && result == " ")
301 throw new TdsException ("");
306 private bool IsFixedSizeColumn (TdsColumnType columnType)
308 switch (columnType) {
309 case TdsColumnType.Int1 :
310 case TdsColumnType.Int2 :
311 case TdsColumnType.Int4 :
312 case TdsColumnType.Float8 :
313 case TdsColumnType.DateTime :
314 case TdsColumnType.Bit :
315 case TdsColumnType.Money :
316 case TdsColumnType.Money4 :
317 case TdsColumnType.SmallMoney :
318 case TdsColumnType.Real :
319 case TdsColumnType.DateTime4 :
321 case TdsColumnType.IntN :
322 case TdsColumnType.MoneyN :
323 case TdsColumnType.VarChar :
324 case TdsColumnType.NVarChar :
325 case TdsColumnType.DateTimeN :
326 case TdsColumnType.FloatN :
327 case TdsColumnType.Char :
328 case TdsColumnType.NChar :
329 case TdsColumnType.NText :
330 case TdsColumnType.Image :
331 case TdsColumnType.VarBinary :
332 case TdsColumnType.Binary :
333 case TdsColumnType.Decimal :
334 case TdsColumnType.Numeric :
335 case TdsColumnType.BitN :
336 case TdsColumnType.UniqueIdentifier :
339 throw new TdsException ("bad type");
344 private TdsPacketRowResult LoadRow (TdsPacketRowResult result)
346 throw new NotImplementedException ();
349 private int LookupBufferSize (TdsColumnType columnType)
351 switch (columnType) {
352 case TdsColumnType.Int1 :
353 case TdsColumnType.Bit :
355 case TdsColumnType.Int2 :
357 case TdsColumnType.Int4 :
358 case TdsColumnType.Real :
359 case TdsColumnType.DateTime4 :
360 case TdsColumnType.Money4 :
361 case TdsColumnType.SmallMoney :
363 case TdsColumnType.Float8 :
364 case TdsColumnType.DateTime :
365 case TdsColumnType.Money :
368 throw new TdsException ("");
372 private int LookupDisplaySize (TdsColumnType columnType)
374 switch (columnType) {
375 case TdsColumnType.Int1 :
377 case TdsColumnType.Int2 :
379 case TdsColumnType.Int4 :
381 case TdsColumnType.Real :
383 case TdsColumnType.Float8 :
385 case TdsColumnType.DateTime :
387 case TdsColumnType.DateTime4 :
389 case TdsColumnType.Bit :
391 case TdsColumnType.Money :
393 case TdsColumnType.Money4 :
394 case TdsColumnType.SmallMoney :
397 throw new TdsException ("");
401 private TdsPacketColumnNamesResult ProcessColumnNames ()
403 int totalLength = comm.GetTdsShort ();
407 bool newTable = (table.Columns.Count > 0);
409 while (bytesRead < totalLength) {
410 int columnNameLength = comm.GetByte ();
411 string columnName = encoder.GetString (comm.GetBytes (columnNameLength, false), 0, columnNameLength);
412 bytesRead = bytesRead + 1 + columnNameLength;
414 table.Columns.Add (columnName);
416 table.Columns[i].ColumnName = columnName;
420 return new TdsPacketColumnNamesResult (table.Columns);
423 private TdsPacketColumnInfoResult ProcessColumnInfo ()
427 int totalLength = comm.GetTdsShort ();
431 bool newTable = (table.Columns.Count > 0);
433 while (bytesRead < totalLength) {
439 byte[] flagData = new byte[4];
440 for (int i = 0; i < 4; i += 1) {
441 flagData[i] = comm.GetByte ();
444 bool nullable = (flagData[2] & 0x01) > 0;
445 bool caseSensitive = (flagData[2] & 0x02) > 0;
446 bool writable = (flagData[2] & 0x0c) > 0;
447 bool autoIncrement = (flagData[2] & 0x10) > 0;
448 string tableName = String.Empty;
449 TdsColumnType columnType = (TdsColumnType) comm.GetByte ();
452 if (columnType == TdsColumnType.Text || columnType == TdsColumnType.Image) {
456 int tableNameLength = comm.GetTdsShort ();
458 tableName = encoder.GetString (comm.GetBytes (tableNameLength, false), 0, tableNameLength);
459 bytesRead += tableNameLength;
460 bufLength = 2 << 31 - 1;
462 else if (columnType == TdsColumnType.Decimal || columnType == TdsColumnType.Numeric) {
463 bufLength = comm.GetByte ();
465 precision = comm.GetByte ();
467 scale = comm.GetByte ();
470 else if (IsFixedSizeColumn (columnType))
471 bufLength = LookupBufferSize (columnType);
473 bufLength = (int) comm.GetByte () & 0xff;
480 column = table.Columns.Add ();
482 column = table.Columns[numColumns];
486 column.AllowDBNull = nullable;
487 column.AutoIncrement = autoIncrement;
488 column.ReadOnly = !writable;
491 int skipLength = totalLength - bytesRead;
493 throw new TdsException ("skipping");
494 return new TdsPacketColumnInfoResult (table.Columns);
498 private TdsPacketEndTokenResult ProcessEndToken (TdsPacketSubType type)
500 byte status = comm.GetByte ();
502 byte op = comm.GetByte ();
504 int rowCount = comm.GetTdsInt ();
505 if (op == (byte) 0xc1)
508 if (type == TdsPacketSubType.DoneInProc)
511 TdsPacketEndTokenResult result = new TdsPacketEndTokenResult (type, status, rowCount);
513 moreResults = result.MoreResults;
515 // FIXME: Finish the query
520 private TdsPacketResult ProcessEnvChange ()
522 int len = GetSubPacketLength ();
523 TdsEnvPacketSubType type = (TdsEnvPacketSubType) comm.GetByte ();
527 case TdsEnvPacketSubType.BlockSize :
529 cLen = comm.GetByte () & 0xff;
530 if (tdsVersion == TdsVersion.tds70) {
531 blockSize = comm.GetString (cLen);
532 comm.Skip (len - 2 - cLen * 2);
535 blockSize = encoder.GetString (comm.GetBytes (cLen, false), 0, cLen);
536 comm.Skip (len - 2 - cLen);
539 comm.ResizeOutBuf (Int32.Parse (blockSize));
541 case TdsEnvPacketSubType.CharSet :
542 cLen = comm.GetByte () & 0xff;
543 if (tdsVersion == TdsVersion.tds70) {
544 this.language = comm.GetString (cLen);
545 comm.Skip (len - 2 - cLen * 2);
548 this.charset = encoder.GetString (comm.GetBytes (cLen, false), 0, cLen);
549 comm.Skip (len - 2 - cLen);
550 SetCharset (charset);
554 case TdsEnvPacketSubType.Database :
555 cLen = comm.GetByte () & 0xff;
556 string newDB = tdsVersion == TdsVersion.tds70 ? comm.GetString (cLen) : encoder.GetString (comm.GetBytes (cLen, false), 0, cLen);
557 cLen = comm.GetByte () & 0xff;
558 string oldDB = tdsVersion == TdsVersion.tds70 ? comm.GetString (cLen) : encoder.GetString (comm.GetBytes (cLen, false), 0, cLen);
559 if (database != String.Empty && database != oldDB)
560 throw new TdsException ("Database mismatch.");
568 return new TdsPacketResult (TdsPacketSubType.EnvChange);
571 private TdsPacketResult ProcessLoginAck ()
573 GetSubPacketLength ();
575 if (tdsVersion == TdsVersion.tds70) {
577 int nameLength = comm.GetByte ();
578 databaseProductName = comm.GetString (nameLength);
579 databaseMajorVersion = comm.GetByte ();
580 databaseProductVersion = String.Format ("0{0}.0{1}.0{2}", databaseMajorVersion, comm.GetByte (), ((256 * (comm.GetByte () + 1)) + comm.GetByte ()));
584 short nameLength = comm.GetByte ();
585 databaseProductName = comm.GetString (nameLength);
587 databaseMajorVersion = comm.GetByte ();
588 databaseProductVersion = String.Format ("{0}.{1}", databaseMajorVersion, comm.GetByte ());
591 Console.WriteLine ("Connected to {0} {1}", databaseProductName, databaseProductVersion);
593 if (databaseProductName.Length > 1 && -1 != databaseProductName.IndexOf ('\0')) {
594 int last = databaseProductName.IndexOf ('\0');
595 databaseProductName = databaseProductName.Substring (0, last);
598 return new TdsPacketResult (TdsPacketSubType.LoginAck);
601 private TdsPacketMessageResult ProcessMessage (TdsPacketSubType subType)
603 TdsMessage message = new TdsMessage ();
604 GetSubPacketLength ();
607 message.Number = comm.GetTdsInt ();
608 message.State = comm.GetByte ();
609 message.Severity = comm.GetByte ();
611 len = comm.GetTdsShort ();
613 message.Message = comm.GetString (len);
615 len = comm.GetByte ();
617 message.Server = comm.GetString (len);
619 if (subType == TdsPacketSubType.Error | subType == TdsPacketSubType.Info) {
620 len = comm.GetByte ();
621 message.ProcName = comm.GetString (len);
624 throw new TdsException ("Invalid subtype");
625 message.Line = comm.GetByte ();
628 Console.WriteLine (message.ToString ());
630 lastServerMessage = message;
631 if (subType == TdsPacketSubType.Error)
632 return new TdsPacketErrorResult (subType, message);
634 return new TdsPacketMessageResult (subType, message);
637 private TdsPacketOutputParam ProcessOutputParam ()
639 GetSubPacketLength ();
640 comm.GetString (comm.GetByte () & 0xff);
642 TdsColumnType colType = (TdsColumnType) comm.GetByte ();
644 object element = null;
646 case TdsColumnType.IntN :
648 element = GetIntValue (colType);
650 case TdsColumnType.Int1 :
651 case TdsColumnType.Int2 :
652 case TdsColumnType.Int4 :
653 element = GetIntValue (colType);
655 case TdsColumnType.Image :
657 element = GetImageValue ();
659 case TdsColumnType.Text :
661 element = GetTextValue (false);
663 case TdsColumnType.NText :
665 element = GetTextValue (true);
667 case TdsColumnType.Char :
668 case TdsColumnType.VarChar :
670 element = GetCharValue (false, true);
672 case TdsColumnType.BigVarBinary :
674 int len = comm.GetTdsShort ();
675 element = comm.GetBytes (len, true);
677 case TdsColumnType.BigVarChar :
679 element = GetCharValue (false, false);
681 case TdsColumnType.NChar :
682 case TdsColumnType.NVarChar :
684 element = GetCharValue (true, true);
686 case TdsColumnType.Real :
687 element = ReadFloatN (4);
689 case TdsColumnType.Float8 :
690 element = ReadFloatN (8);
692 case TdsColumnType.FloatN :
694 int actualSize = comm.GetByte ();
695 element = ReadFloatN (actualSize);
697 case TdsColumnType.SmallMoney :
698 case TdsColumnType.Money :
699 case TdsColumnType.MoneyN :
701 element = GetMoneyValue (colType);
703 case TdsColumnType.Numeric :
704 case TdsColumnType.Decimal :
707 int scale = comm.GetByte ();
708 element = GetDecimalValue (scale);
710 case TdsColumnType.DateTimeN :
712 element = GetDateTimeValue (colType);
714 case TdsColumnType.DateTime4 :
715 case TdsColumnType.DateTime :
716 element = GetDateTimeValue (colType);
718 case TdsColumnType.VarBinary :
719 case TdsColumnType.Binary :
721 int len = (comm.GetByte () & 0xff);
722 element = comm.GetBytes (len, true);
724 case TdsColumnType.BitN :
726 if (comm.GetByte () == 0)
729 element = (comm.GetByte() != 0);
731 case TdsColumnType.Bit :
732 int columnSize = comm.GetByte ();
733 element = (columnSize != 0);
735 case TdsColumnType.UniqueIdentifier :
736 int len = comm.GetByte () & 0xff;
737 element = (len == 0 ? null : new Guid (comm.GetBytes (len, false)));
740 throw new TdsException ("");
743 return new TdsPacketOutputParam (element);
746 private TdsPacketResult ProcessProcId ()
749 return new TdsPacketResult (TdsPacketSubType.ProcId);
752 private TdsPacketRetStatResult ProcessReturnStatus ()
754 return new TdsPacketRetStatResult (comm.GetTdsInt ());
758 private TdsPacketResult ProcessSubPacket ()
760 TdsPacketResult result = null;
763 TdsPacketSubType subType = (TdsPacketSubType) comm.GetByte ();
766 case TdsPacketSubType.EnvChange :
767 result = ProcessEnvChange ();
769 case TdsPacketSubType.Error :
770 case TdsPacketSubType.Info :
771 case TdsPacketSubType.Msg50Token :
772 result = ProcessMessage (subType);
774 case TdsPacketSubType.Param :
775 result = ProcessOutputParam ();
777 case TdsPacketSubType.LoginAck :
778 result = ProcessLoginAck ();
780 case TdsPacketSubType.ReturnStatus :
781 result = ProcessReturnStatus ();
783 case TdsPacketSubType.ProcId :
784 result = ProcessProcId ();
786 case TdsPacketSubType.Done :
787 case TdsPacketSubType.DoneProc :
788 case TdsPacketSubType.DoneInProc :
789 result = ProcessEndToken (subType);
790 moreResults2 = ((TdsPacketEndTokenResult) result).MoreResults;
792 case TdsPacketSubType.ColumnNameToken :
793 result = ProcessColumnNames ();
795 case TdsPacketSubType.ColumnInfoToken :
796 result = ProcessColumnInfo ();
798 case TdsPacketSubType.Unknown0xA5 :
799 case TdsPacketSubType.Unknown0xA7 :
800 case TdsPacketSubType.Unknown0xA8 :
801 comm.Skip (comm.GetTdsShort ());
802 result = new TdsPacketUnknown (subType);
804 case TdsPacketSubType.TableName :
805 result = ProcessTableName ();
807 case TdsPacketSubType.Order :
808 comm.Skip (comm.GetTdsShort ());
809 result = new TdsPacketColumnOrderResult ();
811 case TdsPacketSubType.Control :
812 comm.Skip (comm.GetTdsShort ());
813 result = new TdsPacketControlResult ();
815 case TdsPacketSubType.Row :
816 result = LoadRow (new TdsPacketRowResult (null));
818 case TdsPacketSubType.ColumnMetadata :
819 result = ProcessTds7Result ();
822 throw new TdsException ("oops!");
828 private TdsPacketTableNameResult ProcessTableName ()
830 int totalLength = comm.GetTdsShort ();
831 comm.Skip (totalLength);
832 return new TdsPacketTableNameResult ();
835 [System.MonoTODO ("complete")]
836 private TdsPacketResult ProcessTds7Result ()
838 int numColumns = comm.GetTdsShort ();
844 private object ReadFloatN (int len)
850 l = comm.GetTdsInt64 ();
851 tmp = BitConverter.Int64BitsToDouble (l);
854 l = comm.GetTdsInt ();
855 tmp = BitConverter.Int64BitsToDouble (l);
861 throw new TdsException ("");
867 private void SetCharset (string charset)
869 if (charset == null || charset.Length > 30)
870 charset = "iso-8859-1";
871 if (this.charset != charset) {
872 encoder = Encoding.GetEncoding (charset);
873 this.charset = charset;
877 public bool Logon (TdsConnectionParameters parms)
880 byte[] empty = new byte[0];
883 if (tdsVersion == TdsVersion.tds70) {
886 comm.StartPacket (TdsPacketType.Logon);
888 // hostname (offset 0)
889 byte[] tmp = comm.Append (hostname, 30, pad);
890 comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
892 // username (offset 31 0x1f)
893 tmp = comm.Append (user, 30, pad);
894 comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
896 // password (offset 62 0x3e)
897 tmp = comm.Append (password, 30, pad);
898 comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
900 // hostproc (offset 93 0x5d)
901 comm.Append ("00000116", 8, pad);
903 // unused (offset 109 0x6d)
904 comm.Append (empty, (30-14), pad);
907 comm.Append ((byte) 0x0);
908 comm.Append ((byte) 0xa0);
909 comm.Append ((byte) 0x24);
910 comm.Append ((byte) 0xcc);
911 comm.Append ((byte) 0x50);
912 comm.Append ((byte) 0x12);
915 comm.Append ((byte) 8);
918 comm.Append ((byte) 3);
921 comm.Append ((byte) 1);
924 comm.Append ((byte) 6);
927 comm.Append ((byte) 10);
930 comm.Append ((byte) 9);
933 comm.Append ((byte) 1);
935 // disallow dump/load and bulk insert
936 comm.Append ((byte) 1);
938 // sql interface type
939 comm.Append ((byte) 0);
941 // type of network connection
942 comm.Append ((byte) 0);
946 comm.Append (empty, 7, pad);
948 tmp = comm.Append (applicationName, 30, pad);
949 comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
952 tmp = comm.Append (server, 30, pad);
953 comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
956 comm.Append (empty, 2, pad);
957 tmp = comm.Append (password, 253, pad);
958 comm.Append ((byte) (tmp.Length < 253 ? tmp.Length + 2 : 253 + 2));
961 comm.Append ((byte) (((byte) tdsVersion) / 10));
962 comm.Append ((byte) (((byte) tdsVersion) % 10));
963 comm.Append ((byte) 0);
964 comm.Append ((byte) 0);
967 tmp = comm.Append (progName, 10, pad);
968 comm.Append ((byte) (tmp.Length < 10 ? tmp.Length : 10));
971 comm.Append ((byte) 6);
973 // Tell the server we can handle SQLServer version 6
974 comm.Append ((byte) 0);
976 // Send zero to tell the server we can't handle any other version
977 comm.Append ((byte) 0);
978 comm.Append ((byte) 0);
980 // auto convert short
981 comm.Append ((byte) 0);
984 comm.Append ((byte) 0x0d);
987 comm.Append ((byte) 0x11);
990 tmp = comm.Append (language, 30, pad);
991 comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
993 // notify on lang change
994 comm.Append ((byte) 1);
996 // security label hierarchy
997 comm.Append ((short) 0);
999 // security components
1000 comm.Append (empty, 8, pad);
1003 comm.Append ((short) 0);
1005 // security login role
1006 comm.Append ((byte) 0);
1009 tmp = comm.Append (charset, 30, pad);
1010 comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
1012 // notify on charset change
1013 comm.Append ((byte) 1);
1015 // length of tds packets
1016 tmp = comm.Append (packetSize.ToString (), 6, pad);
1017 comm.Append ((byte) 3);
1019 // pad out to a longword
1020 comm.Append (empty, 8, pad);
1025 TdsPacketResult result;
1027 while (!((result = ProcessSubPacket()) is TdsPacketEndTokenResult)) {
1028 if (result is TdsPacketErrorResult) {
1031 // XXX Should really process some more types of packets.
1035 // XXX Should we move this to the Connection class?
1036 //isOkay = initSettings(_database);
1039 // XXX Possible bug. What happend if this is cancelled before the logon
1040 // takes place? Should isOkay be false?
1045 // This packet is documented at
1046 // http://www.freetds.org/tds.htm#login7
1047 public void Send70Logon (TdsConnectionParameters parms)
1049 byte[] empty = new byte[0];
1050 byte pad = (byte) 0;
1052 byte[] magic1 = {0x06, 0x83, 0xf2, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x88, 0xff, 0xff, 0xff, 0x36, 0x04, 0x00, 0x00};
1053 byte[] magic2 = {0x00, 0x40, 0x33, 0x9a, 0x6b, 0x50};
1054 byte[] magic3 = {0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50}; // NTLMSSP
1055 short partialPacketSize = (short) (86 + 2 * (
1058 applicationName.Length +
1061 libraryName.Length +
1064 short totalPacketSize = (short) (partialPacketSize + 48);
1065 comm.StartPacket (TdsPacketType.Logon70);
1066 comm.Append (totalPacketSize);
1067 comm.Append (empty, 5, pad);
1069 if (tdsVersion == TdsVersion.tds80)
1070 comm.Append ((byte) 0x80);
1072 comm.Append ((byte) 0x70);
1074 comm.Append (empty, 7, pad);
1075 comm.Append (magic1);
1080 comm.Append (curPos);
1081 comm.Append ((short) hostname.Length);
1082 curPos += (short) (hostname.Length * 2);
1085 comm.Append (curPos);
1086 comm.Append ((short) user.Length);
1087 curPos += (short) (user.Length * 2);
1090 comm.Append (curPos);
1091 comm.Append ((short) password.Length);
1092 curPos += (short) (password.Length * 2);
1095 comm.Append (curPos);
1096 comm.Append ((short) applicationName.Length);
1097 curPos += (short) (applicationName.Length * 2);
1100 comm.Append (curPos);
1101 comm.Append ((short) server.Length);
1102 curPos += (short) (server.Length * 2);
1105 comm.Append ((short) 0);
1106 comm.Append ((short) 0);
1109 comm.Append (curPos);
1110 comm.Append ((short) libraryName.Length);
1111 curPos += (short) (libraryName.Length * 2);
1114 comm.Append (curPos);
1115 comm.Append ((short) language.Length);
1116 curPos += (short) (language.Length * 2);
1119 comm.Append (curPos);
1120 comm.Append ((short) connectDB.Length);
1121 curPos += (short) (connectDB.Length * 2);
1123 comm.Append (magic2);
1124 comm.Append (partialPacketSize);
1125 comm.Append ((short) 48);
1126 comm.Append (totalPacketSize);
1127 comm.Append ((short) 0);
1129 string scrambledPwd = Tds7CryptPass (password);
1131 comm.Append (hostname);
1133 comm.Append (scrambledPwd);
1134 comm.Append (applicationName);
1135 comm.Append (server);
1136 comm.Append (libraryName);
1137 comm.Append (language);
1138 comm.Append (connectDB);
1139 comm.Append (magic3);
1141 comm.Append ((byte) 0x0);
1142 comm.Append ((byte) 0x1);
1143 comm.Append (empty, 3, pad);
1144 comm.Append ((byte) 0x6);
1145 comm.Append ((byte) 0x82);
1146 comm.Append (empty, 22, pad);
1147 comm.Append ((byte) 0x30);
1148 comm.Append (empty, 7, pad);
1149 comm.Append ((byte) 0x30);
1150 comm.Append (empty, 3, pad);
1153 private string SqlStatementForSettings (bool autoCommit, IsolationLevel isolationLevel)
1155 if (autoCommit == this.autoCommit && isolationLevel == this.isolationLevel)
1157 StringBuilder res = new StringBuilder ();
1158 if (autoCommit != this.autoCommit) {
1159 this.autoCommit = autoCommit;
1160 res.Append (SqlStatementToSetCommit ());
1163 if (isolationLevel != this.isolationLevel) {
1164 this.isolationLevel = isolationLevel;
1165 res.Append (SqlStatementToSetIsolationLevel ());
1168 return res.ToString ();
1171 private string SqlStatementToSetCommit ()
1174 if (serverType == TdsServerType.Sybase) {
1176 result = "set CHAINED off";
1178 result = "set CHAINED on";
1182 result = "set implicit_transactions off";
1184 result = "set implicit_transactions on";
1190 private string SqlStatementToSetIsolationLevel ()
1196 private static string Tds7CryptPass (string pass)
1198 int xormask = 0x5a5a;
1199 int len = pass.Length;
1200 char[] chars = new char[len];
1202 for (int i = 0; i < len; ++i) {
1203 int c = ((int) (pass[i])) ^ xormask;
1204 int m1 = (c >> 4) & 0x0f0f;
1205 int m2 = (c << 4) & 0xf0f0;
1206 chars[i] = (char) (m1 | m2);
1209 return new String (chars);
1212 #endregion // Methods