DeveelDB  20151217
complete SQL database system, primarly developed for .NET/Mono frameworks
SqlString.cs
Go to the documentation of this file.
1 //
2 // Copyright 2010-2015 Deveel
3 //
4 // Licensed under the Apache License, Version 2.0 (the "License");
5 // you may not use this file except in compliance with the License.
6 // You may obtain a copy of the License at
7 //
8 // http://www.apache.org/licenses/LICENSE-2.0
9 //
10 // Unless required by applicable law or agreed to in writing, software
11 // distributed under the License is distributed on an "AS IS" BASIS,
12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 // See the License for the specific language governing permissions and
14 // limitations under the License.
15 //
16 
17 using System;
18 using System.Collections;
19 using System.Collections.Generic;
20 using System.IO;
21 using System.Text;
22 
24 using Deveel.Data.Types;
25 
26 namespace Deveel.Data.Sql.Objects {
41  [Serializable]
42  public struct SqlString : ISqlString, IEquatable<SqlString>, IConvertible, ISerializable {
46  public const int MaxLength = Int16.MaxValue;
47 
51  public static readonly SqlString Null = new SqlString(null, 0, true);
52 
53  private readonly byte[] source;
54 
55  private SqlString(char[] chars, int length, bool isNull) : this() {
56  if (chars == null) {
57  source = null;
58  } else {
59  if (length > MaxLength)
60  throw new ArgumentOutOfRangeException("length");
61 
62  source = Encoding.Unicode.GetBytes(chars);
63  Length = Encoding.Unicode.GetCharCount(source);
64  }
65 
66  IsNull = isNull || source == null;
67  }
68 
74  public SqlString(char[] chars)
75  : this(chars, chars == null ? 0 : chars.Length) {
76  }
77 
84  public SqlString(char[] chars, int length)
85  : this(chars, length, false) {
86  }
87 
88  public SqlString(string source)
89  : this(source == null ? (char[]) null : source.ToCharArray()) {
90  }
91 
92  public SqlString(byte[] bytes, int offset, int length)
93  : this(GetChars(bytes, offset, length)) {
94  }
95 
96  public SqlString(byte[] bytes)
97  : this(bytes, 0, bytes == null ? 0 : bytes.Length) {
98  }
99 
100  private SqlString(ObjectData data)
101  : this() {
102  source = data.GetValue<byte[]>("Source");
103  }
104 
105  private static char[] GetChars(byte[] bytes, int offset, int length) {
106  if (bytes == null)
107  return null;
108 
109  return Encoding.Unicode.GetChars(bytes, offset, length);
110  }
111 
112  int IComparable.CompareTo(object obj) {
113  return CompareTo((ISqlString) obj);
114  }
115 
116  int IComparable<ISqlObject>.CompareTo(ISqlObject other) {
117  return CompareTo((ISqlString) other);
118  }
119 
120  public bool IsNull { get; private set; }
121 
122  Encoding ISqlString.Encoding {
123  get { return Encoding.Unicode; }
124  }
125 
126  public string Value {
127  get { return source == null ? null : Encoding.Unicode.GetString(source, 0, source.Length); }
128  }
129 
130  public char this[long index] {
131  get {
132  if (index > Int32.MaxValue)
133  throw new ArgumentOutOfRangeException("index");
134 
135  if (source == null)
136  return '\0';
137  if (index >= Length)
138  throw new ArgumentOutOfRangeException("index");
139 
140  var chars = Encoding.Unicode.GetChars(source);
141  return chars[index];
142  }
143  }
144 
146  return other is ISqlString;
147  }
148 
149  public int CompareTo(ISqlString other) {
150  if (other == null)
151  throw new ArgumentNullException("other");
152 
153  if (IsNull && other.IsNull)
154  return 0;
155  if (IsNull)
156  return 1;
157  if (other.IsNull)
158  return -1;
159 
160  if (other is SqlString) {
161  var otherString = (SqlString) other;
162  return String.Compare(Value, otherString.Value, StringComparison.Ordinal);
163  }
164 
165  throw new NotImplementedException("Comparison with long strong not implemented yet.");
166  }
167 
168  public IEnumerator<char> GetEnumerator() {
169  return new StringEnumerator(this);
170  }
171 
172  IEnumerator IEnumerable.GetEnumerator() {
173  return GetEnumerator();
174  }
175 
176  public long Length { get; private set; }
177 
179  data.SetValue("Source", source);
180  }
181 
182  public string ToString(Encoding encoding) {
183  if (IsNull)
184  return null;
185 
186  var bytes = source;
187 
188  if (!encoding.Equals(Encoding.Unicode))
189  bytes = Encoding.Convert(Encoding.Unicode, encoding, bytes);
190 
191  return encoding.GetString(bytes, 0, bytes.Length);
192  }
193 
194  public TextReader GetInput(Encoding encoding) {
195  if (IsNull)
196  return TextReader.Null;
197 
198  if (encoding == null)
199  encoding = Encoding.Unicode;
200 
201  var bytes = source;
202  if (!encoding.Equals(Encoding.Unicode))
203  bytes = Encoding.Convert(Encoding.Unicode, encoding, bytes);
204 
205  var stream = new MemoryStream(bytes);
206  return new StreamReader(stream, encoding);
207  }
208 
209  public bool Equals(SqlString other) {
210  if (source == null && other.source == null)
211  return true;
212 
213  if (source == null)
214  return false;
215 
216  if (source.Length != other.source.Length)
217  return false;
218 
219  for (int i = 0; i < source.Length; i++) {
220  var c1 = source[i];
221  var c2 = other.source[i];
222  if (!c1.Equals(c2))
223  return false;
224  }
225 
226  return true;
227  }
228 
229  public override bool Equals(object obj) {
230  if (obj is SqlNull && IsNull)
231  return true;
232 
233  return Equals((SqlString) obj);
234  }
235 
236  public override int GetHashCode() {
237  if (source == null)
238  return 0;
239 
240  unchecked {
241  int hash = 17;
242 
243  // get hash code for all items in array
244  foreach (var item in source) {
245  hash = hash*23 + item.GetHashCode();
246  }
247 
248  return hash;
249  }
250  }
251 
252  public byte[] ToByteArray(Encoding encoding) {
253  if (encoding == null)
254  throw new ArgumentNullException("encoding");
255 
256  if (source == null)
257  return new byte[0];
258 
259  return (byte[]) source.Clone();
260  }
261 
262  public SqlString Concat(ISqlString other) {
263  if (other == null || other.IsNull)
264  return this;
265 
266  if (other is SqlString) {
267  var otheString = (SqlString) other;
268  var length = (int) (Length + otheString.Length);
269  if (length >= MaxLength)
270  throw new ArgumentException("The final string will be over the maximum length");
271 
272  var sourceChars = ToCharArray();
273  var otherChars = otheString.ToCharArray();
274  var destChars = new char[length];
275 
276  Array.Copy(sourceChars, 0, destChars, 0, (int)Length);
277  Array.Copy(otherChars, 0, destChars, (int)Length, (int)otheString.Length);
278  return new SqlString(destChars, length);
279  }
280 
281  var sb = new StringBuilder(Int16.MaxValue);
282  using (var output = new StringWriter(sb)) {
283  // First read the current stream
284  using (var reader = GetInput(Encoding.Unicode)) {
285  var buffer = new char[2048];
286  int count;
287  while ((count = reader.Read(buffer, 0, buffer.Length)) != 0) {
288  output.Write(buffer, 0, count);
289  }
290  }
291 
292  // Then read the second stream
293  using (var reader = other.GetInput(Encoding.Unicode)) {
294  var buffer = new char[2048];
295  int count;
296  while ((count = reader.Read(buffer, 0, buffer.Length)) != 0) {
297  output.Write(buffer, 0, count);
298  }
299  }
300 
301  output.Flush();
302  }
303 
304 #if PCL
305  var s = sb.ToString();
306  return new SqlString(s);
307 
308 #else
309  var outChars = new char[sb.Length];
310  sb.CopyTo(0, outChars, 0, sb.Length);
311  return new SqlString(outChars, outChars.Length);
312 #endif
313  }
314 
315  public int GetByteCount(Encoding encoding) {
316  if (IsNull)
317  return 0;
318 
319  var bytes = Encoding.Convert(Encoding.Unicode, encoding, source);
320  return bytes.Length;
321  }
322 
323  #region StringEnumerator
324 
325  class StringEnumerator : IEnumerator<char> {
326  private readonly SqlString sqlString;
327  private int index = -1;
328  private readonly int length;
329 
330  public StringEnumerator(SqlString sqlString) {
331  this.sqlString = sqlString;
332  length = (int) sqlString.Length;
333  }
334 
335  public void Dispose() {
336  }
337 
338  public bool MoveNext() {
339  return ++index < length;
340  }
341 
342  public void Reset() {
343  index = -1;
344  }
345 
346  public char Current {
347  get {
348  if (index >= length)
349  throw new InvalidOperationException();
350 
351  return sqlString[index];
352  }
353  }
354 
355  object IEnumerator.Current {
356  get { return Current; }
357  }
358  }
359 
360  #endregion
361 
362  public override string ToString() {
363  return Value;
364  }
365 
366  TypeCode IConvertible.GetTypeCode() {
367  return TypeCode.String;
368  }
369 
370  bool IConvertible.ToBoolean(IFormatProvider provider) {
371  return Convert.ToBoolean(Value, provider);
372  }
373 
374  char IConvertible.ToChar(IFormatProvider provider) {
375  return Convert.ToChar(Value, provider);
376  }
377 
378  sbyte IConvertible.ToSByte(IFormatProvider provider) {
379  return Convert.ToSByte(Value, provider);
380  }
381 
382  byte IConvertible.ToByte(IFormatProvider provider) {
383  return Convert.ToByte(Value, provider);
384  }
385 
386  short IConvertible.ToInt16(IFormatProvider provider) {
387  return Convert.ToInt16(Value, provider);
388  }
389 
390  ushort IConvertible.ToUInt16(IFormatProvider provider) {
391  return Convert.ToUInt16(Value, provider);
392  }
393 
394  int IConvertible.ToInt32(IFormatProvider provider) {
395  return Convert.ToInt32(Value, provider);
396  }
397 
398  uint IConvertible.ToUInt32(IFormatProvider provider) {
399  return Convert.ToUInt32(Value, provider);
400  }
401 
402  long IConvertible.ToInt64(IFormatProvider provider) {
403  return Convert.ToInt64(Value, provider);
404  }
405 
406  ulong IConvertible.ToUInt64(IFormatProvider provider) {
407  return Convert.ToUInt64(Value, provider);
408  }
409 
410  float IConvertible.ToSingle(IFormatProvider provider) {
411  return Convert.ToSingle(Value, provider);
412  }
413 
414  double IConvertible.ToDouble(IFormatProvider provider) {
415  return Convert.ToDouble(Value, provider);
416  }
417 
418  decimal IConvertible.ToDecimal(IFormatProvider provider) {
419  return Convert.ToDecimal(Value, provider);
420  }
421 
422  DateTime IConvertible.ToDateTime(IFormatProvider provider) {
423  return Convert.ToDateTime(Value, provider);
424  }
425 
426  string IConvertible.ToString(IFormatProvider provider) {
427  return Convert.ToString(Value, provider);
428  }
429 
430  object IConvertible.ToType(Type conversionType, IFormatProvider provider) {
431  if (conversionType == typeof (bool))
432  return Convert.ToBoolean(Value, provider);
433  if (conversionType == typeof (byte))
434  return Convert.ToByte(Value, provider);
435  if (conversionType == typeof (sbyte))
436  return Convert.ToSByte(Value, provider);
437  if (conversionType == typeof (short))
438  return Convert.ToInt16(Value, provider);
439  if (conversionType == typeof (ushort))
440  return Convert.ToUInt16(Value, provider);
441  if (conversionType == typeof (int))
442  return Convert.ToInt32(Value, provider);
443  if (conversionType == typeof (uint))
444  return Convert.ToUInt32(Value, provider);
445  if (conversionType == typeof (long))
446  return Convert.ToInt64(Value, provider);
447  if (conversionType == typeof (ulong))
448  return Convert.ToUInt64(Value, provider);
449  if (conversionType == typeof (float))
450  return Convert.ToSingle(Value, provider);
451  if (conversionType == typeof (double))
452  return Convert.ToDouble(Value, provider);
453  if (conversionType == typeof (decimal))
454  return Convert.ToDecimal(Value, provider);
455  if (conversionType == typeof (string))
456  return Convert.ToString(Value, provider);
457 
458  if (conversionType == typeof (char[]))
459  return ToCharArray();
460 
461  if (conversionType == typeof (SqlNumber))
462  return ToNumber();
463  if (conversionType == typeof (SqlBoolean))
464  return ToBoolean();
465  if (conversionType == typeof (SqlDateTime))
466  return ToDateTime();
467  if (conversionType == typeof (SqlBinary))
468  return ToBinary();
469 
470  throw new InvalidCastException(String.Format("Cannot convet SQL STRING to {0}", conversionType.FullName));
471  }
472 
474  SqlBoolean value;
475  if (!SqlBoolean.TryParse(Value, out value))
476  return SqlBoolean.Null; // TODO: Should we throw an exception?
477 
478  return value;
479  }
480 
481  public SqlNumber ToNumber() {
482  SqlNumber value;
483  if (!SqlNumber.TryParse(Value, out value))
484  return SqlNumber.Null; // TODO: Shoudl we throw an exception?
485 
486  return value;
487  }
488 
490  SqlDateTime value;
491  if (!SqlDateTime.TryParse(Value, out value))
492  return SqlDateTime.Null; // TODO: Shoudl we throw an exception?
493 
494  return value;
495  }
496 
497  public SqlBinary ToBinary() {
498  var bytes = ToByteArray(Encoding.Unicode);
499  return new SqlBinary(bytes);
500  }
501 
502  public char[] ToCharArray() {
503  if (source == null)
504  return new char[0];
505 
506  return Encoding.Unicode.GetChars(source);
507  }
508  }
509 }
byte[] ToByteArray(Encoding encoding)
Definition: SqlString.cs:252
override bool Equals(object obj)
Definition: SqlString.cs:229
void GetData(SerializeData data)
A long string in the system.
static bool TryParse(string s, out SqlNumber value)
Definition: SqlNumber.cs:702
Implements a BINARY object that handles a limited number of bytes, not exceding MaxLength.
Definition: SqlBinary.cs:27
SqlString(byte[] bytes, int offset, int length)
Definition: SqlString.cs:92
void SetValue(string key, Type type, object value)
bool IsNull
Gets a boolean value indicating if the object is NULL.
Definition: ISqlObject.cs:28
static char[] GetChars(byte[] bytes, int offset, int length)
Definition: SqlString.cs:105
Defines the contract for a valid SQL Object
Definition: ISqlObject.cs:23
SqlString(char[] chars, int length, bool isNull)
Definition: SqlString.cs:55
IEnumerator< char > GetEnumerator()
Definition: SqlString.cs:168
static readonly SqlDateTime Null
Definition: SqlDateTime.cs:24
string ToString(Encoding encoding)
Definition: SqlString.cs:182
int CompareTo(ISqlString other)
Definition: SqlString.cs:149
TextReader GetInput(Encoding encoding)
static readonly SqlNumber Null
Definition: SqlNumber.cs:31
bool IsComparableTo(ISqlObject other)
Checks if the current object is comparable with the given one.
TextReader GetInput(Encoding encoding)
Definition: SqlString.cs:194
int GetByteCount(Encoding encoding)
Definition: SqlString.cs:315
SqlString(char[] chars)
Initializes a new instance of the SqlString structure with the given set of characters.
Definition: SqlString.cs:74
SqlString Concat(ISqlString other)
Definition: SqlString.cs:262
bool Equals(SqlString other)
Definition: SqlString.cs:209
SqlString(char[] chars, int length)
Initializes a new instance of the SqlString structure.
Definition: SqlString.cs:84
static bool TryParse(string s, out SqlDateTime value)
Definition: SqlDateTime.cs:495
Deveel.Data.Sql.Objects.SqlString SqlString
Definition: DataObject.cs:27