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