2005-04-12 Dick Porter <dick@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 readonly NumberFormatInfo MoneyFormat;
68                 internal static NumberFormatInfo DecimalFormat;
69                 #endregion // Fields
70
71                 #region Constructors
72
73                 static SqlString ()
74                 {
75                         MoneyFormat = (NumberFormatInfo) NumberFormatInfo.InvariantInfo.Clone ();
76                         MoneyFormat.NumberDecimalDigits = 4;
77                         MoneyFormat.NumberGroupSeparator = String.Empty;
78
79                         DecimalFormat = (NumberFormatInfo) NumberFormatInfo.InvariantInfo.Clone ();
80                         DecimalFormat.NumberDecimalDigits = 13;
81                         DecimalFormat.NumberGroupSeparator = String.Empty;
82                 }
83
84                 // init with a string data
85                 public SqlString (string data) 
86                 {
87                         this.value = data;
88                         lcid = CultureInfo.CurrentCulture.LCID;
89                         notNull = true;
90                         this.compareOptions = SqlCompareOptions.IgnoreCase |
91                                 SqlCompareOptions.IgnoreKanaType |
92                                 SqlCompareOptions.IgnoreWidth;
93                 }
94
95                 // init with a string data and locale id values.
96                 public SqlString (string data, int lcid) 
97                 {
98                         this.value = data;
99                         this.lcid = lcid;
100                         notNull = true;
101                         this.compareOptions = SqlCompareOptions.IgnoreCase |
102                                 SqlCompareOptions.IgnoreKanaType |
103                                 SqlCompareOptions.IgnoreWidth;
104                 }
105
106                 // init with locale id, compare options, 
107                 // and an array of bytes data
108                 public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data) 
109                         : this (lcid, compareOptions, data, true) { }
110
111                 // init with string data, locale id, and compare options
112                 public SqlString (string data, int lcid, SqlCompareOptions compareOptions) 
113                 {
114                         this.value = data;
115                         this.lcid = lcid;
116                         this.compareOptions = compareOptions;
117                         notNull = true;
118                 }
119
120                 // init with locale id, compare options, array of bytes data,
121                 // and whether unicode is encoded or not
122                 public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data, bool fUnicode) 
123                 {
124                         char [] chars;
125
126                         if (fUnicode)
127                                 chars = new char [data.Length/2];
128                         else
129                                 chars = new char [data.Length];
130                         
131                         int j = 0;
132                         for (int i = 0; i < chars.Length; i++) {
133
134                                 if (fUnicode) {
135                                         chars [i] = (char)(data [j] << 16);
136                                         chars [i] += (char)data [j + 1];
137                                         j += 2;
138                                 } else {
139                                         chars [i] = (char)data[i];
140                                 }
141                         }
142                                 
143                         this.value = new String (chars);
144                         this.lcid = lcid;
145                         this.compareOptions = compareOptions;
146                         notNull = true;
147                 }
148
149                 // init with locale id, compare options, array of bytes data,
150                 // starting index in the byte array, 
151                 // and number of bytes to copy
152                 public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data, 
153                                   int index, int count) 
154                         : this (lcid, compareOptions, data, index, count, true) { }
155
156                 // init with locale id, compare options, array of bytes data,
157                 // starting index in the byte array, number of byte to copy,
158                 // and whether unicode is encoded or not
159                 public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data, int index, int count, bool fUnicode) 
160                 {                      
161                         char [] chars;
162
163                         if (fUnicode)
164                                 chars = new char [(count - index) / 2];
165                         else
166                                 chars = new char [count - index];
167
168                         if (index >= data.Length)
169                                 throw new ArgumentOutOfRangeException ("index");
170
171                         if ((index + count) > data.Length)
172                                 throw new ArgumentOutOfRangeException ("count");
173
174                         int j = 0;
175                         for (int i = index; i < chars.Length; i++) {
176                                 
177                                 if (fUnicode) {
178                                         chars [i] = (char)(data[j] << 16);
179                                         chars [i] += (char)data[j+1];
180                                         j += 2;
181                                 } else {
182                                         chars [i] = (char)data [j];
183                                         j++;
184                                 }
185                         }
186
187                         this.value = new String (chars);
188                         this.lcid = lcid;
189                         this.compareOptions = compareOptions;
190                         notNull = true;
191                 }
192
193                 #endregion // Constructors
194
195
196                 #region Public Properties
197
198                 public CompareInfo CompareInfo {
199                         get { 
200                                 return new CultureInfo (lcid).CompareInfo;
201                         }
202                 }
203
204                 public CultureInfo CultureInfo {
205                         get { 
206                                 return new CultureInfo (lcid);
207                         }
208                 }
209
210                 public bool IsNull {
211                         get { return !notNull; }
212                 }
213
214                 // geographics location and language (locale id)
215                 public int LCID {
216                         get { 
217                                 return lcid;
218                         }
219                 }
220         
221                 public SqlCompareOptions SqlCompareOptions {
222                         get { 
223                                 return compareOptions;
224                         }
225                 }
226
227                 public string Value {
228                         get {
229                                 if (this.IsNull)
230                                         throw new SqlNullValueException (Locale.GetText ("The property contains Null."));
231                                 else
232                                         return value;
233                         }
234                 }
235
236                 #endregion // Public Properties\r
237 \r
238                 #region Private Properties\r
239 \r
240                 private CompareOptions CompareOptions {\r
241                         get {\r
242                                 return\r
243                                         (this.compareOptions & SqlCompareOptions.BinarySort) != 0 ?\r
244                                         CompareOptions.Ordinal :\r
245                                         // 27 == all SqlCompareOptions - BinarySort \r
246                                         // (1,2,8,24 are common to CompareOptions)\r
247                                         (CompareOptions)((int)this.compareOptions & 27);\r
248                         }\r
249                 }\r
250 \r
251                 #endregion Private Properties
252
253                 #region Public Methods
254
255                 public SqlString Clone() 
256                 {
257                         return new  SqlString (value, lcid, compareOptions);
258                 }
259
260                 public static CompareOptions CompareOptionsFromSqlCompareOptions (SqlCompareOptions compareOptions) 
261                 {
262                         CompareOptions options = CompareOptions.None;
263                         
264                         if ((compareOptions & SqlCompareOptions.IgnoreCase) != 0)
265                                 options |= CompareOptions.IgnoreCase;
266                         if ((compareOptions & SqlCompareOptions.IgnoreKanaType) != 0)
267                                 options |= CompareOptions.IgnoreKanaType;
268                         if ((compareOptions & SqlCompareOptions.IgnoreNonSpace) != 0)
269                                 options |= CompareOptions.IgnoreNonSpace;
270                         if ((compareOptions & SqlCompareOptions.IgnoreWidth) != 0)
271                                 options |= CompareOptions.IgnoreWidth;
272                         if ((compareOptions & SqlCompareOptions.BinarySort) != 0)
273                                 // FIXME: Exception string
274                                 throw new ArgumentOutOfRangeException (); 
275                         
276                         return options;         
277                 }
278
279                 // **********************************
280                 // Comparison Methods
281                 // **********************************
282
283                 public int CompareTo (object value)
284                 {
285                         if (value == null)
286                                 return 1;
287                         else if (!(value is SqlString))
288                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Data.SqlTypes.SqlString"));
289                         
290                         return CompareSqlString ((SqlString)value);
291                 }
292
293                 
294                 private int CompareSqlString (SqlString value)
295                 {
296                         if (value.IsNull)
297                                 return 1;
298                         else if (value.CompareOptions != this.CompareOptions)
299                                 throw new SqlTypeException (Locale.GetText ("Two strings to be compared have different collation"));
300 //                      else
301 //                              return String.Compare (this.value, ((SqlString)value).Value, (this.SqlCompareOptions & SqlCompareOptions.IgnoreCase) != 0, this.CultureInfo);
302                         return CultureInfo.CompareInfo.Compare (this.value, value.Value, this.CompareOptions);
303                 }
304
305                 public static SqlString Concat(SqlString x, SqlString y) 
306                 {
307                         return (x + y);
308                 }
309
310                 public override bool Equals(object value) 
311                 {
312                         if (!(value is SqlString))
313                                 return false;
314                         if (this.IsNull && ((SqlString)value).IsNull)
315                                 return true;
316                         else if (((SqlString)value).IsNull)
317                                 return false;
318                         else
319                                 return (bool) (this == (SqlString)value);
320                 }
321
322                 public static SqlBoolean Equals(SqlString x, SqlString y) 
323                 {
324                         return (x == y);
325                 }
326
327                 public override int GetHashCode() 
328                 {
329                         int result = 10;
330                         for (int i = 0; i < value.Length; i++)
331                                 result = 91 * result + (int)(value [i] ^ (value [i] >> 32));
332                                                 
333                         result = 91 * result + lcid.GetHashCode ();
334                         result = 91 * result + (int)compareOptions;
335
336                         return result;
337                 }
338
339                 public byte[] GetNonUnicodeBytes() 
340                 {
341                         byte [] bytes = new byte [value.Length];
342
343                         for (int i = 0; i < bytes.Length; i++) 
344                                 bytes [i] = (byte)value [i];
345
346                         return bytes;
347                 }
348
349                 public byte[] GetUnicodeBytes() 
350                 {
351                         byte [] bytes = new byte [value.Length * 2];
352                         
353                         int j = 0;
354                         for (int i = 0; i < value.Length; i++) {                                
355                                 bytes [j] = (byte)(value [i] & 0x0000FFFF);
356                                 bytes [j + 1] = (byte)((value [i] & 0xFFFF0000) >> 16);
357                                 j += 2;
358                         }
359                         
360                         return bytes;
361                 }
362
363                 public static SqlBoolean GreaterThan(SqlString x, SqlString y) 
364                 {
365                         return (x > y);
366                 }
367
368                 public static SqlBoolean GreaterThanOrEqual(SqlString x, SqlString y) 
369                 {
370                         return (x >= y);
371                 }
372
373                 public static SqlBoolean LessThan(SqlString x, SqlString y) 
374                 {
375                         return (x < y);
376                 }
377
378                 public static SqlBoolean LessThanOrEqual(SqlString x, SqlString y) 
379                 {
380                         return (x <= y);
381                 }
382
383                 public static SqlBoolean NotEquals(SqlString x, SqlString y) 
384                 {
385                         return (x != y);
386                 }
387
388                 // ****************************************
389                 // Type Conversions From SqlString To ...
390                 // ****************************************
391
392                 public SqlBoolean ToSqlBoolean() 
393                 {
394                         return ((SqlBoolean)this);
395                 }
396
397                 public SqlByte ToSqlByte() 
398                 {
399                         return ((SqlByte)this);
400                 }
401
402                 public SqlDateTime ToSqlDateTime() 
403                 {
404                         return ((SqlDateTime)this);
405                 }
406
407                 public SqlDecimal ToSqlDecimal() 
408                 {
409                         return ((SqlDecimal)this);
410                 }
411
412                 public SqlDouble ToSqlDouble() 
413                 {
414                         return ((SqlDouble)this);
415                 }
416
417                 public SqlGuid ToSqlGuid() 
418                 {
419                         return ((SqlGuid)this);
420                 }
421
422                 public SqlInt16 ToSqlInt16() 
423                 {
424                         return ((SqlInt16)this);
425                 }
426
427                 public SqlInt32 ToSqlInt32() 
428                 {
429                         return ((SqlInt32)this);
430                 }
431
432                 public SqlInt64 ToSqlInt64() 
433                 {
434                         return ((SqlInt64)this);
435                 }
436
437                 public SqlMoney ToSqlMoney() 
438                 {
439                         return ((SqlMoney)this);
440                 }
441
442                 public SqlSingle ToSqlSingle() 
443                 {
444                         return ((SqlSingle)this);
445                 }
446
447                 public override string ToString() 
448                 {
449                         if (!notNull)
450                                 return "Null";
451                         return ((string)this);
452                 }
453
454                 // ***********************************
455                 // Operators
456                 // ***********************************
457
458                 // Concatenates
459                 public static SqlString operator + (SqlString x, SqlString y) 
460                 {
461                          if (x.IsNull || y.IsNull)
462                                 return SqlString.Null;
463
464                         if (( x == null) || (y == null))
465                                 return SqlString.Null;
466                         
467                         return new SqlString (x.Value + y.Value);
468                 }
469
470                 // Equality
471                 public static SqlBoolean operator == (SqlString x, SqlString y) 
472                 {
473                         if (x.IsNull || y.IsNull)
474                                 return SqlBoolean.Null;
475                         else
476                                 return new SqlBoolean (x.Value == y.Value);
477                 }
478
479                 // Greater Than
480                 public static SqlBoolean operator > (SqlString x, SqlString y) 
481                 {
482                         if (x.IsNull || y.IsNull)
483                                 return SqlBoolean.Null;
484                         else
485                                 return new SqlBoolean (x.CompareTo (y) > 0);
486                 }
487
488                 // Greater Than Or Equal
489                 public static SqlBoolean operator >= (SqlString x, SqlString y) 
490                 {
491                         if (x.IsNull || y.IsNull)
492                                 return SqlBoolean.Null;
493                         else
494                                 return new SqlBoolean (x.CompareTo (y) >= 0);
495                 }
496
497                 public static SqlBoolean operator != (SqlString x, SqlString y) 
498                 { 
499                         if (x.IsNull || y.IsNull)
500                                 return SqlBoolean.Null;
501                         else
502                                 return new SqlBoolean (x.Value != y.Value);
503                 }
504
505                 // Less Than
506                 public static SqlBoolean operator < (SqlString x, SqlString y) 
507                 {
508                         if (x.IsNull || y.IsNull)
509                                 return SqlBoolean.Null;
510                         else
511                                 return new SqlBoolean (x.CompareTo (y) < 0);
512                 }
513
514                 // Less Than Or Equal
515                 public static SqlBoolean operator <= (SqlString x, SqlString y) 
516                 {
517                         if (x.IsNull || y.IsNull)
518                                 return SqlBoolean.Null;
519                         else
520                                 return new SqlBoolean (x.CompareTo (y) <= 0);
521                 }
522
523                 // **************************************
524                 // Type Conversions
525                 // **************************************
526
527                 public static explicit operator SqlString (SqlBoolean 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 (SqlByte 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 (SqlDateTime 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 (SqlDecimal x)
552                 {
553                         if (x.IsNull)
554                                 return Null;
555                         else
556                                 return new SqlString (x.Value.ToString ());
557                                 // return new SqlString (x.Value.ToString ("N", DecimalFormat));
558                 }
559
560                 public static explicit operator SqlString (SqlDouble x) 
561                 {
562                         if (x.IsNull)
563                                 return Null;
564                         else
565                                 return new SqlString (x.Value.ToString ());
566                 }
567
568                 public static explicit operator SqlString (SqlGuid 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 SqlString (SqlInt16 x) 
577                 {
578                         if (x.IsNull)
579                                 return Null;
580                         else
581                                 return new SqlString (x.Value.ToString ());
582                 }
583
584                 public static explicit operator SqlString (SqlInt32 x) 
585                 {
586                         if (x.IsNull)
587                                 return Null;
588                         else
589                                 return new SqlString (x.Value.ToString ());
590                 }
591
592                 public static explicit operator SqlString (SqlInt64 x) 
593                 {
594                         if (x.IsNull)
595                                 return Null;
596                         else
597                                 return new SqlString (x.Value.ToString ());
598                 }
599
600                 public static explicit operator SqlString (SqlMoney x) 
601                 {
602                         if (x.IsNull)
603                                 return Null;
604                         else
605                                 return new SqlString (x.Value.ToString ());
606                                 // return new SqlString (x.Value.ToString ("N", MoneyFormat));
607                 }
608
609                 public static explicit operator SqlString (SqlSingle x) 
610                 {
611                         if (x.IsNull)
612                                 return Null;
613                         else
614                                 return new SqlString (x.Value.ToString ());
615                 }
616
617                 public static explicit operator string (SqlString x) 
618                 {
619                         return x.Value;
620                 }
621
622                 public static implicit operator SqlString (string x) 
623                 {
624                         return new SqlString (x);
625                 }
626
627                 #if NET_2_0
628                 public static SqlString Add (SqlString x, SqlString y)
629                 {
630                         return ( x + y);
631                                                                                                     
632                 }
633
634                 public int CompareTo (SqlString value)
635                 {
636                         return CompareSqlString (value);
637                 }
638                 #endif
639
640
641
642                 #endregion // Public Methods
643         }
644 }