Apache.Calcite.Data
1.0.1
dotnet add package Apache.Calcite.Data --version 1.0.1
NuGet\Install-Package Apache.Calcite.Data -Version 1.0.1
<PackageReference Include="Apache.Calcite.Data" Version="1.0.1" />
<PackageVersion Include="Apache.Calcite.Data" Version="1.0.1" />
<PackageReference Include="Apache.Calcite.Data" />
paket add Apache.Calcite.Data --version 1.0.1
#r "nuget: Apache.Calcite.Data, 1.0.1"
#:package Apache.Calcite.Data@1.0.1
#addin nuget:?package=Apache.Calcite.Data&version=1.0.1
#tool nuget:?package=Apache.Calcite.Data&version=1.0.1
Apache.Calcite.Data
Apache.Calcite.Data is a native, in-process ADO.NET provider for Apache Calcite — the SQL parser, optimizer, and execution framework that powers many leading database and data-virtualization products.
The Calcite engine runs directly inside your .NET process via IKVM. There is no JDBC driver, no Avatica server, and no separate process. SQL flows from your DbConnection straight into Calcite's planner.
Why use this?
- Standard ADO.NET — works with any code that understands
DbConnection/DbCommand/DbDataReader, including Dapper, EF Core conventions, and generic data-access layers. - Federated queries — join CSV files, in-memory collections, REST adapters, JDBC databases, and custom Calcite schemas in a single SQL statement.
- Rich SQL — standards-conformant SQL with window functions, lateral joins,
MATCH_RECOGNIZE, and much more. - Code-driven schemas — register .NET objects as Calcite schemas, tables, and user-defined functions at runtime via the
SchemaPlusAPI; no JSON model required. - No external dependencies — everything runs in-process; no server to provision or maintain.
Supported platforms
Targets .NET 8 and is verified on .NET 8 and .NET 10.
Install
dotnet add package Apache.Calcite.Data
Quick start — inline JSON model
The quickest way to connect is with an inline Calcite model that wires up one or more adapters:
using Apache.Calcite.Data;
const string model = """
{
"version": "1.0",
"defaultSchema": "SALES",
"schemas": [
{
"name": "SALES",
"type": "custom",
"factory": "org.apache.calcite.adapter.csv.CsvSchemaFactory",
"operand": { "directory": "sales" }
}
]
}
""";
await using var conn = new CalciteConnection($"Model=inline:{model}");
await conn.OpenAsync();
await using var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT \"NAME\", \"DEPTNO\" FROM \"EMPS\" WHERE \"DEPTNO\" = 10";
await using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync())
Console.WriteLine($"{reader.GetString(0)}\t{reader.GetInt32(1)}");
Quick start — model file
Point Model at a JSON file on disk:
await using var conn = new CalciteConnection("Model=path/to/model.json;Schema=SALES");
await conn.OpenAsync();
Parameterized queries
Calcite uses positional ? placeholders (ODBC-style). Parameters are matched to placeholders by the order they are added to Parameters; the ParameterName is informational only.
await using var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT \"NAME\" FROM \"EMPS\" WHERE \"DEPTNO\" = ? AND \"SALARY\" > ?";
cmd.Parameters.Add(new CalciteParameter("deptno", 10));
cmd.Parameters.Add(new CalciteParameter("salary", 50_000m));
await using var reader = await cmd.ExecuteReaderAsync();
while (await reader.ReadAsync())
Console.WriteLine(reader.GetString(0));
Code-driven schemas
Register .NET objects as Calcite schemas directly — no JSON model required:
using org.apache.calcite.schema;
await using var conn = new CalciteConnection();
await conn.OpenAsync();
SchemaPlus root = conn.RootSchema;
root.add("MEM", new MyCustomSchema()); // any org.apache.calcite.schema.Schema implementation
await using var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT * FROM \"MEM\".\"USERS\" ORDER BY \"ID\"";
await using var reader = await cmd.ExecuteReaderAsync();
Connection lifecycle
CalciteConnection is designed to be long-lived, mirroring the behaviour of Calcite's own JDBC driver. Opening a connection initialises the in-process Calcite engine, parses and validates the model, and builds the schema — work that is relatively expensive and intended to be amortised over many queries. Keep one connection (or one CalciteDataSource) open for the lifetime of a logical data source rather than opening and closing connections per query.
Thread safety:
- The ADO.NET layer (
CalciteConnection,CalciteCommand,CalciteDataReader, etc.) is thread-safe: multiple threads may share a single connection and issue concurrent commands against it. - The Calcite engine layer (schemas, the planner,
RootSchema, etc.) is thread-safe for concurrent reads and queries. Mutating the schema (e.g. callingRootSchema.add(...)) while queries are in-flight is Calcite's concern, not this provider's; refer to the Apache Calcite documentation for its concurrency guarantees.
Using DbDataSource (.NET 7+)
CalciteDataSource implements the modern DbDataSource pattern for dependency-injection and pooled-connection scenarios:
using Apache.Calcite.Data;
// Create once and share across the application (e.g. register as a singleton in DI).
await using var dataSource = new CalciteDataSource("Model=path/to/model.json");
await using var conn = await dataSource.OpenConnectionAsync();
await using var cmd = conn.CreateCommand();
cmd.CommandText = "SELECT COUNT(*) FROM \"ORDERS\"";
var count = await cmd.ExecuteScalarAsync();
Console.WriteLine($"Order count: {count}");
Using DbProviderFactory
using System.Data.Common;
using Apache.Calcite.Data;
// Register once at startup.
DbProviderFactories.RegisterFactory("Apache.Calcite.Data", CalciteProviderFactory.Instance);
// Resolve anywhere.
var factory = DbProviderFactories.GetFactory("Apache.Calcite.Data");
await using var conn = factory.CreateConnection()!;
conn.ConnectionString = "Model=path/to/model.json";
await conn.OpenAsync();
Connection string reference
All keys are exposed as typed properties on CalciteConnectionStringBuilder. Unknown keys are preserved and forwarded to the engine.
| Key | Type | Description |
|---|---|---|
Model |
string |
Path/URI to a Calcite model JSON file, or inline:<json> for an embedded model. |
Schema |
string |
Default schema name when identifiers are unqualified. |
CaseSensitive |
bool |
Whether identifier lookup is case-sensitive (default: true). |
Conformance |
string |
SQL conformance level: DEFAULT, STRICT_2003, PRAGMATIC_2003, etc. |
Lex |
string |
Lexical policy: ORACLE (default), MYSQL, MYSQL_ANSI, SQL_SERVER, JAVA, BIG_QUERY. |
Quoting |
string |
Quote style: DOUBLE_QUOTE, BACK_TICK, BACK_TICK_BACKSLASH, BRACKET. |
QuotedCasing |
string |
How quoted identifiers are stored: UNCHANGED, TO_UPPER, TO_LOWER. |
UnquotedCasing |
string |
How unquoted identifiers are stored: UNCHANGED, TO_UPPER, TO_LOWER. |
Fun |
string |
Extra function libraries: standard (default), oracle, spatial, or comma-separated combinations. |
TimeZone |
string |
Session time zone, e.g. UTC or gmt-3. Defaults to the JVM time zone. |
Conformance |
string |
SQL conformance level. |
DefaultNullCollation |
string |
How NULLs sort when NULLS FIRST/NULLS LAST is not specified. Default: HIGH (Oracle behaviour). |
ForceDecorrelate |
bool |
Whether the planner aggressively de-correlates subqueries (default: true). |
MaterializationsEnabled |
bool |
Whether the planner may use materializations (default: false). |
TypeCoercion |
bool |
Whether implicit type coercion is applied during validation (default: true). |
parserFactory |
string |
Custom SQL parser factory class, e.g. org.apache.calcite.sql.parser.ddl.SqlDdlParserImpl#FACTORY. |
Identifier casing
Calcite's default lexer (Lex=ORACLE) follows standard SQL rules:
| Identifier kind | Normalized to | Compared |
|---|---|---|
Unquoted (emps) |
Upper case (EMPS) |
Case-sensitive |
Quoted ("Emps") |
Unchanged (Emps) |
Case-sensitive |
Most built-in adapters (CSV, JDBC against H2/HSQLDB/Oracle) expose names in upper case, so unquoted identifiers work naturally with them.
If your schema uses mixed- or lower-case names, quote them:
cmd.CommandText = """SELECT "Name", "DeptNo" FROM "Emps" WHERE "DeptNo" = 10""";
Or switch to a case-insensitive lexer:
// Lex=MYSQL_ANSI: unquoted identifiers are left unchanged, matching is case-insensitive.
await using var conn = new CalciteConnection("Model=inline:{...};Lex=MYSQL_ANSI");
Accessing the Calcite engine directly
CalciteConnection exposes Calcite-native objects as typed .NET properties for advanced scenarios:
| Property | Java type | Purpose |
|---|---|---|
RootSchema |
org.apache.calcite.schema.SchemaPlus |
Add/remove schemas and tables at runtime. |
TypeFactory |
org.apache.calcite.adapter.java.JavaTypeFactory |
Construct Calcite RelDataType instances. |
Config |
org.apache.calcite.config.CalciteConnectionConfig |
Inspect resolved connection configuration. |
These properties are only valid while the connection is open.
Related packages
| Package | Purpose |
|---|---|
Apache.Calcite.Adapter.AdoNet |
Expose any ADO.NET data source as a federated Calcite schema with query pushdown. |
Apache.Calcite.Extensions |
.NET helper types for working with Calcite connection properties and IKVM interop. |
Further reading
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
- IKVM (>= 8.15.0)
- IKVM.Java.Extensions (>= 8.15.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.