Skip to content

chkit query

Executes an ad-hoc SQL query against the configured target and prints the result.

chkit query "<sql>" [flags]

The SQL must be a single positional argument. Wrap it in quotes if it contains spaces.

An argument that starts with -, such as -x or --bogus, is read as a flag, and an unknown one is an error. SQL that starts with a line comment (-- note followed by a newline and the query) is still SQL: an argument that holds a line break, or a space before any =, is never read as a flag. To pass any other SQL that starts with -, put -- before it: chkit query -- "<sql>".

No command-specific flags. See global flags.

When the ObsessionDB plugin is loaded, chkit query also accepts --service <name-or-alias> to route the query to a specific service for this invocation (see Per-command override).

chkit query runs the SQL through whichever executor is active:

  • Without any plugin override, it uses the clickhouse connection from your config.
  • With the ObsessionDB plugin loaded, it routes the query to the selected service (or to the service named with --service).

The command requires an executor — if no clickhouse config is present and no plugin supplies one, it exits with an error.

Over the clickhouse connection, chkit query asks ClickHouse for progress headers every 30 seconds (send_progress_in_http_headers, http_headers_progress_interval_ms), which keep a long query’s connection open through a proxy or load balancer with an idle timeout. A readonly = 1 user cannot change any setting, so chkit checks the user’s readonly level once and sends that user no settings. A read-only user (readonly = 1 or readonly = 2) can run chkit query.

chkit query reads the result in ClickHouse’s JSON format, appending FORMAT JSON to the statement. A statement without a result set, such as CREATE, DROP, OPTIMIZE or INSERT ... SELECT, prints (no rows), and --json prints an envelope with empty data and meta and rows set to 0. INSERT ... VALUES with inline data is not supported, because ClickHouse reads the appended FORMAT JSON as part of the values; use INSERT ... SELECT instead.

The table and --json print the same values. A 64-bit or wider integer or a Decimal keeps every digit ClickHouse sent (see large integers and Decimals). The TypeScript CLI needs Node.js 22 or later, or Bun, for this: on an older Node.js, a query that returns such a column fails with an error instead of printing rounded digits. In the table, strings print without quotes, and arrays, maps and tuples print as compact JSON:

u64max │ d128 │ arr_u64
─────────────────────┼────────────────────────────────┼─────────────────────────────
18446744073709551615 │ 12345678901234567890.123456789 │ ["18446744073709551615","1"]
(1 row)
Terminal window
chkit query "SELECT count() FROM users"
count()
───────
42
(1 row)

Override the ObsessionDB service for a single query by service name or saved alias:

Terminal window
chkit query "SELECT count() FROM users" --service customer-b

Machine-readable JSON output:

Terminal window
chkit query "SELECT count() FROM users" --json
CodeMeaning
0Query executed successfully
1Missing SQL, no executor configured, or query failed

--json prints the raw ClickHouse result envelope (the JSON format), not a chkit-specific wrapper:

{
"data": [
{ "count()": "42" }
],
"meta": [
{ "name": "count()", "type": "UInt64" }
],
"rows": 1,
"statistics": {
"elapsed": 0.000773,
"rows_read": 1,
"bytes_read": 1
},
"query_id": "6f1c0e8e-5d5a-4f0e-9c1b-2b8d7c3e9a41"
}
  • data — the result rows.
  • meta — column names and ClickHouse types.
  • rows — the row count (a number), not the rows array.
  • statistics — server-side timing and read counters.
  • query_id — present when the executor reports it.

There is no rowCount, command, or schemaVersion field; the row count lives in rows.

ClickHouse writes 64-bit and wider integers and Decimals as bare JSON numbers, which many JSON parsers read as 64-bit floats: 18446744073709551615 becomes 18446744073709552000, and a Decimal128 loses digits. chkit query reads them without losing digits and prints them as strings of the digits ClickHouse sent, the same in the TypeScript CLI and chkit-py:

ClickHouse typeJSON value
UInt8–UInt32, Int8–Int32, Float32, Float64number
UInt64, Int64, UInt128, Int128, UInt256, Int256string, e.g. "18446744073709551615"
Decimal(P, S) of any widthstring, e.g. "12345678901234567890.123456789"
JSON, Object, Dynamicnumber, or string when a 64-bit float cannot hold it

Every number in a column whose type contains a 64-bit or wider integer or a Decimal is a string, in data and in the totals (WITH TOTALS) and extremes (SETTINGS extremes = 1) rows, also inside arrays, maps, tuples and Nullable: Array(UInt64) prints ["18446744073709551615","1"], and Tuple(UInt8, UInt64) prints both numbers as strings. A column whose type contains JSON, Object or Dynamic holds numbers of any type, so a number in it is a string only when a 64-bit float would print other digits: CAST('{"a": 2.5, "b": [1, 0.1], "u": 18446744073709551615}' AS JSON) prints {"a":2.5,"b":[1,0.1],"u":"18446744073709551615"}. meta[].type gives each column’s type. Through an ObsessionDB service the console API returns every value as a string.