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