1 //------------------------------------------------------------------------------ 2 // <copyright file="DecimalStorage.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.Collections; 15 16 internal sealed class DecimalStorage : DataStorage { 17 18 private static readonly Decimal defaultValue = Decimal.Zero; 19 20 private Decimal[] values; 21 DecimalStorage(DataColumn column)22 internal DecimalStorage(DataColumn column) 23 : base(column, typeof(Decimal), defaultValue, StorageType.Decimal) { 24 } 25 Aggregate(int[] records, AggregateType kind)26 override public Object Aggregate(int[] records, AggregateType kind) { 27 bool hasData = false; 28 try { 29 switch (kind) { 30 case AggregateType.Sum: 31 Decimal sum = defaultValue; 32 foreach (int record in records) { 33 if (HasValue(record)) { 34 checked { sum += values[record];} 35 hasData = true; 36 } 37 } 38 if (hasData) { 39 return sum; 40 } 41 return NullValue; 42 43 case AggregateType.Mean: 44 Decimal meanSum = (Decimal)defaultValue; 45 int meanCount = 0; 46 foreach (int record in records) { 47 if (HasValue(record)) { 48 checked { meanSum += (Decimal)values[record];} 49 meanCount++; 50 hasData = true; 51 } 52 } 53 if (hasData) { 54 Decimal mean; 55 checked {mean = (meanSum /(Decimal) meanCount);} 56 return mean; 57 } 58 return NullValue; 59 60 case AggregateType.Var: 61 case AggregateType.StDev: 62 int count = 0; 63 double var = (double)defaultValue; 64 double prec = (double)defaultValue; 65 double dsum = (double)defaultValue; 66 double sqrsum = (double)defaultValue; 67 68 foreach (int record in records) { 69 if (HasValue(record)) { 70 dsum += (double)values[record]; 71 sqrsum += (double)values[record]*(double)values[record]; 72 count++; 73 } 74 } 75 76 if (count > 1) { 77 var = ((double)count * sqrsum - (dsum * dsum)); 78 prec = var / (dsum * dsum); 79 80 // we are dealing with the risk of a cancellation error 81 // double is guaranteed only for 15 digits so a difference 82 // with a result less than 1e-15 should be considered as zero 83 84 if ((prec < 1e-15) || (var <0)) 85 var = 0; 86 else 87 var = var / (count * (count -1)); 88 89 if (kind == AggregateType.StDev) { 90 return Math.Sqrt(var); 91 } 92 return var; 93 } 94 return NullValue; 95 96 case AggregateType.Min: 97 Decimal min = Decimal.MaxValue; 98 for (int i = 0; i < records.Length; i++) { 99 int record = records[i]; 100 if (HasValue(record)) { 101 min=Math.Min(values[record], min); 102 hasData = true; 103 } 104 } 105 if (hasData) { 106 return min; 107 } 108 return NullValue; 109 110 case AggregateType.Max: 111 Decimal max = Decimal.MinValue; 112 for (int i = 0; i < records.Length; i++) { 113 int record = records[i]; 114 if (HasValue(record)) { 115 max=Math.Max(values[record], max); 116 hasData = true; 117 } 118 } 119 if (hasData) { 120 return max; 121 } 122 return NullValue; 123 124 case AggregateType.First: 125 if (records.Length > 0) { 126 return values[records[0]]; 127 } 128 return null; 129 130 case AggregateType.Count: 131 return base.Aggregate(records, kind); 132 133 } 134 } 135 catch (OverflowException) { 136 throw ExprException.Overflow(typeof(Decimal)); 137 } 138 throw ExceptionBuilder.AggregateException(kind, DataType); 139 } 140 Compare(int recordNo1, int recordNo2)141 override public int Compare(int recordNo1, int recordNo2) { 142 Decimal valueNo1 = values[recordNo1]; 143 Decimal valueNo2 = values[recordNo2]; 144 145 if (valueNo1 == defaultValue || valueNo2 == defaultValue) { 146 int bitCheck = CompareBits(recordNo1, recordNo2); 147 if (0 != bitCheck) 148 return bitCheck; 149 } 150 return Decimal.Compare(valueNo1, valueNo2); // InternalCall 151 } 152 CompareValueTo(int recordNo, object value)153 public override int CompareValueTo(int recordNo, object value) { 154 System.Diagnostics.Debug.Assert(0 <= recordNo, "Invalid record"); 155 System.Diagnostics.Debug.Assert(null != value, "null value"); 156 157 if (NullValue == value) { 158 return (HasValue(recordNo) ? 1 : 0); 159 } 160 161 Decimal valueNo1 = values[recordNo]; 162 if ((defaultValue == valueNo1) && !HasValue(recordNo)) { 163 return -1; 164 } 165 return Decimal.Compare(valueNo1, (Decimal)value); 166 } 167 ConvertValue(object value)168 public override object ConvertValue(object value) { 169 if (NullValue != value) { 170 if (null != value) { 171 value = ((IConvertible)value).ToDecimal(FormatProvider); 172 } 173 else { 174 value = NullValue; 175 } 176 } 177 return value; 178 } 179 Copy(int recordNo1, int recordNo2)180 override public void Copy(int recordNo1, int recordNo2) { 181 CopyBits(recordNo1, recordNo2); 182 values[recordNo2] = values[recordNo1]; 183 } 184 Get(int record)185 override public Object Get(int record) { 186 return (HasValue(record) ? values[record] : NullValue); 187 } 188 Set(int record, Object value)189 override public void Set(int record, Object value) { 190 System.Diagnostics.Debug.Assert(null != value, "null value"); 191 if (NullValue == value) { 192 values[record] = defaultValue; 193 SetNullBit(record, true); 194 } 195 else { 196 values[record] = ((IConvertible)value).ToDecimal(FormatProvider); 197 SetNullBit(record, false); 198 } 199 } 200 SetCapacity(int capacity)201 override public void SetCapacity(int capacity) { 202 Decimal[] newValues = new Decimal[capacity]; 203 if (null != values) { 204 Array.Copy(values, 0, newValues, 0, Math.Min(capacity, values.Length)); 205 } 206 values = newValues; 207 base.SetCapacity(capacity); 208 } 209 ConvertXmlToObject(string s)210 override public object ConvertXmlToObject(string s) { 211 return XmlConvert.ToDecimal(s); 212 } 213 ConvertObjectToXml(object value)214 override public string ConvertObjectToXml(object value) { 215 return XmlConvert.ToString((Decimal)value); 216 } 217 GetEmptyStorage(int recordCount)218 override protected object GetEmptyStorage(int recordCount) { 219 return new Decimal[recordCount]; 220 } 221 CopyValue(int record, object store, BitArray nullbits, int storeIndex)222 override protected void CopyValue(int record, object store, BitArray nullbits, int storeIndex) { 223 Decimal[] typedStore = (Decimal[]) store; 224 typedStore[storeIndex] = values[record]; 225 nullbits.Set(storeIndex, !HasValue(record)); 226 } 227 SetStorage(object store, BitArray nullbits)228 override protected void SetStorage(object store, BitArray nullbits) { 229 values = (Decimal[]) store; 230 SetNullStorage(nullbits); 231 } 232 } 233 } 234