Elyra
Elyra The coding agent e The native code editor Elyra Grove Native local development environment Askr The real server for Laravel & PHP Elyra Conductor Local project conductor Elyra SQL Server MySQL-compatible SQL server in Rust Elyra SQL Client Native desktop SQL workbench Elyra SQL Anywhere Replication-ready SQL engine
Release notes
Changelog
Elyra

Changelog

All notable changes to ElyraSQL are documented here. The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

0.9.2 - 2026-07-10

MySQL client & driver compatibility release, driven by testing real GUI tools and a Rust sqlx client against ElyraSQL. No on-disk format change.

Query engine

  • LIKE / ILIKE in WHERE are now supported (they were rejected before): %/_ wildcards, ESCAPE, NOT LIKE, case-insensitive under the default collation — so contains/prefix search works.
  • Numeric/string comparison coercion: comparing a numeric column to a string literal (id = '5', IN ('5','6'), price = '10.50', id > '4') now coerces per MySQL rules. This also fixes bound parameters not matching numeric columns (drivers render params as string literals).
  • Expressions over aggregates: ROUND(SUM(x),2), SUM(a)/COUNT(*), SUM(qty*price), COALESCE(SUM(x),0)+n, and scalar expressions over group columns like UPPER(status) — with or without GROUP BY.
  • Positional ORDER BY (ORDER BY 2, ORDER BY 1 DESC).
  • VERSION(), DATABASE(), USER(), CURRENT_USER(), CONNECTION_ID(), CURRENT_ROLE() work as scalar functions in any context (not just as an exact-match intercept).
  • CREATE/DROP DATABASE and SCHEMA are accepted as no-ops (single-file database), so tools and migrations that issue them proceed.

Introspection

  • information_schema: added engines, schemata, views, events, routines, triggers; KEY_COLUMN_USAGE gained POSITION_IN_UNIQUE_ CONSTRAINT and REFERENCED_TABLE_SCHEMA/NAME/COLUMN_NAME (foreign-key discovery). Database name unified to elyra.
  • SHOW: VARIABLES, STATUS, COLLATION, DATABASES, WARNINGS, TABLE STATUS, FUNCTION/PROCEDURE STATUS (incl. the WHERE form), and PROCESSLIST (now handled in-engine, so it works over the prepared path too).
  • mysql.user lists accounts (always including the built-in root).

Drivers

  • Opt-in prepared-statement column description (ELYRASQL_STMT_DESCRIBE, default off): describes a simple SELECT's result columns at PREPARE time so drivers like sqlx resolve result columns by name. Off by default because strict libmysqlclient-based clients mishandle it; verified with a real sqlx harness that it enables by-name resolution and survives multiple prepares on one connection.

0.9.1 - 2026-07-10

MySQL client compatibility release. Real GUI tools (DBeaver, Workbench) and drivers fire a cluster of introspection queries on connect and to populate their schema tree; ElyraSQL now answers them, and a few everyday query forms that errored now work. No on-disk format change.

Session / introspection queries

  • SHOW [GLOBAL|SESSION] VARIABLES [LIKE ...] returns a MySQL 8.0-compatible system-variable set (character sets, collations, timeouts, max_allowed_packet, lower_case_table_names, sql_mode, version*, ...) with LIKE filtering.
  • SHOW STATUS, SHOW COLLATION, SHOW DATABASES, SHOW WARNINGS/ERRORS, SHOW TABLE STATUS, and SHOW FUNCTION/PROCEDURE STATUS (including the WHERE form, which the SQL parser rejects, handled pre-parse).

information_schema virtual tables

  • Added engines, schemata, views, events, routines, and triggers (views/routines/triggers reflect the actual stored objects). The reported database name is now consistently elyra (matching TABLE_SCHEMA and Tables_in_elyra).

Query engine

  • Expressions over aggregates: ROUND(SUM(x), 2), SUM(a)/COUNT(*), SUM(qty*price), COALESCE(SUM(x), 0) + n, and scalar expressions over group columns like UPPER(status) — with or without GROUP BY, and over an empty input (yields NULL). Previously these errored.
  • Positional ORDER BY (ORDER BY 2, ORDER BY 1 DESC) in both the aggregated and plain paths.

