2007-07-22 Nagappan A <anagappan@novell.com>
[mono.git] / mcs / class / Mono.Data.Tds / Mono.Data.Tds.Protocol / Tds.cs
1 //
2 // Mono.Data.Tds.Protocol.Tds.cs
3 //
4 // Author:
5 //   Tim Coleman (tim@timcoleman.com)
6 //   Sebastien Pouliot (spouliot@motus.com)
7 //   Daniel Morgan (danielmorgan@verizon.net)
8 //
9 // Copyright (C) 2002 Tim Coleman
10 // Portions (C) 2003 Motus Technologies Inc. (http://www.motus.com)
11 // Portions (C) 2003,2005 Daniel Morgan
12 //
13
14 //
15 // Permission is hereby granted, free of charge, to any person obtaining
16 // a copy of this software and associated documentation files (the
17 // "Software"), to deal in the Software without restriction, including
18 // without limitation the rights to use, copy, modify, merge, publish,
19 // distribute, sublicense, and/or sell copies of the Software, and to
20 // permit persons to whom the Software is furnished to do so, subject to
21 // the following conditions:
22 // 
23 // The above copyright notice and this permission notice shall be
24 // included in all copies or substantial portions of the Software.
25 // 
26 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
27 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
28 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
29 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
30 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
31 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
32 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 //
34
35 using Mono.Security.Protocol.Ntlm;
36 using System;
37 using System.Collections;
38 using System.ComponentModel;
39 using System.Diagnostics;
40 using System.Net.Sockets;
41 using System.Text;
42
43 namespace Mono.Data.Tds.Protocol {
44         public abstract class Tds : Component, ITds
45         {
46                 #region Fields
47
48                 TdsComm comm;
49                 TdsVersion tdsVersion;
50                 
51                 protected internal TdsConnectionParameters connectionParms;
52                 protected readonly byte[] NTLMSSP_ID = new byte[] {0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00};
53
54                 int packetSize;
55                 string dataSource;
56                 string database;
57                 string originalDatabase = string.Empty;
58                 string databaseProductName;
59                 string databaseProductVersion;
60                 int databaseMajorVersion;
61
62                 string charset;
63                 string language;
64
65                 bool connected = false;
66                 bool moreResults;
67
68                 Encoding encoder;
69 //              bool autoCommit;
70
71                 bool doneProc;
72                 TdsDataRow currentRow = null;
73                 TdsDataColumnCollection columns;
74
75                 ArrayList tableNames;
76                 ArrayList columnNames;
77
78                 TdsMetaParameterCollection parameters = new TdsMetaParameterCollection ();
79
80                 bool queryInProgress;
81                 int cancelsRequested;
82                 int cancelsProcessed;
83
84 //              bool isDone;
85 //              bool isDoneInProc;
86
87                 ArrayList outputParameters = new ArrayList ();
88                 protected TdsInternalErrorCollection messages = new TdsInternalErrorCollection ();
89
90                 int recordsAffected = -1;
91
92                 long StreamLength = 0;
93                 long StreamIndex = 0;
94                 int StreamColumnIndex = 0;
95
96                 bool sequentialAccess = false;
97                 bool isRowRead = false;
98                 bool isResultRead = false;
99                 bool LoadInProgress = false;
100
101                 #endregion // Fields
102
103                 #region Properties
104
105                 protected string Charset {
106                         get { return charset; }
107                 }
108
109                 public bool DoneProc {
110                         get { return doneProc; }
111                 }
112
113                 protected string Language {
114                         get { return language; }
115                 }
116
117                 protected ArrayList ColumnNames {
118                         get { return columnNames; }
119                 }
120
121                 public TdsDataRow ColumnValues {
122                         get { return currentRow; }
123                 }
124
125                 internal TdsComm Comm {
126                         get { return comm; }
127                 }
128
129                 public string Database {
130                         get { return database; }
131                 }
132
133                 public string DataSource {
134                         get { return dataSource; }
135                 }
136
137                 public bool IsConnected {
138                         get { return connected; }
139                         set { connected = value; }
140                 }
141
142                 public bool MoreResults {
143                         get { return moreResults; }
144                         set { moreResults = value; }
145                 }
146
147                 public int PacketSize {
148                         get { return packetSize; }
149                 }
150
151                 public int RecordsAffected {
152                         get { return recordsAffected; }
153                         set { recordsAffected = value; }
154                 }
155
156                 public string ServerVersion {
157                         get { return databaseProductVersion; }
158                 }
159
160                 public TdsDataColumnCollection Columns {
161                         get { return columns; }
162                 }
163
164                 public TdsVersion TdsVersion {
165                         get { return tdsVersion; }
166                 }
167
168                 public ArrayList OutputParameters {
169                         get { return outputParameters; }
170                         set { outputParameters = value; }
171                 }
172
173                 protected TdsMetaParameterCollection Parameters {
174                         get { return parameters; }
175                         set { parameters = value; }
176                 }
177
178                 public bool SequentialAccess {
179                         get { return sequentialAccess; }
180                         set { sequentialAccess = value; }
181                 }
182
183                 private void SkipRow ()
184                 {
185                         SkipToColumnIndex (Columns.Count);
186
187                         StreamLength = 0;
188                         StreamColumnIndex = 0;
189                         StreamIndex = 0;
190                         LoadInProgress = false;
191                 }
192
193                 private void SkipToColumnIndex (int colIndex)
194                 {
195                         if (LoadInProgress)
196                                 EndLoad ();
197
198                         if (colIndex < StreamColumnIndex)
199                                 throw new Exception ("Cannot Skip to a colindex less than the curr index");
200
201                         while (colIndex != StreamColumnIndex) {
202                                 TdsColumnType colType = (TdsColumnType)Columns[StreamColumnIndex]["ColumnType"];
203                                 if (!(colType == TdsColumnType.Image ||
204                                         colType == TdsColumnType.Text ||
205                                         colType == TdsColumnType.NText)) {
206                                         GetColumnValue (colType, false, StreamColumnIndex);
207                                         StreamColumnIndex ++;
208                                 }
209                                 else {
210                                         BeginLoad (colType);
211                                         Comm.Skip (StreamLength);
212                                         StreamLength = 0;
213                                         EndLoad ();
214                                 }
215                         }
216                 }
217
218                 public object GetSequentialColumnValue (int colIndex)
219                 {
220                         if (colIndex < StreamColumnIndex)
221                                 throw new InvalidOperationException ("Invalid attempt tp read from column ordinal" + colIndex); 
222
223                         if (LoadInProgress)
224                                 EndLoad ();
225
226                         if (colIndex != StreamColumnIndex)
227                                 SkipToColumnIndex (colIndex);
228
229                         object o = GetColumnValue ((TdsColumnType)Columns[colIndex]["ColumnType"], false, colIndex);
230                         StreamColumnIndex++;
231                         return o;
232                 }
233
234                 public long GetSequentialColumnValue (int colIndex, long fieldIndex, byte[] buffer, int bufferIndex, int size) 
235                 {
236                         if (colIndex < StreamColumnIndex)
237                                 throw new InvalidOperationException ("Invalid attempt tp read from column ordinal" + colIndex); 
238
239                         if (colIndex != StreamColumnIndex) 
240                                 SkipToColumnIndex (colIndex);
241
242                         if (!LoadInProgress)
243                                 BeginLoad ((TdsColumnType)Columns[colIndex]["ColumnType"]);
244
245                         if (buffer == null) {
246                                 return StreamLength;
247                         }
248                         return LoadData (fieldIndex, buffer, bufferIndex, size);
249                 }
250
251                 private void BeginLoad(TdsColumnType colType) 
252                 {
253                         if (LoadInProgress)
254                                 EndLoad ();
255
256                         StreamLength = 0;
257                 
258                         switch (colType) {
259                         case TdsColumnType.Text :
260                         case TdsColumnType.NText:
261                         case TdsColumnType.Image:
262                                 if (Comm.GetByte () != 0) {
263                                         Comm.Skip (24);
264                                         StreamLength = Comm.GetTdsInt ();
265                                 }
266                                 break;
267                         case TdsColumnType.BigVarChar:
268                         case TdsColumnType.BigChar:
269                         case TdsColumnType.BigBinary:
270                         case TdsColumnType.BigVarBinary:
271                                 Comm.GetTdsShort ();
272                                 StreamLength = Comm.GetTdsShort ();
273                                 break;
274                         case TdsColumnType.VarChar :
275                         case TdsColumnType.NVarChar :
276                         case TdsColumnType.Char:
277                         case TdsColumnType.NChar:
278                         case TdsColumnType.Binary:
279                         case TdsColumnType.VarBinary:
280                                 StreamLength = Comm.GetTdsShort ();
281                                 break;
282                         default :
283                                 StreamLength = -1;
284                                 break;
285                         }
286
287                         StreamIndex = 0;
288                         LoadInProgress = true;
289                 }
290
291                 private void EndLoad()
292                 {
293                         if (StreamLength > 0)
294                                 Comm.Skip (StreamLength);
295                         StreamLength = 0;
296                         StreamIndex = 0;
297                         StreamColumnIndex++;
298                         LoadInProgress = false;
299                 }
300
301                 private long LoadData (long fieldIndex, byte[] buffer, int bufferIndex, int size)
302                 {
303                         if (StreamLength <= 0)
304                                 return StreamLength;
305
306                         if (fieldIndex < StreamIndex)
307                                 throw new InvalidOperationException ("field index less than stream pos");
308
309                         if (fieldIndex >= (StreamLength + StreamIndex))
310                                 return 0;
311
312                         // Skip to the index
313                         Comm.Skip ((int) (fieldIndex - StreamIndex));
314                         StreamIndex += (fieldIndex - StreamIndex);
315
316                         // Load the reqd amt of bytes   
317                         int loadlen = (int) ((size > StreamLength) ? StreamLength : size);
318                         byte[] arr = Comm.GetBytes (loadlen, true);
319
320                         // update the index and stream length
321                         StreamIndex +=  loadlen + (fieldIndex - StreamIndex);
322                         StreamLength -= loadlen;
323                         arr.CopyTo (buffer, bufferIndex);
324
325                         return arr.Length;
326                 }
327
328                 #endregion // Properties
329
330                 #region Events
331
332                 public event TdsInternalErrorMessageEventHandler TdsErrorMessage;
333                 public event TdsInternalInfoMessageEventHandler TdsInfoMessage;
334
335                 #endregion // Events
336
337                 #region Constructors
338
339                 public Tds (string dataSource, int port, int packetSize, int timeout, TdsVersion tdsVersion)
340                 {
341                         this.tdsVersion = tdsVersion;
342                         this.packetSize = packetSize;
343                         this.dataSource = dataSource;
344
345                         comm = new TdsComm (dataSource, port, packetSize, timeout, tdsVersion);
346                 }
347
348                 #endregion // Constructors
349
350                 #region Public Methods
351
352                 internal protected void InitExec () 
353                 {
354                         // clean up 
355                         moreResults = true;
356                         doneProc = false;
357                         messages.Clear ();
358                         outputParameters.Clear ();
359                 }
360
361                 public void Cancel ()
362                 {
363                         if (queryInProgress) {
364                                 if (cancelsRequested == cancelsProcessed) {
365                                         comm.StartPacket (TdsPacketType.Cancel);
366                                         comm.SendPacket ();
367                                         cancelsRequested += 1;
368                                 }
369                         }       
370                 }
371         
372                 public abstract bool Connect (TdsConnectionParameters connectionParameters);
373
374                 public static TdsTimeoutException CreateTimeoutException (string dataSource, string method)
375                 {
376                         string message = "Timeout expired. The timeout period elapsed prior to completion of the operation or the server is not responding.";
377                         return new TdsTimeoutException (0, 0, message, -2, method, dataSource, "Mono TdsClient Data Provider", 0);
378                 }
379
380                 public void Disconnect ()
381                 {
382                         comm.StartPacket (TdsPacketType.Logoff);
383                         comm.Append ((byte) 0);
384                         comm.SendPacket ();     
385                         comm.Close ();
386                         connected = false;
387                 }
388                 
389                 public virtual bool Reset ()
390                 {
391                         database = originalDatabase;
392                         return true;
393                 }
394
395                 protected virtual bool IsValidRowCount (byte status, byte op)
396                 {
397                         return ((status & (0x10)) != 0) ;
398                 }
399
400                 public void Execute (string sql)
401                 {
402                         Execute (sql, null, 0, false);
403                 }
404
405                 public void ExecProc (string sql)
406                 {
407                         ExecProc (sql, null, 0, false);
408                 }
409
410                 public virtual void Execute (string sql, TdsMetaParameterCollection parameters, int timeout, bool wantResults)
411                 {
412                         ExecuteQuery (sql, timeout, wantResults);       
413                 }
414
415                 public virtual void ExecProc (string sql, TdsMetaParameterCollection parameters, int timeout, bool wantResults)
416                 {
417                         ExecuteQuery (String.Format ("exec {0}", sql), timeout, wantResults);
418                 }
419
420                 public virtual void ExecPrepared (string sql, TdsMetaParameterCollection parameters, int timeout, bool wantResults)
421                 {
422                         throw new NotSupportedException ();
423                 }
424
425                 internal void ExecBulkCopyMetaData (int timeout, bool wantResults)
426                 {
427                         moreResults = true;
428                         Comm.SendPacket ();
429
430                         CheckForData (timeout);
431                         if (!wantResults) 
432                                 SkipToEnd ();
433                 }
434
435                 internal void ExecBulkCopy (int timeout, bool wantResults)
436                 {
437                         moreResults = true;
438                         Comm.SendPacket ();
439
440                         CheckForData (timeout);
441                         if (!wantResults) 
442                                 SkipToEnd ();
443                 }
444
445                 protected void ExecuteQuery (string sql, int timeout, bool wantResults)
446                 {
447                         InitExec ();
448
449                         Comm.StartPacket (TdsPacketType.Query);
450                         Comm.Append (sql);
451                         Comm.SendPacket ();
452
453                         CheckForData (timeout);
454                         if (!wantResults) 
455                                 SkipToEnd ();
456                 }
457
458                 protected virtual void ExecRPC (string rpcName, TdsMetaParameterCollection parameters,
459                                                 int timeout, bool wantResults)
460                 {
461                         Comm.StartPacket (TdsPacketType.DBRPC);
462
463                         byte [] rpcNameBytes = Comm.Encoder.GetBytes (rpcName);
464                         byte rpcNameLength = (byte) rpcNameBytes.Length;
465                         ushort mask = 0x0000;
466                         ushort packetLength =  (ushort) (sizeof (byte) + rpcNameLength +
467                                                 sizeof (ushort));
468
469                         Comm.Append (packetLength);
470                         Comm.Append (rpcNameLength);
471                         Comm.Append (rpcNameBytes);
472                         Comm.Append (mask);
473                         
474                         Comm.SendPacket ();
475                         CheckForData (timeout);
476                         if (!wantResults) 
477                                 SkipToEnd ();
478                 }
479
480                 public bool NextResult ()
481                 {
482                         if (SequentialAccess) {
483                                 if (isResultRead) {
484                                         while (NextRow ()) {}
485                                         isRowRead = false;
486                                         isResultRead = false;
487                                 }
488                         }
489                         if (!moreResults)
490                                 return false;
491
492                         TdsPacketSubType subType;
493
494                         bool done = false;
495                         bool outputParams = false;
496
497                         while (!done) {
498                                 subType = ProcessSubPacket ();
499                                 if (outputParams) {
500                                         moreResults = false;
501                                         break;
502                                 }
503
504                                 switch (subType) {
505                                 case TdsPacketSubType.ColumnInfo:
506                                 case TdsPacketSubType.ColumnMetadata: 
507                                 case TdsPacketSubType.RowFormat: 
508                                         byte peek = Comm.Peek ();
509                                         done = (peek != (byte) TdsPacketSubType.TableName);
510                                         if (done && doneProc && peek == (byte) TdsPacketSubType.Row) {
511                                                 outputParams = true;
512                                                 done = false;
513                                         }
514
515                                         break;
516                                 case TdsPacketSubType.TableName:
517                                 //      done = true;
518                                         peek = Comm.Peek ();
519                                         done = (peek != (byte) TdsPacketSubType.ColumnDetail);
520
521                                         break;
522                                 case TdsPacketSubType.ColumnDetail:
523                                         done = true;
524                                         break;
525                                 default:
526                                         done = !moreResults;
527                                         break;
528                                 }
529                         }
530
531                         return moreResults;
532                 }
533
534                 public bool NextRow ()
535                 {
536                         if (SequentialAccess) {
537                                 if (isRowRead) {
538                                         SkipRow ();
539                                         isRowRead = false;
540                                 }
541                         }
542
543                         TdsPacketSubType subType;
544                         bool done = false;
545                         bool result = false;
546
547                         do {
548                                 subType = ProcessSubPacket ();
549                                 switch (subType) {
550                                 case TdsPacketSubType.Row:
551                                         result = true;
552                                         done = true;
553                                         break;
554                                 case TdsPacketSubType.Done:
555                                 case TdsPacketSubType.DoneProc:
556                                 case TdsPacketSubType.DoneInProc:
557                                         result = false;
558                                         done = true;
559                                         break;
560                                 }
561                         } while (!done);
562
563                         return result;
564                 }
565
566                 public virtual string Prepare (string sql, TdsMetaParameterCollection parameters)
567                 {
568                         throw new NotSupportedException ();
569                 }
570
571                 public void SkipToEnd ()
572                 {
573                         while (NextResult ()) { /* DO NOTHING */ }
574                 }
575
576                 public virtual void Unprepare (string statementId) 
577                 {
578                         throw new NotSupportedException ();
579                 }
580
581                 #endregion // Public Methods
582
583                 #region // Private Methods
584
585                 [MonoTODO ("Is cancel enough, or do we need to drop the connection?")]
586                 protected void CheckForData (int timeout) 
587                 {
588                         if (timeout > 0 && !comm.Poll (timeout, SelectMode.SelectRead)) {
589                                 Cancel ();
590                                 throw CreateTimeoutException (dataSource, "CheckForData()");
591                         }
592                 }
593         
594                 protected TdsInternalInfoMessageEventArgs CreateTdsInfoMessageEvent (TdsInternalErrorCollection errors)
595                 {
596                         return new TdsInternalInfoMessageEventArgs (errors);
597                 }
598
599                 protected TdsInternalErrorMessageEventArgs CreateTdsErrorMessageEvent (byte theClass, int lineNumber, string message, int number, string procedure, string server, string source, byte state)
600                 {
601                         return new TdsInternalErrorMessageEventArgs (new TdsInternalError (theClass, lineNumber, message, number, procedure, server, source, state));
602                 }
603
604                 private object GetColumnValue (TdsColumnType colType, bool outParam)
605                 {
606                         return GetColumnValue (colType, outParam, -1);
607                 }
608
609                 private object GetColumnValue (TdsColumnType colType, bool outParam, int ordinal)
610                 {
611                         int len;
612                         object element = null;
613
614                         switch (colType) {
615                         case TdsColumnType.IntN :
616                                 if (outParam)
617                                         comm.Skip (1);
618                                 element = GetIntValue (colType);
619                                 break;
620                         case TdsColumnType.Int1 :
621                         case TdsColumnType.Int2 :
622                         case TdsColumnType.Int4 :
623                                 element = GetIntValue (colType);
624                                 break;
625                         case TdsColumnType.Image :
626                                 if (outParam)
627                                         comm.Skip (1);
628                                 element = GetImageValue ();
629                                 break;
630                         case TdsColumnType.Text :
631                                 if (outParam) 
632                                         comm.Skip (1);
633                                 element = GetTextValue (false);
634                                 break;
635                         case TdsColumnType.NText :
636                                 if (outParam) 
637                                         comm.Skip (1);
638                                 element = GetTextValue (true);
639                                 break;
640                         case TdsColumnType.Char :
641                         case TdsColumnType.VarChar :
642                                 if (outParam)
643                                         comm.Skip (1);
644                                 element = GetStringValue (false, false);
645                                 break;
646                         case TdsColumnType.BigVarBinary :
647                                 if (outParam)
648                                         comm.Skip (1);
649                                 len = comm.GetTdsShort ();
650                                 element = comm.GetBytes (len, true);
651                                 break;
652                                 /*
653                         case TdsColumnType.BigBinary :
654                                 if (outParam)
655                                         comm.Skip (2);
656                                 len = comm.GetTdsShort ();
657                                 element = comm.GetBytes (len, true);
658                                 break;
659                                 */
660                         case TdsColumnType.BigBinary :
661                                 if (outParam)
662                                         comm.Skip (2);
663                                 element = GetBinaryValue ();
664                                 break;
665                         case TdsColumnType.BigChar :
666                         case TdsColumnType.BigVarChar :
667                                 if (outParam)
668                                         comm.Skip (2);
669                                 element = GetStringValue (false, false);
670                                 break;
671                         case TdsColumnType.NChar :
672                         case TdsColumnType.BigNVarChar :
673                                 if (outParam)
674                                         comm.Skip(2);
675                                 element = GetStringValue (true, false);
676                                 break;
677                         case TdsColumnType.NVarChar :
678                                 if (outParam) 
679                                         comm.Skip (1);
680                                 element = GetStringValue (true, false);
681                                 break;
682                         case TdsColumnType.Real :
683                         case TdsColumnType.Float8 :
684                                 element = GetFloatValue (colType);
685                                 break;
686                         case TdsColumnType.FloatN :
687                                 if (outParam) 
688                                         comm.Skip (1);
689                                 element = GetFloatValue (colType);
690                                 break;
691                         case TdsColumnType.SmallMoney :
692                         case TdsColumnType.Money :
693                                 element = GetMoneyValue (colType);
694                                 break;
695                         case TdsColumnType.MoneyN :
696                                 if (outParam)
697                                         comm.Skip (1);
698                                 element = GetMoneyValue (colType);
699                                 break;
700                         case TdsColumnType.Numeric :
701                         case TdsColumnType.Decimal :
702                                 byte precision;
703                                 byte scale;
704                                 if (outParam) {
705                                         comm.Skip (1);
706                                         precision = comm.GetByte ();
707                                         scale = comm.GetByte ();
708                                 }
709                                 else {
710                                         precision = (byte) columns[ordinal]["NumericPrecision"];
711                                         scale = (byte) columns[ordinal]["NumericScale"];
712                                 }
713
714                                 element = GetDecimalValue (precision, scale);
715                                 break;
716                         case TdsColumnType.DateTimeN :
717                                 if (outParam) 
718                                         comm.Skip (1);
719                                 element = GetDateTimeValue (colType);
720                                 break;
721                         case TdsColumnType.DateTime4 :
722                         case TdsColumnType.DateTime :
723                                 element = GetDateTimeValue (colType);
724                                 break;
725                         case TdsColumnType.VarBinary :
726                         case TdsColumnType.Binary :
727                                 if (outParam) 
728                                         comm.Skip (1);
729                                 element = GetBinaryValue ();
730                                 break;
731                         case TdsColumnType.BitN :
732                                 if (outParam) 
733                                         comm.Skip (1);
734                                 if (comm.GetByte () == 0)
735                                         element = DBNull.Value;
736                                 else
737                                         element = (comm.GetByte() != 0);
738                                 break;
739                         case TdsColumnType.Bit :
740                                 int columnSize = comm.GetByte ();
741                                 element = (columnSize != 0);
742                                 break;
743                         case TdsColumnType.UniqueIdentifier :
744                                 if (comm.Peek () != 16) { // If it's null, then what to do?
745                                         /*byte swallowed =*/ comm.GetByte();
746                                         element = DBNull.Value;
747                                         break;
748                                 }
749                                 if (outParam)
750                                         comm.Skip (1);
751                                 
752                                 len = comm.GetByte () & 0xff;
753                                 if (len > 0) {
754                                         byte[] guidBytes = comm.GetBytes (len, true);
755                                         if (!BitConverter.IsLittleEndian) {
756                                                 byte[] swappedguidBytes = new byte[len];
757                                                 for (int i = 0; i < 4; i++)
758                                                         swappedguidBytes[i] = guidBytes[4-i-1];
759                                                 for (int i = 4; i < 6; i++)
760                                                         swappedguidBytes[i] = guidBytes[6-(i-4)-1];
761                                                 for (int i = 6; i < 8; i++)
762                                                         swappedguidBytes[i] = guidBytes[8-(i-6)-1];
763                                                 for (int i = 8; i < 16; i++)
764                                                         swappedguidBytes[i] = guidBytes[i];
765                                                 Array.Copy(swappedguidBytes, 0, guidBytes, 0, len);
766                                         }
767                                         element = new Guid (guidBytes);
768                                 }
769                                 break;
770                         default :
771                                 return DBNull.Value;
772                         }
773                         return element;
774                 }
775
776                 private object GetBinaryValue ()
777                 {
778                         int len;
779                         object result = DBNull.Value;
780
781                         if (tdsVersion == TdsVersion.tds70) {
782                                 len = comm.GetTdsShort ();
783                                 if (len != 0xffff && len > 0)
784                                         result = comm.GetBytes (len, true);
785                         } else {
786                                 len = (comm.GetByte () & 0xff);
787                                 if (len != 0)
788                                         result = comm.GetBytes (len, true);
789                         }
790
791                         return result;
792                 }
793
794                 private object GetDateTimeValue (TdsColumnType type)
795                 {
796                         int len = 0;
797                         object result;
798                 
799                         switch (type) {
800                         case TdsColumnType.DateTime4:
801                                 len = 4;
802                                 break;
803                         case TdsColumnType.DateTime:
804                                 len = 8;
805                                 break;
806                         case TdsColumnType.DateTimeN:
807                                 byte tmp = comm.Peek ();
808                                 if (tmp != 0 && tmp != 4 && tmp != 8)
809                                         break;
810                                 len = comm.GetByte ();
811                                 break;
812                         }
813         
814                         DateTime epoch = new DateTime (1900, 1, 1);
815         
816                         switch (len) {
817                         case 8 :
818                                 result = epoch.AddDays (comm.GetTdsInt ());
819                                 int seconds = comm.GetTdsInt ();
820                                 long millis = ((((long) seconds) % 300L) * 1000L) / 300L;
821                                 if (seconds != 0 || millis != 0) {
822                                         result = ((DateTime) result).AddSeconds (seconds / 300);
823                                         result = ((DateTime) result).AddMilliseconds (millis);
824                                 }
825                                 break;
826                         case 4 :
827                                 // MSDN says small datetime is stored in 2 bytes as no of days
828                                 // *after* 1/1/1900. so, cast to unsigned short
829                                 result = epoch.AddDays ((ushort) comm.GetTdsShort ());
830                                 short minutes = comm.GetTdsShort ();
831                                 if (minutes != 0) 
832                                         result = ((DateTime) result).AddMinutes ((int) minutes);
833                                 break;
834                         default:
835                                 result = DBNull.Value;
836                                 break;
837                         }
838
839                         return result;
840                 }
841
842                 private object GetDecimalValue (byte precision, byte scale) {
843                         if (tdsVersion < TdsVersion.tds70)
844                                 return GetDecimalValueTds50 (precision, scale);
845                         else
846                                 return GetDecimalValueTds70 (precision, scale);
847                 }
848                 
849                 private object GetDecimalValueTds70 (byte precision, byte scale) {
850                         int[] bits = new int[4] {0,0,0,0};
851
852                         int len = (comm.GetByte() & 0xff) - 1;
853                         if (len < 0)
854                                 return DBNull.Value;
855                         
856                         bool positive = (comm.GetByte () == 1);
857                         if (len > 16)
858                                 throw new OverflowException ();
859
860                         for (int i = 0, index = 0; i < len && i < 16; i += 4, index += 1) 
861                                 bits[index] = comm.GetTdsInt ();
862                         
863                         if (bits [3] != 0) 
864                                 return new TdsBigDecimal (precision, scale, !positive, bits);
865                         else
866                                 return new Decimal (bits[0], bits[1], bits[2], !positive, scale);
867                 }
868
869                 private object GetDecimalValueTds50 (byte precision, byte scale) {
870                         int[] bits = new int[4] {0,0,0,0};
871
872                         int len = (comm.GetByte() & 0xff);
873                         if (len == 0)
874                                 return DBNull.Value;
875
876                         byte[] dec_bytes=comm.GetBytes(len,false);      
877                 
878                         byte[] easy=new byte[4];
879
880                         bool positive = dec_bytes[0]==1;
881
882                         if (len > 17)
883                                 throw new OverflowException ();
884
885                         for (int i = 1, index = 0; i < len && i < 16; i += 
886                                 4, index += 1) {
887                                 for(int j=0; j<4; j++)
888                                         if(i+j<len)
889                                                 easy[j]=dec_bytes[len-
890                                                         (i+j)];
891                                         else
892                                                 easy[j]=0;
893                                 if(!BitConverter.IsLittleEndian)
894                                         easy=comm.Swap(easy);
895                                 bits[index] = BitConverter.ToInt32(easy,0);
896                         }
897                         if (bits [3] != 0) 
898                                 return new TdsBigDecimal (precision, 
899                                         scale, positive, bits);
900                         else
901                                 return new Decimal(bits[0], bits[1], bits
902                                         [2], positive, scale);
903                         
904                 }
905
906                 private object GetFloatValue (TdsColumnType columnType)
907                 {
908                         int columnSize = 0;
909
910                         switch (columnType) {
911                         case TdsColumnType.Real:
912                                 columnSize = 4;
913                                 break;
914                         case TdsColumnType.Float8:
915                                 columnSize = 8;
916                                 break;
917                         case TdsColumnType.FloatN:
918                                 columnSize = comm.GetByte ();
919                                 break;
920                         }
921
922                         switch (columnSize) {
923                         case 8 :
924                                 return BitConverter.Int64BitsToDouble (comm.GetTdsInt64 ());
925                         case 4 :
926                                 return BitConverter.ToSingle (BitConverter.GetBytes (comm.GetTdsInt ()), 0);
927                         default :
928                                 return DBNull.Value;
929                         }
930                 }
931
932                 private object GetImageValue ()
933                 {
934                         byte hasValue = comm.GetByte ();
935
936                         if (hasValue == 0)
937                                 return DBNull.Value;
938                         
939                         comm.Skip (24);
940                         int len = comm.GetTdsInt ();
941
942                         if (len < 0)
943                                 return DBNull.Value;
944
945                         return (comm.GetBytes (len, true));
946                 }
947
948                 private object GetIntValue (TdsColumnType type)
949                 {
950                         int len;
951
952                         switch (type) {
953                         case TdsColumnType.IntN :
954                                 len = comm.GetByte ();
955                                 break;
956                         case TdsColumnType.Int4 :
957                                 len = 4; 
958                                 break;
959                         case TdsColumnType.Int2 :
960                                 len = 2; 
961                                 break;
962                         case TdsColumnType.Int1 :
963                                 len = 1; 
964                                 break;
965                         default:
966                                 return DBNull.Value;
967                         }
968
969                         switch (len) {
970                         case 4 :
971                                 return (comm.GetTdsInt ());
972                         case 2 :
973                                 return (comm.GetTdsShort ());
974                         case 1 :
975                                 return (comm.GetByte ());
976                         default:
977                                 return DBNull.Value;
978                         }
979                 }
980
981                 private object GetMoneyValue (TdsColumnType type)
982                 {
983                         int len;
984
985                         switch (type) {
986                         case TdsColumnType.SmallMoney :
987                         case TdsColumnType.Money4 :
988                                 len = 4;
989                                 break;
990                         case TdsColumnType.Money :
991                                 len = 8;
992                                 break;
993                         case TdsColumnType.MoneyN :
994                                 len = comm.GetByte ();
995                                 break;
996                         default:
997                                 return DBNull.Value;
998                         }
999
1000                         switch (len) {
1001                         case 4:
1002                                 return new Decimal (Comm.GetTdsInt (), 0, 0, false, 4);
1003                         case 8:
1004                                 int hi = Comm.GetTdsInt ();
1005                                 int lo = Comm.GetTdsInt ();
1006                                 return new Decimal (lo, hi, 0, false, 4);
1007                         default:
1008                                 return DBNull.Value;
1009                         }
1010                 }
1011
1012                 private object GetStringValue (bool wideChars, bool outputParam)
1013                 {
1014                         bool shortLen = (tdsVersion == TdsVersion.tds70) && (wideChars || !outputParam);
1015                         int len = shortLen ? comm.GetTdsShort () : (comm.GetByte () & 0xff);
1016
1017                         if (tdsVersion < TdsVersion.tds70 && len == 0)
1018                                 return DBNull.Value;
1019                         else if (len >= 0) {
1020                                 object result;
1021                                 if (wideChars)
1022                                         result = comm.GetString (len / 2);
1023                                 else
1024                                         result = comm.GetString (len, false);
1025                                 if (tdsVersion < TdsVersion.tds70 && ((string) result).Equals (" "))
1026                                         result = "";
1027                                 return result;
1028                         }
1029                         else
1030                                 return DBNull.Value;
1031                 }
1032
1033                 protected int GetSubPacketLength ()
1034                 {
1035                         return comm.GetTdsShort ();
1036                 }
1037
1038                 private object GetTextValue (bool wideChars)
1039                 {
1040                         string result = null;
1041                         byte hasValue = comm.GetByte ();
1042
1043                         if (hasValue != 16)
1044                                 return DBNull.Value;
1045
1046                         // 16 Byte TEXTPTR, 8 Byte TIMESTAMP
1047                         comm.Skip (24);
1048
1049                         int len = comm.GetTdsInt ();
1050
1051                         //if the len is 0 , then the string can be a '' string 
1052                         // this method is called only for Text and NText. Hence will
1053                         // return a empty string
1054                         if (len == 0)
1055                                 return "";
1056
1057                         if (wideChars)
1058                                 result = comm.GetString (len / 2);
1059                         else
1060                                 result = comm.GetString (len, false);
1061                                 len /= 2;
1062
1063                         if ((byte) tdsVersion < (byte) TdsVersion.tds70 && result == " ")
1064                                 result = "";
1065
1066                         return result;
1067                 }
1068
1069                 internal bool IsBlobType (TdsColumnType columnType)
1070                 {
1071                         return (columnType == TdsColumnType.Text || columnType == TdsColumnType.Image || columnType == TdsColumnType.NText);
1072                 }
1073
1074                 internal bool IsLargeType (TdsColumnType columnType)
1075                 {
1076                         return ((byte) columnType > 128);
1077                 }
1078
1079                 internal static bool IsFixedSizeColumn (TdsColumnType columnType)
1080                 {
1081                         switch (columnType) {
1082                                 case TdsColumnType.Int1 :
1083                                 case TdsColumnType.Int2 :
1084                                 case TdsColumnType.Int4 :
1085                                 case TdsColumnType.Float8 :
1086                                 case TdsColumnType.DateTime :
1087                                 case TdsColumnType.Bit :
1088                                 case TdsColumnType.Money :
1089                                 case TdsColumnType.Money4 :
1090                                 case TdsColumnType.SmallMoney :
1091                                 case TdsColumnType.Real :
1092                                 case TdsColumnType.DateTime4 :
1093                                   /*
1094                                 case TdsColumnType.Decimal:
1095                                 case TdsColumnType.Numeric:
1096                                   */
1097                                         return true;
1098                                 default :
1099                                         return false;
1100                         }
1101                 }
1102
1103                 protected void LoadRow ()
1104                 {
1105                         if (SequentialAccess) {
1106                                 if (isRowRead)
1107                                         SkipRow ();
1108                                 isRowRead = true;
1109                                 isResultRead = true;
1110                                 return;
1111                         }
1112
1113                         currentRow = new TdsDataRow ();
1114
1115                         int i = 0;
1116                         foreach (TdsDataColumn column in columns) {
1117                                 object o = GetColumnValue ((TdsColumnType) column["ColumnType"], false, i);
1118                                 currentRow.Add (o);
1119                                 if (doneProc)
1120                                         outputParameters.Add (o);
1121
1122                                 if (o is TdsBigDecimal && currentRow.BigDecimalIndex < 0) 
1123                                         currentRow.BigDecimalIndex = i;
1124                                 i += 1;
1125                         }
1126                 }
1127
1128                 internal static int LookupBufferSize (TdsColumnType columnType)
1129                 {
1130                         switch (columnType) {
1131                                 case TdsColumnType.Int1 :
1132                                 case TdsColumnType.Bit :
1133                                         return 1;
1134                                 case TdsColumnType.Int2 :
1135                                         return 2;
1136                                 case TdsColumnType.Int4 :
1137                                 case TdsColumnType.Real :
1138                                 case TdsColumnType.DateTime4 :
1139                                 case TdsColumnType.Money4 :
1140                                 case TdsColumnType.SmallMoney :
1141                                         return 4;
1142                                 case TdsColumnType.Float8 :
1143                                 case TdsColumnType.DateTime :
1144                                 case TdsColumnType.Money :
1145                                         return 8;
1146                                 default :
1147                                         return 0;
1148                         }
1149                 }
1150
1151                 private int LookupDisplaySize (TdsColumnType columnType) 
1152                 {
1153                         switch (columnType) {
1154                                 case TdsColumnType.Int1 :
1155                                         return 3;
1156                                 case TdsColumnType.Int2 :
1157                                         return 6;
1158                                 case TdsColumnType.Int4 :
1159                                         return 11;
1160                                 case TdsColumnType.Real :
1161                                         return 14;
1162                                 case TdsColumnType.Float8 :
1163                                         return 24;
1164                                 case TdsColumnType.DateTime :
1165                                         return 23;
1166                                 case TdsColumnType.DateTime4 :
1167                                         return 16;
1168                                 case TdsColumnType.Bit :
1169                                         return 1;
1170                                 case TdsColumnType.Money :
1171                                         return 21;
1172                                 case TdsColumnType.Money4 :
1173                                 case TdsColumnType.SmallMoney :
1174                                         return 12;
1175                                 default:
1176                                         return 0;
1177                         }
1178                 }
1179
1180                 protected internal int ProcessAuthentication ()
1181                 {
1182                         int pdu_size = Comm.GetTdsShort ();
1183                         byte[] msg2 = Comm.GetBytes (pdu_size, true);
1184
1185                         Type2Message t2 = new Type2Message (msg2);
1186                         // 0x0001       Negotiate Unicode
1187                         // 0x0200       Negotiate NTLM
1188                         // 0x8000       Negotiate Always Sign
1189
1190                         Type3Message t3 = new Type3Message ();
1191                         t3.Challenge = t2.Nonce;
1192                         
1193                         t3.Domain = this.connectionParms.DefaultDomain;
1194                         t3.Host = this.connectionParms.Hostname;
1195                         t3.Username = this.connectionParms.User;
1196                         t3.Password = this.connectionParms.Password;
1197
1198                         Comm.StartPacket (TdsPacketType.SspAuth); // 0x11
1199                         Comm.Append (t3.GetBytes ());
1200                         Comm.SendPacket ();
1201                         return 1; // TDS_SUCCEED
1202                 }
1203
1204                 protected void ProcessColumnDetail ()
1205                 {
1206                         int len = GetSubPacketLength ();
1207                         byte[] values = new byte[3];
1208                         int columnNameLength;
1209                         string baseColumnName = String.Empty;
1210                         int position = 0;
1211
1212                         while (position < len) {
1213                                 for (int j = 0; j < 3; j += 1) 
1214                                         values[j] = comm.GetByte ();
1215                                 position += 3;
1216
1217                                 bool isAlias = ((values[2] & (byte) TdsColumnStatus.Rename) != 0);
1218                                 if (isAlias) {
1219                                         if (tdsVersion == TdsVersion.tds70) {
1220                                                 columnNameLength = comm.GetByte ();
1221                                                 position += 2 * columnNameLength + 1;
1222                                         }
1223                                         else {
1224                                                 columnNameLength = comm.GetByte ();
1225                                                 position += columnNameLength + 1;
1226                                         }
1227                                         baseColumnName = comm.GetString (columnNameLength);
1228                                 }
1229
1230                                 byte index = (byte) (values[0] - (byte) 1);
1231                                 byte tableIndex = (byte) (values[1] - (byte) 1);
1232                                 bool isExpression = ((values[2] & (byte) TdsColumnStatus.IsExpression) != 0);
1233
1234                                 columns [index]["IsExpression"] = isExpression;
1235                                 columns [index]["IsKey"] = ((values[2] & (byte) TdsColumnStatus.IsKey) != 0);
1236                                 columns [index]["IsHidden"] = ((values[2] & (byte) TdsColumnStatus.Hidden) != 0);
1237                                 columns [index]["IsAliased"] = isAlias;
1238
1239                                 columns [index]["BaseColumnName"] = ((isAlias) ? baseColumnName : null);
1240                                 columns [index]["BaseTableName"] = ((!isExpression) ? tableNames [tableIndex] : null);
1241                         }
1242                 }
1243
1244                 protected abstract TdsDataColumnCollection ProcessColumnInfo ();
1245
1246                 protected void ProcessColumnNames ()
1247                 {
1248                         columnNames = new ArrayList ();
1249
1250                         int totalLength = comm.GetTdsShort ();
1251                         int bytesRead = 0;
1252                         int i = 0;
1253
1254                         while (bytesRead < totalLength) {
1255                                 int columnNameLength = comm.GetByte ();
1256                                 string columnName = comm.GetString (columnNameLength);
1257                                 bytesRead = bytesRead + 1 + columnNameLength;
1258                                 columnNames.Add (columnName);
1259                                 i += 1;
1260                         }
1261                 }
1262
1263                 [MonoTODO ("Make sure counting works right, especially with multiple resultsets.")]
1264                 protected void ProcessEndToken (TdsPacketSubType type)
1265                 {
1266                         byte status = Comm.GetByte ();
1267                         Comm.Skip (1);
1268                         byte op = comm.GetByte ();
1269                         Comm.Skip (1);
1270
1271                         int rowCount = comm.GetTdsInt ();
1272                         bool validRowCount = IsValidRowCount (status,op);
1273                         moreResults = ((status & 0x01) != 0);
1274                         bool cancelled = ((status & 0x20) != 0);
1275
1276                         switch (type) {
1277                         case TdsPacketSubType.DoneProc:
1278                                 doneProc = true;
1279                                 goto case TdsPacketSubType.Done;
1280                         case TdsPacketSubType.Done:
1281                         case TdsPacketSubType.DoneInProc:
1282                                 if (validRowCount) {
1283                                         if (recordsAffected == -1) 
1284                                                 recordsAffected = rowCount;
1285                                         else
1286                                                 recordsAffected += rowCount;
1287                                 }
1288                                 break;
1289                         }
1290
1291                         if (moreResults) 
1292                                 queryInProgress = false;
1293                         if (cancelled)
1294                                 cancelsProcessed += 1;
1295                         if (messages.Count > 0 && !moreResults) 
1296                                 OnTdsInfoMessage (CreateTdsInfoMessageEvent (messages));
1297                 }
1298
1299                 protected void ProcessEnvironmentChange ()
1300                 {
1301                         int len = GetSubPacketLength ();
1302                         TdsEnvPacketSubType type = (TdsEnvPacketSubType) comm.GetByte ();
1303                         int cLen;
1304
1305                         switch (type) {
1306                         case TdsEnvPacketSubType.BlockSize :
1307                                 string blockSize;
1308                                 cLen = comm.GetByte ();
1309                                 blockSize = comm.GetString (cLen);
1310
1311                                 if (tdsVersion == TdsVersion.tds70) 
1312                                         comm.Skip (len - 2 - cLen * 2);
1313                                 else 
1314                                         comm.Skip (len - 2 - cLen);
1315
1316                                 packetSize = Int32.Parse (blockSize);   
1317                                 comm.ResizeOutBuf (packetSize);
1318                                 break;
1319                         case TdsEnvPacketSubType.CharSet :
1320                                 cLen = comm.GetByte ();
1321                                 if (tdsVersion == TdsVersion.tds70) {
1322                                         SetCharset (comm.GetString (cLen));
1323                                         comm.Skip (len - 2 - cLen * 2);
1324                                 }
1325                                 else {
1326                                         SetCharset (comm.GetString (cLen));
1327                                         comm.Skip (len - 2 - cLen);
1328                                 }
1329
1330                                 break;
1331                         case TdsEnvPacketSubType.Database :
1332                                 cLen = comm.GetByte ();
1333                                 string newDB = comm.GetString (cLen);
1334                                 cLen = comm.GetByte () & 0xff;
1335                                 comm.GetString (cLen);
1336                                 if (originalDatabase == string.Empty)
1337                                         originalDatabase = newDB;
1338                                 database = newDB;
1339                                 break;
1340                         default:
1341                                 comm.Skip (len - 1);
1342                                 break;
1343                         }
1344                 }
1345
1346                 protected void ProcessLoginAck ()
1347                 {
1348                         GetSubPacketLength ();
1349
1350                         if (tdsVersion == TdsVersion.tds70) {
1351                                 comm.Skip (5);
1352                                 int nameLength = comm.GetByte ();
1353                                 databaseProductName = comm.GetString (nameLength);
1354                                 databaseMajorVersion = comm.GetByte ();
1355                                 databaseProductVersion = String.Format ("{0}.{1}.{2}", databaseMajorVersion.ToString("00"),
1356                                                                 comm.GetByte ().ToString("00"), 
1357                                                                 (256 * comm.GetByte () + comm.GetByte ()).ToString("0000"));
1358                         }
1359                         else {
1360                                 comm.Skip (5);
1361                                 short nameLength = comm.GetByte ();
1362                                 databaseProductName = comm.GetString (nameLength);
1363                                 comm.Skip (1);
1364                                 databaseMajorVersion = comm.GetByte ();
1365                                 databaseProductVersion = String.Format ("{0}.{1}", databaseMajorVersion, comm.GetByte ());
1366                                 comm.Skip (1);
1367                         }
1368
1369                         if (databaseProductName.Length > 1 && -1 != databaseProductName.IndexOf ('\0')) {
1370                                 int last = databaseProductName.IndexOf ('\0');
1371                                 databaseProductName = databaseProductName.Substring (0, last);
1372                         }
1373
1374                         connected = true;
1375                 }
1376
1377                 protected void OnTdsErrorMessage (TdsInternalErrorMessageEventArgs e)
1378                 {
1379                         if (TdsErrorMessage != null)
1380                                 TdsErrorMessage (this, e);
1381                 }
1382
1383                 protected void OnTdsInfoMessage (TdsInternalInfoMessageEventArgs e)
1384                 {
1385                         if (TdsInfoMessage != null)
1386                                 TdsInfoMessage (this, e);
1387                         messages.Clear ();
1388                 }
1389
1390                 protected void ProcessMessage (TdsPacketSubType subType)
1391                 {
1392                         GetSubPacketLength ();
1393
1394                         int number = comm.GetTdsInt ();
1395                         byte state = comm.GetByte ();
1396                         byte theClass = comm.GetByte ();
1397                         string message;
1398                         string server;
1399                         string procedure;
1400                         byte lineNumber;
1401                         string source;
1402                         bool isError = false;
1403
1404                         if (subType == TdsPacketSubType.EED) {
1405                                 isError = (theClass > 10);
1406                                 comm.Skip (comm.GetByte ()); // SQL State
1407                                 comm.Skip (1);               // Status
1408                                 comm.Skip (2);               // TranState
1409                         } else 
1410                                 isError = (subType == TdsPacketSubType.Error);
1411
1412                         message = comm.GetString (comm.GetTdsShort ());
1413                         server = comm.GetString (comm.GetByte ());
1414                         procedure = comm.GetString (comm.GetByte ());
1415                         lineNumber = comm.GetByte ();
1416                         comm.Skip (1);
1417                         source = String.Empty; // FIXME
1418
1419                         if (isError)
1420                                 OnTdsErrorMessage (CreateTdsErrorMessageEvent (theClass, lineNumber, message, number, procedure, server, source, state));
1421                         else
1422                                 messages.Add (new TdsInternalError (theClass, lineNumber, message, number, procedure, server, source, state));
1423                 }
1424
1425                 protected void ProcessOutputParam ()
1426                 {
1427                         GetSubPacketLength ();
1428                         /*string paramName = */comm.GetString (comm.GetByte () & 0xff);
1429                         comm.Skip (5);
1430
1431                         TdsColumnType colType = (TdsColumnType) comm.GetByte ();
1432                         object value = GetColumnValue (colType, true);
1433                         outputParameters.Add (value);
1434                 }
1435
1436                 protected void ProcessDynamic ()
1437                 {
1438                         Comm.Skip (2);
1439                         /*byte type =*/ Comm.GetByte ();
1440                         /*byte status =*/ Comm.GetByte ();
1441                         /*string id =*/ Comm.GetString (Comm.GetByte ());
1442                 }
1443
1444                 protected virtual TdsPacketSubType ProcessSubPacket ()
1445                 {
1446                         TdsPacketSubType subType = (TdsPacketSubType) comm.GetByte ();
1447
1448                         switch (subType) {
1449                         case TdsPacketSubType.Dynamic2:
1450                                 comm.Skip (comm.GetTdsInt ());
1451                                 break;
1452                         case TdsPacketSubType.AltName:
1453                         case TdsPacketSubType.AltFormat:
1454                         case TdsPacketSubType.Capability:
1455                         case TdsPacketSubType.ParamFormat:
1456                                 comm.Skip (comm.GetTdsShort ());
1457                                 break;
1458                         case TdsPacketSubType.Dynamic:
1459                                 ProcessDynamic ();
1460                                 break;
1461                         case TdsPacketSubType.EnvironmentChange:
1462                                 ProcessEnvironmentChange ();
1463                                 break;
1464                         case TdsPacketSubType.Info:  // TDS 4.2/7.0
1465                         case TdsPacketSubType.EED:   // TDS 5.0
1466                         case TdsPacketSubType.Error: // TDS 4.2/7.0
1467                                 ProcessMessage (subType);
1468                                 break;
1469                         case TdsPacketSubType.Param:
1470                                 ProcessOutputParam ();
1471                                 break;
1472                         case TdsPacketSubType.LoginAck:
1473                                 ProcessLoginAck ();
1474                                 break;
1475                         case TdsPacketSubType.Authentication: // TDS 7.0
1476                                 ProcessAuthentication ();
1477                                 break;
1478                         case TdsPacketSubType.ReturnStatus :
1479                                 ProcessReturnStatus ();
1480                                 break;
1481                         case TdsPacketSubType.ProcId:
1482                                 Comm.Skip (8);
1483                                 break;
1484                         case TdsPacketSubType.Done:
1485                         case TdsPacketSubType.DoneProc:
1486                         case TdsPacketSubType.DoneInProc:
1487                                 ProcessEndToken (subType);
1488                                 break;
1489                         case TdsPacketSubType.ColumnName:
1490                                 Comm.Skip (8);
1491                                 ProcessColumnNames ();
1492                                 break;
1493                         case TdsPacketSubType.ColumnInfo:      // TDS 4.2
1494                         case TdsPacketSubType.ColumnMetadata:  // TDS 7.0
1495                         case TdsPacketSubType.RowFormat:       // TDS 5.0
1496                                 columns = ProcessColumnInfo ();
1497                                 break;
1498                         case TdsPacketSubType.ColumnDetail:
1499                                 ProcessColumnDetail ();
1500                                 break;
1501                         case TdsPacketSubType.TableName:
1502                                 ProcessTableName ();
1503                                 break;
1504                         case TdsPacketSubType.ColumnOrder:
1505                                 comm.Skip (comm.GetTdsShort ());
1506                                 break;
1507                         case TdsPacketSubType.Control:
1508                                 comm.Skip (comm.GetTdsShort ());
1509                                 break;
1510                         case TdsPacketSubType.Row:
1511                                 LoadRow ();
1512                                 break;
1513                         }
1514
1515                         return subType;
1516                 }
1517
1518                 protected void ProcessTableName ()
1519                 {
1520                         tableNames = new ArrayList ();
1521                         int totalLength = comm.GetTdsShort ();
1522                         int position = 0;
1523                         int len;
1524
1525                         while (position < totalLength) {
1526                                 if (tdsVersion == TdsVersion.tds70) {
1527                                         len = comm.GetTdsShort ();
1528                                         position += 2 * (len + 1);
1529                                 }
1530                                 else {
1531                                         len = comm.GetByte ();
1532                                         position += len + 1;
1533                                 }
1534                                 tableNames.Add (comm.GetString (len));
1535                         }       
1536                 }
1537
1538                 protected void SetCharset (string charset)
1539                 {
1540                         if (charset == null || charset.Length > 30)
1541                                 charset = "iso_1";
1542
1543                         if (this.charset != null && this.charset == charset)
1544                                 return;
1545
1546                         if (charset.StartsWith ("cp")) {
1547                                 encoder = Encoding.GetEncoding (Int32.Parse (charset.Substring (2)));
1548                                 this.charset = charset;
1549                         }
1550                         else {
1551                                 encoder = Encoding.GetEncoding ("iso-8859-1");
1552                                 this.charset = "iso_1";
1553                         }
1554                         comm.Encoder = encoder;
1555                 }
1556
1557                 protected void SetLanguage (string language)
1558                 {
1559                         if (language == null || language.Length > 30)
1560                                 language = "us_english";
1561
1562                         this.language = language;
1563                 }
1564
1565                 protected virtual void ProcessReturnStatus () 
1566                 {
1567                         comm.Skip(4);
1568                 }
1569
1570                 #endregion // Private Methods
1571
1572 #if NET_2_0
1573                 #region asynchronous methods
1574                 protected IAsyncResult BeginExecuteQueryInternal (string sql, bool wantResults, 
1575                                                           AsyncCallback callback, object state)
1576                 {
1577                         InitExec ();
1578
1579                         TdsAsyncResult ar = new TdsAsyncResult (callback, state);
1580                         ar.TdsAsyncState.WantResults = wantResults;
1581
1582                         Comm.StartPacket (TdsPacketType.Query);
1583                         Comm.Append (sql);
1584                         Comm.SendPacket ();
1585
1586                         Comm.BeginReadPacket (new AsyncCallback(OnBeginExecuteQueryCallback), 
1587                                                                     ar);
1588                         return ar;
1589                 }
1590                 
1591                 protected void EndExecuteQueryInternal (IAsyncResult ar)
1592                 {
1593                         if (!ar.IsCompleted)
1594                                 ar.AsyncWaitHandle.WaitOne ();
1595                         TdsAsyncResult result = (TdsAsyncResult) ar;
1596                         if (result.IsCompletedWithException)
1597                                 throw result.Exception;
1598                 }
1599
1600                 protected void OnBeginExecuteQueryCallback (IAsyncResult ar)
1601                 {
1602                         TdsAsyncResult result = (TdsAsyncResult) ar.AsyncState;
1603                         TdsAsyncState tdsState = (TdsAsyncState) result.TdsAsyncState;
1604
1605                         try {
1606                                 Comm.EndReadPacket (ar);
1607                                 if (!tdsState.WantResults)
1608                                         SkipToEnd ();
1609                         } catch (Exception e) {
1610                                 result.MarkComplete (e);
1611                                 return;
1612                         }
1613                         result.MarkComplete ();
1614                 }
1615                 
1616
1617                 public virtual IAsyncResult BeginExecuteNonQuery (string sql,
1618                                                                   TdsMetaParameterCollection parameters,
1619                                                                   AsyncCallback callback,
1620                                                                   object state)
1621                 {
1622                         // abstract, kept to be backward compatiable.
1623                         throw new NotImplementedException ("should not be called!");
1624                 }
1625                 
1626                 public virtual void EndExecuteNonQuery (IAsyncResult ar)
1627                 {
1628                         // abstract method
1629                         throw new NotImplementedException ("should not be called!");
1630                 }
1631                 
1632                 public virtual IAsyncResult BeginExecuteQuery (string sql,
1633                                                                   TdsMetaParameterCollection parameters,
1634                                                                   AsyncCallback callback,
1635                                                                   object state)
1636                 {
1637                         // abstract, kept to be backward compatiable.
1638                         throw new NotImplementedException ("should not be called!");
1639                 }
1640                 
1641                 public virtual void EndExecuteQuery (IAsyncResult ar)
1642                 {
1643                         // abstract method
1644                         throw new NotImplementedException ("should not be called!");
1645                 }
1646
1647                 public virtual IAsyncResult BeginExecuteProcedure (string prolog,
1648                                                                     string epilog,
1649                                                                     string cmdText,
1650                                                                     bool IsNonQuery,
1651                                                                     TdsMetaParameterCollection parameters,
1652                                                                     AsyncCallback callback,
1653                                                                     object state)
1654                 {
1655                         throw new NotImplementedException ("should not be called!");
1656                 }
1657                 
1658                 public virtual void EndExecuteProcedure (IAsyncResult ar)
1659                 {
1660                         // abstract method
1661                         throw new NotImplementedException ("should not be called!");
1662                 }
1663                 
1664                 public void WaitFor (IAsyncResult ar)
1665                 {
1666                         if (! ar.IsCompleted)
1667                                 ar.AsyncWaitHandle.WaitOne ();
1668                 }
1669
1670                 public void CheckAndThrowException (IAsyncResult ar)
1671                 {
1672                         TdsAsyncResult result = (TdsAsyncResult) ar;
1673                         if (result.IsCompleted && result.IsCompletedWithException)
1674                                 throw result.Exception;
1675                 }
1676
1677                 #endregion // asynchronous methods
1678 #endif // NET_2_0
1679
1680
1681         }
1682 }