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