Apache.Calcite.Adapter.AdoNet
2.0.0-pre.5
See the version list below for details.
dotnet add package Apache.Calcite.Adapter.AdoNet --version 2.0.0-pre.5
NuGet\Install-Package Apache.Calcite.Adapter.AdoNet -Version 2.0.0-pre.5
<PackageReference Include="Apache.Calcite.Adapter.AdoNet" Version="2.0.0-pre.5" />
<PackageVersion Include="Apache.Calcite.Adapter.AdoNet" Version="2.0.0-pre.5" />
<PackageReference Include="Apache.Calcite.Adapter.AdoNet" />
paket add Apache.Calcite.Adapter.AdoNet --version 2.0.0-pre.5
#r "nuget: Apache.Calcite.Adapter.AdoNet, 2.0.0-pre.5"
#:package Apache.Calcite.Adapter.AdoNet@2.0.0-pre.5
#addin nuget:?package=Apache.Calcite.Adapter.AdoNet&version=2.0.0-pre.5&prerelease
#tool nuget:?package=Apache.Calcite.Adapter.AdoNet&version=2.0.0-pre.5&prerelease
Apache.Calcite.Adapter.AdoNet
Apache.Calcite.Adapter.AdoNet lets Apache Calcite treat any ADO.NET data source as a first-class relational schema. Calcite can then plan and execute federated SQL queries across those sources — pushing filters, projections, joins, aggregations, sorts, and set operations down to the underlying database wherever possible.
Use this package together with Apache.Calcite.Data to federate SQL Server, SQLite, and any other ADO.NET-capable database under a single Calcite connection.
How it works
- You describe the remote database with an
AdoDataSource— aDbProviderFactoryplus a connection string, or a .NET 7+DbDataSource. - You register it with Calcite as a schema, either programmatically or through a JSON model.
- Calcite's planner produces a query plan, pushing as much SQL as possible back to the source in the right dialect.
- Whatever cannot be pushed down runs in-process, and the results arrive through the standard
DbDataReader.
Install
dotnet add package Apache.Calcite.Adapter.AdoNet
dotnet add package Apache.Calcite.Data
Targets .NET 8, and is verified on .NET 8 and .NET 10.
Quick start — code-driven registration
AdoSchema.Create builds the schema; SchemaPlus.add puts it on the connection under a name:
using Apache.Calcite.Adapter.AdoNet;
using Apache.Calcite.Data;
using Microsoft.Data.Sqlite;
// 1. Any DbDataSource will do. The matching metadata provider is chosen for you.
var dataSource = SqliteFactory.Instance.CreateDataSource("Data Source=sales.db");
// 2. Open a Calcite connection and attach the schema.
await using var conn = new CalciteConnection("Lex=JAVA;CaseSensitive=false");
await conn.OpenAsync();
var root = conn.RootSchema;
root.add("ADO", AdoSchema.Create(root, "ADO", dataSource, null, null));
// 3. Query it.
await using var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT NAME FROM ADO.EMPS WHERE SALARY > ? ORDER BY NAME";
cmd.Parameters.Add(new CalciteParameter("salary", 100.0));
await using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync())
Console.WriteLine(reader.GetString(0));
The last two arguments to AdoSchema.Create are the database and schema name to restrict discovery to; pass null for either to take the source's default. Overloads accept an AdoDataSource, an AdoDatabaseMetadata, or an AdoDatabaseMetadataFactory where you need to choose the metadata provider yourself.
Quick start — JSON model
The adapter can also be named from a Calcite model. Two things are required and neither is obvious:
- The
factoryvalue must be the IKVM name of the CLR class —cli.followed by its .NET full name. Calcite resolves a model's factory through Java'sClass.forName, which does not know a bare .NET type name. - The assembly must be on IKVM's boot class path before the connection is opened, because
Class.forNamecannot see a type that is only in a referenced assembly.
// Once, at startup — before opening any connection that uses the model.
ikvm.runtime.Startup.addBootClassPathAssembly(typeof(AdoSchemaFactory).Assembly);
DbProviderFactories.RegisterFactory("Microsoft.Data.Sqlite", SqliteFactory.Instance);
{
"version": "1.0",
"defaultSchema": "ADO",
"schemas": [
{
"name": "ADO",
"type": "custom",
"factory": "cli.Apache.Calcite.Adapter.AdoNet.AdoSchemaFactory",
"operand": {
"adoProviderName": "Microsoft.Data.Sqlite",
"adoConnectionString": "Data Source=sales.db"
}
}
]
}
await using var conn = new CalciteConnection($"Model=inline:{model};Lex=JAVA;CaseSensitive=false");
await conn.OpenAsync();
Operand reference
| Operand | Required | Meaning |
|---|---|---|
adoProviderName |
yes, unless adoDataSource is given |
Invariant name registered with DbProviderFactories. |
adoConnectionString |
yes, with adoProviderName |
Connection string handed to that factory. |
adoDataSource |
— | Assembly-qualified .NET type name of a DbDataSource with a parameterless constructor. Used instead of the two above. |
adoDatabaseMetadata |
— | Assembly-qualified .NET type name of an AdoDatabaseMetadata to use instead of the detected one. |
adoDatabaseMetadataFactory |
— | Assembly-qualified .NET type name of an AdoDatabaseMetadataFactory. |
adoDatabase |
— | Restrict discovery to one database. |
adoSchema |
— | Restrict discovery to one schema. |
A missing adoProviderName or adoConnectionString throws AdoCalciteException, and so does a type name that cannot be loaded.
Federated query across two databases
Federating across unrelated databases is the point of the adapter:
var root = conn.RootSchema;
root.add("SQL", AdoSchema.Create(root, "SQL", sqlServerDataSource, null, null));
root.add("SQLITE", AdoSchema.Create(root, "SQLITE", sqliteDataSource, null, null));
await using var cmd = conn.CreateCommand();
cmd.CommandText = """
SELECT s.CustomerId, s.Name, COUNT(o.OrderId) AS Orders
FROM SQL.Customers s
JOIN SQLITE.Orders o ON o.CustomerId = s.CustomerId
GROUP BY s.CustomerId, s.Name
""";
Each side is pushed to its own database as far as it can go, and the join runs in-process.
Provider support
AdoDatabaseMetadataFactoryImpl — the default, used when you do not name one — inspects the connection the data source produces and selects a metadata provider:
| Connection type | Discovery | Dialect |
|---|---|---|
Microsoft.Data.SqlClient.SqlConnection, System.Data.SqlClient.SqlConnection |
INFORMATION_SCHEMA, via GetSchema |
SQL Server, at the version the server reports |
Microsoft.Data.Sqlite.SqliteConnection |
PRAGMA table_xinfo |
SQLite |
System.Data.Odbc.OdbcConnection |
The ODBC catalog — SQLTables and SQLColumns, via GetSchema |
Whatever the driver names as the product behind it |
System.Data.OleDb.OleDbConnection |
The OLE DB schema rowsets, via GetSchema |
Whatever the provider names as the product behind it |
Anything else throws AdoCalciteException naming the connection type. To support it, derive from AdoDatabaseMetadata — the abstract base that supplies the SqlDialect, table and column enumeration, and type mapping — and pass your implementation to an AdoSchema.Create overload, or name it in the adoDatabaseMetadata operand. The built-in implementations are internal; AdoDatabaseMetadata and AdoDatabaseMetadataFactory are the extension points.
ODBC and OLE DB
Both front an unknown database, so both take the product name from the driver's DataSourceInformation collection and match it the way Calcite's own SqlDialectFactoryImpl does. An unrecognised name gets the generic ANSI dialect, which is Calcite's answer too. Neither has a default schema — a null schema means every schema rather than a particular one — so pass adoSchema (or the schemaName argument) where the database has more than one and the table names collide.
The parameter marker for both is ?, bound by position.
Two limitations worth knowing before choosing one of these over a native provider:
- A dialect matched from a product name alone is, in Calcite's words, an approximation. The version is carried where it changes the SQL — SQL Server below 2012 gets
TOP (n)rather thanOFFSET/FETCH— but a driver that will not report its product gets generic SQL. Name a metadata provider throughadoDatabaseMetadatawhere that is not good enough. System.Data.Odbchas no mapping for SQL Server'stimeordatetimeoffsetand throwsArgumentExceptionon reading either. The columns are still discovered and typed; only reading one fails. That is the driver, not the adapter.System.Data.OleDbcannot bind aDateTimeOffsetparameter at all — the Variant marshal refuses it on the client — and binds aTimeSpanthrough OLE DB'sDBTIME, which has no fractional seconds, so a bound time reaches the server truncated to the whole second. Reading both types works; only a correlated comparison on one is affected.
Key public types
| Type | Purpose |
|---|---|
AdoSchema |
The Calcite Schema that enumerates tables from a data source. AdoSchema.Create(...) is how you build one. |
AdoSchemaFactory |
The SchemaFactory a JSON model names. |
AdoDataSource |
Abstract base — implement to connect Calcite to any ADO.NET source. |
DbProviderAdoDataSource |
AdoDataSource over a DbProviderFactory, a connection string, and an AdoDatabaseMetadata. |
DbDataSourceAdoDataSource |
AdoDataSource over a .NET 7+ DbDataSource and an AdoDatabaseMetadata. |
AdoDatabaseMetadata |
Abstract base for schema, column, and dialect discovery. |
AdoDatabaseMetadataFactory |
Chooses the metadata provider for a data source. AdoDatabaseMetadataFactoryImpl.Instance is the default. |
AdoDatabaseSchema |
A single database-level schema within the adapter. |
AdoConvention |
The calling convention a pushed-down subtree is planned into. |
AdoRules |
The adapter's conversion rules. |
DbCommandEnricher |
Hook for adjusting each DbCommand before it runs. |
AdoCalciteException |
What the adapter throws. |
Pushdown support
The adapter provides Calcite conversion rules for these operators, which become SQL against the source when the dialect supports them:
AdoFilter—WHEREpredicatesAdoProject— column projectionsAdoJoin— inner and outer joinsAdoAggregate—GROUP BYand aggregate functionsAdoSort—ORDER BY,LIMIT,OFFSETAdoUnion/AdoIntersect/AdoMinus— set operationsAdoValues— constant value setsAdoTableScan— the scan itself
Anything that cannot be pushed down runs in-process. Converters exist into both execution conventions — AdoToClrEnumerableConverter for the compiled-.NET convention that Apache.Calcite.Data plans into, and AdoToEnumerableConverter for Calcite's own — so the adapter works under either.
Correlated sub-queries are supported: AdoCorrelationDataContext carries the outer row's values into the inner query.
Related packages
| Package | Purpose |
|---|---|
Apache.Calcite.Data |
The ADO.NET provider — required to open connections and execute SQL. |
Apache.Calcite.Extensions |
The calling convention plans are compiled into, the prepare pipeline behind it, and the IKVM interop helpers. |
Further reading
- Apache Calcite documentation
- Calcite adapters overview
- Calcite model JSON reference
- Source repository
License
Apache License 2.0.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net8.0
- Apache.Calcite.Extensions (>= 2.0.0-pre.5)
- IKVM (>= 8.15.0)
- IKVM.Java.Extensions (>= 8.15.0)
- System.Data.OleDb (>= 8.0.1)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 2.0.0-pre.7 | 56 | 8/14/2026 |
| 2.0.0-pre.5 | 54 | 8/12/2026 |
| 2.0.0-pre.4 | 55 | 8/11/2026 |
| 2.0.0-pre.3 | 59 | 8/10/2026 |
| 2.0.0-pre.2 | 66 | 8/9/2026 |
| 2.0.0-pre.1 | 64 | 8/9/2026 |
| 1.0.3 | 130 | 6/4/2026 |
| 1.0.2 | 130 | 5/28/2026 |
| 1.0.1 | 125 | 5/26/2026 |
| 1.0.0 | 109 | 5/26/2026 |
| 0.0.4 | 154 | 1/29/2026 |
| 0.0.3 | 144 | 1/29/2026 |
| 0.0.2 | 231 | 10/21/2025 |