2002-11-30 Tim Coleman <tim@timcoleman.com>
[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 using System;
11
12 namespace Mono.Data.Tds.Protocol {
13         public 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                         MoreResults = true;
195                         SkipToEnd ();
196
197                         return IsConnected;
198                 }
199
200                 protected override TdsPacketColumnInfoResult ProcessColumnInfo ()
201                 {
202                         byte precision;
203                         byte scale;
204                         int totalLength = Comm.GetTdsShort ();
205                         int bytesRead = 0;
206
207                         TdsPacketColumnInfoResult result = new TdsPacketColumnInfoResult ();
208
209                         while (bytesRead < totalLength) {
210                                 scale = 0;
211                                 precision = 0;
212
213                                 int bufLength = -1;
214                                 byte[] flagData = new byte[4];
215                                 for (int i = 0; i < 4; i += 1) {
216                                         flagData[i] = Comm.GetByte ();
217                                         bytesRead += 1;
218                                 }
219                                 bool nullable = (flagData[2] & 0x01) > 0;
220                                 bool caseSensitive = (flagData[2] & 0x02) > 0;
221                                 bool writable = (flagData[2] & 0x0c) > 0;
222                                 bool autoIncrement = (flagData[2] & 0x10) > 0;
223
224                                 string tableName = String.Empty;
225                                 TdsColumnType columnType = (TdsColumnType) Comm.GetByte ();
226
227                                 bytesRead += 1;
228
229                                 if (columnType == TdsColumnType.Text || columnType == TdsColumnType.Image) {
230                                         Comm.Skip (4);
231                                         bytesRead += 4;
232
233                                         int tableNameLength = Comm.GetTdsShort ();
234                                         bytesRead += 2;
235                                         tableName = Comm.GetString (tableNameLength);
236                                         bytesRead += tableNameLength;
237                                         bufLength = 2 << 31 - 1;
238                                 }
239                                 else if (columnType == TdsColumnType.Decimal || columnType == TdsColumnType.Numeric) {
240                                         bufLength = Comm.GetByte ();
241                                         bytesRead += 1;
242                                         precision = Comm.GetByte ();
243                                         bytesRead += 1;
244                                         scale = Comm.GetByte ();
245                                         bytesRead += 1;
246                                 }
247                                 else if (IsFixedSizeColumn (columnType))
248                                         bufLength = LookupBufferSize (columnType);
249                                 else {
250                                         bufLength = (int) Comm.GetByte () & 0xff;
251                                         bytesRead += 1;
252                                 }
253
254                                 int index = result.Add (new TdsSchemaInfo ());
255                                 result[index]["NumericPrecision"] = precision;
256                                 result[index]["NumericScale"] = scale;
257                                 result[index]["ColumnSize"] = bufLength;
258                                 result[index]["ColumnName"] = ColumnNames[index];
259                                 result[index]["ColumnType"] = columnType;
260                                 result[index]["BaseTableName"] = tableName;
261                                 result[index]["AllowDBNull"] = nullable;
262                                 result[index]["IsReadOnly"] = !writable;
263                         }
264
265                         return result;
266                 }
267
268                 #endregion // Methods
269         }
270 }