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;
37 string databaseProductName;
38 string databaseProductVersion;
39 int databaseMajorVersion;
41 DataTable table = new DataTable ();
46 TdsMessage lastServerMessage;
49 TdsServerType serverType;
51 TdsConnectionParameters parms;
53 IsolationLevel isolationLevel;
55 Socket socket = new Socket (AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
61 //public TdsCommandInternal Command {
62 //get { return command; }
63 //set { command = value; }
66 public string Database {
67 get { return database; }
68 set { database = value; }
71 public TdsVersion TdsVersion {
72 get { return tdsVersion; }
75 #endregion // Properties
79 public Tds (TdsConnectionParameters parms)
81 applicationName = parms.ApplicationName;
82 connectDB = parms.Database;
83 encoder = Encoding.GetEncoding (parms.Encoding);
84 charset = parms.Encoding;
85 hostname = parms.Hostname;
86 server = parms.DataSource;
87 language = parms.Language;
88 libraryName = parms.LibraryName;
89 packetSize = parms.PacketSize;
90 password = parms.Password;
92 progName = parms.ProgName;
93 tdsVersion = parms.TdsVersion;
96 IPHostEntry hostEntry = Dns.Resolve (server);
97 IPAddress[] addresses = hostEntry.AddressList;
101 foreach (IPAddress address in addresses) {
102 endPoint = new IPEndPoint (address, port);
103 socket.Connect (endPoint);
105 if (socket.Connected)
109 comm = new TdsComm (encoder, socket, packetSize, tdsVersion);
112 #endregion // Constructors
116 public void BeginTransaction ()
118 SubmitProcedure ("BEGIN TRANSACTION");
120 public void ChangeDatabase (string databaseName)
122 TdsPacketResult result;
125 string query = String.Format ("use {0}", databaseName);
126 comm.StartPacket (TdsPacketType.Query);
130 while (!((result = ProcessSubPacket ()) is TdsPacketEndTokenResult)) {
131 if (result is TdsPacketErrorResult) {
137 public void ChangeSettings (bool autoCommit, IsolationLevel isolationLevel)
139 /*string query = SqlStatementForSettings (autoCommit, isolationLevel);
141 ChangeSettings (query);
145 private bool ChangeSettings (string query)
147 TdsPacketResult result;
149 if (query.Length == 0)
152 comm.StartPacket (TdsPacketType.Query);
158 result = ProcessSubPacket ();
159 done = (result is TdsPacketEndTokenResult) && !((TdsPacketEndTokenResult) result).MoreResults;
160 if (result is TdsPacketErrorResult) {
169 public void CommitTransaction ()
171 string sql = "IF @@TRANCOUNT>0 COMMIT TRAN";
172 SubmitProcedure (sql);
176 public int ExecuteNonQuery (string sql)
178 TdsPacketResult result;
181 if (sql.Length > 0) {
182 comm.StartPacket (TdsPacketType.Query);
189 result = ProcessSubPacket ();
190 if (result is TdsPacketMessageResult) {
191 Console.WriteLine (((TdsPacketMessageResult) result).Message);
193 done = (result is TdsPacketEndTokenResult) && (!((TdsPacketEndTokenResult) result).MoreResults);
201 public void ExecuteQuery (string sql)
203 if (sql.Length > 0) {
204 comm.StartPacket (TdsPacketType.Query);
211 private object GetCharValue (bool wideChars, bool outputParam)
213 object result = null;
214 bool shortLen = (tdsVersion == TdsVersion.tds70) && (wideChars || !outputParam);
215 int len = shortLen ? comm.GetTdsShort () : (comm.GetByte () & 0xff);
217 if ((tdsVersion < TdsVersion.tds70 && len == 0) || (tdsVersion == TdsVersion.tds70 && len == 0xffff))
221 result = comm.GetString (len / 2);
223 result = encoder.GetString (comm.GetBytes (len, false), 0, len);
225 if (tdsVersion < TdsVersion.tds70 && ((string) result).Equals (" "))
229 throw new TdsException ("");
234 private object GetDecimalValue (int scale)
236 throw new NotImplementedException ();
240 private object GetDateTimeValue (TdsColumnType type)
242 throw new NotImplementedException ();
245 private object GetImageValue ()
248 byte hasValue = comm.GetByte ();
253 int len = comm.GetTdsInt ();
255 result = comm.GetBytes (len, true);
257 throw new TdsException ("");
261 private object GetIntValue (TdsColumnType type)
267 case TdsColumnType.IntN :
268 len = comm.GetByte ();
270 case TdsColumnType.Int4 :
273 case TdsColumnType.Int2 :
276 case TdsColumnType.Int1 :
280 throw new TdsException ("");
285 result = comm.GetTdsInt ();
288 result = comm.GetTdsShort ();
291 result = (byte) comm.GetByte ();
297 throw new TdsException ("Bad integer length");
304 private object GetMoneyValue (TdsColumnType type)
310 case TdsColumnType.SmallMoney :
311 case TdsColumnType.Money4 :
314 case TdsColumnType.Money :
317 case TdsColumnType.MoneyN :
318 len = comm.GetByte ();
321 throw new TdsException ("not a money value");
327 throw new NotImplementedException ();
333 private int GetSubPacketLength ()
335 return comm.GetTdsShort ();
338 private object GetTextValue (bool wideChars)
341 byte hasValue = comm.GetByte ();
347 int len = comm.GetTdsInt ();
351 result = comm.GetString (len / 2);
353 result = encoder.GetString (comm.GetBytes (len, false), 0, len);
355 if ((byte) tdsVersion < (byte) TdsVersion.tds70 && result == " ")
359 throw new TdsException ("");
364 private bool IsFixedSizeColumn (TdsColumnType columnType)
366 switch (columnType) {
367 case TdsColumnType.Int1 :
368 case TdsColumnType.Int2 :
369 case TdsColumnType.Int4 :
370 case TdsColumnType.Float8 :
371 case TdsColumnType.DateTime :
372 case TdsColumnType.Bit :
373 case TdsColumnType.Money :
374 case TdsColumnType.Money4 :
375 case TdsColumnType.SmallMoney :
376 case TdsColumnType.Real :
377 case TdsColumnType.DateTime4 :
379 case TdsColumnType.IntN :
380 case TdsColumnType.MoneyN :
381 case TdsColumnType.VarChar :
382 case TdsColumnType.NVarChar :
383 case TdsColumnType.DateTimeN :
384 case TdsColumnType.FloatN :
385 case TdsColumnType.Char :
386 case TdsColumnType.NChar :
387 case TdsColumnType.NText :
388 case TdsColumnType.Image :
389 case TdsColumnType.VarBinary :
390 case TdsColumnType.Binary :
391 case TdsColumnType.Decimal :
392 case TdsColumnType.Numeric :
393 case TdsColumnType.BitN :
394 case TdsColumnType.UniqueIdentifier :
397 throw new TdsException ("bad type");
402 private TdsPacketRowResult LoadRow (TdsPacketRowResult result)
404 throw new NotImplementedException ();
407 private int LookupBufferSize (TdsColumnType columnType)
409 switch (columnType) {
410 case TdsColumnType.Int1 :
411 case TdsColumnType.Bit :
413 case TdsColumnType.Int2 :
415 case TdsColumnType.Int4 :
416 case TdsColumnType.Real :
417 case TdsColumnType.DateTime4 :
418 case TdsColumnType.Money4 :
419 case TdsColumnType.SmallMoney :
421 case TdsColumnType.Float8 :
422 case TdsColumnType.DateTime :
423 case TdsColumnType.Money :
426 throw new TdsException ("");
430 private int LookupDisplaySize (TdsColumnType columnType)
432 switch (columnType) {
433 case TdsColumnType.Int1 :
435 case TdsColumnType.Int2 :
437 case TdsColumnType.Int4 :
439 case TdsColumnType.Real :
441 case TdsColumnType.Float8 :
443 case TdsColumnType.DateTime :
445 case TdsColumnType.DateTime4 :
447 case TdsColumnType.Bit :
449 case TdsColumnType.Money :
451 case TdsColumnType.Money4 :
452 case TdsColumnType.SmallMoney :
455 throw new TdsException ("");
459 private TdsPacketColumnNamesResult ProcessColumnNames ()
461 int totalLength = comm.GetTdsShort ();
465 bool newTable = (table.Columns.Count > 0);
467 while (bytesRead < totalLength) {
468 int columnNameLength = comm.GetByte ();
469 string columnName = encoder.GetString (comm.GetBytes (columnNameLength, false), 0, columnNameLength);
470 bytesRead = bytesRead + 1 + columnNameLength;
472 table.Columns.Add (columnName);
474 table.Columns[i].ColumnName = columnName;
478 return new TdsPacketColumnNamesResult (table.Columns);
481 private TdsPacketColumnInfoResult ProcessColumnInfo ()
485 int totalLength = comm.GetTdsShort ();
489 bool newTable = (table.Columns.Count > 0);
491 while (bytesRead < totalLength) {
497 byte[] flagData = new byte[4];
498 for (int i = 0; i < 4; i += 1) {
499 flagData[i] = comm.GetByte ();
502 bool nullable = (flagData[2] & 0x01) > 0;
503 bool caseSensitive = (flagData[2] & 0x02) > 0;
504 bool writable = (flagData[2] & 0x0c) > 0;
505 bool autoIncrement = (flagData[2] & 0x10) > 0;
506 string tableName = String.Empty;
507 TdsColumnType columnType = (TdsColumnType) comm.GetByte ();
510 if (columnType == TdsColumnType.Text || columnType == TdsColumnType.Image) {
514 int tableNameLength = comm.GetTdsShort ();
516 tableName = encoder.GetString (comm.GetBytes (tableNameLength, false), 0, tableNameLength);
517 bytesRead += tableNameLength;
518 bufLength = 2 << 31 - 1;
520 else if (columnType == TdsColumnType.Decimal || columnType == TdsColumnType.Numeric) {
521 bufLength = comm.GetByte ();
523 precision = comm.GetByte ();
525 scale = comm.GetByte ();
528 else if (IsFixedSizeColumn (columnType))
529 bufLength = LookupBufferSize (columnType);
531 bufLength = (int) comm.GetByte () & 0xff;
538 column = table.Columns.Add ();
540 column = table.Columns[numColumns];
544 column.AllowDBNull = nullable;
545 column.AutoIncrement = autoIncrement;
546 column.ReadOnly = !writable;
549 int skipLength = totalLength - bytesRead;
551 throw new TdsException ("skipping");
552 return new TdsPacketColumnInfoResult (table.Columns);
556 private TdsPacketEndTokenResult ProcessEndToken (TdsPacketSubType type)
558 byte status = comm.GetByte ();
560 byte op = comm.GetByte ();
562 int rowCount = comm.GetTdsInt ();
563 if (op == (byte) 0xc1)
566 if (type == TdsPacketSubType.DoneInProc)
569 TdsPacketEndTokenResult result = new TdsPacketEndTokenResult (type, status, rowCount);
571 Console.WriteLine ("Row count {0}", rowCount);
573 moreResults = result.MoreResults;
575 // FIXME: Finish the query
580 private TdsPacketResult ProcessEnvChange ()
582 int len = GetSubPacketLength ();
583 TdsEnvPacketSubType type = (TdsEnvPacketSubType) comm.GetByte ();
587 case TdsEnvPacketSubType.BlockSize :
589 cLen = comm.GetByte () & 0xff;
590 if (tdsVersion == TdsVersion.tds70) {
591 blockSize = comm.GetString (cLen);
592 comm.Skip (len - 2 - cLen * 2);
595 blockSize = encoder.GetString (comm.GetBytes (cLen, false), 0, cLen);
596 comm.Skip (len - 2 - cLen);
599 comm.ResizeOutBuf (Int32.Parse (blockSize));
601 case TdsEnvPacketSubType.CharSet :
602 cLen = comm.GetByte () & 0xff;
603 if (tdsVersion == TdsVersion.tds70) {
604 this.language = comm.GetString (cLen);
605 comm.Skip (len - 2 - cLen * 2);
608 this.charset = encoder.GetString (comm.GetBytes (cLen, false), 0, cLen);
609 comm.Skip (len - 2 - cLen);
610 SetCharset (charset);
614 case TdsEnvPacketSubType.Database :
615 cLen = comm.GetByte () & 0xff;
616 string newDB = tdsVersion == TdsVersion.tds70 ? comm.GetString (cLen) : encoder.GetString (comm.GetBytes (cLen, false), 0, cLen);
617 cLen = comm.GetByte () & 0xff;
618 string oldDB = tdsVersion == TdsVersion.tds70 ? comm.GetString (cLen) : encoder.GetString (comm.GetBytes (cLen, false), 0, cLen);
619 if (database != String.Empty && database != oldDB)
620 throw new TdsException ("Database mismatch.");
628 return new TdsPacketResult (TdsPacketSubType.EnvChange);
631 private TdsPacketResult ProcessLoginAck ()
633 GetSubPacketLength ();
635 if (tdsVersion == TdsVersion.tds70) {
637 int nameLength = comm.GetByte ();
638 databaseProductName = comm.GetString (nameLength);
639 databaseMajorVersion = comm.GetByte ();
640 databaseProductVersion = String.Format ("0{0}.0{1}.0{2}", databaseMajorVersion, comm.GetByte (), ((256 * (comm.GetByte () + 1)) + comm.GetByte ()));
644 short nameLength = comm.GetByte ();
645 databaseProductName = comm.GetString (nameLength);
647 databaseMajorVersion = comm.GetByte ();
648 databaseProductVersion = String.Format ("{0}.{1}", databaseMajorVersion, comm.GetByte ());
651 Console.WriteLine ("Connected to {0} {1}", databaseProductName, databaseProductVersion);
653 if (databaseProductName.Length > 1 && -1 != databaseProductName.IndexOf ('\0')) {
654 int last = databaseProductName.IndexOf ('\0');
655 databaseProductName = databaseProductName.Substring (0, last);
658 return new TdsPacketResult (TdsPacketSubType.LoginAck);
661 private TdsPacketMessageResult ProcessMessage (TdsPacketSubType subType)
663 TdsMessage message = new TdsMessage ();
664 GetSubPacketLength ();
667 message.Number = comm.GetTdsInt ();
668 message.State = comm.GetByte ();
669 message.Severity = comm.GetByte ();
671 len = comm.GetTdsShort ();
673 message.Message = comm.GetString (len);
675 len = comm.GetByte ();
677 message.Server = comm.GetString (len);
679 if (subType == TdsPacketSubType.Error | subType == TdsPacketSubType.Info) {
680 len = comm.GetByte ();
681 message.ProcName = comm.GetString (len);
684 throw new TdsException ("Invalid subtype");
685 message.Line = comm.GetByte ();
688 Console.WriteLine (message.ToString ());
690 lastServerMessage = message;
691 if (subType == TdsPacketSubType.Error)
692 return new TdsPacketErrorResult (subType, message);
694 return new TdsPacketMessageResult (subType, message);
697 private TdsPacketOutputParam ProcessOutputParam ()
699 GetSubPacketLength ();
700 comm.GetString (comm.GetByte () & 0xff);
702 TdsColumnType colType = (TdsColumnType) comm.GetByte ();
705 object element = null;
707 case TdsColumnType.IntN :
709 element = GetIntValue (colType);
711 case TdsColumnType.Int1 :
712 case TdsColumnType.Int2 :
713 case TdsColumnType.Int4 :
714 element = GetIntValue (colType);
716 case TdsColumnType.Image :
718 element = GetImageValue ();
720 case TdsColumnType.Text :
722 element = GetTextValue (false);
724 case TdsColumnType.NText :
726 element = GetTextValue (true);
728 case TdsColumnType.Char :
729 case TdsColumnType.VarChar :
731 element = GetCharValue (false, true);
733 case TdsColumnType.BigVarBinary :
735 len = comm.GetTdsShort ();
736 element = comm.GetBytes (len, true);
738 case TdsColumnType.BigVarChar :
740 element = GetCharValue (false, false);
742 case TdsColumnType.NChar :
743 case TdsColumnType.NVarChar :
745 element = GetCharValue (true, true);
747 case TdsColumnType.Real :
748 element = ReadFloatN (4);
750 case TdsColumnType.Float8 :
751 element = ReadFloatN (8);
753 case TdsColumnType.FloatN :
755 int actualSize = comm.GetByte ();
756 element = ReadFloatN (actualSize);
758 case TdsColumnType.SmallMoney :
759 case TdsColumnType.Money :
760 case TdsColumnType.MoneyN :
762 element = GetMoneyValue (colType);
764 case TdsColumnType.Numeric :
765 case TdsColumnType.Decimal :
768 int scale = comm.GetByte ();
769 element = GetDecimalValue (scale);
771 case TdsColumnType.DateTimeN :
773 element = GetDateTimeValue (colType);
775 case TdsColumnType.DateTime4 :
776 case TdsColumnType.DateTime :
777 element = GetDateTimeValue (colType);
779 case TdsColumnType.VarBinary :
780 case TdsColumnType.Binary :
782 len = (comm.GetByte () & 0xff);
783 element = comm.GetBytes (len, true);
785 case TdsColumnType.BitN :
787 if (comm.GetByte () == 0)
790 element = (comm.GetByte() != 0);
792 case TdsColumnType.Bit :
793 int columnSize = comm.GetByte ();
794 element = (columnSize != 0);
796 case TdsColumnType.UniqueIdentifier :
797 len = comm.GetByte () & 0xff;
798 //element = (len == 0 ? null : new Guid (comm.GetBytes (len, false)));
801 throw new TdsException ("");
804 return new TdsPacketOutputParam (element);
807 private TdsPacketResult ProcessProcId ()
810 return new TdsPacketResult (TdsPacketSubType.ProcId);
813 private TdsPacketRetStatResult ProcessReturnStatus ()
815 return new TdsPacketRetStatResult (comm.GetTdsInt ());
819 private TdsPacketResult ProcessSubPacket ()
821 TdsPacketResult result = null;
824 TdsPacketSubType subType = (TdsPacketSubType) comm.GetByte ();
827 case TdsPacketSubType.EnvChange :
828 Console.WriteLine ("Environment change");
829 result = ProcessEnvChange ();
831 case TdsPacketSubType.Error :
832 case TdsPacketSubType.Info :
833 case TdsPacketSubType.Msg50Token :
834 Console.WriteLine ("Error/info/message");
835 result = ProcessMessage (subType);
837 case TdsPacketSubType.Param :
838 Console.WriteLine ("Param");
839 result = ProcessOutputParam ();
841 case TdsPacketSubType.LoginAck :
842 Console.WriteLine ("Login Ack");
843 result = ProcessLoginAck ();
845 case TdsPacketSubType.ReturnStatus :
846 Console.WriteLine ("Return Status");
847 result = ProcessReturnStatus ();
849 case TdsPacketSubType.ProcId :
850 Console.WriteLine ("Proc Id");
851 result = ProcessProcId ();
853 case TdsPacketSubType.Done :
854 case TdsPacketSubType.DoneProc :
855 case TdsPacketSubType.DoneInProc :
856 Console.WriteLine ("Done");
857 result = ProcessEndToken (subType);
858 moreResults2 = ((TdsPacketEndTokenResult) result).MoreResults;
860 case TdsPacketSubType.ColumnNameToken :
861 Console.WriteLine ("Column Name");
862 result = ProcessColumnNames ();
864 case TdsPacketSubType.ColumnInfoToken :
865 Console.WriteLine ("Column Info");
866 result = ProcessColumnInfo ();
868 case TdsPacketSubType.Unknown0xA5 :
869 case TdsPacketSubType.Unknown0xA7 :
870 case TdsPacketSubType.Unknown0xA8 :
871 Console.WriteLine ("Unknown");
872 comm.Skip (comm.GetTdsShort ());
873 result = new TdsPacketUnknown (subType);
875 case TdsPacketSubType.TableName :
876 Console.WriteLine ("Table Name");
877 result = ProcessTableName ();
879 case TdsPacketSubType.Order :
880 Console.WriteLine ("Order");
881 comm.Skip (comm.GetTdsShort ());
882 result = new TdsPacketColumnOrderResult ();
884 case TdsPacketSubType.Control :
885 Console.WriteLine ("Control");
886 comm.Skip (comm.GetTdsShort ());
887 result = new TdsPacketControlResult ();
889 case TdsPacketSubType.Row :
890 Console.WriteLine ("Row");
891 result = LoadRow (new TdsPacketRowResult (null));
893 case TdsPacketSubType.ColumnMetadata :
894 Console.WriteLine ("Column Metadata");
895 result = ProcessTds7Result ();
898 throw new TdsException ("oops!");
904 private TdsPacketTableNameResult ProcessTableName ()
906 int totalLength = comm.GetTdsShort ();
907 comm.Skip (totalLength);
908 return new TdsPacketTableNameResult ();
911 [MonoTODO ("complete")]
912 private TdsPacketResult ProcessTds7Result ()
914 int numColumns = comm.GetTdsShort ();
920 private object ReadFloatN (int len)
926 l = comm.GetTdsInt64 ();
927 tmp = BitConverter.Int64BitsToDouble (l);
930 l = comm.GetTdsInt ();
931 tmp = BitConverter.Int64BitsToDouble (l);
937 throw new TdsException ("");
944 public void RollbackTransaction ()
946 SubmitProcedure ("IF @@TRANCOUNT>0 ROLLBACK TRAN");
950 public void SaveTransaction (string savePointName)
952 string sql = String.Format ("SAVE TRAN {0}", savePointName);
953 SubmitProcedure (sql);
956 private void SetCharset (string charset)
958 if (charset == null || charset.Length > 30)
959 charset = "iso-8859-1";
960 if (this.charset != charset) {
961 encoder = Encoding.GetEncoding (charset);
962 this.charset = charset;
966 public void SubmitProcedure (string sql)
968 TdsPacketResult result;
972 result = ProcessSubPacket ();
973 if (result is TdsPacketMessageResult) {
974 Console.WriteLine (((TdsPacketMessageResult) result).Message);
976 done = (result is TdsPacketEndTokenResult) && (!((TdsPacketEndTokenResult) result).MoreResults);
981 public bool Logon (TdsConnectionParameters parms)
984 byte[] empty = new byte[0];
987 if (tdsVersion == TdsVersion.tds70) {
990 comm.StartPacket (TdsPacketType.Logon);
992 // hostname (offset 0)
993 byte[] tmp = comm.Append (hostname, 30, pad);
994 comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
996 // username (offset 31 0x1f)
997 tmp = comm.Append (user, 30, pad);
998 comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
1000 // password (offset 62 0x3e)
1001 tmp = comm.Append (password, 30, pad);
1002 comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
1004 // hostproc (offset 93 0x5d)
1005 comm.Append ("00000116", 8, pad);
1007 // unused (offset 109 0x6d)
1008 comm.Append (empty, (30-14), pad);
1011 comm.Append ((byte) 0x0);
1012 comm.Append ((byte) 0xa0);
1013 comm.Append ((byte) 0x24);
1014 comm.Append ((byte) 0xcc);
1015 comm.Append ((byte) 0x50);
1016 comm.Append ((byte) 0x12);
1019 comm.Append ((byte) 8);
1022 comm.Append ((byte) 3);
1025 comm.Append ((byte) 1);
1028 comm.Append ((byte) 6);
1031 comm.Append ((byte) 10);
1034 comm.Append ((byte) 9);
1037 comm.Append ((byte) 1);
1039 // disallow dump/load and bulk insert
1040 comm.Append ((byte) 1);
1042 // sql interface type
1043 comm.Append ((byte) 0);
1045 // type of network connection
1046 comm.Append ((byte) 0);
1050 comm.Append (empty, 7, pad);
1052 tmp = comm.Append (applicationName, 30, pad);
1053 comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
1056 tmp = comm.Append (server, 30, pad);
1057 comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
1060 comm.Append (empty, 2, pad);
1061 tmp = comm.Append (password, 253, pad);
1062 comm.Append ((byte) (tmp.Length < 253 ? tmp.Length + 2 : 253 + 2));
1065 comm.Append ((byte) (((byte) tdsVersion) / 10));
1066 comm.Append ((byte) (((byte) tdsVersion) % 10));
1067 comm.Append ((byte) 0);
1068 comm.Append ((byte) 0);
1071 tmp = comm.Append (progName, 10, pad);
1072 comm.Append ((byte) (tmp.Length < 10 ? tmp.Length : 10));
1075 comm.Append ((byte) 6);
1077 // Tell the server we can handle SQLServer version 6
1078 comm.Append ((byte) 0);
1080 // Send zero to tell the server we can't handle any other version
1081 comm.Append ((byte) 0);
1082 comm.Append ((byte) 0);
1084 // auto convert short
1085 comm.Append ((byte) 0);
1088 comm.Append ((byte) 0x0d);
1091 comm.Append ((byte) 0x11);
1094 tmp = comm.Append (language, 30, pad);
1095 comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
1097 // notify on lang change
1098 comm.Append ((byte) 1);
1100 // security label hierarchy
1101 comm.Append ((short) 0);
1103 // security components
1104 comm.Append (empty, 8, pad);
1107 comm.Append ((short) 0);
1109 // security login role
1110 comm.Append ((byte) 0);
1113 tmp = comm.Append (charset, 30, pad);
1114 comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
1116 // notify on charset change
1117 comm.Append ((byte) 1);
1119 // length of tds packets
1120 tmp = comm.Append (packetSize.ToString (), 6, pad);
1121 comm.Append ((byte) 3);
1123 // pad out to a longword
1124 comm.Append (empty, 8, pad);
1129 TdsPacketResult result;
1131 while (!((result = ProcessSubPacket()) is TdsPacketEndTokenResult)) {
1132 if (result is TdsPacketErrorResult) {
1135 // XXX Should really process some more types of packets.
1139 // XXX Should we move this to the Connection class?
1140 //isOkay = initSettings(_database);
1143 // XXX Possible bug. What happend if this is cancelled before the logon
1144 // takes place? Should isOkay be false?
1149 // This packet is documented at
1150 // http://www.freetds.org/tds.htm#login7
1151 public void Send70Logon (TdsConnectionParameters parms)
1153 byte[] empty = new byte[0];
1154 byte pad = (byte) 0;
1156 byte[] magic1 = {0x06, 0x83, 0xf2, 0xf8, 0xff, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x03, 0x00, 0x00, 0x88, 0xff, 0xff, 0xff, 0x36, 0x04, 0x00, 0x00};
1157 byte[] magic2 = {0x00, 0x40, 0x33, 0x9a, 0x6b, 0x50};
1158 byte[] magic3 = {0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50}; // NTLMSSP
1159 short partialPacketSize = (short) (86 + 2 * (
1162 applicationName.Length +
1165 libraryName.Length +
1168 short totalPacketSize = (short) (partialPacketSize + 48);
1169 comm.StartPacket (TdsPacketType.Logon70);
1170 comm.Append (totalPacketSize);
1171 comm.Append (empty, 5, pad);
1173 if (tdsVersion == TdsVersion.tds80)
1174 comm.Append ((byte) 0x80);
1176 comm.Append ((byte) 0x70);
1178 comm.Append (empty, 7, pad);
1179 comm.Append (magic1);
1184 comm.Append (curPos);
1185 comm.Append ((short) hostname.Length);
1186 curPos += (short) (hostname.Length * 2);
1189 comm.Append (curPos);
1190 comm.Append ((short) user.Length);
1191 curPos += (short) (user.Length * 2);
1194 comm.Append (curPos);
1195 comm.Append ((short) password.Length);
1196 curPos += (short) (password.Length * 2);
1199 comm.Append (curPos);
1200 comm.Append ((short) applicationName.Length);
1201 curPos += (short) (applicationName.Length * 2);
1204 comm.Append (curPos);
1205 comm.Append ((short) server.Length);
1206 curPos += (short) (server.Length * 2);
1209 comm.Append ((short) 0);
1210 comm.Append ((short) 0);
1213 comm.Append (curPos);
1214 comm.Append ((short) libraryName.Length);
1215 curPos += (short) (libraryName.Length * 2);
1218 comm.Append (curPos);
1219 comm.Append ((short) language.Length);
1220 curPos += (short) (language.Length * 2);
1223 comm.Append (curPos);
1224 comm.Append ((short) connectDB.Length);
1225 curPos += (short) (connectDB.Length * 2);
1227 comm.Append (magic2);
1228 comm.Append (partialPacketSize);
1229 comm.Append ((short) 48);
1230 comm.Append (totalPacketSize);
1231 comm.Append ((short) 0);
1233 string scrambledPwd = Tds7CryptPass (password);
1235 comm.Append (hostname);
1237 comm.Append (scrambledPwd);
1238 comm.Append (applicationName);
1239 comm.Append (server);
1240 comm.Append (libraryName);
1241 comm.Append (language);
1242 comm.Append (connectDB);
1243 comm.Append (magic3);
1245 comm.Append ((byte) 0x0);
1246 comm.Append ((byte) 0x1);
1247 comm.Append (empty, 3, pad);
1248 comm.Append ((byte) 0x6);
1249 comm.Append ((byte) 0x82);
1250 comm.Append (empty, 22, pad);
1251 comm.Append ((byte) 0x30);
1252 comm.Append (empty, 7, pad);
1253 comm.Append ((byte) 0x30);
1254 comm.Append (empty, 3, pad);
1257 private string SqlStatementForSettings (bool autoCommit, IsolationLevel isolationLevel)
1259 if (autoCommit == this.autoCommit && isolationLevel == this.isolationLevel)
1261 StringBuilder res = new StringBuilder ();
1262 if (autoCommit != this.autoCommit) {
1263 this.autoCommit = autoCommit;
1264 res.Append (SqlStatementToSetCommit ());
1267 if (isolationLevel != this.isolationLevel) {
1268 this.isolationLevel = isolationLevel;
1269 res.Append (SqlStatementToSetIsolationLevel ());
1272 return res.ToString ();
1275 private string SqlStatementToSetCommit ()
1278 if (serverType == TdsServerType.Sybase) {
1280 result = "set CHAINED off";
1282 result = "set CHAINED on";
1286 result = "set implicit_transactions off";
1288 result = "set implicit_transactions on";
1294 private string SqlStatementToSetIsolationLevel ()
1300 private static string Tds7CryptPass (string pass)
1302 int xormask = 0x5a5a;
1303 int len = pass.Length;
1304 char[] chars = new char[len];
1306 for (int i = 0; i < len; ++i) {
1307 int c = ((int) (pass[i])) ^ xormask;
1308 int m1 = (c >> 4) & 0x0f0f;
1309 int m2 = (c << 4) & 0xf0f0;
1310 chars[i] = (char) (m1 | m2);
1313 return new String (chars);
1316 #endregion // Methods