Standard library · Database

db/clickhouse

A ClickHouse client over the HTTP interface: statements, typed rows, batch inserts and the shared db interface.

import db.clickhouse

ClickHouse is a column oriented database for analytics: it scans billions of rows fast, and takes inserts in large batches. This package talks to it over its HTTP interface (port 8123, or 8443 with TLS) with net.http, so there is no driver library to install and no native protocol to speak. Results arrive as JSONCompact, with 64 bit integers quoted so that none of them loses digits.

Open a connection with Open or OpenURL, send statements with Exec, read rows with Query, and load many rows at once with a batch. Values go into the SQL through the argument functions, such as StrArg and IntArg, which escape them, or through ClickHouse's own typed {name:Type} placeholders. AsDb adapts a connection to the shared db interface. A statement that fails behind a 200 status, because the server hit an exception while already streaming the reply, is caught too: it shows in Error and Code like any other failure.

The package does not speak the native TCP protocol or RowBinary, does not compress, and has no SQL dialect in db/sql yet. Each page section below is one part of the API, and each has a runnable example.

Put values into SQL safely

Never build SQL by joining strings. Make each value with an argument function, which quotes and escapes it, and let Bind put the values into the ? places in order. Bind does not run anything, so it is also a good way to see the final text. A ? inside quotes or a comment is not a place, and when the number of values differs from the number of places the result is empty.

db-clickhouse-guide-args.salam
import db.clickhouse

func main:
    mut args := Vector {} as Vector<str>
    args.push(clickhouse.StrArg("o'brien"))
    args.push(clickhouse.IntArg(42 as i64))
    println clickhouse.Bind("SELECT * FROM users WHERE name = ? AND age > ?", args)
    mut one := Vector {} as Vector<str>
    one.push(clickhouse.IntArg(7 as i64))
    println clickhouse.Bind("SELECT '?' AS mark, ? /* ? */", one)
    println clickhouse.QuoteIdent("my table")
    println clickhouse.Bind("SELECT ?", args).len()
end
OutputSELECT * FROM users WHERE name = 'o\'brien' AND age > 42 SELECT '?' AS mark, 7 /* ? */ `my table` 0

The quote in o'brien is escaped for you. Table and column names are not values, so they go through QuoteIdent. Exec and Query do the same binding when you give them the values.

Connect and create a table

Start from DefaultOptions (a server on this machine, user default) and change what differs. Open sends nothing yet, so call Ping to see whether the server answers. Exec runs a statement that returns no rows and gives true on success; on failure Error and Code say why.

db-clickhouse-guide-connect.salam
import db.clickhouse

func main:
    mut o := clickhouse.DefaultOptions()
    o.addr = "127.0.0.1:8123"
    o.database = "default"
    o.username = "default"
    mut c := clickhouse.Open(o)
    defer c.Close()
    if not c.Ping():
        println "no ClickHouse at", o.addr
        ret 1
    end
    println c.ServerVersion()

    none := Vector {} as Vector<str>
    ok := c.Exec("CREATE TABLE IF NOT EXISTS visits (day Date, page String, hits UInt32) ENGINE = MergeTree ORDER BY (day, page)", none)
    if not ok:
        println "create failed:", c.Code(), c.Error()
        ret 1
    end
    println "table ready"
end

The table uses the MergeTree engine, the usual one, and its ORDER BY is the sort key that makes queries on day and page fast. ClickHouse has no auto increment key and no transactions to wait for; a statement is done when Exec returns.

Insert in batches

ClickHouse likes a few large inserts, not many small ones. PrepareBatch takes the INSERT INTO table (columns) part, Append adds one row of ready SQL values, and SendBatch sends all the rows in one request. Append returns false if the row has a different number of values than there are columns.

db-clickhouse-guide-insert.salam
import db.clickhouse

func row(day: str, page: str, hits: i64): Vector<str>:
    mut r := Vector {} as Vector<str>
    r.push(clickhouse.StrArg(day))
    r.push(clickhouse.StrArg(page))
    r.push(clickhouse.IntArg(hits))
    ret r
