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

Query: Assign aliases to tables differently #17337

Closed
smitpatel opened this issue Aug 21, 2019 · 13 comments
Closed

Query: Assign aliases to tables differently #17337

smitpatel opened this issue Aug 21, 2019 · 13 comments
Assignees
Labels
area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. punted-for-3.1 punted-for-5.0 type-bug
Milestone

Comments

@smitpatel
Copy link
Member

smitpatel commented Aug 21, 2019

A selectExpression contains projections & other constructs, which refers to tables in that select expression. When visiting children of select expression if that table is updated then it causes re-generation for each node using it. Hence the constraint is violated. While it has low functional impact but it means that we need to do deep equals every time we want to compare. Ideally, VisitChildren should take care of re-connecting nodes.

@ajcvickers ajcvickers added this to the Backlog milestone Aug 23, 2019
@smitpatel smitpatel changed the title Query: SelectExpression loses referential integrity upon recreation Query: SelectExpression loses referential integrity to outer upon recreation Sep 4, 2019
@roji
Copy link
Member

roji commented Sep 4, 2019

This also has an important perf aspect, since we're visiting the same TableExpressions via both projections and tables. #17455 shows an extreme, exponential effect where only 7 includes cause over 20 seconds of query compilation time.

Clearing milestone to consider for 3.1.

@NetTecture
Copy link

"Clearing milestone to consider for 3.1." - unless you plan to pass 3.1 within 4 weeks of 3.0 or so that means for me and a lot of people like me EFCore is totally absolutely UNUSABLE because we DO have 10+ includes in large parts of our application and if you go from "instant compilation" to "minutes" that is a regression that is NOT ready even for development.

@roji
Copy link
Member

roji commented Sep 6, 2019

Any objection to me poaching this @smitpatel?

@smitpatel
Copy link
Member Author

Yes. I will fix this.

@smitpatel
Copy link
Member Author

@roji - If you have ideas around it and want to work on this, then please schedule a meeting and bring a design. I want to avoid you doing work and then having to discard because of lack of communication around complexity and areas this would touch.

@roji
Copy link
Member

roji commented Sep 8, 2019

At least as a first step, the idea was simply to collect old to new table mappings as we visit SelectExpression.Tables, and then use ReplacingExpressionVisitor on each query component before visiting it. You've already removed visitation in ColumnExpression in #17651, so unless we have other forms of references to tables from within query constructs, it seems like it should take care of it. Am I missing other aspects?

@smitpatel
Copy link
Member Author

How would you do it if Visitation of SelectExpression is outside of your control? i.e. what if SelectExpression.VisitChildren is not used?

@roji
Copy link
Member

roji commented Sep 8, 2019

At least for 3.1, where we're still doing low-risk bugfixes only, it may be enough to identify current visitors which visit SelectExpression themselves and apply the same logic (e.g. SearchConditionConvertingExpressionVisitor, not sure if there are others). This is similar to what you've done in #17651 - we no longer visit tables via ColumnExpressions but badly-written visitors may still do that.

A more extreme approach would be to factor out the various visitations from VisitChildren (e.g. VisitProjections, VisitPredicate), and not allow SqlExpressionVisitor subclasses to override VisitSelect, locking down the correct behavior. Since we have very little visitors at the moment, it's difficult to know whether that would prevent useful/legitimate overriding scenarios, so it doesn't seem right (or at least premature). Even if we do this, it's always possible for a visitor to extend ExpressionVisitor directly and mess up a SelectExpression in various ways.

Finally, we can add a verification (debug-only?) visitor at end of postprocessing to verify that referential integrity is maintained, to catch any bugs (like SqlTypeMappingVerifyingExpressionVisitor for missing type mappings).

But if I'm missing something or if you have something different in mind for 3.1 we can just have a conversation about it.

@smitpatel
Copy link
Member Author

None of those fixes the crux of the issue. While they resolve things for internal visitors, they still leave scope for external ones to do things incorrectly. If that is what we are heading at (fixing for internal visitors), then the solution we have in codebase right now is good enough.

There are altogether different ideas how to deal with this so that this problem does not arise in first place. Hence my hesitance over this issue being poachable.

@roji
Copy link
Member

roji commented Sep 9, 2019

If that is what we are heading at (fixing for internal visitors), then the solution we have in codebase right now is good enough.

