diff --git a/src/EFCore.Jet/Query/Internal/JetLiftOrderByPostprocessor.cs b/src/EFCore.Jet/Query/Internal/JetLiftOrderByPostprocessor.cs index 568be87..2bbf3b4 100644 --- a/src/EFCore.Jet/Query/Internal/JetLiftOrderByPostprocessor.cs +++ b/src/EFCore.Jet/Query/Internal/JetLiftOrderByPostprocessor.cs @@ -1,14 +1,8 @@ -using System; using System.Collections.Generic; -using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Linq; using System.Linq.Expressions; -using EntityFrameworkCore.Jet.Utilities; -using Microsoft.EntityFrameworkCore.Metadata; -using Microsoft.EntityFrameworkCore.Metadata.Internal; using Microsoft.EntityFrameworkCore.Query; -using Microsoft.EntityFrameworkCore.Query.Internal; using Microsoft.EntityFrameworkCore.Query.SqlExpressions; using Microsoft.EntityFrameworkCore.Storage; @@ -65,14 +59,15 @@ public class JetLiftOrderByPostprocessor : ExpressionVisitor case SelectExpression selectExpression: { Dictionary columnsToRewrite = new(); - + bool isscalarselect = selectExpression is { Limit: SqlConstantExpression { Value: 1 }, Projection.Count: 1 }; for (int i = 0; i < selectExpression.Orderings.Count; i++) { var sqlExpression = selectExpression.Orderings[i].Expression; if (sqlExpression is not ColumnExpression) { - bool containsscalar = sqlExpression is ScalarSubqueryExpression; - containsscalar = containsscalar || TryPeekFunction(sqlExpression as SqlFunctionExpression) || TryPeekCase(sqlExpression as CaseExpression) || TryPeekExists(sqlExpression as ExistsExpression); + var locate = new JetLocateScalarSubqueryVisitor(_typeMappingSource, _sqlExpressionFactory); + var locatedExpression = locate.Visit(sqlExpression); + bool containsscalar = locatedExpression is ScalarSubqueryExpression or ExistsExpression; if (containsscalar) { int index = selectExpression.AddToProjection(sqlExpression); @@ -134,6 +129,25 @@ public class JetLiftOrderByPostprocessor : ExpressionVisitor selectExpression.AppendOrdering(new OrderingExpression(newcolexp, ascending)); } } + + if (isscalarselect) + { + List newProjections = new List(); + for (int j = 0; j < selectExpression.Projection.Count; j++) + { + var proj = selectExpression.Projection[j]; + var item = columnsToRewrite.SingleOrDefault(c => c.Value.indexcol == j); + if (item.Value.indexcol == null) + { + newProjections.Add(proj); + } + + } + + selectExpression = selectExpression.Update(newProjections, selectExpression.Tables, selectExpression.Predicate, + selectExpression.GroupBy, selectExpression.Having, selectExpression.Orderings, + selectExpression.Limit, selectExpression.Offset); + } var result = base.Visit(selectExpression); return result; } @@ -141,24 +155,4 @@ public class JetLiftOrderByPostprocessor : ExpressionVisitor return base.Visit(expression); } - - private bool TryPeekExists(ExistsExpression? existsExpression) - { - return existsExpression is not null; - } - - private bool TryPeekCase(CaseExpression? sqlExpression) - { - if (sqlExpression is null) return false; - if (sqlExpression.ElseResult is ScalarSubqueryExpression) return true; - if (sqlExpression.WhenClauses.Any(x => x.Result is ScalarSubqueryExpression)) return true; - if (sqlExpression.Operand is ScalarSubqueryExpression) return true; - return false; - } - - private bool TryPeekFunction(SqlFunctionExpression? sqlExpression) - { - if (sqlExpression is null) return false; - return sqlExpression.Arguments != null && sqlExpression.Arguments.Any(x => x is ScalarSubqueryExpression); - } } diff --git a/src/EFCore.Jet/Query/Internal/JetLocateScalarSubqueryVisitor.cs b/src/EFCore.Jet/Query/Internal/JetLocateScalarSubqueryVisitor.cs new file mode 100644 index 0000000..2691a6a --- /dev/null +++ b/src/EFCore.Jet/Query/Internal/JetLocateScalarSubqueryVisitor.cs @@ -0,0 +1,413 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Linq.Expressions; +using EntityFrameworkCore.Jet.Utilities; +using Microsoft.EntityFrameworkCore.Metadata; +using Microsoft.EntityFrameworkCore.Metadata.Internal; +using Microsoft.EntityFrameworkCore.Query; +using Microsoft.EntityFrameworkCore.Query.Internal; +using Microsoft.EntityFrameworkCore.Query.SqlExpressions; +using Microsoft.EntityFrameworkCore.Storage; + +namespace EntityFrameworkCore.Jet.Query.Internal; + +/// +/// This is an internal API that supports the Entity Framework Core infrastructure and not subject to +/// the same compatibility standards as public APIs. It may be changed or removed without notice in +/// any release. You should only use it directly in your code with extreme caution and knowing that +/// doing so can result in application failures when updating to a new Entity Framework Core release. +/// +public class JetLocateScalarSubqueryVisitor : SqlExpressionVisitor +{ + private readonly IRelationalTypeMappingSource _typeMappingSource; + private readonly ISqlExpressionFactory _sqlExpressionFactory; + + /// + /// This is an internal API that supports the Entity Framework Core infrastructure and not subject to + /// the same compatibility standards as public APIs. It may be changed or removed without notice in + /// any release. You should only use it directly in your code with extreme caution and knowing that + /// doing so can result in application failures when updating to a new Entity Framework Core release. + /// + public JetLocateScalarSubqueryVisitor( + IRelationalTypeMappingSource typeMappingSource, + ISqlExpressionFactory sqlExpressionFactory) + { + (_typeMappingSource, _sqlExpressionFactory) = (typeMappingSource, sqlExpressionFactory); + } + + protected override Expression VisitAtTimeZone(AtTimeZoneExpression atTimeZoneExpression) + { + var operand = (SqlExpression)Visit(atTimeZoneExpression.Operand); + var timeZone = (SqlExpression)Visit(atTimeZoneExpression.TimeZone); + return atTimeZoneExpression.Update(operand, timeZone); + } + + protected override Expression VisitCase(CaseExpression caseExpression) + { + var operand = (SqlExpression?)Visit(caseExpression.Operand); + var whenClauses = new List(); + foreach (var whenClause in caseExpression.WhenClauses) + { + var test = (SqlExpression)Visit(whenClause.Test); + var result = (SqlExpression)Visit(whenClause.Result); + whenClauses.Add(new CaseWhenClause(test, result)); + } + var elseResult = (SqlExpression?)Visit(caseExpression.ElseResult); + + return caseExpression.Update(operand, whenClauses, elseResult); + } + + protected override Expression VisitCollate(CollateExpression collateExpression) + { + var operand = (SqlExpression)Visit(collateExpression.Operand); + + return collateExpression.Update(operand); + } + + protected override Expression VisitColumn(ColumnExpression columnExpression) + { + return columnExpression; + } + + protected override Expression VisitCrossApply(CrossApplyExpression crossApplyExpression) + { + var table = (TableExpressionBase)Visit(crossApplyExpression.Table); + return crossApplyExpression.Update(table); + } + + protected override Expression VisitCrossJoin(CrossJoinExpression crossJoinExpression) + { + var table = (TableExpressionBase)Visit(crossJoinExpression.Table); + return crossJoinExpression.Update(table); + } + + protected override Expression VisitDelete(DeleteExpression deleteExpression) + { + return deleteExpression.Update((SelectExpression)Visit(deleteExpression.SelectExpression)); + } + + protected override Expression VisitDistinct(DistinctExpression distinctExpression) + { + var operand = (SqlExpression)Visit(distinctExpression.Operand); + return distinctExpression.Update(operand); + } + + protected override Expression VisitExcept(ExceptExpression exceptExpression) + { + var source1 = (SelectExpression)Visit(exceptExpression.Source1); + var source2 = (SelectExpression)Visit(exceptExpression.Source2); + return exceptExpression.Update(source1, source2); + } + + protected override Expression VisitExists(ExistsExpression existsExpression) + { + var subquery = (SelectExpression)Visit(existsExpression.Subquery); + + return existsExpression.Update(subquery); + } + + protected override Expression VisitFromSql(FromSqlExpression fromSqlExpression) + { + return fromSqlExpression; + } + + protected override Expression VisitIn(InExpression inExpression) + { + var item = (SqlExpression)Visit(inExpression.Item); + var subquery = (SelectExpression?)Visit(inExpression.Subquery); + + var values = inExpression.Values; + SqlExpression[]? newValues = null; + if (values is not null) + { + for (var i = 0; i < values.Count; i++) + { + var value = values[i]; + var newValue = (SqlExpression)Visit(value); + + if (newValue != value && newValues is null) + { + newValues = new SqlExpression[values.Count]; + for (var j = 0; j < i; j++) + { + newValues[j] = values[j]; + } + } + + if (newValues is not null) + { + newValues[i] = newValue; + } + } + } + + var valuesParameter = (SqlParameterExpression?)Visit(inExpression.ValuesParameter); + return inExpression.Update(item, subquery, newValues ?? values, valuesParameter); + } + + protected override Expression VisitIntersect(IntersectExpression intersectExpression) + { + var source1 = (SelectExpression)Visit(intersectExpression.Source1); + var source2 = (SelectExpression)Visit(intersectExpression.Source2); + return intersectExpression.Update(source1, source2); + } + + protected override Expression VisitLike(LikeExpression likeExpression) + { + var match = (SqlExpression)Visit(likeExpression.Match); + var pattern = (SqlExpression)Visit(likeExpression.Pattern); + var escapeChar = (SqlExpression?)Visit(likeExpression.EscapeChar); + + return likeExpression.Update(match, pattern, escapeChar); + } + + protected override Expression VisitInnerJoin(InnerJoinExpression innerJoinExpression) + { + var table = (TableExpressionBase)Visit(innerJoinExpression.Table); + var joinPredicate = (SqlExpression)Visit(innerJoinExpression.JoinPredicate); + return innerJoinExpression.Update(table, joinPredicate); + } + + protected override Expression VisitLeftJoin(LeftJoinExpression leftJoinExpression) + { + var table = (TableExpressionBase)Visit(leftJoinExpression.Table); + var joinPredicate = (SqlExpression)Visit(leftJoinExpression.JoinPredicate); + return leftJoinExpression.Update(table, joinPredicate); + } + + protected override Expression VisitOrdering(OrderingExpression orderingExpression) + { + var expression = (SqlExpression)Visit(orderingExpression.Expression); + return orderingExpression.Update(expression); + } + + protected override Expression VisitOuterApply(OuterApplyExpression outerApplyExpression) + { + var table = (TableExpressionBase)Visit(outerApplyExpression.Table); + return outerApplyExpression.Update(table); + } + + protected override Expression VisitProjection(ProjectionExpression projectionExpression) + { + var expression = (SqlExpression)Visit(projectionExpression.Expression); + + return projectionExpression.Update(expression); + } + + protected override Expression VisitTableValuedFunction(TableValuedFunctionExpression tableValuedFunctionExpression) + { + var arguments = new SqlExpression[tableValuedFunctionExpression.Arguments.Count]; + for (var i = 0; i < arguments.Length; i++) + { + arguments[i] = (SqlExpression)Visit(tableValuedFunctionExpression.Arguments[i]); + } + + return tableValuedFunctionExpression.Update(arguments); + } + + protected override Expression VisitRowNumber(RowNumberExpression rowNumberExpression) + { + var partitions = new List(); + foreach (var partition in rowNumberExpression.Partitions) + { + var newPartition = (SqlExpression)Visit(partition); + partitions.Add(newPartition); + } + + var orderings = new List(); + foreach (var ordering in rowNumberExpression.Orderings) + { + var newOrdering = (OrderingExpression)Visit(ordering); + orderings.Add(newOrdering); + } + return rowNumberExpression.Update(partitions, orderings); + } + + protected override Expression VisitRowValue(RowValueExpression rowValueExpression) + { + var values = new SqlExpression[rowValueExpression.Values.Count]; + for (var i = 0; i < values.Length; i++) + { + values[i] = (SqlExpression)Visit(rowValueExpression.Values[i]); + } + return rowValueExpression.Update(values); + } + + protected override Expression VisitScalarSubquery(ScalarSubqueryExpression scalarSubqueryExpression) + { + return scalarSubqueryExpression; + } + + protected override Expression VisitSelect(SelectExpression selectExpression) + { + var changed = false; + var projections = new List(); + foreach (var item in selectExpression.Projection) + { + var updatedProjection = (ProjectionExpression)Visit(item); + projections.Add(updatedProjection); + changed |= updatedProjection != item; + } + + var tables = new List(); + foreach (var table in selectExpression.Tables) + { + var newTable = (TableExpressionBase)Visit(table); + changed |= newTable != table; + tables.Add(newTable); + } + + var predicate = (SqlExpression?)Visit(selectExpression.Predicate); + changed |= predicate != selectExpression.Predicate; + + var groupBy = new List(); + foreach (var groupingKey in selectExpression.GroupBy) + { + var newGroupingKey = (SqlExpression)Visit(groupingKey); + changed |= newGroupingKey != groupingKey; + groupBy.Add(newGroupingKey); + } + + var havingExpression = (SqlExpression?)Visit(selectExpression.Having); + changed |= havingExpression != selectExpression.Having; + + var orderings = new List(); + foreach (var ordering in selectExpression.Orderings) + { + var orderingExpression = (SqlExpression)Visit(ordering.Expression); + changed |= orderingExpression != ordering.Expression; + orderings.Add(ordering.Update(orderingExpression)); + } + + var offset = (SqlExpression?)Visit(selectExpression.Offset); + changed |= offset != selectExpression.Offset; + + var limit = (SqlExpression?)Visit(selectExpression.Limit); + changed |= limit != selectExpression.Limit; + + return changed + ? selectExpression.Update( + projections, tables, predicate, groupBy, havingExpression, orderings, limit, offset) + : selectExpression; + } + + protected override Expression VisitSqlBinary(SqlBinaryExpression sqlBinaryExpression) + { + var newLeft = (SqlExpression)Visit(sqlBinaryExpression.Left); + var newRight = (SqlExpression)Visit(sqlBinaryExpression.Right); + if (newLeft is ScalarSubqueryExpression) + { + return newLeft; + } + + if (newRight is ScalarSubqueryExpression) + { + return newRight; + } + sqlBinaryExpression = sqlBinaryExpression.Update(newLeft, newRight); + return sqlBinaryExpression; + } + + protected override Expression VisitSqlConstant(SqlConstantExpression sqlConstantExpression) + { + return sqlConstantExpression; + } + + protected override Expression VisitSqlFragment(SqlFragmentExpression sqlFragmentExpression) + { + return sqlFragmentExpression; + } + + protected override Expression VisitSqlFunction(SqlFunctionExpression sqlFunctionExpression) + { + var instance = (SqlExpression?)Visit(sqlFunctionExpression.Instance); + SqlExpression[]? arguments = default; + if (!sqlFunctionExpression.IsNiladic) + { + arguments = new SqlExpression[sqlFunctionExpression.Arguments.Count]; + for (var i = 0; i < arguments.Length; i++) + { + arguments[i] = (SqlExpression)Visit(sqlFunctionExpression.Arguments[i]); + if (arguments[i] is ScalarSubqueryExpression) + { + return arguments[i]; + } + } + } + var newFunction = sqlFunctionExpression.Update(instance, arguments); + + return newFunction; + } + + protected override Expression VisitSqlParameter(SqlParameterExpression sqlParameterExpression) + { + return sqlParameterExpression; + } + + protected override Expression VisitSqlUnary(SqlUnaryExpression sqlUnaryExpression) + { + var operand = (SqlExpression)Visit(sqlUnaryExpression.Operand); + if (operand is ScalarSubqueryExpression) + { + return operand; + } + return sqlUnaryExpression.Update(operand); + } + + protected override Expression VisitTable(TableExpression tableExpression) + { + return tableExpression; + } + + protected override Expression VisitUnion(UnionExpression unionExpression) + { + var source1 = (SelectExpression)Visit(unionExpression.Source1); + var source2 = (SelectExpression)Visit(unionExpression.Source2); + return unionExpression.Update(source1, source2); + } + + protected override Expression VisitUpdate(UpdateExpression updateExpression) + { + var selectExpression = (SelectExpression)Visit(updateExpression.SelectExpression); + List? columnValueSetters = null; + for (var (i, n) = (0, updateExpression.ColumnValueSetters.Count); i < n; i++) + { + var columnValueSetter = updateExpression.ColumnValueSetters[i]; + var newValue = (SqlExpression)Visit(columnValueSetter.Value); + if (columnValueSetters != null) + { + columnValueSetters.Add(new ColumnValueSetter(columnValueSetter.Column, newValue)); + } + else if (!ReferenceEquals(newValue, columnValueSetter.Value)) + { + columnValueSetters = new List(); + for (var j = 0; j < i; j++) + { + columnValueSetters.Add(updateExpression.ColumnValueSetters[j]); + } + + columnValueSetters.Add(new ColumnValueSetter(columnValueSetter.Column, newValue)); + } + } + + return updateExpression.Update(selectExpression, columnValueSetters ?? updateExpression.ColumnValueSetters); + } + + protected override Expression VisitJsonScalar(JsonScalarExpression jsonScalarExpression) + { + return jsonScalarExpression; + } + + protected override Expression VisitValues(ValuesExpression valuesExpression) + { + var rowValues = new RowValueExpression[valuesExpression.RowValues.Count]; + for (var i = 0; i < rowValues.Length; i++) + { + rowValues[i] = (RowValueExpression)Visit(valuesExpression.RowValues[i]); + } + return valuesExpression.Update(rowValues); + } +} diff --git a/test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_odbc_x86.txt b/test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_odbc_x86.txt index a873f07..2db7d82 100644 --- a/test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_odbc_x86.txt +++ b/test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_odbc_x86.txt @@ -10279,6 +10279,8 @@ EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest.OrderBy_conditional_operator(isAsync: True) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest.OrderBy_correlated_subquery1(isAsync: False) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest.OrderBy_correlated_subquery1(isAsync: True) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest.OrderBy_correlated_subquery2(isAsync: False) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest.OrderBy_correlated_subquery2(isAsync: True) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest.OrderBy_Dto_projection_skip_take(isAsync: False) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest.OrderBy_Dto_projection_skip_take(isAsync: True) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest.OrderBy_empty_list_contains(isAsync: False) diff --git a/test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_oledb_x86.txt b/test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_oledb_x86.txt index 8ad1d7c..cb5e3ee 100644 --- a/test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_oledb_x86.txt +++ b/test/EFCore.Jet.FunctionalTests/GreenTests/ace_2010_oledb_x86.txt @@ -10513,8 +10513,12 @@ EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_subqu EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_subquery_boolean(isAsync: True) EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_subquery_distinct_singleordefault_boolean2(isAsync: False) EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_subquery_distinct_singleordefault_boolean2(isAsync: True) +EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_subquery_equality_to_null_with_composite_key_should_match_nulls(async: False) +EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_subquery_equality_to_null_with_composite_key_should_match_nulls(async: True) EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_subquery_equality_to_null_with_composite_key(async: False) EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_subquery_equality_to_null_with_composite_key(async: True) +EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_subquery_equality_to_null_without_composite_key_should_match_null(async: False) +EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_subquery_equality_to_null_without_composite_key_should_match_null(async: True) EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_subquery_equality_to_null_without_composite_key(async: False) EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_subquery_equality_to_null_without_composite_key(async: True) EntityFrameworkCore.Jet.FunctionalTests.Query.GearsOfWarQueryJetTest.Where_TimeOnly_Add_TimeSpan(async: False) @@ -13138,6 +13142,8 @@ EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest.OrderBy_conditional_operator(isAsync: True) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest.OrderBy_correlated_subquery1(isAsync: False) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest.OrderBy_correlated_subquery1(isAsync: True) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest.OrderBy_correlated_subquery2(isAsync: False) +EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest.OrderBy_correlated_subquery2(isAsync: True) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest.OrderBy_Dto_projection_skip_take(isAsync: False) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest.OrderBy_Dto_projection_skip_take(isAsync: True) EntityFrameworkCore.Jet.FunctionalTests.Query.NorthwindMiscellaneousQueryJetTest.OrderBy_empty_list_contains(isAsync: False) @@ -17115,8 +17121,12 @@ EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_su EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_subquery_boolean(async: True) EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_subquery_distinct_singleordefault_boolean2(async: False) EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_subquery_distinct_singleordefault_boolean2(async: True) +EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_subquery_equality_to_null_with_composite_key_should_match_nulls(async: False) +EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_subquery_equality_to_null_with_composite_key_should_match_nulls(async: True) EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_subquery_equality_to_null_with_composite_key(async: False) EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_subquery_equality_to_null_with_composite_key(async: True) +EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_subquery_equality_to_null_without_composite_key_should_match_null(async: False) +EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_subquery_equality_to_null_without_composite_key_should_match_null(async: True) EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_subquery_equality_to_null_without_composite_key(async: False) EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_subquery_equality_to_null_without_composite_key(async: True) EntityFrameworkCore.Jet.FunctionalTests.Query.TPCGearsOfWarQueryJetTest.Where_TimeOnly_Add_TimeSpan(async: False) @@ -18739,8 +18749,12 @@ EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_su EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_subquery_boolean(async: True) EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_subquery_distinct_singleordefault_boolean2(async: False) EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_subquery_distinct_singleordefault_boolean2(async: True) +EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_subquery_equality_to_null_with_composite_key_should_match_nulls(async: False) +EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_subquery_equality_to_null_with_composite_key_should_match_nulls(async: True) EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_subquery_equality_to_null_with_composite_key(async: False) EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_subquery_equality_to_null_with_composite_key(async: True) +EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_subquery_equality_to_null_without_composite_key_should_match_null(async: False) +EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_subquery_equality_to_null_without_composite_key_should_match_null(async: True) EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_subquery_equality_to_null_without_composite_key(async: False) EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_subquery_equality_to_null_without_composite_key(async: True) EntityFrameworkCore.Jet.FunctionalTests.Query.TPTGearsOfWarQueryJetTest.Where_TimeOnly_Add_TimeSpan(async: False) diff --git a/test/EFCore.Jet.FunctionalTests/Query/GearsOfWarQueryJetTest.cs b/test/EFCore.Jet.FunctionalTests/Query/GearsOfWarQueryJetTest.cs index 25f3e66..b7b938c 100644 --- a/test/EFCore.Jet.FunctionalTests/Query/GearsOfWarQueryJetTest.cs +++ b/test/EFCore.Jet.FunctionalTests/Query/GearsOfWarQueryJetTest.cs @@ -9352,12 +9352,12 @@ WHERE NOT EXISTS ( AssertSql( """ -SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] -FROM [Squads] AS [s] +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` WHERE NOT EXISTS ( SELECT 1 - FROM [Gears] AS [g] - WHERE [s].[Id] = [g].[SquadId] AND [g].[FullName] = N'Anthony Carmine') + FROM `Gears` AS `g` + WHERE `s`.`Id` = `g`.`SquadId` AND `g`.`FullName` = 'Anthony Carmine') """); } @@ -9382,12 +9382,12 @@ WHERE NOT EXISTS ( AssertSql( """ -SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[Discriminator], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank] -FROM [Gears] AS [g] +SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`Discriminator`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank` +FROM `Gears` AS `g` WHERE NOT EXISTS ( SELECT 1 - FROM [Weapons] AS [w] - WHERE [g].[FullName] = [w].[OwnerFullName] AND [w].[Name] = N'Hammer of Dawn') + FROM `Weapons` AS `w` + WHERE `g`.`FullName` = `w`.`OwnerFullName` AND `w`.`Name` = 'Hammer of Dawn') """); } diff --git a/test/EFCore.Jet.FunctionalTests/Query/NorthwindMiscellaneousQueryJetTest.cs b/test/EFCore.Jet.FunctionalTests/Query/NorthwindMiscellaneousQueryJetTest.cs index acb55f2..d92c0cc 100644 --- a/test/EFCore.Jet.FunctionalTests/Query/NorthwindMiscellaneousQueryJetTest.cs +++ b/test/EFCore.Jet.FunctionalTests/Query/NorthwindMiscellaneousQueryJetTest.cs @@ -2283,27 +2283,29 @@ ORDER BY NOT (`t`.`c`), `t`.`CustomerID` await base.OrderBy_correlated_subquery2(isAsync); AssertSql( - $@"SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` + """ +SELECT `o`.`OrderID`, `o`.`CustomerID`, `o`.`EmployeeID`, `o`.`OrderDate` FROM `Orders` AS `o` -WHERE (`o`.`OrderID` <= 10250) AND ((( - SELECT TOP 1 `c`.`City` - FROM `Customers` AS `c` - ORDER BY CASE - WHEN EXISTS ( - SELECT 1 - FROM `Customers` AS `c0` - WHERE `c0`.`CustomerID` = 'ALFKI') THEN True - ELSE False - END) <> 'Nowhere') OR ( - SELECT TOP 1 `c`.`City` - FROM `Customers` AS `c` - ORDER BY CASE - WHEN EXISTS ( - SELECT 1 - FROM `Customers` AS `c0` - WHERE `c0`.`CustomerID` = 'ALFKI') THEN True - ELSE False - END) IS NULL)"); +WHERE `o`.`OrderID` <= 10250 AND (( + SELECT `t`.`City` + FROM ( + SELECT TOP 1 `c`.`City`, IIF(EXISTS ( + SELECT 1 + FROM `Customers` AS `c1` + WHERE `c1`.`CustomerID` = 'ALFKI'), TRUE, FALSE) AS `c`, `c`.`CustomerID` + FROM `Customers` AS `c` + ) AS `t` + ORDER BY NOT (`t`.`c`)) <> 'Nowhere' OR ( + SELECT `t`.`City` + FROM ( + SELECT TOP 1 `c`.`City`, IIF(EXISTS ( + SELECT 1 + FROM `Customers` AS `c1` + WHERE `c1`.`CustomerID` = 'ALFKI'), TRUE, FALSE) AS `c`, `c`.`CustomerID` + FROM `Customers` AS `c` + ) AS `t` + ORDER BY NOT (`t`.`c`)) IS NULL) +"""); } public override async Task Where_subquery_recursive_trivial(bool isAsync) diff --git a/test/EFCore.Jet.FunctionalTests/Query/TPCGearsOfWarQueryJetTest.cs b/test/EFCore.Jet.FunctionalTests/Query/TPCGearsOfWarQueryJetTest.cs index 9fdb2b3..93fb93b 100644 --- a/test/EFCore.Jet.FunctionalTests/Query/TPCGearsOfWarQueryJetTest.cs +++ b/test/EFCore.Jet.FunctionalTests/Query/TPCGearsOfWarQueryJetTest.cs @@ -12792,18 +12792,18 @@ WHERE NOT EXISTS ( AssertSql( """ -SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] -FROM [Squads] AS [s] +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` WHERE NOT EXISTS ( SELECT 1 FROM ( - SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], N'Gear' AS [Discriminator] - FROM [Gears] AS [g] + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` UNION ALL - SELECT [o].[Nickname], [o].[SquadId], [o].[AssignedCityName], [o].[CityOfBirthName], [o].[FullName], [o].[HasSoulPatch], [o].[LeaderNickname], [o].[LeaderSquadId], [o].[Rank], N'Officer' AS [Discriminator] - FROM [Officers] AS [o] - ) AS [t] - WHERE [s].[Id] = [t].[SquadId] AND [t].[FullName] = N'Anthony Carmine') + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` + ) AS `t` + WHERE `s`.`Id` = `t`.`SquadId` AND `t`.`FullName` = 'Anthony Carmine') """); } @@ -12834,18 +12834,18 @@ WHERE NOT EXISTS ( AssertSql( """ -SELECT [t].[Nickname], [t].[SquadId], [t].[AssignedCityName], [t].[CityOfBirthName], [t].[FullName], [t].[HasSoulPatch], [t].[LeaderNickname], [t].[LeaderSquadId], [t].[Rank], [t].[Discriminator] +SELECT `t`.`Nickname`, `t`.`SquadId`, `t`.`AssignedCityName`, `t`.`CityOfBirthName`, `t`.`FullName`, `t`.`HasSoulPatch`, `t`.`LeaderNickname`, `t`.`LeaderSquadId`, `t`.`Rank`, `t`.`Discriminator` FROM ( - SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], N'Gear' AS [Discriminator] - FROM [Gears] AS [g] + SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, 'Gear' AS `Discriminator` + FROM `Gears` AS `g` UNION ALL - SELECT [o].[Nickname], [o].[SquadId], [o].[AssignedCityName], [o].[CityOfBirthName], [o].[FullName], [o].[HasSoulPatch], [o].[LeaderNickname], [o].[LeaderSquadId], [o].[Rank], N'Officer' AS [Discriminator] - FROM [Officers] AS [o] -) AS [t] + SELECT `o`.`Nickname`, `o`.`SquadId`, `o`.`AssignedCityName`, `o`.`CityOfBirthName`, `o`.`FullName`, `o`.`HasSoulPatch`, `o`.`LeaderNickname`, `o`.`LeaderSquadId`, `o`.`Rank`, 'Officer' AS `Discriminator` + FROM `Officers` AS `o` +) AS `t` WHERE NOT EXISTS ( SELECT 1 - FROM [Weapons] AS [w] - WHERE [t].[FullName] = [w].[OwnerFullName] AND [w].[Name] = N'Hammer of Dawn') + FROM `Weapons` AS `w` + WHERE `t`.`FullName` = `w`.`OwnerFullName` AND `w`.`Name` = 'Hammer of Dawn') """); } diff --git a/test/EFCore.Jet.FunctionalTests/Query/TPTGearsOfWarQueryJetTest.cs b/test/EFCore.Jet.FunctionalTests/Query/TPTGearsOfWarQueryJetTest.cs index bdd33fc..a95c4da 100644 --- a/test/EFCore.Jet.FunctionalTests/Query/TPTGearsOfWarQueryJetTest.cs +++ b/test/EFCore.Jet.FunctionalTests/Query/TPTGearsOfWarQueryJetTest.cs @@ -10403,13 +10403,13 @@ WHERE NOT EXISTS ( AssertSql( """ -SELECT [s].[Id], [s].[Banner], [s].[Banner5], [s].[InternalNumber], [s].[Name] -FROM [Squads] AS [s] +SELECT `s`.`Id`, `s`.`Banner`, `s`.`Banner5`, `s`.`InternalNumber`, `s`.`Name` +FROM `Squads` AS `s` WHERE NOT EXISTS ( SELECT 1 - FROM [Gears] AS [g] - LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId] - WHERE [s].[Id] = [g].[SquadId] AND [g].[FullName] = N'Anthony Carmine') + FROM `Gears` AS `g` + LEFT JOIN `Officers` AS `o` ON `g`.`Nickname` = `o`.`Nickname` AND `g`.`SquadId` = `o`.`SquadId` + WHERE `s`.`Id` = `g`.`SquadId` AND `g`.`FullName` = 'Anthony Carmine') """); } @@ -10435,15 +10435,13 @@ WHERE NOT EXISTS ( AssertSql( """ -SELECT [g].[Nickname], [g].[SquadId], [g].[AssignedCityName], [g].[CityOfBirthName], [g].[FullName], [g].[HasSoulPatch], [g].[LeaderNickname], [g].[LeaderSquadId], [g].[Rank], CASE - WHEN [o].[Nickname] IS NOT NULL THEN N'Officer' -END AS [Discriminator] -FROM [Gears] AS [g] -LEFT JOIN [Officers] AS [o] ON [g].[Nickname] = [o].[Nickname] AND [g].[SquadId] = [o].[SquadId] +SELECT `g`.`Nickname`, `g`.`SquadId`, `g`.`AssignedCityName`, `g`.`CityOfBirthName`, `g`.`FullName`, `g`.`HasSoulPatch`, `g`.`LeaderNickname`, `g`.`LeaderSquadId`, `g`.`Rank`, IIF(`o`.`Nickname` IS NOT NULL, 'Officer', NULL) AS `Discriminator` +FROM `Gears` AS `g` +LEFT JOIN `Officers` AS `o` ON `g`.`Nickname` = `o`.`Nickname` AND `g`.`SquadId` = `o`.`SquadId` WHERE NOT EXISTS ( SELECT 1 - FROM [Weapons] AS [w] - WHERE [g].[FullName] = [w].[OwnerFullName] AND [w].[Name] = N'Hammer of Dawn') + FROM `Weapons` AS `w` + WHERE `g`.`FullName` = `w`.`OwnerFullName` AND `w`.`Name` = 'Hammer of Dawn') """); }