Read-only ClickHouse Users
How hypequery works with ClickHouse users set to readonly = 1 or readonly = 2, and what each level costs you.
Give hypequery a dedicated ClickHouse user that can only read. ClickHouse has two ways to make a user read-only, and hypequery accepts both. They differ in one thing: whether hypequery can still apply its own query settings.
The two levels
readonly = 1 | readonly = 2 | |
|---|---|---|
| Blocks writes and schema changes | Yes | Yes |
| Accepts per-query settings | Only when the value matches the user's profile | Yes, except readonly itself |
| Limits hypequery can apply | Only what the profile already sets | All of them |
Both keep your data equally safe. The difference is who controls query limits:
- With
readonly = 1, only the user's profile does. Nobody, hypequery included, can change a setting for a single query. - With
readonly = 2, hypequery can tighten limits per query. To stop anyone raising a limit past what you allow, add constraints to the profile, for example amaxonmax_memory_usage.
Use readonly = 2 unless you have a reason not to. If you use readonly = 1,
put the limits you want in the user's profile.
TypeScript query builder
@hypequery/clickhouse sends one setting by default,
output_format_json_quote_64bit_integers = 1, so Int64 and wider values arrive
as exact strings.
readonly = 2and unrestricted users work without changes.- A
readonly = 1user works without changes if its profile already setsoutput_format_json_quote_64bit_integers = 1. - Otherwise, set
integerJsonEncoding: 'server-default'. Wide integers may then lose precision beyond2^53. See 64-bit integer encoding.
Any setting you pass yourself with .settings({...}) follows the same rule: a
readonly = 1 user rejects it unless the value already matches the profile.
Python datasets
The Python planner attaches readonly = 1, max_execution_time,
max_result_rows, max_result_bytes, and max_threads to every query. The
executor never silently drops a query limit.
readonly = 2: works without configuration. The user may not changereadonly, so when the driver reports that the user is already read-only the executor leaves out only the planner'sreadonlysetting. Every query limit still applies.readonly = 1: set the same limits in the user's profile. If a limit differs, ClickHouse rejects the query; change the profile rather than disabling the limit in HypeQuery.- Unrestricted users get all five settings, including
readonly = 1.
To require a read-only user, set readonly_policy="profile" on the
connection. The executor then refuses, before any query is sent, a user whose
profile does not enforce readonly = 1 or 2:
from hypequery.execution import ClickHouseConnection, create_clickhouse_executor
executor = create_clickhouse_executor(
ClickHouseConnection(
host="localhost",
username="hypequery_reader",
password="...",
readonly_policy="profile",
)
)
The same connection option works with create_async_clickhouse_executor.
Cancellation and deadlines still stop queries on the server for both levels,
because the executor cancels with KILL QUERY, which read-only users may run.
hypequery Cloud
Cloud's executor sends readonly = 2, server-side cancellation, per-query
resource limits, and precision-safe integers on every query. A readonly = 1 user
refuses those, so Cloud sends it no settings at all, and your profile is the only
protection those queries get.
When you connect a readonly = 1 user, setup lists what your profile leaves out,
for example "Cancelled queries keep running" or "No per-query memory limit". It
also generates the profile SQL that fixes it. You must confirm before saving.
This profile gives a readonly = 1 user every protection Cloud relies on:
CREATE SETTINGS PROFILE hypequery_cloud SETTINGS
readonly = 1,
cancel_http_readonly_queries_on_client_close = 1,
output_format_json_quote_64bit_integers = 1,
max_execution_time = 25,
timeout_overflow_mode = 'throw',
max_threads = 8,
max_memory_usage = 4294967296,
max_result_rows = 20000,
max_result_bytes = 67108864,
result_overflow_mode = 'throw'
TO hypequery_user;
Stricter limits are fine. Keep max_result_rows at 10,001 or more, or full pages
of results will be refused.