14.0.1: a join condition means the same thing whichever way round it is written - #226
Merged
Merged
Conversation
…is written Two defects a client found by being used, both in the planner, neither reachable from the SQL the suite happens to write. ON c.Id = o.CustomerId returned rows; ON o.CustomerId = c.Id - the same condition, the same two tables - failed with Column 'CustomerId' not found. The equi-join key pair was built from the ORDER THE CONDITION WAS WRITTEN IN, never from where the columns come from, so the hash join looked for the right table's column in rows of the left one. It now reads the left input's schema, which is a required parameter of Analyze so the question is asked at every call site, and orients each pair. Where the engine does not know which side a column is on the written order still decides, and that branch is deliberate: an INFORMATION_SCHEMA source reports no table name, such a join resolves a qualified name by column name anyway, and treating it as "neither is from the left" turned Studio's primary-key query into a cross product. Five Studio cases went red before that branch existed - which is the whole reason the provider suites are run before a release rather than after it. EXPLAIN gave the right input's child the wrong parent: each child's subtree was re-based by a constant instead of by where that subtree starts, so everything below the SECOND child of any node was attributed into the first child's subtree. A join has two children, and so does every set operation. Anything drawing the plan as a tree drew the wrong tree faithfully. Both guards assert the surface rather than the case: the two orders agree ROW FOR ROW across inner, left, chained, aliased, unaliased, composite-key and residual-beside-key shapes, with a control that the hash join is the path being taken; and each ALIAS stands over the scan of the table it aliases, with both arms of a UNION keeping their own children. Seven and three cases go red respectively when the fixes are reverted. Engine 2563, AdoNet 1054, Studio 1030 - green. Seven packages packed and read: all at 14.0.1, every internal dependency at 14.0.1. Known issues 25 and 26 are marked fixed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Eight snippets across five READMEs still said 14.0.0. Caught by ShippedReadmesTests, which exists because five READMEs once installed 12.8.0 while the packages were at 13.x - a README goes inside the package, so it reaches people who never open the repository. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two defects a client found by being used, both in the planner, neither reachable from the SQL the suite happens to write. Known issues 25 and 26 are marked fixed by this.
25. The join condition
The equi-join key pair was built as
LeftKey = binary.Left, RightKey = binary.Right- the order the condition was written in, never where the columns come from. The extractor checked that the two references named different tables and stopped there, so the hash join looked for the right table's column in rows of the left one. In a chain the trap is easier to fall into, because "the left input" is everything joined so far.It now reads the left input's schema - a required parameter of
OptimizerJoinCondition.Analyze, so the compiler asks the question at every call site - and orients each pair.One branch is deliberately unchanged: where the engine does not know which side a column is on, the written order still decides. An
INFORMATION_SCHEMAsource reports no table name; such a join resolves a qualified name by column name anyway, and reading it as "neither is from the left" turned Studio's primary-key query into a cross product - five Studio cases went red before that branch was written. That is what running the provider suites before a release is for.26.
EXPLAINEach child's subtree was re-based by a constant instead of by where that subtree starts, so everything below the second child of any node was attributed into the first child's subtree. A join has two children, and so does every set operation:
Anything drawing the plan as a tree drew the wrong tree faithfully.
The guards assert the surface, not the case
JoinKeysBelongToTheirOwnSideTests- the two orders agree row for row across inner, left, chained, aliased, unaliased, composite-key and residual-beside-key shapes, plus the condition moved toWHERE. Controls: the plan actually says HASH (a nested loop has never cared which way round the condition is), and the joins match rows. Seven of ten go red with the orientation removed. Two of its cases passed for the wrong reason until the two sides were given different column names - a mis-oriented key still resolved by name.APlanNodeNamesItsRealParentTests- eachALIASstands over the scan of the table it aliases; both arms of aUNIONkeep their own children; one root and every parent a real earlier line. Three of four go red with the offset reverted. The purely structural case passes on both versions, which is why it is not the assertion.Verified
14.0.1, every internalOutWit.Database*dependency at14.0.1.🤖 Generated with Claude Code