Eliminating the legacy row-store

One storage format, one code path: flat columnar arrays everywhere.

Setup

All benchmarks, all workloads. This was not a single-query optimization but a structural change that affected every read and write path in the engine.

Problem

The engine had two storage representations living side by side:

Every query paid the cost of both representations. Inserts wrote to the row store; the columnar executor then scanned the row store to build column blocks. Deletes had to update both. The row store was the authoritative copy, and the column blocks were ephemeral views rebuilt on each query.

Cause

The row store predated the columnar executor. When the plan executor was added, it was built as a layer on top of the existing row store rather than replacing it. This was the right incremental approach—it allowed the new executor to be tested against the old one—but it left the system with two representations that had to be kept in sync.

Fix

Removed t->rows entirely. Tables now store data exclusively in struct flat_table: one contiguous typed array per column, plus a parallel null bitmap. The key changes:

Result

A single storage representation simplifies every code path:

The legacy row-by-row executor still works via flat_snap, so queries that fall back from the plan executor to the legacy path (e.g. complex correlated subqueries) continue to produce correct results. All 1,514 tests pass under AddressSanitizer.