Port status

From the project's own docs/ROADMAP.md ↗ and README. The roadmap's Current status block is pinned to the commit it was written at, and new work lands after it — so this page quotes it, then adds what has landed since.

Status in one line: a usable subset runs end to end — an ADO.NET provider over an in-memory engine: open connection, DDL, DML, query, reader, Dapper.

Newer than the roadmap block

Verified in the source, not taken on trust from commit titles:

Landed after the roadmap refreshWhat it means
Predicates: BETWEEN, IN (list and constant set), LIKE, ILIKE, REGEXP, NOTPorted as the reference's own predicate types — BetweenPredicate, ConditionIn / ConditionInList / ConditionInConstantSet, CompareLike, ConditionNot — not a shortcut in the parser, and none of them refuses.
CASE, both formsSimpleCase and SearchedCase with OperationN.
Aggregates: JSON_ARRAYAGG, JSON_OBJECTAGG, HISTOGRAM, MODEJSON aggregates build straight into bytes; HISTOGRAM/MODE on a value-to-count map.
Window frame units, bound types, exclusionsThe frame machinery is ported. Window functions (OVER/FILTER) still are not.
UPDATE SET listBuilt from the reference's update-action array.
Built-in functionsA function dispatcher plus the built-ins: ABS, MOD, FLOOR/CEIL/ROUND/TRUNC, the trigonometry, LN/EXP/SQRT/LOG/POWER, the whole bit family (BITAND…ROTATERIGHT), EXTRACT, DATE_TRUNC, DATEADD/DATEDIFF, FORMATDATETIME/PARSEDATETIME, DAYNAME/MONTHNAME, the string family (UPPER…SUBSTRING, TRIM, LPAD/RPAD, REPLACE, REGEXP_*, SOUNDEX/DIFFERENCE), XML*, JSON_OBJECT/JSON_ARRAY, array functions, COMPRESS/EXPAND, CONCAT, COALESCE, NULLIF, RANDOM.
AS in a table aliasParsed and pinned against the reference's answers. The implicit alias (FROM T e) worked before; note that bare column aliases still refuse.
CASTCast in expressions and the data type reader are ported, including the format template the reference reads after the type — CAST(x AS DATE FORMAT 'yyyy-MM-dd').
CASTCast in expressions and the data type reader are ported, including the format template the reference reads after the type — CAST(x AS DATE FORMAT 'yyyy-MM-dd').
Statements commit at the reference's pointsThe reference's stop and commitIfNonTransactional are ported, so a single INSERT/UPDATE/DELETE is durable on its own and DDL commits its transaction.
CREATE TABLE … PRIMARY KEYCreates, names and drops the index the way H2 does — the PRIMARY_KEY_ prefix, and the same name back when the table is recreated, as on the JVM.
Constraints are schema objectsNamed and table-level PRIMARY KEYs own their index and the 23505 duplicate-key prefix; ALTER TABLE adds and drops them and frees their names.
CREATE INDEX / DROP INDEXPorted over the full MVSecondaryIndex and its row factories.
LIKE / REGEXP semanticsSemantics suites pass; the default LIKE escape and IN parameter binding were fixed.
Allocation workPooled page scratches, one Bits.Reverse for the MVStore byte helpers, the pattern Regex cached once, digit appends without an intermediate string, numeric conversion delegates hoisted to statics.
Differential harnessOracle snippets compile once into a per-machine cache and run from it, so the JVM side costs nothing per repeat.

Phases

0 · Bootstrapdone
1 · Foundationdone
2 · MVStoredone — file-compat both ways
3 · Values, schemadone for what is portable
4 · Expressionspartial
5 · Commands/SQLpartial
6 · Enginepartial
7 · Constraints, rightstodo
8 · ADO.NET providerdone
9 · EF Corein progress — own repository
10 · Conformance, polishtodo

SQL that executes

AreaWorks
QueriesFlat SELECT, UNION/UNION ALL, DISTINCT, GROUP BY/HAVING, ORDER BY, LIMIT/OFFSET/FETCH, DUAL, CAST, literals
PredicatesBETWEEN, IN, LIKE, ILIKE, REGEXP, NOT, CASE (simple and searched) — as the reference's own predicate types
Parameters? placeholders, and @name rewritten
AggregatesCOUNT/COUNT(*), SUM, MIN, MAX, AVG, STDDEV*, VAR*, ANY/EVERY, MEDIAN, ANY_VALUE, HISTOGRAM, MODE, PERCENTILE_CONT/DISC, LISTAGG (+ GROUP_CONCAT/STRING_AGG), JSON_ARRAYAGG/JSON_OBJECTAGG, REGR_* (count, avgx, avgy, sxx, syy, slope, intercept, r2, sxy), COVAR_*, CORR, BIT_*_AGG (+ BIT_AND/BIT_OR), ARRAY_AGG
DMLINSERT, UPDATE, DELETE (text with ? parameters)
DDLCREATE TABLE (columns + inline PK), DROP TABLE, CREATE INDEX, DROP INDEX, ALTER TABLE (adding and dropping PK constraints) — ALTER TABLE is partial

SQL conformance suite

The repo carries tests/H2SharpSql.Specs — 947 tests, one per documented SQL construct, each anchored to a line number in the frozen snapshot the repo keeps in docs/. It is deliberately not part of H2Sharp.sln: while the port is young it shows hundreds of failures, and the daily ritual dotnet test H2Sharp.sln should not depend on it.

AreaPassedTotalNote
SystemTables/1737was 0 — the catalogue is ported now
Commands/17254was 11
Grammar/61263was 49
Datatypes/3866was 37
Total251947the first run, on 2026-10-19, was 102

