Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 65 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,70 @@
# Changelog

## 14.0.1

**Two defects a client found by being used, both in the planner, neither reachable from the SQL
the suite happens to write.** No file format change; no API change beyond one internal signature.

### A join condition means the same thing whichever way round it is written

`ON c.Id = o.CustomerId` returned rows. `ON o.CustomerId = c.Id` - the same condition, the same
two tables - failed at execution with `Column 'CustomerId' not found`. It affected qualified
names with or without aliases, and the shape most likely to be met by accident is a chain, where
"the left input" is everything joined so far:

```sql
SELECT c.Country FROM Customers c JOIN Orders o ON c.Id = o.CustomerId
JOIN Items i ON i.OrderId = o.Id -- refused before 14.0.1
```

**The cause was that the equi-join key pair was built from the order the condition was WRITTEN
in**, and never from where the columns come from: `LeftKey = binary.Left, RightKey = binary.Right`.
The extractor checked that the two column references named different tables and stopped there, 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 `OptimizerJoinCondition.Analyze`, so the
question is asked at every call site - and orients each pair by which side its columns are on.

Two conditions that used to become hash keys no longer do, and both are corrections: a pair whose
columns are BOTH from the left input is a filter on that input rather than a join key, and a pair
with an unqualified column cannot be attributed at all. Both now go to the residual condition,
which is evaluated over the joined row and cannot be wrong.

**Where the engine does not know which side a column is on, the written order still decides.**
An `INFORMATION_SCHEMA` source reports no table name, so `tc.X = kcu.X` over two of them cannot be
attributed to either input; those keep the old behaviour deliberately. Reading it as «neither is
from the left» and sending it to the residual turned Studio's primary-key query into a cross
product - measured, five of its cases went red - because a qualified name over such a join
resolves by column name, and the same name appears once per side.

**Why the suite said nothing:** every join case in it writes the equality left-hand-side first.
The new fixture asserts the two orders agree ROW FOR ROW across inner, left, chained, aliased,
unaliased, composite-key and residual-beside-key shapes - and carries a control that the hash join
is the path being taken, because a nested loop has never cared.

### `EXPLAIN` names the line each line is really under

The lines of each child’s subtree were re-based by a constant rather than 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:

```
id parent detail
2 1 HASH INNER JOIN
3 2 ALIAS c
4 3 SCAN TABLE Customers
5 2 ALIAS o
6 3 SCAN TABLE Orders <- said 3, which is ALIAS c
```

Anything that draws the plan as a tree drew the wrong tree faithfully. The rows themselves were
all present and every parent was a real earlier line, which is why a structural check passes on
both versions; the new fixture asserts instead that each `ALIAS` stands over the scan of the table
it aliases, and that the two arms of a `UNION` keep their own children.

### Known issues

Issues 25 and 26 of [Docs/KnownIssues.md](Docs/KnownIssues.md) are these two, and are now marked
fixed there.
## 14.0.0

