1 //------------------------------------------------------------------------------ 2 // <copyright file="BinaryNode.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 { 11 using System; 12 using System.Diagnostics; 13 using System.Collections.Generic; 14 using System.Globalization; 15 using System.ComponentModel; 16 using System.Data.SqlTypes; 17 using System.Data.Common; 18 19 internal class BinaryNode : ExpressionNode { 20 internal int op; 21 22 internal ExpressionNode left; 23 internal ExpressionNode right; 24 BinaryNode(DataTable table, int op, ExpressionNode left, ExpressionNode right)25 internal BinaryNode(DataTable table, int op, ExpressionNode left, ExpressionNode right) : base(table) { 26 this.op = op; 27 this.left = left; 28 this.right = right; 29 } 30 Bind(DataTable table, List<DataColumn> list)31 internal override void Bind(DataTable table, List<DataColumn> list) { 32 BindTable(table); 33 left.Bind(table, list); 34 right.Bind(table, list); 35 } 36 Eval()37 internal override object Eval() { 38 return Eval(null, DataRowVersion.Default); 39 } 40 Eval(DataRow row, DataRowVersion version)41 internal override object Eval(DataRow row, DataRowVersion version) { 42 return EvalBinaryOp(op, left, right, row, version, null); 43 } 44 Eval(int[] recordNos)45 internal override object Eval(int[] recordNos) { 46 return EvalBinaryOp(op, left, right, null, DataRowVersion.Default, recordNos); 47 } 48 IsConstant()49 internal override bool IsConstant() { 50 // 51 return(left.IsConstant() && right.IsConstant()); 52 } 53 IsTableConstant()54 internal override bool IsTableConstant() { 55 return(left.IsTableConstant() && right.IsTableConstant()); 56 } HasLocalAggregate()57 internal override bool HasLocalAggregate() { 58 return(left.HasLocalAggregate() || right.HasLocalAggregate()); 59 } 60 HasRemoteAggregate()61 internal override bool HasRemoteAggregate() { 62 return(left.HasRemoteAggregate() || right.HasRemoteAggregate()); 63 } 64 DependsOn(DataColumn column)65 internal override bool DependsOn(DataColumn column) { 66 if (left.DependsOn(column)) 67 return true; 68 return right.DependsOn(column); 69 } 70 Optimize()71 internal override ExpressionNode Optimize() { 72 left = left.Optimize(); 73 74 if (op == Operators.Is) { 75 // only 'Is Null' or 'Is Not Null' are valid 76 if (right is UnaryNode) { 77 UnaryNode un = (UnaryNode)right; 78 if (un.op != Operators.Not) { 79 throw ExprException.InvalidIsSyntax(); 80 } 81 op = Operators.IsNot; 82 right = un.right; 83 } 84 if (right is ZeroOpNode) { 85 if (((ZeroOpNode)right).op != Operators.Null) { 86 throw ExprException.InvalidIsSyntax(); 87 } 88 } 89 else { 90 throw ExprException.InvalidIsSyntax(); 91 } 92 } 93 else { 94 right = right.Optimize(); 95 } 96 97 98 if (this.IsConstant()) { 99 100 object val = this.Eval(); 101 102 if (val == DBNull.Value) { 103 return new ZeroOpNode(Operators.Null); 104 } 105 106 if (val is bool) { 107 if ((bool)val) 108 return new ZeroOpNode(Operators.True); 109 else 110 return new ZeroOpNode(Operators.False); 111 } 112 return new ConstNode(table, ValueType.Object, val, false); 113 } 114 else 115 return this; 116 } 117 SetTypeMismatchError(int op, Type left, Type right)118 internal void SetTypeMismatchError(int op, Type left, Type right) { 119 throw ExprException.TypeMismatchInBinop(op, left, right); 120 } 121 Eval(ExpressionNode expr, DataRow row, DataRowVersion version, int[] recordNos)122 private static object Eval(ExpressionNode expr, DataRow row, DataRowVersion version, int[] recordNos) { 123 if (recordNos == null) { 124 return expr.Eval(row, version); 125 } 126 else { 127 return expr.Eval(recordNos); 128 } 129 } 130 BinaryCompare(object vLeft, object vRight, StorageType resultType, int op)131 internal int BinaryCompare(object vLeft, object vRight, StorageType resultType, int op) { 132 return BinaryCompare(vLeft, vRight, resultType, op, null); 133 } 134 BinaryCompare(object vLeft, object vRight, StorageType resultType, int op, CompareInfo comparer)135 internal int BinaryCompare(object vLeft, object vRight, StorageType resultType, int op, CompareInfo comparer) { 136 int result = 0; 137 try { 138 if (!DataStorage.IsSqlType(resultType)) { 139 switch(resultType) { 140 case StorageType.SByte: 141 case StorageType.Int16: 142 case StorageType.Int32: 143 case StorageType.Byte: 144 case StorageType.UInt16: 145 return Convert.ToInt32(vLeft, FormatProvider).CompareTo(Convert.ToInt32(vRight, FormatProvider)); 146 case StorageType.Int64: 147 case StorageType.UInt32: 148 case StorageType.UInt64: 149 case StorageType.Decimal: 150 return Decimal.Compare(Convert.ToDecimal(vLeft, FormatProvider), Convert.ToDecimal(vRight, FormatProvider)); 151 case StorageType.Char: 152 return Convert.ToInt32(vLeft, FormatProvider).CompareTo(Convert.ToInt32(vRight, FormatProvider)); 153 case StorageType.Double: 154 return Convert.ToDouble(vLeft, FormatProvider).CompareTo(Convert.ToDouble(vRight, FormatProvider)); 155 case StorageType.Single: 156 return Convert.ToSingle(vLeft, FormatProvider).CompareTo(Convert.ToSingle(vRight, FormatProvider)); 157 case StorageType.DateTime: 158 return DateTime.Compare(Convert.ToDateTime(vLeft, FormatProvider), Convert.ToDateTime(vRight, FormatProvider)); 159 case StorageType.DateTimeOffset: 160 // DTO can only be compared to DTO, other cases: cast Exception 161 return DateTimeOffset.Compare((DateTimeOffset)vLeft, (DateTimeOffset)vRight); 162 case StorageType.String: 163 return table.Compare(Convert.ToString(vLeft, FormatProvider), Convert.ToString(vRight, FormatProvider), comparer); 164 case StorageType.Guid: 165 return ((Guid)vLeft).CompareTo((Guid) vRight); 166 case StorageType.Boolean: 167 if (op == Operators.EqualTo || op == Operators.NotEqual) { 168 return Convert.ToInt32(DataExpression.ToBoolean(vLeft), FormatProvider) - 169 Convert.ToInt32(DataExpression.ToBoolean(vRight), FormatProvider); 170 } 171 break; 172 } 173 } 174 else{ 175 switch(resultType) { 176 case StorageType.SByte: 177 case StorageType.Int16: 178 case StorageType.Int32: 179 case StorageType.Byte: 180 case StorageType.UInt16: 181 case StorageType.SqlByte: 182 case StorageType.SqlInt16: 183 case StorageType.SqlInt32: 184 return SqlConvert.ConvertToSqlInt32(vLeft).CompareTo(SqlConvert.ConvertToSqlInt32(vRight)); 185 case StorageType.Int64: 186 case StorageType.UInt32: 187 case StorageType.SqlInt64: 188 return SqlConvert.ConvertToSqlInt64(vLeft).CompareTo(SqlConvert.ConvertToSqlInt64(vRight)); 189 case StorageType.UInt64: 190 case StorageType.SqlDecimal: 191 return SqlConvert.ConvertToSqlDecimal(vLeft).CompareTo(SqlConvert.ConvertToSqlDecimal(vRight)); 192 case StorageType.SqlDouble: 193 return SqlConvert.ConvertToSqlDouble(vLeft).CompareTo(SqlConvert.ConvertToSqlDouble(vRight)); 194 case StorageType.SqlSingle: 195 return SqlConvert.ConvertToSqlSingle(vLeft).CompareTo(SqlConvert.ConvertToSqlSingle(vRight)); 196 case StorageType.SqlString: 197 return table.Compare(vLeft.ToString(), vRight.ToString()); 198 case StorageType.SqlGuid: 199 return ((SqlGuid)vLeft).CompareTo(vRight); 200 case StorageType.SqlBoolean: 201 if (op == Operators.EqualTo || op == Operators.NotEqual) { 202 result = 1; 203 if (((vLeft.GetType() == typeof(SqlBoolean)) && ((vRight.GetType() == typeof(SqlBoolean))|| (vRight.GetType() == typeof(Boolean))))|| 204 ((vRight.GetType() == typeof(SqlBoolean)) && ((vLeft.GetType() == typeof(SqlBoolean))|| (vLeft.GetType() == typeof(Boolean))))){ 205 return SqlConvert.ConvertToSqlBoolean(vLeft).CompareTo(SqlConvert.ConvertToSqlBoolean(vRight)); 206 } 207 } 208 break; 209 case StorageType.SqlBinary: 210 return SqlConvert.ConvertToSqlBinary(vLeft).CompareTo(SqlConvert.ConvertToSqlBinary(vRight)); 211 case StorageType.SqlDateTime: 212 return SqlConvert.ConvertToSqlDateTime(vLeft).CompareTo(SqlConvert.ConvertToSqlDateTime(vRight)); 213 case StorageType.SqlMoney: 214 return SqlConvert.ConvertToSqlMoney(vLeft).CompareTo(SqlConvert.ConvertToSqlMoney(vRight)); 215 } 216 } 217 } 218 catch (System.ArgumentException e) { 219 ExceptionBuilder.TraceExceptionWithoutRethrow(e); 220 } 221 catch (System.FormatException e) { 222 ExceptionBuilder.TraceExceptionWithoutRethrow(e); 223 } 224 catch (System.InvalidCastException e) { 225 ExceptionBuilder.TraceExceptionWithoutRethrow(e); 226 } 227 catch (System.OverflowException e) { 228 ExceptionBuilder.TraceExceptionWithoutRethrow(e); 229 } 230 catch (System.Data.EvaluateException e) { 231 ExceptionBuilder.TraceExceptionWithoutRethrow(e); 232 } 233 SetTypeMismatchError(op, vLeft.GetType(), vRight.GetType()); 234 return result; 235 } 236 EvalBinaryOp(int op, ExpressionNode left, ExpressionNode right, DataRow row, DataRowVersion version, int[] recordNos)237 private object EvalBinaryOp(int op, ExpressionNode left, ExpressionNode right, DataRow row, DataRowVersion version, int[] recordNos) { 238 object vLeft; 239 object vRight; 240 StorageType resultType; 241 242 /* 243 special case for OR and AND operators: we don't want to evaluate 244 both right and left operands, because we can shortcut : 245 for OR operator If one of the operands is true the result is true 246 for AND operator If one of rhe operands is flase the result is false 247 248 */ 249 250 if (op != Operators.Or && op != Operators.And && op != Operators.In && op != Operators.Is && op != Operators.IsNot) { 251 vLeft = BinaryNode.Eval(left, row, version, recordNos); 252 vRight = BinaryNode.Eval(right, row, version, recordNos); 253 Type typeofLeft = vLeft.GetType(); 254 Type typeofRight = vRight.GetType(); 255 256 StorageType leftStorage = DataStorage.GetStorageType(typeofLeft); 257 StorageType rightStorage = DataStorage.GetStorageType(typeofRight); 258 259 bool leftIsSqlType = DataStorage.IsSqlType(leftStorage); 260 bool rightIsSqlType = DataStorage.IsSqlType(rightStorage); 261 262 // special case of handling NULLS, currently only OR operator can work with NULLS 263 if (leftIsSqlType && DataStorage.IsObjectSqlNull(vLeft)) { 264 return vLeft; 265 } 266 else if (rightIsSqlType && DataStorage.IsObjectSqlNull(vRight)) { 267 return vRight; 268 } 269 else if ((vLeft == DBNull.Value)||(vRight == DBNull.Value)) { 270 return DBNull.Value; 271 } 272 273 if (leftIsSqlType || rightIsSqlType) { 274 resultType = ResultSqlType(leftStorage, rightStorage, (left is ConstNode), (right is ConstNode), op); 275 } 276 else { 277 resultType = ResultType(leftStorage, rightStorage, (left is ConstNode), (right is ConstNode), op); 278 } 279 280 if (StorageType.Empty == resultType) { 281 SetTypeMismatchError(op, typeofLeft, typeofRight); 282 } 283 284 } 285 else { 286 vLeft = vRight = DBNull.Value; 287 resultType = StorageType.Empty; // shouldnt we make it boolean? 288 } 289 290 object value = DBNull.Value; 291 bool typeMismatch = false; 292 293 try { 294 switch (op) { 295 case Operators.Plus: 296 switch(resultType) { 297 case StorageType.Byte:{ 298 value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) + Convert.ToByte(vRight, FormatProvider)), FormatProvider); 299 break;} 300 case StorageType.SByte:{ 301 value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) + Convert.ToSByte(vRight, FormatProvider)), FormatProvider); 302 break;} 303 case StorageType.Int16:{ 304 value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) + Convert.ToInt16(vRight, FormatProvider)), FormatProvider); 305 break;} 306 case StorageType.UInt16:{ 307 value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) + Convert.ToUInt16(vRight, FormatProvider)), FormatProvider); 308 break;} 309 case StorageType.Int32: { 310 checked {value = Convert.ToInt32(vLeft, FormatProvider) + Convert.ToInt32(vRight, FormatProvider);} 311 break;} 312 case StorageType.UInt32: { 313 checked {value = Convert.ToUInt32(vLeft, FormatProvider) + Convert.ToUInt32(vRight, FormatProvider);} 314 break;} 315 case StorageType.UInt64: { 316 checked {value = Convert.ToUInt64(vLeft, FormatProvider) + Convert.ToUInt64(vRight, FormatProvider);} 317 break;} 318 case StorageType.Int64:{ 319 checked {value = Convert.ToInt64(vLeft, FormatProvider) + Convert.ToInt64(vRight, FormatProvider);} 320 break;} 321 case StorageType.Decimal:{ 322 checked {value = Convert.ToDecimal(vLeft, FormatProvider) + Convert.ToDecimal(vRight, FormatProvider);} 323 break;} 324 case StorageType.Single:{ 325 checked {value = Convert.ToSingle(vLeft, FormatProvider) + Convert.ToSingle(vRight, FormatProvider);} 326 break;} 327 case StorageType.Double:{ 328 checked {value = Convert.ToDouble(vLeft, FormatProvider) + Convert.ToDouble(vRight, FormatProvider);} 329 break;} 330 case StorageType.String: 331 case StorageType.Char:{ 332 value = Convert.ToString(vLeft, FormatProvider) + Convert.ToString(vRight, FormatProvider); 333 break;} 334 case StorageType.DateTime:{ 335 // one of the operands should be a DateTime, and an other a TimeSpan 336 337 if (vLeft is TimeSpan && vRight is DateTime) { 338 value = (DateTime)vRight + (TimeSpan)vLeft; 339 } 340 else if (vLeft is DateTime && vRight is TimeSpan) { 341 value = (DateTime)vLeft + (TimeSpan)vRight; 342 } 343 else { 344 typeMismatch = true; 345 } 346 break;} 347 case StorageType.TimeSpan:{ 348 value = (TimeSpan)vLeft + (TimeSpan)vRight; 349 break;} 350 case StorageType.SqlInt16:{ 351 value = (SqlConvert.ConvertToSqlInt16(vLeft) + SqlConvert.ConvertToSqlInt16(vRight)); 352 break;} 353 case StorageType.SqlInt32:{ 354 value = ( SqlConvert.ConvertToSqlInt32(vLeft) + SqlConvert.ConvertToSqlInt32(vRight)); 355 break;} 356 case StorageType.SqlInt64:{ 357 value = (SqlConvert.ConvertToSqlInt64(vLeft) + SqlConvert.ConvertToSqlInt64(vRight)); 358 break;} 359 case StorageType.SqlDouble:{ 360 value = (SqlConvert.ConvertToSqlDouble(vLeft) + SqlConvert.ConvertToSqlDouble(vRight)); 361 break;} 362 case StorageType.SqlSingle:{ 363 value = (SqlConvert.ConvertToSqlSingle(vLeft)+ SqlConvert.ConvertToSqlSingle(vRight)); 364 break;} 365 case StorageType.SqlDecimal:{ 366 value = (SqlConvert.ConvertToSqlDecimal(vLeft) + SqlConvert.ConvertToSqlDecimal(vRight)); 367 break;} 368 case StorageType.SqlMoney:{ 369 value = (SqlConvert.ConvertToSqlMoney(vLeft) + SqlConvert.ConvertToSqlMoney(vRight)); 370 break;} 371 case StorageType.SqlByte:{ 372 value = (SqlConvert.ConvertToSqlByte(vLeft) + SqlConvert.ConvertToSqlByte(vRight)); 373 break;} 374 case StorageType.SqlString:{ 375 value = (SqlConvert.ConvertToSqlString(vLeft) + SqlConvert.ConvertToSqlString(vRight)); 376 break;} 377 case StorageType.SqlDateTime:{ 378 if (vLeft is TimeSpan && vRight is SqlDateTime) { 379 SqlDateTime rValue = (SqlDateTime)SqlConvert.ConvertToSqlDateTime(vRight); 380 value = (SqlDateTime)SqlConvert.ConvertToSqlDateTime((DateTime)rValue.Value + (TimeSpan)vLeft); 381 } 382 else if (vLeft is SqlDateTime && vRight is TimeSpan) { 383 SqlDateTime lValue = (SqlDateTime)SqlConvert.ConvertToSqlDateTime(vLeft); 384 value = (SqlDateTime)SqlConvert.ConvertToSqlDateTime((DateTime)lValue.Value + (TimeSpan)vRight); 385 } 386 else { 387 typeMismatch = true; 388 } 389 break;} 390 default:{ 391 typeMismatch = true; 392 break;} 393 } 394 break; // Operators.Plus 395 396 case Operators.Minus: 397 switch(resultType) { 398 case StorageType.Byte: { 399 value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) - Convert.ToByte(vRight, FormatProvider)), FormatProvider); 400 break; } 401 case StorageType.SqlByte: { 402 value = (SqlConvert.ConvertToSqlByte(vLeft) - SqlConvert.ConvertToSqlByte(vRight)); 403 break;} 404 case StorageType.SByte:{ 405 value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) - Convert.ToSByte(vRight, FormatProvider)), FormatProvider); 406 break;} 407 case StorageType.Int16:{ 408 value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) - Convert.ToInt16(vRight, FormatProvider)), FormatProvider); 409 break;} 410 case StorageType.SqlInt16:{ 411 value = (SqlConvert.ConvertToSqlInt16(vLeft) - SqlConvert.ConvertToSqlInt16(vRight)); 412 break;} 413 case StorageType.UInt16:{ 414 value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) - Convert.ToUInt16(vRight, FormatProvider)), FormatProvider); 415 break;} 416 case StorageType.Int32:{ 417 checked {value = Convert.ToInt32(vLeft, FormatProvider) - Convert.ToInt32(vRight, FormatProvider);} 418 break;} 419 case StorageType.SqlInt32:{ 420 value = (SqlConvert.ConvertToSqlInt32(vLeft) - SqlConvert.ConvertToSqlInt32(vRight)); 421 break;} 422 case StorageType.UInt32:{ 423 checked {value = Convert.ToUInt32(vLeft, FormatProvider) - Convert.ToUInt32(vRight, FormatProvider);} 424 break;} 425 case StorageType.Int64:{ 426 checked {value = Convert.ToInt64(vLeft, FormatProvider) - Convert.ToInt64(vRight, FormatProvider);} 427 break;} 428 case StorageType.SqlInt64:{ 429 value = (SqlConvert.ConvertToSqlInt64(vLeft) - SqlConvert.ConvertToSqlInt64(vRight)); 430 break;} 431 case StorageType.UInt64:{ 432 checked {value = Convert.ToUInt64(vLeft, FormatProvider) - Convert.ToUInt64(vRight, FormatProvider);} 433 break;} 434 case StorageType.Decimal:{ 435 checked {value = Convert.ToDecimal(vLeft, FormatProvider) - Convert.ToDecimal(vRight, FormatProvider);} 436 break;} 437 case StorageType.SqlDecimal:{ 438 value = (SqlConvert.ConvertToSqlDecimal(vLeft) - SqlConvert.ConvertToSqlDecimal(vRight)); 439 break;} 440 case StorageType.Single:{ 441 checked {value = Convert.ToSingle(vLeft, FormatProvider) - Convert.ToSingle(vRight, FormatProvider);} 442 break;} 443 case StorageType.SqlSingle:{ 444 value = (SqlConvert.ConvertToSqlSingle(vLeft) - SqlConvert.ConvertToSqlSingle(vRight)); 445 break;} 446 case StorageType.Double:{ 447 checked {value = Convert.ToDouble(vLeft, FormatProvider) - Convert.ToDouble(vRight, FormatProvider);} 448 break;} 449 case StorageType.SqlDouble:{ 450 value = (SqlConvert.ConvertToSqlDouble(vLeft) - SqlConvert.ConvertToSqlDouble(vRight)); 451 break;} 452 case StorageType.SqlMoney:{ 453 value = (SqlConvert.ConvertToSqlMoney(vLeft) - SqlConvert.ConvertToSqlMoney(vRight)); 454 break;} 455 case StorageType.DateTime:{ 456 value = (DateTime)vLeft - (TimeSpan)vRight; 457 break;} 458 case StorageType.TimeSpan:{ 459 if (vLeft is DateTime) { 460 value = (DateTime)vLeft - (DateTime)vRight; 461 } 462 else 463 value = (TimeSpan)vLeft - (TimeSpan)vRight; 464 break;} 465 case StorageType.SqlDateTime:{ 466 if (vLeft is TimeSpan && vRight is SqlDateTime) { 467 SqlDateTime rValue = (SqlDateTime)SqlConvert.ConvertToSqlDateTime(vRight); 468 value = (SqlDateTime)SqlConvert.ConvertToSqlDateTime((DateTime)rValue.Value - (TimeSpan)vLeft); 469 } 470 else if (vLeft is SqlDateTime && vRight is TimeSpan) { 471 SqlDateTime lValue = (SqlDateTime)SqlConvert.ConvertToSqlDateTime(vLeft); 472 value = (SqlDateTime)SqlConvert.ConvertToSqlDateTime((DateTime)lValue.Value - (TimeSpan)vRight); 473 } 474 else { 475 typeMismatch = true; 476 } 477 break;} 478 default:{ 479 typeMismatch = true; 480 break;} 481 } 482 break; // Operators.Minus 483 484 case Operators.Multiply: 485 switch(resultType) { 486 case StorageType.Byte:{ 487 value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) * Convert.ToByte(vRight, FormatProvider)), FormatProvider); 488 break;} 489 case StorageType.SqlByte:{ 490 value = (SqlConvert.ConvertToSqlByte(vLeft) * SqlConvert.ConvertToSqlByte(vRight)); 491 break;} 492 case StorageType.SByte:{ 493 value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) * Convert.ToSByte(vRight, FormatProvider)), FormatProvider); 494 break;} 495 case StorageType.Int16:{ 496 value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) * Convert.ToInt16(vRight, FormatProvider)), FormatProvider); 497 break;} 498 case StorageType.SqlInt16:{ 499 value = (SqlConvert.ConvertToSqlInt16(vLeft) * SqlConvert.ConvertToSqlInt16(vRight)); 500 break;} 501 case StorageType.UInt16:{ 502 value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) * Convert.ToUInt16(vRight, FormatProvider)), FormatProvider); 503 break;} 504 case StorageType.Int32:{ 505 checked {value = Convert.ToInt32(vLeft, FormatProvider) * Convert.ToInt32(vRight, FormatProvider);} 506 break;} 507 case StorageType.SqlInt32:{ 508 value = (SqlConvert.ConvertToSqlInt32(vLeft) * SqlConvert.ConvertToSqlInt32(vRight)); 509 break;} 510 case StorageType.UInt32:{ 511 checked {value = Convert.ToUInt32(vLeft, FormatProvider) * Convert.ToUInt32(vRight, FormatProvider);} 512 break;} 513 case StorageType.Int64:{ 514 515 checked {value = Convert.ToInt64(vLeft, FormatProvider) * Convert.ToInt64(vRight, FormatProvider);} 516 break;} 517 case StorageType.SqlInt64:{ 518 value = (SqlConvert.ConvertToSqlInt64(vLeft) * SqlConvert.ConvertToSqlInt64(vRight)); 519 break;} 520 case StorageType.UInt64:{ 521 checked {value = Convert.ToUInt64(vLeft, FormatProvider) * Convert.ToUInt64(vRight, FormatProvider);} 522 break;} 523 case StorageType.Decimal:{ 524 checked {value = Convert.ToDecimal(vLeft, FormatProvider) * Convert.ToDecimal(vRight, FormatProvider);} 525 break;} 526 case StorageType.SqlDecimal:{ 527 value = (SqlConvert.ConvertToSqlDecimal(vLeft) * SqlConvert.ConvertToSqlDecimal(vRight)); 528 break;} 529 case StorageType.Single:{ 530 checked {value = Convert.ToSingle(vLeft, FormatProvider) * Convert.ToSingle(vRight, FormatProvider);} 531 break;} 532 case StorageType.SqlSingle:{ 533 value = ( SqlConvert.ConvertToSqlSingle(vLeft) * SqlConvert.ConvertToSqlSingle(vRight)); 534 break;} 535 case StorageType.SqlMoney:{ 536 value = (SqlConvert.ConvertToSqlMoney(vLeft) * SqlConvert.ConvertToSqlMoney(vRight)); 537 break;} 538 case StorageType.Double:{ 539 checked {value = Convert.ToDouble(vLeft, FormatProvider) * Convert.ToDouble(vRight, FormatProvider);} 540 break;} 541 case StorageType.SqlDouble:{ 542 value = (SqlConvert.ConvertToSqlDouble(vLeft) * SqlConvert.ConvertToSqlDouble(vRight)); 543 break;} 544 default:{ 545 typeMismatch = true; 546 break;} 547 } 548 break; // Operators.Multiply 549 550 case Operators.Divide: 551 switch(resultType) { 552 case StorageType.Byte:{ 553 value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) / Convert.ToByte(vRight, FormatProvider)), FormatProvider); 554 break;} 555 case StorageType.SqlByte:{ 556 value = (SqlConvert.ConvertToSqlByte(vLeft) / SqlConvert.ConvertToSqlByte(vRight)); 557 break;} 558 case StorageType.SByte:{ 559 value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) / Convert.ToSByte(vRight, FormatProvider)), FormatProvider); 560 break;} 561 case StorageType.Int16:{ 562 value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) / Convert.ToInt16(vRight, FormatProvider)), FormatProvider); 563 break;} 564 case StorageType.SqlInt16:{ 565 value = (SqlConvert.ConvertToSqlInt16(vLeft) / SqlConvert.ConvertToSqlInt16(vRight)); 566 break;} 567 case StorageType.UInt16:{ 568 value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) / Convert.ToUInt16(vRight, FormatProvider)), FormatProvider); 569 break;} 570 case StorageType.Int32:{ 571 checked {value = Convert.ToInt32(vLeft, FormatProvider) / Convert.ToInt32(vRight, FormatProvider);} 572 break;} 573 case StorageType.SqlInt32:{ 574 value = (SqlConvert.ConvertToSqlInt32(vLeft) / SqlConvert.ConvertToSqlInt32(vRight)); 575 break;} 576 case StorageType.UInt32:{ 577 checked {value = Convert.ToUInt32(vLeft, FormatProvider) / Convert.ToUInt32(vRight, FormatProvider);} 578 break;} 579 case StorageType.UInt64:{ 580 checked {value = Convert.ToUInt64(vLeft, FormatProvider) / Convert.ToUInt64(vRight, FormatProvider);} 581 break;} 582 case StorageType.Int64:{ 583 checked {value = Convert.ToInt64(vLeft, FormatProvider) / Convert.ToInt64(vRight, FormatProvider);} 584 break;} 585 case StorageType.SqlInt64:{ 586 value = (SqlConvert.ConvertToSqlInt64(vLeft) / SqlConvert.ConvertToSqlInt64(vRight)); 587 break;} 588 case StorageType.Decimal:{ 589 checked {value = Convert.ToDecimal(vLeft, FormatProvider) / Convert.ToDecimal(vRight, FormatProvider);} 590 break;} 591 case StorageType.SqlDecimal:{ 592 value = (SqlConvert.ConvertToSqlDecimal(vLeft) / SqlConvert.ConvertToSqlDecimal(vRight)); 593 break;} 594 case StorageType.Single:{ 595 checked {value = Convert.ToSingle(vLeft, FormatProvider) / Convert.ToSingle(vRight, FormatProvider);} 596 break;} 597 case StorageType.SqlSingle:{ 598 value = ( SqlConvert.ConvertToSqlSingle(vLeft) / SqlConvert.ConvertToSqlSingle(vRight)); 599 break;} 600 case StorageType.SqlMoney:{ 601 value = (SqlConvert.ConvertToSqlMoney(vLeft) / SqlConvert.ConvertToSqlMoney(vRight)); 602 break;} 603 case StorageType.Double:{ 604 Double b = Convert.ToDouble(vRight, FormatProvider); 605 checked {value = Convert.ToDouble(vLeft, FormatProvider) / b;} 606 break;} 607 case StorageType.SqlDouble:{ 608 value = (SqlConvert.ConvertToSqlDouble(vLeft) / SqlConvert.ConvertToSqlDouble(vRight)); 609 break;} 610 default:{ 611 typeMismatch = true; 612 break;} 613 } 614 break; // Operators.Divide 615 616 case Operators.EqualTo: 617 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) || 618 (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight))) 619 return DBNull.Value; 620 return(0 == BinaryCompare (vLeft, vRight, resultType, Operators.EqualTo)); 621 622 case Operators.GreaterThen: 623 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) || 624 (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight))) 625 return DBNull.Value; 626 return(0 < BinaryCompare (vLeft, vRight, resultType, op)); 627 628 case Operators.LessThen: 629 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) || 630 (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight))) 631 return DBNull.Value; 632 return(0 > BinaryCompare (vLeft, vRight, resultType, op)); 633 634 case Operators.GreaterOrEqual: 635 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) || 636 (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight))) 637 return DBNull.Value; 638 return(0 <= BinaryCompare (vLeft, vRight, resultType, op)); 639 640 case Operators.LessOrEqual: 641 if (((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))) || 642 ((vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))) 643 return DBNull.Value; 644 return(0 >= BinaryCompare (vLeft, vRight, resultType, op)); 645 646 case Operators.NotEqual: 647 if (((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))) || 648 ((vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))) 649 return DBNull.Value; 650 return(0 != BinaryCompare (vLeft, vRight, resultType, op)); 651 652 case Operators.Is: 653 vLeft = BinaryNode.Eval(left, row, version, recordNos); 654 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))){ 655 return true; 656 } 657 return false; 658 659 case Operators.IsNot: 660 vLeft = BinaryNode.Eval(left, row, version, recordNos); 661 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))){ 662 return false; 663 } 664 return true; 665 666 case Operators.And: 667 /* 668 special case evaluating of the AND operator: we don't want to evaluate 669 both right and left operands, because we can shortcut : 670 If one of the operands is flase the result is false 671 672 */ 673 vLeft = BinaryNode.Eval(left, row, version, recordNos); 674 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))) 675 return DBNull.Value; 676 677 if ((!(vLeft is bool)) && (!(vLeft is SqlBoolean))){ 678 vRight = BinaryNode.Eval(right, row, version, recordNos); 679 typeMismatch = true; 680 break; 681 } 682 683 if (vLeft is bool){ 684 if ((bool)vLeft == false){ 685 value = false; 686 break; 687 } 688 } 689 else{ 690 if (((SqlBoolean) vLeft).IsFalse){ 691 value = false; 692 break; 693 } 694 } 695 vRight = BinaryNode.Eval(right, row, version, recordNos); 696 if ((vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight ))) 697 return DBNull.Value; 698 699 if ((!(vRight is bool)) && (!(vRight is SqlBoolean))){ 700 typeMismatch = true; 701 break; 702 } 703 704 if (vRight is bool){ 705 value = (bool)vRight; 706 break; 707 } 708 else{ 709 value = ((SqlBoolean) vRight).IsTrue; 710 } 711 break; 712 case Operators.Or: 713 /* 714 special case evaluating the OR operator: we don't want to evaluate 715 both right and left operands, because we can shortcut : 716 If one of the operands is true the result is true 717 718 */ 719 720 vLeft = BinaryNode.Eval(left, row, version, recordNos); 721 722 if ((vLeft != DBNull.Value) && (!DataStorage.IsObjectSqlNull(vLeft))) { 723 if ((!(vLeft is bool)) && (!(vLeft is SqlBoolean))) { 724 vRight = BinaryNode.Eval(right, row, version, recordNos); 725 typeMismatch = true; 726 break; 727 } 728 729 if ((bool)vLeft == true) { 730 value = true; 731 break; 732 } 733 } 734 735 vRight = BinaryNode.Eval(right, row, version, recordNos); 736 if ((vRight == DBNull.Value)||(DataStorage.IsObjectSqlNull(vRight))) 737 return vLeft; 738 739 if ((vLeft == DBNull.Value)||(DataStorage.IsObjectSqlNull(vLeft))) 740 return vRight; 741 742 if ((!(vRight is bool)) && (!(vRight is SqlBoolean))) { 743 typeMismatch = true; 744 break; 745 } 746 747 value = (vRight is bool) ? ((bool)vRight) : (((SqlBoolean)vRight).IsTrue); 748 break; 749 750 /* for M3, use original code , in below, and make sure to have two different code path; increases perf 751 752 vLeft = BinaryNode.Eval(left, row, version, recordNos); 753 if (vLeft != DBNull.Value) { 754 if (!(vLeft is bool)) { 755 vRight = BinaryNode.Eval(right, row, version, recordNos); 756 typeMismatch = true; 757 break; 758 } 759 760 if ((bool)vLeft == true) { 761 value = true; 762 break; 763 } 764 } 765 766 vRight = BinaryNode.Eval(right, row, version, recordNos); 767 if (vRight == DBNull.Value) 768 return vLeft; 769 770 if (vLeft == DBNull.Value) 771 return vRight; 772 773 if (!(vRight is bool)) { 774 typeMismatch = true; 775 break; 776 } 777 778 value = (bool)vRight; 779 break; 780 */ 781 782 case Operators.Modulo: 783 if (ExpressionNode.IsIntegerSql(resultType)) { 784 if (resultType == StorageType.UInt64) { 785 value = Convert.ToUInt64(vLeft, FormatProvider) % Convert.ToUInt64(vRight, FormatProvider); 786 } 787 else if (DataStorage.IsSqlType(resultType)) { 788 SqlInt64 res = (SqlConvert.ConvertToSqlInt64(vLeft) % SqlConvert.ConvertToSqlInt64(vRight)); 789 790 if (resultType == StorageType.SqlInt32){ 791 value = (SqlInt32) res.ToSqlInt32(); 792 } 793 else if (resultType == StorageType.SqlInt16){ 794 value = (SqlInt16) res.ToSqlInt16(); 795 } 796 else if (resultType == StorageType.SqlByte){ 797 value = (SqlByte) res.ToSqlByte(); 798 } 799 else{ 800 value = (SqlInt64) res; 801 } 802 } 803 else { 804 value = Convert.ToInt64(vLeft, FormatProvider) % Convert.ToInt64(vRight, FormatProvider); 805 value = Convert.ChangeType(value, DataStorage.GetTypeStorage(resultType), FormatProvider); 806 } 807 } 808 else { 809 typeMismatch = true; 810 } 811 break; 812 813 case Operators.In: 814 /* 815 special case evaluating of the IN operator: the right have to be IN function node 816 */ 817 818 819 if (!(right is FunctionNode)) { 820 // this is more like an Assert: should never happens, so we do not care about "nice" Exseptions 821 throw ExprException.InWithoutParentheses(); 822 } 823 824 vLeft = BinaryNode.Eval(left, row, version, recordNos); 825 826 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))) 827 return DBNull.Value; 828 829 /* validate IN parameters : must all be constant expressions */ 830 831 value = false; 832 833 FunctionNode into = (FunctionNode)right; 834 835 for (int i = 0; i < into.argumentCount; i++) { 836 vRight = into.arguments[i].Eval(); 837 838 839 if ((vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight))) 840 continue; 841 Debug.Assert((!DataStorage.IsObjectNull(vLeft))&& (!DataStorage.IsObjectNull(vRight)), "Imposible.."); 842 843 resultType = DataStorage.GetStorageType(vLeft.GetType()); 844 845 if (0 == BinaryCompare(vLeft, vRight, resultType, Operators.EqualTo)) { 846 value = true; 847 break; 848 } 849 } 850 break; 851 852 default: 853 throw ExprException.UnsupportedOperator(op); 854 } 855 } 856 catch (OverflowException) { 857 throw ExprException.Overflow(DataStorage.GetTypeStorage(resultType)); 858 } 859 if (typeMismatch) { 860 SetTypeMismatchError(op, vLeft.GetType(), vRight.GetType()); 861 } 862 863 return value; 864 } 865 866 // Data type precedence rules specify which data type is converted to the other. 867 // The data type with the lower precedence is converted to the data type with the higher precedence. 868 // If the conversion is not a supported implicit conversion, an error is returned. 869 // When both operand expressions have the same data type, the result of the operation has that data type. 870 // This is the precedence order for the DataSet numeric data types: 871 872 private enum DataTypePrecedence { 873 SqlDateTime = 25, 874 DateTimeOffset = 24, 875 DateTime = 23, 876 TimeSpan = 20, 877 SqlDouble = 19, 878 Double = 18, 879 SqlSingle = 17, 880 Single = 16, 881 SqlDecimal = 15, 882 Decimal = 14, 883 SqlMoney = 13, 884 UInt64 = 12, 885 SqlInt64 = 11, 886 Int64 = 10, 887 UInt32 = 9, 888 SqlInt32 = 8, 889 Int32 = 7, 890 UInt16 = 6, 891 SqlInt16 = 5, 892 Int16 = 4, 893 Byte = 3, 894 SqlByte = 2, 895 SByte = 1, 896 Error = 0, 897 SqlBoolean = -1, 898 Boolean = -2, 899 SqlGuid = -3, 900 SqlString = -4, 901 String = -5, 902 SqlXml = -6, 903 SqlChars = -7, 904 Char = -8, 905 SqlBytes = -9, 906 SqlBinary = -10, 907 } 908 GetPrecedence(StorageType storageType)909 private DataTypePrecedence GetPrecedence(StorageType storageType) { 910 switch(storageType) { 911 case StorageType.Boolean: return DataTypePrecedence.Boolean; 912 case StorageType.Char: return DataTypePrecedence.Char; 913 case StorageType.SByte: return DataTypePrecedence.SByte; 914 case StorageType.Byte: return DataTypePrecedence.Byte; 915 case StorageType.Int16: return DataTypePrecedence.Int16; 916 case StorageType.UInt16: return DataTypePrecedence.UInt16; 917 case StorageType.Int32: return DataTypePrecedence.Int32; 918 case StorageType.UInt32: return DataTypePrecedence.UInt32; 919 case StorageType.Int64: return DataTypePrecedence.Int64; 920 case StorageType.UInt64: return DataTypePrecedence.UInt64; 921 case StorageType.Single: return DataTypePrecedence.Single; 922 case StorageType.Double: return DataTypePrecedence.Double; 923 case StorageType.Decimal: return DataTypePrecedence.Decimal; 924 case StorageType.DateTime: return DataTypePrecedence.DateTime; 925 case StorageType.DateTimeOffset: return DataTypePrecedence.DateTimeOffset; 926 case StorageType.TimeSpan: return DataTypePrecedence.TimeSpan; 927 case StorageType.String: return DataTypePrecedence.String; 928 case StorageType.SqlBinary: return DataTypePrecedence.SqlBinary; 929 case StorageType.SqlBoolean: return DataTypePrecedence.SqlBoolean; 930 case StorageType.SqlByte: return DataTypePrecedence.SqlByte; 931 case StorageType.SqlBytes: return DataTypePrecedence.SqlBytes; 932 case StorageType.SqlChars: return DataTypePrecedence.SqlChars; 933 case StorageType.SqlDateTime: return DataTypePrecedence.SqlDateTime; 934 case StorageType.SqlDecimal: return DataTypePrecedence.SqlDecimal; 935 case StorageType.SqlDouble: return DataTypePrecedence.SqlDouble; 936 case StorageType.SqlGuid: return DataTypePrecedence.SqlGuid; 937 case StorageType.SqlInt16: return DataTypePrecedence.SqlInt16; 938 case StorageType.SqlInt32: return DataTypePrecedence.SqlInt32; 939 case StorageType.SqlInt64: return DataTypePrecedence.SqlInt64; 940 case StorageType.SqlMoney: return DataTypePrecedence.SqlMoney; 941 case StorageType.SqlSingle: return DataTypePrecedence.SqlSingle; 942 case StorageType.SqlString: return DataTypePrecedence.SqlString; 943 // case StorageType.SqlXml: return DataTypePrecedence.SqlXml; 944 case StorageType.Empty: 945 case StorageType.Object: 946 case StorageType.DBNull: 947 default: return DataTypePrecedence.Error; 948 } 949 } 950 GetPrecedenceType(DataTypePrecedence code)951 private static StorageType GetPrecedenceType(DataTypePrecedence code) { 952 switch (code) { 953 case DataTypePrecedence.Error: return StorageType.Empty; 954 case DataTypePrecedence.SByte: return StorageType.SByte; 955 case DataTypePrecedence.Byte: return StorageType.Byte; 956 case DataTypePrecedence.Int16: return StorageType.Int16; 957 case DataTypePrecedence.UInt16: return StorageType.UInt16; 958 case DataTypePrecedence.Int32: return StorageType.Int32; 959 case DataTypePrecedence.UInt32: return StorageType.UInt32; 960 case DataTypePrecedence.Int64: return StorageType.Int64; 961 case DataTypePrecedence.UInt64: return StorageType.UInt64; 962 case DataTypePrecedence.Decimal: return StorageType.Decimal; 963 case DataTypePrecedence.Single: return StorageType.Single; 964 case DataTypePrecedence.Double: return StorageType.Double; 965 966 case DataTypePrecedence.Boolean: return StorageType.Boolean; 967 case DataTypePrecedence.String: return StorageType.String; 968 case DataTypePrecedence.Char: return StorageType.Char; 969 970 case DataTypePrecedence.DateTimeOffset: return StorageType.DateTimeOffset; 971 case DataTypePrecedence.DateTime: return StorageType.DateTime; 972 case DataTypePrecedence.TimeSpan: return StorageType.TimeSpan; 973 974 case DataTypePrecedence.SqlDateTime: return StorageType.SqlDateTime; 975 case DataTypePrecedence.SqlDouble: return StorageType.SqlDouble; 976 case DataTypePrecedence.SqlSingle: return StorageType.SqlSingle; 977 case DataTypePrecedence.SqlDecimal: return StorageType.SqlDecimal; 978 case DataTypePrecedence.SqlInt64: return StorageType.SqlInt64; 979 case DataTypePrecedence.SqlInt32: return StorageType.SqlInt32; 980 case DataTypePrecedence.SqlInt16: return StorageType.SqlInt16; 981 case DataTypePrecedence.SqlByte: return StorageType.SqlByte; 982 case DataTypePrecedence.SqlBoolean: return StorageType.SqlBoolean; 983 case DataTypePrecedence.SqlString: return StorageType.SqlString; 984 case DataTypePrecedence.SqlGuid: return StorageType.SqlGuid; 985 case DataTypePrecedence.SqlBinary: return StorageType.SqlBinary; 986 case DataTypePrecedence.SqlMoney: return StorageType.SqlMoney; 987 default: 988 Debug.Assert(false, "Invalid (unmapped) precedence " + code.ToString()); 989 goto case DataTypePrecedence.Error; 990 } 991 } 992 IsMixed(StorageType left, StorageType right)993 private bool IsMixed(StorageType left, StorageType right) { 994 return ((IsSigned(left) && IsUnsigned(right)) || 995 (IsUnsigned(left) && IsSigned(right))); 996 } 997 IsMixedSql(StorageType left, StorageType right)998 private bool IsMixedSql(StorageType left, StorageType right) { 999 return ((IsSignedSql(left) && IsUnsignedSql(right)) || 1000 (IsUnsignedSql(left) && IsSignedSql(right))); 1001 } 1002 ResultType(StorageType left, StorageType right, bool lc, bool rc, int op)1003 internal StorageType ResultType(StorageType left, StorageType right, bool lc, bool rc, int op) { 1004 if ((left == StorageType.Guid) && (right == StorageType.Guid) && Operators.IsRelational(op)) 1005 return left; 1006 if ((left == StorageType.String) && (right == StorageType.Guid) && Operators.IsRelational(op)) 1007 return left; 1008 if ((left == StorageType.Guid) && (right == StorageType.String) && Operators.IsRelational(op)) 1009 return right; 1010 1011 int leftPrecedence = (int)GetPrecedence(left); 1012 if (leftPrecedence == (int)DataTypePrecedence.Error) { 1013 return StorageType.Empty; 1014 } 1015 1016 int rightPrecedence = (int)GetPrecedence(right); 1017 if (rightPrecedence == (int)DataTypePrecedence.Error) { 1018 return StorageType.Empty; 1019 } 1020 1021 if (Operators.IsLogical(op)){ 1022 if (left == StorageType.Boolean && right == StorageType.Boolean) 1023 return StorageType.Boolean; 1024 else 1025 return StorageType.Empty; 1026 } 1027 if ((left == StorageType.DateTimeOffset) ||(right == StorageType.DateTimeOffset)) 1028 { 1029 // Rules to handle DateTimeOffset: 1030 // we only allow Relational operations to operate only on DTO vs DTO 1031 // all other operations: "exception" 1032 if (Operators.IsRelational(op) && left == StorageType.DateTimeOffset && right == StorageType.DateTimeOffset) 1033 return StorageType.DateTimeOffset; 1034 return StorageType.Empty; 1035 } 1036 1037 if ((op == Operators.Plus) && ((left == StorageType.String) || (right == StorageType.String))) 1038 return StorageType.String; 1039 1040 DataTypePrecedence higherPrec = (DataTypePrecedence)Math.Max(leftPrecedence, rightPrecedence); 1041 1042 StorageType result = GetPrecedenceType(higherPrec); 1043 1044 if (Operators.IsArithmetical(op)) { 1045 if (result != StorageType.String && result != StorageType.Char) { 1046 if (!IsNumeric(left)) 1047 return StorageType.Empty; 1048 if (!IsNumeric(right)) 1049 return StorageType.Empty; 1050 } 1051 } 1052 1053 // if the operation is a division the result should be at least a double 1054 1055 if ((op == Operators.Divide) && IsInteger(result)) { 1056 return StorageType.Double; 1057 } 1058 1059 if (IsMixed(left, right)) { 1060 // we are dealing with one signed and one unsigned type so 1061 // try to see if one of them is a ConstNode 1062 if (lc && (!rc)) { 1063 return right; 1064 } 1065 else if ((!lc) && rc) { 1066 return left; 1067 } 1068 1069 if (IsUnsigned(result)) { 1070 if (higherPrec < DataTypePrecedence.UInt64) 1071 // left and right are mixed integers but with the same length 1072 // so promote to the next signed type 1073 result = GetPrecedenceType(higherPrec+1); 1074 else 1075 throw ExprException.AmbiguousBinop(op, DataStorage.GetTypeStorage(left), DataStorage.GetTypeStorage(right)); 1076 } 1077 } 1078 1079 return result; 1080 } 1081 ResultSqlType(StorageType left, StorageType right, bool lc, bool rc, int op)1082 internal StorageType ResultSqlType(StorageType left, StorageType right, bool lc, bool rc, int op) { 1083 int leftPrecedence = (int)GetPrecedence(left); 1084 if (leftPrecedence == (int)DataTypePrecedence.Error) { 1085 return StorageType.Empty; 1086 } 1087 1088 int rightPrecedence = (int)GetPrecedence(right); 1089 if (rightPrecedence == (int)DataTypePrecedence.Error) { 1090 return StorageType.Empty; 1091 } 1092 1093 if (Operators.IsLogical(op)){ 1094 if ((left != StorageType.Boolean && left != StorageType.SqlBoolean) || (right != StorageType.Boolean && right != StorageType.SqlBoolean)) 1095 return StorageType.Empty; 1096 if (left == StorageType.Boolean && right == StorageType.Boolean) 1097 return StorageType.Boolean; 1098 return StorageType.SqlBoolean; 1099 } 1100 1101 if (op == Operators.Plus){ 1102 if((left == StorageType.SqlString) ||(right == StorageType.SqlString)) 1103 return StorageType.SqlString; 1104 if ((left == StorageType.String) || (right == StorageType.String)) 1105 return StorageType.String; 1106 } 1107 //SqlBinary is operable just with SqlBinary 1108 if ((left == StorageType.SqlBinary && right != StorageType.SqlBinary) ||(left != StorageType.SqlBinary && right == StorageType.SqlBinary)) 1109 return StorageType.Empty; 1110 //SqlGuid is operable just with SqlGuid 1111 if((left == StorageType.SqlGuid && right != StorageType.SqlGuid) ||(left != StorageType.SqlGuid && right == StorageType.SqlGuid)) 1112 return StorageType.Empty; 1113 1114 if ((leftPrecedence > (int)DataTypePrecedence.SqlDouble && rightPrecedence <(int) DataTypePrecedence.TimeSpan)){ 1115 return StorageType.Empty; 1116 } 1117 1118 if ((leftPrecedence < (int)DataTypePrecedence.TimeSpan && rightPrecedence >(int) DataTypePrecedence.SqlDouble)){ 1119 return StorageType.Empty; 1120 } 1121 1122 if (leftPrecedence > (int) DataTypePrecedence.SqlDouble){ 1123 if (op == Operators.Plus || op == Operators.Minus){ 1124 if (left == StorageType.TimeSpan) 1125 return right; 1126 if (right == StorageType.TimeSpan) 1127 return left; 1128 return StorageType.Empty; // for plus or minus operations for time types, one of them MUST be time span 1129 } 1130 1131 if (!Operators.IsRelational(op)) 1132 return StorageType.Empty; // we just have relational operations amoung time types 1133 return left; 1134 } 1135 // time types finished 1136 // continue with numerical types, numbers 1137 1138 DataTypePrecedence higherPrec = (DataTypePrecedence)Math.Max(leftPrecedence, rightPrecedence); 1139 1140 StorageType result = GetPrecedenceType(higherPrec); 1141 // if we have at least one Sql type, the intermediate result should be Sql type 1142 result = GetPrecedenceType((DataTypePrecedence)SqlResultType((int)higherPrec)); 1143 1144 if (Operators.IsArithmetical(op)) { 1145 if (result != StorageType.String && result != StorageType.Char && result != StorageType.SqlString) { 1146 if (!IsNumericSql(left)) 1147 return StorageType.Empty; 1148 if (!IsNumericSql(right)) 1149 return StorageType.Empty; 1150 } 1151 } 1152 1153 // if the operation is a division the result should be at least a double 1154 if ((op == Operators.Divide) && IsIntegerSql(result)) { 1155 return StorageType.SqlDouble; 1156 } 1157 1158 if (result == StorageType.SqlMoney){ 1159 if ((left != StorageType.SqlMoney) && (right != StorageType.SqlMoney)) 1160 result = StorageType.SqlDecimal; 1161 } 1162 1163 if (IsMixedSql(left, right)) { 1164 // we are dealing with one signed and one unsigned type so 1165 // try to see if one of them is a ConstNode 1166 1167 if (IsUnsignedSql(result)) { 1168 if (higherPrec < DataTypePrecedence.UInt64) 1169 // left and right are mixed integers but with the same length 1170 // so promote to the next signed type 1171 result = GetPrecedenceType(higherPrec+1); 1172 else 1173 throw ExprException.AmbiguousBinop(op, DataStorage.GetTypeStorage(left), DataStorage.GetTypeStorage(right)); 1174 } 1175 } 1176 1177 return result; 1178 } 1179 SqlResultType(int typeCode)1180 private int SqlResultType(int typeCode){ 1181 switch (typeCode){ 1182 case 23: return 24; 1183 case 20: return 21; 1184 case 18: return 19; 1185 case 16: return 17; 1186 case 14: return 15; 1187 case 12: return 13; 1188 case 9 : 1189 case 10: return 11; 1190 case 6 : 1191 case 7 : return 8; 1192 case 3 : 1193 case 4 : return 5; 1194 case 1 : return 2; 1195 case -2: return -1; 1196 case -5: return -4; 1197 case -8: return -7; 1198 default : return typeCode; 1199 } 1200 } 1201 } 1202 1203 internal sealed class LikeNode : BinaryNode { 1204 // like kinds 1205 internal const int match_left = 1; // <STR>* 1206 internal const int match_right = 2; // *<STR> 1207 internal const int match_middle = 3; // *<STR>* 1208 internal const int match_exact = 4; // <STR> 1209 internal const int match_all = 5; // * 1210 1211 int kind; 1212 string pattern = null; 1213 LikeNode(DataTable table, int op, ExpressionNode left, ExpressionNode right)1214 internal LikeNode(DataTable table, int op, ExpressionNode left, ExpressionNode right) 1215 : base (table, op, left, right) { 1216 } 1217 Eval(DataRow row, DataRowVersion version)1218 internal override object Eval(DataRow row, DataRowVersion version) { 1219 object vRight; 1220 // 1221 object vLeft = left.Eval(row, version); 1222 string substring; 1223 1224 1225 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))) 1226 return DBNull.Value; 1227 1228 if (pattern == null) { 1229 vRight = right.Eval(row, version); 1230 1231 if (!(vRight is string) && !(vRight is SqlString)) { 1232 SetTypeMismatchError(op, vLeft.GetType(), vRight.GetType()); 1233 } 1234 1235 if (vRight == DBNull.Value || DataStorage.IsObjectSqlNull(vRight)) 1236 return DBNull.Value; 1237 string rightStr = (string) SqlConvert.ChangeType2(vRight, StorageType.String, typeof(string), FormatProvider); 1238 1239 1240 // need to convert like pattern to a string 1241 1242 // Parce the original pattern, and get the constant part of it.. 1243 substring = AnalyzePattern(rightStr); 1244 1245 if (right.IsConstant()) 1246 pattern = substring; 1247 } 1248 else { 1249 substring = pattern; 1250 } 1251 1252 if (!(vLeft is string) && !(vLeft is SqlString)) { 1253 SetTypeMismatchError(op, vLeft.GetType(), typeof(string)); 1254 } 1255 1256 // WhiteSpace Chars Include : 0x9, 0xA, 0xB, 0xC, 0xD, 0x20, 0xA0, 0x2000, 0x2001, 0x2002, 0x2003, 0x2004, 0x2005, 0x2006, 0x2007, 0x2008, 0x2009, 0x200A, 0x200B, 0x3000, and 0xFEFF. 1257 char[] trimChars = new char[2] {(char)0x20, (char)0x3000}; 1258 string tempStr; 1259 if (vLeft is SqlString) 1260 tempStr = ((SqlString)vLeft).Value; 1261 else 1262 tempStr = (string)vLeft; 1263 1264 string s1 = (tempStr).TrimEnd(trimChars); 1265 1266 switch (kind) { 1267 case match_all: 1268 return true; 1269 case match_exact: 1270 return(0 == table.Compare(s1, substring)); 1271 case match_middle: 1272 return(0 <= table.IndexOf(s1, substring)); 1273 case match_left: 1274 return(0 == table.IndexOf(s1, substring)); 1275 case match_right: 1276 string s2 = substring.TrimEnd(trimChars); 1277 return table.IsSuffix(s1, s2); 1278 default: 1279 Debug.Assert(false, "Unexpected LIKE kind"); 1280 return DBNull.Value; 1281 } 1282 } 1283 AnalyzePattern(string pat)1284 internal string AnalyzePattern(string pat) { 1285 1286 int length = pat.Length; 1287 char[] patchars = new char[length+1]; 1288 pat.CopyTo(0, patchars, 0, length); 1289 patchars[length] = (char)0; 1290 string substring = null; 1291 1292 char[] constchars = new char[length+1]; 1293 int newLength = 0; 1294 1295 int stars = 0; 1296 1297 int i = 0; 1298 1299 while (i < length) { 1300 1301 if (patchars[i] == '*' || patchars[i] == '%') { 1302 1303 // replace conseq. * or % with one.. 1304 while ((patchars[i] == '*' || patchars[i] == '%') && i < length) 1305 i++; 1306 1307 // we allowing only *str* pattern 1308 if ((i < length && newLength > 0) || stars >= 2) { 1309 // we have a star inside string constant.. 1310 throw ExprException.InvalidPattern(pat); 1311 } 1312 stars++; 1313 1314 } 1315 else if (patchars[i] == '[') { 1316 i++; 1317 if (i >= length) { 1318 throw ExprException.InvalidPattern(pat); 1319 } 1320 constchars[newLength++] = patchars[i++]; 1321 1322 if (i >= length) { 1323 throw ExprException.InvalidPattern(pat); 1324 } 1325 1326 if (patchars[i] != ']') { 1327 throw ExprException.InvalidPattern(pat); 1328 } 1329 i++; 1330 } 1331 else { 1332 constchars[newLength++] = patchars[i]; 1333 i++; 1334 } 1335 } 1336 1337 substring = new string(constchars, 0, newLength); 1338 1339 if (stars == 0) { 1340 kind = match_exact; 1341 } 1342 else { 1343 if (newLength > 0) { 1344 if (patchars[0] == '*' || patchars[0] == '%') { 1345 1346 if (patchars[length-1] == '*' || patchars[length-1] == '%') { 1347 kind = match_middle; 1348 } 1349 else { 1350 kind = match_right; 1351 } 1352 } 1353 else { 1354 Debug.Assert(patchars[length-1] == '*' || patchars[length-1] == '%', "Invalid LIKE pattern formed.. "); 1355 kind = match_left; 1356 } 1357 } 1358 else { 1359 kind = match_all; 1360 } 1361 } 1362 return substring; 1363 } 1364 } 1365 } 1366