// // System.Data.ExpressionElement // // Author: // Ville Palo // // Copyright (C) Ville Palo, 2003 // // TODO: - Some functionelements and aggregates. // - New parsing style. // - Exceptions // using System; using System.Data; using System.Reflection; using System.Collections; using System.Text; namespace System.Data { #if false /// /// The main element which includes whole expression /// internal class ExpressionMainElement : ExpressionElement { public ExpressionMainElement (string s) { s = ExpressionElement.ValidateExpression (s); ParseExpression (s); } public override bool Test (DataRow Row) { foreach (ExpressionElement El in Elements) { if (!El.Test (Row)) return false; } return true; } } // // O_P_E_R_A_T_O_R_S // /// /// Class for = /// internal class ExpressionEquals : ExpressionElement { public ExpressionEquals (string exp1, string exp2) { this.exp1 = exp1; this.exp2 = exp2; ParseExpression (exp1); ParseExpression (exp2); } public override bool Test (DataRow Row) { ExpressionElement E1 = (ExpressionElement)Elements [0]; ExpressionElement E2 = (ExpressionElement)Elements [1]; return ExpressionElement.Compare (E1, E2, Row) == 0; } } /// /// Class for < /// internal class ExpressionLessThan : ExpressionElement { public ExpressionLessThan (string exp1, string exp2) { this.exp1 = exp1; this.exp2 = exp2; ParseExpression (exp1); ParseExpression (exp2); } public override bool Test (DataRow Row) { ExpressionElement E1 = (ExpressionElement)Elements [0]; ExpressionElement E2 = (ExpressionElement)Elements [1]; return ExpressionElement.Compare (E1, E2, Row) < 0; } } /// /// Class for <= /// internal class ExpressionLessThanOrEqual : ExpressionElement { public ExpressionLessThanOrEqual (string exp1, string exp2) { this.exp1 = exp1; this.exp2 = exp2; ParseExpression (exp1); ParseExpression (exp2); } public override bool Test (DataRow Row) { ExpressionElement E1 = (ExpressionElement)Elements [0]; ExpressionElement E2 = (ExpressionElement)Elements [1]; return ExpressionElement.Compare (E1, E2, Row) <= 0; } } /// /// Class for > /// internal class ExpressionGreaterThan : ExpressionElement { public ExpressionGreaterThan (string exp1, string exp2) { this.exp1 = exp1; this.exp2 = exp2; ParseExpression (exp1); ParseExpression (exp2); } public override bool Test (DataRow Row) { ExpressionElement E1 = (ExpressionElement)Elements [0]; ExpressionElement E2 = (ExpressionElement)Elements [1]; return ExpressionElement.Compare (E1, E2, Row) > 0; } } /// /// Class for >= /// internal class ExpressionGreaterThanOrEqual : ExpressionElement { public ExpressionGreaterThanOrEqual (string exp1, string exp2) { this.exp1 = exp1; this.exp2 = exp2; ParseExpression (exp1); ParseExpression (exp2); } public override bool Test (DataRow Row) { ExpressionElement E1 = (ExpressionElement)Elements [0]; ExpressionElement E2 = (ExpressionElement)Elements [1]; return ExpressionElement.Compare (E1, E2, Row) >= 0; } } /// /// Class for <> /// internal class ExpressionUnequals : ExpressionElement { public ExpressionUnequals (string exp1, string exp2) { this.exp1 = exp1; this.exp2 = exp2; ParseExpression (exp1); ParseExpression (exp2); } public override bool Test (DataRow Row) { ExpressionElement E1 = (ExpressionElement)Elements [0]; ExpressionElement E2 = (ExpressionElement)Elements [1]; return ExpressionElement.Compare (E1, E2, Row) != 0; } } /// /// Class for LIKE-operator /// internal class ExpressionLike : ExpressionElement { public ExpressionLike (string exp1, string exp2) { ParseExpression (exp1); ParseExpression (exp2); } public override bool Test (DataRow Row) { ExpressionElement E1 = (ExpressionElement)Elements [0]; ExpressionElement E2 = (ExpressionElement)Elements [1]; object value1 = E1.Result (Row); object value2 = E2.Result (Row); if (value1.GetType () != typeof (string) || value2.GetType () != typeof (string)) throw new Exception (); // TODO: what exception string operand1 = value1.ToString (); string operand2 = value2.ToString (); // find out is there wildcards like * or %. while (operand2.EndsWith ("*") || operand2.EndsWith ("%")) operand2 = operand2.Remove (operand2.Length - 1, 1); while (operand2.StartsWith ("*") || operand2.StartsWith ("%")) operand2 = operand2.Remove (0, 1); int oldIndex = 0; int indexOf = -1; indexOf = operand2.IndexOf ("*"); while (indexOf != -1) { oldIndex = indexOf + 1; if (operand2 [indexOf + 1] != ']' || operand2 [indexOf - 1] != '[') throw new EvaluateException ("Error in Like operator: ther string pattern " + operand1 + " is invalid"); else { operand2 = operand2.Remove (indexOf + 1, 1); operand2 = operand2.Remove (indexOf -1, 1); oldIndex--; } indexOf = operand2.IndexOf ("*", oldIndex); } oldIndex = 0; indexOf = operand2.IndexOf ("%"); while (indexOf != -1) { oldIndex = indexOf + 1; if (operand2 [indexOf + 1] != ']' || operand2 [indexOf - 1] != '[') throw new EvaluateException ("Error in Like operator: ther string pattern " + operand2 + " is invalid"); else { operand2 = operand2.Remove (indexOf + 1, 1); operand2 = operand2.Remove (indexOf -1, 1); oldIndex--; } indexOf = operand2.IndexOf ("%", oldIndex); } int len2 = operand2.Length; int startIndex = 0; while ((startIndex + len2) <= operand1.Length) { if (String.Compare (operand1.Substring (startIndex, len2), operand2, !Row.Table.CaseSensitive) == 0) return true; startIndex++; } return false; } } /// /// Class for OR /// internal class ExpressionOr : ExpressionElement { public ExpressionOr (string exp1, string exp2) { ParseExpression (exp1); ParseExpression (exp2); } public override bool Test (DataRow Row) { foreach (ExpressionElement El in Elements) { if (El.Test (Row)) return true; } return false; } } /// /// Class for AND /// internal class ExpressionAnd : ExpressionElement { public ExpressionAnd (string exp1, string exp2) { ParseExpression (exp1); ParseExpression (exp2); } public override object Result (DataRow Row) { return Test(Row); } public override bool Test (DataRow Row) { foreach (ExpressionElement El in Elements) { if (!El.Test (Row)) return false; } return true; } } // // A_R_I_T_H_M_E_T_I_C O_P_E_R_A_T_O_R_S // /// /// Class for + /// internal class ExpressionAddition : ExpressionElement { public ExpressionAddition (string exp1, string exp2) { this.exp1 = exp1; this.exp2 = exp2; ParseExpression (exp1); ParseExpression (exp2); } public override Type ResultType (DataRow Row) { Type ResultType = typeof (string); ExpressionElement exp1Temp = ((ExpressionElement)Elements [0]); ExpressionElement exp2Temp = ((ExpressionElement)Elements [1]); if (exp1Temp.ResultType (Row) == typeof (string) || exp2Temp.ResultType (Row) == typeof (string)) ResultType = typeof (string); else if (exp1Temp.ResultType (Row) == typeof (long) || exp2Temp.ResultType (Row) == typeof (long)) ResultType = typeof (long); else if (exp1Temp.ResultType (Row) == typeof (int) || exp2Temp.ResultType (Row) == typeof (int)) ResultType = typeof (int); return ResultType; } public override object Result (DataRow Row) { return CalculateResult (Row); } protected override object Calculate (object value1, object value2, Type TempType) { object Result = null; if (TempType == typeof (string)) Result = (string)value1 + (string)value2; else if (TempType == typeof (long)) Result = (long)value1 + (long)value2; else if (TempType == typeof (int)) Result = (int)value1 + (int)value2; else if (TempType == typeof (short)) Result = (short)value1 + (short)value2; else if (TempType == typeof (ulong)) Result = (ulong)value1 + (ulong)value2; else if (TempType == typeof (uint)) Result = (uint)value1 + (uint)value2; else if (TempType == typeof (ushort)) Result = (ushort)value1 + (ushort)value2; else if (TempType == typeof (byte)) Result = (byte)value1 + (byte)value2; else if (TempType == typeof (sbyte)) Result = (sbyte)value1 + (sbyte)value2; // FIXME: //else if (TempType == typeof (bool)) // Result = (bool)value1 + (bool)value2; else if (TempType == typeof (float)) Result = (float)value1 + (float)value2; else if (TempType == typeof (double)) Result = (double)value1 + (double)value2; else if (TempType == typeof (decimal)) Result = (decimal)value1 + (decimal)value2; // FIXME: //else if (TempType == typeof (DateTime)) // Result = (DateTime)value1 + (DateTime)value2; return Result; } // This method is shouldnt never invoked public override bool Test (DataRow Row) { throw new EvaluateException (); } } /// /// Class for - /// internal class ExpressionSubtraction : ExpressionElement { public ExpressionSubtraction (string exp1, string exp2) { this.exp1 = exp1; this.exp2 = exp2; ParseExpression (exp1); ParseExpression (exp2); } public override object Result (DataRow Row) { return CalculateResult (Row); } // This method is shouldnt never invoked public override bool Test (DataRow Row) { throw new EvaluateException (); } protected override object Calculate (object value1, object value2, Type TempType) { object Result = null; // FIXME: //if (TempType == typeof (string)) // Result = (string)value1 - (string)value2; if (TempType == typeof (long)) Result = (long)value1 - (long)value2; else if (TempType == typeof (int)) Result = (int)value1 - (int)value2; else if (TempType == typeof (short)) Result = (short)value1 - (short)value2; else if (TempType == typeof (ulong)) Result = (ulong)value1 + (ulong)value2; else if (TempType == typeof (uint)) Result = (uint)value1 - (uint)value2; else if (TempType == typeof (ushort)) Result = (ushort)value1 - (ushort)value2; else if (TempType == typeof (byte)) Result = (byte)value1 - (byte)value2; else if (TempType == typeof (sbyte)) Result = (sbyte)value1 - (sbyte)value2; // FIXME: //else if (TempType == typeof (bool)) // Result = (bool)value1 - (bool)value2; else if (TempType == typeof (float)) Result = (float)value1 - (float)value2; else if (TempType == typeof (double)) Result = (double)value1 - (double)value2; else if (TempType == typeof (decimal)) Result = (decimal)value1 - (decimal)value2; // FIXME: //else if (TempType == typeof (DateTime)) // Result = (DateTime)value1 - (DateTime)value2; return Result; } } /// /// Class for * /// internal class ExpressionMultiply : ExpressionElement { public ExpressionMultiply (string exp1, string exp2) { this.exp1 = exp1; this.exp2 = exp2; ParseExpression (exp1); ParseExpression (exp2); } public override Type ResultType (DataRow Row) { Type ResultType = null; ExpressionElement E1 = ((ExpressionElement)Elements [0]); ExpressionElement E2 = ((ExpressionElement)Elements [1]); Type t1 = E1.ResultType (Row); Type t2 = E2.ResultType (Row); if (t1 == typeof (string) || t2 == typeof (string)) throw new EvaluateException ("Cannon perform '*' operation on " + t1.ToString () + " and " + t2.ToString ()); else if (t1 == typeof (long) || t2 == typeof (long)) ResultType = typeof (long); else if (t1 == typeof (int) || t2 == typeof (int)) ResultType = typeof (int); return ResultType; } public override object Result (DataRow Row) { return CalculateResult (Row); } public override bool Test (DataRow Row) { throw new EvaluateException (); } protected override object Calculate (object value1, object value2, Type TempType) { object Result = null; if (TempType == typeof (long)) Result = (long)value1 * (long)value2; else if (TempType == typeof (int)) Result = (int)value1 * (int)value2; else if (TempType == typeof (short)) Result = (short)value1 * (short)value2; else if (TempType == typeof (ulong)) Result = (ulong)value1 * (ulong)value2; else if (TempType == typeof (uint)) Result = (uint)value1 * (uint)value2; else if (TempType == typeof (ushort)) Result = (ushort)value1 * (ushort)value2; else if (TempType == typeof (byte)) Result = (byte)value1 * (byte)value2; else if (TempType == typeof (sbyte)) Result = (sbyte)value1 * (sbyte)value2; // FIXME: //else if (TempType == typeof (bool)) // Result = (bool)value1 * (bool)value2; else if (TempType == typeof (float)) Result = (float)value1 * (float)value2; else if (TempType == typeof (double)) Result = (double)value1 * (double)value2; else if (TempType == typeof (decimal)) Result = (decimal)value1 * (decimal)value2; // FIXME: //else if (TempType == typeof (DateTime)) // Result = (DateTime)value1 * (DateTime)value2; return Result; } } /// /// Class for * /// internal class ExpressionDivide : ExpressionElement { public ExpressionDivide (string exp1, string exp2) { this.exp1 = exp1; this.exp2 = exp2; ParseExpression (exp1); ParseExpression (exp2); } public override object Result (DataRow Row) { return CalculateResult (Row); } // This method is shouldnt never invoked public override bool Test (DataRow Row) { throw new EvaluateException (); } protected override object Calculate (object value1, object value2, Type TempType) { object Result = null; if (TempType == typeof (long)) Result = (long)value1 / (long)value2; // FIXME: //else if (TempType == typeof (int)) // Result = (string)value1 / (string)value2; else if (TempType == typeof (int)) Result = (int)value1 / (int)value2; else if (TempType == typeof (short)) Result = (short)value1 / (short)value2; else if (TempType == typeof (ulong)) Result = (ulong)value1 / (ulong)value2; else if (TempType == typeof (uint)) Result = (uint)value1 / (uint)value2; else if (TempType == typeof (ushort)) Result = (ushort)value1 / (ushort)value2; else if (TempType == typeof (byte)) Result = (byte)value1 / (byte)value2; else if (TempType == typeof (sbyte)) Result = (sbyte)value1 / (sbyte)value2; // FIXME: //else if (TempType == typeof (bool)) // Result = (bool)value1 // (bool)value2; else if (TempType == typeof (float)) Result = (float)value1 / (float)value2; else if (TempType == typeof (double)) Result = (double)value1 / (double)value2; else if (TempType == typeof (decimal)) Result = (decimal)value1 / (decimal)value2; // FIXME: //else if (TempType == typeof (DateTime)) // Result = (DateTime)value1 / (DateTime)value2; return Result; } } /// /// Class for * /// internal class ExpressionModulus : ExpressionElement { public ExpressionModulus (string exp1, string exp2) { this.exp1 = exp1; this.exp2 = exp2; ParseExpression (exp1); ParseExpression (exp2); } public override object Result (DataRow Row) { return CalculateResult (Row); } // This method is shouldnt never invoked public override bool Test (DataRow Row) { throw new EvaluateException (); } protected override object Calculate (object value1, object value2, Type TempType) { object Result = null; if (TempType == typeof (long)) Result = (long)value1 % (long)value2; // FIXME: //else if (TempType == typeof (int)) // Result = (string)value1 % (string)value2; else if (TempType == typeof (int)) Result = (int)value1 % (int)value2; else if (TempType == typeof (short)) Result = (short)value1 % (short)value2; else if (TempType == typeof (ulong)) Result = (ulong)value1 % (ulong)value2; else if (TempType == typeof (uint)) Result = (uint)value1 % (uint)value2; else if (TempType == typeof (ushort)) Result = (ushort)value1 % (ushort)value2; else if (TempType == typeof (byte)) Result = (byte)value1 % (byte)value2; else if (TempType == typeof (sbyte)) Result = (sbyte)value1 % (sbyte)value2; // FIXME: //else if (TempType == typeof (bool)) // Result = (bool)value1 // (bool)value2; else if (TempType == typeof (float)) Result = (float)value1 % (float)value2; else if (TempType == typeof (double)) Result = (double)value1 % (double)value2; else if (TempType == typeof (decimal)) Result = (decimal)value1 % (decimal)value2; // FIXME: //else if (TempType == typeof (DateTime)) // Result = (DateTime)value1 / (DateTime)value2; return Result; } } // // _____A_G_G_R_E_G_A_T_E_S_____ // internal class ExpressionAggregate : ExpressionElement { public ExpressionAggregate() { } public ExpressionAggregate(string s) { s = ExpressionElement.ValidateExpression (s); ParseExpression (s); } public override bool Test (DataRow Row) { throw new EvaluateException (); } public override object Result(DataRow Row) { DataRow[] rows = new DataRow[Row.Table.Rows.Count]; Row.Table.Rows.CopyTo(rows, 0); return ((ExpressionAggregate)Elements[0]).Result(rows); } public virtual object Result(DataRow[] rows) { return ((ExpressionAggregate)Elements[0]).Result(rows); } protected virtual void ParseParameters (string s) { string stemp = s.ToLower (); bool inString = false; string p1 = null; // find ( while (!s.StartsWith ("(")) s = s.Remove (0, 1); // remove ( s = s.Remove (0, 1); int parentheses = 0; for (int i = 0; i < s.Length; i++) { if (s [i] == '\'') inString = !inString; else if (s [i] == '(') parentheses++; else if (s [i] == ')') parentheses--; if ((s [i] == ',' || s [i] == ')') && !inString && parentheses == -1) { // Parameter changed if (p1 == null) { p1 = s.Substring (0, i); break; } } } if (p1 == null) throw new Exception (); ParseExpression (p1); } } /// /// Class for Sum (column_Name) /// /// Class for Avg (column_Name) /// /// This is used from ExpressionStdDev for evaluating avg. /// public ExpressionAvg (ExpressionElement E) { Elements.Add (E); } } /// /// Class for Min (column_Name) /// /// Class for Max (column_Name) /// 0) result = v; } } return result; } } /// /// Class for count (column) /// internal class ExpressionCount : ExpressionAggregate { public ExpressionCount (string exp1) { ParseParameters (exp1); } public override object Result(DataRow[] rows) { ExpressionElement E1 = (ExpressionElement)Elements [0]; int count = 0; if (E1 is ExpressionSingleElement) count = rows.Length; return count; } public override object Result (DataRow Row) { ExpressionElement E1 = (ExpressionElement)Elements [0]; int count = 0; if (E1 is ExpressionSingleElement) { count = Row.Table.Rows.Count; } return count; } } /// /// Class for StdDev (column) /// internal class ExpressionStdev : ExpressionAggregate { public ExpressionStdev (string exp1) { ParseParameters (exp1); } public override object Result(DataRow[] rows) { ExpressionElement E1 = (ExpressionElement)Elements [0]; ExpressionAvg Avg = new ExpressionAvg (E1); object tempAvg = Avg.Result (rows[0]); double avg = 0; double sum = 0; double result = 0; if (tempAvg.GetType () == typeof (int)) avg = (double)(int)tempAvg; if (E1 is ExpressionSingleElement) { for (int i = 0; i /// Class for Var (column) /// internal class ExpressionVar : ExpressionAggregate { public ExpressionVar (string exp1) { ParseParameters (exp1); } public override object Result(DataRow[] rows) { ExpressionElement E1 = (ExpressionElement)Elements [0]; ExpressionAvg Avg = new ExpressionAvg (E1); object tempAvg = Avg.Result (rows[0]); double avg = 0; double sum = 0; double result = 0; if (tempAvg.GetType () == typeof (int)) avg = (double)(int)tempAvg; if (E1 is ExpressionSingleElement) { for (int i = 0; i < rows.Length; i++) { // (value - avg)² object v = E1.Result (rows[i]); if (v == null || v == DBNull.Value) continue; if (v.GetType () == typeof (long)) sum = avg - (long)v; else if (v.GetType () == typeof (int)) sum = avg - (int)v; else if (v.GetType () == typeof (short)) sum = avg - (short)v; else throw new NotImplementedException (); result += Math.Pow (sum, 2); } result = result / (rows.Length - 1); } return result; } } // // _____F_U_ N_C_T_I_O_N_S_______ // /// /// Class for len (string) function /// internal class ExpressionLen : ExpressionElement { public ExpressionLen (string exp1) { _ResultType = typeof (int); ParseParameters (exp1); } public override object Result (DataRow Row) { ExpressionElement E1 = ((ExpressionElement)Elements [0]); object value1 = E1.Result (Row); return value1.ToString ().Length; } public override bool Test (DataRow Row) { throw new EvaluateException (); } public void ParseParameters (string s) { string stemp = s.ToLower (); bool inString = false; string p1 = null; // find ( while (!s.StartsWith ("(")) s = s.Remove (0, 1); // remove ( s = s.Remove (0, 1); int parentheses = 0; for (int i = 0; i < s.Length; i++) { if (s [i] == '\'') inString = !inString; else if (s [i] == '(') parentheses++; else if (s [i] == ')') parentheses--; if ((s [i] == ',' || s [i] == ')') && !inString && parentheses == -1) { // Parameter changed if (p1 == null) { p1 = s.Substring (0, i); break; } } } if (p1 == null) throw new Exception (); ParseExpression (p1); } } /// /// Class for iif (exp1, truepart, falsepart) function /// internal class ExpressionIif : ExpressionElement { public ExpressionIif (string exp) { ParseParameters (exp); } public override object Result (DataRow Row) { ExpressionElement E1 = ((ExpressionElement)Elements [0]); ExpressionElement E2 = ((ExpressionElement)Elements [1]); ExpressionElement E3 = ((ExpressionElement)Elements [2]); if (E1.Test (Row)) // expression return E2.Result (Row); // truepart else return E3.Result (Row); // false part } // This method is shouldnt never invoked public override bool Test (DataRow Row) { throw new EvaluateException (); } public override Type ResultType (DataRow Row) { ExpressionElement E1 = ((ExpressionElement)Elements [0]); ExpressionElement E2 = ((ExpressionElement)Elements [1]); ExpressionElement E3 = ((ExpressionElement)Elements [2]); if (E1.Test (Row)) // expression return E2.Result (Row).GetType (); // truepart else return E3.Result (Row).GetType (); // false part } /// /// Parses expressions in parameters (exp, truepart, falsepart) /// private void ParseParameters (string s) { bool inString = false; string stemp = s.ToLower (); string p1 = null; string p2 = null; string p3 = null; s = s.Substring (stemp.IndexOf ("iif") + 3); // find ( while (!s.StartsWith ("(")) s = s.Remove (0, 1); // remove ( s = s.Remove (0, 1); int parentheses = 0; for (int i = 0; i < s.Length; i++) { if (s [i] == '\'') inString = !inString; else if (s [i] == '(') parentheses++; else if (s [i] == ')') parentheses--; if ((s [i] == ',' && !inString && parentheses == 0) || (s [i] == ')' && i == (s.Length -1))) { // Parameter changed if (p1 == null) { p1 = s.Substring (0, i); s = s.Substring (i + 1); i = 0; } else if (p2 == null) { p2 = s.Substring (0, i); s = s.Substring (i + 1); i = 0; } else if (p3 == null) { p3 = s.Substring (0, i); s = s.Substring (i + 1); i = 0; } else throw new Exception (); // FIXME: What exception } } if (p1 == null || p2 == null || p3 == null) throw new Exception (); ParseExpression (p1); ParseExpression (p2); ParseExpression (p3); } } /// /// Class for isnull (expression, returnvalue) function /// internal class ExpressionIsNull : ExpressionElement { public ExpressionIsNull (string exp) { ParseParameters (exp); } public override object Result (DataRow Row) { ExpressionElement E1 = (ExpressionElement)Elements [0]; ExpressionElement E2 = (ExpressionElement)Elements [1]; object R1 = E1.Result (Row); object value1 = null; if (R1 == null || R1 == DBNull.Value) return E2.Result (Row); else return R1; } public override Type ResultType (DataRow Row) { ExpressionElement E1 = (ExpressionElement)Elements [0]; ExpressionElement E2 = (ExpressionElement)Elements [1]; object R1 = E1.Result (Row); object value1 = null; if (R1 == null || R1 == DBNull.Value) return E2.Result (Row).GetType (); else return R1.GetType (); } /// /// IsNull function does not return boolean value, so throw exception /// public override bool Test (DataRow Row) { throw new EvaluateException (); } /// /// Parses parameters of function and invoke ParseExpression methods /// private void ParseParameters (string s) { bool inString = false; string stemp = s.ToLower (); string p1 = null; string p2 = null; s = s.Substring (stemp.IndexOf ("isnull") + 6); // find ( while (!s.StartsWith ("(")) s = s.Remove (0, 1); // remove ( s = s.Remove (0, 1); int parentheses = 0; for (int i = 0; i < s.Length; i++) { if (s [i] == '\'') inString = !inString; else if (s [i] == '(') parentheses++; else if (s [i] == ')') parentheses--; if ((s [i] == ',' && !inString && parentheses == 0) || (s [i] == ')' && i == (s.Length -1))) { // Parameter changed if (p1 == null) { p1 = s.Substring (0, i); s = s.Substring (i + 1); i = 0; } else if (p2 == null) { p2 = s.Substring (0, i); s = s.Substring (i + 1); i = 0; } else throw new Exception (); // FIXME: What exception } } if (p1 == null || p2 == null) throw new Exception (); ParseExpression (p1); ParseExpression (p2); } } /// /// Class for Substring (expression, start, length) function /// internal class ExpressionSubstring : ExpressionElement { public ExpressionSubstring (string exp) { ParseParameters (exp); _ResultType = typeof (string); } public override object Result (DataRow Row) { ExpressionElement E1 = (ExpressionElement)Elements [0]; ExpressionElement E2 = (ExpressionElement)Elements [1]; ExpressionElement E3 = (ExpressionElement)Elements [2]; object value1 = E1.Result (Row); object value2 = E2.Result (Row); object value3 = E3.Result (Row); Type t1 = value1.GetType (); Type t2 = value2.GetType (); Type t3 = value3.GetType (); if (value1 == null || value2 == null || value3 == null || value1 == DBNull.Value || value2 == DBNull.Value || value3 == DBNull.Value) return string.Empty; if (t1 != typeof (string)) throw new Exception (); // FIXME: what exception else if (t2 != typeof (int)) throw new EvaluateException ("Type mismatch is function argument: Substring (), argument 2, excepted System.Int32"); else if (t3 != typeof (int)) throw new EvaluateException ("Type mismatch is function argument: Substring (), argument 3, excepted System.Int32"); string str = value1.ToString (); int start = (int)value2; int length = (int)value3; if (str.Length < start) str = string.Empty; else { if ((start + length - 1) > str.Length) str = str.Substring (start - 1); else str = str.Substring (start - 1, length); } return str; } /// /// IsNull function does not return boolean value, so throw exception /// public override bool Test (DataRow Row) { throw new EvaluateException (); } /// /// Parses parameters of function and invoke ParseExpression methods /// private void ParseParameters (string s) { bool inString = false; string stemp = s.ToLower (); string p1 = null; string p2 = null; string p3 = null; s = s.Substring (stemp.IndexOf ("substring") + 9); // find ( while (!s.StartsWith ("(")) s = s.Remove (0, 1); // remove ( s = s.Remove (0, 1); int parentheses = 0; for (int i = 0; i < s.Length; i++) { if (s [i] == '\'') inString = !inString; else if (s [i] == '(') parentheses++; else if (s [i] == ')') parentheses--; if ((s [i] == ',' && !inString && parentheses == 0) || (s [i] == ')' && i == (s.Length -1))) { // Parameter changed if (p1 == null) { p1 = s.Substring (0, i); s = s.Substring (i + 1); i = 0; } else if (p2 == null) { p2 = s.Substring (0, i); s = s.Substring (i + 1); i = 0; } else if (p3 == null) { p3 = s.Substring (0, i); s = s.Substring (i + 1); i = 0; } else throw new Exception (); // FIXME: What exception } } if (p1 == null || p2 == null) throw new Exception (); ParseExpression (p1); ParseExpression (p2); ParseExpression (p3); } } /// /// Class for In (exp, exp, exp, ...) function /// internal class ExpressionIn : ExpressionElement { public ExpressionIn (string exp1, string exp2) { ParseExpression(exp1); ParseParameters (exp2); } /// /// IsNull function does not return boolean value, so throw exception /// public override bool Test (DataRow Row) { ExpressionElement E; ExpressionElement columnElement = (ExpressionElement)Elements [0]; ExpressionElementComparer comparer = new ExpressionElementComparer(columnElement, Row); for (int i = 1; i < Elements.Count; i++) { E = (ExpressionElement)Elements [i]; if(comparer.CompareTo(E) == 0) return true; } return false; } /// /// Parses parameters of function and invoke ParseExpression methods /// private void ParseParameters (string s) { bool inString = false; ArrayList parameters = new ArrayList(); // find ( while (!s.StartsWith ("(")) s = s.Remove (0, 1); // remove ( s = s.Remove (0, 1); int parentheses = 0; for (int i = 0; i < s.Length; i++) { if (s [i] == '\'') inString = !inString; else if (s [i] == '(') parentheses++; else if (s [i] == ')') parentheses--; if ((s [i] == ',' && !inString && parentheses == 0) || (s [i] == ')' && i == (s.Length -1))) { parameters.Add(s.Substring (0, i)); s = s.Substring (i + 1); i = 0; } } for (int i = 0; i < parameters.Count; i++) ParseExpression((string)parameters[i]); } } /// /// Class for just one element for example string, int, ... /// internal class ExpressionSingleElement : ExpressionElement { private object Element = null; public ExpressionSingleElement (string s) { // TODO: Every type should be checked if (s.StartsWith ("'") && s.EndsWith ("'")) { Element = s.Substring (1, s.Length - 2); _ResultType = typeof (string); } else if (!Char.IsDigit (s [0]) && s [0] != '-' && s [0] != '+') { Element = s; _ResultType = typeof (DataColumn); } else if (s.StartsWith ("#") && s.EndsWith ("#")) { Element = DateTime.Parse (s.Substring (1, s.Length - 2)); _ResultType = typeof (DateTime); } else { try { Element = int.Parse (s); _ResultType = typeof (int); } catch { Element = Decimal.Parse (s); _ResultType = typeof (Decimal); } } } public override object Result (DataRow Row) { object Result = null; if (ResultType (Row) == typeof (DataColumn)) { if (!Row.Table.Columns.Contains (Element.ToString ())) throw new EvaluateException ("Column name '" + Element.ToString () + "' not found."); else { DataRowVersion rowVersion = DataRowVersion.Default; // if this row is deleted we get the original version, or else we get an exception. if (Row.RowState == DataRowState.Deleted) rowVersion = DataRowVersion.Original; Result = Row [Element.ToString (), rowVersion]; } } else Result = Element; return Result; } public override bool Test (DataRow Row) { throw new EvaluateException (); } } /// /// Parent class of all the elements of expression /// internal abstract class ExpressionElement { enum OP {OPERATOR, OPERAND}; enum OPERATOR_TYPE {SYMBOLIC, LITERAL, UNDEFINED}; enum OPERAND_TYPE {NUMERIC, STRING, UNDEFINED}; // // TODO/FIXME: This class should be inherited more than once. I mean own subclass for operators, functions,... // protected string exp1; protected string exp2; protected Type _ResultType; protected ArrayList Elements = new ArrayList (); enum AGGREGATE {SUM, AVG, MIN, MAX, COUNT, STDEV, VAR} //protected ArrayList Singles = new ArrayList (); /// /// Tells does the current expressions match to current DataRow /// abstract public bool Test (DataRow Row); public virtual object Result (DataRow Row) {return null;} public virtual Type ResultType (DataRow Row) { return _ResultType; } protected object CalculateResult (DataRow Row) { ExpressionElement E1 = ((ExpressionElement)Elements [0]); ExpressionElement E2 = ((ExpressionElement)Elements [1]); object Result = null; object value1 = E1.Result (Row); object value2 = E2.Result (Row); Type t1 = value1.GetType (); Type t2 = value2.GetType (); // Check nulls if (value1 == DBNull.Value && value2 == DBNull.Value) return null; // TODO: More types if (t1 == typeof (string) || t2 == typeof (string)) { if (t1 != typeof (string)) value1 = Convert.ChangeType (value1, Type.GetTypeCode (t2)); else if (t2 != typeof (string)) value2 = Convert.ChangeType (value2, Type.GetTypeCode (t1)); } if (t1 != t2) value2 = Convert.ChangeType (value2, Type.GetTypeCode (t1)); Result = Calculate (value1, value2, t1); return Result; } protected virtual object Calculate (object value1, object value2, Type TempType) { return null; } /// /// static method for comparing two ExpressionElement. This is used in =, <, >, <>, <=, >= elements. /// If elements are equal returns 0, if E1 is less that E2, return -1 else if E1 is greater 1 /// protected static int Compare (ExpressionElement E1, ExpressionElement E2, DataRow Row) { ExpressionElementComparer comparer = new ExpressionElementComparer(E1, Row); return comparer.CompareTo(E2); } /// /// Checks syntax of expression and throws exception if needed. /// Also removes whitespaces between operator elements for example: age < = 64 --> age <= 64 /// internal static string ValidateExpression (string s) { // // TODO: find out nice way to do this. This is NOT nice way :-P // //string temp = ""; OP op = OP.OPERAND; OPERATOR_TYPE operatorType = OPERATOR_TYPE.UNDEFINED; StringBuilder strOperator = new StringBuilder(); StringBuilder strOperand = new StringBuilder(); int quotes = 0; int parentheses = 0; StringBuilder newExp = new StringBuilder(); bool isDigit = false; //bool litOperator = false; s = s.Trim(); for (int i = 0; i < s.Length; i++) { char c = s [i]; if (c == '\'') quotes++; if ((c == '\n' || c == '\t') && quotes == 0) c = ' '; if (op == OP.OPERAND && c == '(') parentheses++; else if (op == OP.OPERAND && c == ')') parentheses--; if (c == ' ' && op == OP.OPERAND && (quotes % 2) == 0 && parentheses == 0) { op = OP.OPERATOR; int max = strOperand.Length; for (int it = 0; it < max; it++) newExp.Append(strOperand[it]); strOperand.Remove(0, max); strOperator.Append(' '); } if (op == OP.OPERAND) { if (!Char.IsDigit (c) && isDigit && (quotes % 2) == 0) { int max = strOperand.Length; for (int it = 0; it < max; it++) newExp.Append(strOperand[it]); strOperand.Remove(0, max); op = OP.OPERATOR; operatorType = OPERATOR_TYPE.UNDEFINED; } else strOperand.Append(c); } if (op == OP.OPERATOR) { isDigit = false; if (operatorType == OPERATOR_TYPE.UNDEFINED) { if (c == '<' || c == '=' || c == '>' || c == '*' || c == '/' || c == '%' || c == '-' || c == '+') operatorType = OPERATOR_TYPE.SYMBOLIC; else if (c != ' ') operatorType = OPERATOR_TYPE.LITERAL; } else if (operatorType == OPERATOR_TYPE.SYMBOLIC) { //Checking for operators following one another if ((c == '=' || c== '<' || c== '>') && (strOperator.Length == 2) && (strOperator[0] == ' ')) { char chSecond = strOperator[1]; if (chSecond == '+' || chSecond == '-' || chSecond == '%' || chSecond == '*') throw new SyntaxErrorException ( "The operator " + strOperator.ToString() + c + " is not valid"); } // this is COPY-PASTE op = OP.OPERAND; if (newExp[newExp.Length - 1] != ' ' && strOperator[0] != ' ') newExp.Append(' '); int max = strOperator.Length; for (int it = 0; it < max; it++) newExp.Append(strOperator[it]); strOperator.Remove(0, max); if (Char.IsDigit (c)) isDigit = true; strOperand.Remove(0, strOperand.Length); strOperand.Append(c); continue; } if (operatorType == OPERATOR_TYPE.LITERAL && c == ' ') { op = OP.OPERAND; int max = strOperator.Length; for (int it = 0; it < max; it++) newExp.Append(strOperator[it]); strOperator.Remove(0, max); strOperand.Append(' '); } if (Char.IsDigit (c) && operatorType != OPERATOR_TYPE.LITERAL) { op = OP.OPERAND; if (newExp[newExp.Length - 1] != ' ' && strOperator[0] != ' ') newExp.Append(' '); int max = strOperator.Length; for (int it = 0; it < max; it++) newExp.Append(strOperator[it]); strOperator.Remove(0, max); if (Char.IsDigit (c)) isDigit = true; strOperand.Remove(0, strOperand.Length); strOperand.Append(c); } else if (c != ' ') strOperator.Append(c); } } if (op == OP.OPERATOR) throw new SyntaxErrorException ( "Missing operand after '" + strOperator.ToString() + "' operator"); else { int max = strOperand.Length; for (int it = 0; it < max; it++) newExp.Append(strOperand[it]); } return newExp.ToString(); } /// /// Finds and creates Expression elements. /// This presumes that expression is valid. /// protected void ParseExpression (string s) { // // TODO/FIXME: IMHO, this should be done with different kind of parsing: // char by char not operand by operand. // fixed the easy places, should consider better parsing // string inside = String.Empty; // stores string betwee parentheses like a = 12 and (b = 1 or b = 2) string lower = s.ToLower(); //string function = ""; // stores fuction paramters like substring (this, are, paramters) //string s1 = ""; //string s2 = ""; int startIndex = lower.IndexOf ('('); // Find parenthesis if (startIndex != -1) { string functionName = String.Empty; if (startIndex > 0) { int functionStart = lower.LastIndexOf('=', startIndex-1, startIndex); if (functionStart < 0) functionStart++; functionName = lower.Substring(functionStart, startIndex); functionName = functionName.Trim (); } // check if previous element is a function if (functionName.Length == 0 || (!functionName.EndsWith ("convert") && !functionName.EndsWith ("len") && !functionName.EndsWith ("isnull") && !functionName.EndsWith ("iif") && !functionName.EndsWith ("trim") && !functionName.EndsWith ("substring") && !functionName.EndsWith ("sum") && !functionName.EndsWith ("avg") && !functionName.EndsWith ("min") && !functionName.EndsWith ("max") && !functionName.EndsWith ("count") && !functionName.EndsWith ("stdev") && !functionName.EndsWith ("var")&& !functionName.EndsWith ("in"))) { int i = startIndex + 1; int max = lower.Length; for (int par = 1; par > 0 && i < max; i++) { char c = s [i]; if (c == '(') par++; else if (c == ')') par--; } inside = s.Substring(startIndex + 1, i - startIndex - 2); lower = lower.Remove (startIndex, i - startIndex); s = s.Remove (startIndex, i - startIndex); } } string string1 = null; string string2 = null; if (FindOrElement (s, lower, ref string1, ref string2)) CreateOrElement (string1, string2, inside); else if (FindAndElement (s, lower, ref string1, ref string2)) CreateAndElement (string1, string2, inside); // find LIKE else if (FindLikeElement (s, lower, ref string1, ref string2)) CreateLikeElement (string1, string2, inside); // find IN else if (FindInElement (s, lower, ref string1, ref string2)) CreateInElement (string1, string2, inside); // find = else if (FindEqualElement (s, lower, ref string1, ref string2)) CreateEqualsElement (string1, string2, inside); // find <> else if (FindUnequalElement (s, lower, ref string1, ref string2)) CreateUnequalsElement (string1, string2, inside); // find <= else if (FindLessThanOrEqualElement (s, lower, ref string1, ref string2)) CreateLessThanOrEqualElement (string1, string2, inside); // find < else if (FindLessThanElement (s, lower, ref string1, ref string2)) CreateLessThanElement (string1, string2, inside); // find >= else if (FindGreaterThanOrEqualElement (s, lower, ref string1, ref string2)) CreateGreaterThanOrEqualElement (string1, string2, inside); // find > else if (FindGreaterThanElement (s, lower, ref string1, ref string2)) CreateGreaterThanElement (string1, string2, inside); // if there wasn't any operators like 'and' or 'not' there still could be // arithmetic operators like '+' or '-' or functions like 'iif' or 'substring' // find * else if (FindMultiplyElement (s, lower, ref string1, ref string2)) CreateMultiplyElement (string1, string2, inside); // find / else if (FindDivideElement (s, lower, ref string1, ref string2)) CreateDivideElement (string1, string2, inside); // find + else if (FindAdditionElement (s, lower, ref string1, ref string2)) CreateAdditionElement (string1, string2, inside); // find - else if (FindSubtractElement (s, lower, ref string1, ref string2)) CreateSubtractionElement (string1, string2, inside); // find % else if (FindModulusElement (s, lower, ref string1, ref string2)) CreateModulusElement (string1, string2, inside); // find sum () else if (FindAggregateElement (s, lower, AGGREGATE.SUM)) Elements.Add (new ExpressionSum (s.Trim ())); // find avg () else if (FindAggregateElement (s, lower, AGGREGATE.AVG)) Elements.Add (new ExpressionAvg (s.Trim ())); // find min () else if (FindAggregateElement (s, lower, AGGREGATE.MIN)) Elements.Add (new ExpressionMin (s.Trim ())); // find max () else if (FindAggregateElement (s, lower, AGGREGATE.MAX)) Elements.Add (new ExpressionMax (s.Trim ())); // find count () else if (FindAggregateElement (s, lower, AGGREGATE.COUNT)) Elements.Add (new ExpressionCount (s.Trim ())); // find stdev () else if (FindAggregateElement (s, lower, AGGREGATE.STDEV)) Elements.Add (new ExpressionStdev (s.Trim ())); // find var () else if (FindAggregateElement (s, lower, AGGREGATE.VAR)) Elements.Add (new ExpressionVar (s.Trim ())); // find len else if (FindLenElement (s, lower)) Elements.Add (new ExpressionLen (s.Trim ())); // find iif else if (FindIifElement (s, lower)) Elements.Add (new ExpressionIif (s.Trim ())); // find isnull else if (FindIsNullElement (s, lower)) Elements.Add (new ExpressionIsNull (s.Trim ())); // find substring else if (FindSubstringElement (s, lower)) Elements.Add (new ExpressionSubstring (s.Trim ())); // if expression is like '(something someoperator something)' else if (inside.Trim () != string.Empty) ParseExpression (inside); // At least, if it wasnt any of the above it is just normat string or int // or.... else Elements.Add (new ExpressionSingleElement (s.Trim ())); } #region CheckElement methods // // These methods are temporary for now // private bool FindOrElement (string s, string lower, ref string s1, ref string s2) { string stemp = lower; int indexOf = stemp.IndexOf("or"); if (indexOf == -1) return false; // Test if or is between '' int oldIndex = -1; while ((indexOf = stemp.IndexOf ("or", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; // check is the 'or' element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; // Check is or part of something else for example column name if (indexOf != 0) { if (stemp [indexOf - 1] != ' ' && stemp [indexOf - 1] != '\'') continue; } if (indexOf < s.Length + 2) { if (stemp [indexOf + 2] != ' ' && stemp [indexOf + 2] != '\'') continue; } if (IsPartOfFunction (stemp, indexOf)) continue; s1 = s.Substring (0, indexOf).Trim (); s2 = s.Substring (indexOf + 2).Trim (); return true; } return false; } private bool FindAndElement (string s, string lower, ref string s1, ref string s2) { string stemp = lower; int indexOf = stemp.IndexOf("and"); if (indexOf == -1) return false; // Test if or is between '' int oldIndex = -1; while ((indexOf = stemp.IndexOf ("and", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; // check is the 'and' element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; // Check is or part of something else for example column name if (indexOf != 0) { if (stemp [indexOf - 1] != ' ' && stemp [indexOf - 1] != '\'') continue; } if (indexOf < stemp.Length + 3) { if (stemp [indexOf + 3] != ' ' && stemp [indexOf + 3] != '\'') continue; } if (IsPartOfFunction (stemp, indexOf)) continue; s1 = s.Substring (0, indexOf).Trim (); s2 = s.Substring (indexOf + 3).Trim (); return true; } return false; } private bool FindLikeElement (string s, string lower, ref string s1, ref string s2) { string stemp = lower; int indexOf = stemp.IndexOf("like"); if (indexOf == -1) return false; // Test if or is between '' int oldIndex = -1; while ((indexOf = stemp.IndexOf ("like", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; // check is the 'and' element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; // Check is or part of something else for example column name if (indexOf != 0) { if (stemp [indexOf - 1] != ' ' && stemp [indexOf - 1] != '\'') continue; } if (indexOf < stemp.Length + 4) { if (stemp [indexOf + 4] != ' ' && stemp [indexOf + 4] != '\'') continue; } if (IsPartOfFunction (stemp, indexOf)) continue; s1 = s.Substring (0, indexOf).Trim (); s2 = s.Substring (indexOf + 4).Trim (); return true; } return false; } private bool FindEqualElement (string s, string lower, ref string s1, ref string s2) { string stemp = lower; int indexOf = stemp.IndexOf ("="); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("=", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; // Check is the = part of <= or >= if (stemp [indexOf - 1] == '<' || stemp [indexOf - 1] == '>') continue; // Check is the = element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; // Check is or part of column name if (IsPartOfColumnName (stemp, indexOf)) continue; if (IsPartOfFunction (stemp, indexOf)) continue; s1 = s.Substring (0, indexOf).Trim (); s2 = s.Substring (indexOf + 1).Trim (); return true; } return false; } private bool FindUnequalElement (string s, string lower, ref string s1, ref string s2) { string stemp = lower; int indexOf = stemp.IndexOf ("<>"); if (stemp.IndexOf ("<>") == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("<>", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; // test if next charachter is something else than ' ' bool failed = false; // Check is the <> element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; // Check is or part of column name if (IsPartOfColumnName (stemp, indexOf)) continue; if (IsPartOfFunction (stemp, indexOf)) continue; s1 = s.Substring (0, indexOf).Trim (); s2 = s.Substring (indexOf + 2).Trim (); return true; } return false; } private bool FindLessThanElement (string s, string lower, ref string s1, ref string s2) { string stemp = lower; int indexOf = stemp.IndexOf ("<"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("<", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; // if < is part of <> or <= if (stemp [indexOf + 1] == '>' || stemp [indexOf + 1] == '=') continue; // Test is < element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; // Check is or part of column name if (IsPartOfColumnName (stemp, indexOf)) continue; if (IsPartOfFunction (stemp, indexOf)) continue; s1 = s.Substring (0, indexOf).Trim (); s2 = s.Substring (indexOf + 1).Trim (); return true; } return false; } private bool FindLessThanOrEqualElement (string s, string lower, ref string s1, ref string s2) { string stemp = lower; int indexOf = stemp.IndexOf ("<="); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("<=", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; // Test is <= element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; // Check is or part of column name if (IsPartOfColumnName (stemp, indexOf)) continue; if (IsPartOfFunction (stemp, indexOf)) continue; s1 = s.Substring (0, indexOf).Trim (); s2 = s.Substring (indexOf + 2).Trim (); return true; } return false; } private bool FindGreaterThanElement (string s, string lower, ref string s1, ref string s2) { string stemp = lower; int indexOf = stemp.IndexOf (">"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf (">", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; // if < is part of <> or <= if (stemp [indexOf - 1] == '<' || stemp [indexOf + 1] == '=') continue; // Test is < element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; // Check is or part of column name if (IsPartOfColumnName (stemp, indexOf)) continue; if (IsPartOfFunction (stemp, indexOf)) continue; s1 = s.Substring (0, indexOf).Trim (); s2 = s.Substring (indexOf + 1).Trim (); return true; } return false; } private bool FindGreaterThanOrEqualElement (string s, string lower, ref string s1, ref string s2) { string stemp = lower; int indexOf = stemp.IndexOf (">="); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf (">=", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; bool failed = false; // Test is <= element part of string element // Check is or part of column name if (IsPartOfColumnName (stemp, indexOf)) continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; if (IsPartOfFunction (stemp, indexOf)) continue; s1 = s.Substring (0, indexOf).Trim (); s2 = s.Substring (indexOf + 2).Trim (); return true; } return false; } private bool FindAdditionElement (string s, string lower, ref string s1, ref string s2) { string stemp = lower; int indexOf = stemp.IndexOf ("+"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("+", oldIndex + 1)) != -1 && indexOf > oldIndex) { // FIXME: if '+' represents sign of integer oldIndex = indexOf; bool failed = false; // Check is or part of column name if (IsPartOfColumnName (stemp, indexOf)) continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; if (IsPartOfFunction (stemp, indexOf)) continue; s1 = s.Substring (0, indexOf).Trim (); s2 = s.Substring (indexOf + 1).Trim (); return true; } return false; } private bool FindSubtractElement (string s, string lower, ref string s1, ref string s2) { string stemp = lower; int indexOf = stemp.IndexOf ("-"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("-", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; bool failed = false; // check is this lonely element failed = true; for (int i = indexOf - 1; i >= 0; i--) { if (stemp [i] != ' ') { failed = false; break; } } if (failed) continue; // Check is or part of column name if (IsPartOfColumnName (stemp, indexOf)) continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; if (IsPartOfFunction (stemp, indexOf)) continue; s1 = s.Substring (0, indexOf).Trim (); s2 = s.Substring (indexOf + 1).Trim (); return true; } return false; } private bool FindMultiplyElement (string s, string lower, ref string s1, ref string s2) { string stemp = lower; int indexOf = stemp.IndexOf ("*"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("*", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; bool failed = false; // FIXME: If there is a divide operator before multiply operator. // Check is or part of column name if (IsPartOfColumnName (stemp, indexOf)) continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; if (IsPartOfFunction (stemp, indexOf)) continue; s1 = s.Substring (0, indexOf).Trim (); s2 = s.Substring (indexOf + 1).Trim (); return true; } return false; } private bool FindDivideElement (string s, string lower, ref string s1, ref string s2) { string stemp = lower; int indexOf = stemp.IndexOf ("/"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("/", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; bool failed = false; // FIXME: If there is a multiply operator before divide operator. // Check is or part of column name if (IsPartOfColumnName (stemp, indexOf)) continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; if (IsPartOfFunction (stemp, indexOf)) continue; s1 = s.Substring (0, indexOf).Trim (); s2 = s.Substring (indexOf + 1).Trim (); return true; } return false; } private bool FindModulusElement (string s, string lower, ref string s1, ref string s2) { string stemp = lower; int indexOf = stemp.IndexOf ("%"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("%", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; bool failed = false; // FIXME: If there is a multiply operator before divide operator. // Check is or part of column name if (IsPartOfColumnName (stemp, indexOf)) continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; s1 = s.Substring (0, indexOf).Trim (); s2 = s.Substring (indexOf + 1).Trim (); return true; } return false; } private bool FindAggregateElement (string s, string lower, AGGREGATE aggregate) { string agg = null; switch (aggregate) { case AGGREGATE.SUM: agg = "sum"; break; case AGGREGATE.AVG: agg = "avg"; break; case AGGREGATE.MIN: agg = "min"; break; case AGGREGATE.MAX: agg = "max"; break; case AGGREGATE.COUNT: agg = "count"; break; case AGGREGATE.STDEV: agg = "stdev"; break; case AGGREGATE.VAR: agg = "var"; break; default: throw new NotImplementedException (); } string stemp = lower; int indexOf = stemp.IndexOf (agg); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf (agg, oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; bool failed = false; // Check is or part of column name if (indexOf != 0 && stemp [indexOf - 1] != ' ') continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; return true; } return false; } private bool FindSumElement (string s, string lower) { string stemp = lower; int indexOf = stemp.IndexOf ("sum"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("sum", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; bool failed = false; // Check is or part of column name if (indexOf != 0 && stemp [indexOf - 1] != ' ') continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; return true; } return false; } private bool FindAvgElement (string s, string lower) { string stemp = lower; int indexOf = stemp.IndexOf ("avg"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("avg", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; bool failed = false; // Check is or part of column name if (indexOf != 0 && stemp [indexOf - 1] != ' ') continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; return true; } return false; } private bool FindMinElement (string s, string lower) { string stemp = lower; int indexOf = stemp.IndexOf ("min"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("min", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; bool failed = false; // Check is or part of column name if (indexOf != 0 && stemp [indexOf - 1] != ' ') continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; return true; } return false; } private bool FindMaxElement (string s, string lower) { string stemp = lower; int indexOf = stemp.IndexOf ("max"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("max", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; bool failed = false; // Check is or part of column name if (indexOf != 0 && stemp [indexOf - 1] != ' ') continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; return true; } return false; } private bool FindCountElement (string s, string lower) { string stemp = lower; int indexOf = stemp.IndexOf ("count"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("count", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; bool failed = false; // Check is or part of column name if (indexOf != 0 && stemp [indexOf - 1] != ' ') continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; return true; } return false; } private bool FindStdevElement (string s, string lower) { string stemp = lower; int indexOf = stemp.IndexOf ("stdev"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("stdev", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; bool failed = false; // Check is or part of column name if (indexOf != 0 && stemp [indexOf - 1] != ' ') continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; return true; } return false; } private bool FindVarElement (string s, string lower) { string stemp = lower; int indexOf = stemp.IndexOf ("var"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("var", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; bool failed = false; // Check is or part of column name if (indexOf != 0 && stemp [indexOf - 1] != ' ') continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; return true; } return false; } private bool FindLenElement (string s, string lower) { string stemp = lower; int indexOf = stemp.IndexOf ("len"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("len", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; bool failed = false; // Check is or part of column name if (indexOf != 0 && stemp [indexOf - 1] != ' ') continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; return true; } return false; } private bool FindIifElement (string s, string lower) { string stemp = lower; int indexOf = stemp.IndexOf ("iif"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("iif", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; bool failed = false; // Check is or part of column name if (indexOf != 0 && stemp [indexOf - 1] != ' ') continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; return true; } return false; } private bool FindIsNullElement (string s, string lower) { string stemp = lower; int indexOf = stemp.IndexOf ("isnull"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("isnull", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; bool failed = false; // Check is or part of column name if (indexOf != 0 && stemp [indexOf - 1] != ' ') continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; return true; } return false; } private bool FindSubstringElement (string s, string lower) { string stemp = lower; int indexOf = stemp.IndexOf ("substring"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("substring", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; bool failed = false; // Check is or part of column name if (indexOf != 0 && stemp [indexOf - 1] != ' ') continue; // is the element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; return true; } return false; } private bool FindInElement (string s, string lower, ref string s1, ref string s2) { string stemp = lower; int indexOf = stemp.IndexOf ("in"); if (indexOf == -1) return false; int oldIndex = -1; while ((indexOf = stemp.IndexOf ("in", oldIndex + 1)) != -1 && indexOf > oldIndex) { oldIndex = indexOf; // check is the 'and' element part of string element if (IsPartOfStringElement (stemp, indexOf)) continue; // Check is or part of something else for example column name if (indexOf != 0) { if (stemp [indexOf - 1] != ' ' && stemp [indexOf - 1] != '\'') continue; } if (indexOf < stemp.Length + 2) { if (stemp [indexOf + 2] != ' ' && stemp [indexOf + 2] != '\'') continue; } if (IsPartOfFunction (stemp, indexOf)) continue; s1 = s.Substring (0, indexOf).Trim (); s2 = s.Substring (indexOf + 2).Trim (); return true; } return false; } #endregion // CheckElement methods #region CreateElement methods // // These methods are going to be removed when way of parsing is changed // private void CreateOrElement (string s1, string s2, string inside) { CheckParenthesis (inside, ref s1, ref s2); Elements.Add (new ExpressionOr (s1.Trim (), s2.Trim ())); } private void CreateAndElement (string s1, string s2, string inside) { CheckParenthesis (inside, ref s1, ref s2); Elements.Add (new ExpressionAnd (s1.Trim (), s2.Trim ())); } private void CreateLikeElement (string s1, string s2, string inside) { CheckParenthesis (inside, ref s1, ref s2); Elements.Add (new ExpressionLike (s1.Trim (), s2.Trim ())); } private void CreateInElement (string s1, string s2, string inside) { CheckParenthesis (inside, ref s1, ref s2); Elements.Add (new ExpressionIn (s1.Trim (), s2.Trim ())); } private void CreateEqualsElement (string s1, string s2, string inside) { CheckParenthesis (inside, ref s1, ref s2); Elements.Add (new ExpressionEquals (s1.Trim (), s2.Trim ())); } private void CreateUnequalsElement (string s1, string s2, string inside) { CheckParenthesis (inside, ref s1, ref s2); Elements.Add (new ExpressionUnequals (s1.Trim (), s2.Trim ())); } private void CreateLessThanElement (string s1, string s2, string inside) { CheckParenthesis (inside, ref s1, ref s2); Elements.Add (new ExpressionLessThan (s1.Trim (), s2.Trim ())); } private void CreateLessThanOrEqualElement (string s1, string s2, string inside) { CheckParenthesis (inside, ref s1, ref s2); Elements.Add (new ExpressionLessThanOrEqual (s1.Trim (), s2.Trim ())); } private void CreateGreaterThanElement (string s1, string s2, string inside) { CheckParenthesis (inside, ref s1, ref s2); Elements.Add (new ExpressionGreaterThan (s1.Trim (), s2.Trim ())); } private void CreateGreaterThanOrEqualElement (string s1, string s2, string inside) { CheckParenthesis (inside, ref s1, ref s2); Elements.Add (new ExpressionGreaterThanOrEqual (s1.Trim (), s2.Trim ())); } private void CreateAdditionElement (string s1, string s2, string inside) { CheckParenthesis (inside, ref s1, ref s2); Elements.Add (new ExpressionAddition (s1.Trim (), s2.Trim ())); } private void CreateSubtractionElement (string s1, string s2, string inside) { CheckParenthesis (inside, ref s1, ref s2); Elements.Add (new ExpressionSubtraction (s1.Trim (), s2.Trim ())); } private void CreateMultiplyElement (string s1, string s2, string inside) { CheckParenthesis (inside, ref s1, ref s2); Elements.Add (new ExpressionMultiply (s1.Trim (), s2.Trim ())); } private void CreateDivideElement (string s1, string s2, string inside) { CheckParenthesis (inside, ref s1, ref s2); Elements.Add (new ExpressionDivide (s1.Trim (), s2.Trim ())); } private void CreateModulusElement (string s1, string s2, string inside) { CheckParenthesis (inside, ref s1, ref s2); Elements.Add (new ExpressionModulus (s1.Trim (), s2.Trim ())); } #endregion // CreateElemnt methods #region Little helppers private void CheckParenthesis (string inside, ref string s1, ref string s2) { if (s1 == string.Empty && inside != string.Empty) s1 = inside; else if (s2 == string.Empty && inside != string.Empty) s2 = inside; } /// /// Checks is the element part of stringelement /// private bool IsPartOfStringElement (string s, int indexOf) { // count how many '-charachters are before or. If count is odd it means or IS between quotes int quotes = 0; for (int i = indexOf - 1; i >= 0; i--) { if (s [i] == '\'') quotes++; } if ((quotes & 1) != 0) return true; else return false; } /// /// Checks is the element part of column table /// private bool IsPartOfColumnName (string s, int indexOf) { for (int i = indexOf; i >= 0; i--) { // If the element is between [] it is part of columnname if (s [i] == '\'' || s [i] == ']') { break; } else if (s [i] == '[') { return true; } } return false; } /// /// Checks are element part of function /// private bool IsPartOfFunction (string s, int indexOf) { // // If ',' or '\'' comes before '(' this element is not part of function's parameters // for (int i = indexOf; i >= 0; i--) { if (s [i] == '(' || s [i] == ',') { return true; } else if (s [i] == ')') { break; } } return false; } #endregion // Little helppers #region ExpressionElementComparer protected sealed class ExpressionElementComparer { object _value1 = null; Type _t1 = null; Type _RT1 = null; DataRow _row = null; public ExpressionElementComparer(ExpressionElement E1, DataRow Row) { _value1 = E1.Result (Row); _row = Row; if (_value1 == null || _value1 == DBNull.Value) return; _t1 = _value1.GetType (); _RT1 = E1.ResultType (Row); } public int CompareTo (ExpressionElement E2) { object value1 = _value1; object value2 = E2.Result (_row); if ((value1 == null || value1 == DBNull.Value) && (value2 == null || value2 == DBNull.Value)) return 0; else if (value2 == null || value2 == DBNull.Value) return 1; else if (value1 == null || value1 == DBNull.Value) return -1; Type t2 = value2.GetType (); Type RT2 = E2.ResultType (_row); if (_t1 == typeof (string) || t2 == typeof (string)) { // FIXME: If one of elements are string they both should be??? return String.Compare(value1.ToString(), value2.ToString(), !_row.Table.CaseSensitive); } if (_t1 != t2) { value2 = Convert.ChangeType (value2, Type.GetTypeCode (_t1)); } if (value1 is IComparable) return ((IComparable)value1).CompareTo(value2); return (int) _t1.InvokeMember ("CompareTo", BindingFlags.Default | BindingFlags.InvokeMethod, null, value1, new object [] {value2}); } } #endregion } #endif }