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