1 //------------------------------------------------------------------------------
2 // <copyright file="BinaryNode.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
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 //------------------------------------------------------------------------------
10 namespace System.Data {
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;
19 internal class BinaryNode : ExpressionNode {
22 internal ExpressionNode left;
23 internal ExpressionNode right;
25 internal BinaryNode(DataTable table, int op, ExpressionNode left, ExpressionNode right) : base(table) {
31 internal override void Bind(DataTable table, List<DataColumn> list) {
33 left.Bind(table, list);
34 right.Bind(table, list);
37 internal override object Eval() {
38 return Eval(null, DataRowVersion.Default);
41 internal override object Eval(DataRow row, DataRowVersion version) {
42 return EvalBinaryOp(op, left, right, row, version, null);
45 internal override object Eval(int[] recordNos) {
46 return EvalBinaryOp(op, left, right, null, DataRowVersion.Default, recordNos);
49 internal override bool IsConstant() {
51 return(left.IsConstant() && right.IsConstant());
54 internal override bool IsTableConstant() {
55 return(left.IsTableConstant() && right.IsTableConstant());
57 internal override bool HasLocalAggregate() {
58 return(left.HasLocalAggregate() || right.HasLocalAggregate());
61 internal override bool HasRemoteAggregate() {
62 return(left.HasRemoteAggregate() || right.HasRemoteAggregate());
65 internal override bool DependsOn(DataColumn column) {
66 if (left.DependsOn(column))
68 return right.DependsOn(column);
71 internal override ExpressionNode Optimize() {
72 left = left.Optimize();
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();
84 if (right is ZeroOpNode) {
85 if (((ZeroOpNode)right).op != Operators.Null) {
86 throw ExprException.InvalidIsSyntax();
90 throw ExprException.InvalidIsSyntax();
94 right = right.Optimize();
98 if (this.IsConstant()) {
100 object val = this.Eval();
102 if (val == DBNull.Value) {
103 return new ZeroOpNode(Operators.Null);
108 return new ZeroOpNode(Operators.True);
110 return new ZeroOpNode(Operators.False);
112 return new ConstNode(table, ValueType.Object, val, false);
118 internal void SetTypeMismatchError(int op, Type left, Type right) {
119 throw ExprException.TypeMismatchInBinop(op, left, right);
122 private static object Eval(ExpressionNode expr, DataRow row, DataRowVersion version, int[] recordNos) {
123 if (recordNos == null) {
124 return expr.Eval(row, version);
127 return expr.Eval(recordNos);
131 internal int BinaryCompare(object vLeft, object vRight, StorageType resultType, int op) {
132 return BinaryCompare(vLeft, vRight, resultType, op, null);
135 internal int BinaryCompare(object vLeft, object vRight, StorageType resultType, int op, CompareInfo comparer) {
138 if (!DataStorage.IsSqlType(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);
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) {
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));
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));
218 catch (System.ArgumentException e) {
219 ExceptionBuilder.TraceExceptionWithoutRethrow(e);
221 catch (System.FormatException e) {
222 ExceptionBuilder.TraceExceptionWithoutRethrow(e);
224 catch (System.InvalidCastException e) {
225 ExceptionBuilder.TraceExceptionWithoutRethrow(e);
227 catch (System.OverflowException e) {
228 ExceptionBuilder.TraceExceptionWithoutRethrow(e);
230 catch (System.Data.EvaluateException e) {
231 ExceptionBuilder.TraceExceptionWithoutRethrow(e);
233 SetTypeMismatchError(op, vLeft.GetType(), vRight.GetType());
237 private object EvalBinaryOp(int op, ExpressionNode left, ExpressionNode right, DataRow row, DataRowVersion version, int[] recordNos) {
240 StorageType resultType;
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
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();
256 StorageType leftStorage = DataStorage.GetStorageType(typeofLeft);
257 StorageType rightStorage = DataStorage.GetStorageType(typeofRight);
259 bool leftIsSqlType = DataStorage.IsSqlType(leftStorage);
260 bool rightIsSqlType = DataStorage.IsSqlType(rightStorage);
262 // special case of handling NULLS, currently only OR operator can work with NULLS
263 if (leftIsSqlType && DataStorage.IsObjectSqlNull(vLeft)) {
266 else if (rightIsSqlType && DataStorage.IsObjectSqlNull(vRight)) {
269 else if ((vLeft == DBNull.Value)||(vRight == DBNull.Value)) {
273 if (leftIsSqlType || rightIsSqlType) {
274 resultType = ResultSqlType(leftStorage, rightStorage, (left is ConstNode), (right is ConstNode), op);
277 resultType = ResultType(leftStorage, rightStorage, (left is ConstNode), (right is ConstNode), op);
280 if (StorageType.Empty == resultType) {
281 SetTypeMismatchError(op, typeofLeft, typeofRight);
286 vLeft = vRight = DBNull.Value;
287 resultType = StorageType.Empty; // shouldnt we make it boolean?
290 object value = DBNull.Value;
291 bool typeMismatch = false;
297 case StorageType.Byte:{
298 value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) + Convert.ToByte(vRight, FormatProvider)), FormatProvider);
300 case StorageType.SByte:{
301 value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) + Convert.ToSByte(vRight, FormatProvider)), FormatProvider);
303 case StorageType.Int16:{
304 value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) + Convert.ToInt16(vRight, FormatProvider)), FormatProvider);
306 case StorageType.UInt16:{
307 value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) + Convert.ToUInt16(vRight, FormatProvider)), FormatProvider);
309 case StorageType.Int32: {
310 checked {value = Convert.ToInt32(vLeft, FormatProvider) + Convert.ToInt32(vRight, FormatProvider);}
312 case StorageType.UInt32: {
313 checked {value = Convert.ToUInt32(vLeft, FormatProvider) + Convert.ToUInt32(vRight, FormatProvider);}
315 case StorageType.UInt64: {
316 checked {value = Convert.ToUInt64(vLeft, FormatProvider) + Convert.ToUInt64(vRight, FormatProvider);}
318 case StorageType.Int64:{
319 checked {value = Convert.ToInt64(vLeft, FormatProvider) + Convert.ToInt64(vRight, FormatProvider);}
321 case StorageType.Decimal:{
322 checked {value = Convert.ToDecimal(vLeft, FormatProvider) + Convert.ToDecimal(vRight, FormatProvider);}
324 case StorageType.Single:{
325 checked {value = Convert.ToSingle(vLeft, FormatProvider) + Convert.ToSingle(vRight, FormatProvider);}
327 case StorageType.Double:{
328 checked {value = Convert.ToDouble(vLeft, FormatProvider) + Convert.ToDouble(vRight, FormatProvider);}
330 case StorageType.String:
331 case StorageType.Char:{
332 value = Convert.ToString(vLeft, FormatProvider) + Convert.ToString(vRight, FormatProvider);
334 case StorageType.DateTime:{
335 // one of the operands should be a DateTime, and an other a TimeSpan
337 if (vLeft is TimeSpan && vRight is DateTime) {
338 value = (DateTime)vRight + (TimeSpan)vLeft;
340 else if (vLeft is DateTime && vRight is TimeSpan) {
341 value = (DateTime)vLeft + (TimeSpan)vRight;
347 case StorageType.TimeSpan:{
348 value = (TimeSpan)vLeft + (TimeSpan)vRight;
350 case StorageType.SqlInt16:{
351 value = (SqlConvert.ConvertToSqlInt16(vLeft) + SqlConvert.ConvertToSqlInt16(vRight));
353 case StorageType.SqlInt32:{
354 value = ( SqlConvert.ConvertToSqlInt32(vLeft) + SqlConvert.ConvertToSqlInt32(vRight));
356 case StorageType.SqlInt64:{
357 value = (SqlConvert.ConvertToSqlInt64(vLeft) + SqlConvert.ConvertToSqlInt64(vRight));
359 case StorageType.SqlDouble:{
360 value = (SqlConvert.ConvertToSqlDouble(vLeft) + SqlConvert.ConvertToSqlDouble(vRight));
362 case StorageType.SqlSingle:{
363 value = (SqlConvert.ConvertToSqlSingle(vLeft)+ SqlConvert.ConvertToSqlSingle(vRight));
365 case StorageType.SqlDecimal:{
366 value = (SqlConvert.ConvertToSqlDecimal(vLeft) + SqlConvert.ConvertToSqlDecimal(vRight));
368 case StorageType.SqlMoney:{
369 value = (SqlConvert.ConvertToSqlMoney(vLeft) + SqlConvert.ConvertToSqlMoney(vRight));
371 case StorageType.SqlByte:{
372 value = (SqlConvert.ConvertToSqlByte(vLeft) + SqlConvert.ConvertToSqlByte(vRight));
374 case StorageType.SqlString:{
375 value = (SqlConvert.ConvertToSqlString(vLeft) + SqlConvert.ConvertToSqlString(vRight));
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);
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);
394 break; // Operators.Plus
396 case Operators.Minus:
398 case StorageType.Byte: {
399 value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) - Convert.ToByte(vRight, FormatProvider)), FormatProvider);
401 case StorageType.SqlByte: {
402 value = (SqlConvert.ConvertToSqlByte(vLeft) - SqlConvert.ConvertToSqlByte(vRight));
404 case StorageType.SByte:{
405 value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) - Convert.ToSByte(vRight, FormatProvider)), FormatProvider);
407 case StorageType.Int16:{
408 value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) - Convert.ToInt16(vRight, FormatProvider)), FormatProvider);
410 case StorageType.SqlInt16:{
411 value = (SqlConvert.ConvertToSqlInt16(vLeft) - SqlConvert.ConvertToSqlInt16(vRight));
413 case StorageType.UInt16:{
414 value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) - Convert.ToUInt16(vRight, FormatProvider)), FormatProvider);
416 case StorageType.Int32:{
417 checked {value = Convert.ToInt32(vLeft, FormatProvider) - Convert.ToInt32(vRight, FormatProvider);}
419 case StorageType.SqlInt32:{
420 value = (SqlConvert.ConvertToSqlInt32(vLeft) - SqlConvert.ConvertToSqlInt32(vRight));
422 case StorageType.UInt32:{
423 checked {value = Convert.ToUInt32(vLeft, FormatProvider) - Convert.ToUInt32(vRight, FormatProvider);}
425 case StorageType.Int64:{
426 checked {value = Convert.ToInt64(vLeft, FormatProvider) - Convert.ToInt64(vRight, FormatProvider);}
428 case StorageType.SqlInt64:{
429 value = (SqlConvert.ConvertToSqlInt64(vLeft) - SqlConvert.ConvertToSqlInt64(vRight));
431 case StorageType.UInt64:{
432 checked {value = Convert.ToUInt64(vLeft, FormatProvider) - Convert.ToUInt64(vRight, FormatProvider);}
434 case StorageType.Decimal:{
435 checked {value = Convert.ToDecimal(vLeft, FormatProvider) - Convert.ToDecimal(vRight, FormatProvider);}
437 case StorageType.SqlDecimal:{
438 value = (SqlConvert.ConvertToSqlDecimal(vLeft) - SqlConvert.ConvertToSqlDecimal(vRight));
440 case StorageType.Single:{
441 checked {value = Convert.ToSingle(vLeft, FormatProvider) - Convert.ToSingle(vRight, FormatProvider);}
443 case StorageType.SqlSingle:{
444 value = (SqlConvert.ConvertToSqlSingle(vLeft) - SqlConvert.ConvertToSqlSingle(vRight));
446 case StorageType.Double:{
447 checked {value = Convert.ToDouble(vLeft, FormatProvider) - Convert.ToDouble(vRight, FormatProvider);}
449 case StorageType.SqlDouble:{
450 value = (SqlConvert.ConvertToSqlDouble(vLeft) - SqlConvert.ConvertToSqlDouble(vRight));
452 case StorageType.SqlMoney:{
453 value = (SqlConvert.ConvertToSqlMoney(vLeft) - SqlConvert.ConvertToSqlMoney(vRight));
455 case StorageType.DateTime:{
456 value = (DateTime)vLeft - (TimeSpan)vRight;
458 case StorageType.TimeSpan:{
459 if (vLeft is DateTime) {
460 value = (DateTime)vLeft - (DateTime)vRight;
463 value = (TimeSpan)vLeft - (TimeSpan)vRight;
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);
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);
482 break; // Operators.Minus
484 case Operators.Multiply:
486 case StorageType.Byte:{
487 value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) * Convert.ToByte(vRight, FormatProvider)), FormatProvider);
489 case StorageType.SqlByte:{
490 value = (SqlConvert.ConvertToSqlByte(vLeft) * SqlConvert.ConvertToSqlByte(vRight));
492 case StorageType.SByte:{
493 value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) * Convert.ToSByte(vRight, FormatProvider)), FormatProvider);
495 case StorageType.Int16:{
496 value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) * Convert.ToInt16(vRight, FormatProvider)), FormatProvider);
498 case StorageType.SqlInt16:{
499 value = (SqlConvert.ConvertToSqlInt16(vLeft) * SqlConvert.ConvertToSqlInt16(vRight));
501 case StorageType.UInt16:{
502 value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) * Convert.ToUInt16(vRight, FormatProvider)), FormatProvider);
504 case StorageType.Int32:{
505 checked {value = Convert.ToInt32(vLeft, FormatProvider) * Convert.ToInt32(vRight, FormatProvider);}
507 case StorageType.SqlInt32:{
508 value = (SqlConvert.ConvertToSqlInt32(vLeft) * SqlConvert.ConvertToSqlInt32(vRight));
510 case StorageType.UInt32:{
511 checked {value = Convert.ToUInt32(vLeft, FormatProvider) * Convert.ToUInt32(vRight, FormatProvider);}
513 case StorageType.Int64:{
515 checked {value = Convert.ToInt64(vLeft, FormatProvider) * Convert.ToInt64(vRight, FormatProvider);}
517 case StorageType.SqlInt64:{
518 value = (SqlConvert.ConvertToSqlInt64(vLeft) * SqlConvert.ConvertToSqlInt64(vRight));
520 case StorageType.UInt64:{
521 checked {value = Convert.ToUInt64(vLeft, FormatProvider) * Convert.ToUInt64(vRight, FormatProvider);}
523 case StorageType.Decimal:{
524 checked {value = Convert.ToDecimal(vLeft, FormatProvider) * Convert.ToDecimal(vRight, FormatProvider);}
526 case StorageType.SqlDecimal:{
527 value = (SqlConvert.ConvertToSqlDecimal(vLeft) * SqlConvert.ConvertToSqlDecimal(vRight));
529 case StorageType.Single:{
530 checked {value = Convert.ToSingle(vLeft, FormatProvider) * Convert.ToSingle(vRight, FormatProvider);}
532 case StorageType.SqlSingle:{
533 value = ( SqlConvert.ConvertToSqlSingle(vLeft) * SqlConvert.ConvertToSqlSingle(vRight));
535 case StorageType.SqlMoney:{
536 value = (SqlConvert.ConvertToSqlMoney(vLeft) * SqlConvert.ConvertToSqlMoney(vRight));
538 case StorageType.Double:{
539 checked {value = Convert.ToDouble(vLeft, FormatProvider) * Convert.ToDouble(vRight, FormatProvider);}
541 case StorageType.SqlDouble:{
542 value = (SqlConvert.ConvertToSqlDouble(vLeft) * SqlConvert.ConvertToSqlDouble(vRight));
548 break; // Operators.Multiply
550 case Operators.Divide:
552 case StorageType.Byte:{
553 value = Convert.ToByte((Convert.ToByte(vLeft, FormatProvider) / Convert.ToByte(vRight, FormatProvider)), FormatProvider);
555 case StorageType.SqlByte:{
556 value = (SqlConvert.ConvertToSqlByte(vLeft) / SqlConvert.ConvertToSqlByte(vRight));
558 case StorageType.SByte:{
559 value = Convert.ToSByte((Convert.ToSByte(vLeft, FormatProvider) / Convert.ToSByte(vRight, FormatProvider)), FormatProvider);
561 case StorageType.Int16:{
562 value = Convert.ToInt16((Convert.ToInt16(vLeft, FormatProvider) / Convert.ToInt16(vRight, FormatProvider)), FormatProvider);
564 case StorageType.SqlInt16:{
565 value = (SqlConvert.ConvertToSqlInt16(vLeft) / SqlConvert.ConvertToSqlInt16(vRight));
567 case StorageType.UInt16:{
568 value = Convert.ToUInt16((Convert.ToUInt16(vLeft, FormatProvider) / Convert.ToUInt16(vRight, FormatProvider)), FormatProvider);
570 case StorageType.Int32:{
571 checked {value = Convert.ToInt32(vLeft, FormatProvider) / Convert.ToInt32(vRight, FormatProvider);}
573 case StorageType.SqlInt32:{
574 value = (SqlConvert.ConvertToSqlInt32(vLeft) / SqlConvert.ConvertToSqlInt32(vRight));
576 case StorageType.UInt32:{
577 checked {value = Convert.ToUInt32(vLeft, FormatProvider) / Convert.ToUInt32(vRight, FormatProvider);}
579 case StorageType.UInt64:{
580 checked {value = Convert.ToUInt64(vLeft, FormatProvider) / Convert.ToUInt64(vRight, FormatProvider);}
582 case StorageType.Int64:{
583 checked {value = Convert.ToInt64(vLeft, FormatProvider) / Convert.ToInt64(vRight, FormatProvider);}
585 case StorageType.SqlInt64:{
586 value = (SqlConvert.ConvertToSqlInt64(vLeft) / SqlConvert.ConvertToSqlInt64(vRight));
588 case StorageType.Decimal:{
589 checked {value = Convert.ToDecimal(vLeft, FormatProvider) / Convert.ToDecimal(vRight, FormatProvider);}
591 case StorageType.SqlDecimal:{
592 value = (SqlConvert.ConvertToSqlDecimal(vLeft) / SqlConvert.ConvertToSqlDecimal(vRight));
594 case StorageType.Single:{
595 checked {value = Convert.ToSingle(vLeft, FormatProvider) / Convert.ToSingle(vRight, FormatProvider);}
597 case StorageType.SqlSingle:{
598 value = ( SqlConvert.ConvertToSqlSingle(vLeft) / SqlConvert.ConvertToSqlSingle(vRight));
600 case StorageType.SqlMoney:{
601 value = (SqlConvert.ConvertToSqlMoney(vLeft) / SqlConvert.ConvertToSqlMoney(vRight));
603 case StorageType.Double:{
604 Double b = Convert.ToDouble(vRight, FormatProvider);
605 checked {value = Convert.ToDouble(vLeft, FormatProvider) / b;}
607 case StorageType.SqlDouble:{
608 value = (SqlConvert.ConvertToSqlDouble(vLeft) / SqlConvert.ConvertToSqlDouble(vRight));
614 break; // Operators.Divide
616 case Operators.EqualTo:
617 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) ||
618 (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))
620 return(0 == BinaryCompare (vLeft, vRight, resultType, Operators.EqualTo));
622 case Operators.GreaterThen:
623 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) ||
624 (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))
626 return(0 < BinaryCompare (vLeft, vRight, resultType, op));
628 case Operators.LessThen:
629 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) ||
630 (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))
632 return(0 > BinaryCompare (vLeft, vRight, resultType, op));
634 case Operators.GreaterOrEqual:
635 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)) ||
636 (vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))
638 return(0 <= BinaryCompare (vLeft, vRight, resultType, op));
640 case Operators.LessOrEqual:
641 if (((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))) ||
642 ((vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight))))
644 return(0 >= BinaryCompare (vLeft, vRight, resultType, op));
646 case Operators.NotEqual:
647 if (((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))) ||
648 ((vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight))))
650 return(0 != BinaryCompare (vLeft, vRight, resultType, op));
653 vLeft = BinaryNode.Eval(left, row, version, recordNos);
654 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))){
659 case Operators.IsNot:
660 vLeft = BinaryNode.Eval(left, row, version, recordNos);
661 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft))){
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
673 vLeft = BinaryNode.Eval(left, row, version, recordNos);
674 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)))
677 if ((!(vLeft is bool)) && (!(vLeft is SqlBoolean))){
678 vRight = BinaryNode.Eval(right, row, version, recordNos);
684 if ((bool)vLeft == false){
690 if (((SqlBoolean) vLeft).IsFalse){
695 vRight = BinaryNode.Eval(right, row, version, recordNos);
696 if ((vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight )))
699 if ((!(vRight is bool)) && (!(vRight is SqlBoolean))){
705 value = (bool)vRight;
709 value = ((SqlBoolean) vRight).IsTrue;
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
720 vLeft = BinaryNode.Eval(left, row, version, recordNos);
722 if ((vLeft != DBNull.Value) && (!DataStorage.IsObjectSqlNull(vLeft))) {
723 if ((!(vLeft is bool)) && (!(vLeft is SqlBoolean))) {
724 vRight = BinaryNode.Eval(right, row, version, recordNos);
729 if ((bool)vLeft == true) {
735 vRight = BinaryNode.Eval(right, row, version, recordNos);
736 if ((vRight == DBNull.Value)||(DataStorage.IsObjectSqlNull(vRight)))
739 if ((vLeft == DBNull.Value)||(DataStorage.IsObjectSqlNull(vLeft)))
742 if ((!(vRight is bool)) && (!(vRight is SqlBoolean))) {
747 value = (vRight is bool) ? ((bool)vRight) : (((SqlBoolean)vRight).IsTrue);
750 /* for M3, use original code , in below, and make sure to have two different code path; increases perf
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);
760 if ((bool)vLeft == true) {
766 vRight = BinaryNode.Eval(right, row, version, recordNos);
767 if (vRight == DBNull.Value)
770 if (vLeft == DBNull.Value)
773 if (!(vRight is bool)) {
778 value = (bool)vRight;
782 case Operators.Modulo:
783 if (ExpressionNode.IsIntegerSql(resultType)) {
784 if (resultType == StorageType.UInt64) {
785 value = Convert.ToUInt64(vLeft, FormatProvider) % Convert.ToUInt64(vRight, FormatProvider);
787 else if (DataStorage.IsSqlType(resultType)) {
788 SqlInt64 res = (SqlConvert.ConvertToSqlInt64(vLeft) % SqlConvert.ConvertToSqlInt64(vRight));
790 if (resultType == StorageType.SqlInt32){
791 value = (SqlInt32) res.ToSqlInt32();
793 else if (resultType == StorageType.SqlInt16){
794 value = (SqlInt16) res.ToSqlInt16();
796 else if (resultType == StorageType.SqlByte){
797 value = (SqlByte) res.ToSqlByte();
800 value = (SqlInt64) res;
804 value = Convert.ToInt64(vLeft, FormatProvider) % Convert.ToInt64(vRight, FormatProvider);
805 value = Convert.ChangeType(value, DataStorage.GetTypeStorage(resultType), FormatProvider);
815 special case evaluating of the IN operator: the right have to be IN function node
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();
824 vLeft = BinaryNode.Eval(left, row, version, recordNos);
826 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)))
829 /* validate IN parameters : must all be constant expressions */
833 FunctionNode into = (FunctionNode)right;
835 for (int i = 0; i < into.argumentCount; i++) {
836 vRight = into.arguments[i].Eval();
839 if ((vRight == DBNull.Value)||(right.IsSqlColumn && DataStorage.IsObjectSqlNull(vRight)))
841 Debug.Assert((!DataStorage.IsObjectNull(vLeft))&& (!DataStorage.IsObjectNull(vRight)), "Imposible..");
843 resultType = DataStorage.GetStorageType(vLeft.GetType());
845 if (0 == BinaryCompare(vLeft, vRight, resultType, Operators.EqualTo)) {
853 throw ExprException.UnsupportedOperator(op);
856 catch (OverflowException) {
857 throw ExprException.Overflow(DataStorage.GetTypeStorage(resultType));
860 SetTypeMismatchError(op, vLeft.GetType(), vRight.GetType());
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:
872 private enum DataTypePrecedence {
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;
951 private static StorageType GetPrecedenceType(DataTypePrecedence 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;
966 case DataTypePrecedence.Boolean: return StorageType.Boolean;
967 case DataTypePrecedence.String: return StorageType.String;
968 case DataTypePrecedence.Char: return StorageType.Char;
970 case DataTypePrecedence.DateTimeOffset: return StorageType.DateTimeOffset;
971 case DataTypePrecedence.DateTime: return StorageType.DateTime;
972 case DataTypePrecedence.TimeSpan: return StorageType.TimeSpan;
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;
988 Debug.Assert(false, "Invalid (unmapped) precedence " + code.ToString());
989 goto case DataTypePrecedence.Error;
993 private bool IsMixed(StorageType left, StorageType right) {
994 return ((IsSigned(left) && IsUnsigned(right)) ||
995 (IsUnsigned(left) && IsSigned(right)));
998 private bool IsMixedSql(StorageType left, StorageType right) {
999 return ((IsSignedSql(left) && IsUnsignedSql(right)) ||
1000 (IsUnsignedSql(left) && IsSignedSql(right)));
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))
1006 if ((left == StorageType.String) && (right == StorageType.Guid) && Operators.IsRelational(op))
1008 if ((left == StorageType.Guid) && (right == StorageType.String) && Operators.IsRelational(op))
1011 int leftPrecedence = (int)GetPrecedence(left);
1012 if (leftPrecedence == (int)DataTypePrecedence.Error) {
1013 return StorageType.Empty;
1016 int rightPrecedence = (int)GetPrecedence(right);
1017 if (rightPrecedence == (int)DataTypePrecedence.Error) {
1018 return StorageType.Empty;
1021 if (Operators.IsLogical(op)){
1022 if (left == StorageType.Boolean && right == StorageType.Boolean)
1023 return StorageType.Boolean;
1025 return StorageType.Empty;
1027 if ((left == StorageType.DateTimeOffset) ||(right == StorageType.DateTimeOffset))
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;
1037 if ((op == Operators.Plus) && ((left == StorageType.String) || (right == StorageType.String)))
1038 return StorageType.String;
1040 DataTypePrecedence higherPrec = (DataTypePrecedence)Math.Max(leftPrecedence, rightPrecedence);
1042 StorageType result = GetPrecedenceType(higherPrec);
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;
1053 // if the operation is a division the result should be at least a double
1055 if ((op == Operators.Divide) && IsInteger(result)) {
1056 return StorageType.Double;
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
1065 else if ((!lc) && rc) {
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);
1075 throw ExprException.AmbiguousBinop(op, DataStorage.GetTypeStorage(left), DataStorage.GetTypeStorage(right));
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;
1088 int rightPrecedence = (int)GetPrecedence(right);
1089 if (rightPrecedence == (int)DataTypePrecedence.Error) {
1090 return StorageType.Empty;
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;
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;
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;
1114 if ((leftPrecedence > (int)DataTypePrecedence.SqlDouble && rightPrecedence <(int) DataTypePrecedence.TimeSpan)){
1115 return StorageType.Empty;
1118 if ((leftPrecedence < (int)DataTypePrecedence.TimeSpan && rightPrecedence >(int) DataTypePrecedence.SqlDouble)){
1119 return StorageType.Empty;
1122 if (leftPrecedence > (int) DataTypePrecedence.SqlDouble){
1123 if (op == Operators.Plus || op == Operators.Minus){
1124 if (left == StorageType.TimeSpan)
1126 if (right == StorageType.TimeSpan)
1128 return StorageType.Empty; // for plus or minus operations for time types, one of them MUST be time span
1131 if (!Operators.IsRelational(op))
1132 return StorageType.Empty; // we just have relational operations amoung time types
1135 // time types finished
1136 // continue with numerical types, numbers
1138 DataTypePrecedence higherPrec = (DataTypePrecedence)Math.Max(leftPrecedence, rightPrecedence);
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));
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;
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;
1158 if (result == StorageType.SqlMoney){
1159 if ((left != StorageType.SqlMoney) && (right != StorageType.SqlMoney))
1160 result = StorageType.SqlDecimal;
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
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);
1173 throw ExprException.AmbiguousBinop(op, DataStorage.GetTypeStorage(left), DataStorage.GetTypeStorage(right));
1180 private int SqlResultType(int typeCode){
1198 default : return typeCode;
1203 internal sealed class LikeNode : BinaryNode {
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; // *
1212 string pattern = null;
1214 internal LikeNode(DataTable table, int op, ExpressionNode left, ExpressionNode right)
1215 : base (table, op, left, right) {
1218 internal override object Eval(DataRow row, DataRowVersion version) {
1221 object vLeft = left.Eval(row, version);
1225 if ((vLeft == DBNull.Value)||(left.IsSqlColumn && DataStorage.IsObjectSqlNull(vLeft)))
1226 return DBNull.Value;
1228 if (pattern == null) {
1229 vRight = right.Eval(row, version);
1231 if (!(vRight is string) && !(vRight is SqlString)) {
1232 SetTypeMismatchError(op, vLeft.GetType(), vRight.GetType());
1235 if (vRight == DBNull.Value || DataStorage.IsObjectSqlNull(vRight))
1236 return DBNull.Value;
1237 string rightStr = (string) SqlConvert.ChangeType2(vRight, StorageType.String, typeof(string), FormatProvider);
1240 // need to convert like pattern to a string
1242 // Parce the original pattern, and get the constant part of it..
1243 substring = AnalyzePattern(rightStr);
1245 if (right.IsConstant())
1246 pattern = substring;
1249 substring = pattern;
1252 if (!(vLeft is string) && !(vLeft is SqlString)) {
1253 SetTypeMismatchError(op, vLeft.GetType(), typeof(string));
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};
1259 if (vLeft is SqlString)
1260 tempStr = ((SqlString)vLeft).Value;
1262 tempStr = (string)vLeft;
1264 string s1 = (tempStr).TrimEnd(trimChars);
1270 return(0 == table.Compare(s1, substring));
1272 return(0 <= table.IndexOf(s1, substring));
1274 return(0 == table.IndexOf(s1, substring));
1276 string s2 = substring.TrimEnd(trimChars);
1277 return table.IsSuffix(s1, s2);
1279 Debug.Assert(false, "Unexpected LIKE kind");
1280 return DBNull.Value;
1284 internal string AnalyzePattern(string pat) {
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;
1292 char[] constchars = new char[length+1];
1299 while (i < length) {
1301 if (patchars[i] == '*' || patchars[i] == '%') {
1303 // replace conseq. * or % with one..
1304 while ((patchars[i] == '*' || patchars[i] == '%') && i < length)
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);
1315 else if (patchars[i] == '[') {
1318 throw ExprException.InvalidPattern(pat);
1320 constchars[newLength++] = patchars[i++];
1323 throw ExprException.InvalidPattern(pat);
1326 if (patchars[i] != ']') {
1327 throw ExprException.InvalidPattern(pat);
1332 constchars[newLength++] = patchars[i];
1337 substring = new string(constchars, 0, newLength);
1343 if (newLength > 0) {
1344 if (patchars[0] == '*' || patchars[0] == '%') {
1346 if (patchars[length-1] == '*' || patchars[length-1] == '%') {
1347 kind = match_middle;
1354 Debug.Assert(patchars[length-1] == '*' || patchars[length-1] == '%', "Invalid LIKE pattern formed.. ");