protected override Expression VisitSelect(SqlSelectExpression selectExpression) { if (selectExpression.Skip != null) { var rowNumber = new SqlFunctionCallExpression(typeof(int), "ROW_NUMBER"); var over = new SqlOverExpression(rowNumber, selectExpression.OrderBy ?? new ReadOnlyList <Expression>(new [] { new SqlOrderByExpression(OrderType.Ascending, selectExpression.Columns[0].Expression) })); var additionalColumn = new SqlColumnDeclaration(RowColumnName, over); var newAlias = selectExpression.Alias + "INNER"; var innerColumns = new ReadOnlyList <SqlColumnDeclaration>(selectExpression.Columns.Select(c => c).Concat(new[] { additionalColumn })); var innerSelect = new SqlSelectExpression(selectExpression.Type, newAlias, innerColumns, selectExpression.From, selectExpression.Where, null, selectExpression.GroupBy, selectExpression.Distinct, null, null, selectExpression.ForUpdate); var outerColumns = selectExpression.Columns.Select(c => new SqlColumnDeclaration(c.Name, new SqlColumnExpression(c.Expression.Type, newAlias, c.Name))); Expression rowPredicate = Expression.GreaterThan(new SqlColumnExpression(typeof(int), newAlias, additionalColumn.Name), selectExpression.Skip); if (selectExpression.Take != null && !(selectExpression.Take is SqlTakeAllValueExpression)) { rowPredicate = Expression.And ( rowPredicate, Expression.LessThanOrEqual(new SqlColumnExpression(typeof(int), newAlias, additionalColumn.Name), Expression.Add(selectExpression.Skip, selectExpression.Take)) ); } return(new SqlSelectExpression(selectExpression.Type, selectExpression.Alias, outerColumns, innerSelect, rowPredicate, null, selectExpression.ForUpdate)); } return(base.VisitSelect(selectExpression)); }
protected override Expression VisitSelect(SqlSelectExpression select) { // Only consider aggregates in these locations if (this.hasAggregate) { return(select); } this.Visit(select.Where); if (this.hasAggregate) { return(select); } this.VisitExpressionList(select.OrderBy); if (this.hasAggregate) { return(select); } this.VisitColumnDeclarations(select.Columns); return(select); }
protected virtual void AppendLimit(SqlSelectExpression selectExpression) { if (selectExpression.Skip != null || selectExpression.Take != null) { this.Write(" LIMIT "); if (selectExpression.Skip == null) { this.Write("0"); } else { this.Visit(selectExpression.Skip); } if (selectExpression.Take != null) { this.Write(", "); this.Visit(selectExpression.Take); } else if (selectExpression.Skip != null) { this.Write(", "); this.Write(Int64.MaxValue); } } }
internal static bool IsNameMapProjection(SqlSelectExpression select) { if (select.From is SqlTableExpression) { return(false); } var fromSelect = select.From as SqlSelectExpression; if (fromSelect == null || select.Columns.Count > fromSelect.Columns.Count) { return(false); } var fromColumnNames = new HashSet <string>(fromSelect.Columns.Select(x => x.Name)); foreach (var t in @select.Columns) { var columnExpression = t.Expression as SqlColumnExpression; if (columnExpression == null || !fromColumnNames.Contains(columnExpression.Name)) { return(false); } } return(true); }
protected override void AppendLimit(SqlSelectExpression selectExpression) { if (selectExpression.Skip != null || selectExpression.Take != null) { if (selectExpression.Take != null) { this.Write(" LIMIT "); this.Visit(selectExpression.Take); this.Write(" "); } else { this.Write(" LIMIT -1 "); } if (selectExpression.Skip != null) { this.Write("OFFSET "); this.Visit(selectExpression.Skip); } } }
protected override Expression VisitSelect(SqlSelectExpression selectExpression) { var from = selectExpression.From; var where = Visit(selectExpression.Where); var orderBy = selectExpression.OrderBy; var groupBy = selectExpression.GroupBy; var skip = selectExpression.Skip; var take = selectExpression.Take; var columns = selectExpression.Columns; if (where?.NodeType == ExpressionType.Constant && where.Type == typeof(bool)) { var value = (bool)((ConstantExpression) where).Value; if (value) { where = null; } } if (where != selectExpression.Where) { return(new SqlSelectExpression(selectExpression.Type, selectExpression.Alias, columns, from, where, orderBy, groupBy, selectExpression.Distinct, skip, take, selectExpression.ForUpdate)); } return(base.VisitSelect(selectExpression)); }
protected override void AppendLimit(SqlSelectExpression selectExpression) { if (selectExpression.Skip != null && selectExpression.Take != null) { throw new InvalidOperationException("Skip/Take not supported"); } }
internal static bool HasAggregates(SqlSelectExpression expression, bool ignoreInSubqueries) { var checker = new HasAggregateChecker(ignoreInSubqueries); checker.Visit(expression); return(checker.hasAggregate); }
protected override Expression VisitUpdate(SqlUpdateExpression expression) { if (!expression.RequiresIdentityInsert) { return(base.VisitUpdate(expression)); } var tableName = ((SqlTableExpression)expression.Source).Name; var typeDescriptor = this .typeDescriptorProvider .GetTypeDescriptors() .Single(c => c.PersistedName == tableName); var insertedColumns = expression .Assignments .OfType <SqlAssignExpression>() .Select(c => new { name = ((SqlColumnExpression)c.Target).Name, value = c.Value, propertyDescriptor = typeDescriptor.GetPropertyDescriptorByColumnName(((SqlColumnExpression)c.Target).Name) }) .ToList(); var columnInfos = QueryBinder .GetColumnInfos(this.typeDescriptorProvider, typeDescriptor.PersistedProperties.Where(c => insertedColumns.All(d => d.propertyDescriptor != c))) .ToList(); var visitedUpdated = (SqlUpdateExpression)base.VisitUpdate(expression); var selectIntoExpression = new SqlSelectExpression ( typeof(void), null, columnInfos.Select ( c => new SqlColumnDeclaration ( null, new SqlColumnExpression(c.DefinitionProperty.PropertyType, null, c.GetColumnName()) ) ) .Concat(insertedColumns.Select(d => d.value.Type.GetUnwrappedNullableType() == typeof(bool) ? new SqlColumnDeclaration(d.name, new BitBooleanExpression(d.value)) : new SqlColumnDeclaration(d.name, d.value))) .ToReadOnlyCollection(), visitedUpdated.Source, visitedUpdated.Where, null, null, false, null, null, false, false, new SqlTableExpression("#TEMP") ); var selectExpression = new SqlSelectExpression(typeof(void), null, null, selectIntoExpression.Into, null, null); var insertExpression = new SqlInsertIntoExpression(visitedUpdated.Source, columnInfos.Select(c => c.GetColumnName()).Concat(insertedColumns.Select(c => c.name)).ToReadOnlyCollection(), null, selectExpression, null, true); var deleteExpression = new SqlDeleteExpression(visitedUpdated.Source, visitedUpdated.Where); var list = new List <Expression> { selectIntoExpression, deleteExpression, new SqlSetCommandExpression("IDENTITY_INSERT", visitedUpdated.Source, new SqlKeywordExpression("ON")), insertExpression, new SqlSetCommandExpression("IDENTITY_INSERT", visitedUpdated.Source, new SqlKeywordExpression("OFF")), }; return(new SqlStatementListExpression(list)); }
protected override void AppendTop(SqlSelectExpression selectExpression) { if (selectExpression.Take != null && selectExpression.Skip == null) { Write("TOP("); Visit(selectExpression.Take); Write(") "); } }
protected override Expression VisitSelect(SqlSelectExpression selectExpression) { var count = selectExpression.Columns.Count; List <SqlColumnDeclaration> newColumns = null; for (var i = 0; i < count; i++) { var column = selectExpression.Columns[i]; var visitedColumnExpression = this.Visit(column.Expression); if (visitedColumnExpression.Type.GetUnwrappedNullableType() == typeof(bool) && !(visitedColumnExpression is BitBooleanExpression)) { if (newColumns == null) { newColumns = new List <SqlColumnDeclaration>(selectExpression.Columns.Take(i)); } var newColumnExpression = BitBooleanExpression.Coerce(visitedColumnExpression); var newColumnDeclaration = new SqlColumnDeclaration(column.Name, newColumnExpression); newColumns.Add(newColumnDeclaration); } else if (visitedColumnExpression != column.Expression) { if (newColumns == null) { newColumns = new List <SqlColumnDeclaration>(selectExpression.Columns.Take(i)); } newColumns.Add(column.ReplaceExpression(visitedColumnExpression)); } else if (newColumns != null) { newColumns.Add(column); } } var from = this.VisitSource(selectExpression.From); var where = this.Visit(selectExpression.Where); var orderBy = this.VisitExpressionList(selectExpression.OrderBy); var groupBy = this.VisitExpressionList(selectExpression.GroupBy); var skip = this.Visit(selectExpression.Skip); var take = this.Visit(selectExpression.Take); if (where is BitBooleanExpression) { where = Expression.Equal(where, Expression.Constant(true, where.Type)); } if (from != selectExpression.From || where != selectExpression.Where || newColumns != selectExpression.Columns || orderBy != selectExpression.OrderBy || groupBy != selectExpression.GroupBy || take != selectExpression.Take || skip != selectExpression.Skip) { return(new SqlSelectExpression(selectExpression.Type, selectExpression.Alias, newColumns ?? selectExpression.Columns, from, where, orderBy, groupBy, selectExpression.Distinct, skip, take, selectExpression.ForUpdate, selectExpression.Reverse, selectExpression.Into)); } return(base.VisitSelect(selectExpression)); }
protected override Expression VisitSelect(SqlSelectExpression selectExpression) { if (selectExpression.OrderBy != null) { return(selectExpression.ChangeOrderBy(null)); } return(base.VisitSelect(selectExpression)); }
protected override Expression VisitSelect(SqlSelectExpression selectExpression) { selectNesting++; var retval = base.VisitSelect(selectExpression); selectNesting--; return(retval); }
private static bool IsRedudantSubquery(SqlSelectExpression select) { return((IsSimpleProjection(select) || IsNameMapProjection(select)) && !select.Distinct && select.Take == null && select.Skip == null && select.Where == null && (select.OrderBy == null || select.OrderBy.Count == 0) && (select.GroupBy == null || select.GroupBy.Count == 0)); }
protected virtual void VisitColumn(SqlSelectExpression selectExpression, SqlColumnDeclaration column) { var c = this.Visit(column.Expression) as SqlColumnExpression; if ((c == null || c.Name != column.Name) && !String.IsNullOrEmpty(column.Name)) { this.Write(" AS "); this.WriteQuotedIdentifier(column.Name); } }
protected override Expression VisitSelect(SqlSelectExpression select) { var saveIsOuterMostSelect = this.isOuterMostSelect; try { this.isOuterMostSelect = false; select = (SqlSelectExpression)base.VisitSelect(select); var canHaveOrderBy = saveIsOuterMostSelect || select.Take != null || select.Skip != null; var hasGroupBy = select.GroupBy?.Count > 0; var canReceiveOrderings = canHaveOrderBy && !hasGroupBy && !select.Distinct && !SqlAggregateChecker.HasAggregates(select); var hasOrderBy = select.OrderBy?.Count > 0; if (hasOrderBy) { PrependOrderings(select.OrderBy); } var columns = select.Columns; var orderings = canReceiveOrderings ? this.gatheredOrderings : (canHaveOrderBy ? select.OrderBy : null); var canPassOnOrderings = !saveIsOuterMostSelect && !hasGroupBy && !select.Distinct && (select.Take == null && select.Skip == null); if (this.gatheredOrderings != null) { if (canPassOnOrderings) { var producedAliases = SqlAliasesProduced.Gather(select.From); var project = RebindOrderings(this.gatheredOrderings, select.Alias, producedAliases, select.Columns); this.gatheredOrderings = null; PrependOrderings(project.Orderings); columns = project.Columns; } else { this.gatheredOrderings = null; } } if (orderings != select.OrderBy || columns != select.Columns) { select = new SqlSelectExpression(select.Type, select.Alias, columns, select.From, select.Where, orderings, select.GroupBy, select.Distinct, select.Skip, select.Take, select.ForUpdate); } return(select); } finally { this.isOuterMostSelect = saveIsOuterMostSelect; } }
protected override Expression VisitSelect(SqlSelectExpression selectExpression) { if (selectExpression.Columns.Count == 1 && selectExpression.From.NodeType == (ExpressionType)SqlExpressionType.Select && selectExpression.Columns[0].Expression.NodeType == (ExpressionType)SqlExpressionType.Aggregate) { var from = (SqlSelectExpression)selectExpression.From; var aggregateExpression = (SqlAggregateExpression)selectExpression.Columns[0].Expression; if (from.Columns.Count > 1 || aggregateExpression.IsDistinct || from.Distinct || from.Take != null || from.Skip != null || from.GroupBy != null /* Don't fold a from with an orderby into the outer select if it has a count or other aggregate */ || from.OrderBy != null && from.OrderBy.Count > 0 && SqlAggregateChecker.HasAggregates(selectExpression)) { return(base.VisitSelect(selectExpression)); } var newColumns = new List <SqlColumnDeclaration>(); if (from.Columns.Count == 1) { foreach (var column in from.Columns) { if (column.Expression.NodeType != (ExpressionType)SqlExpressionType.Column) { return(base.VisitSelect(selectExpression)); } var newAggregate = new SqlAggregateExpression ( aggregateExpression.Type, aggregateExpression.AggregateType, column.Expression, aggregateExpression.IsDistinct ); newColumns.Add(new SqlColumnDeclaration(column.Name, newAggregate)); } } else { newColumns.Add(selectExpression.Columns[0]); } var where = this.Visit(from.Where); return(from.ChangeWhereAndColumns(where, newColumns.ToReadOnlyList(), from.ForUpdate || selectExpression.ForUpdate)); } return(base.VisitSelect(selectExpression)); }
protected override Expression VisitSelect(SqlSelectExpression select) { if (this.selectsToRemove.Contains(select)) { return(Visit(select.From)); } else { return(base.VisitSelect(select)); } }
private static bool IsRedudantSubquery(SqlSelectExpression select) { return((IsSimpleProjection(select) || IsNameMapProjection(select)) && !select.Distinct && (select.Take == null) && (select.Skip == null) && select.Where == null && !select.Columns.Any(c => c.NoOptimise) && ((select.OrderBy?.Count ?? 0) == 0) && ((select.GroupBy?.Count ?? 0) == 0)); }
protected override Expression VisitSelect(SqlSelectExpression selectExpression) { if (selectExpression.GroupBy != null && selectExpression.GroupBy.Count == 1 && selectExpression.GroupBy[0].NodeType == ExpressionType.New) { var groupBy = ((NewExpression)selectExpression.GroupBy[0]).Arguments; return(new SqlSelectExpression(selectExpression.Type, selectExpression.Alias, selectExpression.Columns.ToReadOnlyList(), selectExpression.From, selectExpression.Where, selectExpression.OrderBy.ToReadOnlyList(), groupBy.ToReadOnlyList(), selectExpression.Distinct, selectExpression.Skip, selectExpression.Take, selectExpression.ForUpdate)); } return(base.VisitSelect(selectExpression)); }
internal static bool IsSimpleProjection(SqlSelectExpression select) { foreach (var decl in select.Columns) { if (!(decl.Expression is SqlColumnExpression col) || decl.Name != col.Name) { return(false); } } return(true); }
protected override Expression VisitSelect(SqlSelectExpression select) { var columnRemoved = false; select = (SqlSelectExpression)base.VisitSelect(select); var columnsOrderedByName = select.Columns.OrderBy(c => c.Name).ToList(); var removedColumns = new BitArray(select.Columns.Count); for (int i = 0, n = columnsOrderedByName.Count; i < n - 1; i++) { var icolumn = columnsOrderedByName[i]; var iNewColumnExpression = new SqlColumnExpression(icolumn.Expression.Type, select.Alias, icolumn.Name); for (var j = i + 1; j < n; j++) { if (!removedColumns.Get(j)) { var jcolumn = columnsOrderedByName[j]; if (IsSameExpression(icolumn.Expression, jcolumn.Expression)) { // 'j' references should now be a reference to 'i' var jNewColumnExpression = new SqlColumnExpression(jcolumn.Expression.Type, select.Alias, jcolumn.Name); this.visitedColumns.Add(jNewColumnExpression, iNewColumnExpression); removedColumns.Set(j, true); columnRemoved = true; } } } } if (columnRemoved) { var newColumnDeclarations = new List <SqlColumnDeclaration>(); for (int i = 0, n = columnsOrderedByName.Count; i < n; i++) { if (!removedColumns.Get(i)) { newColumnDeclarations.Add(columnsOrderedByName[i]); } } select = select.ChangeColumns(newColumnDeclarations); } return(select); }
protected override Expression VisitSelect(SqlSelectExpression select) { var saveIsOuterMostSelect = this.isOuterMostSelect; try { this.isOuterMostSelect = false; select = (SqlSelectExpression)base.VisitSelect(select); var hasOrderBy = select.OrderBy != null && select.OrderBy.Count > 0; if (hasOrderBy) { this.PrependOrderings(select.OrderBy.Select(c => (SqlOrderByExpression)c)); } var canHaveOrderBy = saveIsOuterMostSelect && !SqlExpressionFinder.FindExists(select, c => c.NodeType == (ExpressionType)SqlExpressionType.Aggregate || c.NodeType == (ExpressionType)SqlExpressionType.AggregateSubquery); var canPassOnOrderings = !saveIsOuterMostSelect; var columns = select.Columns; IEnumerable <Expression> orderings = (canHaveOrderBy) ? this.gatheredOrderings : null; if (this.gatheredOrderings != null) { if (canPassOnOrderings) { var producedAliases = AliasesProduced.Gather(select.From); var project = this.RebindOrderings(this.gatheredOrderings, select.Alias, producedAliases, select.Columns); this.gatheredOrderings = project.Orderings; columns = project.Columns; } else { this.gatheredOrderings = null; } } if (orderings != select.OrderBy || columns != select.Columns) { select = new SqlSelectExpression(select.Type, select.Alias, columns, select.From, select.Where, orderings, select.GroupBy, select.Distinct, select.Skip, select.Take, select.ForUpdate); } return(select); } finally { this.isOuterMostSelect = saveIsOuterMostSelect; } }
protected override Expression VisitSelect(SqlSelectExpression select) { var savedIsTopLevel = this.isTopLevel; this.isTopLevel = false; select = (SqlSelectExpression)base.VisitSelect(select); // Attempt to merge subqueries that would have been removed by the above // logic except for the existence of a where clause while (CanMergeWithFrom(select)) { var fromSelect = select.From.GetLeftMostSelect(); CanMergeWithFrom(select); // remove the redundant subquery select = SqlSubqueryRemover.Remove(select, fromSelect); // merge where expressions var where = select.Where; if (fromSelect.Where != null) { if (where != null) { where = Expression.And(fromSelect.Where, where); } else { where = fromSelect.Where; } } var orderBy = select.OrderBy != null && select.OrderBy.Count > 0 ? select.OrderBy : fromSelect.OrderBy; var groupBy = select.GroupBy != null && select.GroupBy.Count > 0 ? select.GroupBy : fromSelect.GroupBy; var skip = select.Skip ?? fromSelect.Skip; var take = select.Take ?? fromSelect.Take; var isDistinct = select.Distinct || fromSelect.Distinct; if (where != select.Where || orderBy != select.OrderBy || groupBy != select.GroupBy || isDistinct != select.Distinct || skip != select.Skip || take != select.Take) { select = new SqlSelectExpression(select.Type, select.Alias, select.Columns, select.From, where, orderBy, groupBy, isDistinct, skip, take, select.ForUpdate); } } this.isTopLevel = savedIsTopLevel; return(select); }
internal static bool IsSimpleProjection(SqlSelectExpression select) { foreach (SqlColumnDeclaration decl in select.Columns) { var col = decl.Expression as SqlColumnExpression; if (col == null || decl.Name != col.Name) { return(false); } } return(true); }
protected override Expression VisitSelect(SqlSelectExpression select) { if (IsRedudantSubquery(select)) { if (this.redundant == null) { this.redundant = new List <SqlSelectExpression>(); } this.redundant.Add(select); } return(select); }
protected override Expression VisitSelect(SqlSelectExpression selectExpression) { this.VisitSource(selectExpression.From); this.VisitColumnDeclarations(selectExpression.Columns); var localInWhereClause = this.inWhereClause; this.inWhereClause = true; this.Visit(selectExpression.Where); this.inWhereClause = localInWhereClause; return(selectExpression); }
protected override Expression VisitSelect(SqlSelectExpression selectExpression) { if (selectExpression.Skip != null) { var rowNumber = new SqlFunctionCallExpression(typeof(int), "ROW_NUMBER"); var oldAliases = (selectExpression.From as ISqlExposesAliases)?.Aliases; var innerSelectWithRowAlias = selectExpression.Alias + "_ROW"; var cols = selectExpression.Columns.Select(c => new SqlColumnDeclaration(c.Name, new SqlColumnExpression(c.Expression.Type, selectExpression.Alias, c.Name))).ToList(); var over = new SqlOverExpression(rowNumber, selectExpression.OrderBy?.Cast <SqlOrderByExpression>().ToReadOnlyCollection() ?? cols.Select(c => new SqlOrderByExpression(OrderType.Ascending, c.Expression)).ToReadOnlyCollection()); if (oldAliases != null) { over = (SqlOverExpression)AliasReferenceReplacer.Replace(over, oldAliases.Contains, selectExpression.Alias); } var rowColumn = new SqlColumnDeclaration(RowColumnName, over); cols.Add(rowColumn); var innerSelectWithRowColumns = cols.ToReadOnlyCollection(); var innerSelectWithRow = new SqlSelectExpression(selectExpression.Type, innerSelectWithRowAlias, innerSelectWithRowColumns, selectExpression.ChangeOrderBy(null).ChangeSkipTake(null, null), null, null, null, false, null, null, false); var outerColumns = selectExpression.Columns.Select(c => new SqlColumnDeclaration(c.Name, new SqlColumnExpression(c.Expression.Type, innerSelectWithRowAlias, c.Name))); Expression rowPredicate = Expression.GreaterThan(new SqlColumnExpression(typeof(int), innerSelectWithRowAlias, rowColumn.Name), selectExpression.Skip); if (selectExpression.Take != null && !(selectExpression.Take is SqlTakeAllValueExpression)) { rowPredicate = Expression.And ( rowPredicate, Expression.LessThanOrEqual(new SqlColumnExpression(typeof(int), innerSelectWithRowAlias, rowColumn.Name), Expression.Add(selectExpression.Skip, selectExpression.Take)) ); } var newOrderBy = selectExpression .OrderBy? .Select(c => oldAliases == null ? c : AliasReferenceReplacer.Replace(c, oldAliases.Contains, innerSelectWithRowAlias)) .Concat(new SqlOrderByExpression(OrderType.Ascending, new SqlColumnExpression(typeof(int), innerSelectWithRowAlias, rowColumn.Name))) .ToReadOnlyCollection(); var retval = new SqlSelectExpression(selectExpression.Type, selectExpression.Alias, outerColumns, innerSelectWithRow, rowPredicate, newOrderBy, selectExpression.ForUpdate); return(retval); } return(base.VisitSelect(selectExpression)); }
protected override Expression VisitSelect(SqlSelectExpression select) { select = (SqlSelectExpression)base.VisitSelect(select); // Expand all purely redundant subqueries var redundantQueries = SqlRedundantSubqueryFinder.Find(select.From); if (redundantQueries != null) { select = SubqueryRemover.Remove(select, redundantQueries); } return(select); }
private static bool IsColumnProjection(SqlSelectExpression select) { var count = select.Columns.Count; for (var i = 0; i < count; i++) { var columnDeclaration = select.Columns[i]; if (columnDeclaration.Expression.NodeType != (ExpressionType)SqlExpressionType.Column && columnDeclaration.Expression.NodeType != ExpressionType.Constant) { return(false); } } return(true); }