Skip to main content

semql-engine

In-process executor for semql FederatedPlan results. Runs each per-backend fragment via a caller-supplied Adapter, materialises the rows into in-memory DuckDB, then runs the plan's merge SQL against the assembled tables.

semql core stays sans-io. semql-engine is the opt-in package that turns a FederatedPlan into result rows when you want the cross-source execution done for you.

Install

pip install semql-engine

Quickstart

import duckdb
from semql import Catalog, Dialect, compile_federated_query
from semql_engine import DuckDBAdapter, Engine

catalog = Catalog([...])  # cubes spanning multiple backends
plan = compile_federated_query(query, catalog.as_dict())

engine = Engine()
engine.register(Dialect.POSTGRES, my_pg_adapter)
engine.register(Dialect.BIGQUERY, my_bq_adapter)
result = engine.run(plan)
result.columns  # ['region', 'revenue', ...]
result.rows     # [(...), ...]   — or stream with engine.iter_rows(plan)

What it does

For every fragment in the plan, the engine calls the adapter registered for that backend with (sql, params). It loads the resulting rows into a DuckDB table named frag_<i> (matching FederatedPlan.fragments indices) and finally applies plan.merge_spec — rendered to DuckDB SQL by semql_engine.merge — to produce the merged shape.

Single-fragment plans (single-backend queries that went through compile_federated_query anyway) work transparently — the merge is a pass-through.

Execution integrity and analysis

Both synchronous and asynchronous execution validate executable versions and every fragment's final binding manifest before any source adapter is called. The synchronous cache path performs that preflight before lookup as well. Merge bindings are validated before merge execution. Missing/renamed parameters, unsupported versions, and mismatched output columns raise ExecutionContractError, catchable as both EngineError and core ContractError. Driver exceptions are not silently converted into successful results.

result.analysis belongs to the current artifact, including on cache hits. result.validation_evidence describes materialized merge-key checks actually performed; a cache hit does not invent fresh validation evidence. Iterator results expose their own analysis and validation_evidence, not shared per-engine state. The async engine does not provide a result cache.

Declared one-side merge keys are checked together on the exact materialized fragment consumed by the merge, respecting its null-key semantics. Observed duplicates and uncheckable explicit materialized-key obligations reject. Underlying database keys/cardinalities that cannot be inspected remain trusted catalog assumptions; the executor does not run a separate database-probing service or require host waivers for those declarations.

Internal exception/artifact dumps may include private information. Use error.to_public_payload() for routine external diagnostics. Recompile stored plans with unsupported executable versions rather than changing their version number by hand.

Adapters

An Adapter is anything with execute(sql, params) -> AdapterResult where AdapterResult carries columns: list[str] and an iterable of positional rows aligned exactly to those columns. Built-ins:

  • DuckDBAdapter(con) — runs the SQL inside an existing DuckDB connection. Useful for local CSV / Parquet enrichment cubes.
  • DBAPIAdapter(con) — wraps any PEP-249 connection (psycopg, mysql, sqlite, etc).

Bring your own for warehouses that need a vendor SDK.

Semi-joins

A cross-backend semi-join (restrict an outer dimension to the value set of an inner query, shipped as a value list rather than a join) compiles to a SemiJoinPlan via semql.compile_semi_join_query. Run it with run_semi_join(plan, engine) — it executes each inner plan, projects the key column to a value list, and runs the outer query with that list bound as an IN / NOT IN filter:

from semql import compile_semi_join_query
from semql_engine import Engine, run_semi_join

plan = compile_semi_join_query(query, catalog.as_dict())
result = run_semi_join(plan, engine)  # same ExecutionResult shape as run()

Scope

The supported strategy is explicit:

  • Distributive federation supports existing legal recipes, including SUM of partial counts and AVG recomposed from partial sums and non-null counts.
  • Explicit mode="raw_rows" preserves existing raw-row aggregation recipes, including distinct counts, min/max, percentiles, and catalog-declared ratios. The compiler never silently switches to this more expensive strategy.
  • Multi-backend inline-derived measures reject instead of disappearing.
  • Aliases and requested output order survive the final merge.
  • Symmetric multi-fact aggregation uses observed qualifying facts, not an implicit full dimension universe. Keys present in only one fact, including qualifying all-null fact rows, remain; keys absent from all facts do not.
  • Cross-backend joins retain the existing supported equality-key restrictions. Cross-backend comparison/fill and independently planned new operators are not added by the semantic-contract release.

The engine itself is small; most of the federation logic lives in semql.federate.

Backend conformance tests

From the workspace root, with Docker running:

uv sync --python 3.12 --all-extras --frozen
just test-conformance

This enables SEMQL_CONFORMANCE_TESTCONTAINERS=1. The existing result fixtures provision disposable PostgreSQL and ClickHouse containers on dynamically mapped ports, execute emitted SQL without rewriting, and stop the containers afterward. Startup or readiness failures fail the requested run rather than silently skipping. DuckDB runs in-process and does not require Docker.

SEMQL_CONFORMANCE_POSTGRES (a psycopg DSN) and SEMQL_CONFORMANCE_CLICKHOUSE (an HTTP URL) override provisioning per backend, allowing the same fixtures to target externally managed disposable services. Without the Testcontainers opt-in or an explicit endpoint, external-backend cells skip in the ordinary local suite. The full-suite CI job enables Testcontainers.

Status

Pre-v1. Compiler and executor packages release in lockstep. The first-release semantic contract and verification inventory are recorded in compiler-semantic-contract-2026-10-01.md.

Metadata

Release files for semql-engine 0.10.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for semql-engine 0.10.0
File Size Uploaded Provenance
semql_engine-0.10.0.tar.gz 28.7 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for semql-engine 0.10.0
File Interpreter ABI Platform
semql_engine-0.10.0-py3-none-any.whl Python 3 none any Details

Total release size: 61.6 kB

Release files / semql_engine-0.10.0.tar.gz

Download URL semql_engine-0.10.0.tar.gz
Size 28.7 kB
Tags Source
SHA-256 checksum
How to use checksums
7862b609016837d013a69a4bdf84a57a4e3b5f4c661413bfe7e96b40cbb7c906
BLAKE2b-256 checksum
How to use checksums
e15dc89d5b5f3973d736e4cc9aea84bb51b63685a4b5e521d619e92dc8800f86
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Release files / semql_engine-0.10.0-py3-none-any.whl

Download URL semql_engine-0.10.0-py3-none-any.whl
Size 32.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
07ee5715dd0dcd4be1c9b45819556a774e81ebc0d391c6be3275259d14ef6a83
BLAKE2b-256 checksum
How to use checksums
be15fa9c953aa00002a0a0b724cad0ac34799a1de9d310d8c23689f7a4642ae8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

Security for semql-engine 0.10.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for semql_engine-0.10.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 2, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page