Update Reference Sources to .NET Framework 4.6.1
[mono.git] / mcs / class / referencesource / System.Data / System / Data / SQLTypes / SQLString.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="SqlString.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 //  </copyright>
5 // <owner current="true" primary="true">junfang</owner>
6 // <owner current="true" primary="false">[....]</owner>
7 // <owner current="true" primary="false">[....]</owner>
8 //------------------------------------------------------------------------------
9
10 //**************************************************************************
11 // @File: SqlString.cs
12 //
13 // Create by:    JunFang
14 //
15 // Purpose: Implementation of SqlString which is equivalent to
16 //            data type "nvarchar/varchar" in SQL Server
17 //
18 // Notes:
19 //
20 // History:
21 //
22 //   09/30/99  JunFang    Created.
23 //
24 // @EndHeader@
25 //**************************************************************************
26
27 using System;
28 using System.Data.Common;
29 using System.Globalization;
30 using System.Diagnostics;
31 using System.Runtime.InteropServices;
32 using System.Xml;
33 using System.Xml.Schema;
34 using System.Xml.Serialization;
35
36 namespace System.Data.SqlTypes {
37     using System.Text;
38     using System.Configuration.Assemblies;
39
40     // Options that are used in comparison
41         [Flags,Serializable]
42     public enum SqlCompareOptions {
43         None            = 0x00000000,
44         IgnoreCase      = 0x00000001,
45         IgnoreNonSpace  = 0x00000002,
46         IgnoreKanaType  = 0x00000008, // ignore kanatype
47         IgnoreWidth     = 0x00000010, // ignore width
48         BinarySort      = 0x00008000, // binary sorting
49         BinarySort2     = 0x00004000, // binary sorting 2
50         }
51
52     /// <devdoc>
53     ///    <para>
54     ///       Represents a variable-length stream of characters to be stored in or retrieved from the database.
55     ///    </para>
56     /// </devdoc>
57     [Serializable]
58     [StructLayout(LayoutKind.Sequential)]
59     [XmlSchemaProvider("GetXsdType")]
60     public struct SqlString : INullable, IComparable, IXmlSerializable {
61         private String            m_value;
62         private CompareInfo       m_cmpInfo;
63         private int               m_lcid;     // Locale Id
64         private SqlCompareOptions m_flag;     // Compare flags
65         private bool              m_fNotNull; // false if null
66
67         /// <devdoc>
68         ///    <para>
69         ///       Represents a null value that can be assigned to the <see cref='System.Data.SqlTypes.SqlString.Value'/> property of an instance of
70         ///       the <see cref='System.Data.SqlTypes.SqlString'/> class.
71         ///    </para>
72         /// </devdoc>
73         public  static readonly SqlString Null = new SqlString(true);
74
75         internal static readonly UnicodeEncoding x_UnicodeEncoding = new UnicodeEncoding();
76
77         /// <devdoc>
78         /// </devdoc>
79         public static readonly int IgnoreCase       = 0x1;
80         /// <devdoc>
81         /// </devdoc>
82         public static readonly int IgnoreWidth      = 0x10;
83         /// <devdoc>
84         /// </devdoc>
85         public static readonly int IgnoreNonSpace   = 0x2;
86         /// <devdoc>
87         /// </devdoc>
88         public static readonly int IgnoreKanaType   = 0x8;
89         /// <devdoc>
90         /// </devdoc>
91         public static readonly int BinarySort       = 0x8000;
92         /// <devdoc>
93         /// </devdoc>
94         public static readonly int BinarySort2      = 0x4000;
95
96         private static readonly SqlCompareOptions x_iDefaultFlag      =
97                     SqlCompareOptions.IgnoreCase | SqlCompareOptions.IgnoreKanaType |
98                     SqlCompareOptions.IgnoreWidth;
99         private static readonly CompareOptions x_iValidCompareOptionMask    =
100                     CompareOptions.IgnoreCase | CompareOptions.IgnoreWidth |
101                     CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreKanaType;
102
103         internal static readonly SqlCompareOptions x_iValidSqlCompareOptionMask    =
104                     SqlCompareOptions.IgnoreCase | SqlCompareOptions.IgnoreWidth |
105                     SqlCompareOptions.IgnoreNonSpace | SqlCompareOptions.IgnoreKanaType |
106                     SqlCompareOptions.BinarySort | SqlCompareOptions.BinarySort2;
107
108         internal static readonly int x_lcidUSEnglish    = 0x00000409;
109         private  static readonly int x_lcidBinary       = 0x00008200;
110
111
112         // constructor
113         // construct a Null
114         private SqlString(bool fNull) {
115             m_value     = null;
116             m_cmpInfo   = null;
117             m_lcid      = 0;
118             m_flag      = SqlCompareOptions.None;
119             m_fNotNull  = false;
120         }
121
122         // Constructor: Construct from both Unicode and NonUnicode data, according to fUnicode
123         /// <devdoc>
124         ///    <para>
125         ///       Initializes a new instance of the <see cref='System.Data.SqlTypes.SqlString'/> class.
126         ///    </para>
127         /// </devdoc>
128         public SqlString(int lcid, SqlCompareOptions compareOptions, byte[] data, int index, int count, bool fUnicode) {
129             m_lcid      = lcid;
130             ValidateSqlCompareOptions(compareOptions);
131             m_flag      = compareOptions;
132             if (data == null) {
133                 m_fNotNull  = false;
134                 m_value     = null;
135                 m_cmpInfo   = null;
136             }
137             else {
138                 m_fNotNull  = true;
139
140                                 // m_cmpInfo is set lazily, so that we don't need to pay the cost
141                                 // unless the string is used in comparison.
142                 m_cmpInfo   = null;
143
144                 if (fUnicode) {
145                     m_value = x_UnicodeEncoding.GetString(data, index, count);
146                 }
147                 else {
148                     CultureInfo culInfo = new CultureInfo(m_lcid);
149                     Encoding cpe = System.Text.Encoding.GetEncoding(culInfo.TextInfo.ANSICodePage);
150                     m_value = cpe.GetString(data, index, count);
151                 }
152             }
153         }
154
155         // Constructor: Construct from both Unicode and NonUnicode data, according to fUnicode
156         /// <devdoc>
157         ///    <para>
158         ///       Initializes a new instance of the <see cref='System.Data.SqlTypes.SqlString'/> class.
159         ///    </para>
160         /// </devdoc>
161         public SqlString(int lcid, SqlCompareOptions compareOptions, byte[] data, bool fUnicode)
162         : this(lcid, compareOptions, data, 0, data.Length, fUnicode) {
163         }
164
165         /// <devdoc>
166         ///    <para>
167         ///       Initializes a new instance of the <see cref='System.Data.SqlTypes.SqlString'/> class.
168         ///    </para>
169         /// </devdoc>
170         public SqlString(int lcid, SqlCompareOptions compareOptions, byte[] data, int index, int count)
171                         : this(lcid, compareOptions, data, index, count, true) {
172         }
173
174         /// <devdoc>
175         ///    <para>
176         ///       Initializes a new instance of the <see cref='System.Data.SqlTypes.SqlString'/> class.
177         ///    </para>
178         /// </devdoc>
179         public SqlString(int lcid, SqlCompareOptions compareOptions, byte[] data)
180                         : this(lcid, compareOptions, data, 0, data.Length, true) {
181         }
182
183 /*
184         // 
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202 */
203
204         /// <devdoc>
205         ///    <para>
206         ///       Initializes a new instance of the <see cref='System.Data.SqlTypes.SqlString'/> class.
207         ///    </para>
208         /// </devdoc>
209         public SqlString(String data, int lcid, SqlCompareOptions compareOptions) {
210             m_lcid      = lcid;
211             ValidateSqlCompareOptions(compareOptions);
212             m_flag      = compareOptions;
213             m_cmpInfo   = null;
214             if (data == null) {
215                 m_fNotNull  = false;
216                 m_value     = null;
217             }
218             else {
219                 m_fNotNull  = true;
220                 m_value     = data; // PERF: do not String.Copy
221             }
222         }
223
224         /// <devdoc>
225         ///    <para>
226         ///       Initializes a new instance of the <see cref='System.Data.SqlTypes.SqlString'/> class.
227         ///    </para>
228         /// </devdoc>
229         public SqlString(String data, int lcid) : this(data, lcid, x_iDefaultFlag) {
230         }
231
232         /// <devdoc>
233         ///    <para>
234         ///       Initializes a new instance of the <see cref='System.Data.SqlTypes.SqlString'/> class.
235         ///    </para>
236         /// </devdoc>
237         public SqlString(String data) : this(data, System.Globalization.CultureInfo.CurrentCulture.LCID, x_iDefaultFlag) {
238         }
239
240         private SqlString(int lcid, SqlCompareOptions compareOptions, String data, CompareInfo cmpInfo) {
241             m_lcid      = lcid;
242             ValidateSqlCompareOptions(compareOptions);
243             m_flag      = compareOptions;
244             if (data == null) {
245                 m_fNotNull  = false;
246                 m_value     = null;
247                 m_cmpInfo   = null;
248             }
249             else {
250                 m_value     = data;
251                 m_cmpInfo   = cmpInfo;
252                 m_fNotNull  = true;
253             }
254         }
255
256
257         // INullable
258         /// <devdoc>
259         ///    <para>
260         ///       Gets whether the <see cref='System.Data.SqlTypes.SqlString.Value'/> of the <see cref='System.Data.SqlTypes.SqlString'/> is <see cref='System.Data.SqlTypes.SqlString.Null'/>.
261         ///    </para>
262         /// </devdoc>
263         public bool IsNull {
264             get { return !m_fNotNull;}
265         }
266
267         // property: Value
268         /// <devdoc>
269         ///    <para>
270         ///       Gets the string that is to be stored.
271         ///    </para>
272         /// </devdoc>
273         public String Value {
274             get {
275                 if (!IsNull)
276                     return m_value;
277                 else
278                     throw new SqlNullValueException();
279             }
280         }
281
282         /// <devdoc>
283         ///    <para>[To be supplied.]</para>
284         /// </devdoc>
285         public int LCID {
286             get {
287                 if (!IsNull)
288                     return m_lcid;
289                 else
290                     throw new SqlNullValueException();
291             }
292         }
293
294         /// <devdoc>
295         ///    <para>[To be supplied.]</para>
296         /// </devdoc>
297         public CultureInfo CultureInfo {
298             get {
299                 if (!IsNull)
300                     return CultureInfo.GetCultureInfo(m_lcid);
301                 else
302                     throw new SqlNullValueException();
303             }
304         }
305
306         private void SetCompareInfo() {
307                         SQLDebug.Check(!IsNull);
308                         if (m_cmpInfo == null)
309                                 m_cmpInfo = (CultureInfo.GetCultureInfo(m_lcid)).CompareInfo;
310                 }
311
312         /// <devdoc>
313         ///    <para>[To be supplied.]</para>
314         /// </devdoc>
315         public CompareInfo CompareInfo {
316             get {
317                 if (!IsNull) {
318                                         SetCompareInfo();
319                     return m_cmpInfo;
320                                 }
321                 else
322                     throw new SqlNullValueException();
323             }
324         }
325
326         /// <devdoc>
327         ///    <para>[To be supplied.]</para>
328         /// </devdoc>
329         public SqlCompareOptions SqlCompareOptions {
330             get {
331                 if (!IsNull)
332                     return m_flag;
333                 else
334                     throw new SqlNullValueException();
335             }
336         }
337
338         // Implicit conversion from String to SqlString
339         /// <devdoc>
340         ///    <para>[To be supplied.]</para>
341         /// </devdoc>
342         public static implicit operator SqlString(String x) {
343             return new SqlString(x);
344         }
345
346         // Explicit conversion from SqlString to String. Throw exception if x is Null.
347         /// <devdoc>
348         ///    <para>[To be supplied.]</para>
349         /// </devdoc>
350         public static explicit operator String(SqlString x) {
351             return x.Value;
352         }
353
354         /// <devdoc>
355         ///    <para>
356         ///       Converts a <see cref='System.Data.SqlTypes.SqlString'/> object to a string.
357         ///    </para>
358         /// </devdoc>
359         public override String ToString() {
360             return IsNull ? SQLResource.NullString : m_value;
361         }
362
363         /// <devdoc>
364         ///    <para>[To be supplied.]</para>
365         /// </devdoc>
366         public byte[] GetUnicodeBytes() {
367             if (IsNull)
368                 return null;
369
370             return x_UnicodeEncoding.GetBytes(m_value);
371         }
372
373         /// <devdoc>
374         ///    <para>[To be supplied.]</para>
375         /// </devdoc>
376         public byte[] GetNonUnicodeBytes() {
377             if (IsNull)
378                 return null;
379
380             // Get the CultureInfo
381             CultureInfo culInfo = new CultureInfo(m_lcid);
382
383             Encoding cpe = System.Text.Encoding.GetEncoding(culInfo.TextInfo.ANSICodePage);
384             return cpe.GetBytes(m_value);
385         }
386
387 /*
388         internal int GetSQLCID() {
389             if (IsNull)
390                 throw new SqlNullValueException();
391
392             return MAKECID(m_lcid, m_flag);
393         }
394 */
395
396         // Binary operators
397
398         // Concatenation
399         /// <devdoc>
400         ///    <para>[To be supplied.]</para>
401         /// </devdoc>
402         public static SqlString operator +(SqlString x, SqlString y) {
403             if (x.IsNull || y.IsNull)
404                 return SqlString.Null;
405
406             if (x.m_lcid != y.m_lcid || x.m_flag != y.m_flag)
407                 throw new SqlTypeException(SQLResource.ConcatDiffCollationMessage);
408
409             return new SqlString(x.m_lcid, x.m_flag, x.m_value + y.m_value,
410                                         (x.m_cmpInfo == null) ? y.m_cmpInfo : x.m_cmpInfo);
411         }
412
413         // StringCompare: Common compare function which is used by Compare and CompareTo
414         //  In the case of Compare (used by comparison operators) the int result needs to be converted to SqlBoolean type
415         //  while CompareTo needs the result in int type
416         //  Pre-requisite: the null condition of the both string needs to be checked and handled by the caller of this function
417         private static int StringCompare(SqlString x, SqlString y)
418         {
419             SQLDebug.Check(!x.IsNull && !y.IsNull,
420                            "!x.IsNull && !y.IsNull", "Null condition should be handled by the caller of StringCompare method");
421
422             if (x.m_lcid != y.m_lcid || x.m_flag != y.m_flag)
423                 throw new SqlTypeException(SQLResource.CompareDiffCollationMessage);
424
425             x.SetCompareInfo();
426             y.SetCompareInfo();
427             SQLDebug.Check(x.FBinarySort() || (x.m_cmpInfo != null && y.m_cmpInfo != null),
428                            "x.FBinarySort() || (x.m_cmpInfo != null && y.m_cmpInfo != null)", "");
429
430             int iCmpResult;
431
432             if ((x.m_flag & SqlCompareOptions.BinarySort) != 0)
433                 iCmpResult = CompareBinary(x, y);
434             else if ((x.m_flag & SqlCompareOptions.BinarySort2) != 0)
435                 iCmpResult = CompareBinary2(x, y);
436             else {
437                 // SqlString can be padded with spaces (Padding is turn on by default in SQL Server 2008
438                 // Trim the trailing space for comparison
439                 //  Avoid using String.TrimEnd function to avoid extra string allocations
440
441                 string rgchX = x.m_value;
442                 string rgchY = y.m_value;
443                 int cwchX = rgchX.Length;
444                 int cwchY = rgchY.Length;
445
446                 while (cwchX > 0 && rgchX[cwchX - 1] == ' ')
447                     cwchX --;
448                 while (cwchY > 0 && rgchY[cwchY - 1] == ' ')
449                     cwchY --;
450
451                 CompareOptions options = CompareOptionsFromSqlCompareOptions(x.m_flag);
452
453                 iCmpResult = x.m_cmpInfo.Compare(x.m_value, 0, cwchX, y.m_value, 0, cwchY, options);
454             }
455
456             return iCmpResult;
457         }
458
459         // Comparison operators
460         private static SqlBoolean Compare(SqlString x, SqlString y, EComparison ecExpectedResult)
461         {
462             if (x.IsNull || y.IsNull)
463                 return SqlBoolean.Null;
464
465             int iCmpResult = StringCompare(x, y);
466
467             bool fResult = false;
468
469             switch (ecExpectedResult) {
470                 case EComparison.EQ:
471                     fResult = (iCmpResult == 0);
472                     break;
473
474                 case EComparison.LT:
475                     fResult = (iCmpResult < 0);
476                     break;
477
478                 case EComparison.LE:
479                     fResult = (iCmpResult <= 0);
480                     break;
481
482                 case EComparison.GT:
483                     fResult = (iCmpResult > 0);
484                     break;
485
486                 case EComparison.GE:
487                     fResult = (iCmpResult >= 0);
488                     break;
489
490                 default:
491                     SQLDebug.Check(false, "Invalid ecExpectedResult");
492                     return SqlBoolean.Null;
493             }
494
495             return new SqlBoolean(fResult);
496         }
497
498
499
500         // Implicit conversions
501
502
503
504         // Explicit conversions
505
506         // Explicit conversion from SqlBoolean to SqlString
507         /// <devdoc>
508         ///    <para>[To be supplied.]</para>
509         /// </devdoc>
510         public static explicit operator SqlString(SqlBoolean x) {
511             return x.IsNull ? Null : new SqlString((x.Value).ToString());
512         }
513
514         // Explicit conversion from SqlByte to SqlString
515         /// <devdoc>
516         ///    <para>[To be supplied.]</para>
517         /// </devdoc>
518         public static explicit operator SqlString(SqlByte x) {
519             return x.IsNull ? Null : new SqlString((x.Value).ToString((IFormatProvider)null));
520         }
521
522         // Explicit conversion from SqlInt16 to SqlString
523         /// <devdoc>
524         ///    <para>[To be supplied.]</para>
525         /// </devdoc>
526         public static explicit operator SqlString(SqlInt16 x) {
527             return x.IsNull ? Null : new SqlString((x.Value).ToString((IFormatProvider)null));
528         }
529
530         // Explicit conversion from SqlInt32 to SqlString
531         /// <devdoc>
532         ///    <para>[To be supplied.]</para>
533         /// </devdoc>
534         public static explicit operator SqlString(SqlInt32 x) {
535             return x.IsNull ? Null : new SqlString((x.Value).ToString((IFormatProvider)null));
536         }
537
538         // Explicit conversion from SqlInt64 to SqlString
539         /// <devdoc>
540         ///    <para>[To be supplied.]</para>
541         /// </devdoc>
542         public static explicit operator SqlString(SqlInt64 x) {
543             return x.IsNull ? Null : new SqlString((x.Value).ToString((IFormatProvider)null));
544         }
545
546         // Explicit conversion from SqlSingle to SqlString
547         /// <devdoc>
548         ///    <para>[To be supplied.]</para>
549         /// </devdoc>
550         public static explicit operator SqlString(SqlSingle x) {
551             return x.IsNull ? Null : new SqlString((x.Value).ToString((IFormatProvider)null));
552         }
553
554         // Explicit conversion from SqlDouble to SqlString
555         /// <devdoc>
556         ///    <para>[To be supplied.]</para>
557         /// </devdoc>
558         public static explicit operator SqlString(SqlDouble x) {
559             return x.IsNull ? Null : new SqlString((x.Value).ToString((IFormatProvider)null));
560         }
561
562         // Explicit conversion from SqlDecimal to SqlString
563         /// <devdoc>
564         ///    <para>[To be supplied.]</para>
565         /// </devdoc>
566         public static explicit operator SqlString(SqlDecimal x) {
567             return x.IsNull ? Null : new SqlString(x.ToString());
568         }
569
570         // Explicit conversion from SqlMoney to SqlString
571         /// <devdoc>
572         ///    <para>[To be supplied.]</para>
573         /// </devdoc>
574         public static explicit operator SqlString(SqlMoney x) {
575             return x.IsNull ? Null : new SqlString(x.ToString());
576         }
577
578         // Explicit conversion from SqlDateTime to SqlString
579         /// <devdoc>
580         ///    <para>[To be supplied.]</para>
581         /// </devdoc>
582         public static explicit operator SqlString(SqlDateTime x) {
583             return x.IsNull ? Null : new SqlString(x.ToString());
584         }
585
586         // Explicit conversion from SqlGuid to SqlString
587         /// <devdoc>
588         ///    <para>[To be supplied.]</para>
589         /// </devdoc>
590         public static explicit operator SqlString(SqlGuid x) {
591             return x.IsNull ? Null : new SqlString(x.ToString());
592         }
593
594         /// <devdoc>
595         ///    <para>[To be supplied.]</para>
596         /// </devdoc>
597         public SqlString Clone() {
598             if (IsNull)
599                 return new SqlString(true);
600             else {
601                 SqlString ret = new SqlString(m_value, m_lcid, m_flag);
602                 return ret;
603             }
604         }
605
606         // Overloading comparison operators
607         /// <devdoc>
608         ///    <para>[To be supplied.]</para>
609         /// </devdoc>
610         public static SqlBoolean operator==(SqlString x, SqlString y) {
611             return Compare(x, y, EComparison.EQ);
612         }
613
614         /// <devdoc>
615         ///    <para>[To be supplied.]</para>
616         /// </devdoc>
617         public static SqlBoolean operator!=(SqlString x, SqlString y) {
618             return ! (x == y);
619         }
620
621         /// <devdoc>
622         ///    <para>[To be supplied.]</para>
623         /// </devdoc>
624         public static SqlBoolean operator<(SqlString x, SqlString y) {
625             return Compare(x, y, EComparison.LT);
626         }
627
628         /// <devdoc>
629         ///    <para>[To be supplied.]</para>
630         /// </devdoc>
631         public static SqlBoolean operator>(SqlString x, SqlString y) {
632             return Compare(x, y, EComparison.GT);
633         }
634
635         /// <devdoc>
636         ///    <para>[To be supplied.]</para>
637         /// </devdoc>
638         public static SqlBoolean operator<=(SqlString x, SqlString y) {
639             return Compare(x, y, EComparison.LE);
640         }
641
642         /// <devdoc>
643         ///    <para>[To be supplied.]</para>
644         /// </devdoc>
645         public static SqlBoolean operator>=(SqlString x, SqlString y) {
646             return Compare(x, y, EComparison.GE);
647         }
648
649         //--------------------------------------------------
650         // Alternative methods for overloaded operators
651         //--------------------------------------------------
652
653         // Alternative method for operator +
654         public static SqlString Concat(SqlString x, SqlString y) {
655             return x + y;
656         }
657         
658         public static SqlString Add(SqlString x, SqlString y) {
659             return x + y;
660         }
661
662         // Alternative method for operator ==
663         public static SqlBoolean Equals(SqlString x, SqlString y) {
664             return (x == y);
665         }
666
667         // Alternative method for operator !=
668         public static SqlBoolean NotEquals(SqlString x, SqlString y) {
669             return (x != y);
670         }
671
672         // Alternative method for operator <
673         public static SqlBoolean LessThan(SqlString x, SqlString y) {
674             return (x < y);
675         }
676
677         // Alternative method for operator >
678         public static SqlBoolean GreaterThan(SqlString x, SqlString y) {
679             return (x > y);
680         }
681
682         // Alternative method for operator <=
683         public static SqlBoolean LessThanOrEqual(SqlString x, SqlString y) {
684             return (x <= y);
685         }
686
687         // Alternative method for operator >=
688         public static SqlBoolean GreaterThanOrEqual(SqlString x, SqlString y) {
689             return (x >= y);
690         }
691
692         // Alternative method for conversions.
693
694         public SqlBoolean ToSqlBoolean() {
695             return (SqlBoolean)this;
696         }
697
698         public SqlByte ToSqlByte() {
699             return (SqlByte)this;
700         }
701
702         public SqlDateTime ToSqlDateTime() {
703             return (SqlDateTime)this;
704         }
705
706         public SqlDouble ToSqlDouble() {
707             return (SqlDouble)this;
708         }
709
710         public SqlInt16 ToSqlInt16() {
711             return (SqlInt16)this;
712         }
713
714         public SqlInt32 ToSqlInt32() {
715             return (SqlInt32)this;
716         }
717
718         public SqlInt64 ToSqlInt64() {
719             return (SqlInt64)this;
720         }
721
722         public SqlMoney ToSqlMoney() {
723             return (SqlMoney)this;
724         }
725
726         public SqlDecimal ToSqlDecimal() {
727             return (SqlDecimal)this;
728         }
729
730         public SqlSingle ToSqlSingle() {
731             return (SqlSingle)this;
732         }
733
734         public SqlGuid ToSqlGuid() {
735             return (SqlGuid)this;
736         }
737
738
739
740
741         // Utility functions and constants
742
743         private static void ValidateSqlCompareOptions(SqlCompareOptions compareOptions) {
744             if ((compareOptions & x_iValidSqlCompareOptionMask) != compareOptions)
745                 throw new ArgumentOutOfRangeException ("compareOptions");
746         }
747
748         public static CompareOptions CompareOptionsFromSqlCompareOptions(SqlCompareOptions compareOptions) {
749             CompareOptions options = CompareOptions.None;
750
751             ValidateSqlCompareOptions(compareOptions);
752
753             if ((compareOptions & (SqlCompareOptions.BinarySort | SqlCompareOptions.BinarySort2)) != 0)
754                 throw ADP.ArgumentOutOfRange("compareOptions");
755             else {
756                 if ((compareOptions & SqlCompareOptions.IgnoreCase) != 0)
757                     options |= CompareOptions.IgnoreCase;
758                 if ((compareOptions & SqlCompareOptions.IgnoreNonSpace) != 0)
759                     options |= CompareOptions.IgnoreNonSpace;
760                 if ((compareOptions & SqlCompareOptions.IgnoreKanaType) != 0)
761                     options |= CompareOptions.IgnoreKanaType;
762                 if ((compareOptions & SqlCompareOptions.IgnoreWidth) != 0)
763                     options |= CompareOptions.IgnoreWidth;
764             }
765
766             return  options;
767         }
768
769         /*
770         private static SqlCompareOptions SqlCompareOptionsFromCompareOptions(CompareOptions compareOptions) {
771             SqlCompareOptions sqlOptions = SqlCompareOptions.None;
772
773             if ((compareOptions & x_iValidCompareOptionMask) != compareOptions)
774                 throw new ArgumentOutOfRangeException ("compareOptions");
775             else {
776                 if ((compareOptions & CompareOptions.IgnoreCase) != 0)
777                     sqlOptions |= SqlCompareOptions.IgnoreCase;
778                 if ((compareOptions & CompareOptions.IgnoreNonSpace) != 0)
779                     sqlOptions |= SqlCompareOptions.IgnoreNonSpace;
780                 if ((compareOptions & CompareOptions.IgnoreKanaType) != 0)
781                     sqlOptions |= SqlCompareOptions.IgnoreKanaType;
782                 if ((compareOptions & CompareOptions.IgnoreWidth) != 0)
783                     sqlOptions |= SqlCompareOptions.IgnoreWidth;
784             }
785
786             return  sqlOptions;
787         }
788         */
789
790         private bool FBinarySort() {
791             return(!IsNull && (m_flag & (SqlCompareOptions.BinarySort | SqlCompareOptions.BinarySort2)) != 0);
792         }
793
794         //    Wide-character string comparison for Binary Unicode Collation
795         //    Return values:
796         //        -1 : wstr1 < wstr2
797         //        0  : wstr1 = wstr2
798         //        1  : wstr1 > wstr2
799         //
800         //    Does a memory comparison.
801         private static int CompareBinary(SqlString x, SqlString y) {
802             byte[] rgDataX = x_UnicodeEncoding.GetBytes(x.m_value);
803             byte[] rgDataY = x_UnicodeEncoding.GetBytes(y.m_value);
804             int cbX = rgDataX.Length;
805             int cbY = rgDataY.Length;
806             int cbMin = cbX < cbY ? cbX : cbY;
807             int i;
808
809             SQLDebug.Check(cbX % 2 == 0);
810             SQLDebug.Check(cbY % 2 == 0);
811
812             for (i = 0; i < cbMin; i ++) {
813                 if (rgDataX[i] < rgDataY[i])
814                     return -1;
815                 else if (rgDataX[i] > rgDataY[i])
816                     return 1;
817             }
818
819             i = cbMin;
820
821             int iCh;
822             int iSpace = (int)' ';
823
824             if (cbX < cbY) {
825                 for (; i < cbY; i += 2) {
826                     iCh = ((int)rgDataY[i + 1]) << 8 + rgDataY[i];
827                     if (iCh != iSpace)
828                         return (iSpace > iCh) ? 1 : -1;
829                 }
830             }
831             else {
832                 for (; i < cbX; i += 2) {
833                     iCh = ((int)rgDataX[i + 1]) << 8 + rgDataX[i];
834                     if (iCh != iSpace)
835                         return (iCh > iSpace) ? 1 : -1;
836                 }
837             }
838
839             return 0;
840         }
841
842         //    Wide-character string comparison for Binary2 Unicode Collation
843         //    Return values:
844         //        -1 : wstr1 < wstr2
845         //        0  : wstr1 = wstr2
846         //        1  : wstr1 > wstr2
847         //
848         //    Does a wchar comparison (different from memcmp of BinarySort).
849         private static int CompareBinary2(SqlString x, SqlString y) {
850             SQLDebug.Check(!x.IsNull && !y.IsNull);
851
852             string rgDataX = x.m_value;
853             string rgDataY = y.m_value;
854             int cwchX = rgDataX.Length;
855             int cwchY = rgDataY.Length;
856             int cwchMin = cwchX < cwchY ? cwchX : cwchY;
857             int i;
858
859             for (i = 0; i < cwchMin; i ++) {
860                 if (rgDataX[i] < rgDataY[i])
861                     return -1;
862                 else if (rgDataX[i] > rgDataY[i])
863                     return 1;
864             }
865
866             // If compares equal up to one of the string terminates,
867             // pad it with spaces and compare with the rest of the other one.
868             //
869             char chSpace = ' ';
870
871             if (cwchX < cwchY) {
872                 for (i = cwchMin; i < cwchY; i ++) {
873                     if (rgDataY[i] != chSpace)
874                         return (chSpace > rgDataY[i]) ? 1 : -1;
875                 }
876             }
877             else {
878                 for (i = cwchMin; i < cwchX; i ++) {
879                     if (rgDataX[i] != chSpace)
880                         return (rgDataX[i] > chSpace) ? 1 : -1;
881                 }
882             }
883
884             return 0;
885         }
886
887 /*
888         private void Print() {
889             Debug.WriteLine("SqlString - ");
890             Debug.WriteLine("\tlcid = " + m_lcid.ToString());
891             Debug.Write("\t");
892             if ((m_flag & SqlCompareOptions.IgnoreCase) != 0)
893                 Debug.Write("IgnoreCase, ");
894             if ((m_flag & SqlCompareOptions.IgnoreNonSpace) != 0)
895                 Debug.Write("IgnoreNonSpace, ");
896             if ((m_flag & SqlCompareOptions.IgnoreKanaType) != 0)
897                 Debug.Write("IgnoreKanaType, ");
898             if ((m_flag & SqlCompareOptions.IgnoreWidth) != 0)
899                 Debug.Write("IgnoreWidth, ");
900             Debug.WriteLine("");
901             Debug.WriteLine("\tvalue = " + m_value);
902             Debug.WriteLine("\tcmpinfo = " + m_cmpInfo);
903         }
904 */
905         // IComparable
906         // Compares this object to another object, returning an integer that
907         // indicates the relationship.
908         // Returns a value less than zero if this < object, zero if this = object,
909         // or a value greater than zero if this > object.
910         // null is considered to be less than any instance.
911         // If object is not of same type, this method throws an ArgumentException.
912         /// <devdoc>
913         ///    <para>[To be supplied.]</para>
914         /// </devdoc>
915         public int CompareTo(Object value) {
916             if (value is SqlString) {
917                 SqlString i = (SqlString)value;
918
919                 return CompareTo(i);
920             }
921             throw ADP.WrongType(value.GetType(), typeof(SqlString));
922         }
923
924         public int CompareTo(SqlString value) {
925             // If both Null, consider them equal.
926             // Otherwise, Null is less than anything.
927             if (IsNull)
928                 return value.IsNull ? 0  : -1;
929             else if (value.IsNull)
930                 return 1;
931
932             int returnValue = StringCompare(this, value);
933
934             // Conver the result into -1, 0, or 1 as this method never returned any other values
935             //  This is to ensure the backcompat
936             if (returnValue < 0) {
937                 return -1;
938             }
939             if (returnValue > 0) {
940                 return 1;
941             }
942
943             return 0;
944         }
945
946         // Compares this instance with a specified object
947         /// <devdoc>
948         ///    <para>[To be supplied.]</para>
949         /// </devdoc>
950         public override bool Equals(Object value) {
951             if (!(value is SqlString)) {
952                 return false;
953             }
954
955             SqlString i = (SqlString)value;
956
957             if (i.IsNull || IsNull)
958                 return (i.IsNull && IsNull);
959             else
960                 return (this == i).Value;
961         }
962
963         // For hashing purpose
964         /// <devdoc>
965         ///    <para>[To be supplied.]</para>
966         /// </devdoc>
967         public override int GetHashCode() {
968             if (IsNull)
969                 return 0;
970
971             byte[] rgbSortKey;
972             if (FBinarySort())
973                 rgbSortKey = x_UnicodeEncoding.GetBytes(m_value.TrimEnd());
974             else
975             {
976                 // VSDevDiv 479660
977                 //  GetHashCode should not throw just because this instance has an invalid LCID or compare options.
978                 CompareInfo cmpInfo;
979                 CompareOptions options;
980                 try {
981                     SetCompareInfo();
982                     cmpInfo = m_cmpInfo;
983                     options = CompareOptionsFromSqlCompareOptions(m_flag);
984                 }
985                 catch (ArgumentException) {
986                     // SetCompareInfo throws this when instance's LCID is unsupported
987                     // CompareOptionsFromSqlCompareOptions throws this when instance's options are invalid
988                     cmpInfo = CultureInfo.InvariantCulture.CompareInfo;
989                     options = CompareOptions.None;
990                 }
991                 rgbSortKey = cmpInfo.GetSortKey(m_value.TrimEnd(), options).KeyData;
992             }
993
994             return SqlBinary.HashByteArray(rgbSortKey, rgbSortKey.Length);
995         }
996
997         /// <devdoc>
998         ///    <para>[To be supplied.]</para>
999         /// </devdoc>
1000         XmlSchema IXmlSerializable.GetSchema() { return null; }
1001
1002         /// <devdoc>
1003         ///    <para>[To be supplied.]</para>
1004         /// </devdoc>
1005         void IXmlSerializable.ReadXml(XmlReader reader) {
1006             string isNull = reader.GetAttribute("nil", XmlSchema.InstanceNamespace);
1007             if (isNull != null && XmlConvert.ToBoolean(isNull)) {
1008                 // VSTFDevDiv# 479603 - SqlTypes read null value infinitely and never read the next value. Fix - Read the next value.
1009                 reader.ReadElementString();
1010                 m_fNotNull = false;
1011             }
1012             else {
1013                 m_value = reader.ReadElementString();
1014                 m_fNotNull = true;
1015             }
1016         }
1017
1018         /// <devdoc>
1019         ///    <para>[To be supplied.]</para>
1020         /// </devdoc>
1021         void IXmlSerializable.WriteXml(XmlWriter writer) {
1022             if (IsNull) {
1023                 writer.WriteAttributeString("xsi", "nil", XmlSchema.InstanceNamespace, "true");
1024             }
1025             else {
1026                 writer.WriteString(m_value);
1027             }
1028         }
1029
1030         /// <devdoc>
1031         ///    <para>[To be supplied.]</para>
1032         /// </devdoc>
1033         public static XmlQualifiedName GetXsdType(XmlSchemaSet schemaSet) {
1034             return new XmlQualifiedName("string", XmlSchema.Namespace);
1035         }
1036
1037     } // SqlString
1038
1039 /*
1040     internal struct SLocaleMapItem {
1041         public int      lcid;           // the primary key, not nullable
1042         public String   name;           // unique, nullable
1043         public int      idCodePage;     // the ANSI default code page of the locale
1044
1045         public SLocaleMapItem(int lid, String str, int cpid) {
1046             lcid = lid;
1047             name = str;
1048             idCodePage = cpid;
1049         }
1050     }
1051
1052     // Struct to map lcid to ordinal
1053     internal struct SLcidOrdMapItem {
1054         internal int    lcid;
1055         internal int    uiOrd;
1056     };
1057
1058     // Class to store map of lcids to ordinal
1059     internal class CBuildLcidOrdMap {
1060         internal SLcidOrdMapItem[] m_rgLcidOrdMap;
1061         internal int m_cValidLocales;
1062         internal int m_uiPosEnglish; // Start binary searches here - this is index in array, not ordinal
1063
1064         // Constructor builds the array sorted by lcid
1065         // We use a simple n**2 sort because the array is mostly sorted anyway
1066         // and objects of this class will be const, hence this will be called
1067         // only by VC compiler
1068         public CBuildLcidOrdMap() {
1069             int i,j;
1070
1071             m_rgLcidOrdMap = new SLcidOrdMapItem[SqlString.x_cLocales];
1072
1073             // Compact the array
1074             for (i=0,j=0; i < SqlString.x_cLocales; i++) {
1075                 if (SqlString.x_rgLocaleMap[i].lcid != SqlString.x_lcidUnused) {
1076                     m_rgLcidOrdMap[j].lcid = SqlString.x_rgLocaleMap[i].lcid;
1077                     m_rgLcidOrdMap[j].uiOrd = i;
1078                     j++;
1079                 }
1080             }
1081
1082             m_cValidLocales = j;
1083
1084             // Set the rest to invalid
1085             while (j < SqlString.x_cLocales) {
1086                 m_rgLcidOrdMap[j].lcid = SqlString.x_lcidUnused;
1087                 m_rgLcidOrdMap[j].uiOrd = 0;
1088                 j++;
1089             }
1090
1091             // Now sort in place
1092             // Algo:
1093             // Start from 1, assume list before i is sorted, if next item
1094             // violates this assumption, exchange with prev items until the
1095             // item is in its correct place
1096             for (i=1; i<m_cValidLocales; i++) {
1097                 for (j=i; j>0 &&
1098                     m_rgLcidOrdMap[j].lcid < m_rgLcidOrdMap[j-1].lcid; j--) {
1099                     // Swap with prev element
1100                     int lcidTemp = m_rgLcidOrdMap[j-1].lcid;
1101                     int uiOrdTemp = m_rgLcidOrdMap[j-1].uiOrd;
1102                     m_rgLcidOrdMap[j-1].lcid = m_rgLcidOrdMap[j].lcid;
1103                     m_rgLcidOrdMap[j-1].uiOrd = m_rgLcidOrdMap[j].uiOrd;
1104                     m_rgLcidOrdMap[j].lcid = lcidTemp;
1105                     m_rgLcidOrdMap[j].uiOrd = uiOrdTemp;
1106                 }
1107             }
1108
1109             // Set the position of the US_English LCID (Latin1_General)
1110             for (i=0; i<m_cValidLocales && m_rgLcidOrdMap[i].lcid != SqlString.x_lcidUSEnglish; i++)
1111                 ; // Deliberately empty
1112
1113             SQLDebug.Check(i<m_cValidLocales);  // Latin1_General better be present
1114             m_uiPosEnglish = i;     // This is index in array, not ordinal
1115         }
1116
1117     } // CBuildLcidOrdMap
1118 */
1119
1120 } // namespace System.Data.SqlTypes