//
// System.Data.SqlTypes.SqlString
//
// Author:
// Rodrigo Moya (rodrigo@ximian.com)
// Daniel Morgan (danmorg@sc.rr.com)
// Tim Coleman (tim@timcoleman.com)
// Ville Palo (vi64pa@koti.soon.fi)
//
// (C) Ximian, Inc. 2002
// (C) Copyright 2002 Tim Coleman
//
//
// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Xml;
using System.Text;
using System.Threading;
using System.Xml.Schema;
using System.Globalization;
using System.Xml.Serialization;
namespace System.Data.SqlTypes
{
///
/// A variable-length stream of characters
/// to be stored in or retrieved from the database
///
#if NET_2_0
[SerializableAttribute]
[XmlSchemaProvider ("GetXsdType")]
#endif
public struct SqlString : INullable, IComparable
#if NET_2_0
, IXmlSerializable
#endif
{
#region Fields
string value;
private bool notNull;
// FIXME: locale id is not working yet
private int lcid;
private SqlCompareOptions compareOptions;
public static readonly int BinarySort = 0x8000;
public static readonly int IgnoreCase = 0x1;
public static readonly int IgnoreKanaType = 0x8;
public static readonly int IgnoreNonSpace = 0x2;
public static readonly int IgnoreWidth = 0x10;
public static readonly SqlString Null;
internal static NumberFormatInfo DecimalFormat;
#endregion // Fields
#region Constructors
static SqlString ()
{
DecimalFormat = (NumberFormatInfo) NumberFormatInfo.InvariantInfo.Clone ();
DecimalFormat.NumberDecimalDigits = 13;
DecimalFormat.NumberGroupSeparator = String.Empty;
}
// init with a string data
public SqlString (string data)
{
this.value = data;
lcid = CultureInfo.CurrentCulture.LCID;
if (value != null)
notNull = true;
else
notNull = false;
this.compareOptions = SqlCompareOptions.IgnoreCase |
SqlCompareOptions.IgnoreKanaType |
SqlCompareOptions.IgnoreWidth;
}
// init with a string data and locale id values.
public SqlString (string data, int lcid)
{
this.value = data;
this.lcid = lcid;
if (value != null)
notNull = true;
else
notNull = false;
this.compareOptions = SqlCompareOptions.IgnoreCase |
SqlCompareOptions.IgnoreKanaType |
SqlCompareOptions.IgnoreWidth;
}
// init with locale id, compare options,
// and an array of bytes data
public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data)
: this (lcid, compareOptions, data, true) { }
// init with string data, locale id, and compare options
public SqlString (string data, int lcid, SqlCompareOptions compareOptions)
{
this.value = data;
this.lcid = lcid;
this.compareOptions = compareOptions;
if (value != null)
notNull = true;
else
notNull = false;
}
// init with locale id, compare options, array of bytes data,
// and whether unicode is encoded or not
public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data, bool fUnicode)
{
Encoding encoding = (fUnicode ? Encoding.Unicode : Encoding.ASCII);
this.value = encoding.GetString (data);
this.lcid = lcid;
this.compareOptions = compareOptions;
if (value != null)
notNull = true;
else
notNull = false;
}
// init with locale id, compare options, array of bytes data,
// starting index in the byte array,
// and number of bytes to copy
public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data,
int index, int count)
: this (lcid, compareOptions, data, index, count, true) { }
// init with locale id, compare options, array of bytes data,
// starting index in the byte array, number of byte to copy,
// and whether unicode is encoded or not
public SqlString (int lcid, SqlCompareOptions compareOptions, byte[] data, int index, int count, bool fUnicode)
{
Encoding encoding = (fUnicode ? Encoding.Unicode : Encoding.ASCII);
this.value = encoding.GetString (data, index, count);
this.lcid = lcid;
this.compareOptions = compareOptions;
if (value != null)
notNull = true;
else
notNull = false;
}
#endregion // Constructors
#region Public Properties
public CompareInfo CompareInfo {
get {
return new CultureInfo (lcid).CompareInfo;
}
}
public CultureInfo CultureInfo {
get {
return new CultureInfo (lcid);
}
}
public bool IsNull {
get { return !notNull; }
}
// geographics location and language (locale id)
public int LCID {
get {
return lcid;
}
}
public SqlCompareOptions SqlCompareOptions {
get {
return compareOptions;
}
}
public string Value {
get {
if (this.IsNull)
throw new SqlNullValueException (Locale.GetText ("The property contains Null."));
else
return value;
}
}
#endregion // Public Properties
#region Private Properties
private CompareOptions CompareOptions {
get {
return
(this.compareOptions & SqlCompareOptions.BinarySort) != 0 ?
CompareOptions.Ordinal :
// 27 == all SqlCompareOptions - BinarySort
// (1,2,8,24 are common to CompareOptions)
(CompareOptions)((int)this.compareOptions & 27);
}
}
#endregion Private Properties
#region Public Methods
public SqlString Clone()
{
return new SqlString (value, lcid, compareOptions);
}
public static CompareOptions CompareOptionsFromSqlCompareOptions (SqlCompareOptions compareOptions)
{
CompareOptions options = CompareOptions.None;
if ((compareOptions & SqlCompareOptions.IgnoreCase) != 0)
options |= CompareOptions.IgnoreCase;
if ((compareOptions & SqlCompareOptions.IgnoreKanaType) != 0)
options |= CompareOptions.IgnoreKanaType;
if ((compareOptions & SqlCompareOptions.IgnoreNonSpace) != 0)
options |= CompareOptions.IgnoreNonSpace;
if ((compareOptions & SqlCompareOptions.IgnoreWidth) != 0)
options |= CompareOptions.IgnoreWidth;
if ((compareOptions & SqlCompareOptions.BinarySort) != 0)
// FIXME: Exception string
throw new ArgumentOutOfRangeException ();
return options;
}
// **********************************
// Comparison Methods
// **********************************
public int CompareTo (object value)
{
if (value == null)
return 1;
else if (!(value is SqlString))
throw new ArgumentException (Locale.GetText ("Value is not a System.Data.SqlTypes.SqlString"));
return CompareSqlString ((SqlString)value);
}
private int CompareSqlString (SqlString value)
{
if (value.IsNull)
return 1;
else if (value.CompareOptions != this.CompareOptions)
throw new SqlTypeException (Locale.GetText ("Two strings to be compared have different collation"));
// else
// return String.Compare (this.value, ((SqlString)value).Value, (this.SqlCompareOptions & SqlCompareOptions.IgnoreCase) != 0, this.CultureInfo);
return CultureInfo.CompareInfo.Compare (this.value, value.Value, this.CompareOptions);
}
public static SqlString Concat(SqlString x, SqlString y)
{
return (x + y);
}
public override bool Equals(object value)
{
if (!(value is SqlString))
return false;
if (this.IsNull && ((SqlString)value).IsNull)
return true;
else if (((SqlString)value).IsNull)
return false;
else
return (bool) (this == (SqlString)value);
}
public static SqlBoolean Equals(SqlString x, SqlString y)
{
return (x == y);
}
public override int GetHashCode()
{
int result = 10;
for (int i = 0; i < value.Length; i++)
result = 91 * result + (int)(value [i] ^ (value [i] >> 32));
result = 91 * result + lcid.GetHashCode ();
result = 91 * result + (int)compareOptions;
return result;
}
public byte[] GetNonUnicodeBytes()
{
return Encoding.ASCII.GetBytes (value);
}
public byte[] GetUnicodeBytes()
{
return Encoding.Unicode.GetBytes (value);
}
public static SqlBoolean GreaterThan(SqlString x, SqlString y)
{
return (x > y);
}
public static SqlBoolean GreaterThanOrEqual(SqlString x, SqlString y)
{
return (x >= y);
}
public static SqlBoolean LessThan(SqlString x, SqlString y)
{
return (x < y);
}
public static SqlBoolean LessThanOrEqual(SqlString x, SqlString y)
{
return (x <= y);
}
public static SqlBoolean NotEquals(SqlString x, SqlString y)
{
return (x != y);
}
// ****************************************
// Type Conversions From SqlString To ...
// ****************************************
public SqlBoolean ToSqlBoolean()
{
return ((SqlBoolean)this);
}
public SqlByte ToSqlByte()
{
return ((SqlByte)this);
}
public SqlDateTime ToSqlDateTime()
{
return ((SqlDateTime)this);
}
public SqlDecimal ToSqlDecimal()
{
return ((SqlDecimal)this);
}
public SqlDouble ToSqlDouble()
{
return ((SqlDouble)this);
}
public SqlGuid ToSqlGuid()
{
return ((SqlGuid)this);
}
public SqlInt16 ToSqlInt16()
{
return ((SqlInt16)this);
}
public SqlInt32 ToSqlInt32()
{
return ((SqlInt32)this);
}
public SqlInt64 ToSqlInt64()
{
return ((SqlInt64)this);
}
public SqlMoney ToSqlMoney()
{
return ((SqlMoney)this);
}
public SqlSingle ToSqlSingle()
{
return ((SqlSingle)this);
}
public override string ToString()
{
if (!notNull)
return "Null";
return ((string)this);
}
// ***********************************
// Operators
// ***********************************
// Concatenates
public static SqlString operator + (SqlString x, SqlString y)
{
if (x.IsNull || y.IsNull)
return SqlString.Null;
else
return new SqlString (x.Value + y.Value);
}
// Equality
public static SqlBoolean operator == (SqlString x, SqlString y)
{
if (x.IsNull || y.IsNull)
return SqlBoolean.Null;
else
return new SqlBoolean (x.Value == y.Value);
}
// Greater Than
public static SqlBoolean operator > (SqlString x, SqlString y)
{
if (x.IsNull || y.IsNull)
return SqlBoolean.Null;
else
return new SqlBoolean (x.CompareTo (y) > 0);
}
// Greater Than Or Equal
public static SqlBoolean operator >= (SqlString x, SqlString y)
{
if (x.IsNull || y.IsNull)
return SqlBoolean.Null;
else
return new SqlBoolean (x.CompareTo (y) >= 0);
}
public static SqlBoolean operator != (SqlString x, SqlString y)
{
if (x.IsNull || y.IsNull)
return SqlBoolean.Null;
else
return new SqlBoolean (x.Value != y.Value);
}
// Less Than
public static SqlBoolean operator < (SqlString x, SqlString y)
{
if (x.IsNull || y.IsNull)
return SqlBoolean.Null;
else
return new SqlBoolean (x.CompareTo (y) < 0);
}
// Less Than Or Equal
public static SqlBoolean operator <= (SqlString x, SqlString y)
{
if (x.IsNull || y.IsNull)
return SqlBoolean.Null;
else
return new SqlBoolean (x.CompareTo (y) <= 0);
}
// **************************************
// Type Conversions
// **************************************
public static explicit operator SqlString (SqlBoolean x)
{
if (x.IsNull)
return Null;
else
return new SqlString (x.Value.ToString ());
}
public static explicit operator SqlString (SqlByte x)
{
if (x.IsNull)
return Null;
else
return new SqlString (x.Value.ToString ());
}
public static explicit operator SqlString (SqlDateTime x)
{
if (x.IsNull)
return Null;
else
return new SqlString (x.Value.ToString ());
}
public static explicit operator SqlString (SqlDecimal x)
{
if (x.IsNull)
return Null;
else
return new SqlString (x.Value.ToString ());
// return new SqlString (x.Value.ToString ("N", DecimalFormat));
}
public static explicit operator SqlString (SqlDouble x)
{
if (x.IsNull)
return Null;
else
return new SqlString (x.Value.ToString ());
}
public static explicit operator SqlString (SqlGuid x)
{
if (x.IsNull)
return Null;
else
return new SqlString (x.Value.ToString ());
}
public static explicit operator SqlString (SqlInt16 x)
{
if (x.IsNull)
return Null;
else
return new SqlString (x.Value.ToString ());
}
public static explicit operator SqlString (SqlInt32 x)
{
if (x.IsNull)
return Null;
else
return new SqlString (x.Value.ToString ());
}
public static explicit operator SqlString (SqlInt64 x)
{
if (x.IsNull)
return Null;
else
return new SqlString (x.Value.ToString ());
}
public static explicit operator SqlString (SqlMoney x)
{
if (x.IsNull)
return Null;
else
return new SqlString (x.ToString ());
}
public static explicit operator SqlString (SqlSingle x)
{
if (x.IsNull)
return Null;
else
return new SqlString (x.Value.ToString ());
}
public static explicit operator string (SqlString x)
{
return x.Value;
}
public static implicit operator SqlString (string x)
{
return new SqlString (x);
}
#if NET_2_0
public static SqlString Add (SqlString x, SqlString y)
{
return (x + y);
}
public int CompareTo (SqlString value)
{
return CompareSqlString (value);
}
#endif
#endregion // Public Methods
#if NET_2_0
public static XmlQualifiedName GetXsdType (XmlSchemaSet schemaSet)
{
XmlQualifiedName qualifiedName = new XmlQualifiedName ("string", "http://www.w3.org/2001/XMLSchema");
return qualifiedName;
}
[MonoTODO]
XmlSchema IXmlSerializable.GetSchema ()
{
throw new NotImplementedException ();
}
void IXmlSerializable.ReadXml (XmlReader reader)
{
if (reader == null)
return;
switch (reader.ReadState) {
case ReadState.EndOfFile:
case ReadState.Error:
case ReadState.Closed:
return;
}
// Skip XML declaration and prolog
// or do I need to validate for the tag?
reader.MoveToContent ();
if (reader.EOF)
return;
reader.Read ();
if (reader.NodeType == XmlNodeType.EndElement)
return;
if (reader.Value.Length > 0) {
if (String.Compare ("Null", reader.Value) == 0) {
// means a null reference/invalid value
notNull = false;
return;
}
// FIXME: Validate the value for expected format
this.value = reader.Value;
this.notNull = true;
this.compareOptions = SqlCompareOptions.IgnoreCase |
SqlCompareOptions.IgnoreKanaType |
SqlCompareOptions.IgnoreWidth;
}
}
void IXmlSerializable.WriteXml (XmlWriter writer)
{
writer.WriteString (this.ToString ());
}
#endif
}
}