Dependencies

  • Applied safe in-range dependency updates; pinned crates that define the on-disk format / SQL parsing / SIMD API (bincode, redb, sqlparser, wide) and the opensrv-pinned rustls stack against breaking Dependabot bumps. Bumped the Alpine runtime image and GitHub Actions. The four rustls-webpki advisories are not reachable (server-only TLS, no client-cert/CRL validation) and are transitively pinned by opensrv-mysql.

0.9.0 - 2026-07-10

Robustness, correctness & security hardening release. A broad review of the query engine, transaction layer, vector search, privilege model and network/ disk I/O, tightening production safety without changing the on-disk format.

Correctness

  • Signed-zero / NaN grouping. GROUP BY, DISTINCT and hash joins now canonicalize float keys, so -0.0 and +0.0 group together (as SQL requires) and all NaNs collapse to one key.
  • Total ordering. Value::total_cmp's fallback no longer compares Debug strings (which allocated per comparison and sorted 10.0 before 2.0); it uses a numeric / stable per-type order.
  • Full-text stemming. Replaced the ad-hoc suffix stripper (which mangled stringstr, runningrunn) with the Snowball algorithms (rust-stemmers); multilingual via ELYRASQL_FULLTEXT_LANGUAGE (default english; none disables stemming).
  • Transaction ORDER BY now uses the disk-spilling sorter inside transactions too (via the snapshot+overlay cursor), not just in autocommit.
  • GROUP BY consults column statistics to go straight to the spilling path when a large group count is predicted, avoiding a wasted in-memory pass and re-scan (run ANALYZE TABLE to benefit).

