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