-
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
Remove SelectExpression private logic out to the translation visitors, making it a minimal, regular expression node #31049
Comments
Similar example: in postprocessing, we have SelectExpressionPruningExpressionVisitor which calls SelectExpression.Prune, which removes unreferenced projected columns from SelectExpression. Ideally we'd also remove e.g. the OPENWITH WITH fragments for unused columns. This would mean the logic needs to move out to the visitor, which the SQL Server provider would then override and augment. Note that the current architecture - where the logic is encapsulated inside SelectExpression rather than inside a real visitor - also leads to pruning not working well, see #31083. |
Another case: when we add a translated SqlExpression to a SelectExpression (e.g. as a predicate), we call AssignUniqueAliases on it; this runs the AliasUniquifier visitor on it, taking the SelectExpression's _usedAliases into account, and uniquifies any aliases within the SqlExpression. However, #31078 was filed because we weren't performing that uniquification on SqlExpressions in UPDATE setters. Since these aren't on SelectExpression, AssignUniqueAliases was made pubternal so it could be called from RelationalQueryableMethodTranslatingEV. If the used aliases were kept as state on RelationalQueryableMethodTranslatingEV (instead of inside SelectExpression), we could also implement this as part of translation rather than doing an additional visitation on each SqlExpression just for alias uniquification. |
Instead of on a private list on SelectExpression. Part of dotnet#31049
Instead of on a private list on SelectExpression. Part of dotnet#31049
Instead of on a private list on SelectExpression. Part of dotnet#31049
Instead of on a private list on SelectExpression. Part of #31049
Another difficulty created by having logic inside SelectExpression: since table alises need to be created e.g. when performing pushdown, and the pushdown logic is implemented inside SelectExpression, SelectExpression needs to always have access to SqlAliasManager. At the same time, for precompiled queries, we need to be able to generate a SQL tree in code - in user interceptors - for cases where the 2nd part of the query pipeline (e.g. SqlNullabilityProcessor) needs to be invoked in realtime (SQL cache disabled, or two many parameters). But making services such as SqlAliasManager available to SelectExpression in generated interceptor code is complicated (requires a liftable constant etc.). SelectExpression really does need to just be a pure expression, just like any other expression type, and not contain logic. |
SelectExpression is currently a non-extensible type with private state, and code closed behind APIs such as ApplyDistinct, ClearOrderings etc. which are invoked from e.g. RelationalQueryableMethodTranslatingExpressionVisitor. This makes it impossible to extend the logic in providers.
As an example, during translation we currently create a SQL Server OPENWITH/WITH expression, with an ordering to preserve the JSON array's natural ordering. We then have a post-processing visitor which detects if the ordering is still there, and replaces OPENWITH/WITH with OPENWITH without WITH (since OPENWITH/WITH doesn't support natural ordering). A better design here would be to create the ordered version (without WITH), and when ClearOrderings is called (e.g. because IN/EXISTS/COUNT are applied), transform the OPENWITH at that point.
But since ClearOrderings() is a SelectExpression API, we cannot override it and add this SQL Server-specific logic. If the ClearOrderings() logic were moved to RelationalQueryableMethodTranslatingEV, we could - but that would also require moving out all SelectExpression logic which depends on it (e.g. ApplyDistinct). We'd need to very carefully consider SelectExpression's private state, and whether that remains on SelectExpression (with specific APIs to manipulate it), or whether it moves to the visitor as well.
Note that we have other examples where we visit the query tree in pre-processing - we ideally shouldn't need to do that, but rather perform the function as part of translation.
Work:
The text was updated successfully, but these errors were encountered: