efcore: Query: Simplify case blocks in SQL tree

Currently we translate CompareTo naively, using case statements with 3 options, however those can be significantly optimized for cases where CompareTo itself is compared to 1, 0 -1

foo.CompareTo(bar) == 0 -> foo == bar

example test: Double_order_by_on_string_compare

example current sql:

SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId]
FROM [Weapons] AS [w]
ORDER BY CASE
    WHEN (CASE
        WHEN ([w].[Name] = N'Marcus'' Lancer') AND [w].[Name] IS NOT NULL THEN 0
        WHEN [w].[Name] > N'Marcus'' Lancer' THEN 1
        WHEN [w].[Name] < N'Marcus'' Lancer' THEN -1
    END = 0) AND CASE
        WHEN ([w].[Name] = N'Marcus'' Lancer') AND [w].[Name] IS NOT NULL THEN 0
        WHEN [w].[Name] > N'Marcus'' Lancer' THEN 1
        WHEN [w].[Name] < N'Marcus'' Lancer' THEN -1
    END IS NOT NULL THEN CAST(1 AS bit)
    ELSE CAST(0 AS bit)
END, [w].[Id]

example improved sql:

SELECT [w].[Id], [w].[AmmunitionType], [w].[IsAutomatic], [w].[Name], [w].[OwnerFullName], [w].[SynergyWithId]
FROM [Weapons] AS [w]
ORDER BY CASE
    WHEN [w].[Name] = N'Marcus'' Lancer'
    THEN CAST(1 AS bit) ELSE CAST(0 AS bit)
END, [w].[Id]

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 2
  • Comments: 21 (21 by maintainers)

Commits related to this issue

Most upvoted comments

On the other hand, AFAIK an expression with NodeType=GreaterThan and string operands is never produced in C# (or even in VB.NET), which is why it makes sense for us not to support it…

Incorrect conclusion. string.Compare is a way to write a > b since you cannot write directly. We need to support it.

My main point here is that the simplification from string.Compare(a, b) == 0 to a == b (or if you prefer, for some reason, string.Equals(a,b)) can/should be universal to all providers (relational or not), which is why I think it belongs in pre-processing and not in post-processing - why repeat that for each provider type.

Re greater/less than, it seems odd to internally transform string.Compare(a,b) > 0 to a > b simply because that construct is never produced AFAIK in C# or VB. But if we want to do that, then like equality why not do this transformation in preprocessing (because again, it’s universal)?

Maybe a quick call would help clear this up.