Qrly speaks JDBC to twenty native engines and to the AWS, Azure and GCP managed variants, and compiles every query through the right dialect — quoting, pagination, NULL ordering and date bucketing included. Connections are read-only by default and credentials are encrypted at rest.
The honest version. Every engine below has a driver in the build; the third column lists the ones that do not.
Forty connection types across twelve dialect compilers. Wire-compatible engines fold into an existing dialect rather than getting a half-finished one of their own.
| Engine | Category | Compiles as | Notes |
|---|---|---|---|
| PostgreSQL | Transactional | POSTGRES | The reference dialect. Full-text search, JSONB, array and range operators, LISTEN/NOTIFY live dashboards, COPY ingest and logical-replication CDC |
| MySQL | Transactional | MYSQL | NULLS ordering emulated with (field IS NULL); binlog CDC; ON DUPLICATE KEY upsert |
| MariaDB | Transactional | MARIADB | Its own compiler rather than a MySQL alias; NULLS ordering emulated; binlog CDC |
| SQL Server | Transactional | SQLSERVER | Bracketed identifiers, OFFSET…FETCH NEXT, sp_rename staging swap, database-level CDC with per-table capture instances |
| SQLite | Embedded | SQLITE | Affinity-aware type classification; native upsert; NULLS ordering emulated. Week and quarter date buckets are rejected |
| H2 | Embedded | H2 | Supports full-text search operators and OLAP grouping sets |
| HSQLDB | Embedded | H2 | Folds into the H2 compiler |
| Derby | Embedded | H2 | Folds into the H2 compiler |
| DuckDB | Analytical | POSTGRES | Wire-compatible, so it inherits the Postgres compiler |
| Snowflake | Warehouse | SNOWFLAKE | variant and timestamp_ltz normalised by the type classifier; grouping sets supported; Constructions warns that Snowflake has no CREATE INDEX |
| Redshift | Warehouse | REDSHIFT | Full-text search, JSON, array and range operators; native COPY ingest; repeatable-read snapshots for FK group sync |
| BigQuery | Warehouse | BIGQUERY | Service-account key auth; struct and bytes normalised; grouping sets supported; staging swap falls back to drop, create and insert in one transaction |
| ClickHouse | Analytical | POSTGRES | Wire-compatible, so it inherits the Postgres compiler |
| Vertica | Warehouse | POSTGRES | Wire-compatible, so it inherits the Postgres compiler |
| Trino | Federated | POSTGRES | Reaches engines Qrly has no driver for, through one connection |
| Presto | Federated | POSTGRES | Same fold as Trino |
| SingleStore | Warehouse | MYSQL | MySQL wire protocol, so it inherits the MySQL compiler |
| DB2 | Transactional | DB2 | Its own compiler, including TRUNC_TIMESTAMP date bucketing |
| Sybase | Transactional | SYBASE | Reached over jTDS. Rejects OFFSET, so pagination is TOP n only; NULLS ordering emulated |
| Pervasive | Transactional | PERVASIVE | Its own compiler |
| Platform | Service | Underlying engine | Notes |
|---|---|---|---|
| AWS | Aurora Postgres | PostgreSQL | Its own connection type, so defaults and tooling can differ from a self-managed Postgres |
| AWS | Aurora MySQL | MySQL | Its own connection type |
| AWS | RDS Postgres | PostgreSQL | Its own connection type |
| AWS | RDS MySQL | MySQL | Its own connection type |
| AWS | RDS MariaDB | MariaDB | Its own connection type |
| AWS | RDS SQL Server | SQL Server | Its own connection type |
| AWS | Redshift | Redshift | Compiles through the dedicated REDSHIFT dialect |
| AWS | Athena | Presto-family | Explicitly folded into the POSTGRES compiler |
| Azure | Azure SQL | SQL Server | Auth modes include service principal, managed identity and AAD password |
| Azure | Synapse | SQL Server | Adds the Synapse tooling below — external tables and views, and generated OPENROWSET Delta Lake view DDL |
| Azure | Database for PostgreSQL | PostgreSQL | Its own connection type |
| Azure | Database for MySQL | MySQL | Its own connection type |
| Azure | Database for MariaDB | MariaDB | Its own connection type |
| GCP | Cloud SQL for PostgreSQL | PostgreSQL | Its own connection type |
| GCP | Cloud SQL for MySQL | MySQL | Its own connection type |
| GCP | Cloud SQL for SQL Server | SQL Server | Its own connection type |
| GCP | AlloyDB | PostgreSQL | Its own connection type |
| GCP | BigQuery | BigQuery | Compiles through the dedicated BIGQUERY dialect; service-account key auth |
| GCP | Spanner | Spanner | Explicitly folded into the POSTGRES compiler |
The dialect layer exists because the same query means four different things in four different engines. Here is exactly what it resolves.
Double quotes on the Postgres family, backticks on MySQL and MariaDB, square brackets on SQL Server. Every table, column and alias Qrly emits is quoted for the target engine, and identifiers are regex-validated before they get anywhere near a statement, alongside a cast allow-list of thirty entries.
The twelve compilers are POSTGRES, MYSQL, MARIADB, SQLSERVER, BIGQUERY, SNOWFLAKE, REDSHIFT, SQLITE, H2, DB2, SYBASE and PERVASIVE.
Three incompatible spellings for the same idea: LIMIT n OFFSET m on the Postgres and MySQL families, OFFSET m ROWS FETCH NEXT n ROWS ONLY on SQL Server and its managed variants, and TOP n where neither is available.
Sybase rejects OFFSET outright, so a query against it is compiled without one rather than being emitted and failing at the driver. The limit and offset in a QQL document are engine-independent; the compiler decides how to say them.
QQL order-by carries ASC/DESC plus NULLS FIRST, NULLS LAST or the database default. Engines that support the clause natively get it verbatim.
Engines that do not — MySQL, MariaDB, SQLite and Sybase — get an automatic (field IS NULL) emulation expression prepended to the sort, so the result set is ordered identically whichever connection the question runs against. That matters the moment a question is repointed at a different environment.
Six bucket levels compiled per engine with the right function: DATE_TRUNC, DATETRUNC, TRUNC_TIMESTAMP, DATE_FORMAT, STRFTIME, or DATEADD/DATEDIFF arithmetic where no truncation function exists. The same six levels drive the OLAP time hierarchy and its period-over-period comparisons.
SQLite rejects week and quarter buckets and says so rather than returning a quietly wrong grouping.
Not every capability exists on every engine. These are the differences worth knowing before you pick a connection.
| Capability | Available on | What happens elsewhere |
|---|---|---|
| Full-text search operators | PostgreSQL, Redshift, H2 | FTS, PLFTS, PHFTS and WFTS — with a validated optional language argument — are Postgres-family only. Elsewhere, use CONTAINS, LIKE, ILIKE or the regex operators MATCH and IMATCH |
| JSON, array and range operators | PostgreSQL, Redshift | Containment (@>, <@), overlap (&&), the range operators <<, >>, &<, &>, -|-, HAS_ELEMENT and the JSON-path operators are Postgres-family only |
OFFSET pagination |
Everything except Sybase | Sybase rejects OFFSET; the compiler emits TOP n instead |
| Week and quarter date buckets | Everything except SQLite | SQLite rejects both levels rather than approximating them |
| NULLS FIRST / NULLS LAST | PostgreSQL, SQL Server, Snowflake, Redshift, BigQuery, DB2, H2 | MySQL, MariaDB, SQLite and Sybase get an automatic (field IS NULL) emulation expression |
| ROLLUP, CUBE, GROUPING SETS | PostgreSQL, BigQuery, Snowflake, Redshift, SQL Server, H2 | MySQL and MariaDB get WITH ROLLUP only |
| Native bulk ingest for sync | PostgreSQL, Redshift | Native COPY with automatic fallback to batched INSERT everywhere else |
| Atomic staging swap | PostgreSQL, MySQL, SQL Server | Postgres rename, MySQL RENAME TABLE, SQL Server sp_rename. BigQuery falls back to drop, create and insert in a single transaction |
| CDC capture | PostgreSQL, MySQL, MariaDB, SQL Server | Postgres logical replication with a per-source slot and publication, MySQL and MariaDB binlog with a derived unique server id, SQL Server database-level CDC. Other engines use full reload, watermark or snapshot-delta sync |
| Live dashboards over push | PostgreSQL | LISTEN/NOTIFY on the data source re-runs the affected cards. Every other engine uses the interval strategy |
| Index creation in Constructions | Most engines | The plan preview warns where an engine has no CREATE INDEX — Snowflake, for example — before anything is executed. SQLite inlines foreign keys with a warning |
Connections are scoped to an organisation and optionally to a project, and can be tested both before and after saving.
SQL authentication, service principal, managed identity and AAD password. Credentials are AES-encrypted in the application database, and each connection carries an extra-options JSON block for SSL settings, an SSH tunnel — host, port, user, private key and passphrase — and a BigQuery service-account key where that applies.
Because Qrly is self-hosted, the usual answer to network reachability is that it already sits inside your network. The tunnel is there for the cases where it does not.
Query timeout (60 s), max rows (10,000), max stream rows (1,000,000), max concurrent queries (4), max queue size (20) and queue wait timeout (30 s) — all set per connection, so a reporting replica and a production primary can carry different rules.
The query governor enforces the last three with a semaphore sized to the concurrency limit and a FIFO wait queue, returning a queue-full error on overflow and a timeout when the wait expires. The admin page shows live per-connection stats — active, queued, max concurrent, max queue and last wait — with a recent-events table.
Every connection declares a role: SOURCE for reading, CACHE_TARGET for receiving materialized tables and synced tables, or BOTH. An organisation nominates a default cache-target pointer, so the materialization and table-sync tiers know where to write without being told each time.
That separation is what lets Qrly write a question's result — or a whole replicated table — into a database you own, queryable by any other tool you run.
A connection carries its own ddl_enabled flag, and it is the third tier of the Constructions cascade: the tenant, the organisation and the connection must each have DDL enabled, and all three default to off.
When a design is blocked, the policy service reports the outermost blocking tier, so an administrator knows which switch to look at rather than guessing down the chain.
Schema sync defaults to off. Switch it on and everything below becomes available.
| Feature | What it does |
|---|---|
| Schema sync | Opt-in, default off. A manual trigger plus a nightly scheduler. It is what powers SQL autocomplete in the Monaco editor and the table and column pickers in the visual query builder |
| Curated metadata | Override display names and descriptions on tables and columns, so cust_ord_hdr reads as "Customer orders" for everyone who did not design the schema |
| Data dictionary | A paginated register of table, column, type, nullable, primary key, foreign key, unique, indexed, description and enum values — exportable as CSV, XLSX, PDF and Markdown, with a print view |
| ERD viewer | A Mermaid entity-relationship diagram with relationships-only or all-tables modes, column detail set to all, keys or none, table multi-select, pointer-anchored zoom from 0.1x to 4x, pan, fit and fullscreen |
| Freshness probe | Nominate a table and a timestamp column; a five-minute scheduler runs SELECT MAX(col) and drives the "Data as of …" badges shown on questions and dashboards |
| Browse endpoints | Schema browse and per-table detail endpoints, so the schema is available to the API and to the AI tool layer as well as the UI |
| AI on the schema | Describe a table, describe all tables, and a written explanation of what the connection holds, with regenerate. Per-connection aiSystemPrompt, and aiRowAccessEnabled is opt-in — schema-only by default, so no row ever reaches a model unless you say so |
A BI tool that can drop a table is a BI tool nobody will point at production. Qrly's query path cannot.
Not a convention, not a documented recommendation — four independent mechanisms, each of which would have to fail for a write to reach your source.
setReadOnly(true) applied, so the driver itself refuses a write before any Qrly code is consulted.SELECT or WITH. A long keyword blocklist is rejected outright: DROP, DELETE, INSERT, UPDATE, TRUNCATE, ALTER, CREATE, GRANT, REVOKE, EXECUTE, EXEC, CALL, MERGE, REPLACE, LOAD, IMPORT, EXPORT, COPY, VACUUM, ANALYZE, LISTEN, NOTIFY, LOCK, SET, RESET, BEGIN, COMMIT, ROLLBACK, SAVEPOINT, DO, DECLARE and REFRESH. The Monaco editor mirrors the same list client-side, so the warning appears as you type rather than on run.{{template_variables}} and interactive filter values become prepared-statement parameters, typed from their declaration or from context — never string-interpolated. Calculated fields go through a separate expression sanitizer: no semicolons, no comments, no DDL, DML or subquery keywords, balanced parentheses and quotes, a 1,000-character cap, identifier rules and a reserved-word list.ddl_enabled, all defaulting to off — on top of which the caller needs FULL data access on the target. Statements run one at a time in auto-commit, stopping at the first failure, and each run records the verbatim SQL, the statement count, the status, the duration and who triggered it. Even the AI assistant cannot bypass this: it proposes a design document, never SQL, which is rebuilt field by field through the DDL generator as a trust boundary.Permissions sit above all of this: data access runs NO_ACCESS → RESTRICTED (run saved questions only, cannot author SQL) → FULL (author and run any SQL — also required for RPC, table writes and applying a Construction). Every executed statement lands in the query audit log with its row count, duration, status and error, under a retention policy enforced daily.
Serverless SQL over a data lake is a different job from querying a table, so it has a different surface.
Browse the external tables and views defined in a Synapse workspace directly from the connection, alongside the ordinary schema browser. What is already published in the lake is visible without leaving Qrly.
Generate OPENROWSET Delta Lake view DDL either from an existing object — pointing at what is already there — or from scratch, and preview the Delta paths before anything is created. The generated DDL is a script you review, not something applied behind your back.
Once a view exists, Synapse behaves like any other connection: schema sync, the data dictionary, the ERD, the visual builder, QQL, OLAP models, dashboards, alerts and the Data API all work against it unchanged.
Read-only enforcement, per-connection execution limits, the query governor, the per-user daily query budget and the query audit log apply identically. Synapse tooling adds a surface; it does not open a side door.
Forty connection types. Twenty native engines — PostgreSQL, MySQL, MariaDB, SQL Server, SQLite, H2, HSQLDB, Derby, DuckDB, Snowflake, Redshift, BigQuery, ClickHouse, Vertica, Trino, Presto, SingleStore, DB2, Sybase via jTDS and Pervasive.
Plus the managed-cloud variants, each with its own type string: AWS Aurora Postgres and MySQL, RDS Postgres, MySQL, MariaDB and SQL Server, Redshift and Athena; Azure SQL, Synapse, Postgres, MySQL and MariaDB; GCP Cloud SQL Postgres, MySQL and SQL Server, AlloyDB, BigQuery and Spanner.
They are not supported. Oracle, Teradata, SAP HANA, Cassandra, MongoDB, Dremio and Firebird have no driver and no dependency in the build, and CockroachDB is recognised by the dialect resolver but has no driver mapping. Older project notes list some of those engines; the shipping code does not, and we would rather say so here than after a proof of concept.
There are two workable routes. Trino and Presto are both supported and both compile as Postgres, so a federated query engine can front what Qrly cannot reach directly. Or replicate the tables you need into a supported target with table sync, and query the copy.
Twelve dialect compilers — POSTGRES, MYSQL, MARIADB, SQLSERVER, BIGQUERY, SNOWFLAKE, REDSHIFT, SQLITE, H2, DB2, SYBASE and PERVASIVE — cover all forty connection types, because wire-compatible engines fold into an existing dialect rather than getting a half-finished one of their own. CockroachDB, Vertica, Trino, Presto, DuckDB, ClickHouse, Athena and Spanner compile as POSTGRES; SingleStore as MYSQL; HSQLDB and Derby as H2. Unknown types default to POSTGRES.
Each dialect resolves identifier quoting, the pagination form (LIMIT/OFFSET, OFFSET…FETCH NEXT or TOP n), NULLS FIRST/LAST support with an emulation expression where the engine lacks it, and per-level date bucketing with the right function spelling. A type classifier normalises the raw JDBC type names on top, so the filter UI offers the operators that engine actually supports.
Not through the query path. The connection pool hands out read-only connections, native SQL must start with SELECT or WITH, a long keyword blocklist covering DROP, DELETE, INSERT, UPDATE, TRUNCATE, ALTER, CREATE, GRANT, REVOKE, EXEC, CALL, MERGE, COPY, SET and more is rejected outright, and every parameter is bound rather than interpolated.
DDL is only ever possible through Constructions, and only when the tenant, the organisation and the connection all have DDL enabled — three flags that each default to off — and the caller additionally holds FULL data access on the target. Materialized tables and table sync write only to a connection you have explicitly marked CACHE_TARGET or BOTH.
Schema sync is opt-in and defaults to off. When you enable it you can trigger it manually or leave it to the nightly scheduler; it powers SQL autocomplete and the visual query builder.
On top of the raw schema you can curate metadata — override display names and descriptions on tables and columns — browse a paginated data dictionary exportable as CSV, XLSX, PDF and Markdown, and read the relationships as a Mermaid ERD with pointer-anchored zoom from 0.1x to 4x. Sending actual row data to an AI provider is a separate per-connection opt-in; the default is schema-only.
Qrly is self-hosted, so in most deployments it already sits inside the same network as the database and no tunnel is needed at all.
Where it does not, each connection carries an extra-options JSON block supporting SSL settings and an SSH tunnel with host, port, user, private key and passphrase, plus a BigQuery service-account key where that applies. Authentication modes cover SQL auth, service principal, managed identity and AAD password, every credential is AES-encrypted at rest, and the connection can be tested both before and after saving.
Page updated 28 August 2026. Connectivity reflects Qrly 1.1.695.
Qrly runs on your own infrastructure, next to the data. Connect, test, sync the schema if you want autocomplete — and query read-only from the first minute.