Stability

  • JSON validator depth limit (MAX_JSON_DEPTH) stops deeply nested input from overflowing the thread stack.
  • O(1) savepoints. SAVEPOINT records an undo-log marker instead of cloning the whole staged write set (previously O(writes × savepoints)); ROLLBACK TO reverts only changes since the savepoint.
  • Bounded transaction buffer. Uncommitted writes past ELYRASQL_TXN_MAX_BYTES (default 1 GiB) are rejected with an error instead of exhausting memory.
  • Single-flight vector index rebuilds. A burst of queries after a write now triggers exactly one HNSW rebuild while the rest await and share it, instead of a thundering-herd of parallel full-table scans.
  • Temp-file hygiene. Sort/aggregation spill files are size-guarded on read (a corrupt file can't trigger a giant allocation) and stale files from a SIGKILLed process are reclaimed at startup (only confirmed-dead PIDs).

Security

  • Fine-grained global privileges. GRANT/REVOKE ON *.* now add/remove individual privileges as a set, so revoking one privilege no longer collapses an admin account to read-only. SHOW GRANTS lists the exact set.
  • DROP USER purges the account's global, per-table, per-column and role grants, so a recreated same-name user can't inherit stale privileges.
  • Constant-time password comparison (ct_eq) closes a hash timing side channel.
  • Bounded frame/record reads. Every length-prefixed read (cluster, replication, binlog, spill files) rejects oversized lengths before allocating, via the configurable ELYRASQL_MAX_FRAME_MB (default 1024 MiB), turning a corrupt file or malicious packet into an error instead of an OOM crash.

Performance

  • HNSW visited-set pooling removes an O(N) heap allocation per vector search.
  • SIMD distance kernels (wide::f32x8, 8-wide) accelerate L2 / inner-product / cosine on the hot ANN path.
  • Cooperative yielding (yield_now) in stored-procedure WHILE/LOOP/ REPEAT loops keeps a long procedure from starving the async runtime.

Known limitations (documented)

  • Multi-table joins still materialize before sort/group (streaming join output is planned); an unanalyzed high-cardinality GROUP BY may still fall back with a second scan; internal cluster/replication traffic is authenticated (ELYRASQL_CLUSTER_SECRET) but not yet encrypted (mTLS is planned — use a private network/VPN meanwhile).

0.8.10 - 2026-07-10

Consensus hardening & security release — making the Raft write path production- viable and strengthening password handling.

Raft write-path throughput

  • The leader holds persistent AppendEntries connections to followers (reused across rounds, TCP_NODELAY) instead of a fresh connection per round.
  • The Raft log is now append-only (fsync only new entries; the whole log is no longer rewritten per write), and the leader fsyncs a round's entries once.
  • Committed entries are applied together through the DB group commit.
  • Together these lift concurrent cluster write throughput from ~60/s to ~500/s (16 connections) / ~800/s (32); a single sequential write stays fsync-latency-bound.

Leader lease (liveness + linearizable leader reads)

  • The leader renews a lease each round it confirms a quorum and steps down if it cannot within the lease window (below the election timeout). A leader partitioned from its quorum now relinquishes leadership — in-flight writes fail fast and a healthy majority elects a new leader — rather than hanging. A lease-valid leader is guaranteed to be the leader, so its local reads are linearizable without a quorum round-trip.

Raft log compaction

  • The replicated log no longer grows unbounded: once entries are applied and replicated to every member, each node discards them (keeping the snapshot boundary term for the consistency check); the applied state machine is the snapshot. Compaction advances only to the slowest member's replicated index.

Password hardening

  • New passwords must satisfy a strength policy (ELYRASQL_PASSWORD_MIN_LEN, default 8; ELYRASQL_PASSWORD_REQUIRE_MIXED, default on; ELYRASQL_PASSWORD_POLICY=off to disable).
  • Repeated failed logins trigger a temporary account lockout (ELYRASQL_AUTH_MAX_FAILURES, default 10; ELYRASQL_AUTH_LOCKOUT_SECS, default 60), logged.

0.8.9 - 2026-07-09

Consensus release: the Raft log is now on the live cluster write path.

Raft replicated-log write path (pre-commit / 2-phase)

  • In cluster mode, every write is proposed through the Raft log: the leader appends the entry, replicates it via AppendEntries, commits it once a quorum has durably logged it, and only then applies it and acknowledges the client. Followers append (with the AppendEntries consistency check + conflicting-suffix truncation) and apply up to the leader's commit index.
  • Votes use the §5.4.1 election restriction on the log, so failover is no-data-loss: an acknowledged write is on a quorum's durable log and any elected leader already has it. A write cannot be acknowledged without a quorum.
  • New plumbing: elyra_storage::WriteOp + Consensus trait + Db.set_consensus / apply_op_local; the single-node write path is unchanged when no consensus layer is installed.
  • Known limitation: a leader partitioned from its quorum blocks writes (until it can replicate or the client times out) rather than stepping down proactively (no leader lease yet).

Verified

  • 3-node cluster: writes commit via quorum and replicate; followers reject writes; killing the leader preserves all acknowledged writes on the new leader (no data loss); no commit without a quorum.

0.8.8 - 2026-07-09

Partitioning release.

Partitioning

  • CREATE TABLE ... PARTITION BY RANGE|LIST|HASH (<pk column>) (...) records a partitioning scheme (managed primary-key ranges), exposed in information_schema.partitions.
  • ALTER TABLE t DROP PARTITION p / TRUNCATE PARTITION p cheaply delete a partition's rows (range/IN delete with index cleanup). Queries with a PK predicate prune automatically via clustered range scans.
  • Also fixed a stale docs line: ON UPDATE referential actions are enforced.

Notes / deferred

  • Partitioning is single-node (managed PK ranges, not physical files, not enforced on INSERT). Horizontal write scale-out across nodes would require distributed sharding and is out of scope by design.
  • Wiring the Raft log into the live cluster write path (leader append → quorum commit → apply, for pre-commit 2-phase durability) is intentionally not bundled here: it is a correctness-critical change that warrants a dedicated release with partition/failover testing (the tested log core landed in 0.8.6). Today's HA remains async replication + quorum/--sync-strict + the LSN-aware election restriction (no data loss for acknowledged writes).

0.8.7 - 2026-07-09

SQL-surface & usability release.

Named windows

  • SELECT ... OVER w ... WINDOW w AS (PARTITION BY ... ORDER BY ...), including OVER (w ...) that inherits a named window and adds local clauses.

Materialized-view auto-refresh

  • Materialized views now auto-refresh on read when a base table has changed since the last refresh (detected via per-table write counters). This is a full recompute, not incremental delta maintenance.

Notes

  • caching_sha2_password remains unimplemented: the latest published opensrv-mysql (0.7.0, what we use) does not drive its multi-round auth exchange. MySQL 8 clients negotiate down to mysql_native_password.

0.8.6 - 2026-07-09

Programmability, security & consensus-foundation release.

Materialized views

  • CREATE MATERIALIZED VIEW v AS <select> materializes the result into a real table; REFRESH MATERIALIZED VIEW v recomputes it; DROP MATERIALIZED VIEW v removes it. Refresh is explicit (no auto-refresh).

Per-column privileges

  • GRANT SELECT(col, ...) ON t TO u restricts a user to reading only those columns of t; querying an ungranted column (via the projection, SELECT *, or a WHERE/ORDER BY reference) is denied. Enforced for single-base-table selects; a restricted table in a join/subquery is denied (deny-safe).

Raft log core (consensus foundation)

  • New unit-tested raftlog: an ordered persistent log with the AppendEntries consistency check + conflicting-suffix truncation, the quorum/current-term commit rule, apply-only-when-committed, and the §5.4.1 election restriction. Routing the live cluster write path through it (for pre-commit 2-phase durability) is the remaining integration step.

Notes

  • caching_sha2_password remains unimplemented: the MySQL-protocol library does not drive its multi-round auth exchange. MySQL 8 clients negotiate down to mysql_native_password.

0.8.5 - 2026-07-09

Planner, security, and durability release.

Histogram-based cardinality

  • ANALYZE TABLE builds an equi-height histogram per column (reservoir sample), exposed as a JSON HISTOGRAM in information_schema.column_statistics. The planner estimates WHERE-predicate selectivity from histograms to order joins by estimated (not just raw) row counts.

Roles, per-database grants & audit log

  • CREATE ROLE / DROP ROLE, GRANT <role> TO <user> / REVOKE <role> FROM <user>; users inherit the global and per-table grants of their roles.
  • GRANT ... ON db.* is accepted (maps to a global grant, single database).
  • --audit-log <path> appends one line per executed statement (timestamp conn_id user OK|ERR sql).

LOAD DATA INFILE & auth hardening

  • LOAD DATA INFILE '<server path>' INTO TABLE t [FIELDS/LINES TERMINATED BY] [IGNORE n LINES] [(cols)] bulk-loads a server-side file (ADMIN required; \N = NULL).
  • Connection salts now use the OS CSPRNG. (caching_sha2_password is not implemented — the wire library lacks its multi-round exchange; MySQL 8 clients negotiate down to mysql_native_password.)

Crash-safe cluster elections

  • Election state (current term + vote) is persisted to <data>.raftstate, so a restarted node never double-votes in a term (Raft safety). Full Raft log replication (pre-commit 2-phase durability) remains a dedicated milestone.

0.8.4 - 2026-07-09

High-availability & query-planner release.

Zero-data-loss failover (election restriction)

  • Cluster leader election now enforces the Raft election restriction: a node only votes for a candidate at least as up-to-date (by LSN) as itself, so an elected leader holds every quorum-acknowledged write. Together with --sync-strict this makes failover no-data-loss for acknowledged writes. (The sync barrier still runs after the local commit; this is not a pre-commit 2-phase protocol.)

Dynamic cluster membership

  • Add/remove cluster members at runtime with elyrasql cluster-ctl --node <addr> --action add|remove --peer id@host:port. The leader advertises the membership in heartbeats and followers adopt it. Add one node at a time and start it before adding.

Cost-based JOIN reordering + merge join

  • Explicit INNER-join chains over base tables are reordered cost-based (drive from the smallest relation, extend along equi-join predicates; alias-aware).
  • Large INNER equi-joins whose inputs are already sorted on the join key (clustered primary-key scans) use a streaming merge join.

Stored procedures: cursors & handlers

  • DECLARE ... CURSOR FOR, OPEN, FETCH ... INTO, CLOSE, and DECLARE {CONTINUE|EXIT} HANDLER FOR {NOT FOUND | SQLEXCEPTION | SQLSTATE '...' | <code>} <action>.

0.8.3 - 2026-07-09

Scalability & robustness release — hardening the write path and high availability.

Pessimistic locking

  • LOCK TABLES t READ|WRITE / UNLOCK TABLES take real blocking table locks (a WRITE lock blocks other readers and writers; a READ lock blocks writers). Conflicting statements from other sessions block until release, or fail with 1205 (lock wait timeout). LOCK IN SHARE MODE is accepted as a synonym for FOR SHARE. Zero overhead when no explicit lock is held.

Quorum / synchronous replication

  • --sync-replicas N makes each commit wait for N replica acknowledgements; --sync-strict fails the commit-confirmation on timeout instead of silently degrading to asynchronous (no silent data-loss window). Per-replica ack tracking replaces the single high-water mark.

Incremental replica catch-up

  • A reconnecting replica streams only the binlog delta since its last applied LSN instead of re-copying the whole database, falling back to a full snapshot only when the binlog is disabled or the needed segments were purged. Replicas reconnect transparently on stream drops. The LSN counter is resumed from the binlog across restarts (correct binlog ordering + working catch-up).

Write throughput

  • Validated transactional commits are now group-committed: many concurrent transactions fold into one write transaction (one fsync) instead of one fsync each, while preserving first-committer-wins ordering and write-write conflict detection. (The single writer remains inherent to the ACID single-file design; there are no parallel writers or sharding.)

0.8.2 - 2026-07-09

High-availability & feature-completeness release.

Automatic failover

  • cluster mode: Raft-style leader election (terms, majority votes, heartbeats, step-down). The elected leader accepts writes and serves replication; followers are read-only and replicate from it. On leader failure a surviving node is automatically elected. Leader-only writes provide fencing; a majority quorum avoids split-brain. Data replication remains asynchronous.

Stored procedures

  • IN/OUT/INOUT parameters, session @user variables, and full control flow: LOOP, REPEAT ... UNTIL, labeled LEAVE/ITERATE (in addition to IF/WHILE).

Full-text search

  • CREATE FULLTEXT INDEX builds a persistent inverted index maintained on INSERT/UPDATE/DELETE and used to accelerate MATCH ... AGAINST; light English stemming folds regular word forms.

Spatial

  • POINT/GEOMETRY columns (WKT) with POINT, ST_X, ST_Y, ST_Distance, ST_AsText, ST_GeomFromText.

0.8.1 - 2026-07-09

Programmability release: triggers, procedural stored procedures, and full-text search.

Triggers

  • Row-level CREATE TRIGGER name {BEFORE|AFTER} {INSERT|UPDATE|DELETE} ON t FOR EACH ROW <body> / DROP TRIGGER, with NEW.col / OLD.col. BEFORE bodies support SET NEW.col = expr; AFTER bodies run arbitrary DML per affected row. Firing is depth-guarded against runaway recursion.

Stored procedures

  • Parameters (IN), local variables (DECLARE, SET), and control flow (IF/ELSEIF/ELSE, WHILE), interpreted over the procedure body.

Full-text search

  • MATCH(col, ...) AGAINST('terms' [IN BOOLEAN MODE]) — scan-based relevance scoring (natural-language OR-of-terms, or boolean +/-).

Fixed

  • The fast INSERT path now persists the AUTO_INCREMENT counter, so consecutive auto-increment inserts no longer reuse ids.

0.8.0 - 2026-07-09

Programmability & log-management release.

Binary log management

  • The binlog is now a directory of rotating segment files, rotating at ELYRASQL_BINLOG_SEGMENT_MB (default 128 MB).
  • SHOW BINARY LOGS lists segments and sizes; PURGE BINARY LOGS TO '<name>' deletes older segments. --binlog and binlog-replay now take a directory.

Stored procedures

  • CREATE [OR REPLACE] PROCEDURE name() BEGIN ...; END, CALL name(), and DROP PROCEDURE — statement-list macros executed through the engine, with a recursion-depth guard. (Parameters, variables and control flow are not yet supported.)

0.7.0 - 2026-07-09

Durability & recovery release: point-in-time recovery, richer statistics, and semi-synchronous replication.

Point-in-time recovery

  • Optional append-only binlog (--binlog) records every committed write-set with an LSN and timestamp.
  • elyrasql binlog-replay --data <f> --binlog <f> [--until-lsn N | --until-time-ms T] replays onto a restored backup (or an empty file) up to a chosen point — exact, idempotent recovery.

Statistics

  • ANALYZE TABLE now collects per-column statistics (distinct-value count, null count, min/max), exposed via information_schema.column_statistics.
  • The planner drives a comma cross-join from the smallest analyzed table.

Replication

  • Semi-synchronous mode (--semi-sync-ms): a commit waits for a replica to acknowledge before returning, degrading to asynchronous on timeout or when no replica is attached. Replication is now bidirectional (replicas acknowledge applied LSNs).

0.6.0 - 2026-07-09

Scale & availability release: replication, partitioned aggregation spill, cost-based joins with statistics, and a Prometheus metrics endpoint.

Replication & HA

  • Asynchronous primary → replica replication. A primary streams LSN-tagged committed write-sets (--replication-listen); a replica bootstraps from a snapshot and applies the stream (elyrasql replica), serving read-only queries. Idempotent, ordered application means replicas never diverge; failover is manual (a replica file is a complete database).

Aggregation

  • GROUP BY with many distinct groups now falls back to partitioned spill aggregation (bounded memory) instead of erroring, completing the OOM-safety story alongside ORDER BY spill.

Query planning

  • Equi hash joins now cover INNER / LEFT / RIGHT with a cost-based build side (INNER builds the smaller relation; RIGHT no longer degrades to nested-loop).
  • ANALYZE TABLE records row-count statistics, surfaced as information_schema.tables.TABLE_ROWS.

Observability

  • Prometheus/OpenMetrics endpoint (--metrics-listen, GET /metrics) exposing the server counters, plus a /health probe.

0.5.0 - 2026-07-09

Operations & data-model release: observability, memory-bounded sorts, per-column collation, and scoped privileges.

Observability

  • SHOW STATUS / SHOW GLOBAL STATUS counters (uptime, connections, Questions/Queries, Com_*, Errors, Slow_queries), with LIKE 'prefix%'.
  • SHOW [FULL] PROCESSLIST listing live connections and their current query.
  • Slow-query log: --slow-query-ms / ELYRASQL_SLOW_QUERY_MS logs statements at or above the threshold with their duration.

Memory safety

  • ORDER BY is now memory-bounded: a top-N heap for ORDER BY ... LIMIT, and an external merge sort that spills to temp files for large sorts (ELYRASQL_SORT_MAX_ROWS).
  • GROUP BY fails gracefully past ELYRASQL_GROUP_MAX_GROUPS instead of risking an out-of-memory crash.

Collation

  • Per-column COLLATE ..._bin / BINARY opt-in to case-sensitive behavior for WHERE comparisons, UNIQUE, PRIMARY KEY and secondary indexes (text is still case-insensitive by default). ORDER BY/GROUP BY/joins still use the default collation.

Access control & integrity

  • Per-table GRANT/REVOKE (ON <table>): raises a read-only account's level for specific tables; reads stay globally allowed. Deny-safe when a target is indeterminate. SHOW GRANTS lists global and per-table grants.
  • ON UPDATE referential actions enforced (CASCADE / SET NULL / RESTRICT) when a parent's referenced key changes.

0.4.0 - 2026-07-09

Production-readiness release: backup, real user management, and a MySQL-style case-insensitive default collation.

Backup & restore

  • Hot backup with BACKUP TO '<path>' (admin): copies the whole database from a consistent MVCC snapshot into a fresh file without blocking writers.
  • Offline elyrasql backup and elyrasql restore CLI subcommands.
  • The backup is a complete database file — start a server on it or copy it back.

Users & access control

  • Persistent accounts stored in the database file (survive restarts): CREATE USER, DROP USER, ALTER USER / SET PASSWORD, GRANT, REVOKE, SHOW GRANTS.
  • New accounts start read-only; GRANT raises them, REVOKE lowers them. Privileges map to the coarse global read/write/admin levels (the object clause is parsed but not scoped). Passwords stored as SHA1(SHA1(pw)).
  • Authentication consults startup bootstrap accounts plus persistent accounts; open dev mode applies only when no account exists.

Collation

  • Default case-insensitive collation for text, applied consistently across comparisons, ORDER BY, indexing, GROUP BY, DISTINCT, joins, set operations, and UNIQUE/PRIMARY KEY.
  • On-disk change: text key encoding is now case-folded. Databases created before 0.4.0 that use text primary keys or text indexes should be reloaded.

0.3.0 - 2026-07-09

Data-integrity release: the constraints a production database must enforce.

Constraints

  • UNIQUE constraints are now enforced (previously stored but not checked). Column-level UNIQUE, table-level UNIQUE(...), and CREATE UNIQUE INDEX all reject duplicates (error 1062), including duplicates within a single statement; multiple NULLs are allowed.
  • FOREIGN KEY constraints are enforced. INSERT/UPDATE require a matching parent row (primary key or unique index, error 1452); DELETE on the parent applies RESTRICT/NO ACTION (block), ON DELETE CASCADE (delete children), or ON DELETE SET NULL.
  • CHECK constraints (column- and table-level) are enforced on INSERT and UPDATE, passing on TRUE or NULL per SQL semantics.

Transactions

  • SAVEPOINT, ROLLBACK TO SAVEPOINT, and RELEASE SAVEPOINT.
  • SELECT ... FOR UPDATE / FOR SHARE: optimistic row locking — a locked row changed by another transaction aborts the locking transaction at commit (lost-update prevention without blocking).

Fixed

  • Three-valued logic for comparisons: NULL = x, x >= NULL, etc. now evaluate to NULL (UNKNOWN) instead of false. WHERE still excludes them, CHECK passes, and SELECT shows NULL — matching SQL semantics.

0.2.1 - 2026-07-09

Performance and robustness pass, verified on Linux (1,000,000-row workloads).

Performance

  • Bulk INSERT ~5-6x faster (~33k → ~190k rows/s in a container, ~240k on fast-fsync storage). The 0.2.0 duplicate-key check did one storage read per row (each opening its own read transaction); it now:
    • detects duplicates inside the write transaction itself for plain INSERT (redb returns the previous value — no existence read), and
    • batches the existence check into a single read for IGNORE/REPLACE/ ON DUPLICATE KEY UPDATE.
  • Group commit for INSERT: the writer coalesces queued plain/insert jobs into one transaction (one fsync), falling back to per-statement application only when a group contains a duplicate — so concurrent write throughput is preserved.
  • GROUP BY ~3.4x faster on low-cardinality groups (~927ms → ~273ms over 1M rows): the group key is a compact binary encoding instead of Debug-formatting every row's key columns.
  • Statement dispatch inspects only a short prefix instead of lowercasing the whole (possibly large) SQL text.

0.2.0 - 2026-07-09

A large expansion of SQL coverage on top of the 0.1.0 foundation, turning ElyraSQL into a broadly MySQL-compatible engine.

Queries

  • Subqueries in WHERE and the SELECT list — uncorrelated and correlated, including correlated subqueries over joins (IN, scalar, EXISTS).
  • Derived tables (FROM (SELECT ...) AS t).
  • Common table expressions (WITH), including chained CTEs and WITH RECURSIVE.
  • Window functions (OVER): ROW_NUMBER, RANK, DENSE_RANK, running and partition SUM/COUNT/AVG/MIN/MAX, LAG/LEAD, and explicit ROWS/RANGE frames.
  • HAVING.
  • Set operations: UNION, UNION ALL, INTERSECT, EXCEPT.
  • FROM-less SELECT (e.g. SELECT 1, SELECT NOW()).

DML

  • INSERT ... SELECT.
  • Upserts: REPLACE, INSERT IGNORE, and ON DUPLICATE KEY UPDATE (with correct secondary-index maintenance and duplicate-key error 1062).
  • Subqueries in UPDATE/DELETE WHERE (uncorrelated and correlated).
  • Multi-table UPDATE and DELETE (joins in mutations).

DDL

  • CREATE TABLE ... AS SELECT, CREATE TABLE ... LIKE, TRUNCATE TABLE.
  • CREATE VIEW / DROP VIEW (including column lists and views over views).
  • ALTER TABLE ... MODIFY/CHANGE COLUMN, and ALTER COLUMN SET/DROP DEFAULT and SET/DROP NOT NULL (with data re-coercion on type change).
  • Column DEFAULT (constants and functions), AUTO_INCREMENT, and stored generated columns.
  • ENUM/SET, BINARY/VARBINARY, and BIT column types.

Functions

  • Date/time: NOW/CURRENT_TIMESTAMP/CURDATE/CURTIME, YEAR/MONTH/DAY/ HOUR/MINUTE/SECOND, QUARTER/DAYOFWEEK/DAYOFYEAR, EXTRACT, DATE_ADD/DATE_SUB/TIMESTAMPADD, DATEDIFF/TIMESTAMPDIFF, WEEK/ YEARWEEK, DATE_FORMAT, STR_TO_DATE, LAST_DAY, and the d + INTERVAL n UNIT operator.
  • String: CONCAT/CONCAT_WS, UPPER/LOWER, SUBSTRING/SUBSTRING_INDEX, LEFT/RIGHT, TRIM family, REPLACE/REVERSE/REPEAT, LPAD/RPAD, INSTR/LOCATE, FIELD/ELT, and REGEXP/RLIKE.
  • Math, conditional (COALESCE/IFNULL/NULLIF/IF/CASE), CAST (including exact DECIMAL and BINARY), UUID().
  • JSON: JSON_EXTRACT/->/->>, JSON_ARRAY/JSON_OBJECT, JSON_SET/ JSON_INSERT/JSON_REPLACE/JSON_REMOVE, JSON_CONTAINS/JSON_LENGTH/ JSON_KEYS/JSON_TYPE/JSON_VALID/JSON_QUOTE.
  • Aggregates: GROUP_CONCAT, conditional aggregates (SUM(CASE ...)), COUNT(DISTINCT expr).
  • Bitwise &, |, ^.

Transactions

  • Write-conflict detection (first-committer-wins, MySQL error 1213).
  • Opt-in serializable isolation with read-set and scanned-range validation.

Introspection

  • SHOW TABLES, SHOW COLUMNS, DESCRIBE/DESC, SHOW CREATE TABLE, SHOW INDEX/SHOW KEYS.
  • Queryable INFORMATION_SCHEMA: tables, columns, statistics, key_column_usage.

Numerics & wire protocol

  • Exact DECIMAL arithmetic (+, -, *) and exact SUM(DECIMAL).
  • Value-driven result column typing (computed columns report the right wire type; no spurious .0).
  • DATE/DATETIME/TIME prepared-statement parameters decoded from the binary protocol.

Fixed

  • DateTime vs DATE comparison (previously always false).
  • DROP TABLE left orphaned secondary-index entries.
  • INSERT affected-row count included index-entry writes.

Docs & project

  • MkDocs Material documentation site, contributing guide, issue/PR templates, security and conduct policies, Dependabot configuration.

0.1.0

Initial release: single-file ACID storage (.edb), MySQL wire protocol, core CRUD with WHERE/ORDER BY/LIMIT, indexes, aggregation and GROUP BY, joins, prepared statements, authentication and TLS, vector search (exact + HNSW), parallel OLAP aggregation, and transactions with snapshot isolation.