private bool GetEquiJoinKeyExpressions(Expression predicate, TableAlias outerAlias, List <Expression> outerExpressions, List <Expression> innerExpressions) { if (predicate.NodeType == ExpressionType.Equal) { var b = (BinaryExpression)predicate; ColumnExpression leftCol = this.GetColumnExpression(b.Left); ColumnExpression rightCol = this.GetColumnExpression(b.Right); if (leftCol != null && rightCol != null) { if (leftCol.Alias == outerAlias) { outerExpressions.Add(b.Left); innerExpressions.Add(b.Right); return(true); } else if (rightCol.Alias == outerAlias) { innerExpressions.Add(b.Left); outerExpressions.Add(b.Right); return(true); } } } bool hadKey = false; var parts = predicate.Split(ExpressionType.And, ExpressionType.AndAlso); if (parts.Length > 1) { foreach (var part in parts) { bool hasOuterAliasReference = ReferencedAliasGatherer.Gather(part).Contains(outerAlias); if (hasOuterAliasReference) { if (!GetEquiJoinKeyExpressions(part, outerAlias, outerExpressions, innerExpressions)) { return(false); } hadKey = true; } } } return(hadKey); }
protected override Expression VisitProjection(ProjectionExpression proj) { if (isTopLevel) { isTopLevel = false; this.currentSelect = proj.Select; Expression projector = this.Visit(proj.Projector); if (projector != proj.Projector || this.currentSelect != proj.Select) { return(new ProjectionExpression(this.currentSelect, projector, proj.Aggregator)); } return(proj); } if (proj.IsSingleton && this.CanJoinOnServer(this.currentSelect)) { TableAlias newAlias = new TableAlias(); this.currentSelect = this.currentSelect.AddRedundantSelect(this.language, newAlias); // remap any references to the outer select to the new alias; SelectExpression source = (SelectExpression)ColumnMapper.Map(proj.Select, newAlias, this.currentSelect.Alias); // add outer-join test ProjectionExpression pex = this.language.AddOuterJoinTest(new ProjectionExpression(source, proj.Projector)); var pc = ColumnProjector.ProjectColumns(this.language, pex.Projector, this.currentSelect.Columns, this.currentSelect.Alias, newAlias, proj.Select.Alias); JoinExpression join = new JoinExpression(JoinType.OuterApply, this.currentSelect.From, pex.Select, null); this.currentSelect = new SelectExpression(this.currentSelect.Alias, pc.Columns, join, null); return(this.Visit(pc.Projector)); } var saveTop = this.isTopLevel; var saveSelect = this.currentSelect; this.isTopLevel = true; this.currentSelect = null; Expression result = base.VisitProjection(proj); this.isTopLevel = saveTop; this.currentSelect = saveSelect; return(result); }
private Expression MakeSubquery(Expression expression) { var newAlias = new TableAlias(); var aliases = DeclaredAliasGatherer.Gather(expression); var decls = new List <ColumnDeclaration>(); foreach (var ta in aliases) { foreach (var col in this.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); this.map.Add(col, newCol); } } return(new SelectExpression(newAlias, decls, expression, null)); }
public SelectExpression( TableAlias alias, IEnumerable <ColumnDeclaration> columns, Expression from, Expression where, IEnumerable <OrderExpression> orderBy, IEnumerable <Expression> groupBy, bool isDistinct, Expression skip, Expression take, bool reverse ) : base(DbExpressionType.Select, typeof(void), alias) { this.columns = columns.ToReadOnly(); this.isDistinct = isDistinct; this.from = from; this.where = where; this.orderBy = orderBy.ToReadOnly(); this.groupBy = groupBy.ToReadOnly(); this.take = take; this.skip = skip; this.reverse = reverse; }
private void ClearColumnsUsed(TableAlias alias) { this.allColumnsUsed[alias] = new HashSet <string>(); }
public static SelectExpression AddRedundantSelect(this SelectExpression sel, QueryLanguage language, TableAlias newAlias) { var 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 AliasedExpression(DbExpressionType nodeType, Type type, TableAlias alias) : base(nodeType, type) { this.alias = alias; }
public TableExpression(TableAlias alias, MappingEntity entity, string name) : base(DbExpressionType.Table, typeof(void), alias) { this.entity = entity; this.name = name; }
protected override Expression VisitProjection(ProjectionExpression proj) { SelectExpression save = this.currentSelect; this.currentSelect = proj.Select; try { if (!this.isTopLevel) { if (this.CanJoinOnClient(this.currentSelect)) { // make a query that combines all the constraints from the outer queries into a single select SelectExpression newOuterSelect = (SelectExpression)QueryDuplicator.Duplicate(save); // remap any references to the outer select to the new alias; SelectExpression newInnerSelect = (SelectExpression)ColumnMapper.Map(proj.Select, newOuterSelect.Alias, save.Alias); // add outer-join test ProjectionExpression newInnerProjection = this.language.AddOuterJoinTest(new ProjectionExpression(newInnerSelect, proj.Projector)); newInnerSelect = newInnerProjection.Select; Expression newProjector = newInnerProjection.Projector; TableAlias newAlias = new TableAlias(); var pc = ColumnProjector.ProjectColumns(this.language, newProjector, null, newAlias, newOuterSelect.Alias, newInnerSelect.Alias); JoinExpression join = new JoinExpression(JoinType.OuterApply, newOuterSelect, newInnerSelect, null); SelectExpression joinedSelect = new SelectExpression(newAlias, pc.Columns, join, null, null, null, proj.IsSingleton, null, null, false); // apply client-join treatment recursively this.currentSelect = joinedSelect; newProjector = this.Visit(pc.Projector); // compute keys (this only works if join condition was a single column comparison) List <Expression> outerKeys = new List <Expression>(); List <Expression> innerKeys = new List <Expression>(); if (this.GetEquiJoinKeyExpressions(newInnerSelect.Where, newOuterSelect.Alias, outerKeys, innerKeys)) { // outerKey needs to refer to the outer-scope's alias var 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 var innerKey = innerKeys.Select(k => ColumnMapper.Map(k, joinedSelect.Alias, ((ColumnExpression)k).Alias)); ProjectionExpression newProjection = new ProjectionExpression(joinedSelect, newProjector, proj.Aggregator); return(new ClientJoinExpression(newProjection, outerKey, innerKey)); } } else { bool saveJoin = this.canJoinOnClient; this.canJoinOnClient = false; var result = base.VisitProjection(proj); this.canJoinOnClient = saveJoin; return(result); } } else { this.isTopLevel = false; } return(base.VisitProjection(proj)); } finally { this.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; List <OrderExpression> newOrderings = new List <OrderExpression>(); foreach (OrderExpression ordering in orderings) { Expression expr = ordering.Expression; ColumnExpression 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) { ColumnExpression 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); var colType = this.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)); }