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