Unless I'm mistaken, #17651 doesn't fix the referential integrity issue in any way - only the perf issue (by skipping visitation in ColumnExpression) - so in the current codebase, ColumnExpressions currently point to potentially old tables which may have been replaced by visitors. It seems to me that this is well worth fixing in 3.1 regardless of external visitors, but I may be mistaken (i.e. there may not be an actual problem caused by this at the moment).

An airtight solution with regards to external visitors would lock down access to SelectExpression.Tables, so that if a visitor wants to replace a table they'd have through a special method on SelectExpression (e.g. ReplaceTable), which would also perform the replacement in all query components. Depending on how far we want to go, we may also want to prevent the possibility of a visitor to replace a ColumnExpression with another that refers to another table (TableExpression and SelectExpression have internal-only constructors, but not set operations). I assumed such design changes would be a too much for 3.1, but again maybe you see things differently.

I'm fine discussing what to do, or if you prefer I can leave this issue to you.

smitpatel added a commit that referenced this issue Mar 22, 2021
…or referential integrity

Part of #17337

- Add TableReferenceExpression
- SelectExpression contains tableReferenceExpression for each table added
- TableReferenceExpression can identify the table by querying the selectExpression
- During pushdown and set operation we update the table references as the selectExpression where columns belong is changing
- Whenever adding something to selectExpression, we assign unique alises if there is nested selectExpression
- Improve identifier detection for Distinct/GroupBy cases
- Pushdown internally gives a visitor to update the expression being added in terms of new column expressions
- Copy proper identifiers when applying set operation
- Make dictionary being passed around in query IReadOnlyDictionary
- Move entityProjectionCache from QueryExpression to ProjectionBindingExpressionVisitor as it is not an internal state for QueryExpression. It existing only in the context of applying particular projection mapping once.
- Remove TableAliasUniquifyingExpressionVisitor, added debug only (currently disabled) TableAliasVerifyingExpressionVisitor which verifies that all alises are unique and used in order.
smitpatel added a commit that referenced this issue Mar 22, 2021
smitpatel added a commit that referenced this issue Mar 22, 2021
…or referential integrity

Part of #17337

- Add TableReferenceExpression
- SelectExpression contains tableReferenceExpression for each table added
- TableReferenceExpression can identify the table by querying the selectExpression
- During pushdown and set operation we update the table references as the selectExpression where columns belong is changing
- Whenever adding something to selectExpression, we assign unique alises if there is nested selectExpression
- Improve identifier detection for Distinct/GroupBy cases
- Pushdown internally gives a visitor to update the expression being added in terms of new column expressions
- Copy proper identifiers when applying set operation
- Make dictionary being passed around in query IReadOnlyDictionary
- Move entityProjectionCache from QueryExpression to ProjectionBindingExpressionVisitor as it is not an internal state for QueryExpression. It existing only in the context of applying particular projection mapping once.
- Remove TableAliasUniquifyingExpressionVisitor, added debug only (currently disabled) TableAliasVerifyingExpressionVisitor which verifies that all alises are unique and used in order.
smitpatel added a commit that referenced this issue Mar 22, 2021
smitpatel added a commit that referenced this issue Mar 23, 2021
Once query start doing client eval, if there are operators afterwards which are binding to index in Projection list, now we translate it if we get the ProjectionBindingExpression.
We cannot translate the part which is generated by client

Some cleanup for #17337
smitpatel added a commit that referenced this issue Mar 23, 2021
smitpatel added a commit that referenced this issue Mar 23, 2021
Part of #17337

This commit doesn't make any functional change. Just moved code around for better organization and made certain private functions local static functions
smitpatel added a commit that referenced this issue Mar 23, 2021
smitpatel added a commit that referenced this issue Mar 23, 2021
…or referential integrity

- Add TableReferenceExpression
- SelectExpression contains tableReferenceExpression for each table added
- TableReferenceExpression can identify the table by querying the selectExpression
- During pushdown and set operation we update the table references as the selectExpression where columns belong is changing
- Whenever adding something to selectExpression, we assign unique alises if there is nested selectExpression
- Improve identifier detection for Distinct/GroupBy cases
- Pushdown internally gives a visitor to update the expression being added in terms of new column expressions
- Copy proper identifiers when applying set operation
- Make dictionary being passed around in query IReadOnlyDictionary
- Move entityProjectionCache from QueryExpression to ProjectionBindingExpressionVisitor as it is not an internal state for QueryExpression. It existing only in the context of applying particular projection mapping once.
- Remove TableAliasUniquifyingExpressionVisitor, added debug only (currently disabled) TableAliasVerifyingExpressionVisitor which verifies that all alises are unique and used in order.

