private ColumnProjector(QueryLanguage language, Expression expression, IEnumerable <ColumnDeclaration> existingColumns, TableAlias newAlias, IEnumerable <TableAlias> existingAliases) { this.language = language; this.newAlias = newAlias; this.existingAliases = new HashSet <TableAlias>(existingAliases); map = new Dictionary <ColumnExpression, ColumnExpression>(); if (existingColumns != null) { columns = new List <ColumnDeclaration>(existingColumns); columnNames = new HashSet <string>(existingColumns.Select(c => c.Name)); } else { columns = new List <ColumnDeclaration>(); columnNames = new HashSet <string>(); } candidates = Nominator.Nominate(language, expression); }
protected override Expression VisitProjection(ProjectionExpression proj) { if (isTopLevel) { isTopLevel = false; currentSelect = proj.Select; Expression projector = Visit(proj.Projector); if (projector != proj.Projector || currentSelect != proj.Select) { return(new ProjectionExpression(currentSelect, projector, proj.Aggregator)); } return(proj); } if (proj.IsSingleton && CanJoinOnServer(currentSelect)) { var newAlias = new TableAlias(); currentSelect = currentSelect.AddRedundantSelect(language, newAlias); // remap any references to the outer select to the new alias; var source = (SelectExpression)ColumnMapper.Map(proj.Select, newAlias, currentSelect.Alias); // add outer-join test ProjectionExpression pex = language.AddOuterJoinTest(new ProjectionExpression(source, proj.Projector)); ProjectedColumns pc = ColumnProjector.ProjectColumns(language, pex.Projector, currentSelect.Columns, currentSelect.Alias, newAlias, proj.Select.Alias); var join = new JoinExpression(JoinType.OuterApply, currentSelect.From, pex.Select, null); currentSelect = new SelectExpression(currentSelect.Alias, pc.Columns, join, null); return(Visit(pc.Projector)); } bool saveTop = isTopLevel; SelectExpression saveSelect = currentSelect; isTopLevel = true; currentSelect = null; Expression result = base.VisitProjection(proj); isTopLevel = saveTop; currentSelect = saveSelect; return(result); }
private Expression MakeSubquery(Expression expression) { var newAlias = new TableAlias(); HashSet <TableAlias> aliases = DeclaredAliasGatherer.Gather(expression); var decls = new List <ColumnDeclaration>(); foreach (TableAlias ta in aliases) { foreach (ColumnExpression col in columns[ta]) { string name = decls.GetAvailableColumnName(col.Name); var decl = new ColumnDeclaration(name, col, col.QueryType); decls.Add(decl); var newCol = new ColumnExpression(col.Type, col.QueryType, newAlias, col.Name); map.Add(col, newCol); } } return(new SelectExpression(newAlias, decls, expression, null)); }
protected override Expression VisitSelect(SelectExpression select) { select = (SelectExpression)base.VisitSelect(select); if (select.Skip != null) { SelectExpression newSelect = select.SetSkip(null).SetTake(null); bool canAddColumn = !select.IsDistinct && (select.GroupBy == null || select.GroupBy.Count == 0); if (!canAddColumn) { newSelect = newSelect.AddRedundantSelect(language, new TableAlias()); } QueryType colType = language.TypeSystem.GetColumnType(typeof(int)); newSelect = newSelect.AddColumn(new ColumnDeclaration("_rownum", new RowNumberExpression(select.OrderBy), colType)); // add layer for WHERE clause that references new rownum column newSelect = newSelect.AddRedundantSelect(language, new TableAlias()); newSelect = newSelect.RemoveColumn(newSelect.Columns.Single(c => c.Name == "_rownum")); TableAlias newAlias = ((SelectExpression)newSelect.From).Alias; var rnCol = new ColumnExpression(typeof(int), colType, newAlias, "_rownum"); Expression where; if (select.Take != null) { where = new BetweenExpression(rnCol, Expression.Add(select.Skip, Expression.Constant(1)), Expression.Add(select.Skip, select.Take)); } else { where = rnCol.GreaterThan(select.Skip); } if (newSelect.Where != null) { where = newSelect.Where.And(where); } newSelect = newSelect.SetWhere(where); select = newSelect; } return(select); }
private void ClearColumnsUsed(TableAlias alias) { allColumnsUsed[alias] = new HashSet <string>(); }
public TableExpression(TableAlias alias, EntryMapping entry, string name) : base(DbExpressionType.Table, typeof(void), alias) { this.entry = entry; this.name = name; }
protected AliasedExpression(DbExpressionType nodeType, Type type, TableAlias alias) : base(nodeType, type) { this.alias = alias; }
public static Expression Map(Expression expression, TableAlias newAlias, IEnumerable <TableAlias> oldAliases) { return(new ColumnMapper(oldAliases, newAlias).Visit(expression)); }
public SelectExpression(TableAlias alias, IEnumerable <ColumnDeclaration> columns, Expression from, Expression where, IEnumerable <OrderExpression> orderBy, IEnumerable <Expression> groupBy) : this(alias, columns, from, where, orderBy, groupBy, false, null, null, false) { }
public static SelectExpression AddRedundantSelect(this SelectExpression sel, QueryLanguage language, TableAlias newAlias) { IEnumerable <ColumnDeclaration> newColumns = from d in sel.Columns let qt = (d.Expression is ColumnExpression) ? ((ColumnExpression)d.Expression).QueryType : language.TypeSystem.GetColumnType(d.Expression.Type) select new ColumnDeclaration(d.Name, new ColumnExpression(d.Expression.Type, qt, newAlias, d.Name), qt); var newFrom = new SelectExpression(newAlias, sel.Columns, sel.From, sel.Where, sel.OrderBy, sel.GroupBy, sel.IsDistinct, sel.Skip, sel.Take, sel.IsReverse); return(new SelectExpression(sel.Alias, newColumns, newFrom, null, null, null, false, null, null, false)); }
protected override Expression VisitProjection(ProjectionExpression proj) { SelectExpression save = currentSelect; currentSelect = proj.Select; try { if (!isTopLevel) { if (CanJoinOnClient(currentSelect)) { // make a query that combines all the constraints from the outer queries into a single select var newOuterSelect = (SelectExpression)QueryDuplicator.Duplicate(save); // remap any references to the outer select to the new alias; var newInnerSelect = (SelectExpression)ColumnMapper.Map(proj.Select, newOuterSelect.Alias, save.Alias); // add outer-join test ProjectionExpression newInnerProjection = language.AddOuterJoinTest(new ProjectionExpression(newInnerSelect, proj.Projector)); newInnerSelect = newInnerProjection.Select; Expression newProjector = newInnerProjection.Projector; var newAlias = new TableAlias(); ProjectedColumns pc = ColumnProjector.ProjectColumns(language, newProjector, null, newAlias, newOuterSelect.Alias, newInnerSelect.Alias); var join = new JoinExpression(JoinType.OuterApply, newOuterSelect, newInnerSelect, null); var joinedSelect = new SelectExpression(newAlias, pc.Columns, join, null, null, null, proj.IsSingleton, null, null, false); // apply client-join treatment recursively currentSelect = joinedSelect; newProjector = Visit(pc.Projector); // compute keys (this only works if join condition was a single column comparison) var outerKeys = new List <Expression>(); var innerKeys = new List <Expression>(); if (GetEquiJoinKeyExpressions(newInnerSelect.Where, newOuterSelect.Alias, outerKeys, innerKeys)) { // outerKey needs to refer to the outer-scope's alias IEnumerable <Expression> outerKey = outerKeys.Select(k => ColumnMapper.Map(k, save.Alias, newOuterSelect.Alias)); // innerKey needs to refer to the new alias for the select with the new join IEnumerable <Expression> innerKey = innerKeys.Select(k => ColumnMapper.Map(k, joinedSelect.Alias, ((ColumnExpression)k).Alias)); var newProjection = new ProjectionExpression(joinedSelect, newProjector, proj.Aggregator); return(new ClientJoinExpression(newProjection, outerKey, innerKey)); } } else { bool saveJoin = canJoinOnClient; canJoinOnClient = false; Expression result = base.VisitProjection(proj); canJoinOnClient = saveJoin; return(result); } } else { isTopLevel = false; } return(base.VisitProjection(proj)); } finally { currentSelect = save; } }
/// <summary> /// Rebind order expressions to reference a new alias and add to column declarations if necessary /// </summary> protected virtual BindResult RebindOrderings(IEnumerable <OrderExpression> orderings, TableAlias alias, HashSet <TableAlias> existingAliases, IEnumerable <ColumnDeclaration> existingColumns) { List <ColumnDeclaration> newColumns = null; var newOrderings = new List <OrderExpression>(); foreach (OrderExpression ordering in orderings) { Expression expr = ordering.Expression; var column = expr as ColumnExpression; if (column == null || (existingAliases != null && existingAliases.Contains(column.Alias))) { // check to see if a declared column already contains a similar expression int iOrdinal = 0; foreach (ColumnDeclaration decl in existingColumns) { var declColumn = decl.Expression as ColumnExpression; if (decl.Expression == ordering.Expression || (column != null && declColumn != null && column.Alias == declColumn.Alias && column.Name == declColumn.Name)) { // found it, so make a reference to this column expr = new ColumnExpression(column.Type, column.QueryType, alias, decl.Name); break; } iOrdinal++; } // if not already projected, add a new column declaration for it if (expr == ordering.Expression) { if (newColumns == null) { newColumns = new List <ColumnDeclaration>(existingColumns); existingColumns = newColumns; } string colName = column != null ? column.Name : "c" + iOrdinal; colName = newColumns.GetAvailableColumnName(colName); QueryType colType; if (ordering.Expression is ConstantExpression && (ordering.Expression as ConstantExpression).Value == null) { colType = language.TypeSystem.GetColumnType(typeof(int)); newColumns.Add(new ColumnDeclaration(colName, Expression.Constant(1, typeof(int)), colType)); } else { colType = language.TypeSystem.GetColumnType(expr.Type); newColumns.Add(new ColumnDeclaration(colName, ordering.Expression, colType)); } expr = new ColumnExpression(expr.Type, colType, alias, colName); } newOrderings.Add(new OrderExpression(ordering.OrderType, expr)); } } return(new BindResult(existingColumns, newOrderings)); }
public static Expression Map(Expression expression, TableAlias newAlias, params TableAlias[] oldAliases) { return(Map(expression, newAlias, (IEnumerable <TableAlias>)oldAliases)); }
public static ProjectedColumns ProjectColumns(QueryLanguage language, Expression expression, IEnumerable <ColumnDeclaration> existingColumns, TableAlias newAlias, IEnumerable <TableAlias> existingAliases) { var projector = new ColumnProjector(language, expression, existingColumns, newAlias, existingAliases); Expression expr = projector.Visit(expression); return(new ProjectedColumns(expr, projector.columns.AsReadOnly())); }
public SelectExpression(TableAlias alias, IEnumerable <ColumnDeclaration> columns, Expression from, Expression where) : this(alias, columns, from, where, null, null) { }
public static ProjectedColumns ProjectColumns(QueryLanguage language, Expression expression, IEnumerable <ColumnDeclaration> existingColumns, TableAlias newAlias, params TableAlias[] existingAliases) { return(ProjectColumns(language, expression, existingColumns, newAlias, (IEnumerable <TableAlias>)existingAliases)); }
private ColumnMapper(IEnumerable <TableAlias> oldAliases, TableAlias newAlias) { this.oldAliases = new HashSet <TableAlias>(oldAliases); this.newAlias = newAlias; }