Add SqlCredential support -
[mono.git] / mcs / class / Mono.Data.Tds / Mono.Data.Tds.Protocol / Tds42.cs
1 //
2 // Mono.Data.Tds.Protocol.Tds42.cs
3 //
4 // Author:
5 //   Tim Coleman (tim@timcoleman.com)
6 //
7 // Copyright (C) 2002 Tim Coleman
8 //
9
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System;
32 using System.Security;
33
34 namespace Mono.Data.Tds.Protocol {
35         public sealed class Tds42 : Tds
36         {
37                 #region Fields
38
39                 public static readonly TdsVersion Version = TdsVersion.tds42;
40
41                 #endregion // Fields
42
43                 #region Constructors
44
45                 public Tds42 (string server, int port)
46                         : this (server, port, 512, 15)
47                 {
48                 }
49
50                 public Tds42 (string server, int port, int packetSize, int timeout)
51                         : base (server, port, packetSize, timeout, Version)
52                 {
53                 }
54
55                 #endregion // Constructors
56
57                 #region Methods
58
59                 public override bool Connect (TdsConnectionParameters connectionParameters)
60                 {
61                         if (IsConnected)
62                                 throw new InvalidOperationException ("The connection is already open.");
63
64                         SetCharset (connectionParameters.Charset);
65                         SetLanguage (connectionParameters.Language);
66
67                         byte pad = (byte) 0;
68                         byte[] empty = new byte[0];
69
70                         Comm.StartPacket (TdsPacketType.Logon);
71
72                         // hostname (offset 0)
73                         byte[] tmp = Comm.Append (connectionParameters.Hostname, 30, pad);
74                         Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
75
76                         // username (offset 31 0x1f)
77                         tmp = Comm.Append (connectionParameters.User, 30, pad);
78                         Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
79
80                         // password (offset 62 0x3e)
81                         tmp = Comm.Append (GetPlainPassword(connectionParameters.Password), 30, pad);
82                         Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
83
84                         // hostproc (offset 93 0x5d)
85                         Comm.Append ("00000116", 8, pad);
86
87                         // unused (offset 109 0x6d)
88                         Comm.Append (empty, (30-14), pad);
89
90                         // apptype 
91                         Comm.Append ((byte) 0x0);
92                         Comm.Append ((byte) 0xa0);
93                         Comm.Append ((byte) 0x24);
94                         Comm.Append ((byte) 0xcc);
95                         Comm.Append ((byte) 0x50);
96                         Comm.Append ((byte) 0x12);
97
98                         // hostproc length 
99                         Comm.Append ((byte) 8);
100
101                         // Byte order of 2 byte ints
102                         // 2 = <MSB, LSB>, 3 = <LSB, MSB>
103                         Comm.Append ((byte) 3);
104
105                         // Byte order of 4 byte ints
106                         // 0 = <MSB, LSB>, 1 = <LSB, MSB>
107                         Comm.Append ((byte) 1);
108
109                         // Character representation
110                         // (6 = ASCII, 7 = EBCDIC)
111                         Comm.Append ((byte) 6);
112
113                         // Eight byte floating point representation
114                         // 4 = IEEE <MSB, ..., LSB>
115                         // 5 = VAX 'D'
116                         // 10 = IEEE <LSB, ..., MSB>
117                         // 11 = ND5000
118                         Comm.Append ((byte) 10);
119
120                         // Eight byte date format
121                         // 8 = <MSB, ..., LSB>
122                         Comm.Append ((byte) 9);
123                         
124                         // notify of use db
125                         Comm.Append ((byte) 1);
126
127                         // disallow dump/load and bulk insert
128                         Comm.Append ((byte) 1);
129
130                         // sql interface type
131                         Comm.Append ((byte) 0);
132
133                         // type of network connection
134                         Comm.Append ((byte) 0);
135
136
137                         // spare [7]
138                         Comm.Append (empty, 7, pad);
139                         // appname
140                         tmp = Comm.Append (connectionParameters.ApplicationName, 30, pad);
141                         Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
142
143                         // server name
144                         tmp = Comm.Append (DataSource, 30, pad);
145                         Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
146
147                         // remote passwords
148                         Comm.Append (empty, 2, pad);
149                         tmp = Comm.Append (GetPlainPassword(connectionParameters.Password), 253, pad);
150                         Comm.Append ((byte) (tmp.Length < 253 ? tmp.Length + 2 : 253 + 2));
151
152                         // tds version
153                         Comm.Append ((byte) (((byte) Version) / 10));
154                         Comm.Append ((byte) (((byte) Version) % 10));
155                         Comm.Append ((byte) 0);
156                         Comm.Append ((byte) 0);
157
158                         // prog name
159                         tmp = Comm.Append (connectionParameters.ProgName, 10, pad);
160                         Comm.Append ((byte) (tmp.Length < 10 ? tmp.Length : 10));
161
162                         // prog version
163                         Comm.Append ((byte) 6);
164
165                         // Tell the server we can handle SQLServer version 6
166                         Comm.Append ((byte) 0);
167
168                         // Send zero to tell the server we can't handle any other version
169                         Comm.Append ((byte) 0);
170                         Comm.Append ((byte) 0);
171
172                         // auto convert short
173                         Comm.Append ((byte) 0);
174
175                         // type of flt4
176                         Comm.Append ((byte) 0x0d);
177
178                         // type of date4
179                         Comm.Append ((byte) 0x11);
180
181                         // language
182                         tmp = Comm.Append (Language, 30, pad);
183                         Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
184
185                         // notify on lang change
186                         Comm.Append ((byte) 1);
187
188                         // security label hierarchy
189                         Comm.Append ((short) 0);
190
191                         // security components
192                         Comm.Append (empty, 8, pad);
193
194                         // security spare
195                         Comm.Append ((short) 0);
196
197                         // security login role
198                         Comm.Append ((byte) 0);
199
200                         // charset
201                         tmp = Comm.Append (Charset, 30, pad);
202                         Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
203
204                         // notify on charset change
205                         Comm.Append ((byte) 1);
206
207                         // length of tds packets
208                         tmp = Comm.Append (PacketSize.ToString (), 6, pad);
209                         Comm.Append ((byte) 3);
210
211                         // pad out to a longword
212                         Comm.Append (empty, 8, pad);
213
214                         Comm.SendPacket ();
215
216                         MoreResults = true;
217                         SkipToEnd ();
218
219                         return IsConnected;
220                 }
221
222                 protected override void ProcessColumnInfo ()
223                 {
224                         byte precision;
225                         byte scale;
226                         int totalLength = Comm.GetTdsShort ();
227                         int bytesRead = 0;
228
229                         while (bytesRead < totalLength) {
230                                 scale = 0;
231                                 precision = 0;
232
233                                 int bufLength = -1;
234                                 byte[] flagData = new byte[4];
235                                 for (int i = 0; i < 4; i += 1) {
236                                         flagData[i] = Comm.GetByte ();
237                                         bytesRead += 1;
238                                 }
239                                 bool nullable = (flagData[2] & 0x01) > 0;
240                                 //bool caseSensitive = (flagData[2] & 0x02) > 0;
241                                 bool writable = (flagData[2] & 0x0c) > 0;
242                                 //bool autoIncrement = (flagData[2] & 0x10) > 0;
243
244                                 string tableName = String.Empty;
245                                 TdsColumnType columnType = (TdsColumnType) Comm.GetByte ();
246
247                                 bytesRead += 1;
248
249                                 if (columnType == TdsColumnType.Text || columnType == TdsColumnType.Image) {
250                                         Comm.Skip (4);
251                                         bytesRead += 4;
252
253                                         int tableNameLength = Comm.GetTdsShort ();
254                                         bytesRead += 2;
255                                         tableName = Comm.GetString (tableNameLength);
256                                         bytesRead += tableNameLength;
257                                         bufLength = 2 << 31 - 1;
258                                 }
259                                 else if (columnType == TdsColumnType.Decimal || columnType == TdsColumnType.Numeric) {
260                                         bufLength = Comm.GetByte ();
261                                         bytesRead += 1;
262                                         precision = Comm.GetByte ();
263                                         bytesRead += 1;
264                                         scale = Comm.GetByte ();
265                                         bytesRead += 1;
266                                 }
267                                 else if (IsFixedSizeColumn (columnType))
268                                         bufLength = LookupBufferSize (columnType);
269                                 else {
270                                         bufLength = (int) Comm.GetByte () & 0xff;
271                                         bytesRead += 1;
272                                 }
273
274                                 TdsDataColumn col = new TdsDataColumn ();
275                                 int index = Columns.Add (col);
276 #if NET_2_0
277                                 col.ColumnType = columnType;
278                                 col.ColumnSize = bufLength;
279                                 col.ColumnName = ColumnNames[index] as string;
280                                 col.NumericPrecision = precision;
281                                 col.NumericScale = scale;
282                                 col.IsReadOnly = !writable;
283                                 col.BaseTableName = tableName;
284                                 col.AllowDBNull = nullable;
285 #else
286                                 col["ColumnType"] = columnType;
287                                 col["ColumnSize"] = bufLength;
288                                 col["ColumnName"] = ColumnNames[index];
289                                 col["NumericPrecision"] = precision;
290                                 col["NumericScale"] = scale;
291                                 col["IsReadOnly"] = !writable;
292                                 col["BaseTableName"] = tableName;
293                                 col["AllowDBNull"] = nullable;
294 #endif
295                         }
296                 }
297
298                 #endregion // Methods
299         }
300 }