public SqlSectionExpr Postprocess() { switch (sectionName) { case "SELECT": case "FROM": var lst = new Expr[args.Count]; for (int i = 0; i < args.Count; i++) { var expr = args[i]; var seq = expr as SequenceExpr; Expr item; if (seq != null && seq.args.Count > 1) { item = AliasExpr.AsAlias(seq.args) ?? expr; } else { item = expr; } lst[i] = item; } var res = new SqlSectionExpr(sectionName, lst); return(res); default: return(this); } }
static IList <Expr> RestructAsSqlSelect(IList <Expr> lst) { var seq = lst[0] as SequenceExpr; if (seq == null) { return(lst); } var ref0 = (seq.args.Count > 0) ? seq.args[0] as ReferenceExpr : null; if (ref0 == null || string.Compare(ref0.name, "SELECT", StringComparison.InvariantCultureIgnoreCase) != 0) { return(lst); } string sectionName = null; string sectionPartialName = string.Empty; var res = new List <Expr>(lst.Count); var sectionItems = new List <Expr>(lst.Count); foreach (var item in lst) { var se = item as SequenceExpr; if (se == null) { se = new SequenceExpr(item); } var argItems = new List <Expr>(); foreach (var exprArg in se.args) { var expr = exprArg; var r = expr as ReferenceExpr; CallExpr ce = null; if (r == null) { ce = expr as CallExpr; if (ce != null && ce.funcName.Length > 0) { r = new ReferenceExpr(ce.funcName); } } if (r != null) { var s = r.name.ToUpperInvariant(); switch (s) { case "SELECT": case "FROM": case "WHERE": case "BY": case "USING": if (argItems.Count > 0) { moveArgsToSection(sectionName, sectionItems, argItems); } if (sectionName != null) { var after = new SqlSectionExpr(sectionName, sectionItems.ToArray()).Postprocess(); if (after == null) { return(null); } res.Add(after); } else if (sectionItems.Count > 0) { res.AddRange(sectionItems); } sectionItems.Clear(); if (s == "BY") { sectionName = sectionPartialName + ' ' + s; sectionPartialName = string.Empty; } else { System.Diagnostics.Trace.Assert(sectionPartialName.Length == 0, "Unknown SQL clause"); sectionName = s; } break; case "JOIN": { System.Diagnostics.Trace.Assert(argItems.Count > 0, "No expressions before JOIN"); var ae = AliasExpr.AsAlias(argItems); if (ae != null) { argItems.Clear(); argItems.Add(ae); } if (sectionPartialName.Length > 0) { argItems.Add(new ReferenceExpr(sectionPartialName)); } argItems.Add(new ReferenceExpr(s)); if (ae == null) { var tmp = new SequenceExpr(argItems.ToArray()); argItems.Clear(); argItems.Add(tmp); } sectionPartialName = string.Empty; } break; case "ON": { int i = argItems.Count - 1; var subseq = new List <Expr>(); while (i >= 0) { var exp = argItems[i]; var re = exp as ReferenceExpr; if (re != null && re.name == "JOIN") { break; } argItems.RemoveAt(i); i--; subseq.Insert(0, exp); } if (subseq.Count > 0) { argItems.Add((Expr)AliasExpr.AsAlias(subseq) ?? new SequenceExpr(subseq)); } argItems.Add(new ReferenceExpr(s)); } break; case "ORDER": case "GROUP": case "INNER": case "OUTER": case "LEFT": case "RIGHT": case "CROSS": case "FULL": if (sectionPartialName.Length == 0) { sectionPartialName = s; } else { sectionPartialName += ' ' + s; } break; default: if (ce == null) { argItems.Add(r); } r = null; break; } if (ce == null) { continue; } if (r != null) { expr = new CallExpr(string.Empty, ce.args); ce = null; } } if (ce != null && ce.funcName == string.Empty) { // no need to modify possible aliases in nested queries var items = RestructAsSqlSelect(ce.args); if (items != ce.args) { argItems.Add(CallExpr.Eval(new SequenceExpr(items))); } } else { argItems.Add(expr); } } moveArgsToSection(sectionName, sectionItems, argItems); } if (sectionName != null) { var after = new SqlSectionExpr(sectionName, sectionItems.ToArray()).Postprocess(); if (after == null) { return(null); } res.Add(after); } else if (sectionItems.Count > 0) { res.AddRange(sectionItems); } return(res.ToArray()); }
public Expr CreateQueryExpr(Expr andCondition = null, AliasExpr groupBy = null, Expr[] orderBy = null, Func <AliasExpr, AliasExpr> resultModifier = null, params string[] resultsNames) { var sections = new List <Expr>(args.Count); // select Expr[] toSelect; var gba = (groupBy == null) ? null : groupBy.alias; // "group by" preprocessing Expr newGroupBySection; Dictionary <string, bool> presentInGroupBy = null; { var currGroupBy = this[SqlSectionExpr.Kind.GroupBy]; if (currGroupBy != null) { newGroupBySection = currGroupBy; presentInGroupBy = GetPresenseDict(currGroupBy.args); } else if (groupBy != null) { newGroupBySection = new SqlSectionExpr(SqlSectionExpr.Kind.GroupBy, groupBy.expr); presentInGroupBy = GetPresenseDict(new Expr[] { groupBy }); } else { newGroupBySection = null; } } // "select" bool resultsModified = false; if (resultsNames.Length == 0) { if (resultModifier != null) { toSelect = new Expr[results.Length]; for (int i = toSelect.Length - 1; i >= 0; i--) { var r = results[i]; var s = IsGroupedBy(presentInGroupBy, r) ? r : resultModifier(r); if (r != s) { resultsModified = true; } toSelect[i] = s; } } else { toSelect = results; } } else { resultModifier = resultModifier ?? AsIs; toSelect = new Expr[resultsNames.Length]; resultsModified = true; for (int i = toSelect.Length - 1; i >= 0; i--) { var r = results[resNdx[resultsNames[i]]]; toSelect[i] = IsGroupedBy(presentInGroupBy, r) ? r : resultModifier(r); } } if (resultsModified) { sections.Add(new SqlSectionExpr(SqlSectionExpr.Kind.Select, toSelect)); } else { sections.Add(this[SqlSectionExpr.Kind.Select]); } // from sections.Add(this[SqlSectionExpr.Kind.From]); // where if (andCondition != null) { sections.Add(new SqlSectionExpr(SqlSectionExpr.Kind.Where, (condition == null) ? andCondition : new BinaryExpr(ExprType.LogicalAnd, condition, andCondition))); } else if (condition != null) { sections.Add(this[SqlSectionExpr.Kind.Where]); } // group by if (newGroupBySection != null) { sections.Add(newGroupBySection); } // order by var thisOrderBy = this[SqlSectionExpr.Kind.OrderBy]; if (orderBy != null && orderBy.Length > 0) { if (thisOrderBy != null) { var fromQuery = thisOrderBy.args.Where(e => { var s = e.ToString(); return(presentInGroupBy == null || presentInGroupBy.ContainsKey(s)); }).ToArray(); var presentInOrderBy = GetPresenseDict(fromQuery); orderBy = fromQuery.Concat(orderBy.Where(e => { var s = e.ToString(); return(!presentInOrderBy.ContainsKey(s)); })).ToArray(); } sections.Add(new SqlSectionExpr(SqlSectionExpr.Kind.OrderBy, orderBy)); } else if (thisOrderBy != null) { sections.Add(this[SqlSectionExpr.Kind.OrderBy]); } //for (int i = 3; i < sql.Length; i++) // if (sql[i] != null) // sections.Add(sql[i]); return(new SequenceExpr(sections)); // todo }
public SqlExpr(IList <Expr> sections, Options opts) : base(sections) { foreach (SqlSectionExpr s in sections) { sql[(int)s.kind] = s; } SqlSectionExpr section; // FROM: scan sources section = this[SqlSectionExpr.Kind.From]; if (section == null) { if (!opts.HasFlag(Options.EmptyFromPossible)) { throw new Generator.Exception($"new SqlExpr(...): nonempty FROM section expected"); } section = new SqlSectionExpr(SqlSectionExpr.Kind.From); } IDictionary <string, int> srcAlias2Ndx; { var items = section.args; var srcs = new List <AliasExpr>(items.Count); srcAlias2Ndx = new Dictionary <string, int>(items.Count, StringComparer.OrdinalIgnoreCase); int i = 0; foreach (var item in items) { var ae = item as AliasExpr; if (ae != null) { srcAlias2Ndx[ae.alias] = i++; srcs.Add(ae); continue; } var sq = item as SequenceExpr; if (sq != null) { foreach (var it in sq.args) { var tmp = it as AliasExpr; if (tmp != null) { srcAlias2Ndx[tmp.alias] = i++; srcs.Add(tmp); } } } else { var tmp = new AliasExpr(item, item); srcAlias2Ndx[tmp.alias] = i++; srcs.Add(tmp); } } //System.Diagnostics.Trace.Assert(i <= 32, "No more than 32 sources in FROM supported"); sources = srcs.ToArray(); } // SELECT: scan results section = this[SqlSectionExpr.Kind.Select]; { var items = section.args; int n = items.Count; //System.Diagnostics.Trace.Assert(n <= 64, "No more than 64 result columns in SELECT supported"); results = new AliasExpr[n]; resFields = new Expr[n]; resNdx = new Dictionary <string, int>(n, StringComparer.OrdinalIgnoreCase); //resultUsesSrcs = new uint[n]; for (int i = 0; i < n; i++) { var aliasExpr = items[i] as AliasExpr; if (aliasExpr != null) { // item in form "expression alias" Expr resField = null; foreach (var srcAlias in aliasExpr.expr.Traverse <BinaryExpr>(e => { var be = e as BinaryExpr; if (be != null && be.nodeType == ExprType.Fluent) { return(be); } else { return(null); } })) { if (srcAlias == null) { continue; } int j; if (srcAlias2Ndx.TryGetValue(srcAlias.left.ToString(), out j)) // source alias may be to the left of point { //resultUsesSrcs[i] |= (uint)(1 << j); resField = srcAlias; } } //System.Diagnostics.Trace.Assert(resField != null, "No field reference found"); resFields[i] = resField ?? aliasExpr.expr; results[i] = aliasExpr; resNdx.Add(aliasExpr.alias, i); continue; } var binExpr = items[i] as BinaryExpr; if (binExpr != null) { if (binExpr.nodeType == ExprType.Fluent) { // item in form "tablename.fieldname" resFields[i] = binExpr; results[i] = new AliasExpr(binExpr, binExpr.right); resNdx.Add(binExpr.right.ToString(), i); continue; } } else { var tmp = items[i] as ReferenceExpr; if (tmp != null) { // item in form "fieldname" resFields[i] = tmp; results[i] = new AliasExpr(tmp, tmp); resNdx.Add(tmp.ToString(), i); continue; } } throw new ArgumentException("SELECTed expression must be a simple field reference or have alias", items[i].ToString()); } } // WHERE: scan conditions section = this[SqlSectionExpr.Kind.Where]; if (section != null) { var items = section.args; System.Diagnostics.Trace.Assert(items.Count == 1, "Only one condition expression in WHERE supported"); condition = items[0]; } }