protected InputFragment VisitInputExpression(DbExpression e, string name, TypeUsage type) { SqlFragment f = e.Accept(this); Debug.Assert(f is InputFragment); InputFragment inputFragment = f as InputFragment; inputFragment.Name = name; TryFusingSelect(inputFragment); if (inputFragment is TableFragment && type != null) { (inputFragment as TableFragment).Type = type; } SelectStatement select = inputFragment as SelectStatement; if ((select != null) && (select.From is TableFragment)) { (select.From as TableFragment).Type = type; } if (name != null) { scope.Add(name, inputFragment); } return(inputFragment); }
internal void AddColumn(ColumnFragment column, Scope scope) { InputFragment input = scope.FindInputFromProperties(column.PropertyFragment); column.TableName = input.Name; // then we rename the column if necessary if (columnHash.ContainsKey(column.ColumnName.ToUpper())) { column.ColumnAlias = MakeColumnNameUnique(column.ColumnName); columnHash.Add(column.ColumnAlias, column); } else { if (!string.IsNullOrEmpty(column.ColumnAlias)) { columnHash.Add(column.ColumnAlias.ToUpper(), column); } else { columnHash.Add(column.ColumnName.ToUpper(), column); } } Columns.Add(column); }
public InputFragment FindInputFromProperties(PropertyFragment fragment) { Debug.Assert(fragment != null); PropertyFragment propertyFragment = fragment as PropertyFragment; Debug.Assert(propertyFragment != null); if (propertyFragment.Properties.Count >= 2) { for (int x = propertyFragment.Properties.Count - 2; x >= 0; x--) { string reference = propertyFragment.Properties[x]; if (reference == null) { continue; } InputFragment input = GetFragment(reference); if (input == null) { continue; } if (input.Scoped) { return(input); } if (input is SelectStatement) { return((input as SelectStatement).From); } continue; } } Debug.Fail("Should have found an input"); return(null); }
public void Remove(string Name, InputFragment fragment) { if (fragment == null) { return; } if (Name != null) { scopeTable.Remove(Name); } if (fragment is SelectStatement) { Remove((fragment as SelectStatement).From); } else if (fragment is JoinFragment) { JoinFragment j = fragment as JoinFragment; Remove(j.Left); Remove(j.Right); } else if (fragment is UnionFragment) { UnionFragment u = fragment as UnionFragment; Remove(u.Left); Remove(u.Right); } }
public void Remove(InputFragment fragment) { if (fragment == null) { return; } Remove(fragment.Name, fragment); }
/// <summary> /// If current fragment is select and its from clause is another select, try fuse the inner select with the outer select. /// (Thus removing a nested query, which may have bad performance in Mysql). /// </summary> /// <param name="f">The fragment to probe and posibly optimize</param> /// <returns>The fragment fused, or the original one.</returns> protected internal InputFragment TryFusingSelect(InputFragment f) { SelectStatement result = f as SelectStatement; if (!CanFuseSelect(f as SelectStatement)) { return(f); } result = FuseSelectWithInnerSelect(result, result.From as SelectStatement); return(result); }
private InputFragment WrapJoinInputIfNecessary(InputFragment fragment, bool isRightPart) { if (fragment is SelectStatement || fragment is UnionFragment) { fragment.Wrap(scope); fragment.Scoped = true; } else if (fragment is JoinFragment && isRightPart) { SelectStatement select = new SelectStatement(this); select.From = fragment; select.Name = fragment.Name; select.Wrap(scope); return(select); } return(fragment); }
private SelectStatement VisitInputExpressionEnsureSelect(DbExpression e, string name, TypeUsage type) { InputFragment fragment = VisitInputExpression(e, name, type); if (fragment is SelectStatement) { return(fragment as SelectStatement); } SelectStatement s = new SelectStatement(this); // if the fragment is a union then it needs to be wrapped if (fragment is UnionFragment) { (fragment as UnionFragment).Wrap(scope); } s.From = fragment; return(s); }
void AddDefaultColumns(Scope scope) { if (columnHash == null) { columnHash = new Dictionary <string, ColumnFragment>(); } List <ColumnFragment> columns = GetDefaultColumnsForFragment(From); bool Exists = false; if (From is TableFragment && scope.GetFragment((From as TableFragment).Table) == null) { scope.Add((From as TableFragment).Table, From); Exists = true; } foreach (ColumnFragment column in columns) { // first we need to set the input for this column InputFragment input = scope.FindInputFromProperties(column.PropertyFragment); column.TableName = input.Name; // then we rename the column if necessary if (columnHash.ContainsKey(column.ColumnName.ToUpper())) { column.ColumnAlias = MakeColumnNameUnique(column.ColumnName); columnHash.Add(column.ColumnAlias, column); } else { columnHash.Add(column.ColumnName.ToUpper(), column); } Columns.Add(column); } if (Exists) { scope.Remove((From as TableFragment).Table, From); } }
List <ColumnFragment> GetDefaultColumnsForFragment(InputFragment input) { List <ColumnFragment> columns = new List <ColumnFragment>(); if (input is TableFragment) { return(GetDefaultColumnsForTable(input as TableFragment)); } else if (input is JoinFragment || input is UnionFragment) { Debug.Assert(input.Left != null); if (input is UnionFragment) { generator.Ops.Push(OpType.Union); } columns = GetDefaultColumnsForFragment(input.Left); if (input is JoinFragment && input.Right != null) { List <ColumnFragment> right = GetDefaultColumnsForFragment(input.Right); columns.AddRange(right); } if (input is UnionFragment) { generator.Ops.Pop(); } } else if (input is SelectStatement) { SelectStatement select = input as SelectStatement; foreach (ColumnFragment cf in select.Columns) { ColumnFragment newColumn = new ColumnFragment(cf.TableName, string.IsNullOrEmpty(cf.ColumnAlias) ? cf.ActualColumnName : cf.ColumnAlias ); if (generator.GetTopOp() == OpType.Join) { newColumn.ColumnAlias = cf.ColumnAlias; newColumn.PushInput(cf.ColumnName); if (cf.TableName != null) { newColumn.PushInput(cf.TableName); } } else { newColumn.PushInput(cf.ActualColumnName); if (cf.TableName != null && cf.ColumnAlias == null) { newColumn.PushInput(cf.TableName); } } if (select.Name != null) { newColumn.PushInput(select.Name); // add the scope } columns.Add(newColumn); } return(columns); } else { throw new NotImplementedException(); } if (!String.IsNullOrEmpty(input.Name) && input.Name != From.Name) { foreach (ColumnFragment c in columns) { c.PushInput(input.Name); } } return(columns); }
public override SqlFragment Visit(DbPropertyExpression expression) { propertyLevel++; PropertyFragment fragment = expression.Instance.Accept(this) as PropertyFragment; fragment.Properties.Add(expression.Property.Name); propertyLevel--; // if we are not at the top level property then just return if (propertyLevel > 0) { return(fragment); } ColumnFragment column = new ColumnFragment(null, fragment.LastProperty); column.PropertyFragment = fragment; InputFragment input = scope.FindInputFromProperties(fragment); if (input != null) { column.TableName = input.Name; } // now we need to check if our column name was possibly renamed if (input is TableFragment) { if (!string.IsNullOrEmpty(input.Name)) { SelectStatement sf = scope.GetFragment(input.Name) as SelectStatement; if (sf != null) { // Special case: undo alias in case of query fusing for (int i = 0; i < sf.Columns.Count; i++) { ColumnFragment cf = sf.Columns[i]; if (column.ColumnName == cf.ColumnAlias) { column.ColumnName = cf.ColumnName; column.ColumnAlias = cf.ColumnAlias; column.TableName = input.Name; return(column); } } } } return(column); } SelectStatement select = input as SelectStatement; UnionFragment union = input as UnionFragment; if (select != null) { select.HasDifferentNameForColumn(column); } else if (union != null) { union.HasDifferentNameForColumn(column); } // input is a table, selectstatement, or unionstatement return(column); }
public void Add(string name, InputFragment fragment) { scopeTable.Add(name, fragment); }
/// <summary> /// If input sqlFragment is a group by structure, is flattened to remove some nested correlation queries. /// </summary> /// <param name="input"></param> /// <returns></returns> private SqlFragment TryFlatteningGroupBy(SqlFragment input) { SelectStatement select = null; SelectStatement tmpFrag = null, tmpFrag2 = null, tmpFrag3 = null; InputFragment table = null; string objName = null, colName = null, queryName = null; // First part assert is a kind-of structure we are looking for tmpFrag = input as SelectStatement; if (tmpFrag == null) { goto NoChanges; } tmpFrag = (tmpFrag).From as SelectStatement; if (tmpFrag == null) { goto NoChanges; } queryName = tmpFrag.Name; if (tmpFrag.Columns.Count < 2) { goto NoChanges; } if (!(tmpFrag.Columns[0] is ColumnFragment)) { goto NoChanges; } colName = objName = (tmpFrag.Columns[0] as ColumnFragment).ActualColumnName; tmpFrag2 = tmpFrag.From as SelectStatement; if (tmpFrag2 == null) { goto NoChanges; } if (tmpFrag2.Columns.Count < 1 || !(tmpFrag2.Columns[0] is ColumnFragment)) { goto NoChanges; } if (string.CompareOrdinal(objName, tmpFrag2.Columns[0].ActualColumnName) != 0) { goto NoChanges; } if (tmpFrag.Columns[1].Literal == null) { goto NoChanges; } tmpFrag2 = tmpFrag.Columns[1].Literal as SelectStatement; if (tmpFrag2 == null) { goto NoChanges; } if ((tmpFrag2.Columns.Count != 1) || !(tmpFrag2.Columns[0].Literal != null)) { goto NoChanges; } tmpFrag3 = tmpFrag2.From as SelectStatement; if (tmpFrag3 == null) { goto NoChanges; } table = tmpFrag3.From as InputFragment; if (table == null) { goto NoChanges; } FunctionFragment func = tmpFrag2.Columns[0].Literal as FunctionFragment; if (tmpFrag3.Columns.Count != 1 || !(tmpFrag3.Columns[0] is ColumnFragment)) { goto NoChanges; } if (func == null) { goto NoChanges; } // Yes it is the kind-of type we like, then optimize it select = new SelectStatement(this); table.Name = null; string tableName = null; TableFragment t = tmpFrag3.From as TableFragment; if (t == null) { tableName = tmpFrag3.Columns[0].TableName; } else { tableName = t.Table; } select.From = table; select.Columns.Add(new ColumnFragment(tableName, colName)); select.Columns.Add(new ColumnFragment(tableName, "C0") { ColumnAlias = "C1", Literal = new FunctionFragment() { Argument = new ColumnFragment(tableName, tmpFrag3.Columns[0].ActualColumnName), Distinct = tmpFrag3.IsDistinct, Name = func.Name } }); select.Wrap(null); select.Name = queryName; select.AddGroupBy(select.Columns[0]); (input as SelectStatement).From = select; NoChanges: return(input); }
public override SqlFragment Visit(DbApplyExpression expression) { DbExpressionBinding inputBinding = expression.Input; InputFragment input = VisitInputExpression(inputBinding.Expression, inputBinding.VariableName, inputBinding.VariableType); DbExpressionBinding applyBinding = expression.Apply; InputFragment apply = VisitInputExpression(applyBinding.Expression, applyBinding.VariableName, applyBinding.VariableType); SelectStatement select = new SelectStatement(this); bool isInputSelect = false; if (!(input is TableFragment)) { input.Wrap(scope); isInputSelect = true; } apply.Wrap(scope); select.From = input; select.Wrap(scope); if (apply is SelectStatement) { SelectStatement applySel = apply as SelectStatement; foreach (ColumnFragment f in applySel.Columns) { SelectStatement newColSelect = new SelectStatement(this); newColSelect.From = applySel.From; newColSelect.Where = applySel.Where; if (isInputSelect) { VisitAndReplaceTableName(newColSelect.Where, (input as SelectStatement).From.Name, input.Name, null); } newColSelect.Limit = applySel.Limit; newColSelect.OrderBy = applySel.OrderBy; newColSelect.Skip = applySel.Skip; newColSelect.GroupBy = applySel.GroupBy; newColSelect.IsDistinct = applySel.IsDistinct; newColSelect.Columns.Add(f); newColSelect.Wrap(scope); scope.Add(applySel.From.Name, applySel.From); ColumnFragment newCol = new ColumnFragment(apply.Name, f.ColumnName); newCol.Literal = newColSelect; newCol.PushInput(newCol.ColumnName); newCol.PushInput(apply.Name); select.AddColumn(newCol, scope); if (string.IsNullOrEmpty(newCol.ColumnAlias)) { newColSelect.Name = newCol.ColumnName; newCol.ColumnAlias = newCol.ColumnName; } scope.Remove(newColSelect); } scope.Remove(applySel.From); scope.Remove(apply); } else if (apply is UnionFragment) { UnionFragment uf = apply as UnionFragment; if (uf.Left == null || uf.Right == null) { throw new Exception("Union fragment is not properly formed."); } var left = uf.Left as SelectStatement; var right = uf.Right as SelectStatement; if (left == null || right == null) { throw new NotImplementedException(); } var whereleft = left.Where as BinaryFragment; var whereright = right.Where as BinaryFragment; if (whereleft == null || whereright == null) { throw new NotImplementedException(); } LiteralFragment literalFragmentWhere = null; //checking where left if (whereleft.Left is ColumnFragment && whereleft.Right is ColumnFragment) { // we replace the where part for a dummy one if (whereright.Left is ColumnFragment && whereright.Right is ColumnFragment) { literalFragmentWhere = new LiteralFragment("1 = 1"); } } if (literalFragmentWhere == null) { throw new NotImplementedException(); } var leftouterjoin = new JoinFragment(); leftouterjoin.JoinType = Metadata.GetOperator(DbExpressionKind.LeftOuterJoin); leftouterjoin.Name = apply.Name; // validating that column fragment on the left matches the name // for the input fragment var leftColumnFragment = whereleft.Left as ColumnFragment; if (leftColumnFragment == null) { throw new NotImplementedException(); } if (!leftColumnFragment.TableName.Equals(input.Name)) { new NotImplementedException(); } var conditionJoin = new BinaryFragment(); conditionJoin.Left = whereleft.Left; //update to the new reference var newColumnFragment = whereright.Right as ColumnFragment; if (newColumnFragment != null) { newColumnFragment.TableName = uf.Name; } conditionJoin.Right = newColumnFragment; conditionJoin.Operator = whereleft.Operator; leftouterjoin.Condition = conditionJoin; (uf.Left as SelectStatement).Where = literalFragmentWhere; (uf.Right as SelectStatement).Where = literalFragmentWhere; leftouterjoin.Left = input; leftouterjoin.Right = uf; return(leftouterjoin); } return(select); }