Data blocks work through SQL queries to the connected sources. A query is described in the block configuration, validated before execution, and its result is cached.
Execution and validation
- execution —
POST /api/query/executeagainst any connected source; - validation before execution —
POST /api/query/validate: syntax, columns, sources; - every query is capped at 30 seconds and 10,000 rows — protection from accidental “SELECT * FROM huge_table”;
- the query description supports Scriban document variables.
Caching
- cached results speed up reopening a report;
- cached result statistics —
GET /api/query/cache/statistics; - cleanup —
POST /api/query/cache/clear.
Server-side calculations
Heavy analytics is computed on the server: histograms (POST /api/query/histogram) and box plots (POST /api/query/boxplot) do not ship the raw data to the client — only the finished result travels.
Binding to a block
A query lives in the block configuration and is bound by queryId. The validator checks that the query and its source exist — details in the Validation & Auto-Fix section.
Values in a query
- placeholders like
@nameand:nameare passed to the database as query parameters — not by gluing text, so a stray value cannot “append” SQL; - the value comes from document variables, the report’s reader settings, header filters and a click on a chart; if the name is set in the report’s address, it wins;
- when no value is set, the parameter is empty (NULL): the query doesn’t crash — the “no filter selected” condition simply doesn’t trigger;
- a list of values is also passed as a single parameter — each database receives it its own way.
AI and performance
Don’t want to write SQL? Describe in words what you need — the AI will write or fix the query (details in the agent in the report). Performance tips: filter by dates, compute aggregates in SQL rather than in the block, and use a row limit.