end

func main:
    mut c := clickhouse.Open(clickhouse.DefaultOptions())
    defer c.Close()
    mut b := c.PrepareBatch("INSERT INTO visits (day, page, hits)")
    if b.Error().len() > 0:
        println b.Error()
        ret 1
    end
    b.Append(row("2026-11-01", "/", 120 as i64))
    b.Append(row("2026-11-01", "/docs", 45 as i64))
    b.Append(row("2026-11-02", "/", 98 as i64))
    println b.Len(), "rows queued"
    if not c.SendBatch(b):
        println "insert failed:", c.Error()
        ret 1
    end
    println "inserted"
end

Hundreds or thousands of rows per batch is a good size to start with. A batch with no rows, or one that already has an error, is not sent.

Read the rows back

Query returns a Rows. Check Ok, then call Next in a loop and read the current row by column number with Text, Int64 and the other readers; Close it when done. The loop is until rows.Next(): because until runs while its condition is true. For a value that comes from outside, the typed placeholders {name:Type} of QueryParams let the server check the type.

db-clickhouse-guide-query.salam
import db.clickhouse

func main:
    mut c := clickhouse.Open(clickhouse.DefaultOptions())
    defer c.Close()
    mut args := Vector {} as Vector<str>
    args.push(clickhouse.StrArg("2026-11-01"))
    mut rows := c.Query("SELECT page, sum(hits) AS total FROM visits WHERE day >= ? GROUP BY page ORDER BY total DESC", args)
    if not rows.Ok():
        println rows.Error()
        ret 1
    end
    until rows.Next():
        println rows.Text(0), rows.Int64(1)
    end
    rows.Close()

    mut params := HashMap {} as HashMap<str, str>
    params.put("page", "/docs")
    mut one := c.QueryParams("SELECT sum(hits) FROM visits WHERE page = {page:String}", params)
    until one.Next():
        println "docs:", one.Int64(0)
    end
    one.Close()
end

An aggregate such as sum(hits) is a 64 bit integer in ClickHouse, which arrives quoted in the JSON and is read back without losing digits by Int64.

Types

Options

struct Options
How to reach the server.
NameTypeDescription
addrstr = "localhost:8123"Host and port, host:port; a leading http:// or https:// is accepted. The port defaults to 8123, or 8443 when secure.
databasestr = ""The database every statement runs in; empty means the user's default.
usernamestr = "default"The user name, sent as X-ClickHouse-User. The default is default.
passwordstr = ""The password, sent as X-ClickHouse-Key.
securebool = falseUse HTTPS.
timeout_msint = 30000How long a request may take, in milliseconds.
settingsHashMapClickHouse settings sent with every request, such as max_threads.
headersHashMapExtra HTTP headers for every request.
db-clickhouse-Connect.salam
import db.clickhouse

func main:
    mut o := clickhouse.DefaultOptions()
    o.addr = "127.0.0.1:8123"
    o.database = "shop"
    o.username = "default"
    o.password = ""
    o.secure = false
    o.timeout_ms = 10000
    o.settings.put("max_threads", "4")
    o.headers.put("X-Request-Source", "docs")
    println clickhouse.DEFAULT_PORT, clickhouse.DEFAULT_SECURE_PORT

    mut c := clickhouse.Open(o)
    if not c.Ping():
        println "no server:", c.Error(), c.status
        ret
    end
    println c.ServerVersion(), c.base, c.connected

    byurl := clickhouse.OpenURL("clickhouse://default:@127.0.0.1:8123/shop?max_threads=4")
    println byurl.Ok(), byurl.opts.database

    none := Vector {} as Vector<str>
    println c.Exec("CREATE TABLE IF NOT EXISTS events (id UInt64, name String) ENGINE = MergeTree ORDER BY id", none)
    mut ins := HashMap {} as HashMap<str, str>
    ins.put("id", "1")
    ins.put("name", "first")
    println c.ExecParams("INSERT INTO events VALUES ({id:UInt64}, {name:String})", ins)
    println c.ExecWith("OPTIMIZE TABLE events", none, o.settings)
    mut pn := HashMap {} as HashMap<str, str>
    pn.put("n", "7")
    println c.ExecFull("SELECT {n:UInt8}", pn, HashMap {} as HashMap<str, str>)
    if not c.Ok():
        println "failed with code", c.Code(), c.Error()
    end
    println c.query_id, c.read_rows, c.written_rows
    c.Close()
