Grove 1.7.0: a fourth database, and the bug it found on the way in
Grove 1.7.0 adds one thing — ElyraSQL as a bundled, supervised service alongside PostgreSQL, MySQL and Redis. Installing it turned up a connection bug that had made a year-old documentation claim about Rust's sqlx false, and fixing that is most of this release.
Grove 1.7.0 adds exactly one thing. The changelog says so in its first line — one addition: a fourth bundled database; everything else from 1.6.0 stands — and I'd like to keep that honesty here, because the interesting part of this release isn't the feature. It's what the feature turned up.
Why a fourth database
Grove already downloads and supervises PostgreSQL, MySQL and Redis for you. You run grove service install mysql, Grove fetches the binary, verifies it, and from then on it's a service that starts with your machine and shows up in grove status. No Homebrew formulae, no version drift between laptops, nothing to remember.
ElyraSQL is our own MySQL-compatible server: a single static binary, the whole database in one crash-safe ACID file, the MySQL wire protocol so your existing drivers work unchanged, plus vector search and parallel OLAP aggregation on top. It has been the odd one out — you could point a Grove site at an ElyraSQL you'd started yourself, but Grove didn't know it was there, and so nothing that makes Grove pleasant (snapshots, the migration sandbox, grove env) knew either.
1.7.0 closes that gap. ElyraSQL becomes a service like the others:
$ grove service install elyrasql
↓ elyrasql-1.11.2-macos-aarch64.tar.gz (7.9 MB)
✓ SHA-256 matches the published checksum
✓ installed 1.11.2, listening on 127.0.0.1:3307
Two details in those three lines are deliberate. The checksum is verified against what upstream published, not computed and admired — a download that matches nothing has proven nothing. And it lands on 3307, not 3306, so it lives beside MySQL rather than fighting it for the port. You can run both, and many people will: MySQL for the project that has to match production, ElyraSQL for the one where you want vector search without a second service.
How your app sees it
It doesn't, really — and that's the point. ElyraSQL speaks MySQL, so your app keeps the MySQL driver:
$ grove env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3307
DB_DATABASE=elyra
DB_USERNAME=root
DB_PASSWORD=
Paste that into .env, run your migrations, and Laravel — or anything else with a MySQL driver — is talking to ElyraSQL without knowing it. Grove tells an ElyraSQL site from a MySQL one by the port it connects to, which is a small thing that matters: the agent-safe migration sandbox and grove bundle need to snapshot the right server, and they do.
Snapshots work the way they do for the others, with one difference underneath:
$ grove db snapshot --engine elyrasql --name before-vectors
✓ BACKUP TO … (hot, consistent, 42 MB)
$ php artisan migrate # oh no
$ grove db restore before-vectors
✓ restored in 0.3s
Because ElyraSQL's database is one file, a snapshot is a hot, consistent copy of that file taken through BACKUP TO while the server keeps serving. Restore puts it back. Undoing a bad migration takes the time it takes to copy a file.
The convert tool takes ElyraSQL as a source or a target too, so moving a project from MySQL to ElyraSQL — or back — is one command rather than a dump-and-hope.
Platforms: macOS on Apple silicon and Linux. Upstream publishes no Intel macOS build, so Grove doesn't pretend to offer one.
The bug it found
Here's the part worth the article.
Grove is written in Rust, and its convert tool talks to databases through sqlx, the driver most Rust applications sit on. When we pointed convert at the freshly bundled ElyraSQL 1.11.1, it couldn't connect. Not "couldn't run a query" — couldn't connect at all.
The reason is a statement sqlx-mysql runs on every new connection, before your application gets a word in:
SET sql_mode=(SELECT CONCAT(@@sql_mode, ',PIPES_AS_CONCAT,NO_ENGINE_SUBSTITUTION')),
time_zone='+00:00'
ElyraSQL refused both halves. A scalar subquery wasn't a valid value for SET, and time_zone wasn't a recognised session variable. Error 1235, connection over. Anything built on sqlx — including anything generic over AnyPool, which has no way to switch the statement off — got exactly nowhere.
And the ElyraSQL documentation said sqlx worked out of the box.
It did not. Nobody had noticed because nobody had tried: the Laravel and PDO paths were well-trodden, the Python and Node drivers had been checked, and "Rust (sqlx)" sat in the list of supported clients on the strength of speaking MySQL. Speaking MySQL and having been connected to by sqlx turned out to be different claims.
So ElyraSQL 1.11.2 shipped the same day, and Grove 1.7.0 requires it. What changed:
A
(SELECT …)in aSETvalue now runs as a query and must return exactly one row and one column, as in MySQL.time_zoneis a session variable, echoed by@@time_zoneand@@session.time_zone, while@@global.time_zonestaysSYSTEM— exactly as MySQL 8.4 reports it.Only spellings of
time_zonethat mean UTC are accepted:+00:00,SYSTEM,UTC. ElyraSQL already evaluates every temporal function in UTC, so+00:00is honoured exactly — which is what sqlx'schronoandtimetypes assume. A non-zero offset is refused with a reason, rather than stored and silently not honoured. A setting that is accepted and ignored is worse than one that's rejected; you find out about the second one.A duplicated
@@sql_modeflag that the same statement produced is deduplicated, becausesql_modeis a set, not a list.
Two neighbouring gaps the same measurement surfaced — UTC_TIMESTAMP() / CONVERT_TZ() aren't implemented, and || isn't concatenation even with PIPES_AS_CONCAT — are filed as issues rather than papered over. They're real; they're just not this release.
Why we're telling you
We could have written "Grove 1.7.0 bundles ElyraSQL (requires 1.11.2)" and moved on. The version floor would have looked arbitrary, and the sqlx fix would have been a line in another product's changelog.
But the whole reason to bundle your own database into your own dev environment is that you become the first person to trip over the gaps between them. That's not a cost of dogfooding; it's the return on it. A claim in the docs that had been true-by-inference for a year got tested by accident and turned out to be false, and now it's true by measurement. The Grove page and the ElyraSQL page on elyracode.com both say so, in those words, because a card that quietly updates its claim is indistinguishable from one that was always right.
Try it
grove service install elyrasql
grove env >> .env # then set DB_DATABASE to something you like
php artisan migrate
grove db snapshot --engine elyrasql --name clean
Then break something, and restore it. That's the feature. The bug was a bonus.