private object EvalFunction(FunctionId id, object[] argumentValues, DataRow row, DataRowVersion version) { #if DEBUG if (CompModSwitches.FunctionNode.TraceVerbose) { Debug.WriteLine("calculate " + this.ToString()); } #endif switch (id) { case FunctionId.Abs: Debug.Assert(argumentCount == 1, "Invalid argument argumentCount for " + funcs[info].name + " : " + argumentCount.ToString()); if (ExpressionNode.IsInteger(argumentValues[0].GetType())) { return(Math.Abs((Int64)argumentValues[0])); } if (ExpressionNode.IsNumeric(argumentValues[0].GetType())) { return(Math.Abs((double)argumentValues[0])); } throw ExprException.ArgumentTypeInteger(funcs[info].name, 1); case FunctionId.cBool: Debug.Assert(argumentCount == 1, "Invalid argument argumentCount for " + funcs[info].name + " : " + argumentCount.ToString()); if (argumentValues[0] is bool) { return((bool)argumentValues[0]); } if (argumentValues[0] is int) { return((int)argumentValues[0] != 0); } if (argumentValues[0] is double) { return((double)argumentValues[0] != 0.0); } if (argumentValues[0] is string) { return(Boolean.Parse((string)argumentValues[0])); } throw ExprException.DatatypeConvertion(argumentValues[0].GetType(), typeof(bool)); case FunctionId.cInt: Debug.Assert(argumentCount == 1, "Invalid argument argumentCount for " + funcs[info].name + " : " + argumentCount.ToString()); return(Convert.ToInt32(argumentValues[0])); case FunctionId.cDate: Debug.Assert(argumentCount == 1, "Invalid argument argumentCount for " + funcs[info].name + " : " + argumentCount.ToString()); #if DEBUG if (CompModSwitches.FunctionNode.TraceVerbose) { Debug.WriteLine("Convert " + Convert.ToString(argumentValues[0]) + " of " + argumentValues[0].GetType().Name + " to datetime"); } #endif return(Convert.ToDateTime(argumentValues[0])); case FunctionId.cDbl: Debug.Assert(argumentCount == 1, "Invalid argument argumentCount for " + funcs[info].name + " : " + argumentCount.ToString()); return(Convert.ToDouble(argumentValues[0])); case FunctionId.cStr: Debug.Assert(argumentCount == 1, "Invalid argument argumentCount for " + funcs[info].name + " : " + argumentCount.ToString()); return(Convert.ToString(argumentValues[0])); case FunctionId.Charindex: Debug.Assert(argumentCount == 2, "Invalid argument argumentCount for " + funcs[info].name + " : " + argumentCount.ToString()); Debug.Assert(argumentValues[0] is string, "Invalid argument type for " + funcs[info].name); Debug.Assert(argumentValues[1] is string, "Invalid argument type for " + funcs[info].name); if ((argumentValues[0] == DBNull.Value) || (argumentValues[1] == DBNull.Value)) { return(DBNull.Value); } return(((string)argumentValues[1]).IndexOf((string)argumentValues[0])); case FunctionId.Iif: Debug.Assert(argumentCount == 3, "Invalid argument argumentCount: " + argumentCount.ToString()); object first = this.arguments[0].Eval(row, version); if (DataExpression.ToBoolean(first) != false) { return(this.arguments[1].Eval(row, version)); } else { return(this.arguments[2].Eval(row, version)); } case FunctionId.In: // we never evaluate IN directly: IN as a binary operator, so evaluation of this should be in // BinaryNode class throw ExprException.NYI(funcs[info].name); case FunctionId.IsNull: Debug.Assert(argumentCount == 2, "Invalid argument argumentCount: "); if ((argumentValues[0]) == DBNull.Value) { return(argumentValues[1]); } else { return(argumentValues[0]); } case FunctionId.Len: Debug.Assert(argumentCount == 1, "Invalid argument argumentCount for " + funcs[info].name + " : " + argumentCount.ToString()); Debug.Assert(argumentValues[0] is string, "Invalid argument type for " + funcs[info].name); return(((string)argumentValues[0]).Length); case FunctionId.Substring: Debug.Assert(argumentCount == 3, "Invalid argument argumentCount: " + argumentCount.ToString()); Debug.Assert(argumentValues[0] is string, "Invalid first argument " + argumentValues[0].GetType().FullName + " in " + funcs[info].name); Debug.Assert(argumentValues[1] is int, "Invalid second argument " + argumentValues[1].GetType().FullName + " in " + funcs[info].name); Debug.Assert(argumentValues[2] is int, "Invalid third argument " + argumentValues[2].GetType().FullName + " in " + funcs[info].name); // work around the differences in COM+ and VBA implementation of the Substring function // 1. The <index> Argument is 0-based in COM+, and 1-based in VBA // 2. If the <Length> argument is longer then the string length COM+ throws an ArgumentException // but our users still want to get a result. int start = (int)argumentValues[1] - 1; int length = (int)argumentValues[2]; if (start < 0) { throw ExprException.FunctionArgumentOutOfRange("index", "Substring"); } if (length < 0) { throw ExprException.FunctionArgumentOutOfRange("length", "Substring"); } if (length == 0) { return(""); } int src_length = ((string)argumentValues[0]).Length; if (start > src_length) { return(DBNull.Value); } if (start + length > src_length) { length = src_length - start; } return(((string)argumentValues[0]).Substring(start, length)); case FunctionId.Trim: { Debug.Assert(argumentCount == 1, "Invalid argument argumentCount for " + funcs[info].name + " : " + argumentCount.ToString()); Debug.Assert(argumentValues[0] is string, "Invalid argument type for " + funcs[info].name); if (argumentValues[0] == DBNull.Value) { return(DBNull.Value); } return(((string)argumentValues[0]).Trim()); } case FunctionId.Convert: if (argumentCount != 2) { throw ExprException.FunctionArgumentCount(this.name); } if (argumentValues[0] == DBNull.Value) { return(DBNull.Value); } Type type = (Type)argumentValues[1]; Type _oType = argumentValues[0].GetType(); if (type != typeof(object)) { if ((type == typeof(Guid)) && (_oType == typeof(String))) { return(new Guid((string)argumentValues[0])); } if (ExpressionNode.IsFloat(_oType) && ExpressionNode.IsInteger(type)) { if (_oType == typeof(Single)) { return(Convert.ChangeType((Single)Convert.ChangeType(argumentValues[0], typeof(Single)), type)); } else if (_oType == typeof(double)) { return(Convert.ChangeType((double)Convert.ChangeType(argumentValues[0], typeof(double)), type)); } else { return(Convert.ChangeType((decimal)Convert.ChangeType(argumentValues[0], typeof(decimal)), type)); } } return(Convert.ChangeType(argumentValues[0], type)); } return(argumentValues[0]); default: throw ExprException.UndefinedFunction(funcs[info].name); } }