**An encrypted database written before 13.1.0 is no longer opened without being asked.** That is the
Expand Down
21 changes: 19 additions & 2 deletions Docs/KnownIssues.md
Original file line number Diff line number Diff line change
Expand Up @@ -1530,7 +1530,19 @@ 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.
> **FIXED in 14.0.1.** The key pair is now oriented by the left input’s schema, which is a
> required parameter of `OptimizerJoinCondition.Analyze` so that the question is asked at every
> call site. `JoinKeysBelongToTheirOwnSideTests` asserts the two orders agree ROW FOR ROW over
> inner, left, chained, aliased, unaliased, composite-key and residual-beside-key shapes, and
> carries a control that the hash join is the path being taken. Seven of its ten cases fail if the
> orientation is removed.
>
> **One limit, deliberate:** where a source reports no table name - `INFORMATION_SCHEMA` does -
> neither column can be attributed and the written order still decides. Such a join resolves a
> qualified name by column name anyway, so nothing is gained by refusing it, and treating it as
> «neither from the left» turned Studio's primary-key query into a cross product.
>
> Measured 2026-08-19 on engine 14.0.0. The account below is what was found.

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`:
Expand Down Expand Up @@ -1580,7 +1592,12 @@ order.

## 26. `EXPLAIN` gives the right input’s child the wrong parent

> Measured 2026-08-19 on engine 14.0.0.
> **FIXED in 14.0.1.** Each child’s subtree is re-based by where it actually starts rather than
> by a constant. `APlanNodeNamesItsRealParentTests` asserts that each `ALIAS` stands over the scan
> of the table it aliases and that the two arms of a `UNION` keep their own children - a purely
> structural check passes on both versions, which is why that is not the assertion.
>
> Measured 2026-08-19 on engine 14.0.0. The account below is what was found.

For `SELECT c.Country, o.Total FROM Customers c JOIN Orders o ON c.Id = o.CustomerId LIMIT 3`,
`EXPLAIN` answers:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<Version>14.0.0</Version>
<Version>14.0.1</Version>
<Description>ChaCha20-Poly1305 encryption provider for WitDatabase using BouncyCastle. Ideal for Blazor WebAssembly where hardware AES acceleration is unavailable.</Description>
<PackageTags>OutWit;database;encryption;chacha20;poly1305;bouncycastle;blazor;wasm;security</PackageTags>
</PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion Sources/Core/OutWit.Database.Core.BouncyCastle/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ This package provides an alternative encryption algorithm when AES-NI hardware a
## Installation

```xml
<PackageReference Include="OutWit.Database.Core.BouncyCastle" Version="14.0.0" />
<PackageReference Include="OutWit.Database.Core.BouncyCastle" Version="14.0.1" />
```

---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<Version>14.0.0</Version>
<Version>14.0.1</Version>
<Description>IndexedDB storage provider for WitDatabase. Enables running WitDatabase entirely in the browser with Blazor WebAssembly applications.</Description>
<PackageTags>OutWit;database;indexeddb;blazor;wasm;webassembly;storage;browser;client-side</PackageTags>
</PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion Sources/Core/OutWit.Database.Core.IndexedDb/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ This package allows WitDatabase to run entirely in the browser with data persist
## Installation

```xml
<PackageReference Include="OutWit.Database.Core.IndexedDb" Version="14.0.0" />
<PackageReference Include="OutWit.Database.Core.IndexedDb" Version="14.0.1" />
```

Add the JavaScript files to your `index.html`:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<Version>14.0.0</Version>
<Version>14.0.1</Version>
<Description>High-performance embedded key-value database engine for .NET. Features B+Tree and LSM-Tree storage engines, MVCC transactions, AES-256-GCM encryption, and full ACID compliance.</Description>
<PackageTags>OutWit;database;embedded;key-value;btree;lsm-tree;mvcc;transactions;encryption;acid;storage</PackageTags>
</PropertyGroup>
Expand Down
8 changes: 4 additions & 4 deletions Sources/Core/OutWit.Database.Core/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,17 @@ OutWit.Database.Core is a production-ready embedded database engine designed for
## Installation

```xml
<PackageReference Include="OutWit.Database.Core" Version="14.0.0" />
<PackageReference Include="OutWit.Database.Core" Version="14.0.1" />
```

For ChaCha20-Poly1305 encryption:
```xml
<PackageReference Include="OutWit.Database.Core.BouncyCastle" Version="14.0.0" />
<PackageReference Include="OutWit.Database.Core.BouncyCastle" Version="14.0.1" />
```

For Blazor WebAssembly (IndexedDB storage):
```xml
<PackageReference Include="OutWit.Database.Core.IndexedDb" Version="14.0.0" />
<PackageReference Include="OutWit.Database.Core.IndexedDb" Version="14.0.1" />
```

---
Expand Down Expand Up @@ -498,7 +498,7 @@ WitDatabase can run entirely in the browser using IndexedDB as the storage backe
### Installation

```xml
<PackageReference Include="OutWit.Database.Core.IndexedDb" Version="14.0.0" />
<PackageReference Include="OutWit.Database.Core.IndexedDb" Version="14.0.1" />
```

Add JavaScript files to `index.html`:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<AntlrScriptPath>$(MSBuildProjectDirectory)\MakeInternal.ps1</AntlrScriptPath>
<_AntlrVendoredJar>$([System.IO.Path]::GetFullPath('$(MSBuildProjectDirectory)/../../../build/antlr/antlr4-4.13.1-complete.jar'))</_AntlrVendoredJar>

<Version>14.0.0</Version>
<Version>14.0.1</Version>
<Description>SQL parser for WitDatabase. ANTLR4-based parser for WitSQL dialect with full SQL-92 compatibility and .NET type extensions.</Description>
<PackageTags>OutWit;database;sql;parser;antlr;witsql;query;syntax</PackageTags>
</PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion Sources/Engine/OutWit.Database.Parser/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ OutWit.Database.Parser is a high-performance SQL parser built on [ANTLR4](https:
## Installation

```xml
<PackageReference Include="OutWit.Database.Parser" Version="14.0.0" />
<PackageReference Include="OutWit.Database.Parser" Version="14.0.1" />
```

---
Expand Down
Loading
Loading