Description
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:
- Track prunability of inner joins on the expression itself #32674: moved out the "removable joins list".
- Move all pruning code to the pruner and make it an immutable visitor #32817: moved out all pruning logic to the pruning visitor.
- Redo query column/table relationship without TableReferenceExpression #32812: removed TableReferenceExpression and the private list tracking it.