-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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
Custom aggregate method translation #23524
Conversation
What is the purpose of this change? Can you please elaborate on following topics as I am not able to understand how those issues are solved in this PR.
I don't see any value of the new visitor, it feels more like refactoring plus there is negative cost associated with it since SqlTranslator can perform the same task today only. Right now this PR seems to going Into the unknown |
The main point is that currently all GroupBy aggregate logic is very hard to override (it's all logic embedded inside SqlTranslatingEV.VisitMethod). With this visitor, it's easy for a provider to just inherit from it, override VisitMethodCall and add the methods they want. Note also that this allow overriding the behavior for the built-in operators (Max/Sum...) by splitting them out to their own methods, but SqlTranslatingEV already has TranslateMax/TranslateSum which only do the minimum work of generating the SqlFunctionExpression etc. So assuming we want overridability for GroupBy aggregate logic of built-in operators, I'm not sure what those methods would be named. Finally, it's true that it's possible to achieve the same by extracting the logic out to a separate method on SqlTranslatingEV instead of to a different visitor - in that sense this isn't strictly necessary, and does contain an element of refactoring. Though that's not necessarily a bad thing - SqlTranslatingEV is pretty massive as-is, and it didn't seem like a bad idea to move GroupBy aggregate logic out to a separate component. Do you see a disadvantage in this approach? |
Yes, it does not provide any additional extensibility and it adds more decision points. Further, ability to override handling of Select/Where/Distinct (or any other operator) applied on Grouping is not required and not sure what different behavior it could achieve and it is orthogonal to support for additional aggregate operators. It will most likely end up being YAGNI. |
But if you feel that strongly against this refactoring - which really seems quite straightforward and without any disadvantages - I can go do something else. |
This refactoring indeed have disadvantages at this point. Mainly it does not solve the issue of extensibility at all which is the main reason to make any changes in this area. If we add this additional visitor right now then it would be additional public surface. When we really try to solve issue of custom aggregate method translation then there could be 3 possibilities
To me in 67% of cases this refactoring is not useful at least until we have solved the main issue first. I strongly feel that doing this refactoring without solving the issue of custom aggregate methods basically puts us in a corner in terms of adding support for them in future and hinders our creativity in terms of arriving at ideal solution for it. |
As a semi-outsider to this part of the codebase, I disagree. I found it quite hard to find my way.
Agreed.
We really are discussing whether the code should be refactored into a protected method in the same class (SqlTranslator), or out into a protected method in another class (a new visitor) - it really is mainly a matter of factoring the code grouping functions that belong together in coherent types. I don't understand what decision points mean here - if a method is on the same visitor or on another doesn't seem to matter to me.
I don't see the perf aspect here, but maybe I'm missing something. Whether we call Visit on SqlTranslator on Visit on GroupingTranslator doesn't make any difference.
Inheriting/implementing the standard ExpressionVisitor is one thing; adding new stuff that's specific to GroupBy aggregate translation is different (GetExpressionForAggregation, RemapLambda). Now any provider writer who's interacting with SqlTranslator sees them (e.g. Intellisense) and must understand if they need to deal with them, whether they're interested in custom aggregates or not. Trust me, as a provider writer the query pipeline can be quite confusing as it is.
As I wrote above, this is first step before tackling the main parts around extensibility. The fact that the refactoring itself doesn't solve the issue doesn't mean it's bad. However... let me save us all time and ASCII characters and leave you to do this work, assuming you feel it's important. You obviously have a very clear idea of how you want the codebase to look like, and I'd rather not waste time on this. |
You have right to disagree though I don't feel your points are changing anything fundamental in what I have written above. |
@roji It seems to me that one way to measure the value here is to compare what the provider code looks like with and without this change. Is it possible to see what the provider PR would look like in each case? |
Following up off-line. |
This starts work on translating custom GroupBy aggregate methods (#22957). For now, the current hard-wired logic for GroupBy aggregate operators (Min/Max/Sum...) has been refactored out of RelationalSqlTranslatingExpressionVisitor to a new RelationalGroupingTranslatingExpressionVisitor, which could be extended by providers.
@smitpatel if you approve of the general direction, I'll continue and look into making GroupingExpression more suitable for usage by providers etc.
(note this is a draft, it's too early for nits/docs)