23c9b8c0109009e04da6ba513de377b0d23ddbcf
[mono.git] / mcs / class / referencesource / System.Data / System / Data / Common / SQLTypes / SQLByteStorage.cs
1 //------------------------------------------------------------------------------
2 // <copyright file="SQLByteStorage.cs" company="Microsoft">
3 //     Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>                                                                
5 // <owner current="true" primary="true">Microsoft</owner>
6 // <owner current="true" primary="false">Microsoft</owner>
7 // <owner current="false" primary="false">Microsoft</owner>
8 //------------------------------------------------------------------------------
9
10 namespace System.Data.Common {
11     using System;
12     using System.Xml;
13     using System.Data.SqlTypes;
14     using System.Diagnostics;
15     using System.Globalization;
16     using System.IO;
17     using System.Xml.Serialization;
18     using System.Collections;
19     
20     internal sealed class SqlByteStorage : DataStorage {
21
22         private SqlByte[] values;
23
24         public SqlByteStorage(DataColumn column)
25         : base(column, typeof(SqlByte), SqlByte.Null, SqlByte.Null, StorageType.SqlByte) {
26         }
27
28         override public Object Aggregate(int[] records, AggregateType kind) {
29             bool hasData = false;
30             try {
31                 switch (kind) {
32                     case AggregateType.Sum:
33                         SqlInt64 sum =  0;
34                         foreach (int record in records) {
35                             if (IsNull(record))
36                                 continue;
37                             checked { sum += values[record];}
38                             hasData = true;
39                         }
40                         if (hasData) {
41                             return sum;
42                         }
43                         return NullValue;
44
45                     case AggregateType.Mean:
46                         SqlInt64 meanSum = 0;
47                         int meanCount = 0;
48                         foreach (int record in records) {
49                             if (IsNull(record))
50                                 continue;
51                             checked { meanSum += values[record].ToSqlInt64();}
52                             meanCount++;
53                             hasData = true;
54                         }
55                         if (hasData) {
56                             SqlByte mean = 0;
57                             checked {mean = (meanSum / (SqlInt64)meanCount).ToSqlByte();}
58                             return mean;
59                         }
60                         return NullValue;
61
62                     case AggregateType.Var:
63                     case AggregateType.StDev:
64                         int count = 0;
65                         SqlDouble var = (SqlDouble)0;
66                         SqlDouble prec = (SqlDouble)0;
67                         SqlDouble dsum = (SqlDouble)0;
68                         SqlDouble sqrsum = (SqlDouble)0;
69
70                         foreach (int record in records) {
71                             if (IsNull(record))
72                                 continue;
73                             dsum += values[record].ToSqlDouble();
74                             sqrsum += values[record].ToSqlDouble() * values[record].ToSqlDouble();
75                             count++;
76                         }
77
78                         if (count > 1) {
79                             var = ((SqlDouble)count * sqrsum - (dsum * dsum));
80                             prec = var / (dsum * dsum);
81                             
82                             // we are dealing with the risk of a cancellation error
83                             // double is guaranteed only for 15 digits so a difference 
84                             // with a result less than 1e-15 should be considered as zero
85
86                             if ((prec < 1e-15) || (var <0))
87                                 var = 0;
88                             else
89                                 var = var / (count * (count -1));
90                             
91                             if (kind == AggregateType.StDev) {
92                                return  Math.Sqrt(var.Value);
93                             }
94                             return var;
95                         }
96                         return NullValue;
97
98                     case AggregateType.Min:
99                         SqlByte min = SqlByte.MaxValue;
100                         for (int i = 0; i < records.Length; i++) {
101                             int record = records[i];
102                             if (IsNull(record))
103                                 continue;
104                             if ((SqlByte.LessThan(values[record], min)).IsTrue)
105                                 min = values[record];                        
106                             hasData = true;
107                         }
108                         if (hasData) {
109                             return min;
110                         }
111                         return NullValue;
112
113                     case AggregateType.Max:
114                         SqlByte max = SqlByte.MinValue;
115                         for (int i = 0; i < records.Length; i++) {
116                             int record = records[i];
117                             if (IsNull(record))
118                                 continue;
119                             if ((SqlByte.GreaterThan(values[record], max)).IsTrue)
120                                 max = values[record];
121                             hasData = true;
122                         }
123                         if (hasData) {
124                             return max;
125                         }
126                         return NullValue;
127
128                     case AggregateType.First:
129                         if (records.Length > 0) {
130                             return values[records[0]];
131                         }
132                         return null;// no data => null
133
134                     case AggregateType.Count:
135                         count = 0;
136                         for (int i = 0; i < records.Length; i++) {
137                             if (!IsNull(records[i]))
138                                 count++;
139                         }
140                         return count;
141                 }
142             }
143             catch (OverflowException) {
144                 throw ExprException.Overflow(typeof(SqlByte));
145             }
146             throw ExceptionBuilder.AggregateException(kind, DataType);
147         }
148
149         override public int Compare(int recordNo1, int recordNo2) {
150             return values[recordNo1].CompareTo(values[recordNo2]);
151         }
152
153         override public int CompareValueTo(int recordNo, Object value) {
154             return values[recordNo].CompareTo((SqlByte)value);
155         }
156         
157         override public object ConvertValue(object value) {
158             if (null != value) {
159                 return SqlConvert.ConvertToSqlByte(value);
160             }
161             return NullValue;
162         }
163
164
165         override public void Copy(int recordNo1, int recordNo2) {
166             values[recordNo2] = values[recordNo1];
167         }
168
169         override public Object Get(int record) {
170             return values[record];
171         }
172
173         override public bool IsNull(int record) {
174             return (values[record].IsNull);
175         }
176
177         override public void Set(int record, Object value) {
178             values[record] =  SqlConvert.ConvertToSqlByte(value);
179         }
180
181         override public void SetCapacity(int capacity) {
182             SqlByte[] newValues = new SqlByte[capacity];
183             if (null != values) {
184                 Array.Copy(values, 0, newValues, 0, Math.Min(capacity, values.Length));
185             }
186             values = newValues;
187         }
188
189         override public object ConvertXmlToObject(string s) {
190             SqlByte newValue = new SqlByte();
191             string tempStr =string.Concat("<col>", s, "</col>"); // this is done since you can give fragmet to reader, 
192             StringReader strReader = new  StringReader(tempStr);
193
194             IXmlSerializable tmp = newValue;
195             
196             using (XmlTextReader xmlTextReader = new XmlTextReader(strReader)) {
197                 tmp.ReadXml(xmlTextReader);
198             }
199             return ((SqlByte)tmp);
200         }
201
202         override public string ConvertObjectToXml(object value) {
203             Debug.Assert(!DataStorage.IsObjectNull(value), "we shouldn't have null here");
204             Debug.Assert((value.GetType() == typeof(SqlByte)), "wrong input type");
205
206             StringWriter strwriter = new StringWriter(FormatProvider);
207
208             using (XmlTextWriter xmlTextWriter = new XmlTextWriter (strwriter)) {
209                 ((IXmlSerializable)value).WriteXml(xmlTextWriter);
210             }
211             return (strwriter.ToString ());
212         }
213         
214         override protected object GetEmptyStorage(int recordCount) {
215             return new SqlByte[recordCount];
216         }
217         
218         override protected void CopyValue(int record, object store, BitArray nullbits, int storeIndex) {
219             SqlByte[] typedStore = (SqlByte[]) store; 
220             typedStore[storeIndex] = values[record];
221             nullbits.Set(record, IsNull(record));
222         }
223         
224         override protected void SetStorage(object store, BitArray nullbits) {
225             values = (SqlByte[]) store; 
226             //SetNullStorage(nullbits);
227         }          
228     }
229 }