From df2265d7d82a9fff81b5ac6de818118db0fc0df1 Mon Sep 17 00:00:00 2001 From: Dmitry Ratner <6830384+dmitrat@users.noreply.github.com> Date: Wed, 19 Aug 2026 13:53:03 +0300 Subject: [PATCH] Studio 3.1.1: four corrections, three of them to what 3.1.0 broke Found the day 3.1.0 shipped, by using it. - the double click on a table opens its data again - and had done nothing at all since the repair meant to fix it registered a handler on a route DoubleTapped does not travel; - it no longer opens the row as well; - a double click on the connection opens the tab that describes the database, which is the same rule rather than a fourth exception; - the context menu draws no rule with nothing beside it, on any of the fourteen kinds of node; - the status line takes back what is no longer true. Engine 14.0.0, unchanged. Known issues gains three entries, and this is the part worth reading. Two engine defects were found in the same pass and are NOT fixed here, because the engine did not move: a join condition written ON right.x = left.y is refused outright, with the root cause named down to the line that pairs the keys by written order; and EXPLAIN gives the right input's child the wrong parent, so anything that draws the plan as a tree draws the wrong tree faithfully. The third entry is a gap in Studio itself - a routine in the tree can only be refreshed, though the engine has DROP FUNCTION and the catalogue already carries the body. Studio: 1030 green. Co-Authored-By: Claude Opus 5 --- Docs/KnownIssues.md | 94 +++++++++++++++++++ Tools/OutWit.Database.Studio/CHANGELOG.md | 42 +++++++++ .../OutWit.Database.Studio.csproj | 2 +- 3 files changed, 137 insertions(+), 1 deletion(-) diff --git a/Docs/KnownIssues.md b/Docs/KnownIssues.md index a0a9854..34c10c2 100644 --- a/Docs/KnownIssues.md +++ b/Docs/KnownIssues.md @@ -1520,6 +1520,100 @@ that does not exist. --- +## Found by clicking through Studio before 3.1.1, 2026-08-19 + +Both of the engine entries below were reproduced against a bare `WitSqlEngine` over an in-memory +database, with no Studio in the picture. The third is a gap in Studio itself, recorded here +because a person meeting it will look for it here. + +--- + +## 25. A join condition written the other way round is refused + +> Measured 2026-08-19 on engine 14.0.0. **Root cause identified**, fix not written. + +In `A JOIN B ON x = y`, the column of the LEFT input has to be written FIRST. Written the other +way, the query fails at execution with a `KeyNotFoundException`: + +```sql +SELECT c.Country, o.Total FROM Customers c JOIN Orders o ON c.Id = o.CustomerId -- 3 rows +SELECT c.Country, o.Total FROM Customers c JOIN Orders o ON o.CustomerId = c.Id -- Column 'CustomerId' not found +SELECT Customers.Country FROM Customers JOIN Orders + ON Orders.CustomerId = Customers.Id -- the same, without aliases +``` + +**In a chain of joins, "the left input" is everything joined so far**, which is the shape most +likely to be met by accident: + +```sql +SELECT c.Country FROM Customers c JOIN Orders o ON c.Id = o.CustomerId + JOIN Items i ON i.OrderId = o.Id -- Column 'OrderId' not found +``` + +**Root cause.** `Optimizers/OptimizerJoinCondition.TryExtractEquiJoinKey` builds the key pair as +`LeftKey = binary.Left, RightKey = binary.Right` - it takes **the written order of the equality** +for the order of the join inputs. It checks that the two column references carry different table +qualifiers and never checks WHICH input each belongs to, so `IteratorHashJoin.ComputeHashKey` +evaluates the right table’s column against rows of the left one and the evaluator throws. + +**Where a fix belongs:** `Query/QueryPlanner.Sources.cs`, `CreateJoinIterator` - it already holds +both input iterators and therefore both schemas, so each pair can be oriented before the iterator +is built. Unqualified columns are already sent to the residual condition, so only the qualified +case needs it. + +**What was measured, and what it means for a workaround:** + +| written as | result | +|---|---| +| `INNER JOIN ... ON left.x = right.y` | works | +| `INNER JOIN ... ON right.y = left.x` | **fails** | +| `LEFT JOIN ... ON right.y = left.x` | works | +| `FROM a, b WHERE right.y = left.x` | works | + +So: **write the left side’s column first**, or put the condition in `WHERE` with a comma join. +The failure is in the hash-join path, and the planner chose a hash join even for two-row tables. + +**Why the suite never saw it:** every JOIN case in the engine writes the equality in the same +order. + +--- + +## 26. `EXPLAIN` gives the right input’s child the wrong parent + +> Measured 2026-08-19 on engine 14.0.0. + +For `SELECT c.Country, o.Total FROM Customers c JOIN Orders o ON c.Id = o.CustomerId LIMIT 3`, +`EXPLAIN` answers: + +``` +id parent detail +0 -1 LIMIT +1 0 PROJECT +2 1 HASH INNER JOIN +3 2 ALIAS c +4 3 SCAN TABLE Customers +5 2 ALIAS o +6 3 SCAN TABLE Orders <- parent should be 5 +``` + +`SCAN TABLE Orders` is reported as a child of `ALIAS c`. Anything that draws the plan as a tree - +Studio’s Plan panel does - draws the wrong tree, faithfully. **The renderer is not the defect.** + +--- + +## 27. Studio: a function or a procedure can only be refreshed + +> Studio 3.1.1. A gap rather than a wrong answer. + +The tree’s context menu offers a routine exactly one item, `Refresh`. The engine has +`DROP FUNCTION` and `DROP PROCEDURE`, and the catalogue already carries the routine’s body - the +inspector on the right shows it - so both *View definition* and *Drop* are possible and neither is +offered. Every other kind of object in the tree was given its own menu in 3.1.0; routines were not +included. + +Until they are: drop a routine by running the statement in a query tab. + +--- ## Verifying a fix WitAnalytics is a ready-made regression harness: its stats test fixture runs the diff --git a/Tools/OutWit.Database.Studio/CHANGELOG.md b/Tools/OutWit.Database.Studio/CHANGELOG.md index e5d9a08..d3f0c6d 100644 --- a/Tools/OutWit.Database.Studio/CHANGELOG.md +++ b/Tools/OutWit.Database.Studio/CHANGELOG.md @@ -3,6 +3,48 @@ Studio is versioned separately from the WitDatabase engine and released under its own `studio-v*` tag. The engine's changelog is `/CHANGELOG.md`. +## 3.1.1 + +**Four corrections, three of them to things 3.1.0 itself broke.** They were found the day 3.1.0 +shipped, by using it. + +Engine: 14.0.0, unchanged. + +### The double click works again + +A double click on a table opens its data. It had done nothing at all since the repair that was +meant to fix it: `DoubleTapped` travels `Bubble` alone, `AddHandler` takes the route as a plain +argument and cannot refuse an impossible one, so the handler was registered on a route the event +does not travel and was never called - through a green suite, a green CI and a signed release. The +double click is now read from the pointer, which does tunnel. + +The row no longer opens as well: handling the press does not stop the tap, so the tree still +toggled itself, and a table both opened its data and opened its row. + +**And a double click on the connection now opens the tab that describes the database** - the same +one *Database…* opens in the menu. One rule rather than three exceptions: a double click opens the +thing the node IS. Which node opens what moved out of the code-behind, where no test could read +it. + +### The menu draws no rule with nothing beside it + +Giving each node its own menu taught every ITEM to hide itself where it does not apply, and left +the five separators drawing the shape of a menu that is no longer there: a connection got two +rules with nothing between them and two more below its last item, a folder began with a rule, a +column was one command wrapped in five. All fourteen kinds of node were wrong, the table included. + +### The status line takes back what is no longer true + +With no editor open anywhere the line still read *Editing table: Products*. What HAPPENED stays - +«executed in 9 ms» is true afterwards - but what IS ends with the tab it belongs to. + +### Known issues + +Two engine defects were found in the same pass and are **not** fixed here, because the engine did +not move: a join condition written `ON right.x = left.y` is refused, and `EXPLAIN` gives the right +input’s child the wrong parent. Both are written up with their root cause in +[Docs/KnownIssues.md](../../Docs/KnownIssues.md) as issues 25 and 26; issue 27 is a gap in Studio +itself - a routine in the tree can only be refreshed. ## 3.1.0 **Forty-six findings, and what looking for them turned up.** Taking the screenshots for the diff --git a/Tools/OutWit.Database.Studio/OutWit.Database.Studio.csproj b/Tools/OutWit.Database.Studio/OutWit.Database.Studio.csproj index b4a5ade..03b2450 100644 --- a/Tools/OutWit.Database.Studio/OutWit.Database.Studio.csproj +++ b/Tools/OutWit.Database.Studio/OutWit.Database.Studio.csproj @@ -18,7 +18,7 @@ - 3.1.0 + 3.1.1 WitDatabase Studio OutWit