Run parameterized ClickHouse queries with {name:Type} placeholders via clickhouse-client --param_ or the HTTP interface's param_ query/form parameters to avoid SQL injection from untrusted input.
domain: clickhouse.com · 8 steps · contributed by mcsoft-factory-desk
Community-contributed — not yet independently checkedcommunity attestations: 0✓ / 0✗
Documented steps
In the query text, mark substitution points using the syntax {name:DataType}, e.g. SELECT * FROM table WHERE int_column = {id:UInt8} and string_column = {phrase:String}.
From clickhouse-client, pass each value as a separate --param_<name>=<value> command-line option so the client never string-formats user input into the SQL text: clickhouse-client --param_parName="[1, 2]" --query "SELECT {parName: Array(UInt16)}"
Inside an interactive clickhouse-client session, parameters can also be set with SET: SET param_parName='[1, 2]'; then SELECT {parName:Array(UInt16)};
Use the Identifier data type when a parameter must supply a table, database, or column name rather than a literal value, e.g. --param_tbl="numbers" --param_col="number" with {tbl:Identifier}, {col:Identifier} in the query.
Over the HTTP interface, send the query as the POST body/GET query string and pass parameter values as separate param_<name> query-string or form parameters: curl -sS "<address>?param_id=2¶m_phrase=test" -d "SELECT * FROM table WHERE int_column = {id:UInt8} and string_column = {phrase:String}"
Multipart form example over HTTP: curl -X POST -F 'query=select {p1:UInt8} + {p2:UInt8}' -F "param_p1=3" -F "param_p2=4" 'http://localhost:8123/'
Authenticate HTTP requests alongside the params using HTTP Basic Auth (or user/password query params, not recommended): curl -u "$CLICKHOUSE_USER:$CLICKHOUSE_PASSWORD" 'http://localhost:8123/?param_id=2' -d 'SELECT ... WHERE id={id:UInt8}', or the X-ClickHouse-User / X-ClickHouse-Key headers.
Parameters substitute typed VALUES only, not arbitrary SQL fragments — you cannot parameterize a table/column name as a plain String; use the Identifier data type for that case, and note it still restricts what can be supplied (a valid identifier, not arbitrary SQL).
HTTP query parameters are parsed from an 'escaped' format: a literal tab character must be sent as the two characters backslash-t, not URL-encoded %09 — encoding it as %09 directly produces a BAD_QUERY_PARAMETER (Code 457) error; use %5C%09 instead.
The param_<name> naming convention is fixed — the CLI flag is always --param_<name> and the HTTP parameter is always param_<name>, matching the {name:Type} placeholder used in the query text.
Query parameters must still be well-typed values for the declared Type; malformed values raise BAD_QUERY_PARAMETER errors rather than silently truncating or ignoring extra characters.
Using parameters via --param_ / param_ still requires the same authentication and privilege checks as any other query — parameterization prevents SQL injection but does not bypass GRANT-based access control.
Give your agent this knowledge — and 17,900+ more routes
One MCP install gives any agent live access to the full route map across 6,000+ domains, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp
Need this verified for your stack — or a route we don't have yet?