Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Empty array in OrderBy generates invalid SQL #21108

Closed
perf2711 opened this issue Jun 2, 2020 · 2 comments
Closed

Empty array in OrderBy generates invalid SQL #21108

perf2711 opened this issue Jun 2, 2020 · 2 comments

Comments

@perf2711
Copy link

perf2711 commented Jun 2, 2020

When using .OrderBy() with predicate, which contains a call to .Contains() on an empty array, invalid SQL is generated and exception is thrown.

Steps to reproduce

Source code:

using Microsoft.EntityFrameworkCore;
using System;
using System.ComponentModel.DataAnnotations;
using System.Linq;

namespace EFReproduction
{
	class SampleEntity
	{
		[Key]
		public int Id { get; set; }
	}

	class SampleDbContext : DbContext
	{
		public SampleDbContext(DbContextOptions options) : base(options)
		{
		}

		public DbSet<SampleEntity> SampleEntities { get; set; }
	}

	class Program
	{
		static void Main(string[] args)
		{
			var options = new DbContextOptionsBuilder()
				.UseSqlServer("Server=localhost;Database=ef_repro;Trusted_Connection=True;MultipleActiveResultSets=True")
				.Options;

			using (var context = new SampleDbContext(options))
			{
				context.Database.EnsureCreated();

				var idArray = new[] { 1 } ;
				context.SampleEntities.OrderBy(e => idArray.Contains(e.Id)).ToArray(); // Working as intended

				var emptyIdArray = new int[0];
				context.SampleEntities.OrderBy(e => emptyIdArray.Contains(e.Id)).ToArray(); // Exception thrown
			}
		}
	}
}

Thrown exception:

Microsoft.Data.SqlClient.SqlException
  HResult=0x80131904
  Message=A constant expression was encountered in the ORDER BY list, position 1.
  Source=Core Microsoft SqlClient Data Provider
  StackTrace:
   at Microsoft.Data.SqlClient.SqlConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at Microsoft.Data.SqlClient.SqlInternalConnection.OnError(SqlException exception, Boolean breakConnection, Action`1 wrapCloseInAction)
   at Microsoft.Data.SqlClient.TdsParser.ThrowExceptionAndWarning(TdsParserStateObject stateObj, Boolean callerHasConnectionLock, Boolean asyncClose)
   at Microsoft.Data.SqlClient.TdsParser.TryRun(RunBehavior runBehavior, SqlCommand cmdHandler, SqlDataReader dataStream, BulkCopySimpleResultSet bulkCopyHandler, TdsParserStateObject stateObj, Boolean& dataReady)
   at Microsoft.Data.SqlClient.SqlDataReader.TryConsumeMetaData()
   at Microsoft.Data.SqlClient.SqlDataReader.get_MetaData()
   at Microsoft.Data.SqlClient.SqlCommand.FinishExecuteReader(SqlDataReader ds, RunBehavior runBehavior, String resetOptionsString, Boolean isInternal, Boolean forDescribeParameterEncryption, Boolean shouldCacheForAlwaysEncrypted)
   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReaderTds(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, Boolean isAsync, Int32 timeout, Task& task, Boolean asyncWrite, Boolean inRetry, SqlDataReader ds, Boolean describeParameterEncryptionRequest)
   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, TaskCompletionSource`1 completion, Int32 timeout, Task& task, Boolean& usedCache, Boolean asyncWrite, Boolean inRetry, String method)
   at Microsoft.Data.SqlClient.SqlCommand.RunExecuteReader(CommandBehavior cmdBehavior, RunBehavior runBehavior, Boolean returnStream, String method)
   at Microsoft.Data.SqlClient.SqlCommand.ExecuteReader(CommandBehavior behavior)
   at Microsoft.Data.SqlClient.SqlCommand.ExecuteDbDataReader(CommandBehavior behavior)
   at System.Data.Common.DbCommand.ExecuteReader()
   at Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReader(RelationalCommandParameterObject parameterObject)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.InitializeReader(DbContext _, Boolean result)
   at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.Execute[TState,TResult](TState state, Func`3 operation, Func`3 verifySucceeded)
   at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.MoveNext()
   at System.Collections.Generic.LargeArrayBuilder`1.AddRange(IEnumerable`1 items)
   at System.Collections.Generic.EnumerableHelpers.ToArray[T](IEnumerable`1 source)
   at System.Linq.Enumerable.ToArray[TSource](IEnumerable`1 source)
   at EFReproduction.Program.Main(String[] args) in C:\Users\Seba\Documents\Projekty\Pierdolki\EFReproduction\Program.cs:line 39

  This exception was originally thrown at this call stack:
    [External Code]
    EFReproduction.Program.Main(string[]) in Program.cs

SQL response:

Msg 408, Level 16, State 1, Line 1
A constant expression was encountered in the ORDER BY list, position 1.

Generated SQL with non-empty array:

SELECT [s].[Id]
FROM [SampleEntities] AS [s]
ORDER BY CASE
    WHEN [s].[Id] IN (1) THEN CAST(1 AS bit)
    ELSE CAST(0 AS bit)
END

Generated SQL with empty array:

SELECT [s].[Id]
FROM [SampleEntities] AS [s]
ORDER BY CASE
    WHEN CAST(1 AS bit) = CAST(0 AS bit) THEN CAST(1 AS bit)
    ELSE CAST(0 AS bit)
END

It seems that when the array is empty, CAST(1 AS bit) = CAST(0 AS bit) THEN CAST(1 AS bit) is generated, which is a constant expression, thus throwing the exception.

Further technical details

EF Core version: 3.1.4
Database provider: Microsoft.EntityFrameworkCore.SqlServer 3.1.4 (Microsoft SQL Server 2017 Express)
Target framework: .NET Core 3.1
Operating system: Windows 10 1903
IDE: Visual Studio 2019 16.5.1

@ajcvickers
Copy link
Contributor

@smitpatel to find dupe

@smitpatel
Copy link
Contributor

Duplicate of #15713

@smitpatel smitpatel marked this as a duplicate of #15713 Jun 5, 2020
@ajcvickers ajcvickers reopened this Oct 16, 2022
@ajcvickers ajcvickers closed this as not planned Won't fix, can't repro, duplicate, stale Oct 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants