private object EvalBinaryOp(int op, ExpressionNode left, ExpressionNode right, DataRow row, DataRowVersion version, int[] recordNos)
{
object vLeft;
object vRight;
bool isLConst, isRConst;
Type result;
/*
* special case for OR and AND operators: we don't want to evaluate
* both right and left operands, because we can shortcut :
* for OR operator If one of the operands is true the result is true
* for AND operator If one of rhe operands is flase the result is false
* CONSIDER : in the shortcut case do we want to type-check the other operand?
*/
if (op != Operators.Or && op != Operators.And && op != Operators.In && op != Operators.Is && op != Operators.IsNot)
{
vLeft = BinaryNode.Eval(left, row, version, recordNos);
vRight = BinaryNode.Eval(right, row, version, recordNos);
isLConst = (left is ConstNode);
isRConst = (right is ConstNode);
// special case of handling NULLS, currently only OR operator can work with NULLS
if ((vLeft == DBNull.Value) || (vRight == DBNull.Value))
{
return(DBNull.Value);
}
result = ResultType(vLeft.GetType(), vRight.GetType(), isLConst, isRConst, op);
if (result == null)
{
SetTypeMismatchError(op, vLeft.GetType(), vRight.GetType());
}
#if DEBUG
if (CompModSwitches.BinaryNode.TraceVerbose)
{
Debug.WriteLine("Result of the operator: " + result.Name);
}
#endif
}
else
{
vLeft = vRight = DBNull.Value;
result = null;
}
object value = DBNull.Value;
bool typeMismatch = false;
try {
switch (op)
{
case Operators.Plus:
if (result == typeof(Byte))
{
value = Convert.ToByte(Convert.ToByte(vLeft) + Convert.ToByte(vRight));
}
else if (result == typeof(SByte))
{
value = Convert.ToSByte(Convert.ToSByte(vLeft) + Convert.ToSByte(vRight));
}
else if (result == typeof(Int16))
{
value = Convert.ToInt16(Convert.ToInt16(vLeft) + Convert.ToInt16(vRight));
}
else if (result == typeof(UInt16))
{
value = Convert.ToUInt16(Convert.ToUInt16(vLeft) + Convert.ToUInt16(vRight));
}
else if (result == typeof(Int32))
{
Int32 a = Convert.ToInt32(vLeft);
Int32 b = Convert.ToInt32(vRight);
checked { value = a + b; }
}
else if (result == typeof(UInt32))
{
UInt32 a = Convert.ToUInt32(vLeft);
UInt32 b = Convert.ToUInt32(vRight);
checked { value = a + b; }
}
else if (result == typeof(UInt64))
{
UInt64 a = Convert.ToUInt64(vLeft);
UInt64 b = Convert.ToUInt64(vRight);
checked { value = a + b; }
}
else if (result == typeof(Int64))
{
Int64 a = Convert.ToInt64(vLeft);
Int64 b = Convert.ToInt64(vRight);
checked { value = a + b; }
}
else if (result == typeof(Decimal))
{
Decimal a = Convert.ToDecimal(vLeft);
Decimal b = Convert.ToDecimal(vRight);
checked { value = a + b; }
}
else if (result == typeof(Single))
{
Single a = Convert.ToSingle(vLeft);
Single b = Convert.ToSingle(vRight);
checked { value = a + b; }
}
else if (result == typeof(double))
{
Double a = Convert.ToDouble(vLeft);
Double b = Convert.ToDouble(vRight);
checked { value = a + b; }
}
else if (result == typeof(string) || result == typeof(char))
{
value = Convert.ToString(vLeft) + Convert.ToString(vRight);
}
else if (result == typeof(DateTime))
{
// one of the operands should be a DateTime, and an other a TimeSpan
if (vLeft is TimeSpan && vRight is DateTime)
{
value = (DateTime)vRight + (TimeSpan)vLeft;
}
else if (vLeft is DateTime && vRight is TimeSpan)
{
value = (DateTime)vLeft + (TimeSpan)vRight;
}
else
{
typeMismatch = true;
}
}
else if (result == typeof(TimeSpan))
{
value = (TimeSpan)vLeft + (TimeSpan)vRight;
}
else
{
typeMismatch = true;
}
break;
case Operators.Minus:
if (result == typeof(Byte))
{
value = Convert.ToByte(Convert.ToByte(vLeft) - Convert.ToByte(vRight));
}
else if (result == typeof(SByte))
{
value = Convert.ToSByte(Convert.ToSByte(vLeft) - Convert.ToSByte(vRight));
}
else if (result == typeof(Int16))
{
value = Convert.ToInt16(Convert.ToInt16(vLeft) - Convert.ToInt16(vRight));
}
else if (result == typeof(UInt16))
{
value = Convert.ToUInt16(Convert.ToUInt16(vLeft) - Convert.ToUInt16(vRight));
}
else if (result == typeof(Int32))
{
Int32 a = Convert.ToInt32(vLeft);
Int32 b = Convert.ToInt32(vRight);
checked { value = a - b; }
}
else if (result == typeof(UInt32))
{
UInt32 a = Convert.ToUInt32(vLeft);
UInt32 b = Convert.ToUInt32(vRight);
checked { value = a - b; }
}
else if (result == typeof(Int64))
{
Int64 a = Convert.ToInt64(vLeft);
Int64 b = Convert.ToInt64(vRight);
checked { value = a - b; }
}
else if (result == typeof(UInt64))
{
UInt64 a = Convert.ToUInt64(vLeft);
UInt64 b = Convert.ToUInt64(vRight);
checked { value = a - b; }
}
else if (result == typeof(Decimal))
{
Decimal a = Convert.ToDecimal(vLeft);
Decimal b = Convert.ToDecimal(vRight);
checked { value = a - b; }
}
else if (result == typeof(Single))
{
Single a = Convert.ToSingle(vLeft);
Single b = Convert.ToSingle(vRight);
checked { value = a - b; }
}
else if (result == typeof(double))
{
Double a = Convert.ToDouble(vLeft);
Double b = Convert.ToDouble(vRight);
checked { value = a - b; }
}
else if (result == typeof(DateTime))
{
value = (DateTime)vLeft - (TimeSpan)vRight;
}
else if (result == typeof(TimeSpan))
{
if (vLeft is DateTime)
{
value = (DateTime)vLeft - (DateTime)vRight;
}
else
{
value = (TimeSpan)vLeft - (TimeSpan)vRight;
}
}
else
{
typeMismatch = true;
}
break;
case Operators.Multiply:
if (result == typeof(Byte))
{
value = Convert.ToByte(Convert.ToByte(vLeft) * Convert.ToByte(vRight));
}
else if (result == typeof(SByte))
{
value = Convert.ToSByte(Convert.ToSByte(vLeft) * Convert.ToSByte(vRight));
}
else if (result == typeof(Int16))
{
value = Convert.ToInt16(Convert.ToInt16(vLeft) * Convert.ToInt16(vRight));
}
else if (result == typeof(UInt16))
{
value = Convert.ToUInt16(Convert.ToUInt16(vLeft) * Convert.ToUInt16(vRight));
}
else if (result == typeof(Int32))
{
Int32 a = Convert.ToInt32(vLeft);
Int32 b = Convert.ToInt32(vRight);
checked { value = a * b; }
}
else if (result == typeof(UInt32))
{
UInt32 a = Convert.ToUInt32(vLeft);
UInt32 b = Convert.ToUInt32(vRight);
checked { value = a * b; }
}
else if (result == typeof(Int64))
{
Int64 a = Convert.ToInt64(vLeft);
Int64 b = Convert.ToInt64(vRight);
checked { value = a * b; }
}
else if (result == typeof(UInt64))
{
UInt64 a = Convert.ToUInt64(vLeft);
UInt64 b = Convert.ToUInt64(vRight);
checked { value = a * b; }
}
else if (result == typeof(Decimal))
{
Decimal a = Convert.ToDecimal(vLeft);
Decimal b = Convert.ToDecimal(vRight);
checked { value = a * b; }
}
else if (result == typeof(Single))
{
Single a = Convert.ToSingle(vLeft);
Single b = Convert.ToSingle(vRight);
checked { value = a * b; }
}
else if (result == typeof(double))
{
Double a = Convert.ToDouble(vLeft);
Double b = Convert.ToDouble(vRight);
checked { value = a * b; }
}
else
{
typeMismatch = true;
}
break;
case Operators.Divide:
if (result == typeof(Byte))
{
value = Convert.ToByte(Convert.ToByte(vLeft) / Convert.ToByte(vRight));
}
else if (result == typeof(SByte))
{
value = Convert.ToSByte(Convert.ToSByte(vLeft) / Convert.ToSByte(vRight));
}
else if (result == typeof(Int16))
{
value = Convert.ToInt16(Convert.ToInt16(vLeft) / Convert.ToInt16(vRight));
}
else if (result == typeof(UInt16))
{
value = Convert.ToUInt16(Convert.ToUInt16(vLeft) / Convert.ToUInt16(vRight));
}
else if (result == typeof(Int32))
{
Int32 a = Convert.ToInt32(vLeft);
Int32 b = Convert.ToInt32(vRight);
checked { value = a / b; }
}
else if (result == typeof(UInt32))
{
UInt32 a = Convert.ToUInt32(vLeft);
UInt32 b = Convert.ToUInt32(vRight);
checked { value = a / b; }
}
else if (result == typeof(UInt64))
{
UInt64 a = Convert.ToUInt64(vLeft);
UInt64 b = Convert.ToUInt64(vRight);
checked { value = a / b; }
}
else if (result == typeof(Int64))
{
Int64 a = Convert.ToInt64(vLeft);
Int64 b = Convert.ToInt64(vRight);
checked { value = a / b; }
}
else if (result == typeof(Decimal))
{
Decimal a = Convert.ToDecimal(vLeft);
Decimal b = Convert.ToDecimal(vRight);
checked { value = a / b; }
}
else if (result == typeof(Single))
{
Single a = Convert.ToSingle(vLeft);
Single b = Convert.ToSingle(vRight);
checked { value = a / b; }
}
else if (result == typeof(double))
{
Double a = Convert.ToDouble(vLeft);
Double b = Convert.ToDouble(vRight);
checked { value = a / b; }
}
else
{
typeMismatch = true;
}
break;
case Operators.EqualTo:
if ((vLeft == DBNull.Value) || (vRight == DBNull.Value))
{
return(DBNull.Value);
}
return(0 == Compare(vLeft, vRight, result, Operators.EqualTo));
case Operators.GreaterThen:
if ((vLeft == DBNull.Value) || (vRight == DBNull.Value))
{
return(DBNull.Value);
}
return(0 < Compare(vLeft, vRight, result, op));
case Operators.LessThen:
if ((vLeft == DBNull.Value) || (vRight == DBNull.Value))
{
return(DBNull.Value);
}
return(0 > Compare(vLeft, vRight, result, op));
case Operators.GreaterOrEqual:
if ((vLeft == DBNull.Value) || (vRight == DBNull.Value))
{
return(DBNull.Value);
}
return(0 <= Compare(vLeft, vRight, result, op));
case Operators.LessOrEqual:
if ((vLeft == DBNull.Value) || (vRight == DBNull.Value))
{
return(DBNull.Value);
}
return(0 >= Compare(vLeft, vRight, result, op));
case Operators.NotEqual:
if ((vLeft == DBNull.Value) || (vRight == DBNull.Value))
{
return(DBNull.Value);
}
return(0 != Compare(vLeft, vRight, result, op));
case Operators.Is:
vLeft = BinaryNode.Eval(left, row, version, recordNos);
if (vLeft == DBNull.Value)
{
return(true);
}
return(false);
case Operators.IsNot:
vLeft = BinaryNode.Eval(left, row, version, recordNos);
if (vLeft == DBNull.Value)
{
return(false);
}
return(true);
case Operators.And:
/*
* special case evaluating of the AND operator: we don't want to evaluate
* both right and left operands, because we can shortcut :
* If one of the operands is flase the result is false
* CONSIDER : in the shortcut case do we want to type-check the other operand?
*/
vLeft = BinaryNode.Eval(left, row, version, recordNos);
if (vLeft == DBNull.Value)
{
return(DBNull.Value);
}
if (!(vLeft is bool))
{
vRight = BinaryNode.Eval(right, row, version, recordNos);
typeMismatch = true;
break;
}
if ((bool)vLeft == false)
{
value = false;
break;
}
vRight = BinaryNode.Eval(right, row, version, recordNos);
if (vRight == DBNull.Value)
{
return(DBNull.Value);
}
if (!(vRight is bool))
{
typeMismatch = true;
break;
}
value = (bool)vRight;
break;
case Operators.Or:
/*
* special case evaluating the OR operator: we don't want to evaluate
* both right and left operands, because we can shortcut :
* If one of the operands is true the result is true
* CONSIDER : in the shortcut case do we want to type-check the other operand?
*/
vLeft = BinaryNode.Eval(left, row, version, recordNos);
if (vLeft != DBNull.Value)
{
if (!(vLeft is bool))
{
vRight = BinaryNode.Eval(right, row, version, recordNos);
typeMismatch = true;
break;
}
if ((bool)vLeft == true)
{
value = true;
break;
}
}
vRight = BinaryNode.Eval(right, row, version, recordNos);
if (vRight == DBNull.Value)
{
return(vLeft);
}
if (vLeft == DBNull.Value)
{
return(vRight);
}
if (!(vRight is bool))
{
typeMismatch = true;
break;
}
value = (bool)vRight;
break;
case Operators.Modulo:
if (ExpressionNode.IsInteger(result))
{
if (result == typeof(UInt64))
{
value = Convert.ToUInt64(vLeft) % Convert.ToUInt64(vRight);
}
else
{
value = Convert.ToInt64(vLeft) % Convert.ToInt64(vRight);
value = Convert.ChangeType(value, result);
}
}
else
{
typeMismatch = true;
}
break;
case Operators.In:
/*
* special case evaluating of the IN operator: the right have to be IN function node
*/
#if DEBUG
if (CompModSwitches.BinaryNode.TraceVerbose)
{
Debug.WriteLine("Evaluating IN operator..");
}
#endif
if (!(right is FunctionNode))
{
// this is more like an Assert: should never happens, so we do not care about "nice" Exseptions
throw ExprException.InWithoutParentheses();
}
vLeft = BinaryNode.Eval(left, row, version, recordNos);
if (vLeft == DBNull.Value)
{
return(DBNull.Value);
}
/* validate IN parameters : must all be constant expressions */
value = false;
FunctionNode into = (FunctionNode)right;
for (int i = 0; i < into.argumentCount; i++)
{
vRight = into.arguments[i].Eval();
#if DEBUG
if (CompModSwitches.BinaryNode.TraceVerbose)
{
Debug.WriteLine("Evaluate IN parameter " + into.arguments[i].ToString() + " = " + vRight.ToString());
}
#endif
if (vRight == DBNull.Value)
{
continue;
}
Debug.Assert((vLeft != DBNull.Value) && (vRight != DBNull.Value), "Imposible..");
result = vLeft.GetType();
if (0 == Compare(vLeft, vRight, result, Operators.EqualTo))
{
value = true;
break;
}
}
break;
default:
#if DEBUG
if (CompModSwitches.BinaryNode.TraceVerbose)
{
Debug.WriteLine("NYI : " + Operators.ToString(op));
}
#endif
throw ExprException.UnsupportedOperator(op);
}
}
catch (OverflowException) {
throw ExprException.Overflow(result);
}
if (typeMismatch)
{
SetTypeMismatchError(op, vLeft.GetType(), vRight.GetType());
}
return(value);
}