Skip to content

NL2SQL 0.4.1

A hardening release: the REST routes that change the server need an admin role, indexing no longer calls the model unless you ask it to, table access is checked by schema as well as table, and one broken datasource no longer stops the engine from starting.

Released 2026-10-13.

Highlights

  • Adding or removing a datasource, changing the LLM and rebuilding the index over REST now need an admin role. With no role source configured, only clients on the same machine may call them.
  • nl2sql index and the indexing SDK calls no longer spend model tokens by default. Ask for descriptions with --enrich or enrich=True, and the comments already in your database are never overwritten.
  • Policies can name a schema: ds.schema.table and ds.schema.*. A grant on sales.orders no longer lets a plan read audit.orders.
  • A datasource that fails to start is marked unavailable and the rest keep working; a secret provider that fails to start stops startup with a message saying which one and why.

What's included

Fixes

  • Passwords and user names with @ : / # % now work for PostgreSQL, MySQL and SQL Server, and statement_timeout_ms is now enforced on SQL Server and DuckDB too (#249).
  • The REST admin routes require an admin role, a failed POST /datasource no longer echoes the connection string, and nl2sql-api pins the engine release it ships with (#250).
  • A secret provider that cannot start fails startup with a clear error; a datasource that cannot start is listed by list_unavailable_datasources() and in index_health() warnings instead of stopping the engine (#251).
  • Routing respects the answerability check's choice of datasources, and the decomposer now sees each datasource's description and table names (#252).
  • Enrichment is opt-in for every indexing entry point, only fills blank descriptions, logs a failure as one line, and a datasource added in code keeps its description (#254).
  • Tier 2 benchmarks run with curated answers off unless --use-curated is passed, and each case records whether its answer was verified or generated (#255).
  • Indexing profiles each column on its own, so a boolean, UUID, JSON or date column, or one failing query, no longer fails the whole datasource (#256).
  • Table access is decided on datasource, schema and table, the same way in the validator, schema retriever, executor and curated matcher (#257).
  • nl2sql setup checks and offers the right driver for bring-your-own PostgreSQL, MySQL, SQL Server and DuckDB databases, offers DuckDB as a type, and nl2sql install postgres installs the right extra (#258).

Known limits

  • A reverse proxy on the same host makes every request look like it comes from loopback. Set NL2SQL_API_ROLE_HEADER in that case.
  • The REST indexing routes do not take an enrich parameter, so they always index without enrichment.
  • There is no strict mode that fails startup when one datasource cannot start. Use nl2sql doctor as a deploy check.
  • The SQL Server timeout counts whole seconds, so statement_timeout_ms is rounded up.

Upgrading

pip install --upgrade "nl2sql-engine[demo]==0.4.1"

Breaking changes / behaviour changes: four, each of which needs a look before you upgrade.

  • REST admin routes need an admin role (#250). POST /datasource, DELETE /datasource/{id}, POST /llm, POST /index/{id}, POST /index-all and DELETE /index now need a role listed in NL2SQL_API_ADMIN_ROLES (comma-separated, default admin). With no role source configured, only loopback clients are allowed. What to do: set NL2SQL_API_ROLE_HEADER behind a proxy, or NL2SQL_API_ROLE=admin for a single-user deployment. In Docker, requests arrive from the bridge gateway rather than loopback, so one of these is needed.
  • Indexing enrichment is opt-in (#254). index_datasource, index_all_datasources and nl2sql index no longer call the LLM unless you pass enrich=True or --enrich, and enrichment never overwrites table or column comments from the database. What to do: if you relied on generated descriptions, add --enrich or enrich=True to your indexing calls.
  • Two-part policy entries mean the default schema (#257). ds.table now grants that table in the datasource's default schema only (public on PostgreSQL, dbo on SQL Server, the connected database on MySQL, main on SQLite and DuckDB). Three-part ds.schema.table and ds.schema.* entries are supported. What to do: for a table outside the default schema, write ds.schema.table or ds.schema.*. Policies on SQLite datasources, including the demo's, mean what they did before.
  • Startup failures (#251). A configured secret provider that fails to start now stops startup with an error naming it and the reason. A datasource that fails to start no longer stops the engine; it is reported as unavailable. What to do: fix or remove a broken entry in the secrets config, and check list_unavailable_datasources(), GET /api/v1/index/status or nl2sql doctor for datasources that did not start.

What's next

Next: 0.5, Configuration v2 and the extension registry.

Full changelog: v0.4.0...v0.4.1