2007-05-10 Nagappan A <anagappan@novell.com>
[mono.git] / mcs / class / FirebirdSql.Data.Firebird / FirebirdSql.Data.Common / DbField.cs
1 /*
2  *  Firebird ADO.NET Data provider for .NET and Mono 
3  * 
4  *     The contents of this file are subject to the Initial 
5  *     Developer's Public License Version 1.0 (the "License"); 
6  *     you may not use this file except in compliance with the 
7  *     License. You may obtain a copy of the License at 
8  *     http://www.firebirdsql.org/index.php?op=doc&id=idpl
9  *
10  *     Software distributed under the License is distributed on 
11  *     an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either 
12  *     express or implied.  See the License for the specific 
13  *     language governing rights and limitations under the License.
14  * 
15  *  Copyright (c) 2002, 2005 Carlos Guzman Alvarez
16  *  All Rights Reserved.
17  */
18
19 using System;
20 using System.Text;
21
22 namespace FirebirdSql.Data.Common
23 {
24         internal sealed class DbField
25         {
26                 #region Fields
27
28                 private short           dataType;
29                 private short           numericScale;
30                 private short           subType;
31                 private short           length;
32                 private short           nullFlag;
33                 private string          name;
34                 private string          relation;
35                 private string          owner;
36                 private string          alias;
37                 private int                     charCount;
38                 private DbValue         dbValue;
39                 private Charset         charset;
40                 private ArrayBase       arrayHandle;
41
42                 #endregion
43
44                 #region Properties
45
46                 public DbDataType DbDataType
47                 {
48                         get { return this.GetDbDataType(); }
49                 }
50
51                 public int SqlType
52                 {
53                         get { return this.dataType & ~1; }
54                 }
55
56                 public short DataType
57                 {
58                         get { return this.dataType; }
59                         set { this.dataType = value; }
60                 }
61
62                 public short NumericScale
63                 {
64                         get { return this.numericScale; }
65                         set { this.numericScale = value; }
66                 }
67
68                 public short SubType
69                 {
70                         get { return this.subType; }
71                         set
72                         {
73                                 this.subType = value;
74                                 if (this.IsCharacter())
75                                 {
76                                         // Bits 0-7 of sqlsubtype is charset_id (127 is a special value -
77                                         // current attachment charset).
78                                         // Bits 8-17 hold collation_id for this value.
79                                         byte[] cs = BitConverter.GetBytes(value);
80
81                                         int index = Charset.SupportedCharsets.IndexOf(cs[0]);
82                                         if (index != -1)
83                                         {
84                                                 this.charset = Charset.SupportedCharsets[index];
85                                         }
86                                         else
87                                         {
88                                                 this.charset = Charset.SupportedCharsets[0];
89                                         }
90                                 }
91                         }
92                 }
93
94                 public short Length
95                 {
96                         get { return this.length; }
97                         set
98                         {
99                                 this.length = value;
100                                 if (this.IsCharacter())
101                                 {
102                                         this.charCount = this.length / this.charset.BytesPerCharacter;
103                                 }
104                         }
105                 }
106
107                 public short NullFlag
108                 {
109                         get { return this.nullFlag; }
110                         set { this.nullFlag = value; }
111                 }
112
113                 public string Name
114                 {
115                         get { return this.name; }
116                         set { this.name = value.Trim(); }
117                 }
118
119                 public string Relation
120                 {
121                         get { return this.relation; }
122                         set { this.relation = value.Trim(); }
123                 }
124
125                 public string Owner
126                 {
127                         get { return this.owner; }
128                         set { this.owner = value.Trim(); }
129                 }
130
131                 public string Alias
132                 {
133                         get { return this.alias; }
134                         set { this.alias = value.Trim(); }
135                 }
136
137                 public Charset Charset
138                 {
139                         get { return this.charset; }
140                 }
141
142                 public int CharCount
143                 {
144                         get { return this.charCount; }
145                 }
146
147                 public ArrayBase ArrayHandle
148                 {
149                         get
150                         {
151                                 if (this.IsArray())
152                                 {
153                                         return this.arrayHandle;
154                                 }
155                                 else
156                                 {
157                                         throw new IscException("Field is not an array type");
158                                 }
159                         }
160
161                         set
162                         {
163                                 if (this.IsArray())
164                                 {
165                                         this.arrayHandle = value;
166                                 }
167                                 else
168                                 {
169                                         throw new IscException("Field is not an array type");
170                                 }
171                         }
172                 }
173
174                 public DbValue DbValue
175                 {
176                         get { return this.dbValue; }
177                 }
178
179                 public object Value
180                 {
181                         get { return this.dbValue.Value; }
182                         set { this.dbValue.Value = value; }
183                 }
184
185                 #endregion
186
187                 #region Constructors
188
189                 public DbField()
190                 {
191                         this.charCount  = -1;
192                         this.name               = String.Empty;
193                         this.relation   = String.Empty;
194                         this.owner              = String.Empty;
195                         this.alias              = String.Empty;
196                         this.dbValue    = new DbValue(this, DBNull.Value);
197                 }
198
199                 #endregion
200
201                 #region Methods
202
203                 public bool IsNumeric()
204                 {
205                         if (this.dataType == 0)
206                         {
207                                 return false;
208                         }
209
210                         switch (this.DbDataType)
211                         {
212                                 case DbDataType.SmallInt:
213                                 case DbDataType.Integer:
214                                 case DbDataType.BigInt:
215                                 case DbDataType.Numeric:
216                                 case DbDataType.Decimal:
217                                 case DbDataType.Float:
218                                 case DbDataType.Double:
219                                         return true;
220
221                                 default:
222                                         return false;
223                         }
224                 }
225
226                 public bool IsDecimal()
227                 {
228                         if (this.dataType == 0)
229                         {
230                                 return false;
231                         }
232
233                         switch (this.DbDataType)
234                         {
235                                 case DbDataType.Numeric:
236                                 case DbDataType.Decimal:
237                                         return true;
238
239                                 default:
240                                         return false;
241                         }
242                 }
243
244                 public bool IsLong()
245                 {
246                         if (this.dataType == 0)
247                         {
248                                 return false;
249                         }
250
251                         switch (this.DbDataType)
252                         {
253                                 case DbDataType.Binary:
254                                 case DbDataType.Text:
255                                         return true;
256
257                                 default:
258                                         return false;
259                         }
260                 }
261
262                 public bool IsCharacter()
263                 {
264                         if (this.dataType == 0)
265                         {
266                                 return false;
267                         }
268
269                         switch (this.DbDataType)
270                         {
271                                 case DbDataType.Char:
272                                 case DbDataType.VarChar:
273                                 case DbDataType.Text:
274                                         return true;
275
276                                 default:
277                                         return false;
278                         }
279                 }
280
281                 public bool IsArray()
282                 {
283                         if (this.dataType == 0)
284                         {
285                                 return false;
286                         }
287
288                         switch (this.DbDataType)
289                         {
290                                 case DbDataType.Array:
291                                         return true;
292
293                                 default:
294                                         return false;
295                         }
296                 }
297
298                 public bool IsAliased()
299                 {
300                         return (this.Name != this.Alias) ? true : false;
301                 }
302
303                 public bool IsExpression()
304                 {
305                         return this.Name.Length == 0 ? true : false;
306                 }
307
308                 public int GetSize()
309                 {
310                         if (this.IsLong())
311                         {
312                                 return System.Int32.MaxValue;
313                         }
314                         else
315                         {
316                                 if (this.IsCharacter())
317                                 {
318                                         return this.CharCount;
319                                 }
320                                 else
321                                 {
322                                         return this.Length;
323                                 }
324                         }
325                 }
326
327                 public bool AllowDBNull()
328                 {
329                         return ((this.DataType & 1) == 1);
330                 }
331
332                 public void SetValue(byte[] buffer)
333                 {
334                         if (buffer == null || this.NullFlag == -1)
335                         {
336                                 this.Value = System.DBNull.Value;
337                         }
338                         else
339                         {
340                                 switch (this.SqlType)
341                                 {
342                                         case IscCodes.SQL_TEXT:
343                                         case IscCodes.SQL_VARYING:
344                                                 if (this.DbDataType == DbDataType.Guid)
345                                                 {
346                                                         this.Value = new Guid(buffer);
347                                                 }
348                                                 else
349                                                 {
350                                                         string s = this.Charset.GetString(buffer, 0, buffer.Length);
351
352                                                         if ((this.Length % this.Charset.BytesPerCharacter) == 0 &&
353                                                                 s.Length > this.CharCount)
354                                                         {
355                                                                 s = s.Substring(0, this.CharCount);
356                                                         }
357
358                                                         this.Value = s;
359                                                 }
360                                                 break;
361
362                                         case IscCodes.SQL_SHORT:
363                                                 if (this.numericScale < 0)
364                                                 {
365                                                         this.Value = TypeDecoder.DecodeDecimal(
366                                                                 BitConverter.ToInt16(buffer, 0),
367                                                                 this.numericScale,
368                                                                 this.dataType);
369                                                 }
370                                                 else
371                                                 {
372                                                         this.Value = BitConverter.ToInt16(buffer, 0);
373                                                 }
374                                                 break;
375
376                                         case IscCodes.SQL_LONG:
377                                                 if (this.NumericScale < 0)
378                                                 {
379                                                         this.Value = TypeDecoder.DecodeDecimal(
380                                                                 BitConverter.ToInt32(buffer, 0),
381                                                                 this.numericScale,
382                                                                 this.dataType);
383                                                 }
384                                                 else
385                                                 {
386                                                         this.Value = BitConverter.ToInt32(buffer, 0);
387                                                 }
388                                                 break;
389
390                                         case IscCodes.SQL_FLOAT:
391                                                 this.Value = BitConverter.ToSingle(buffer, 0);
392                                                 break;
393
394                                         case IscCodes.SQL_DOUBLE:
395                                         case IscCodes.SQL_D_FLOAT:
396                                                 this.Value = BitConverter.ToDouble(buffer, 0);
397                                                 break;
398
399                                         case IscCodes.SQL_QUAD:
400                                         case IscCodes.SQL_INT64:
401                                         case IscCodes.SQL_BLOB:
402                                         case IscCodes.SQL_ARRAY:
403                                                 if (this.NumericScale < 0)
404                                                 {
405                                                         this.Value = TypeDecoder.DecodeDecimal(
406                                                                 BitConverter.ToInt64(buffer, 0),
407                                                                 this.numericScale,
408                                                                 this.dataType);
409                                                 }
410                                                 else
411                                                 {
412                                                         this.Value = BitConverter.ToInt64(buffer, 0);
413                                                 }
414                                                 break;
415
416                                         case IscCodes.SQL_TIMESTAMP:
417                                                 DateTime date = TypeDecoder.DecodeDate(
418                                                         BitConverter.ToInt32(buffer, 0));
419
420                                                 DateTime time = TypeDecoder.DecodeTime(
421                                                         BitConverter.ToInt32(buffer, 4));
422
423                                                 this.Value = new System.DateTime(
424                                                         date.Year, date.Month, date.Day,
425                                                         time.Hour, time.Minute, time.Second, time.Millisecond);
426                                                 break;
427
428                                         case IscCodes.SQL_TYPE_TIME:
429                                                 this.Value = TypeDecoder.DecodeTime(BitConverter.ToInt32(buffer, 0));
430                                                 break;
431
432                                         case IscCodes.SQL_TYPE_DATE:
433                                                 this.Value = TypeDecoder.DecodeDate(BitConverter.ToInt32(buffer, 0));
434                                                 break;
435
436                                         default:
437                                                 throw new NotSupportedException("Unknown data type");
438                                 }
439                         }
440                 }
441
442                 public void FixNull()
443                 {
444                         if (this.NullFlag == -1 && this.dbValue.IsDBNull())
445                         {
446                                 switch (this.DbDataType)
447                                 {
448                                         case DbDataType.Char:
449                                         case DbDataType.VarChar:
450                                                 this.Value = String.Empty;
451                                                 break;
452
453                                         case DbDataType.Guid:
454                                                 this.Value = Guid.Empty;
455                                                 break;
456
457                                         case DbDataType.SmallInt:
458                                                 this.Value = (short)0;
459                                                 break;
460
461                                         case DbDataType.Integer:
462                                                 this.Value = (int)0;
463                                                 break;
464
465                                         case DbDataType.BigInt:
466                                         case DbDataType.Binary:
467                                         case DbDataType.Array:
468                                         case DbDataType.Text:
469                                                 this.Value = (long)0;
470                                                 break;
471
472                                         case DbDataType.Numeric:
473                                         case DbDataType.Decimal:
474                                                 this.Value = (decimal)0;
475                                                 break;
476
477                                         case DbDataType.Float:
478                                                 this.Value = (float)0;
479                                                 break;
480
481                                         case DbDataType.Double:
482                                                 this.Value = (double)0;
483                                                 break;
484
485                                         case DbDataType.Date:
486                                         case DbDataType.Time:
487                                         case DbDataType.TimeStamp:
488                                                 this.Value = new System.DateTime(0 * 10000L + 621355968000000000);
489                                                 break;
490
491                                         default:
492                                                 throw new IscException("Unknown sql data type: " + this.DataType);
493                                 }
494                         }
495                 }
496
497                 public Type GetSystemType()
498                 {
499                         switch (this.DbDataType)
500                         {
501                                 case DbDataType.Char:
502                                 case DbDataType.VarChar:
503                                 case DbDataType.Text:
504                                         return Type.GetType("System.String");
505
506                                 case DbDataType.SmallInt:
507                                         return Type.GetType("System.Int16");
508
509                                 case DbDataType.Integer:
510                                         return Type.GetType("System.Int32");
511
512                                 case DbDataType.BigInt:
513                                         return Type.GetType("System.Int64");
514
515                                 case DbDataType.Numeric:
516                                 case DbDataType.Decimal:
517                                         return Type.GetType("System.Decimal");
518
519                                 case DbDataType.Float:
520                                         return Type.GetType("System.Single");
521
522                                 case DbDataType.Guid:
523                                         return Type.GetType("System.Guid");
524
525                                 case DbDataType.Double:
526                                         return Type.GetType("System.Double");
527
528                                 case DbDataType.Date:
529                                 case DbDataType.Time:
530                                 case DbDataType.TimeStamp:
531                                         return Type.GetType("System.DateTime");
532
533                                 case DbDataType.Binary:
534                                         return typeof(byte[]);
535
536                                 case DbDataType.Array:
537                                         return Type.GetType("System.Array");
538
539                                 default:
540                                         throw new SystemException("Invalid data type");
541                         }
542                 }
543
544                 #endregion
545
546                 #region Private Methods
547
548                 private DbDataType GetDbDataType()
549                 {
550                         // Special case for Guid handling
551                         if (this.SqlType == IscCodes.SQL_TEXT && this.Length == 16 &&
552                                 (this.Charset != null && this.Charset.Name == "OCTETS"))
553                         {
554                                 return DbDataType.Guid;
555                         }
556
557                         switch (this.SqlType)
558                         {
559                                 case IscCodes.SQL_TEXT:
560                                         return DbDataType.Char;
561
562                                 case IscCodes.SQL_VARYING:
563                                         return DbDataType.VarChar;
564
565                                 case IscCodes.SQL_SHORT:
566                                         if (this.subType == 2)
567                                         {
568                                                 return DbDataType.Decimal;
569                                         }
570                     else if (subType == 1)
571                     {
572                         return DbDataType.Numeric;
573                     }
574                     else
575                                         {
576                                                 return DbDataType.SmallInt;
577                                         }
578
579                                 case IscCodes.SQL_LONG:
580                                         if (this.subType == 2)
581                                         {
582                                                 return DbDataType.Decimal;
583                                         }
584                     else if (subType == 1)
585                     {
586                         return DbDataType.Numeric;
587                     }
588                     else
589                                         {
590                                                 return DbDataType.Integer;
591                                         }
592
593                                 case IscCodes.SQL_QUAD:
594                                 case IscCodes.SQL_INT64:
595                                         if (this.subType == 2)
596                                         {
597                                                 return DbDataType.Decimal;
598                                         }
599                     else if (subType == 1)
600                     {
601                         return DbDataType.Numeric;
602                     }
603                     else
604                                         {
605                                                 return DbDataType.BigInt;
606                                         }
607
608                                 case IscCodes.SQL_FLOAT:
609                                         return DbDataType.Float;
610
611                                 case IscCodes.SQL_DOUBLE:
612                                 case IscCodes.SQL_D_FLOAT:
613                                         if (this.subType == 2)
614                                         {
615                                                 return DbDataType.Decimal;
616                                         }
617                     else if (subType == 1)
618                     {
619                         return DbDataType.Numeric;
620                     }
621                     else
622                                         {
623                                                 return DbDataType.Double;
624                                         }
625
626                                 case IscCodes.SQL_BLOB:
627                                         if (this.subType == 1)
628                                         {
629                                                 return DbDataType.Text;
630                                         }
631                                         else
632                                         {
633                                                 return DbDataType.Binary;
634                                         }
635
636                                 case IscCodes.SQL_TIMESTAMP:
637                                         return DbDataType.TimeStamp;
638
639                                 case IscCodes.SQL_TYPE_TIME:
640                                         return DbDataType.Time;
641
642                                 case IscCodes.SQL_TYPE_DATE:
643                                         return DbDataType.Date;
644
645                                 case IscCodes.SQL_ARRAY:
646                                         return DbDataType.Array;
647
648                                 default:
649                                         throw new SystemException("Invalid data type");
650                         }
651                 }
652
653                 #endregion
654         }
655 }