// STRYKE-CLICKHOUSE — ENGINEERING REPORT

Opt-in stryke connector package · cdylib libstryke_clickhouse · namespace Clickhouse · JSON-in/JSON-out FFI over dlopen

>_EXECUTIVE SUMMARY

stryke-clickhouse is an opt-in connector package in the stryke ecosystem — a ClickHouse client. It exposes SELECTs, bulk insert via JSONEachRow, DDL, and schema introspection as the Clickhouse package, against any ClickHouse server over its HTTP interface (default port 8123).

Transport is ureq over rustls — synchronous, pure-Rust, no tokio, no OpenSSL. The cdylib caches a keep-alive connection pool and ships once on demand rather than being linked into stryke core.

Clickhouse
stryke namespace
opt-in
Tier
cdylib
Load model (dlopen)
HTTP
Transport (ureq, rustls)
43
Public functions

>_TRANSPORT

The client uses ClickHouse's HTTP interface (default port 8123) via ureq — synchronous, pure-Rust, rustls-backed, no async runtime, no OpenSSL. SQL is sent in the POST body. SELECTs append default_format=JSON so results return as { meta, data, rows, statistics }; DDL/DML return an empty body on success.


~CONNECTION CACHE

One ureq::Agent (HTTP keep-alive pool) is cached per (base_url, auth, database) tuple in a OnceCell<Mutex<HashMap>> for the life of the stryke process, so repeated queries reuse the connection. The database rides on the query string (?database=) and HTTP Basic carries the credentials (default user default).


~INSERTS

insert serializes an array of row objects into an INSERT INTO <table> FORMAT JSONEachRow body — one JSON object per line — which is ClickHouse's high-throughput ingestion path and avoids per-row round trips.


$FFI CONTRACT + PURE HELPERS

Each #[no_mangle] extern "C" fn clickhouse__* is a JSON-string-in / JSON-string-out wrapper; handlers run inside catch_unwind so a panic becomes an { "error": … } result rather than crossing the C ABI into the host shell. The SQL-escaping and value-formatting helpers and the URL helpers take no connection and are unit-tested in-crate, so they validate in CI with no server present.

GroupFunctions
Livenessversion, ping, server_version
Queryquery, query_rows, query_row, query_value, exec, insert, delete_where, raw
Introspectiondatabases, tables, describe, columns, count, table_exists, database_exists, settings, parts, disk_usage, mutations, processes
DDLcreate_database, drop_database, create_table, drop_table, truncate_table, rename_table, add_column, drop_column, optimize
Pure helpersescape, escape_like, quote_literal, quote_ident, valid_identifier, format_value, format_in_list, format_array, build_url, parse_url, redact_url

@SQL MAPPING

Introspection functions resolve against ClickHouse's system.* tables; DDL functions emit idempotent statements (IF [NOT] EXISTS). Identifiers/values interpolated into system.* predicates are run through the in-crate escape_string first.

FunctionStatement
server_versionSELECT version()
databasesSELECT name FROM system.databases ORDER BY name
tablesSELECT name FROM system.tables WHERE database = '…' ORDER BY name
describeDESCRIBE TABLE <table>
table_existsSELECT count() AS c FROM system.tables WHERE database = '…' AND name = '…'
database_existsSELECT count() AS c FROM system.databases WHERE name = '…'
settingsSELECT name, value, changed, description FROM system.settings ORDER BY name
columnsSELECT name, type, default_kind, default_expression, data_compressed_bytes, data_uncompressed_bytes, comment FROM system.columns WHERE database = '…' AND table = '…' ORDER BY position
partsSELECT … FROM system.parts WHERE database = '…' AND table = '…' AND active ORDER BY name
disk_usageSELECT sum(rows), sum(bytes_on_disk), sum(data_compressed_bytes), sum(data_uncompressed_bytes), round(uncompressed/greatest(compressed,1),3) AS ratio FROM system.parts WHERE … AND active
mutationsSELECT mutation_id, command, create_time, parts_to_do, is_done, latest_fail_reason FROM system.mutations WHERE … ORDER BY create_time DESC
processesSELECT query_id, user, query, elapsed, read_rows, read_bytes, memory_usage FROM system.processes ORDER BY elapsed DESC
create_databaseCREATE DATABASE IF NOT EXISTS <name>
drop_databaseDROP DATABASE IF EXISTS <name>
create_tableCREATE TABLE IF NOT EXISTS <name> (<columns>) ENGINE = <engine, default MergeTree> ORDER BY <order_by, default tuple()> — or a full sql CREATE verbatim
drop_tableDROP TABLE IF EXISTS <table>
truncate_tableTRUNCATE TABLE IF EXISTS <table>
rename_tableRENAME TABLE <from> TO <to>
add_columnALTER TABLE <table> ADD COLUMN IF NOT EXISTS <name> <type> [DEFAULT <expr>]
drop_columnALTER TABLE <table> DROP COLUMN IF EXISTS <name>
delete_whereDELETE FROM <table> WHERE <where> (lightweight delete, ClickHouse 22.8+)
optimizeOPTIMIZE TABLE <table> [FINAL]

%PURE-HELPER SEMANTICS

The SQL-building helpers take no connection and are exercised by the in-crate unit tests, so they validate in CI with no server present.

HelperRule
escapeEscapes \\\ and '\' for a single-quoted literal body.
quote_literal'<escape(value)>' — the escaped body wrapped in single quotes.
quote_identBacktick-wraps; embedded ` becomes \`.
valid_identifierTrue iff the value matches [A-Za-z_][A-Za-z0-9_]* (leading underscore allowed).
escape_likeBackslash-escapes \, %, _ — the body to wrap with surrounding % and quote.
format_valuestring→'…', number→as-is, bool→true/false, null→NULL, array→[…], object→quoted JSON string.
format_in_list(v1, v2, …) via format_value; empty input → (NULL) (matches nothing).
format_array[v1, v2, …] via format_value.
build_urlResolves the base URL the opts connect to (scheme + host + port).
redact_urlRewrites userinfo to ***: scheme://***@host….

?URL PARSING

parse_url decomposes a URL into the connection fields. A missing scheme defaults to http; a missing port defaults to 8443 when the scheme is https, otherwise 8123; a leading /<db> path names the database.

FieldSource
schemeBefore ://; defaults to http.
hostAuthority host (after any user:pass@).
portExplicit port, else 8443 (https) / 8123 (http).
username / passwordFrom the user:pass@ userinfo, when present.
databaseLeading path segment, or null when absent.
tlsTrue when scheme is https.

&RESULT EXTRACTION

query returns the full result object { meta, data, rows, statistics }; query_rows / query_row / query_value peel off the array / first row / first scalar respectively. exec is for statements that return no rows. The extraction logic is unit-tested in-crate against captured JSON payloads, so it validates without a live server.


/DEPENDENCIES

ureq (HTTP, rustls TLS) for transport and serde_json for the FFI payloads and result parsing. Pure-Rust throughout — no tokio, no OpenSSL, no native client library.


#PROJECT METADATA

ItemValue
LicenseMIT
Repositorygithub.com/MenkeTechnologies/stryke-clickhouse
Parent languagestrykelang
Meta umbrellaMenkeTechnologiesMeta
Issuesgithub.com/MenkeTechnologies/stryke-clickhouse/issues