void CreateSubQueries(QueryContextsEntry queryContextsEntry, OqlExpression expressionTree, bool hollow, bool hasSubclassResultsets, List <QueryOrder> orderings, int skip, int take) { Type t = queryContextsEntry.Type; var queryContexts = queryContextsEntry.QueryContexts; if (queryContexts.Count == 0) { this.subQueries.Add(new QueryInfo(t, ConstructQueryString(t, new Dictionary <Relation, Class>(), expressionTree, hollow, hasSubclassResultsets, orderings, skip, take))); } else { string queryString = string.Empty; int added = 0; foreach (var queryContext in queryContexts) { if (!queryContext.Any(kvp => kvp.Value.SystemType == t)) { if (added > 0) { queryString += " UNION \r\n"; } queryString += ConstructQueryString(t, queryContext, expressionTree, hollow, hasSubclassResultsets, orderings, skip, take); added++; } } this.subQueries.Add(new QueryInfo(t, queryString)); } }
void AddExpr(out OqlExpression expression) { OqlExpression child; OqlExpression result = new OqlExpression(la.line, la.col); string newOp = null; MulExpr(out child); result.Add(child); while (la.kind == 31 || la.kind == 32) { if (la.kind == 31) { Get(); newOp = "+"; } else { Get(); newOp = "-"; } MulExpr(out child); result.Add(child, newOp); } expression = result.Simplify(); }
internal string GenerateFromExpression(OqlExpression expressionTree, List <Relation> prefetchRelations = null) { StringBuilder sb = new StringBuilder(); AnnotateExpressionTree(expressionTree, prefetchRelations); if (expressionTree != null) { List <IdentifierExpression> identifiers = expressionTree.GetAll(e => e is IdentifierExpression && !String.Empty.Equals(e.GetAnnotation <string>(anKey))).Select(e => (IdentifierExpression)e).ToList(); identifiers.Sort((i1, i2) => ((string)i1.Value).CompareTo((string)i2.Value)); bool isFirst = true; foreach (IdentifierExpression exp in identifiers) { if (!String.IsNullOrEmpty(exp.GetAnnotation <string>(anKey))) { if (isFirst) { sb.Append(' '); isFirst = false; } sb.Append(exp.GetAnnotation <string>(anKey)); sb.Append(' '); } } if (sb.Length > 0) { sb.Length--; } } return("FROM " + cls.GetQualifiedTableName() + sb.ToString()); }
void AndExpr(out OqlExpression expression) { OqlExpression child; OqlExpression result = new OqlExpression(la.line, la.col); EqlExpr(out child); result.Add(child); while (la.kind == 5) { Get(); bool negated = false; if (la.kind == 7) { Get(); negated = true; } EqlExpr(out child); if (negated) { child.UnaryOp = "NOT"; } result.Add(child, "AND"); } expression = result.Simplify(); }
void Unary(out OqlExpression expression) { OqlExpression child; OqlExpression result = new OqlExpression(la.line, la.col); string newOp = null; if (la.kind == 31 || la.kind == 32 || la.kind == 36) { if (la.kind == 31) { Get(); newOp = "+"; } else if (la.kind == 32) { Get(); newOp = "-"; } else { Get(); newOp = "~"; } } Primary(out child); result.Add(child); child.UnaryOp = newOp; expression = result.Simplify(); }
private void GenerateQueryContexts() { //if ((int) this.queryLanguage == OldQuery.LoadRelations) // LoadRelatedTables(); //else if (this.queryLanguage == Language.NDOql) if (this.queryLanguage == QueryLanguage.Sql) { var selectList = new SqlColumnListGenerator(pm.NDOMapping.FindClass(typeof(T))).SelectList; var sql = Regex.Replace(this.queryExpression, @"SELECT\s+\*", "SELECT " + selectList); this.expressionTree = new RawIdentifierExpression(sql, 0, 0); } else { NDOql.OqlParser parser = new NDOql.OqlParser(); var parsedTree = parser.Parse(this.queryExpression); if (parsedTree != null) { // The root expression tree might get exchanged. // To make this possible we make it the child of a dummy expression. this.expressionTree = new OqlExpression(0, 0); this.expressionTree.Add(parsedTree); ((IManageExpression)parsedTree).SetParent(this.expressionTree); } } CreateQueryContextsForTypes(); }
/// <summary> /// Parses a given Oql string /// </summary> /// <param name="oql"></param> /// <returns></returns> public OqlExpression Parse(string oql) { if (String.IsNullOrEmpty(oql)) { return(null); } MemoryStream stream = new MemoryStream(); StreamWriter sw = new StreamWriter(stream, Encoding.UTF8); sw.Write(oql); sw.Flush(); stream.Position = 0; Parser parser = new Parser(new Scanner(stream)); MemoryStream ms = new MemoryStream(); StreamWriter errSw = new StreamWriter(ms); parser.errors.errorStream = errSw; parser.Parse(); if (parser.errors.count > 0) { errSw.Flush(); ms.Seek(0L, SeekOrigin.Begin); string errString = string.Empty; using (StreamReader sr = new StreamReader(ms)) errString = sr.ReadToEnd(); throw new OqlExpressionException("Parser Errors: " + errString); } OqlExpression result = parser.RootExpression; AddParents(result); return(result); }
/// <summary> /// Get the where clause of the SQL string /// </summary> /// <returns>Where clause string</returns> public QueryContexts GetContexts(Class resultClass, OqlExpression expressionTree) { var result = new QueryContexts(); if (expressionTree == null) { return(result); } this.names = (from oex in expressionTree.GetAll(e => e is IdentifierExpression) select(string) oex.Value).ToList(); this.allRelations = new HashSet <Relation>(); if (names.Count == 0) { return(result); } foreach (string name in names) { CreateContextForName(resultClass, name, allRelations); } if (allRelations.Count > 0) { this.relations = new List <Relation>(); foreach (var de in allRelations) { relations.Add(de); } BuildMutations(0, result, new Stack <Class>()); } return(result); }
void MulExpr(out OqlExpression expression) { OqlExpression child; OqlExpression result = new OqlExpression(la.line, la.col); string newOp = null; Unary(out child); result.Add(child); while (StartOf(4)) { if (la.kind == 33) { Get(); newOp = "*"; } else if (la.kind == 34) { Get(); newOp = "/"; } else if (la.kind == 35) { Get(); newOp = "%"; } else { Get(); newOp = "MOD"; } Unary(out child); result.Add(child, newOp); } expression = result.Simplify(); }
void Identifier(out OqlExpression expression) { OqlExpression result = null; Expect(1); result = new IdentifierExpression(t.val, t.line, t.col); expression = result.Simplify(); }
/// <summary> /// Sets the Parent property for each element in the tree /// </summary> /// <param name="exp"></param> private void AddParents(OqlExpression exp) { foreach (OqlExpression child in exp.Children) { ((IManageExpression)child).SetParent(exp); AddParents(child); } }
void Primary(out OqlExpression expression) { OqlExpression result = null; OqlExpression child; if (la.kind == 1) { Get(); result = new IdentifierExpression(t.val, t.line, t.col); if (la.kind == 20) { if (IsOidIdentifier(result)) { Expect(20); Expect(3); result.UnaryOp = ""; result.Add(new IndexExpression(int.Parse(t.val), t.line, t.col)); Expect(21); } else { Get(); ParameterList(out child); result = new FunctionExpression(result.Value, t.line, t.col); result.UnaryOp = ""; result.Add(child); Expect(21); } } } else if (StartOf(5)) { Literal(out result); } else if (la.kind == 16) { Get(); result = new ParameterExpression(t.val, t.line, t.col); } else if (la.kind == 20) { Get(); RootExpr(out result); result.HasBrackets = true; Expect(21); } else { SynErr(44); } expression = result.Simplify(); }
internal string GenerateWhereClause(OqlExpression expressionTree) { if (expressionTree == null) { return(string.Empty); } AnnotateExpressionTree(expressionTree); // We remove the dummy expression here. return("WHERE " + WhereString(expressionTree)); }
void CreateSubQueriesForAllTypes( List <QueryContextsEntry> queryContextsList, OqlExpression expressionTree, bool hollow, List <QueryOrder> orderings, int skip, int take, string prefetch = null) { foreach (var item in queryContextsList) { CreateSubQueries(item, expressionTree, hollow, queryContextsList.Count > 1, orderings, skip, take); } }
void StringList(out OqlExpression expression) { OqlExpression result = new OqlExpression(la.line, la.col); Expect(4); result.Add(new StringLiteralExpression(t.val, t.line, t.col)); while (la.kind == 37) { Get(); Expect(4); result.Add(new StringLiteralExpression(t.val, t.line, t.col), ","); } expression = result; }
/// <summary> /// Creates a SQL query string, which can be passed to the IPersistenceHandler to fetch the results for a given concrete type. /// </summary> /// <param name="queryContextsEntry">All contexts which define possible mutations of concrete classes in results and relations.</param> /// <param name="expressionTree">The syntax tree of the NDOql query expression.</param> /// <param name="hollow">Determines, if the query results should be hollow objects.</param> /// <param name="hasSubclassResultsets">Determines, if this query is part of a composed query which spans over several tables.</param> /// <param name="orderings">List of orderings for the resultset.</param> /// <param name="skip">Determines how many records of the resultset should be skipped. The resultset must be ordered.</param> /// <param name="take">Determines how many records of the resultset should be returned by the query. The resultset must be ordered.</param> /// <param name="prefetch">Query for the given prefetch relation.</param> /// <returns>A Query string.</returns> public string GenerateQueryString( QueryContextsEntry queryContextsEntry, OqlExpression expressionTree, bool hollow, bool hasSubclassResultsets, List <QueryOrder> orderings, int skip, int take, string prefetch) { this.selectPartCreator = CreateQuerySelectPart; return(InnerGenerateQueryString(queryContextsEntry, expressionTree, hollow, hasSubclassResultsets, orderings, skip, take, prefetch)); }
void BitAndExpr(out OqlExpression expression) { OqlExpression child; OqlExpression result = new OqlExpression(la.line, la.col); AddExpr(out child); result.Add(child); while (la.kind == 30) { Get(); AddExpr(out child); result.Add(child, "&"); } expression = result.Simplify(); }
void BitOrExpr(out OqlExpression expression) { OqlExpression child; OqlExpression result = new OqlExpression(la.line, la.col); BitXorExpr(out child); result.Add(child); while (la.kind == 28) { Get(); BitXorExpr(out child); result.Add(child, "|"); } expression = result.Simplify(); }
string ConstructQueryString( Type resultType, Dictionary <Relation, Class> relationContext, OqlExpression expressionTree, bool hollow, bool hasSubclassResultsets, List <QueryOrder> orderings, int skip, int take) { Class cls = this.mappings.FindClass(resultType); StringBuilder sb = new StringBuilder("SELECT "); var from = new FromGenerator(cls, relationContext).GenerateFromExpression(expressionTree); var qualifyWithTableName = from.IndexOf("INNER JOIN") > -1; string columnList = this.selectPartCreator(relationContext, hollow, cls, qualifyWithTableName, this.additionalSelectPartData); sb.Append(columnList); // If we need to sort a set of hollow results for different subclasses // we need to fetch the ordering columns together with the oid columns if (hollow && orderings.Count > 0 && hasSubclassResultsets) { var orderCols = (from o in orderings select cls.FindField(o.FieldName).Column.GetQualifiedName()).ToArray(); columnList += ", " + String.Join(", ", orderCols); } sb.Append(' '); sb.Append(from); string where = new WhereGenerator(cls, relationContext).GenerateWhereClause(expressionTree); if (where != string.Empty) { sb.Append(' '); sb.Append(where); } if (orderings.Count > 0) { sb.Append(' '); sb.Append(new OrderGenerator(cls).GenerateOrderClause(orderings, skip, take)); } return(sb.ToString()); }
void Literal(out OqlExpression expression) { OqlExpression result = null; switch (la.kind) { case 2: { Get(); result = new NumberExpression(double.Parse(t.val, CultureInfo.InvariantCulture), t.line, t.col); break; } case 3: { Get(); result = new NumberExpression(int.Parse(t.val), t.line, t.col); break; } case 4: { Get(); result = new StringLiteralExpression(t.val, t.line, t.col); break; } case 13: { Get(); result = new NamedConstantExpression("TRUE", t.line, t.col); break; } case 38: { Get(); result = new NamedConstantExpression("FALSE", t.line, t.col); break; } case 12: { Get(); result = new NamedConstantExpression("NULL", t.line, t.col); break; } default: SynErr(45); break; } expression = result.Simplify(); }
void ParameterList(out OqlExpression expression) { OqlExpression result = new ParameterListExpression(la.line, la.col); OqlExpression child; if (StartOf(6)) { Primary(out child); result.Add(child); while (la.kind == 37) { Get(); Primary(out child); result.Add(child, ","); } } expression = result; /* Do not simplify here, because otherwise the brackets are missing */ }
private Class GetParentClass(OqlExpression exp, string[] arr, out string fieldName, out Relation relation) { Class relClass = this.cls; NDOMapping mappings = relClass.Parent; int i; relation = null; for (i = 0; i < arr.Length - 1; i++) { relation = relClass.FindRelation(arr[i]); if (relation == null) // must be a value type or embedded type { break; } if (this.queryContext.ContainsKey(relation)) { relClass = this.queryContext[relation]; } else { relClass = mappings.FindClass(relation.ReferencedType); } } fieldName = String.Join(".", arr, i, arr.Length - i); if (relClass.FindField(fieldName) == null && fieldName.IndexOf('.') > -1) { // We might have a value type or embedded type here. // These don't have accessor names. // So we try to find the field via the standard column name. // Note, that this doesn't work, if the column name was remapped. // But we don't see another solution for this situation. string tempName = fieldName.Replace('.', '_'); var field = relClass.Fields.FirstOrDefault(f => f.Column.Name == tempName); if (field != null) { fieldName = field.Name; } } return(relClass); }
void RootExpr(out OqlExpression expression) { OqlExpression child; OqlExpression result = new OqlExpression(la.line, la.col); bool negated = false; if (la.kind == 7) { Get(); negated = true; } OrExpr(out child); if (negated) { result.UnaryOp = "NOT"; } result.Add(child); expression = result.Simplify(); }
void Initialize(MappingNode mappingNode, IEnumerable <OidColumn> oidColumns, IEnumerable <ForeignKeyColumn> fkColumns, KeyValuePair <string, int>?typeCodeInfo) { IEnumerator <OidColumn> oidEnumerator = oidColumns.GetEnumerator(); oidEnumerator.MoveNext(); List <OqlExpression> compareExpressions = new List <OqlExpression>(); foreach (ForeignKeyColumn fkColumn in fkColumns) { OidColumn oidColumn = oidEnumerator.Current; compareExpressions.Add(new OnCompareExpression(mappingNode, oidColumn, fkColumn)); oidEnumerator.MoveNext(); } if (typeCodeInfo.HasValue) { compareExpressions.Add(new OnCompareExpression(mappingNode, typeCodeInfo.Value.Key, typeCodeInfo.Value.Value)); } if (compareExpressions.Count == 1) { Add(compareExpressions[0]); } else { OqlExpression andExpression = new OqlExpression(0, 0); int i = 0; foreach (var compareExpression in compareExpressions) { if (i++ == 0) { andExpression.Add(compareExpression); } else { andExpression.Add(compareExpression, "AND"); } } Add(andExpression); } }
private void MoveParameterExpression(OqlExpression expressionTree, int fromOrdinal, int additionalSpace) { if (additionalSpace == 0) { return; } // Moves the ordinal numbers of ParameterExpressions above the current expression to leave parameters for // the additional columns. foreach (ParameterExpression parExp in expressionTree.GetAll(e => { ParameterExpression pe = e as ParameterExpression; if (pe == null) { return(false); } return(pe.Ordinal > fromOrdinal); })) { parExp.Ordinal += additionalSpace; } }
void NumList(out OqlExpression expression) { OqlExpression result = new OqlExpression(la.line, la.col); if (la.kind == 2) { Get(); result.Add(new NumberExpression(double.Parse(t.val, CultureInfo.InvariantCulture), t.line, t.col)); } else if (la.kind == 3) { Get(); result.Add(new NumberExpression(int.Parse(t.val), t.line, t.col)); } else { SynErr(42); } while (la.kind == 37) { Get(); if (la.kind == 2) { Get(); result.Add(new NumberExpression(double.Parse(t.val, CultureInfo.InvariantCulture), t.line, t.col), ","); } else if (la.kind == 3) { Get(); result.Add(new NumberExpression(int.Parse(t.val), t.line, t.col), ","); } else { SynErr(43); } } expression = result; }
/// <summary> /// Creates a Sql query string for the complete query over all types. /// </summary> /// <param name="queryContextsList">List of all contexts which define possible mutations of concrete classes in results and relations.</param> /// <param name="expressionTree">The syntax tree of the NDOql query expression.</param> /// <param name="hollow">Determines, if the query results should be hollow objects.</param> /// <param name="orderings">List of orderings for the resultset.</param> /// <param name="skip">Determines how many records of the resultset should be skipped. The resultset must be ordered.</param> /// <param name="take">Determines how many records of the resultset should be returned by the query. The resultset must be ordered.</param> /// <param name="prefetch">Query for the given prefetch relation.</param> /// <returns>A query string.</returns> /// <remarks>The result can be used for debugging and display purposes or with handlers, which don't support distributed databases.</remarks> public string GenerateQueryStringForAllTypes( List <QueryContextsEntry> queryContextsList, OqlExpression expressionTree, bool hollow, List <QueryOrder> orderings, int skip, int take, string prefetch = null) { this.selectPartCreator = CreateQuerySelectPart; CreateSubQueriesForAllTypes(queryContextsList, expressionTree, hollow, orderings, skip, take); StringBuilder generatedQuery = new StringBuilder(); foreach (QueryInfo qi in subQueries) { generatedQuery.Append(qi.QueryString); generatedQuery.Append(";\r\n"); } generatedQuery.Length -= 3; // the trailing ;\r\n return(generatedQuery.ToString()); }
void RelExpr(out OqlExpression expression) { OqlExpression child; OqlExpression result = new OqlExpression(la.line, la.col); string newOp = null; bool negated = false; BitOrExpr(out child); result.Add(child); if (StartOf(2)) { if (StartOf(3)) { switch (la.kind) { case 22: { Get(); newOp = "<"; break; } case 23: { Get(); newOp = ">"; break; } case 24: { Get(); newOp = "<="; break; } case 25: { Get(); newOp = ">="; break; } case 26: { Get(); newOp = ">="; break; } case 27: { Get(); newOp = "<="; break; } } BitOrExpr(out child); result.Add(child, newOp); } else if (la.kind == 11) { Get(); if (la.kind == 7) { Get(); negated = true; } Expect(12); result.Add(new NamedConstantExpression("NULL", negated, t.line, t.col), "IS"); } else { if (la.kind == 7) { Get(); negated = true; } Expect(10); BitOrExpr(out child); result.Add(child, "BETWEEN"); Expect(5); BitOrExpr(out child); result.Add(child, "BETWEEN"); } } expression = result.Simplify(); }
private void AnnotateExpressionTree(OqlExpression expressionTree) { foreach (ParameterExpression parExp in expressionTree.GetAll(e => e is ParameterExpression).ToList()) { if (Guid.Empty.Equals(parExp.ParameterValue) || DateTime.MinValue.Equals(parExp.ParameterValue)) { var parent = parExp.Parent; if (parent.Operator == "=") { var i = parent.Children.IndexOf(parExp); var nullExp = new NamedConstantExpression("NULL", false, 0, 0); parent.Children[i] = nullExp; ((IManageExpression)nullExp).SetParent(parent); parent.Operator = "IS"; } if (parent.Operator == "<>") { var i = parent.Children.IndexOf(parExp); var nullExp = new NamedConstantExpression("NULL", true, 0, 0); parent.Children[i] = nullExp; ((IManageExpression)nullExp).SetParent(parent); parent.Operator = "IS"; } } } foreach (IdentifierExpression exp in expressionTree.GetAll(e => e is IdentifierExpression).ToList()) { string[] arr = ((string)exp.Value).Split('.'); string fieldName = arr[arr.Length - 1]; // In case of embedded or value types this will be overwritten Relation relation; Class parentClass = GetParentClass(exp, arr, out fieldName, out relation); if (fieldName == "oid") { string[] oidColumns = (from c in parentClass.Oid.OidColumns select QualifiedColumnName.Get(c)).ToArray(); if (relation != null) { // In these cases we don't need the join to the table of the class owning the oid. // It's sufficient to compare against the foreign keys stored in the owner class' table // or in the mapping table if (relation.MappingTable != null) { oidColumns = (from c in relation.MappingTable.ChildForeignKeyColumns select QualifiedColumnName.Get(relation.MappingTable, c)).ToArray(); } else if (relation.Multiplicity == RelationMultiplicity.Element) { oidColumns = (from c in relation.ForeignKeyColumns select QualifiedColumnName.Get(c)).ToArray(); } } ParameterExpression parExp = exp.Siblings[0] as ParameterExpression; var isDirectSingleExpression = exp.Parent.Operator != "=" || oidColumns.Length == 1 && exp.Siblings[0] is ConstantExpression; // like "oid = 123" if (parExp == null && !isDirectSingleExpression) { throw new QueryException(10010, $"Expression '{exp.ToString()}' resolves to an oid. It's sibling expression must be a ParameterExpression. But the sibling is {exp.Siblings[0]}"); } object[] oidKeys = null; if (!isDirectSingleExpression) { // split the ObjectId or an array into individual parameters oidKeys = ExtractOidKeys(parExp); // Now set the parameter value of the first column if (oidKeys != null) { parExp.ParameterValue = oidKeys[0]; } } if (oidColumns.Length > 1 && exp.Children.Count == 0) { OqlExpression equalsExpression = exp.Parent; // Must be a = expression like 'xxx.oid = {0}'. // We need some additional parameters for the additional columns. MoveParameterExpression(expressionTree, parExp.Ordinal, oidColumns.Length - 1); // Replace the parent expression with a new AND expression OqlExpression andExpression = new OqlExpression(0, 0); ((IManageExpression)andExpression).SetParent(equalsExpression.Parent); equalsExpression.Parent.Children.Remove(equalsExpression); equalsExpression.Parent.Add(andExpression); // We need to set Parent and Child explicitly. // See comment in IManageExpression.SetParent. // Reuse the original equality expression as first child of the AND expression ((IManageExpression)equalsExpression).SetParent(andExpression); andExpression.Add(equalsExpression); exp.SetAnnotation(anKey, oidColumns[0]); int currentOrdinal = parExp.Ordinal; // Now add the additional children of the AND expression for (int i = 1; i < oidColumns.Length; i++) { OqlExpression newParent = equalsExpression.DeepClone; // equality expression and it's both children andExpression.Add(newParent, "AND"); ((IManageExpression)newParent).SetParent(andExpression); // Now patch the Annotation and a new parameter to the children IdentifierExpression newIdentExp = (IdentifierExpression)newParent.Children.Where(e => e is IdentifierExpression).First(); newIdentExp.SetAnnotation(anKey, oidColumns[i]); ParameterExpression newParExp = (ParameterExpression)newParent.Children.Where(e => e is ParameterExpression).First(); if (oidKeys != null) { newParExp.ParameterValue = oidKeys[i]; } newParExp.Ordinal = ++currentOrdinal; } } else { int index = 0; if (exp.Children.Count > 0 && exp.Children[0] is IndexExpression) { index = (int)exp.Children[0].Value; } if (index >= oidColumns.Length) { throw new IndexOutOfRangeException("oid index exceeds oid column count"); } exp.SetAnnotation(anKey, oidColumns[index]); } } else { Field field = parentClass.FindField(fieldName); if (field != null) { exp.SetAnnotation(anKey, QualifiedColumnName.Get(field.Column)); } else { Relation oneTooneRelation = parentClass.Relations.FirstOrDefault(r => r.Multiplicity == RelationMultiplicity.Element && (r.FieldName == fieldName || r.AccessorName == fieldName)); if (oneTooneRelation != null) { exp.SetAnnotation(anKey, QualifiedColumnName.Get(oneTooneRelation.ForeignKeyColumns.First())); } else { throw new Exception("Can't find Field mapping for " + fieldName + " in " + exp.Value); } } } } }
string WhereString(OqlExpression thisExpression) { StringBuilder sb = new StringBuilder(); if (thisExpression.IsTerminating || thisExpression is IdentifierExpression) { if (thisExpression.UnaryOp != null) { sb.Append(thisExpression.UnaryOp); sb.Append(' '); } if (thisExpression.Value.GetType().IsPrimitive) { sb.Append(Convert.ToString(thisExpression.Value, CultureInfo.InvariantCulture)); } else { IdentifierExpression iexp = thisExpression as IdentifierExpression; if (iexp != null) { sb.Append(iexp.GetAnnotation <string>(anKey)); } else { sb.Append(thisExpression.Value.ToString()); } } } else { if (thisExpression.UnaryOp != null) { sb.Append(thisExpression.UnaryOp); sb.Append(' '); } if (thisExpression is FunctionExpression) { sb.Append(thisExpression.Value); } if (thisExpression.HasBrackets) { sb.Append('('); } string op1 = thisExpression.Operator; int childExpEndIndex = thisExpression.Children.Count - 1; for (int i = 0; i <= childExpEndIndex; i++) { OqlExpression child = thisExpression.Children[i]; sb.Append(WhereString(child)); if (i < childExpEndIndex) { if (op1 != ",") { sb.Append(' '); } sb.Append(op1); if (op1 == "BETWEEN") { op1 = "AND"; } sb.Append(' '); } } if (thisExpression.HasBrackets) { sb.Append(')'); } } return(sb.ToString()); }