end

Conn

struct Conn
A connection to a ClickHouse server over its HTTP interface. Each call is one HTTP request, so there is nothing to keep alive. After a failed call Ok is false and Error and Code say why; the next call clears them.
NameTypeDescription
optsOptionsThe options the connection was opened with.
basestr = ""The base URL, such as http://127.0.0.1:8123.
connectedbool = falseFalse after Close or when the address was invalid.
statusint = 0The HTTP status of the last reply; 0 when no reply arrived.
errstr = ""The last error text.
codeint = 0The ClickHouse exception code of the last failure, 0 if none.
query_idstr = ""The query id the server gave the last request.
read_rowsi64 = 0Rows the last request read, from the server's summary header.
written_rowsi64 = 0Rows the last request wrote, from the server's summary header.

The example for this item is shown with the ones above: db-clickhouse-Connect.salam

Ok

func Ok(): bool
True when the connection is open and the last call did not fail.

The example for this item is shown with the ones above: db-clickhouse-Connect.salam

Error

func Error(): str
The last error text; empty when the last call worked. A failure that the server reported partway through a reply is caught too, even though the status was 200.

The example for this item is shown with the ones above: db-clickhouse-Connect.salam

Code

func Code(): int
The ClickHouse exception code of the last failure, read from the X-ClickHouse-Exception-Code header or the Code: N text of the body.

The example for this item is shown with the ones above: db-clickhouse-Connect.salam

Close

func Close()
Closes the connection; later calls fail with an error.

The example for this item is shown with the ones above: db-clickhouse-Connect.salam

Ping

func Ping(): bool
Asks /ping; true when the server answers.

The example for this item is shown with the ones above: db-clickhouse-Connect.salam

Exec

func Exec(sql: str, args: Vector<str>): bool
Runs a statement that returns no rows. Each ? is replaced by the next value of args, built with StrArg, IntArg and the other argument functions. Question marks inside quotes and comments are left alone.

The example for this item is shown with the ones above: db-clickhouse-Connect.salam

ExecParams

func ExecParams(sql: str, params: HashMap<str, str>): bool
Runs a statement with ClickHouse's own typed placeholders, {name:Type}, sent as param_name query parameters.

The example for this item is shown with the ones above: db-clickhouse-Connect.salam

ExecWith

func ExecWith(sql: str, args: Vector<str>, settings: HashMap<str, str>): bool
Like Exec, with ClickHouse settings for this call only, added to those in the options.

The example for this item is shown with the ones above: db-clickhouse-Connect.salam

ExecFull

func ExecFull(sql: str, params: HashMap<str, str>, extra: HashMap<str, str>): bool
Runs a statement with both typed parameters and per-call settings.

The example for this item is shown with the ones above: db-clickhouse-Connect.salam

Query

func Query(sql: str, args: Vector<str>): Rows
Runs a query and returns its rows, with ? placeholders as in Exec. Check Ok on the result, and call Close when done.
db-clickhouse-Query.salam
import db.clickhouse

func main:
    mut c := clickhouse.Open(clickhouse.DefaultOptions())
    defer c.Close()
    none := Vector {} as Vector<str>

    mut args := Vector {} as Vector<str>
    args.push(clickhouse.UIntArg(10 as u64))
    mut rows := c.Query("SELECT id, name, price, tags, active FROM events WHERE id >= ?", args)
    if not rows.Ok():
        println rows.Error()
        ret
    end
    println rows.ColumnCount(), rows.RowCount(), rows.total
    repeat rows.ColumnCount() in i:
        println i, rows.ColumnName(i), rows.ColumnType(i), rows.ColumnKind(i), rows.ColumnIndex(rows.ColumnName(i))
    end
    until rows.Next():
        println rows.UInt64(0), rows.Int64(0), rows.Int(0), rows.Text(1), rows.Float(2), rows.Bool(4)
        println rows.IsNull(1), rows.Raw(3), rows.List(3).len(), rows.Row().len()
        println rows.TextBy("name"), rows.Int64By("id"), rows.FloatBy("price")
    end
    println rows.pos, rows.names.len(), rows.types.len(), rows.rows.len(), rows.cells.len()
    rows.Close()

    mut params := HashMap {} as HashMap<str, str>
    params.put("min", "10")
    mut byname := c.QueryParams("SELECT count() FROM events WHERE id >= {min:UInt64}", params)
    println byname.Ok()
    byname.Close()

    mut limits := HashMap {} as HashMap<str, str>
    limits.put("max_execution_time", "5")
    mut limited := c.QueryWith("SELECT sum(id) FROM events", none, limits)
    println limited.Ok()
    limited.Close()

    mut full := c.QueryFull("SELECT {min:UInt64}", params, limits)
    println full.Ok()
    full.Close()

    first := c.QueryRow("SELECT id, name FROM events ORDER BY id LIMIT 1", none)
    if first.len() == 2:
        println first.get(0), first.get(1)
    end
    println c.QueryText("SELECT version()"), c.QueryInt("SELECT count() FROM events")
end

QueryParams

func QueryParams(sql: str, params: HashMap<str, str>): Rows
Runs a query with typed {name:Type} placeholders.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

QueryWith

func QueryWith(sql: str, args: Vector<str>, settings: HashMap<str, str>): Rows
Like Query, with settings for this call only.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

QueryRow

func QueryRow(sql: str, args: Vector<str>): Vector<str>
Runs a query and returns the first row as text values; an empty vector when there is no row or the query failed.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

QueryFull

func QueryFull(sql: str, params: HashMap<str, str>, extra: HashMap<str, str>): Rows
Runs a query with typed parameters and per-call settings.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

QueryText

func QueryText(sql: str): str
The first column of the first row as text; empty when there is none.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

QueryInt

func QueryInt(sql: str): i64
The first column of the first row as a 64 bit integer; 0 when there is none.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

ServerVersion

func ServerVersion(): str
The server version, from SELECT version().

The example for this item is shown with the ones above: db-clickhouse-Connect.salam

PrepareBatch

func PrepareBatch(sql: str): Batch
Starts a batch insert from INSERT INTO table (columns); a trailing VALUES or semicolon is dropped. Anything else gives a batch whose Error says why.
db-clickhouse-Batch.salam
import db.clickhouse

func main:
    mut c := clickhouse.Open(clickhouse.DefaultOptions())
    defer c.Close()

    mut b := c.PrepareBatch("INSERT INTO events (id, name, tags, score)")
    if b.Error().len() > 0:
        println b.Error()
        ret
    end
    println b.head, b.width

    mut tags := Vector {} as Vector<str>
    tags.push(clickhouse.StrArg("a"))
    tags.push(clickhouse.StrArg("b"))
    mut row := Vector {} as Vector<str>
    row.push(clickhouse.IntArg(1 as i64))
    row.push(clickhouse.StrArg("o'brien"))
    row.push(clickhouse.ArrayArg(tags))
    row.push(clickhouse.FloatArg(2.5))
    println b.Append(row)

    again := clickhouse.Args(row)
    println b.Append(again)
    println c.SendBatch(b)

    mut broken := c.PrepareBatch("INSERT INTO events (id, name, tags, score)")
    mut bad := Vector {} as Vector<str>
    bad.push(clickhouse.NullArg())
    println broken.Append(bad), broken.Error(), broken.Len(), broken.rows.len()
    broken.Abort()

    keys := clickhouse.Args(tags)
    println clickhouse.MapArg(keys, keys)
    println clickhouse.TupleArg(keys), clickhouse.BoolArg(true), clickhouse.RawArg("now()")
    println clickhouse.QuoteIdent("my table")
end

SendBatch

func SendBatch(b: Batch): bool
Sends every row of the batch as one INSERT; false when the batch is empty or broken, or the server refused it.

The example for this item is shown with the ones above: db-clickhouse-Batch.salam

Rows

struct Rows
The result of a query: column names and types, and the rows as JSON. Move with Next, then read the current row by column number or name.
NameTypeDescription
namesVectorThe column names.
typesVectorThe column types as ClickHouse writes them, such as Nullable(String).
rowsVectorEvery row, each as JSON text.
cellsVectorThe values of the current row as JSON text.
posint = -1The index of the current row; -1 before the first Next.
totali64 = 0The row count the server reported.
errstr = ""The error text; empty when the query worked.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

Ok

func Ok(): bool
True when the query worked.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

Error

func Error(): str
The error text.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

Next

func Next(): bool
Moves to the next row; false when there are no more.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

RowCount

func RowCount(): int
The number of rows.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

ColumnCount

func ColumnCount(): int
The number of columns.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

ColumnName

func ColumnName(col: int): str
The name of a column, by number.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

ColumnType

func ColumnType(col: int): str
The ClickHouse type of a column, by number.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

ColumnKind

func ColumnKind(col: int): int
The KIND_... group of a column's type.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

ColumnIndex

func ColumnIndex(name: str): int
The number of the column with this name, or -1.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

Raw

func Raw(col: int): str
The value of the current row as JSON text.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

IsNull

func IsNull(col: int): bool
The value is NULL.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

Text

func Text(col: int): str
The value as text, without the JSON quotes.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

Int64

func Int64(col: int): i64
The value as a 64 bit integer. ClickHouse sends 64 bit numbers as strings and this reads them without loss.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

Int

func Int(col: int): int
The value as a 32 bit integer.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

UInt64

func UInt64(col: int): u64
The value as an unsigned 64 bit integer.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

Float

func Float(col: int): f64
The value as a float; nan and inf are understood.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

Bool

func Bool(col: int): bool
The value as a bool.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

List

func List(col: int): Vector<str>
An array value as a vector of text items.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

TextBy

func TextBy(name: str): str
Like Text, by column name.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

Int64By

func Int64By(name: str): i64
Like Int64, by column name.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

FloatBy

func FloatBy(name: str): f64
Like Float, by column name.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

Row

func Row(): Vector<str>
The whole current row as a vector of text values.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

Close

func Close()
Frees the rows.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

Batch

struct Batch
Rows collected for one insert. Build each row from the argument functions, Append it, then send the batch with SendBatch.
NameTypeDescription
headstr = ""The INSERT INTO table (columns) part.
widthint = 0The number of columns the insert names; 0 when it names none.
rowsVectorThe rows added so far, each already formatted as SQL.
errstr = ""The error text; empty when the batch is fine.

The example for this item is shown with the ones above: db-clickhouse-Batch.salam

Append

func Append(values: Vector<str>): bool
Adds a row of SQL values; false, with Error set, when the count differs from the number of columns.

The example for this item is shown with the ones above: db-clickhouse-Batch.salam

Len

func Len(): int
The number of rows added.

The example for this item is shown with the ones above: db-clickhouse-Batch.salam

Error

func Error(): str
The error text.

The example for this item is shown with the ones above: db-clickhouse-Batch.salam

Abort

func Abort()
Throws the rows away and clears the error.

The example for this item is shown with the ones above: db-clickhouse-Batch.salam

Constants and variables

DEFAULT_PORT

const DEFAULT_PORT: i32 = 8123
The default HTTP port, 8123.

The example for this item is shown with the ones above: db-clickhouse-Connect.salam

DEFAULT_SECURE_PORT

const DEFAULT_SECURE_PORT: i32 = 8443
The default HTTPS port, 8443, used when secure is on and the address has no port.

The example for this item is shown with the ones above: db-clickhouse-Connect.salam

KIND_OTHER

const KIND_OTHER: i32 = 0
Kind of column type: a type with no special handling.
db-clickhouse-Types.salam
import db.clickhouse

func main:
    mut args := Vector {} as Vector<str>
    args.push(clickhouse.IntArg(7 as i64))
    args.push(clickhouse.StrArg("it's"))
    println clickhouse.Bind("SELECT ? AS id, ? AS name", args)

    t := "LowCardinality(Nullable(String))"
    println clickhouse.BaseType(t), clickhouse.IsNullableType(t)
    println clickhouse.TypeKind("Array(Int32)") == clickhouse.KIND_ARRAY
    println clickhouse.ElementType("Array(Nullable(Int32))")
    println clickhouse.KIND_OTHER, clickhouse.KIND_INT, clickhouse.KIND_UINT, clickhouse.KIND_FLOAT, clickhouse.KIND_DECIMAL, clickhouse.KIND_STRING
    println clickhouse.KIND_BOOL, clickhouse.KIND_DATE, clickhouse.KIND_DATETIME, clickhouse.KIND_MAP, clickhouse.KIND_TUPLE
end

KIND_INT

const KIND_INT: i32 = 1
Kind of column type: a signed integer, Int8 to Int256.

The example for this item is shown with the ones above: db-clickhouse-Types.salam

KIND_UINT

const KIND_UINT: i32 = 2
Kind of column type: an unsigned integer, UInt8 to UInt256.

The example for this item is shown with the ones above: db-clickhouse-Types.salam

KIND_FLOAT

const KIND_FLOAT: i32 = 3
Kind of column type: a float, Float32 or Float64.

The example for this item is shown with the ones above: db-clickhouse-Types.salam

KIND_DECIMAL

const KIND_DECIMAL: i32 = 4
Kind of column type: a Decimal.

The example for this item is shown with the ones above: db-clickhouse-Types.salam

KIND_STRING

const KIND_STRING: i32 = 5
Kind of column type: text: String, FixedString, UUID, Enum, IPv4, IPv6.

The example for this item is shown with the ones above: db-clickhouse-Types.salam

KIND_BOOL

const KIND_BOOL: i32 = 6
Kind of column type: a Bool.

The example for this item is shown with the ones above: db-clickhouse-Types.salam

KIND_DATE

const KIND_DATE: i32 = 7
Kind of column type: a Date or Date32.

The example for this item is shown with the ones above: db-clickhouse-Types.salam

KIND_DATETIME

const KIND_DATETIME: i32 = 8
Kind of column type: a DateTime or DateTime64.

The example for this item is shown with the ones above: db-clickhouse-Types.salam

KIND_ARRAY

const KIND_ARRAY: i32 = 9
Kind of column type: an Array or Nested.

The example for this item is shown with the ones above: db-clickhouse-Types.salam

KIND_MAP

const KIND_MAP: i32 = 10
Kind of column type: a Map.

The example for this item is shown with the ones above: db-clickhouse-Types.salam

KIND_TUPLE

const KIND_TUPLE: i32 = 11
Kind of column type: a Tuple.

The example for this item is shown with the ones above: db-clickhouse-Types.salam

Functions

StrArg

func StrArg(s: str): str
A string as a quoted SQL literal, with quotes, backslashes and line breaks escaped.

The example for this item is shown with the ones above: db-clickhouse-Types.salam

QuoteIdent

func QuoteIdent(name: str): str
A table or column name in backticks.

The example for this item is shown with the ones above: db-clickhouse-Batch.salam

IntArg

func IntArg(n: i64): str
A signed integer as a SQL literal.

The example for this item is shown with the ones above: db-clickhouse-Batch.salam

UIntArg

func UIntArg(n: u64): str
An unsigned integer as a SQL literal.

The example for this item is shown with the ones above: db-clickhouse-Query.salam

FloatArg

func FloatArg(x: f64): str
A float as a SQL literal; nan, inf and -inf are written as ClickHouse reads them.

The example for this item is shown with the ones above: db-clickhouse-Batch.salam

BoolArg

func BoolArg(b: bool): str
A bool as true or false.

The example for this item is shown with the ones above: db-clickhouse-Batch.salam

RawArg

func RawArg(sql: str): str
SQL text passed through unchanged, such as now(). Never use it with user input.

The example for this item is shown with the ones above: db-clickhouse-Batch.salam

ArrayArg

func ArrayArg(items: Vector<str>): str
An array literal from items that are already SQL literals.

The example for this item is shown with the ones above: db-clickhouse-Batch.salam

TupleArg

func TupleArg(items: Vector<str>): str
A tuple literal from items that are already SQL literals.

The example for this item is shown with the ones above: db-clickhouse-Batch.salam

MapArg

func MapArg(keys: Vector<str>, values: Vector<str>): str
A map(...) literal from keys and values that are already SQL literals; the shorter list decides the size.

The example for this item is shown with the ones above: db-clickhouse-Batch.salam

Args

func Args(items: Vector<str>): Vector<str>
Returns the vector unchanged; it only makes a call site read as a list of arguments.

The example for this item is shown with the ones above: db-clickhouse-Batch.salam

Bind

func Bind(sql: str, args: Vector<str>): str
Puts the values into the ? places of the SQL and returns the text, without running it. Empty when the counts differ.

The example for this item is shown with the ones above: db-clickhouse-Types.salam

BaseType

func BaseType(t: str): str
The type with Nullable(...) and LowCardinality(...) taken off.

The example for this item is shown with the ones above: db-clickhouse-Types.salam

IsNullableType

func IsNullableType(t: str): bool
The type is Nullable, possibly inside LowCardinality.

The example for this item is shown with the ones above: db-clickhouse-Types.salam

TypeKind

func TypeKind(t: str): int
The KIND_... group of a type.

The example for this item is shown with the ones above: db-clickhouse-Types.salam

ElementType

func ElementType(t: str): str
The element type of an Array(...); empty for anything else.

The example for this item is shown with the ones above: db-clickhouse-Types.salam

DefaultOptions

func DefaultOptions(): Options
Options for a server on this machine: localhost:8123, user default, no password.

The example for this item is shown with the ones above: db-clickhouse-Connect.salam

Open

func Open(o: Options): Conn
Makes a connection from the options. Nothing is sent yet; Ping checks that the server is there.

The example for this item is shown with the ones above: db-clickhouse-Connect.salam

OpenURL

func OpenURL(dsn: str): Conn
Makes a connection from an address like clickhouse://user:pass@host:8123/db?secure=true&max_threads=4. clickhouses://, http:// and https:// also work. database, username, password, secure and timeout set options; any other key becomes a ClickHouse setting.

The example for this item is shown with the ones above: db-clickhouse-Connect.salam

AsDb

func AsDb(c: Conn): dyn db.Connection
Wraps a connection as a dyn db.Connection, so code written against the shared db interface runs on ClickHouse too. Exec returns 0 or -1, Changes is the rows the last request wrote, LastInsertId is always 0, and a transaction runs each statement at once: ClickHouse has none, so Commit returns 0 and Rollback returns -1.
db-clickhouse-Shared.salam
import db
import db.clickhouse

func total(c: dyn db.Connection, table: str): int:
    ret db.QueryInt(c, "SELECT count() FROM " + table)
end

func main:
    c := clickhouse.Open(clickhouse.DefaultOptions())
    d := clickhouse.AsDb(c)
    defer d.Close()
    println d.Kind() == db.CLICKHOUSE, d.Ping()
    println total(d, "events")
    r := d.Query("SELECT id, name FROM events LIMIT 5")
    until r.Next():
        println r.Int64(0), r.Text(1), r.ColumnType(0)
    end
    r.Close()
    t := d.Begin()
    println t.Exec("INSERT INTO events VALUES (99, 'x')"), t.Commit()
end