2005-06-05 Peter Bartok <pbartok@novell.com>
[mono.git] / mcs / class / System.Data / System.Data.Odbc / OdbcTypeConverter.cs
1 //
2 // System.Data.Odbc.OdbcTypeConverter
3 //
4 // Author:
5 //   Sureshkumar T <tsureshkumar@novell.com>
6 //
7
8 //
9 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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 //
32 // * Type mapping between various odbc driver types.
33 // For further infomartion between these mapping visit following msdn site
34 //
35 //      * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/
36 //        odbcc_data_types.asp
37 //      * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/
38 //        odbcconverting_data_from_c_to_sql_data_types.asp
39 //      * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/
40 //        odbcconverting_data_from_sql_to_c_data_types.asp
41 //      * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/odbc/htm/
42 //        odbcparameter_data_types.asp
43 //      * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/
44 //        html/frlrfsystemdataodbcodbctypeclasstopic.asp
45 //
46 //
47 // OdbcType             SQL_C_TYPE              SQL_TYPE
48 // ===================================================================
49 // BigInt               SQL_C_TYPE.SBIGINT      SQL_TYPE.BIGINT     
50 // Binary               SQL_C_TYPE.BINARY       SQL_TYPE.BINARY     
51 // Bit                  SQL_C_TYPE.BIT          SQL_TYPE.BIT        
52 // Char                 SQL_C_TYPE.CHAR         SQL_TYPE.CHAR       
53 // Date                 SQL_C_TYPE.TYPE_DATE    SQL_TYPE.TYPE_DATE  
54 // DateTime             SQL_C_TYPE.TIMESTAMP    SQL_TYPE.TIMESTAMP  
55 // Decimal              SQL_C_TYPE.NUMERIC      SQL_TYPE.NUMERIC    
56 // Double               SQL_C_TYPE.DOUBLE       SQL_TYPE.DOUBLE     
57 // Image                SQL_C_TYPE.BINARY       SQL_TYPE.BINARY     
58 // Int                  SQL_C_TYPE.LONG         SQL_TYPE.INTEGER    
59 // NChar                SQL_C_TYPE.WCHAR        SQL_TYPE.WCHAR      
60 // NText                SQL_C_TYPE.WCHAR        SQL_TYPE.WLONGVARCHAR
61 // Numeric              SQL_C_TYPE.NUMERIC      SQL_TYPE.NUMERIC    
62 // NVarChar             SQL_C_TYPE.WCHAR        SQL_TYPE.WVARCHAR   
63 // Real                 SQL_C_TYPE.FLOAT        SQL_TYPE.REAL       
64 // SignedBigInt         SQL_C_TYPE.SBIGINT      SQL_TYPE.BIGINT     
65 // SmallDateTime        SQL_C_TYPE.TIMESTAMP    SQL_TYPE.TIMESTAMP  
66 // SmallInt             SQL_C_TYPE.SHORT        SQL_TYPE.SMALLINT   
67 // Text                 SQL_C_TYPE.WCHAR        SQL_TYPE.LONGVARCHAR
68 // Time                 SQL_C_TYPE.TYPE_TIME    SQL_TYPE.TYPE_TIME  
69 // Timestamp            SQL_C_TYPE.BINARY       SQL_TYPE.BINARY     
70 // TinyInt              SQL_C_TYPE.UTINYINT     SQL_TYPE.TINYINT    
71 // UniqueIdentifier     SQL_C_TYPE.GUID         SQL_TYPE.GUID       
72 // VarBinary            SQL_C_TYPE.BINARY       SQL_TYPE.VARBINARY  
73 // VarChar              SQL_C_TYPE.WCHAR        SQL_TYPE.WVARCHAR   
74 //====================================================================
75
76
77 using System.Data;
78 using System.Collections;
79 using System.Data.Common;
80
81 namespace System.Data.Odbc
82
83         internal sealed class OdbcTypeConverter
84         {
85                 internal struct TypeMap
86                 {
87                         public const short DefaultForOdbcType   = 1;
88                         public const short DefaultForSQLCType   = 1<<1;
89                         public const short DefaultForSQLType    = 1<<2;
90                         public const short DefaultAll           = (DefaultForOdbcType |
91                                                                    DefaultForSQLCType |
92                                                                    DefaultForSQLType);
93                         public OdbcType         OdbcType;
94                         public SQL_C_TYPE       SqlCType;
95                         public SQL_TYPE         SqlType;
96                         public short            BitMask;
97
98                         public TypeMap (OdbcType odbcType, SQL_C_TYPE sqlCType, SQL_TYPE sqlType)
99                         {
100                                 OdbcType        = odbcType;
101                                 SqlType         = sqlType;
102                                 SqlCType        = sqlCType;
103                                 BitMask         = DefaultForOdbcType 
104                                         | DefaultForSQLCType
105                                         | DefaultForSQLType
106                                         ;
107                         }
108
109                         public TypeMap (OdbcType odbcType, SQL_C_TYPE sqlCType, SQL_TYPE sqlType, short defaultFlags)
110                                 : this (odbcType, sqlCType, sqlType)
111                         {
112                                 BitMask = defaultFlags;
113                         }
114                         
115                 }
116
117
118                 // FIXME: Write a binary search to make faster
119                 internal class MapCollection : CollectionBase
120                 {
121                         public TypeMap this [OdbcType odbcType]
122                         {
123                                 get {
124                                         foreach (TypeMap map in List){
125                                                 if (map.OdbcType == odbcType
126                                                     && (map.BitMask & TypeMap.DefaultForOdbcType) > 0 )
127                                                         return map;
128                                         }
129                                         throw new ArgumentException (String.Format ("Type mapping for odbc type {0} is not found", 
130                                                                                     odbcType.ToString ()
131                                                                                     )
132                                                                      );
133                                 }
134                                 set {
135                                         int i = IndexOf (odbcType);
136                                         if (i == -1)
137                                                 Add (value);
138                                         List [i] = value;
139                                 }
140                         }
141
142                         public TypeMap this [SQL_C_TYPE sqlCType]
143                         {
144                                 get {
145                                         foreach (TypeMap map in List){
146                                                 if (map.SqlCType == sqlCType
147                                                     && (map.BitMask & TypeMap.DefaultForSQLCType) > 0 )
148                                                         return map;
149                                         }
150                                         throw new ArgumentException (String.Format ("Type mapping for odbc type {0} is not found", 
151                                                                                     sqlCType.ToString ()
152                                                                                     )
153                                                                      );
154                                 }
155                                 set {
156                                         int i = IndexOf (sqlCType);
157                                         if (i == -1)
158                                                 Add (value);
159                                         List [i] = value;
160                                 }
161                                 
162                         }
163
164
165                         public TypeMap this [SQL_TYPE sqlType]
166                         {
167                                 get {
168                                         foreach (TypeMap map in List){
169                                                 if (map.SqlType == sqlType
170                                                     && (map.BitMask & TypeMap.DefaultForSQLType) > 0 )
171                                                         return map;
172                                         }
173                                         throw new ArgumentException (String.Format ("Type mapping for odbc type {0} is not found", 
174                                                                                     sqlType.ToString ()
175                                                                                     )
176                                                                      );
177                                 }
178                                 set {
179                                         int i = IndexOf (sqlType);
180                                         if (i == -1)
181                                                 Add (value);
182                                         List [i] = value;
183                                 }
184                                 
185                         }
186
187                         public TypeMap this [int index]
188                         {
189                                 get { return (TypeMap) List [index];}
190                                 set { List [index] = value;}
191                         }
192                         
193
194                         
195                         public int IndexOf (OdbcType odbcType)
196                         {
197                                 for (int i=0; i < List.Count; i++) {
198                                         TypeMap map = (TypeMap) List [i];
199                                         if (map.OdbcType == odbcType
200                                             && (map.BitMask & TypeMap.DefaultForOdbcType) > 0 )
201                                                 return i;
202                                 }
203                                 return -1;
204                         }
205                         
206                         public int IndexOf (SQL_C_TYPE sqlCType)
207                         {
208                                 for (int i=0; i < List.Count; i++) {
209                                         TypeMap map = (TypeMap) List [i];
210                                         if (map.SqlCType == sqlCType
211                                             && (map.BitMask & TypeMap.DefaultForSQLCType) > 0 )
212                                                 return i;
213                                 }
214                                 return -1;
215                         }
216
217                         public int IndexOf (SQL_TYPE sqlType)
218                         {
219                                 for (int i=0; i < List.Count; i++) {
220                                         TypeMap map = (TypeMap) List [i];
221                                         if (map.SqlType == sqlType
222                                             && (map.BitMask & TypeMap.DefaultForSQLType) > 0 )
223                                                 return i;
224                                 }
225                                 return -1;
226                         }
227
228                         public int Add (TypeMap map)
229                         {
230                                 return List.Add (map);
231                         }
232                         
233                         protected override void OnValidate (object value)
234                         {
235                                 if (value.GetType () != typeof (TypeMap))
236                                         throw new ArgumentException ("value is not of type TypeMap");
237                         }
238                         
239                 }
240                 
241
242                 private static MapCollection OdbcTypeMap;
243
244                 static OdbcTypeConverter ()
245                 {
246                         OdbcTypeMap = new MapCollection ();
247                         OdbcTypeMap.Add (new TypeMap (OdbcType.BigInt,          SQL_C_TYPE.SBIGINT,             SQL_TYPE.BIGINT     ));
248                         OdbcTypeMap.Add (new TypeMap (OdbcType.Binary,          SQL_C_TYPE.BINARY,              SQL_TYPE.BINARY     ));
249                         OdbcTypeMap.Add (new TypeMap (OdbcType.Bit,             SQL_C_TYPE.BIT,                 SQL_TYPE.BIT        ));
250                         OdbcTypeMap.Add (new TypeMap (OdbcType.Char,            SQL_C_TYPE.CHAR,                SQL_TYPE.CHAR       ));
251                         OdbcTypeMap.Add (new TypeMap (OdbcType.Date,            SQL_C_TYPE.TYPE_DATE,           SQL_TYPE.TYPE_DATE  ));
252                         OdbcTypeMap.Add (new TypeMap (OdbcType.DateTime,        SQL_C_TYPE.TIMESTAMP,           SQL_TYPE.TIMESTAMP  ));
253                         OdbcTypeMap.Add (new TypeMap (OdbcType.Decimal,         SQL_C_TYPE.NUMERIC,             SQL_TYPE.NUMERIC    , TypeMap.DefaultAll & (~TypeMap.DefaultForSQLType)));
254                         OdbcTypeMap.Add (new TypeMap (OdbcType.Double,          SQL_C_TYPE.DOUBLE,              SQL_TYPE.DOUBLE     ));
255                         OdbcTypeMap.Add (new TypeMap (OdbcType.Image,           SQL_C_TYPE.BINARY,              SQL_TYPE.BINARY     , TypeMap.DefaultAll & (~TypeMap.DefaultForSQLType)));
256                         OdbcTypeMap.Add (new TypeMap (OdbcType.Int,             SQL_C_TYPE.LONG,                SQL_TYPE.INTEGER    ));
257                         OdbcTypeMap.Add (new TypeMap (OdbcType.NChar,           SQL_C_TYPE.WCHAR,               SQL_TYPE.WCHAR      ));
258                         OdbcTypeMap.Add (new TypeMap (OdbcType.NText,           SQL_C_TYPE.WCHAR,               SQL_TYPE.WLONGVARCHAR));
259                         OdbcTypeMap.Add (new TypeMap (OdbcType.Numeric,         SQL_C_TYPE.NUMERIC,             SQL_TYPE.NUMERIC    ));
260                         OdbcTypeMap.Add (new TypeMap (OdbcType.NVarChar,        SQL_C_TYPE.WCHAR,               SQL_TYPE.WVARCHAR   ));
261                         OdbcTypeMap.Add (new TypeMap (OdbcType.Real,            SQL_C_TYPE.FLOAT,               SQL_TYPE.REAL       ));
262                         OdbcTypeMap.Add (new TypeMap (OdbcType.SmallDateTime,   SQL_C_TYPE.TIMESTAMP,           SQL_TYPE.TIMESTAMP  , TypeMap.DefaultAll & (~TypeMap.DefaultForSQLType)));
263                         OdbcTypeMap.Add (new TypeMap (OdbcType.SmallInt,        SQL_C_TYPE.SHORT,               SQL_TYPE.SMALLINT   ));
264                         OdbcTypeMap.Add (new TypeMap (OdbcType.Text,            SQL_C_TYPE.WCHAR,               SQL_TYPE.LONGVARCHAR));
265                         OdbcTypeMap.Add (new TypeMap (OdbcType.Time,            SQL_C_TYPE.TYPE_TIME,           SQL_TYPE.TYPE_TIME  ));
266                         OdbcTypeMap.Add (new TypeMap (OdbcType.Timestamp,       SQL_C_TYPE.BINARY,              SQL_TYPE.BINARY     , TypeMap.DefaultAll & (~TypeMap.DefaultForSQLType)));
267                         OdbcTypeMap.Add (new TypeMap (OdbcType.TinyInt,         SQL_C_TYPE.UTINYINT,            SQL_TYPE.TINYINT    ));
268                         OdbcTypeMap.Add (new TypeMap (OdbcType.UniqueIdentifier,SQL_C_TYPE.GUID,                SQL_TYPE.GUID       ));
269                         OdbcTypeMap.Add (new TypeMap (OdbcType.VarBinary,       SQL_C_TYPE.BINARY,              SQL_TYPE.VARBINARY  ));
270                         OdbcTypeMap.Add (new TypeMap (OdbcType.VarChar,         SQL_C_TYPE.WCHAR,               SQL_TYPE.WVARCHAR   , TypeMap.DefaultAll & (~TypeMap.DefaultForSQLType)));
271                 }
272                 
273                 public static SQL_C_TYPE ConvertToSqlCType (OdbcType type)
274                 {
275                         return OdbcTypeMap [type].SqlCType;
276                 }
277                 
278                 public static SQL_TYPE ConvertToSqlType (OdbcType type)
279                 {
280                         return OdbcTypeMap [type].SqlType;
281                 }
282
283
284                 public static OdbcType ConvertToOdbcType (SQL_TYPE sqlType)
285                 {
286                         // Unmapped SQL Types
287                         //
288                         //#define SQL_FLOAT     6
289                         //      could map to SQL_DOUBLE?
290                         //#define SQL_INTERVAL  10
291                         //      could map to SmallDateTime?
292                         return GetTypeMap (sqlType).OdbcType;
293                 }
294
295                 public static TypeMap GetTypeMap (SQL_TYPE sqlType)
296                 {
297                         TypeMap map;
298                         try {
299                                 map  = OdbcTypeMap [sqlType];
300                                 return map;
301                         } catch (ArgumentException) {
302                                 
303                         }
304
305                         // If not in default translation
306                         map = new TypeMap ();
307                         map.SqlType = sqlType;
308                         switch (sqlType) {
309                         case SQL_TYPE.DATE:                      
310                                 map.OdbcType = OdbcType.DateTime;
311                                 map.SqlCType = SQL_C_TYPE.TYPE_DATE;
312                                 return map;
313
314                         case SQL_TYPE.DECIMAL:                      
315                                 map.OdbcType = OdbcType.Decimal;
316                                 map.SqlCType = SQL_C_TYPE.CHAR;
317                                 return map;
318
319                         case SQL_TYPE.INTERVAL_DAY:              
320                                 map.OdbcType = OdbcType.DateTime;
321                                 map.SqlCType = SQL_C_TYPE.INTERVAL_DAY;
322                                 return map;
323
324                         case SQL_TYPE.INTERVAL_DAY_TO_HOUR:      
325                                 map.OdbcType = OdbcType.DateTime;
326                                 map.SqlCType = SQL_C_TYPE.INTERVAL_DAY_TO_HOUR;
327                                 return map;
328
329                         case SQL_TYPE.INTERVAL_DAY_TO_MINUTE:    
330                                 map.OdbcType = OdbcType.DateTime;
331                                 map.SqlCType = SQL_C_TYPE.INTERVAL_DAY_TO_MINUTE;
332                                 return map;
333
334                         case SQL_TYPE.INTERVAL_DAY_TO_SECOND:    
335                                 map.OdbcType = OdbcType.DateTime;
336                                 map.SqlCType = SQL_C_TYPE.INTERVAL_DAY_TO_SECOND;
337                                 return map;
338
339                         case SQL_TYPE.INTERVAL_HOUR:             
340                                 map.OdbcType = OdbcType.DateTime;
341                                 map.SqlCType = SQL_C_TYPE.INTERVAL_HOUR;
342                                 return map;
343
344                         case SQL_TYPE.INTERVAL_HOUR_TO_MINUTE:   
345                                 map.OdbcType = OdbcType.DateTime;
346                                 map.SqlCType = SQL_C_TYPE.INTERVAL_HOUR_TO_MINUTE;
347                                 return map;
348
349                         case SQL_TYPE.INTERVAL_HOUR_TO_SECOND:   
350                                 map.OdbcType = OdbcType.DateTime;
351                                 map.SqlCType = SQL_C_TYPE.INTERVAL_HOUR_TO_SECOND;
352                                 return map;
353
354                         case SQL_TYPE.INTERVAL_MINUTE:           
355                                 map.OdbcType = OdbcType.DateTime;
356                                 map.SqlCType = SQL_C_TYPE.INTERVAL_MINUTE;
357                                 return map;
358
359                         case SQL_TYPE.INTERVAL_MINUTE_TO_SECOND: 
360                                 map.OdbcType = OdbcType.DateTime;
361                                 map.SqlCType = SQL_C_TYPE.INTERVAL_MINUTE_TO_SECOND;
362                                 return map;
363
364                         case SQL_TYPE.INTERVAL_MONTH:            
365                                 map.OdbcType = OdbcType.DateTime;
366                                 map.SqlCType = SQL_C_TYPE.INTERVAL_MONTH;
367                                 return map;
368
369                         case SQL_TYPE.INTERVAL_SECOND:           
370                                 map.OdbcType = OdbcType.DateTime;
371                                 map.SqlCType = SQL_C_TYPE.INTERVAL_SECOND;
372                                 return map;
373
374                         case SQL_TYPE.INTERVAL_YEAR:             
375                                 map.OdbcType = OdbcType.DateTime;
376                                 map.SqlCType = SQL_C_TYPE.INTERVAL_YEAR;
377                                 return map;
378
379                         case SQL_TYPE.INTERVAL_YEAR_TO_MONTH:    
380                                 map.OdbcType = OdbcType.DateTime;
381                                 map.SqlCType = SQL_C_TYPE.INTERVAL_YEAR_TO_MONTH;
382                                 return map;
383
384                         case SQL_TYPE.LONGVARBINARY:    
385                                 map.OdbcType = OdbcType.Binary;
386                                 map.SqlCType = SQL_C_TYPE.BINARY;
387                                 return map;
388
389                         case SQL_TYPE.TIME:                      
390                                 map.OdbcType = OdbcType.DateTime;
391                                 map.SqlCType = SQL_C_TYPE.TIME;
392                                 return map;
393
394                         case SQL_TYPE.TYPE_TIMESTAMP:            
395                                 map.OdbcType = OdbcType.DateTime;
396                                 map.SqlCType = SQL_C_TYPE.TIMESTAMP;
397                                 return map;
398
399                         case SQL_TYPE.VARCHAR:                   
400                                 map.OdbcType = OdbcType.VarChar;
401                                 map.SqlCType = SQL_C_TYPE.CHAR;
402                                 return map;
403
404                         default:                        
405                                 map.OdbcType = OdbcType.NVarChar;
406                                 map.SqlCType = SQL_C_TYPE.WCHAR;
407                                 return map;
408                         }
409                 }
410                 
411         }
412 }