The biggest gaps by failure count were: EXTRACT in the parser (66), FILTER/OVER (35), INFORMATION_SCHEMA as a table (25), CREATE DOMAIN (15), ALTER TABLE beyond ADD/DROP CONSTRAINT (12), YEAR (12), derived tables (12), CREATE ROLE (11), HOUR (10), table constraints other than PRIMARY KEY (9), CREATE SEQUENCE (8).

The catalogue is ported

INFORMATION_SCHEMA came across with the reference's own column lists, read verbatim from its getColumns(), with an index of its own whose cursor computes the rows at read time — so the view is always current. The schema is created with the database, as in the reference.

FilledEmpty for now
CATALOG_NAME, SCHEMATA, TABLES, VIEWS, COLUMNS, TABLE_CONSTRAINTS, KEY_COLUMN_USAGE, CONSTRAINT_COLUMN_USAGE, INDEXES, INDEX_COLUMNS, COLLATIONS (only OFF — no ICU in the port), SETTINGS (only the version)USERS, ROLES, RIGHTS, TABLE_PRIVILEGES, COLUMN_PRIVILEGES, PARAMETERS, ROUTINES, CONSTANTS, DOMAINS, TRIGGERS, SYNONYMS, SEQUENCES, SESSIONS, LOCKS and others — the views are there with the reference's columns, and fill as their objects arrive

The parser learned a qualified name in FROM (INFORMATION_SCHEMA.TABLES, an unknown schema giving 90079 as in the reference) and SYSTEM_RANGE(min, max[, step]) with its GENERATE_SERIES alias. A selection list may now be a comparison — SELECT COUNT(*) > 0 FROM … reads.

Verified against the reference: InformationSchemaOracleTests.TheCatalogueAnswersTheSameAsTheReference asks twelve questions (schemata, all tables, all columns — every one of the 33 views and all their columns — constraints, key usage, constraint usage, indexes, index columns, views, collations, SYSTEM_RANGE both ways) and compares every row and every cell.

Why the numbers differ from the site's mirror: the frozen docs are H2 2.5.252, while the reference checkout the port is written against is 2.5.259-SNAPSHOT (reference/H2_COMMIT.txt). On a disagreement the reference wins, not the snapshot. This site's mirror is the same 8 files the repo commits, verified byte-for-byte — python tools/verify-snapshot.py.

The providers

Two provider projects run alongside the engine, each in its own repository, each with its own history: dimzon/h2sharp-efcore — a fork of EFCore.PG with PostgreSQL's surface replaced by H2's, keeping EF Core's own specification suite as the measure; and dimzon/h2sharp-linq2db — written from scratch against linq2db's public API, not a fork.

RunPassedFailedTotal
Category!=BlockedByPort — the provider is correct as far as the port allows103401034
Category=BlockedByPort — the port defects the provider has signed up for19185206
Total10531851240

Both runs are needed, and the split is the point: a test failing because a function was not ported stays in the suite, tagged BlockedByPort, so the port's remaining work is visible rather than quietly removed. The provider is checked against the reference engine on the JVM, not against the port — a test against the port would only prove the port agrees with itself.

The engine gaps it is waiting on are numbered in its docs/DIVERGENCES.md: quoted column references, AS aliases (now landed), GENERATED … AS IDENTITY, FOREIGN KEY in CREATE TABLE, INTERVAL types, DB_CLOSE_DELAY, the INFORMATION_SCHEMA catalogue, and CREATE SEQUENCE.

The linq2db provider

Written from scratch against linq2db's public API and the engine's public API — not a fork of another provider. It generates H2's SQL: always-quoted identifiers, H2's own types, LIMIT/OFFSET, || for concatenation, named @name parameters, and a table alias without the AS — the form the engine reads. Query, insert, filter with a parameter and order work against the engine; the schema provider reads the catalogue the way H2 2.5 keeps it.

Its docs/DIVERGENCES.md lists the port defects it waits on, and every one of them is the engine's work, not a limit of H2: the catalogue's name differs from the reference's, DB_CLOSE_DELAY and file databases, the engine's catalogue not being reachable from the ADO layer (H2Connection.Session is internal), JOIN, AS before a table alias, identity DDL, CREATE SEQUENCE, and IN with a subquery.

Not yet — as port defects, not as limits of H2

The project's own wording: a feature missing from the port is unfinished work, not a property of the database. JOIN, subqueries, window functions, MERGE, INFORMATION_SCHEMA, CREATE SEQUENCE, identity DDL and AS before a table alias all exist in H2 2.5 and will be in the port — the orientation is the frozen documentation and the reference jar, not the port's current state. Each gap below is a tracked defect with an owner, and the tests that fail on it stay in the suite, tagged BlockedByPort.

Tests

ProjectCount
H2Sharp.Tests1115
H2Sharp.Data.Tests343, plus 19 red — the same AS-alias, CTE, JOIN and MERGE pins
H2Sharp.MvStore.Tests86
H2Sharp.Engine.Tests4 of 9 — red by design (the reference TestIndex port; the rest of the engine suite is not ported)
TODOException is the honest measure. The roadmap counts 236 sites across ~40 files, and it distinguishes a class that parses a statement and then refuses from one that works — that is why phases here say "partial" and not "done". The site does not restate a current count, because counting it yourself gives a different number (roughly 240 sites in ~50 files): the figure only means something at the commit it was measured at.
Reference pin: 27c51709fef687bc064f23c8dd495b566c69bb93 — H2 2.5.x, unchanged, so the SQL mirror is still valid.