2004-04-12 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / class / System.Data / System.Data.SqlTypes / SqlString.cs
1 //
2 // System.Data.SqlTypes.SqlString
3 //
4 // Author:
5 //   Rodrigo Moya (rodrigo@ximian.com)
6 //   Daniel Morgan (danmorg@sc.rr.com)
7 //   Tim Coleman (tim@timcoleman.com)
8 //   Ville Palo (vi64pa@koti.soon.fi)
9 //
10 // (C) Ximian, Inc. 2002
11 // (C) Copyright 2002 Tim Coleman
12 //
13
14 using System;
15 using System.Globalization;
16 using System.Threading;
17
18 namespace System.Data.SqlTypes
19 {
20         /// <summary>
21         /// A variable-length stream of characters 
22         /// to be stored in or retrieved from the database
23         /// </summary>
24         public struct SqlString : INullable, IComparable 
25         {
26
27                 #region Fields
28
29                 string value;
30
31                 private bool notNull;
32
33                 // FIXME: locale id is not working yet
34                 private int lcid;
35                 private SqlCompareOptions compareOptions;
36
37                 public static readonly int BinarySort = 0x8000;
38                 public static readonly int IgnoreCase = 0x1;
39                 public static readonly int IgnoreKanaType = 0x8;
40                 public static readonly int IgnoreNonSpace = 0x2;
41                 public static readonly int IgnoreWidth = 0x10;
42                 public static readonly SqlString Null;
43
44                 internal static readonly NumberFormatInfo MoneyFormat;
45                 internal static NumberFormatInfo DecimalFormat;
46                 #endregion // Fields
47
48                 #region Constructors
49
50                 static SqlString ()
51                 {
52                         MoneyFormat = (NumberFormatInfo) NumberFormatInfo.InvariantInfo.Clone ();
53                         MoneyFormat.NumberDecimalDigits = 4;
54                         MoneyFormat.NumberGroupSeparator = String.Empty;
55
56                         DecimalFormat = (NumberFormatInfo) NumberFormatInfo.InvariantInfo.Clone ();
57                         DecimalFormat.NumberDecimalDigits = 13;
58                         DecimalFormat.NumberGroupSeparator = String.Empty;
59                 }
60
61                 // init with a string data
62                 public SqlString (string data) 
63                 {
64                         this.value = data;
65                         lcid = CultureInfo.CurrentCulture.LCID;
66                         notNull = true;
67                         this.compareOptions = SqlCompareOptions.IgnoreCase |
68                                 SqlCompareOptions.IgnoreKanaType |
69                                 SqlCompareOptions.IgnoreWidth;
70                 }
71
72                 // init with a string data and locale id values.
73                 public SqlString (string data, int lcid) 
74                 {
75                         this.value = data;
76                         this.lcid = lcid;
77                         notNull = true;
78                         this.compareOptions = SqlCompareOptions.IgnoreCase |
79                                 SqlCompareOptions.IgnoreKanaType |
80                                 SqlCompareOptions.IgnoreWidth;
81                 }
82
83                 // init with locale id, compare options, 
84                 // and an array of bytes data
85                 public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data) 
86                         : this (lcid, compareOptions, data, true) { }
87
88                 // init with string data, locale id, and compare options
89                 public SqlString (string data, int lcid, SqlCompareOptions compareOptions) 
90                 {
91                         this.value = data;
92                         this.lcid = lcid;
93                         this.compareOptions = compareOptions;
94                         notNull = true;
95                 }
96
97                 // init with locale id, compare options, array of bytes data,
98                 // and whether unicode is encoded or not
99                 public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data, bool fUnicode) 
100                 {
101                         char [] chars;
102
103                         if (fUnicode)
104                                 chars = new char [data.Length/2];
105                         else
106                                 chars = new char [data.Length];
107                         
108                         int j = 0;
109                         for (int i = 0; i < chars.Length; i++) {
110
111                                 if (fUnicode) {
112                                         chars [i] = (char)(data [j] << 16);
113                                         chars [i] += (char)data [j + 1];
114                                         j += 2;
115                                 } else {
116                                         chars [i] = (char)data[i];
117                                 }
118                         }
119                                 
120                         this.value = new String (chars);
121                         this.lcid = lcid;
122                         this.compareOptions = compareOptions;
123                         notNull = true;
124                 }
125
126                 // init with locale id, compare options, array of bytes data,
127                 // starting index in the byte array, 
128                 // and number of bytes to copy
129                 public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data, 
130                                   int index, int count) 
131                         : this (lcid, compareOptions, data, index, count, true) { }
132
133                 // init with locale id, compare options, array of bytes data,
134                 // starting index in the byte array, number of byte to copy,
135                 // and whether unicode is encoded or not
136                 public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data, int index, int count, bool fUnicode) 
137                 {                      
138                         char [] chars;
139
140                         if (fUnicode)
141                                 chars = new char [(count - index) / 2];
142                         else
143                                 chars = new char [count - index];
144
145                         if (index >= data.Length)
146                                 throw new ArgumentOutOfRangeException ("index");
147
148                         if ((index + count) > data.Length)
149                                 throw new ArgumentOutOfRangeException ("count");
150
151                         int j = 0;
152                         for (int i = index; i < chars.Length; i++) {
153                                 
154                                 if (fUnicode) {
155                                         chars [i] = (char)(data[j] << 16);
156                                         chars [i] += (char)data[j+1];
157                                         j += 2;
158                                 } else {
159                                         chars [i] = (char)data [j];
160                                         j++;
161                                 }
162                         }
163
164                         this.value = new String (chars);
165                         this.lcid = lcid;
166                         this.compareOptions = compareOptions;
167                         notNull = true;
168                 }
169
170                 #endregion // Constructors
171
172
173                 #region Public Properties
174
175                 public CompareInfo CompareInfo {
176                         get { 
177                                 return new CultureInfo (lcid).CompareInfo;
178                         }
179                 }
180
181                 public CultureInfo CultureInfo {
182                         get { 
183                                 return new CultureInfo (lcid);
184                         }
185                 }
186
187                 public CompareOptions CompareOptions {
188                         get {
189                                 return 
190                                         (this.compareOptions & SqlCompareOptions.BinarySort) != 0 ? 
191                                         CompareOptions.Ordinal :
192                                         // 27 == all SqlCompareOptions - BinarySort 
193                                         // (1,2,8,24 are common to CompareOptions)
194                                         (CompareOptions) ((int) this.compareOptions & 27);
195                         }
196                 }
197
198                 public bool IsNull {
199                         get { return !notNull; }
200                 }
201
202                 // geographics location and language (locale id)
203                 public int LCID {
204                         get { 
205                                 return lcid;
206                         }
207                 }
208         
209                 public SqlCompareOptions SqlCompareOptions {
210                         get { 
211                                 return compareOptions;
212                         }
213                 }
214
215                 public string Value {
216                         get {
217                                 if (this.IsNull)
218                                         throw new SqlNullValueException (Locale.GetText ("The property contains Null."));
219                                 else
220                                         return value;
221                         }
222                 }
223
224                 #endregion // Public Properties
225
226                 #region Public Methods
227
228                 public SqlString Clone() 
229                 {
230                         return new  SqlString (value, lcid, compareOptions);
231                 }
232
233                 public static CompareOptions CompareOptionsFromSqlCompareOptions (SqlCompareOptions compareOptions) 
234                 {
235                         CompareOptions options = CompareOptions.None;
236                         
237                         if ((compareOptions & SqlCompareOptions.IgnoreCase) != 0)
238                                 options |= CompareOptions.IgnoreCase;
239                         if ((compareOptions & SqlCompareOptions.IgnoreKanaType) != 0)
240                                 options |= CompareOptions.IgnoreKanaType;
241                         if ((compareOptions & SqlCompareOptions.IgnoreNonSpace) != 0)
242                                 options |= CompareOptions.IgnoreNonSpace;
243                         if ((compareOptions & SqlCompareOptions.IgnoreWidth) != 0)
244                                 options |= CompareOptions.IgnoreWidth;
245                         if ((compareOptions & SqlCompareOptions.BinarySort) != 0)
246                                 // FIXME: Exception string
247                                 throw new ArgumentOutOfRangeException (); 
248                         
249                         return options;         
250                 }
251
252                 // **********************************
253                 // Comparison Methods
254                 // **********************************
255
256                 public int CompareTo (object value)
257                 {
258                         if (value == null)
259                                 return 1;
260                         else if (!(value is SqlString))
261                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Data.SqlTypes.SqlString"));
262                         else if (((SqlString)value).IsNull)
263                                 return 1;
264 //                      else
265 //                              return String.Compare (this.value, ((SqlString)value).Value, (this.SqlCompareOptions & SqlCompareOptions.IgnoreCase) != 0, this.CultureInfo);
266                         return CultureInfo.CompareInfo.Compare (this.value, ((SqlString)value).Value, this.CompareOptions);
267                 }
268
269                 public static SqlString Concat(SqlString x, SqlString y) 
270                 {
271                         return (x + y);
272                 }
273
274                 public override bool Equals(object value) 
275                 {
276                         if (!(value is SqlString))
277                                 return false;
278                         if (this.IsNull && ((SqlString)value).IsNull)
279                                 return true;
280                         else if (((SqlString)value).IsNull)
281                                 return false;
282                         else
283                                 return (bool) (this == (SqlString)value);
284                 }
285
286                 public static SqlBoolean Equals(SqlString x, SqlString y) 
287                 {
288                         return (x == y);
289                 }
290
291                 public override int GetHashCode() 
292                 {
293                         int result = 10;
294                         for (int i = 0; i < value.Length; i++)
295                                 result = 91 * result + (int)(value [i] ^ (value [i] >> 32));
296                                                 
297                         result = 91 * result + lcid.GetHashCode ();
298                         result = 91 * result + (int)compareOptions;
299
300                         return result;
301                 }
302
303                 public byte[] GetNonUnicodeBytes() 
304                 {
305                         byte [] bytes = new byte [value.Length];
306
307                         for (int i = 0; i < bytes.Length; i++) 
308                                 bytes [i] = (byte)value [i];
309
310                         return bytes;
311                 }
312
313                 public byte[] GetUnicodeBytes() 
314                 {
315                         byte [] bytes = new byte [value.Length * 2];
316                         
317                         int j = 0;
318                         for (int i = 0; i < value.Length; i++) {                                
319                                 bytes [j] = (byte)(value [i] & 0x0000FFFF);
320                                 bytes [j + 1] = (byte)((value [i] & 0xFFFF0000) >> 16);
321                                 j += 2;
322                         }
323                         
324                         return bytes;
325                 }
326
327                 public static SqlBoolean GreaterThan(SqlString x, SqlString y) 
328                 {
329                         return (x > y);
330                 }
331
332                 public static SqlBoolean GreaterThanOrEqual(SqlString x, SqlString y) 
333                 {
334                         return (x >= y);
335                 }
336
337                 public static SqlBoolean LessThan(SqlString x, SqlString y) 
338                 {
339                         return (x < y);
340                 }
341
342                 public static SqlBoolean LessThanOrEqual(SqlString x, SqlString y) 
343                 {
344                         return (x <= y);
345                 }
346
347                 public static SqlBoolean NotEquals(SqlString x, SqlString y) 
348                 {
349                         return (x != y);
350                 }
351
352                 // ****************************************
353                 // Type Conversions From SqlString To ...
354                 // ****************************************
355
356                 public SqlBoolean ToSqlBoolean() 
357                 {
358                         return ((SqlBoolean)this);
359                 }
360
361                 public SqlByte ToSqlByte() 
362                 {
363                         return ((SqlByte)this);
364                 }
365
366                 public SqlDateTime ToSqlDateTime() 
367                 {
368                         return ((SqlDateTime)this);
369                 }
370
371                 public SqlDecimal ToSqlDecimal() 
372                 {
373                         return ((SqlDecimal)this);
374                 }
375
376                 public SqlDouble ToSqlDouble() 
377                 {
378                         return ((SqlDouble)this);
379                 }
380
381                 public SqlGuid ToSqlGuid() 
382                 {
383                         return ((SqlGuid)this);
384                 }
385
386                 public SqlInt16 ToSqlInt16() 
387                 {
388                         return ((SqlInt16)this);
389                 }
390
391                 public SqlInt32 ToSqlInt32() 
392                 {
393                         return ((SqlInt32)this);
394                 }
395
396                 public SqlInt64 ToSqlInt64() 
397                 {
398                         return ((SqlInt64)this);
399                 }
400
401                 public SqlMoney ToSqlMoney() 
402                 {
403                         return ((SqlMoney)this);
404                 }
405
406                 public SqlSingle ToSqlSingle() 
407                 {
408                         return ((SqlSingle)this);
409                 }
410
411                 public override string ToString() 
412                 {
413                         return ((string)this);
414                 }
415
416                 // ***********************************
417                 // Operators
418                 // ***********************************
419
420                 // Concatenates
421                 public static SqlString operator + (SqlString x, SqlString y) 
422                 {
423                         if (x.IsNull || y.IsNull)
424                                 return SqlString.Null;
425
426                         return new SqlString (x.Value + y.Value);
427                 }
428
429                 // Equality
430                 public static SqlBoolean operator == (SqlString x, SqlString y) 
431                 {
432                         if (x.IsNull || y.IsNull)
433                                 return SqlBoolean.Null;
434                         else
435                                 return new SqlBoolean (x.Value == y.Value);
436                 }
437
438                 // Greater Than
439                 public static SqlBoolean operator > (SqlString x, SqlString y) 
440                 {
441                         if (x.IsNull || y.IsNull)
442                                 return SqlBoolean.Null;
443                         else
444                                 return new SqlBoolean (x.CompareTo (y) > 0);
445                 }
446
447                 // Greater Than Or Equal
448                 public static SqlBoolean operator >= (SqlString x, SqlString y) 
449                 {
450                         if (x.IsNull || y.IsNull)
451                                 return SqlBoolean.Null;
452                         else
453                                 return new SqlBoolean (x.CompareTo (y) >= 0);
454                 }
455
456                 public static SqlBoolean operator != (SqlString x, SqlString y) 
457                 { 
458                         if (x.IsNull || y.IsNull)
459                                 return SqlBoolean.Null;
460                         else
461                                 return new SqlBoolean (x.Value != y.Value);
462                 }
463
464                 // Less Than
465                 public static SqlBoolean operator < (SqlString x, SqlString y) 
466                 {
467                         if (x.IsNull || y.IsNull)
468                                 return SqlBoolean.Null;
469                         else
470                                 return new SqlBoolean (x.CompareTo (y) < 0);
471                 }
472
473                 // Less Than Or Equal
474                 public static SqlBoolean operator <= (SqlString x, SqlString y) 
475                 {
476                         if (x.IsNull || y.IsNull)
477                                 return SqlBoolean.Null;
478                         else
479                                 return new SqlBoolean (x.CompareTo (y) <= 0);
480                 }
481
482                 // **************************************
483                 // Type Conversions
484                 // **************************************
485
486                 public static explicit operator SqlString (SqlBoolean x) 
487                 {
488                         if (x.IsNull)
489                                 return Null;
490                         else
491                                 return new SqlString (x.Value.ToString ());
492                 }
493
494                 public static explicit operator SqlString (SqlByte x) 
495                 {
496                         if (x.IsNull)
497                                 return Null;
498                         else
499                                 return new SqlString (x.Value.ToString ());
500                 }
501
502                 public static explicit operator SqlString (SqlDateTime x) 
503                 {
504                         if (x.IsNull)
505                                 return Null;
506                         else
507                                 return new SqlString (x.Value.ToString ());
508                 }
509
510                 public static explicit operator SqlString (SqlDecimal x)
511                 {
512                         if (x.IsNull)
513                                 return Null;
514                         else
515                                 return new SqlString (x.Value.ToString ());
516                                 return new SqlString (x.Value.ToString ("N", DecimalFormat));
517                 }
518
519                 public static explicit operator SqlString (SqlDouble x) 
520                 {
521                         if (x.IsNull)
522                                 return Null;
523                         else
524                                 return new SqlString (x.Value.ToString ());
525                 }
526
527                 public static explicit operator SqlString (SqlGuid x) 
528                 {
529                         if (x.IsNull)
530                                 return Null;
531                         else
532                                 return new SqlString (x.Value.ToString ());
533                 }
534
535                 public static explicit operator SqlString (SqlInt16 x) 
536                 {
537                         if (x.IsNull)
538                                 return Null;
539                         else
540                                 return new SqlString (x.Value.ToString ());
541                 }
542
543                 public static explicit operator SqlString (SqlInt32 x) 
544                 {
545                         if (x.IsNull)
546                                 return Null;
547                         else
548                                 return new SqlString (x.Value.ToString ());
549                 }
550
551                 public static explicit operator SqlString (SqlInt64 x) 
552                 {
553                         if (x.IsNull)
554                                 return Null;
555                         else
556                                 return new SqlString (x.Value.ToString ());
557                 }
558
559                 public static explicit operator SqlString (SqlMoney x) 
560                 {
561                         if (x.IsNull)
562                                 return Null;
563                         else
564                                 return new SqlString (x.Value.ToString ());
565                                 return new SqlString (x.Value.ToString ("N", MoneyFormat));
566                 }
567
568                 public static explicit operator SqlString (SqlSingle x) 
569                 {
570                         if (x.IsNull)
571                                 return Null;
572                         else
573                                 return new SqlString (x.Value.ToString ());
574                 }
575
576                 public static explicit operator string (SqlString x) 
577                 {
578                         return x.Value;
579                 }
580
581                 public static implicit operator SqlString (string x) 
582                 {
583                         return new SqlString (x);
584                 }
585
586                 #endregion // Public Methods
587         }
588 }