2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[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
33 namespace Mono.Data.Tds.Protocol {
34         public class Tds42 : Tds
35         {
36                 #region Fields
37
38                 public static readonly TdsVersion Version = TdsVersion.tds42;
39
40                 #endregion // Fields
41
42                 #region Constructors
43
44                 public Tds42 (string server, int port)
45                         : this (server, port, 512, 15)
46                 {
47                 }
48
49                 public Tds42 (string server, int port, int packetSize, int timeout)
50                         : base (server, port, packetSize, timeout, Version)
51                 {
52                 }
53
54                 #endregion // Constructors
55
56                 #region Methods
57
58                 public override bool Connect (TdsConnectionParameters connectionParameters)
59                 {
60                         if (IsConnected)
61                                 throw new InvalidOperationException ("The connection is already open.");
62
63                         SetCharset (connectionParameters.Charset);
64                         SetLanguage (connectionParameters.Language);
65
66                         byte pad = (byte) 0;
67                         byte[] empty = new byte[0];
68
69                         Comm.StartPacket (TdsPacketType.Logon);
70
71                         // hostname (offset 0)
72                         byte[] tmp = Comm.Append (connectionParameters.Hostname, 30, pad);
73                         Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
74
75                         // username (offset 31 0x1f)
76                         tmp = Comm.Append (connectionParameters.User, 30, pad);
77                         Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
78
79                         // password (offset 62 0x3e)
80                         tmp = Comm.Append (connectionParameters.Password, 30, pad);
81                         Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
82
83                         // hostproc (offset 93 0x5d)
84                         Comm.Append ("00000116", 8, pad);
85
86                         // unused (offset 109 0x6d)
87                         Comm.Append (empty, (30-14), pad);
88
89                         // apptype 
90                         Comm.Append ((byte) 0x0);
91                         Comm.Append ((byte) 0xa0);
92                         Comm.Append ((byte) 0x24);
93                         Comm.Append ((byte) 0xcc);
94                         Comm.Append ((byte) 0x50);
95                         Comm.Append ((byte) 0x12);
96
97                         // hostproc length 
98                         Comm.Append ((byte) 8);
99
100                         // Byte order of 2 byte ints
101                         // 2 = <MSB, LSB>, 3 = <LSB, MSB>
102                         Comm.Append ((byte) 3);
103
104                         // Byte order of 4 byte ints
105                         // 0 = <MSB, LSB>, 1 = <LSB, MSB>
106                         Comm.Append ((byte) 1);
107
108                         // Character representation
109                         // (6 = ASCII, 7 = EBCDIC)
110                         Comm.Append ((byte) 6);
111
112                         // Eight byte floating point representation
113                         // 4 = IEEE <MSB, ..., LSB>
114                         // 5 = VAX 'D'
115                         // 10 = IEEE <LSB, ..., MSB>
116                         // 11 = ND5000
117                         Comm.Append ((byte) 10);
118
119                         // Eight byte date format
120                         // 8 = <MSB, ..., LSB>
121                         Comm.Append ((byte) 9);
122                         
123                         // notify of use db
124                         Comm.Append ((byte) 1);
125
126                         // disallow dump/load and bulk insert
127                         Comm.Append ((byte) 1);
128
129                         // sql interface type
130                         Comm.Append ((byte) 0);
131
132                         // type of network connection
133                         Comm.Append ((byte) 0);
134
135
136                         // spare [7]
137                         Comm.Append (empty, 7, pad);
138                         // appname
139                         tmp = Comm.Append (connectionParameters.ApplicationName, 30, pad);
140                         Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
141
142                         // server name
143                         tmp = Comm.Append (DataSource, 30, pad);
144                         Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
145
146                         // remote passwords
147                         Comm.Append (empty, 2, pad);
148                         tmp = Comm.Append (connectionParameters.Password, 253, pad);
149                         Comm.Append ((byte) (tmp.Length < 253 ? tmp.Length + 2 : 253 + 2));
150
151                         // tds version
152                         Comm.Append ((byte) (((byte) Version) / 10));
153                         Comm.Append ((byte) (((byte) Version) % 10));
154                         Comm.Append ((byte) 0);
155                         Comm.Append ((byte) 0);
156
157                         // prog name
158                         tmp = Comm.Append (connectionParameters.ProgName, 10, pad);
159                         Comm.Append ((byte) (tmp.Length < 10 ? tmp.Length : 10));
160
161                         // prog version
162                         Comm.Append ((byte) 6);
163
164                         // Tell the server we can handle SQLServer version 6
165                         Comm.Append ((byte) 0);
166
167                         // Send zero to tell the server we can't handle any other version
168                         Comm.Append ((byte) 0);
169                         Comm.Append ((byte) 0);
170
171                         // auto convert short
172                         Comm.Append ((byte) 0);
173
174                         // type of flt4
175                         Comm.Append ((byte) 0x0d);
176
177                         // type of date4
178                         Comm.Append ((byte) 0x11);
179
180                         // language
181                         tmp = Comm.Append (Language, 30, pad);
182                         Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
183
184                         // notify on lang change
185                         Comm.Append ((byte) 1);
186
187                         // security label hierarchy
188                         Comm.Append ((short) 0);
189
190                         // security components
191                         Comm.Append (empty, 8, pad);
192
193                         // security spare
194                         Comm.Append ((short) 0);
195
196                         // security login role
197                         Comm.Append ((byte) 0);
198
199                         // charset
200                         tmp = Comm.Append (Charset, 30, pad);
201                         Comm.Append ((byte) (tmp.Length < 30 ? tmp.Length : 30));
202
203                         // notify on charset change
204                         Comm.Append ((byte) 1);
205
206                         // length of tds packets
207                         tmp = Comm.Append (PacketSize.ToString (), 6, pad);
208                         Comm.Append ((byte) 3);
209
210                         // pad out to a longword
211                         Comm.Append (empty, 8, pad);
212
213                         Comm.SendPacket ();
214
215                         MoreResults = true;
216                         SkipToEnd ();
217
218                         return IsConnected;
219                 }
220
221                 protected override TdsDataColumnCollection ProcessColumnInfo ()
222                 {
223                         byte precision;
224                         byte scale;
225                         int totalLength = Comm.GetTdsShort ();
226                         int bytesRead = 0;
227
228                         TdsDataColumnCollection result = new TdsDataColumnCollection ();
229
230                         while (bytesRead < totalLength) {
231                                 scale = 0;
232                                 precision = 0;
233
234                                 int bufLength = -1;
235                                 byte[] flagData = new byte[4];
236                                 for (int i = 0; i < 4; i += 1) {
237                                         flagData[i] = Comm.GetByte ();
238                                         bytesRead += 1;
239                                 }
240                                 bool nullable = (flagData[2] & 0x01) > 0;
241                                 bool caseSensitive = (flagData[2] & 0x02) > 0;
242                                 bool writable = (flagData[2] & 0x0c) > 0;
243                                 bool autoIncrement = (flagData[2] & 0x10) > 0;
244
245                                 string tableName = String.Empty;
246                                 TdsColumnType columnType = (TdsColumnType) Comm.GetByte ();
247
248                                 bytesRead += 1;
249
250                                 if (columnType == TdsColumnType.Text || columnType == TdsColumnType.Image) {
251                                         Comm.Skip (4);
252                                         bytesRead += 4;
253
254                                         int tableNameLength = Comm.GetTdsShort ();
255                                         bytesRead += 2;
256                                         tableName = Comm.GetString (tableNameLength);
257                                         bytesRead += tableNameLength;
258                                         bufLength = 2 << 31 - 1;
259                                 }
260                                 else if (columnType == TdsColumnType.Decimal || columnType == TdsColumnType.Numeric) {
261                                         bufLength = Comm.GetByte ();
262                                         bytesRead += 1;
263                                         precision = Comm.GetByte ();
264                                         bytesRead += 1;
265                                         scale = Comm.GetByte ();
266                                         bytesRead += 1;
267                                 }
268                                 else if (IsFixedSizeColumn (columnType))
269                                         bufLength = LookupBufferSize (columnType);
270                                 else {
271                                         bufLength = (int) Comm.GetByte () & 0xff;
272                                         bytesRead += 1;
273                                 }
274
275                                 int index = result.Add (new TdsDataColumn ());
276                                 result[index]["NumericPrecision"] = precision;
277                                 result[index]["NumericScale"] = scale;
278                                 result[index]["ColumnSize"] = bufLength;
279                                 result[index]["ColumnName"] = ColumnNames[index];
280                                 result[index]["ColumnType"] = columnType;
281                                 result[index]["BaseTableName"] = tableName;
282                                 result[index]["AllowDBNull"] = nullable;
283                                 result[index]["IsReadOnly"] = !writable;
284                         }
285
286                         return result;
287                 }
288
289                 #endregion // Methods
290         }
291 }