Update VS project files
[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.Xml;
39 using System.Text;
40 using System.Threading;
41 using System.Xml.Schema;
42 using System.Globalization;
43 using System.Xml.Serialization;
44
45 namespace System.Data.SqlTypes
46 {
47         /// <summary>
48         /// A variable-length stream of characters 
49         /// to be stored in or retrieved from the database
50         /// </summary>
51 #if NET_2_0
52         [SerializableAttribute]
53         [XmlSchemaProvider ("GetXsdType")]
54 #endif
55         public struct SqlString : INullable, IComparable 
56 #if NET_2_0
57                                 , IXmlSerializable
58 #endif
59         {
60
61                 #region Fields
62
63                 string value;
64
65                 private bool notNull;
66
67                 // FIXME: locale id is not working yet
68                 private int lcid;
69                 private SqlCompareOptions compareOptions;
70
71                 public static readonly int BinarySort = 0x8000;
72                 public static readonly int IgnoreCase = 0x1;
73                 public static readonly int IgnoreKanaType = 0x8;
74                 public static readonly int IgnoreNonSpace = 0x2;
75                 public static readonly int IgnoreWidth = 0x10;
76                 public static readonly SqlString Null;
77
78                 internal static NumberFormatInfo DecimalFormat;
79                 #endregion // Fields
80
81                 #region Constructors
82
83                 static SqlString ()
84                 {
85                         DecimalFormat = (NumberFormatInfo) NumberFormatInfo.InvariantInfo.Clone ();
86                         DecimalFormat.NumberDecimalDigits = 13;
87                         DecimalFormat.NumberGroupSeparator = String.Empty;
88                 }
89
90                 // init with a string data
91                 public SqlString (string data) 
92                 {
93                         this.value = data;
94                         lcid = CultureInfo.CurrentCulture.LCID;
95                         if (value != null)
96                                 notNull = true;
97                         else
98                                 notNull = false;
99                         this.compareOptions = SqlCompareOptions.IgnoreCase |
100                                 SqlCompareOptions.IgnoreKanaType |
101                                 SqlCompareOptions.IgnoreWidth;
102                 }
103
104                 // init with a string data and locale id values.
105                 public SqlString (string data, int lcid) 
106                 {
107                         this.value = data;
108                         this.lcid = lcid;
109                         if (value != null)
110                                 notNull = true;
111                         else
112                                 notNull = false;
113                         this.compareOptions = SqlCompareOptions.IgnoreCase |
114                                 SqlCompareOptions.IgnoreKanaType |
115                                 SqlCompareOptions.IgnoreWidth;
116                 }
117
118                 // init with locale id, compare options, 
119                 // and an array of bytes data
120                 public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data) 
121                         : this (lcid, compareOptions, data, true) { }
122
123                 // init with string data, locale id, and compare options
124                 public SqlString (string data, int lcid, SqlCompareOptions compareOptions) 
125                 {
126                         this.value = data;
127                         this.lcid = lcid;
128                         this.compareOptions = compareOptions;
129                         if (value != null)
130                                 notNull = true;
131                         else
132                                 notNull = false;
133                 }
134
135                 // init with locale id, compare options, array of bytes data,
136                 // and whether unicode is encoded or not
137                 public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data, bool fUnicode) 
138                 {
139                         Encoding encoding = (fUnicode ? Encoding.Unicode : Encoding.ASCII);
140                         this.value = encoding.GetString (data);
141                         this.lcid = lcid;
142                         this.compareOptions = compareOptions;
143                         if (value != null)
144                                 notNull = true;
145                         else
146                                 notNull = false;
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                         Encoding encoding = (fUnicode ? Encoding.Unicode : Encoding.ASCII);
162                         this.value = encoding.GetString (data, index, count);
163                         this.lcid = lcid;
164                         this.compareOptions = compareOptions;
165                         if (value != null)
166                                 notNull = true;
167                         else
168                                 notNull = false;
169                 }
170
171                 #endregion // Constructors
172
173
174                 #region Public Properties
175
176                 public CompareInfo CompareInfo {
177                         get { 
178                                 return new CultureInfo (lcid).CompareInfo;
179                         }
180                 }
181
182                 public CultureInfo CultureInfo {
183                         get { 
184                                 return new CultureInfo (lcid);
185                         }
186                 }
187
188                 public bool IsNull {
189                         get { return !notNull; }
190                 }
191
192                 // geographics location and language (locale id)
193                 public int LCID {
194                         get { 
195                                 return lcid;
196                         }
197                 }
198         
199                 public SqlCompareOptions SqlCompareOptions {
200                         get { 
201                                 return compareOptions;
202                         }
203                 }
204
205                 public string Value {
206                         get {
207                                 if (this.IsNull)
208                                         throw new SqlNullValueException (Locale.GetText ("The property contains Null."));
209                                 else
210                                         return value;
211                         }
212                 }
213
214                 #endregion // Public Properties
215
216                 #region Private Properties
217
218                 private CompareOptions CompareOptions {
219                         get {
220                                 return
221                                         (this.compareOptions & SqlCompareOptions.BinarySort) != 0 ?
222                                         CompareOptions.Ordinal :
223                                         // 27 == all SqlCompareOptions - BinarySort 
224                                         // (1,2,8,24 are common to CompareOptions)
225                                         (CompareOptions)((int)this.compareOptions & 27);
226                         }
227                 }
228
229                 #endregion Private Properties
230
231                 #region Public Methods
232
233                 public SqlString Clone() 
234                 {
235                         return new  SqlString (value, lcid, compareOptions);
236                 }
237
238                 public static CompareOptions CompareOptionsFromSqlCompareOptions (SqlCompareOptions compareOptions) 
239                 {
240                         CompareOptions options = CompareOptions.None;
241                         
242                         if ((compareOptions & SqlCompareOptions.IgnoreCase) != 0)
243                                 options |= CompareOptions.IgnoreCase;
244                         if ((compareOptions & SqlCompareOptions.IgnoreKanaType) != 0)
245                                 options |= CompareOptions.IgnoreKanaType;
246                         if ((compareOptions & SqlCompareOptions.IgnoreNonSpace) != 0)
247                                 options |= CompareOptions.IgnoreNonSpace;
248                         if ((compareOptions & SqlCompareOptions.IgnoreWidth) != 0)
249                                 options |= CompareOptions.IgnoreWidth;
250                         if ((compareOptions & SqlCompareOptions.BinarySort) != 0)
251                                 // FIXME: Exception string
252                                 throw new ArgumentOutOfRangeException (); 
253                         
254                         return options;         
255                 }
256
257                 // **********************************
258                 // Comparison Methods
259                 // **********************************
260
261                 public int CompareTo (object value)
262                 {
263                         if (value == null)
264                                 return 1;
265                         else if (!(value is SqlString))
266                                 throw new ArgumentException (Locale.GetText ("Value is not a System.Data.SqlTypes.SqlString"));
267                         
268                         return CompareSqlString ((SqlString)value);
269                 }
270
271                 
272                 private int CompareSqlString (SqlString value)
273                 {
274                         if (value.IsNull)
275                                 return 1;
276                         else if (value.CompareOptions != this.CompareOptions)
277                                 throw new SqlTypeException (Locale.GetText ("Two strings to be compared have different collation"));
278 //                      else
279 //                              return String.Compare (this.value, ((SqlString)value).Value, (this.SqlCompareOptions & SqlCompareOptions.IgnoreCase) != 0, this.CultureInfo);
280                         return CultureInfo.CompareInfo.Compare (this.value, value.Value, this.CompareOptions);
281                 }
282
283                 public static SqlString Concat(SqlString x, SqlString y) 
284                 {
285                         return (x + y);
286                 }
287
288                 public override bool Equals(object value) 
289                 {
290                         if (!(value is SqlString))
291                                 return false;
292                         if (this.IsNull)
293                                 return ((SqlString)value).IsNull;
294                         else if (((SqlString)value).IsNull)
295                                 return false;
296                         else
297                                 return (bool) (this == (SqlString)value);
298                 }
299
300                 public static SqlBoolean Equals(SqlString x, SqlString y) 
301                 {
302                         return (x == y);
303                 }
304
305                 public override int GetHashCode() 
306                 {
307                         int result = 10;
308                         for (int i = 0; i < value.Length; i++)
309                                 result = 91 * result + (int)(value [i] ^ (value [i] >> 32));
310                                                 
311                         result = 91 * result + lcid.GetHashCode ();
312                         result = 91 * result + (int)compareOptions;
313
314                         return result;
315                 }
316
317                 public byte[] GetNonUnicodeBytes() 
318                 {
319                         return Encoding.ASCII.GetBytes (value);
320                 }
321
322                 public byte[] GetUnicodeBytes() 
323                 {
324                         return Encoding.Unicode.GetBytes (value);
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                         if (!notNull)
414                                 return "Null";
415                         return ((string)this);
416                 }
417
418                 // ***********************************
419                 // Operators
420                 // ***********************************
421
422                 // Concatenates
423                 public static SqlString operator + (SqlString x, SqlString y) 
424                 {
425                          if (x.IsNull || y.IsNull)
426                                 return SqlString.Null;
427                         else
428                                 return new SqlString (x.Value + y.Value);
429                 }
430
431                 // Equality
432                 public static SqlBoolean operator == (SqlString x, SqlString y) 
433                 {
434                         if (x.IsNull || y.IsNull)
435                                 return SqlBoolean.Null;
436                         else
437                                 return new SqlBoolean (x.Value == y.Value);
438                 }
439
440                 // Greater Than
441                 public static SqlBoolean operator > (SqlString x, SqlString y) 
442                 {
443                         if (x.IsNull || y.IsNull)
444                                 return SqlBoolean.Null;
445                         else
446                                 return new SqlBoolean (x.CompareTo (y) > 0);
447                 }
448
449                 // Greater Than Or Equal
450                 public static SqlBoolean operator >= (SqlString x, SqlString y) 
451                 {
452                         if (x.IsNull || y.IsNull)
453                                 return SqlBoolean.Null;
454                         else
455                                 return new SqlBoolean (x.CompareTo (y) >= 0);
456                 }
457
458                 public static SqlBoolean operator != (SqlString x, SqlString y) 
459                 { 
460                         if (x.IsNull || y.IsNull)
461                                 return SqlBoolean.Null;
462                         else
463                                 return new SqlBoolean (x.Value != y.Value);
464                 }
465
466                 // Less Than
467                 public static SqlBoolean operator < (SqlString x, SqlString y) 
468                 {
469                         if (x.IsNull || y.IsNull)
470                                 return SqlBoolean.Null;
471                         else
472                                 return new SqlBoolean (x.CompareTo (y) < 0);
473                 }
474
475                 // Less Than Or Equal
476                 public static SqlBoolean operator <= (SqlString x, SqlString y) 
477                 {
478                         if (x.IsNull || y.IsNull)
479                                 return SqlBoolean.Null;
480                         else
481                                 return new SqlBoolean (x.CompareTo (y) <= 0);
482                 }
483
484                 // **************************************
485                 // Type Conversions
486                 // **************************************
487
488                 public static explicit operator SqlString (SqlBoolean x) 
489                 {
490                         if (x.IsNull)
491                                 return Null;
492                         else
493                                 return new SqlString (x.Value.ToString ());
494                 }
495
496                 public static explicit operator SqlString (SqlByte x) 
497                 {
498                         if (x.IsNull)
499                                 return Null;
500                         else
501                                 return new SqlString (x.Value.ToString ());
502                 }
503
504                 public static explicit operator SqlString (SqlDateTime x) 
505                 {
506                         if (x.IsNull)
507                                 return Null;
508                         else
509                                 return new SqlString (x.Value.ToString ());
510                 }
511
512                 public static explicit operator SqlString (SqlDecimal x)
513                 {
514                         if (x.IsNull)
515                                 return Null;
516                         else
517                                 return new SqlString (x.Value.ToString ());
518                                 // return new SqlString (x.Value.ToString ("N", DecimalFormat));
519                 }
520
521                 public static explicit operator SqlString (SqlDouble x) 
522                 {
523                         if (x.IsNull)
524                                 return Null;
525                         else
526                                 return new SqlString (x.Value.ToString ());
527                 }
528
529                 public static explicit operator SqlString (SqlGuid x) 
530                 {
531                         if (x.IsNull)
532                                 return Null;
533                         else
534                                 return new SqlString (x.Value.ToString ());
535                 }
536
537                 public static explicit operator SqlString (SqlInt16 x) 
538                 {
539                         if (x.IsNull)
540                                 return Null;
541                         else
542                                 return new SqlString (x.Value.ToString ());
543                 }
544
545                 public static explicit operator SqlString (SqlInt32 x) 
546                 {
547                         if (x.IsNull)
548                                 return Null;
549                         else
550                                 return new SqlString (x.Value.ToString ());
551                 }
552
553                 public static explicit operator SqlString (SqlInt64 x) 
554                 {
555                         if (x.IsNull)
556                                 return Null;
557                         else
558                                 return new SqlString (x.Value.ToString ());
559                 }
560
561                 public static explicit operator SqlString (SqlMoney x) 
562                 {
563                         if (x.IsNull)
564                                 return Null;
565                         else
566                                 return new SqlString (x.ToString ());
567                 }
568
569                 public static explicit operator SqlString (SqlSingle x) 
570                 {
571                         if (x.IsNull)
572                                 return Null;
573                         else
574                                 return new SqlString (x.Value.ToString ());
575                 }
576
577                 public static explicit operator string (SqlString x) 
578                 {
579                         return x.Value;
580                 }
581
582                 public static implicit operator SqlString (string x) 
583                 {
584                         return new SqlString (x);
585                 }
586
587 #if NET_2_0
588                 public static SqlString Add (SqlString x, SqlString y)
589                 {
590                         return (x + y);
591                 }
592
593                 public int CompareTo (SqlString value)
594                 {
595                         return CompareSqlString (value);
596                 }
597 #endif
598
599
600
601                 #endregion // Public Methods
602 #if NET_2_0
603                 public static XmlQualifiedName GetXsdType (XmlSchemaSet schemaSet)
604                 {
605                         if (schemaSet != null && schemaSet.Count == 0) {
606                                 XmlSchema xs = new XmlSchema ();
607                                 XmlSchemaComplexType ct = new XmlSchemaComplexType ();
608                                 ct.Name = "string";
609                                 xs.Items.Add (ct);
610                                 schemaSet.Add (xs);
611                         }
612                         return new XmlQualifiedName ("string", "http://www.w3.org/2001/XMLSchema");
613                 }
614
615                 XmlSchema IXmlSerializable.GetSchema ()
616                 {
617                         return null;
618                 }
619                 
620                 void IXmlSerializable.ReadXml (XmlReader reader)
621                 {
622                         if (reader == null)
623                                 return;
624
625                         switch (reader.ReadState) {
626                         case ReadState.EndOfFile:
627                         case ReadState.Error:
628                         case ReadState.Closed:
629                                 return;
630                         }
631                         // Skip XML declaration and prolog
632                         // or do I need to validate for the <string> tag?
633                         reader.MoveToContent ();
634                         if (reader.EOF)
635                                 return;
636                         
637                         reader.Read ();
638                         if (reader.NodeType == XmlNodeType.EndElement)
639                                 return;
640
641                         if (reader.Value.Length > 0) {
642                                 if (String.Compare ("Null", reader.Value) == 0) {
643                                         // means a null reference/invalid value
644                                         notNull = false;
645                                         return; 
646                                 }
647                                 // FIXME: Validate the value for expected format
648                                 this.value = reader.Value;
649                                 this.notNull = true;
650                                 this.compareOptions = SqlCompareOptions.IgnoreCase |
651                                         SqlCompareOptions.IgnoreKanaType |
652                                         SqlCompareOptions.IgnoreWidth;
653                         }
654                 }
655                 
656                 void IXmlSerializable.WriteXml (XmlWriter writer) 
657                 {
658                         writer.WriteString (this.ToString ());
659                 }
660 #endif
661         }
662 }