Resolves #17337
smitpatel added a commit that referenced this issue Mar 23, 2021
smitpatel added a commit that referenced this issue Mar 23, 2021
Part of #17337

This commit doesn't make any functional change. Just moved code around for better organization and made certain private functions local static functions
smitpatel added a commit that referenced this issue Mar 23, 2021
…or referential integrity

- Add TableReferenceExpression
- SelectExpression contains tableReferenceExpression for each table added
- TableReferenceExpression can identify the table by querying the selectExpression
- During pushdown and set operation we update the table references as the selectExpression where columns belong is changing
- Whenever adding something to selectExpression, we assign unique alises if there is nested selectExpression
- Improve identifier detection for Distinct/GroupBy cases
- Pushdown internally gives a visitor to update the expression being added in terms of new column expressions
- Copy proper identifiers when applying set operation
- Make dictionary being passed around in query IReadOnlyDictionary
- Move entityProjectionCache from QueryExpression to ProjectionBindingExpressionVisitor as it is not an internal state for QueryExpression. It existing only in the context of applying particular projection mapping once.
- Remove TableAliasUniquifyingExpressionVisitor, added debug only (currently disabled) TableAliasVerifyingExpressionVisitor which verifies that all alises are unique and used in order.

Resolves #17337
@smitpatel smitpatel added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Mar 23, 2021
smitpatel added a commit that referenced this issue Mar 23, 2021
smitpatel added a commit that referenced this issue Mar 24, 2021
- Don't apply Include on entities with Include already applied
- Update table references when pushing down select into left for set operation
- Update identifiers after applying set operation if the projection removed exiting identifiers
- Update SQL references in pending collection during push down

Fix for the repro in #17337
Resolves #18738
Resolves #19763
Resolves #19947
Resolves #20813
Resolves #21026
Resolves #22222
Resolves #23676
Resolves #23720
smitpatel added a commit that referenced this issue Mar 24, 2021
- Don't apply Include on entities with Include already applied
- Update table references when pushing down select into left for set operation
- Update identifiers after applying set operation if the projection removed exiting identifiers
- Update SQL references in pending collection during push down

Fix for the repro in #17337
Resolves #18738
Resolves #19763
Resolves #19947
Resolves #20813
Resolves #21026
Resolves #22222
Resolves #23676
Resolves #23720
Resolves #24216
smitpatel added a commit that referenced this issue Mar 24, 2021
smitpatel added a commit that referenced this issue Mar 24, 2021
- Don't apply Include on entities with Include already applied
- Update table references when pushing down select into left for set operation
- Update identifiers after applying set operation if the projection removed exiting identifiers
- Update SQL references in pending collection during push down

Fix for the repro in #17337
Resolves #18738
Resolves #19763
Resolves #19947
Resolves #20813
Resolves #21026
Resolves #22222
Resolves #23676
Resolves #23720
Resolves #24216
smitpatel added a commit that referenced this issue Mar 25, 2021
smitpatel added a commit that referenced this issue Mar 25, 2021
- Don't apply Include on entities with Include already applied
- Update table references when pushing down select into left for set operation
- Update identifiers after applying set operation if the projection removed exiting identifiers
- Update SQL references in pending collection during push down

Fix for the repro in #17337
Resolves #18738
Resolves #19763
Resolves #19947
Resolves #20813
Resolves #21026
Resolves #22222
Resolves #23676
Resolves #23720
Resolves #24216
smitpatel added a commit that referenced this issue Mar 25, 2021
- Don't apply Include on entities with Include already applied
- Update table references when pushing down select into left for set operation
- Update identifiers after applying set operation if the projection removed exiting identifiers
- Update SQL references in pending collection during push down

Fix for the repro in #17337
Resolves #18738
Resolves #19763
Resolves #19947
Resolves #20813
Resolves #21026
Resolves #22222
Resolves #23676
Resolves #23720
Resolves #24216
@ajcvickers ajcvickers modified the milestones: 6.0.0, 6.0.0-preview3 Mar 25, 2021
@ajcvickers ajcvickers modified the milestones: 6.0.0-preview3, 6.0.0 Nov 8, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-query closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. punted-for-3.1 punted-for-5.0 type-bug
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants