2 // Mono.Data.Tds.Protocol.Tds.cs
5 // Tim Coleman (tim@timcoleman.com)
6 // Sebastien Pouliot (spouliot@motus.com)
7 // Daniel Morgan (danielmorgan@verizon.net)
8 // Veerapuram Varadhan (vvaradhan@novell.com)
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.
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:
24 // The above copyright notice and this permission notice shall be
25 // included in all copies or substantial portions of the Software.
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.
36 using Mono
.Security
.Protocol
.Ntlm
;
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
;
46 using System
.Runtime
.InteropServices
;
48 namespace Mono
.Data
.Tds
.Protocol
50 public abstract class Tds
55 TdsVersion tdsVersion
;
57 protected internal TdsConnectionParameters connectionParms
;
58 protected readonly byte[] NTLMSSP_ID
= new byte[] {0x4e, 0x54, 0x4c, 0x4d, 0x53, 0x53, 0x50, 0x00}
;
63 string originalDatabase
= string.Empty
;
64 string databaseProductName
;
65 string databaseProductVersion
;
66 int databaseMajorVersion
;
67 CultureInfo locale
= CultureInfo
.InvariantCulture
;
69 readonly int lifeTime
;
70 readonly DateTime created
= DateTime
.Now
;
83 TdsDataRow currentRow
;
84 TdsDataColumnCollection columns
;
87 ArrayList columnNames
;
89 TdsMetaParameterCollection parameters
= new TdsMetaParameterCollection ();
98 ArrayList outputParameters
= new ArrayList ();
99 protected TdsInternalErrorCollection messages
= new TdsInternalErrorCollection ();
101 int recordsAffected
= -1;
105 int StreamColumnIndex
;
107 bool sequentialAccess
;
113 internal int poolStatus
= 0;
119 protected string Charset
{
120 get { return charset; }
123 protected CultureInfo Locale
{
124 get { return locale; }
127 public bool DoneProc
{
128 get { return doneProc; }
131 protected string Language
{
132 get { return language; }
135 protected ArrayList ColumnNames
{
136 get { return columnNames; }
139 public TdsDataRow ColumnValues
{
140 get { return currentRow; }
143 internal TdsComm Comm
{
147 public string Database
{
148 get { return database; }
151 public string DataSource
{
152 get { return dataSource; }
155 public virtual bool IsConnected
{
156 get { return connected && comm != null && comm.IsConnected (); }
157 set { connected = value; }
160 public bool Pooling
{
161 get { return pooling; }
162 set { pooling = value; }
165 public bool MoreResults
{
166 get { return moreResults; }
167 set { moreResults = value; }
170 public int PacketSize
{
171 get { return packetSize; }
174 public int RecordsAffected
{
175 get { return recordsAffected; }
176 set { recordsAffected = value; }
179 public string ServerVersion
{
180 get { return databaseProductVersion; }
183 public TdsDataColumnCollection Columns
{
184 get { return columns; }
187 public TdsVersion TdsVersion
{
188 get { return tdsVersion; }
191 public ArrayList OutputParameters
{
192 get { return outputParameters; }
193 set { outputParameters = value; }
196 protected TdsMetaParameterCollection Parameters
{
197 get { return parameters; }
198 set { parameters = value; }
201 public bool SequentialAccess
{
202 get { return sequentialAccess; }
203 set { sequentialAccess = value; }
206 public byte[] Collation
{
207 get {return collation; }
210 public TdsVersion ServerTdsVersion
{
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
224 private void SkipRow ()
226 SkipToColumnIndex (Columns
.Count
);
229 StreamColumnIndex
= 0;
231 LoadInProgress
= false;
234 private void SkipToColumnIndex (int colIndex
)
239 if (colIndex
< StreamColumnIndex
)
240 throw new Exception ("Cannot Skip to a colindex less than the curr index");
242 while (colIndex
!= StreamColumnIndex
) {
244 TdsColumnType
? colType
= Columns
[StreamColumnIndex
].ColumnType
;
246 throw new Exception ("Column type unset.");
248 TdsColumnType colType
= (TdsColumnType
) Columns
[StreamColumnIndex
]["ColumnType"];
250 if (!(colType
== TdsColumnType
.Image
||
251 colType
== TdsColumnType
.Text
||
252 colType
== TdsColumnType
.NText
)) {
253 GetColumnValue (colType
, false, StreamColumnIndex
);
254 StreamColumnIndex
++;
258 Comm
.Skip (StreamLength
);
265 public object GetSequentialColumnValue (int colIndex
)
267 if (colIndex
< StreamColumnIndex
)
268 throw new InvalidOperationException ("Invalid attempt tp read from column ordinal" + colIndex
);
273 if (colIndex
!= StreamColumnIndex
)
274 SkipToColumnIndex (colIndex
);
277 object o
= GetColumnValue (Columns
[colIndex
].ColumnType
, false, colIndex
);
279 object o
= GetColumnValue ((TdsColumnType
)Columns
[colIndex
]["ColumnType"], false, colIndex
);
285 public long GetSequentialColumnValue (int colIndex
, long fieldIndex
, byte[] buffer
, int bufferIndex
, int size
)
287 if (colIndex
< StreamColumnIndex
)
288 throw new InvalidOperationException ("Invalid attempt to read from column ordinal" + colIndex
);
290 if (colIndex
!= StreamColumnIndex
)
291 SkipToColumnIndex (colIndex
);
293 if (!LoadInProgress
) {
295 BeginLoad (Columns
[colIndex
].ColumnType
);
297 BeginLoad ((TdsColumnType
)Columns
[colIndex
]["ColumnType"]);
303 return LoadData (fieldIndex
, buffer
, bufferIndex
, size
);
304 } catch (IOException ex
) {
306 throw new TdsInternalException ("Server closed the connection.", ex
);
310 private void BeginLoad (
312 TdsColumnType
? colType
314 TdsColumnType colType
325 throw new ArgumentNullException ("colType");
329 case TdsColumnType
.Text
:
330 case TdsColumnType
.NText
:
331 case TdsColumnType
.Image
:
332 if (Comm
.GetByte () != 0) {
334 StreamLength
= Comm
.GetTdsInt ();
336 // use -2 to indicate that we're dealing
341 case TdsColumnType
.BigVarChar
:
342 case TdsColumnType
.BigChar
:
343 case TdsColumnType
.BigBinary
:
344 case TdsColumnType
.BigVarBinary
:
346 StreamLength
= Comm
.GetTdsShort ();
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 ();
362 LoadInProgress
= true;
365 private void EndLoad()
367 if (StreamLength
> 0)
368 Comm
.Skip (StreamLength
);
372 LoadInProgress
= false;
375 private long LoadData (long fieldIndex
, byte[] buffer
, int bufferIndex
, int size
)
377 if (StreamLength
<= 0)
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
));
388 if (fieldIndex
>= (StreamLength
+ StreamIndex
))
391 // determine number of bytes to skip
392 int skip
= (int) (fieldIndex
- StreamIndex
);
395 // update the current position
396 StreamIndex
+= (fieldIndex
- StreamIndex
);
397 // update the remaining length
398 StreamLength
-= skip
;
400 // Load the reqd amt of bytes
401 int loadlen
= (int) ((size
> StreamLength
) ? StreamLength
: size
);
402 byte[] arr
= Comm
.GetBytes (loadlen
, true);
404 // update the index and stream length
405 StreamIndex
+= loadlen
+ (fieldIndex
- StreamIndex
);
406 StreamLength
-= loadlen
;
407 arr
.CopyTo (buffer
, bufferIndex
);
412 #endregion // Properties
416 public event TdsInternalErrorMessageEventHandler TdsErrorMessage
;
417 public event TdsInternalInfoMessageEventHandler TdsInfoMessage
;
423 public Tds (string dataSource
, int port
, int packetSize
, int timeout
, TdsVersion tdsVersion
)
424 : this (dataSource
, port
, packetSize
, timeout
, 0, tdsVersion
)
428 public Tds (string dataSource
, int port
, int packetSize
, int timeout
, int lifeTime
, TdsVersion tdsVersion
)
430 this.tdsVersion
= tdsVersion
;
431 this.packetSize
= packetSize
;
432 this.dataSource
= dataSource
;
433 this.columns
= new TdsDataColumnCollection ();
434 this.lifeTime
= lifeTime
;
436 InitComm (port
, timeout
);
439 protected virtual void InitComm (int port
, int timeout
)
441 comm
= new TdsComm (dataSource
, port
, packetSize
, timeout
, tdsVersion
);
444 #endregion // Constructors
446 #region Public Methods
448 internal bool Expired
{
452 return DateTime
.Now
> (created
+ TimeSpan
.FromSeconds (lifeTime
));
456 internal protected void InitExec ()
462 // Reset "read" status variables - used in case of SequentialAccess
463 isResultRead
= false;
467 StreamColumnIndex
= 0;
468 LoadInProgress
= false;
470 // Reset more variables
471 queryInProgress
= false;
472 cancelsRequested
= 0;
473 cancelsProcessed
= 0;
474 recordsAffected
= -1;
477 outputParameters
.Clear ();
480 public void Cancel ()
482 if (queryInProgress
) {
483 if (cancelsRequested
== cancelsProcessed
) {
484 comm
.StartPacket (TdsPacketType
.Cancel
);
487 } catch (IOException ex
) {
489 throw new TdsInternalException ("Server closed the connection.", ex
);
491 cancelsRequested
+= 1;
496 public abstract bool Connect (TdsConnectionParameters connectionParameters
);
498 public static TdsTimeoutException
CreateTimeoutException (string dataSource
, string method
)
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);
504 public virtual void Disconnect ()
507 comm
.StartPacket (TdsPacketType
.Logoff
);
508 comm
.Append ((byte) 0);
511 // We're closing the socket anyway
517 public virtual bool Reset ()
519 database
= originalDatabase
;
523 protected virtual bool IsValidRowCount (byte status
, byte op
)
525 return ((status
& (0x10)) != 0) ;
528 public void Execute (string sql
)
530 Execute (sql
, null, 0, false);
533 public void ExecProc (string sql
)
535 ExecProc (sql
, null, 0, false);
538 public virtual void Execute (string sql
, TdsMetaParameterCollection parameters
, int timeout
, bool wantResults
)
540 ExecuteQuery (sql
, timeout
, wantResults
);
543 public virtual void ExecProc (string sql
, TdsMetaParameterCollection parameters
, int timeout
, bool wantResults
)
545 ExecuteQuery (String
.Format ("exec {0}", sql
), timeout
, wantResults
);
548 public virtual void ExecPrepared (string sql
, TdsMetaParameterCollection parameters
, int timeout
, bool wantResults
)
550 throw new NotSupportedException ();
553 internal void ExecBulkCopyMetaData (int timeout
, bool wantResults
)
558 CheckForData (timeout
);
561 } catch (IOException ex
) {
563 throw new TdsInternalException ("Server closed the connection.", ex
);
567 internal void ExecBulkCopy (int timeout
, bool wantResults
)
572 CheckForData (timeout
);
575 } catch (IOException ex
) {
577 throw new TdsInternalException ("Server closed the connection.", ex
);
581 protected void ExecuteQuery (string sql
, int timeout
, bool wantResults
)
585 Comm
.StartPacket (TdsPacketType
.Query
);
589 CheckForData (timeout
);
592 } catch (IOException ex
) {
594 throw new TdsInternalException ("Server closed the connection.", ex
);
598 protected virtual void ExecRPC (string rpcName
, TdsMetaParameterCollection parameters
,
599 int timeout
, bool wantResults
)
601 Comm
.StartPacket (TdsPacketType
.DBRPC
);
603 byte [] rpcNameBytes
= Comm
.Encoder
.GetBytes (rpcName
);
604 byte rpcNameLength
= (byte) rpcNameBytes
.Length
;
605 ushort mask
= 0x0000;
606 ushort packetLength
= (ushort) (sizeof (byte) + rpcNameLength
+
609 Comm
.Append (packetLength
);
610 Comm
.Append (rpcNameLength
);
611 Comm
.Append (rpcNameBytes
);
616 CheckForData (timeout
);
619 } catch (IOException ex
) {
621 throw new TdsInternalException ("Server closed the connection.", ex
);
625 public bool NextResult ()
627 if (SequentialAccess
) {
629 while (NextRow ()) {}
631 isResultRead
= false;
637 TdsPacketSubType subType
;
640 bool outputParams
= false;
643 subType
= ProcessSubPacket ();
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
) {
659 case TdsPacketSubType
.TableName
:
662 done
= (peek
!= (byte) TdsPacketSubType
.ColumnDetail
);
664 case TdsPacketSubType
.ColumnDetail
:
676 public bool NextRow ()
678 if (SequentialAccess
) {
685 TdsPacketSubType subType
;
690 subType
= ProcessSubPacket ();
692 case TdsPacketSubType
.Row
:
696 case TdsPacketSubType
.Done
:
697 case TdsPacketSubType
.DoneProc
:
698 case TdsPacketSubType
.DoneInProc
:
708 public virtual string Prepare (string sql
, TdsMetaParameterCollection parameters
)
710 throw new NotSupportedException ();
713 public void SkipToEnd ()
716 while (NextResult ()) { /* DO NOTHING */ }
717 } catch (IOException ex
) {
719 throw new TdsInternalException ("Server closed the connection.", ex
);
723 public virtual void Unprepare (string statementId
)
725 throw new NotSupportedException ();
728 #endregion // Public Methods
730 #region // Private Methods
732 [MonoTODO ("Is cancel enough, or do we need to drop the connection?")]
733 protected void CheckForData (int timeout
)
735 if (timeout
> 0 && !comm
.Poll (timeout
, SelectMode
.SelectRead
)) {
737 throw CreateTimeoutException (dataSource
, "CheckForData()");
741 protected TdsInternalInfoMessageEventArgs
CreateTdsInfoMessageEvent (TdsInternalErrorCollection errors
)
743 return new TdsInternalInfoMessageEventArgs (errors
);
746 protected TdsInternalErrorMessageEventArgs
CreateTdsErrorMessageEvent (byte theClass
, int lineNumber
, string message
, int number
, string procedure
, string server
, string source
, byte state
)
748 return new TdsInternalErrorMessageEventArgs (new TdsInternalError (theClass
, lineNumber
, message
, number
, procedure
, server
, source
, state
));
751 private Encoding
GetEncodingFromColumnCollation (int lcid
, int sortId
)
754 return TdsCharset
.GetEncodingFromSortOrder (sortId
);
756 return TdsCharset
.GetEncodingFromLCID (lcid
);
759 protected object GetColumnValue (
761 TdsColumnType
? colType
,
763 TdsColumnType colType
,
767 return GetColumnValue (colType
, outParam
, -1);
770 private object GetColumnValue (
772 TdsColumnType
? colType
,
774 TdsColumnType colType
,
776 bool outParam
, int ordinal
)
779 object element
= null;
781 int lcid
= 0, sortId
= 0;
785 throw new ArgumentNullException ("colType");
787 if (ordinal
> -1 && tdsVersion
> TdsVersion
.tds70
) {
789 lcid
= (int) columns
[ordinal
].LCID
;
790 sortId
= (int) columns
[ordinal
].SortOrder
;
792 lcid
= (int) columns
[ordinal
]["LCID"];
793 sortId
= (int) columns
[ordinal
]["SortOrder"];
798 case TdsColumnType
.IntN
:
801 element
= GetIntValue (colType
);
803 case TdsColumnType
.Int1
:
804 case TdsColumnType
.Int2
:
805 case TdsColumnType
.Int4
:
806 case TdsColumnType
.BigInt
:
807 element
= GetIntValue (colType
);
809 case TdsColumnType
.Image
:
812 element
= GetImageValue ();
814 case TdsColumnType
.Text
:
815 enc
= GetEncodingFromColumnCollation (lcid
, sortId
);
818 element
= GetTextValue (false, enc
);
820 case TdsColumnType
.NText
:
821 enc
= GetEncodingFromColumnCollation (lcid
, sortId
);
824 element
= GetTextValue (true, enc
);
826 case TdsColumnType
.Char
:
827 case TdsColumnType
.VarChar
:
828 enc
= GetEncodingFromColumnCollation (lcid
, sortId
);
831 element
= GetStringValue (colType
, false, outParam
, enc
);
833 case TdsColumnType
.BigVarBinary
:
836 len
= comm
.GetTdsShort ();
837 element
= comm
.GetBytes (len
, true);
840 case TdsColumnType.BigBinary :
843 len = comm.GetTdsShort ();
844 element = comm.GetBytes (len, true);
847 case TdsColumnType
.BigBinary
:
850 element
= GetBinaryValue ();
852 case TdsColumnType
.BigChar
:
853 case TdsColumnType
.BigVarChar
:
854 enc
= GetEncodingFromColumnCollation (lcid
, sortId
);
857 element
= GetStringValue (colType
, false, outParam
, enc
);
859 case TdsColumnType
.NChar
:
860 case TdsColumnType
.BigNVarChar
:
861 enc
= GetEncodingFromColumnCollation (lcid
, sortId
);
864 element
= GetStringValue (colType
, true, outParam
, enc
);
866 case TdsColumnType
.NVarChar
:
867 enc
= GetEncodingFromColumnCollation (lcid
, sortId
);
870 element
= GetStringValue (colType
, true, outParam
, enc
);
872 case TdsColumnType
.Real
:
873 case TdsColumnType
.Float8
:
874 element
= GetFloatValue (colType
);
876 case TdsColumnType
.FloatN
:
879 element
= GetFloatValue (colType
);
881 case TdsColumnType
.SmallMoney
:
882 case TdsColumnType
.Money
:
883 element
= GetMoneyValue (colType
);
885 case TdsColumnType
.MoneyN
:
888 element
= GetMoneyValue (colType
);
890 case TdsColumnType
.Numeric
:
891 case TdsColumnType
.Decimal
:
896 precision
= comm
.GetByte ();
897 scale
= comm
.GetByte ();
901 precision
= (byte) columns
[ordinal
].NumericPrecision
;
902 scale
= (byte) columns
[ordinal
].NumericScale
;
904 precision
= (byte) columns
[ordinal
]["NumericPrecision"];
905 scale
= (byte) columns
[ordinal
]["NumericScale"];
909 element
= GetDecimalValue (precision
, scale
);
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
);
919 case TdsColumnType
.DateTimeN
:
922 element
= GetDateTimeValue (colType
);
924 case TdsColumnType
.DateTime4
:
925 case TdsColumnType
.DateTime
:
926 element
= GetDateTimeValue (colType
);
928 case TdsColumnType
.VarBinary
:
929 case TdsColumnType
.Binary
:
932 element
= GetBinaryValue ();
934 case TdsColumnType
.BitN
:
937 if (comm
.GetByte () == 0)
938 element
= DBNull
.Value
;
940 element
= (comm
.GetByte() != 0);
942 case TdsColumnType
.Bit
:
943 int columnSize
= comm
.GetByte ();
944 element
= (columnSize
!= 0);
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
;
955 len
= comm
.GetByte () & 0xff;
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
);
970 element
= new Guid (guidBytes
);
979 private object GetBinaryValue ()
982 object result
= DBNull
.Value
;
984 if (tdsVersion
>= TdsVersion
.tds70
) {
985 len
= comm
.GetTdsShort ();
986 if (len
!= 0xffff && len
>= 0)
987 result
= comm
.GetBytes (len
, true);
989 len
= (comm
.GetByte () & 0xff);
991 result
= comm
.GetBytes (len
, true);
997 private object GetDateTimeValue (
1010 throw new ArgumentNullException ("type");
1013 case TdsColumnType
.DateTime4
:
1016 case TdsColumnType
.DateTime
:
1019 case TdsColumnType
.DateTimeN
:
1020 byte tmp
= comm
.Peek ();
1021 if (tmp
!= 0 && tmp
!= 4 && tmp
!= 8)
1023 len
= comm
.GetByte ();
1027 DateTime epoch
= new DateTime (1900, 1, 1);
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
);
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 ();
1045 result
= ((DateTime
) result
).AddMinutes ((int) minutes
);
1048 result
= DBNull
.Value
;
1055 private object GetDecimalValue (byte precision
, byte scale
)
1057 if (tdsVersion
< TdsVersion
.tds70
)
1058 return GetDecimalValueTds50 (precision
, scale
);
1060 return GetDecimalValueTds70 (precision
, scale
);
1063 private object GetDecimalValueTds70 (byte precision
, byte scale
)
1065 int[] bits
= new int[4] {0,0,0,0}
;
1067 int len
= (comm
.GetByte() & 0xff) - 1;
1069 return DBNull
.Value
;
1071 bool positive
= (comm
.GetByte () == 1);
1073 throw new OverflowException ();
1075 for (int i
= 0, index
= 0; i
< len
&& i
< 16; i
+= 4, index
+= 1)
1076 bits
[index
] = comm
.GetTdsInt ();
1079 return new TdsBigDecimal (precision
, scale
, !positive
, bits
);
1081 return new Decimal (bits
[0], bits
[1], bits
[2], !positive
, scale
);
1084 private object GetDecimalValueTds50 (byte precision
, byte scale
)
1086 int[] bits
= new int[4] {0,0,0,0}
;
1088 int len
= (comm
.GetByte() & 0xff);
1090 return DBNull
.Value
;
1092 byte[] dec_bytes
=comm
.GetBytes(len
,false);
1094 byte[] easy
=new byte[4];
1096 bool positive
= dec_bytes
[0]==1;
1099 throw new OverflowException ();
1101 for (int i
= 1, index
= 0; i
< len
&& i
< 16; i
+=
1103 for(int j
=0; j
<4; j
++)
1105 easy
[j
]=dec_bytes
[len
-
1109 if(!BitConverter
.IsLittleEndian
)
1110 easy
=comm
.Swap(easy
);
1111 bits
[index
] = BitConverter
.ToInt32(easy
,0);
1114 return new TdsBigDecimal (precision
,
1115 scale
, positive
, bits
);
1117 return new Decimal(bits
[0], bits
[1], bits
1118 [2], positive
, scale
);
1122 private object GetFloatValue (
1124 TdsColumnType
? columnType
1126 TdsColumnType columnType
1131 if (columnType
== null)
1132 throw new ArgumentNullException ("columnType");
1136 switch (columnType
) {
1137 case TdsColumnType
.Real
:
1140 case TdsColumnType
.Float8
:
1143 case TdsColumnType
.FloatN
:
1144 columnSize
= comm
.GetByte ();
1148 switch (columnSize
) {
1150 return BitConverter
.Int64BitsToDouble (comm
.GetTdsInt64 ());
1152 return BitConverter
.ToSingle (BitConverter
.GetBytes (comm
.GetTdsInt ()), 0);
1154 return DBNull
.Value
;
1158 private object GetImageValue ()
1160 byte hasValue
= comm
.GetByte ();
1163 return DBNull
.Value
;
1166 int len
= comm
.GetTdsInt ();
1169 return DBNull
.Value
;
1171 return (comm
.GetBytes (len
, true));
1174 private object GetIntValue (
1186 throw new ArgumentNullException ("type");
1189 case TdsColumnType
.BigInt
:
1192 case TdsColumnType
.IntN
:
1193 len
= comm
.GetByte ();
1195 case TdsColumnType
.Int4
:
1198 case TdsColumnType
.Int2
:
1201 case TdsColumnType
.Int1
:
1205 return DBNull
.Value
;
1210 return (comm
.GetTdsInt64 ());
1212 return (comm
.GetTdsInt ());
1214 return (comm
.GetTdsShort ());
1216 return (comm
.GetByte ());
1218 return DBNull
.Value
;
1222 private object GetMoneyValue (
1234 throw new ArgumentNullException ("type");
1237 case TdsColumnType
.SmallMoney
:
1238 case TdsColumnType
.Money4
:
1241 case TdsColumnType
.Money
:
1244 case TdsColumnType
.MoneyN
:
1245 len
= comm
.GetByte ();
1248 return DBNull
.Value
;
1253 int val
= Comm
.GetTdsInt ();
1254 bool negative
= val
< 0;
1257 return new Decimal (val
, 0, 0, negative
, 4);
1260 int hi
= Comm
.GetTdsInt ();
1261 int lo
= Comm
.GetTdsInt ();
1262 bool negative
= hi
< 0;
1268 return new Decimal (lo
, hi
, 0, negative
, 4);
1271 return DBNull
.Value
;
1275 protected object GetStringValue (
1277 TdsColumnType
? colType
,
1279 TdsColumnType colType
,
1281 bool wideChars
, bool outputParam
, Encoding encoder
)
1283 bool shortLen
= false;
1284 Encoding enc
= encoder
;
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
1292 collation
= Comm
.GetBytes (5, true);
1293 enc
= TdsCharset
.GetEncoding (collation
);
1296 shortLen
= (tdsVersion
>= TdsVersion
.tds70
) && (wideChars
|| !outputParam
);
1299 int len
= shortLen
? comm
.GetTdsShort () : (comm
.GetByte () & 0xff);
1300 return GetStringValue (wideChars
, len
, enc
);
1303 protected object GetStringValue (bool wideChars
, int len
, Encoding enc
)
1305 if (tdsVersion
< TdsVersion
.tds70
&& len
== 0)
1306 return DBNull
.Value
;
1308 else if (len
>= 0) {
1311 result
= comm
.GetString (len
/ 2, enc
);
1313 result
= comm
.GetString (len
, false, enc
);
1314 if (tdsVersion
< TdsVersion
.tds70
&& ((string) result
).Equals (" "))
1315 result
= string.Empty
;
1319 return DBNull
.Value
;
1322 protected int GetSubPacketLength ()
1324 return comm
.GetTdsShort ();
1327 private object GetTextValue (bool wideChars
, Encoding encoder
)
1329 string result
= null;
1330 byte hasValue
= comm
.GetByte ();
1333 return DBNull
.Value
;
1335 // 16 Byte TEXTPTR, 8 Byte TIMESTAMP
1338 int len
= comm
.GetTdsInt ();
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
1344 return string.Empty
;
1347 result
= comm
.GetString (len
/ 2, encoder
);
1349 result
= comm
.GetString (len
, false, encoder
);
1352 if ((byte) tdsVersion
< (byte) TdsVersion
.tds70
&& result
== " ")
1353 result
= string.Empty
;
1358 internal bool IsBlobType (TdsColumnType columnType
)
1360 return (columnType
== TdsColumnType
.Text
|| columnType
== TdsColumnType
.Image
|| columnType
== TdsColumnType
.NText
);
1363 internal bool IsLargeType (TdsColumnType columnType
)
1365 return ((byte) columnType
> 128);
1368 protected bool IsWideType (TdsColumnType columnType
)
1370 switch (columnType
) {
1371 case TdsColumnType
.NChar
:
1372 case TdsColumnType
.NText
:
1373 case TdsColumnType
.NVarChar
:
1380 internal static bool IsFixedSizeColumn (TdsColumnType columnType
)
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
:
1396 case TdsColumnType.Decimal:
1397 case TdsColumnType.Numeric:
1405 protected void LoadRow ()
1407 if (SequentialAccess
) {
1411 isResultRead
= true;
1415 currentRow
= new TdsDataRow ();
1418 foreach (TdsDataColumn column
in columns
) {
1420 object o
= GetColumnValue (column
.ColumnType
, false, i
);
1422 object o
= GetColumnValue ((TdsColumnType
)column
["ColumnType"], false, i
);
1426 outputParameters
.Add (o
);
1428 if (o
is TdsBigDecimal
&& currentRow
.BigDecimalIndex
< 0)
1429 currentRow
.BigDecimalIndex
= i
;
1434 internal static int LookupBufferSize (TdsColumnType columnType
)
1436 switch (columnType
) {
1437 case TdsColumnType
.Int1
:
1438 case TdsColumnType
.Bit
:
1440 case TdsColumnType
.Int2
:
1442 case TdsColumnType
.Int4
:
1443 case TdsColumnType
.Real
:
1444 case TdsColumnType
.DateTime4
:
1445 case TdsColumnType
.Money4
:
1446 case TdsColumnType
.SmallMoney
:
1448 case TdsColumnType
.Float8
:
1449 case TdsColumnType
.DateTime
:
1450 case TdsColumnType
.Money
:
1451 case TdsColumnType
.BigInt
:
1458 protected internal int ProcessAuthentication ()
1460 int pdu_size
= Comm
.GetTdsShort ();
1461 byte[] msg2
= Comm
.GetBytes (pdu_size
, true);
1463 Type2Message t2
= new Type2Message (msg2
);
1464 // 0x0001 Negotiate Unicode
1465 // 0x0200 Negotiate NTLM
1466 // 0x8000 Negotiate Always Sign
1468 Type3Message t3
= new Type3Message (t2
);
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
);
1475 Comm
.StartPacket (TdsPacketType
.SspAuth
); // 0x11
1476 Comm
.Append (t3
.GetBytes ());
1479 } catch (IOException ex
) {
1481 throw new TdsInternalException ("Server closed the connection.", ex
);
1483 return 1; // TDS_SUCCEED
1486 protected void ProcessColumnDetail ()
1488 int len
= GetSubPacketLength ();
1489 byte[] values
= new byte[3];
1490 int columnNameLength
;
1491 string baseColumnName
= String
.Empty
;
1494 while (position
< len
) {
1495 for (int j
= 0; j
< 3; j
+= 1)
1496 values
[j
] = comm
.GetByte ();
1499 bool isAlias
= ((values
[2] & (byte) TdsColumnStatus
.Rename
) != 0);
1501 if (tdsVersion
>= TdsVersion
.tds70
) {
1502 columnNameLength
= comm
.GetByte ();
1503 position
+= 2 * columnNameLength
+ 1;
1506 columnNameLength
= comm
.GetByte ();
1507 position
+= columnNameLength
+ 1;
1509 baseColumnName
= comm
.GetString (columnNameLength
);
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);
1516 TdsDataColumn column
= columns
[index
];
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);
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);
1535 protected abstract void ProcessColumnInfo ();
1537 protected void ProcessColumnNames ()
1539 columnNames
= new ArrayList ();
1541 int totalLength
= comm
.GetTdsShort ();
1545 while (bytesRead
< totalLength
) {
1546 int columnNameLength
= comm
.GetByte ();
1547 string columnName
= comm
.GetString (columnNameLength
);
1548 bytesRead
= bytesRead
+ 1 + columnNameLength
;
1549 columnNames
.Add (columnName
);
1554 [MonoTODO ("Make sure counting works right, especially with multiple resultsets.")]
1555 protected void ProcessEndToken (TdsPacketSubType type
)
1557 byte status
= Comm
.GetByte ();
1559 byte op
= comm
.GetByte ();
1562 int rowCount
= comm
.GetTdsInt ();
1563 bool validRowCount
= IsValidRowCount (status
,op
);
1564 moreResults
= ((status
& 0x01) != 0);
1565 bool cancelled
= ((status
& 0x20) != 0);
1568 case TdsPacketSubType
.DoneProc
:
1570 goto case TdsPacketSubType
.Done
;
1571 case TdsPacketSubType
.Done
:
1572 case TdsPacketSubType
.DoneInProc
:
1573 if (validRowCount
) {
1574 if (recordsAffected
== -1)
1575 recordsAffected
= rowCount
;
1577 recordsAffected
+= rowCount
;
1583 queryInProgress
= false;
1585 cancelsProcessed
+= 1;
1586 if (messages
.Count
> 0 && !moreResults
)
1587 OnTdsInfoMessage (CreateTdsInfoMessageEvent (messages
));
1590 protected void ProcessEnvironmentChange ()
1592 // VARADHAN: TDS 8 Debugging
1593 //Console.WriteLine ("In ProcessEnvironmentChange... entry");
1594 int len
= GetSubPacketLength ();
1595 TdsEnvPacketSubType type
= (TdsEnvPacketSubType
) comm
.GetByte ();
1599 case TdsEnvPacketSubType
.BlockSize
:
1601 cLen
= comm
.GetByte ();
1602 blockSize
= comm
.GetString (cLen
);
1604 if (tdsVersion
>= TdsVersion
.tds70
)
1605 comm
.Skip (len
- 2 - cLen
* 2);
1607 comm
.Skip (len
- 2 - cLen
);
1609 packetSize
= Int32
.Parse (blockSize
);
1610 comm
.ResizeOutBuf (packetSize
);
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);
1619 SetCharset (comm
.GetString (cLen
));
1620 comm
.Skip (len
- 2 - cLen
);
1624 case TdsEnvPacketSubType
.Locale
:
1625 cLen
= comm
.GetByte ();
1627 if (tdsVersion
>= TdsVersion
.tds70
) {
1628 lcid
= (int) Convert
.ChangeType (comm
.GetString (cLen
), typeof (int));
1629 comm
.Skip (len
- 2 - cLen
* 2);
1632 lcid
= (int) Convert
.ChangeType (comm
.GetString (cLen
), typeof (int));
1633 comm
.Skip (len
- 2 - cLen
);
1635 locale
= new CultureInfo (lcid
);
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
;
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
));
1656 comm
.Skip (len
- 1);
1659 // VARADHAN: TDS 8 Debugging
1660 //Console.WriteLine ("In ProcessEnvironmentChange... exit");
1663 protected void ProcessLoginAck ()
1665 uint srvVersion
= 0;
1666 GetSubPacketLength ();
1668 //Console.WriteLine ("ProcessLoginAck: B4 tdsVersion:{0}", tdsVersion);
1669 // Valid only for a Login7 request
1670 if (tdsVersion
>= TdsVersion
.tds70
) {
1672 srvVersion
= (uint)comm
.GetTdsInt ();
1674 //Console.WriteLine ("srvVersion: {0}", srvVersion);
1675 switch (srvVersion
) {
1677 tdsVersion
= TdsVersion
.tds70
;
1680 tdsVersion
= TdsVersion
.tds80
;
1683 tdsVersion
= TdsVersion
.tds81
;
1686 tdsVersion
= TdsVersion
.tds90
;
1689 //Console.WriteLine ("ProcessLoginAck: after tdsVersion:{0}", tdsVersion);
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"));
1701 short nameLength
= comm
.GetByte ();
1702 databaseProductName
= comm
.GetString (nameLength
);
1704 databaseMajorVersion
= comm
.GetByte ();
1705 databaseProductVersion
= String
.Format ("{0}.{1}", databaseMajorVersion
, comm
.GetByte ());
1709 if (databaseProductName
.Length
> 1 && -1 != databaseProductName
.IndexOf ('\0')) {
1710 int last
= databaseProductName
.IndexOf ('\0');
1711 databaseProductName
= databaseProductName
.Substring (0, last
);
1715 //Console.WriteLine ("databaseProductVersion:{0}", databaseProductVersion);
1718 protected void OnTdsErrorMessage (TdsInternalErrorMessageEventArgs e
)
1720 if (TdsErrorMessage
!= null)
1721 TdsErrorMessage (this, e
);
1724 protected void OnTdsInfoMessage (TdsInternalInfoMessageEventArgs e
)
1726 if (TdsInfoMessage
!= null)
1727 TdsInfoMessage (this, e
);
1731 protected void ProcessMessage (TdsPacketSubType subType
)
1733 GetSubPacketLength ();
1735 int number
= comm
.GetTdsInt ();
1736 byte state
= comm
.GetByte ();
1737 byte theClass
= comm
.GetByte ();
1743 bool isError
= false;
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
1751 isError
= (subType
== TdsPacketSubType
.Error
);
1753 message
= comm
.GetString (comm
.GetTdsShort ());
1754 server
= comm
.GetString (comm
.GetByte ());
1755 procedure
= comm
.GetString (comm
.GetByte ());
1756 lineNumber
= comm
.GetByte ();
1758 source
= String
.Empty
; // FIXME
1761 OnTdsErrorMessage (CreateTdsErrorMessageEvent (theClass
, lineNumber
, message
, number
, procedure
, server
, source
, state
));
1763 messages
.Add (new TdsInternalError (theClass
, lineNumber
, message
, number
, procedure
, server
, source
, state
));
1766 protected virtual void ProcessOutputParam ()
1768 GetSubPacketLength ();
1769 /*string paramName = */comm
.GetString (comm
.GetByte () & 0xff);
1772 TdsColumnType colType
= (TdsColumnType
) comm
.GetByte ();
1773 object value = GetColumnValue (colType
, true);
1774 outputParameters
.Add (value);
1777 protected void ProcessDynamic ()
1780 /*byte type =*/ Comm
.GetByte ();
1781 /*byte status =*/ Comm
.GetByte ();
1782 /*string id =*/ Comm
.GetString (Comm
.GetByte ());
1785 protected virtual TdsPacketSubType
ProcessSubPacket ()
1787 // VARADHAN: TDS 8 Debugging
1788 // Console.WriteLine ("In ProcessSubPacket... entry");
1790 TdsPacketSubType subType
= (TdsPacketSubType
) comm
.GetByte ();
1792 // VARADHAN: TDS 8 Debugging
1793 //Console.WriteLine ("Subpacket type: {0}", subType);
1795 case TdsPacketSubType
.Dynamic2
:
1796 comm
.Skip (comm
.GetTdsInt ());
1798 case TdsPacketSubType
.AltName
:
1799 case TdsPacketSubType
.AltFormat
:
1800 case TdsPacketSubType
.Capability
:
1801 case TdsPacketSubType
.ParamFormat
:
1802 comm
.Skip (comm
.GetTdsShort ());
1804 case TdsPacketSubType
.Dynamic
:
1807 case TdsPacketSubType
.EnvironmentChange
:
1808 ProcessEnvironmentChange ();
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
);
1815 case TdsPacketSubType
.Param
:
1816 ProcessOutputParam ();
1818 case TdsPacketSubType
.LoginAck
:
1821 case TdsPacketSubType
.Authentication
: // TDS 7.0
1822 ProcessAuthentication ();
1824 case TdsPacketSubType
.ReturnStatus
:
1825 ProcessReturnStatus ();
1827 case TdsPacketSubType
.ProcId
:
1830 case TdsPacketSubType
.Done
:
1831 case TdsPacketSubType
.DoneProc
:
1832 case TdsPacketSubType
.DoneInProc
:
1833 ProcessEndToken (subType
);
1835 case TdsPacketSubType
.ColumnName
:
1837 ProcessColumnNames ();
1839 case TdsPacketSubType
.ColumnInfo
: // TDS 4.2
1840 case TdsPacketSubType
.ColumnMetadata
: // TDS 7.0
1841 case TdsPacketSubType
.RowFormat
: // TDS 5.0
1843 ProcessColumnInfo ();
1845 case TdsPacketSubType
.ColumnDetail
:
1846 ProcessColumnDetail ();
1848 case TdsPacketSubType
.TableName
:
1849 ProcessTableName ();
1851 case TdsPacketSubType
.ColumnOrder
:
1852 comm
.Skip (comm
.GetTdsShort ());
1854 case TdsPacketSubType
.Control
:
1855 comm
.Skip (comm
.GetTdsShort ());
1857 case TdsPacketSubType
.Row
:
1862 // VARADHAN: TDS 8 Debugging
1863 //Console.WriteLine ("In ProcessSubPacket... exit");
1867 protected void ProcessTableName ()
1869 tableNames
= new ArrayList ();
1870 int totalLength
= comm
.GetTdsShort ();
1874 while (position
< totalLength
) {
1875 if (tdsVersion
>= TdsVersion
.tds70
) {
1876 len
= comm
.GetTdsShort ();
1877 position
+= 2 * (len
+ 1);
1880 len
= comm
.GetByte ();
1881 position
+= len
+ 1;
1883 tableNames
.Add (comm
.GetString (len
));
1887 protected void SetCharset (Encoding encoder
)
1889 comm
.Encoder
= encoder
;
1892 protected void SetCharset (string charset
)
1894 if (charset
== null || charset
.Length
> 30)
1897 if (this.charset
!= null && this.charset
== charset
)
1900 if (charset
.StartsWith ("cp")) {
1901 encoder
= Encoding
.GetEncoding (Int32
.Parse (charset
.Substring (2)));
1902 this.charset
= charset
;
1905 encoder
= Encoding
.GetEncoding ("iso-8859-1");
1906 this.charset
= "iso_1";
1908 SetCharset (encoder
);
1911 protected void SetLanguage (string language
)
1913 if (language
== null || language
.Length
> 30)
1914 language
= "us_english";
1916 this.language
= language
;
1919 protected virtual void ProcessReturnStatus ()
1924 public static string GetPlainPassword(SecureString secPass
)
1926 IntPtr plainString
= IntPtr
.Zero
;
1929 plainString
= Marshal
.SecureStringToGlobalAllocUnicode(secPass
);
1930 return Marshal
.PtrToStringUni(plainString
);
1934 Marshal
.ZeroFreeGlobalAllocUnicode(plainString
);
1938 #endregion // Private Methods
1941 #region asynchronous methods
1942 protected IAsyncResult
BeginExecuteQueryInternal (string sql
, bool wantResults
,
1943 AsyncCallback callback
, object state
)
1947 TdsAsyncResult ar
= new TdsAsyncResult (callback
, state
);
1948 ar
.TdsAsyncState
.WantResults
= wantResults
;
1950 Comm
.StartPacket (TdsPacketType
.Query
);
1954 Comm
.BeginReadPacket (new AsyncCallback(OnBeginExecuteQueryCallback
),
1956 } catch (IOException ex
) {
1958 throw new TdsInternalException ("Server closed the connection.", ex
);
1964 protected void EndExecuteQueryInternal (IAsyncResult ar
)
1966 if (!ar
.IsCompleted
)
1967 ar
.AsyncWaitHandle
.WaitOne ();
1968 TdsAsyncResult result
= (TdsAsyncResult
) ar
;
1969 if (result
.IsCompletedWithException
)
1970 throw result
.Exception
;
1973 protected void OnBeginExecuteQueryCallback (IAsyncResult ar
)
1975 TdsAsyncResult result
= (TdsAsyncResult
) ar
.AsyncState
;
1976 TdsAsyncState tdsState
= (TdsAsyncState
) result
.TdsAsyncState
;
1979 Comm
.EndReadPacket (ar
);
1980 if (!tdsState
.WantResults
)
1982 } catch (Exception e
) {
1983 result
.MarkComplete (e
);
1986 result
.MarkComplete ();
1990 public virtual IAsyncResult
BeginExecuteNonQuery (string sql
,
1991 TdsMetaParameterCollection parameters
,
1992 AsyncCallback callback
,
1995 // abstract, kept to be backward compatiable.
1996 throw new NotImplementedException ("should not be called!");
1999 public virtual void EndExecuteNonQuery (IAsyncResult ar
)
2002 throw new NotImplementedException ("should not be called!");
2005 public virtual IAsyncResult
BeginExecuteQuery (string sql
,
2006 TdsMetaParameterCollection parameters
,
2007 AsyncCallback callback
,
2010 // abstract, kept to be backward compatiable.
2011 throw new NotImplementedException ("should not be called!");
2014 public virtual void EndExecuteQuery (IAsyncResult ar
)
2017 throw new NotImplementedException ("should not be called!");
2020 public virtual IAsyncResult
BeginExecuteProcedure (string prolog
,
2024 TdsMetaParameterCollection parameters
,
2025 AsyncCallback callback
,
2028 throw new NotImplementedException ("should not be called!");
2031 public virtual void EndExecuteProcedure (IAsyncResult ar
)
2034 throw new NotImplementedException ("should not be called!");
2037 public void WaitFor (IAsyncResult ar
)
2039 if (! ar
.IsCompleted
)
2040 ar
.AsyncWaitHandle
.WaitOne ();
2043 public void CheckAndThrowException (IAsyncResult ar
)
2045 TdsAsyncResult result
= (TdsAsyncResult
) ar
;
2046 if (result
.IsCompleted
&& result
.IsCompletedWithException
)
2047 throw result
.Exception
;
2050 #endregion // asynchronous methods