2005-09-19 Chris Toshok <toshok@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 //
15 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
16 //
17 // Permission is hereby granted, free of charge, to any person obtaining
18 // a copy of this software and associated documentation files (the
19 // "Software"), to deal in the Software without restriction, including
20 // without limitation the rights to use, copy, modify, merge, publish,
21 // distribute, sublicense, and/or sell copies of the Software, and to
22 // permit persons to whom the Software is furnished to do so, subject to
23 // the following conditions:
24 // 
25 // The above copyright notice and this permission notice shall be
26 // included in all copies or substantial portions of the Software.
27 // 
28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 //
36
37 using System;
38 using System.Globalization;
39 using System.Threading;
40
41 namespace System.Data.SqlTypes
42 {
43         /// <summary>
44         /// A variable-length stream of characters 
45         /// to be stored in or retrieved from the database
46         /// </summary>
47         public struct SqlString : INullable, IComparable 
48         {
49
50                 #region Fields
51
52                 string value;
53
54                 private bool notNull;
55
56                 // FIXME: locale id is not working yet
57                 private int lcid;
58                 private SqlCompareOptions compareOptions;
59
60                 public static readonly int BinarySort = 0x8000;
61                 public static readonly int IgnoreCase = 0x1;
62                 public static readonly int IgnoreKanaType = 0x8;
63                 public static readonly int IgnoreNonSpace = 0x2;
64                 public static readonly int IgnoreWidth = 0x10;
65                 public static readonly SqlString Null;
66
67                 internal static NumberFormatInfo DecimalFormat;
68                 #endregion // Fields
69
70                 #region Constructors
71
72                 static SqlString ()
73                 {
74                         DecimalFormat = (NumberFormatInfo) NumberFormatInfo.InvariantInfo.Clone ();
75                         DecimalFormat.NumberDecimalDigits = 13;
76                         DecimalFormat.NumberGroupSeparator = String.Empty;
77                 }
78
79                 // init with a string data
80                 public SqlString (string data) 
81                 {
82                         this.value = data;
83                         lcid = CultureInfo.CurrentCulture.LCID;
84                         notNull = true;
85                         this.compareOptions = SqlCompareOptions.IgnoreCase |
86                                 SqlCompareOptions.IgnoreKanaType |
87                                 SqlCompareOptions.IgnoreWidth;
88                 }
89
90                 // init with a string data and locale id values.
91                 public SqlString (string data, int lcid) 
92                 {
93                         this.value = data;
94                         this.lcid = lcid;
95                         notNull = true;
96                         this.compareOptions = SqlCompareOptions.IgnoreCase |
97                                 SqlCompareOptions.IgnoreKanaType |
98                                 SqlCompareOptions.IgnoreWidth;
99                 }
100
101                 // init with locale id, compare options, 
102                 // and an array of bytes data
103                 public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data) 
104                         : this (lcid, compareOptions, data, true) { }
105
106                 // init with string data, locale id, and compare options
107                 public SqlString (string data, int lcid, SqlCompareOptions compareOptions) 
108                 {
109                         this.value = data;
110                         this.lcid = lcid;
111                         this.compareOptions = compareOptions;
112                         notNull = true;
113                 }
114
115                 // init with locale id, compare options, array of bytes data,
116                 // and whether unicode is encoded or not
117                 public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data, bool fUnicode) 
118                 {
119                         char [] chars;
120
121                         if (fUnicode)
122                                 chars = new char [data.Length/2];
123                         else
124                                 chars = new char [data.Length];
125                         
126                         int j = 0;
127                         for (int i = 0; i < chars.Length; i++) {
128
129                                 if (fUnicode) {
130                                         chars [i] = (char)(data [j] << 16);
131                                         chars [i] += (char)data [j + 1];
132                                         j += 2;
133                                 } else {
134                                         chars [i] = (char)data[i];
135                                 }
136                         }
137                                 
138                         this.value = new String (chars);
139                         this.lcid = lcid;
140                         this.compareOptions = compareOptions;
141                         notNull = true;
142                 }
143
144                 // init with locale id, compare options, array of bytes data,
145                 // starting index in the byte array, 
146                 // and number of bytes to copy
147                 public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data, 
148                                   int index, int count) 
149                         : this (lcid, compareOptions, data, index, count, true) { }
150
151                 // init with locale id, compare options, array of bytes data,
152                 // starting index in the byte array, number of byte to copy,
153                 // and whether unicode is encoded or not
154                 public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data, int index, int count, bool fUnicode) 
155                 {                      
156                         char [] chars;
157
158                         if (fUnicode)
159                                 chars = new char [(count - index) / 2];
160                         else
161                                 chars = new char [count - index];
162
163                         if (index >= data.Length)
164                                 throw new ArgumentOutOfRangeException ("index");
165
166                         if ((index + count) > data.Length)
167                                 throw new ArgumentOutOfRangeException ("count");
168
169                         int j = 0;
170                         for (int i = index; i < chars.Length; i++) {
171                                 
172                                 if (fUnicode) {
173                                         chars [i] = (char)(data[j] << 16);
174                                         chars [i] += (char)data[j+1];
175                                         j += 2;
176                                 } else {
177                                         chars [i] = (char)data [j];
178                                         j++;
179                                 }
180                         }
181
182                         this.value = new String (chars);
183                         this.lcid = lcid;
184                         this.compareOptions = compareOptions;
185                         notNull = true;
186                 }
187
188                 #endregion // Constructors
189
190
191                 #region Public Properties
192
193                 public CompareInfo CompareInfo {
194                         get { 
195                                 return new CultureInfo (lcid).CompareInfo;
196                         }
197                 }
198
199                 public CultureInfo CultureInfo {
200                         get { 
201                                 return new CultureInfo (lcid);
202                         }
203                 }
204
205                 public bool IsNull {
206                         get { return !notNull; }
207                 }
208
209                 // geographics location and language (locale id)
210                 public int LCID {
211                         get { 
212                                 return lcid;
213                         }
214                 }
215         
216                 public SqlCompareOptions SqlCompareOptions {
217                         get { 
218                                 return compareOptions;
219                         }
220                 }
221
222                 public string Value {
223                         get {
224                                 if (this.IsNull)
225                                         throw new SqlNullValueException (Locale.GetText ("The property contains Null."));
226                                 else
227                                         return value;
228                         }
229                 }
230
231                 #endregion // Public Properties
232
233                 #region Private Properties
234
235                 private CompareOptions CompareOptions {
236                         get {
237                                 return
238                                         (this.compareOptions & SqlCompareOptions.BinarySort) != 0 ?
239                                         CompareOptions.Ordinal :
240                                         // 27 == all SqlCompareOptions - BinarySort 
241                                         // (1,2,8,24 are common to CompareOptions)
242                                         (CompareOptions)((int)this.compareOptions & 27);
243                         }
244                 }
245
246                 #endregion Private Properties
247
248                 #region Public Methods
249
250                 public SqlString Clone() 
251                 {
252                         return new  SqlString (value, lcid, compareOptions);
253                 }
254
255                 public static CompareOptions CompareOptionsFromSqlCompareOptions (SqlCompareOptions compareOptions) 
256                 {
257                         CompareOptions options = CompareOptions.None;
258                         
259                         if ((compareOptions & SqlCompareOptions.IgnoreCase) != 0)
260                                 options |= CompareOptions.IgnoreCase;
261                         if ((compareOptions & SqlCompareOptions.IgnoreKanaType) != 0)
262                                 options |= CompareOptions.IgnoreKanaType;
263                         if ((compareOptions & SqlCompareOptions.IgnoreNonSpace) != 0)
264                                 options |= CompareOptions.IgnoreNonSpace;
265                         if ((compareOptions & SqlCompareOptions.IgnoreWidth) != 0)
266                                 options |= CompareOptions.IgnoreWidth;
267                         if ((compareOptions & SqlCompareOptions.BinarySort) != 0)
268                                 // FIXME: Exception string
269                                 throw new ArgumentOutOfRangeException (); 
270                         
271                         return options;         
272                 }
273
274                 // **********************************
275                 // Comparison Methods
276                 // **********************************
277
278                 public int CompareTo (object value)
279                 {
280                         if (value == null)
281                                 return 1;
282                         else if (!(value is SqlString))
283                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Data.SqlTypes.SqlString"));
284                         
285                         return CompareSqlString ((SqlString)value);
286                 }
287
288                 
289                 private int CompareSqlString (SqlString value)
290                 {
291                         if (value.IsNull)
292                                 return 1;
293                         else if (value.CompareOptions != this.CompareOptions)
294                                 throw new SqlTypeException (Locale.GetText ("Two strings to be compared have different collation"));
295 //                      else
296 //                              return String.Compare (this.value, ((SqlString)value).Value, (this.SqlCompareOptions & SqlCompareOptions.IgnoreCase) != 0, this.CultureInfo);
297                         return CultureInfo.CompareInfo.Compare (this.value, value.Value, this.CompareOptions);
298                 }
299
300                 public static SqlString Concat(SqlString x, SqlString y) 
301                 {
302                         return (x + y);
303                 }
304
305                 public override bool Equals(object value) 
306                 {
307                         if (!(value is SqlString))
308                                 return false;
309                         if (this.IsNull && ((SqlString)value).IsNull)
310                                 return true;
311                         else if (((SqlString)value).IsNull)
312                                 return false;
313                         else
314                                 return (bool) (this == (SqlString)value);
315                 }
316
317                 public static SqlBoolean Equals(SqlString x, SqlString y) 
318                 {
319                         return (x == y);
320                 }
321
322                 public override int GetHashCode() 
323                 {
324                         int result = 10;
325                         for (int i = 0; i < value.Length; i++)
326                                 result = 91 * result + (int)(value [i] ^ (value [i] >> 32));
327                                                 
328                         result = 91 * result + lcid.GetHashCode ();
329                         result = 91 * result + (int)compareOptions;
330
331                         return result;
332                 }
333
334                 public byte[] GetNonUnicodeBytes() 
335                 {
336                         byte [] bytes = new byte [value.Length];
337
338                         for (int i = 0; i < bytes.Length; i++) 
339                                 bytes [i] = (byte)value [i];
340
341                         return bytes;
342                 }
343
344                 public byte[] GetUnicodeBytes() 
345                 {
346                         byte [] bytes = new byte [value.Length * 2];
347                         
348                         int j = 0;
349                         for (int i = 0; i < value.Length; i++) {                                
350                                 bytes [j] = (byte)(value [i] & 0x0000FFFF);
351                                 bytes [j + 1] = (byte)((value [i] & 0xFFFF0000) >> 16);
352                                 j += 2;
353                         }
354                         
355                         return bytes;
356                 }
357
358                 public static SqlBoolean GreaterThan(SqlString x, SqlString y) 
359                 {
360                         return (x > y);
361                 }
362
363                 public static SqlBoolean GreaterThanOrEqual(SqlString x, SqlString y) 
364                 {
365                         return (x >= y);
366                 }
367
368                 public static SqlBoolean LessThan(SqlString x, SqlString y) 
369                 {
370                         return (x < y);
371                 }
372
373                 public static SqlBoolean LessThanOrEqual(SqlString x, SqlString y) 
374                 {
375                         return (x <= y);
376                 }
377
378                 public static SqlBoolean NotEquals(SqlString x, SqlString y) 
379                 {
380                         return (x != y);
381                 }
382
383                 // ****************************************
384                 // Type Conversions From SqlString To ...
385                 // ****************************************
386
387                 public SqlBoolean ToSqlBoolean() 
388                 {
389                         return ((SqlBoolean)this);
390                 }
391
392                 public SqlByte ToSqlByte() 
393                 {
394                         return ((SqlByte)this);
395                 }
396
397                 public SqlDateTime ToSqlDateTime() 
398                 {
399                         return ((SqlDateTime)this);
400                 }
401
402                 public SqlDecimal ToSqlDecimal() 
403                 {
404                         return ((SqlDecimal)this);
405                 }
406
407                 public SqlDouble ToSqlDouble() 
408                 {
409                         return ((SqlDouble)this);
410                 }
411
412                 public SqlGuid ToSqlGuid() 
413                 {
414                         return ((SqlGuid)this);
415                 }
416
417                 public SqlInt16 ToSqlInt16() 
418                 {
419                         return ((SqlInt16)this);
420                 }
421
422                 public SqlInt32 ToSqlInt32() 
423                 {
424                         return ((SqlInt32)this);
425                 }
426
427                 public SqlInt64 ToSqlInt64() 
428                 {
429                         return ((SqlInt64)this);
430                 }
431
432                 public SqlMoney ToSqlMoney() 
433                 {
434                         return ((SqlMoney)this);
435                 }
436
437                 public SqlSingle ToSqlSingle() 
438                 {
439                         return ((SqlSingle)this);
440                 }
441
442                 public override string ToString() 
443                 {
444                         if (!notNull)
445                                 return "Null";
446                         return ((string)this);
447                 }
448
449                 // ***********************************
450                 // Operators
451                 // ***********************************
452
453                 // Concatenates
454                 public static SqlString operator + (SqlString x, SqlString y) 
455                 {
456                          if (x.IsNull || y.IsNull)
457                                 return SqlString.Null;
458
459                         if (( x == null) || (y == null))
460                                 return SqlString.Null;
461                         
462                         return new SqlString (x.Value + y.Value);
463                 }
464
465                 // Equality
466                 public static SqlBoolean operator == (SqlString x, SqlString y) 
467                 {
468                         if (x.IsNull || y.IsNull)
469                                 return SqlBoolean.Null;
470                         else
471                                 return new SqlBoolean (x.Value == y.Value);
472                 }
473
474                 // Greater Than
475                 public static SqlBoolean operator > (SqlString x, SqlString y) 
476                 {
477                         if (x.IsNull || y.IsNull)
478                                 return SqlBoolean.Null;
479                         else
480                                 return new SqlBoolean (x.CompareTo (y) > 0);
481                 }
482
483                 // Greater Than Or Equal
484                 public static SqlBoolean operator >= (SqlString x, SqlString y) 
485                 {
486                         if (x.IsNull || y.IsNull)
487                                 return SqlBoolean.Null;
488                         else
489                                 return new SqlBoolean (x.CompareTo (y) >= 0);
490                 }
491
492                 public static SqlBoolean operator != (SqlString x, SqlString y) 
493                 { 
494                         if (x.IsNull || y.IsNull)
495                                 return SqlBoolean.Null;
496                         else
497                                 return new SqlBoolean (x.Value != y.Value);
498                 }
499
500                 // Less Than
501                 public static SqlBoolean operator < (SqlString x, SqlString y) 
502                 {
503                         if (x.IsNull || y.IsNull)
504                                 return SqlBoolean.Null;
505                         else
506                                 return new SqlBoolean (x.CompareTo (y) < 0);
507                 }
508
509                 // Less Than Or Equal
510                 public static SqlBoolean operator <= (SqlString x, SqlString y) 
511                 {
512                         if (x.IsNull || y.IsNull)
513                                 return SqlBoolean.Null;
514                         else
515                                 return new SqlBoolean (x.CompareTo (y) <= 0);
516                 }
517
518                 // **************************************
519                 // Type Conversions
520                 // **************************************
521
522                 public static explicit operator SqlString (SqlBoolean x) 
523                 {
524                         if (x.IsNull)
525                                 return Null;
526                         else
527                                 return new SqlString (x.Value.ToString ());
528                 }
529
530                 public static explicit operator SqlString (SqlByte x) 
531                 {
532                         if (x.IsNull)
533                                 return Null;
534                         else
535                                 return new SqlString (x.Value.ToString ());
536                 }
537
538                 public static explicit operator SqlString (SqlDateTime x) 
539                 {
540                         if (x.IsNull)
541                                 return Null;
542                         else
543                                 return new SqlString (x.Value.ToString ());
544                 }
545
546                 public static explicit operator SqlString (SqlDecimal x)
547                 {
548                         if (x.IsNull)
549                                 return Null;
550                         else
551                                 return new SqlString (x.Value.ToString ());
552                                 // return new SqlString (x.Value.ToString ("N", DecimalFormat));
553                 }
554
555                 public static explicit operator SqlString (SqlDouble x) 
556                 {
557                         if (x.IsNull)
558                                 return Null;
559                         else
560                                 return new SqlString (x.Value.ToString ());
561                 }
562
563                 public static explicit operator SqlString (SqlGuid x) 
564                 {
565                         if (x.IsNull)
566                                 return Null;
567                         else
568                                 return new SqlString (x.Value.ToString ());
569                 }
570
571                 public static explicit operator SqlString (SqlInt16 x) 
572                 {
573                         if (x.IsNull)
574                                 return Null;
575                         else
576                                 return new SqlString (x.Value.ToString ());
577                 }
578
579                 public static explicit operator SqlString (SqlInt32 x) 
580                 {
581                         if (x.IsNull)
582                                 return Null;
583                         else
584                                 return new SqlString (x.Value.ToString ());
585                 }
586
587                 public static explicit operator SqlString (SqlInt64 x) 
588                 {
589                         if (x.IsNull)
590                                 return Null;
591                         else
592                                 return new SqlString (x.Value.ToString ());
593                 }
594
595                 public static explicit operator SqlString (SqlMoney x) 
596                 {
597                         if (x.IsNull)
598                                 return Null;
599                         else
600                                 return new SqlString (x.ToString ());
601                 }
602
603                 public static explicit operator SqlString (SqlSingle x) 
604                 {
605                         if (x.IsNull)
606                                 return Null;
607                         else
608                                 return new SqlString (x.Value.ToString ());
609                 }
610
611                 public static explicit operator string (SqlString x) 
612                 {
613                         return x.Value;
614                 }
615
616                 public static implicit operator SqlString (string x) 
617                 {
618                         return new SqlString (x);
619                 }
620
621                 #if NET_2_0
622                 public static SqlString Add (SqlString x, SqlString y)
623                 {
624                         return ( x + y);
625                                                                                                     
626                 }
627
628                 public int CompareTo (SqlString value)
629                 {
630                         return CompareSqlString (value);
631                 }
632                 #endif
633
634
635
636                 #endregion // Public Methods
637         }
638 }