Calíope app icon

The drivers I write

Six clients, each written from the specification its makers publish.

Calíope talks to six kinds of server through clients I wrote myself. Each one was written from the documentation its makers publish, not from another client’s code, and each implements what Calíope uses and nothing more. This page sums up each one in three parts: what it was written from, what it speaks, and what it leaves out on purpose, with the reason.

Behind every summary there is a full specification: every message, every sign-in method, how the client is built and how it is tested against real servers. It lives in the source repository, in Spanish, and it is checked on every commit against the code it describes: when a driver changes, its document has to be read again before the change goes in.

MySQL and MariaDB

Written from

What it speaks

  • The connection phase with capability negotiation, and TLS started in the middle of it.
  • Sign-in with mysql_native_password, caching_sha2_password, client_ed25519, parsec and mysql_clear_password, the last one only over TLS.
  • Text queries (COM_QUERY) with several result sets per reply, so a CALL returns its rows.
  • Prepared statements (COM_STMT_PREPARE, COM_STMT_EXECUTE, COM_STMT_CLOSE) with binary rows: values travel apart from the SQL.
  • LOCAL INFILE, sending only the file you choose.
  • Affected rows, the last insert id, warnings and the transaction state, as the server reports them in its own reply.
  • Stopping a running query with KILL QUERY from a second connection.

What it does not

  • CLIENT_MULTI_STATEMENTS: never declared. The editor sends one statement at a time, and leaving it off means injected text cannot chain a second statement.
  • Compression and the X Protocol (port 33060): not needed by any tool.
  • Server-side cursors: large results stream row by row instead.
  • Replication, COM_CHANGE_USER and the binlog commands: no tool uses them.
  • Other sign-in methods (sha256_password, Kerberos, LDAP SASL, GSSAPI): refused with the method’s name, so the error says what is missing.
  • A plain-text password over an unencrypted connection: never.
  • Servers older than MySQL 4.1.

PostgreSQL

Written from

What it speaks

  • TLS requested before anything else; if the server refuses it, nothing is sent in the clear.
  • Sign-in with SCRAM-SHA-256, md5 or a plain-text password, the last one only over TLS.
  • The simple query, and the extended query (Parse, Bind, Execute) with parameters sent apart from the SQL.
  • Every value as text, the same text psql shows, delivered row by row as it arrives.
  • Affected rows, errors and notices with all their fields, and the transaction state with every reply.
  • Cancelling with CancelRequest and the key the server hands over at sign-in, and DISCARD ALL before a connection goes back to the pool.

What it does not

  • COPY: Calíope never sends it; one typed in the editor closes the connection, because the server would wait for data that never comes.
  • LISTEN/NOTIFY: notifications are read and discarded.
  • Kerberos (GSSAPI) and SSPI: they need system tickets the sandbox does not give.
  • SCRAM with channel binding (SCRAM-SHA-256-PLUS): the server cannot require it, so it changes nothing about who gets in.
  • Results in binary, named cursors, named prepared statements and pipelining: one request in flight per connection.
  • The replication protocol and function calls.
  • A plain-text password over an unencrypted connection: never.

MongoDB

Written from

What it speaks

  • BSON, type by type, including Decimal128.
  • OP_MSG and the hello handshake, with MongoDB 4.0 or later.
  • Sign-in with SCRAM-SHA-256 and SCRAM-SHA-1.
  • TLS with the same policy as every other engine.
  • Connection strings, mongodb:// and mongodb+srv://, with the SRV and TXT records looked up through the system DNS.
  • The primary of a replica set, found from the hello reply, and a connection pool.

What it does not

  • Any message other than OP_MSG: a server that only speaks the legacy ones is older than 4.0 and is refused.
  • Compression and exhaust cursors: every command waits for its own reply.
  • Sessions, transactions, change streams, retryable writes and reading from secondaries: the tools do not use them, and everything goes to the primary.
  • Sign-in methods that are not SCRAM (x.509, Kerberos, LDAP, AWS, OIDC): the error lists what the server offers.
  • Deprecated BSON types: read and shown as unsupported, never written.
  • File options in the connection string (tlsCAFile): the sandbox does not let the app read a path, so the certificates go in the profile.
  • A mongodb+srv:// name through an SSH tunnel: the name would be resolved by the far end, not by your device.

Redis

Written from

What it speaks

  • RESP2 and RESP3, every type, with each reply matched to its command by position.
  • Sign-in with HELLO or AUTH, with an ACL user and its password.
  • SELECT applied to each connection as it is lent out, and TLS with the same policy as every other engine.
  • Cluster mode: the 16,384 slots, a fresh map after MOVED, a one-off ASK.
  • A console that checks every command you type against a list before it reaches the server.

What it does not

  • The inline form of commands: it cannot carry arbitrary bytes.
  • Pub/sub and MONITOR: nothing in the client subscribes.
  • Transactions (MULTI, WATCH), blocking commands without a timeout, CLIENT REPLY OFF, RESET and replication commands: a pooled connection is shared by every tool, and they would leave state on it.
  • Client-side caching and Sentinel discovery: the client connects to the address in the profile.
  • A cluster through an SSH tunnel: the nodes announce addresses the tunnel cannot reach, so it is refused before connecting.

SQL Server (TDS)

Written from

What it speaks

  • Always encrypted: TDS 8.0 strict mode first, TLS from the first byte with TLS 1.2 or later, and the TDS 7.x handshake inside PRELOGIN when the server does not offer strict mode.
  • PRELOGIN and LOGIN7 (TDS 7.4) with a SQL Server login.
  • Batches (SQL_BATCH) and parameterized queries through RPC to sp_executesql, with typed values sent apart from the SQL.
  • The token stream: columns, rows, row counts, errors, messages and environment changes, and the SQL Server types, spatial ones included.
  • Cancelling with ATTENTION, and RESETCONNECTION before a connection goes back to the pool.
  • GO as a batch separator, handled by the client as SQL Server’s own tools do.

What it does not

  • MARS: one request per connection, and one connection per user of the pool.
  • Windows integrated authentication (SSPI, Kerberos, NTLM): it needs a domain and a Kerberos client the sandbox does not have.
  • Microsoft Entra ID: it is an OAuth flow against Microsoft, a separate product.
  • Unencrypted connections, or ones that would encrypt only the login: refused.
  • Bulk load, transaction manager requests and Always On routing: transactions travel as T-SQL, and loads as INSERT.
  • text, ntext, image, hierarchyid and user CLR types: shown as unsupported.

ClickHouse (HTTP)

Written from

  • The ClickHouse documentation of its HTTP interface, its formats and settings, the query parameter syntax, and its system tables.
  • RFC 3986, for encoding the query string.
  • And the server itself, which describes its settings, functions and types in its own system tables.

What it speaks

  • HTTP or HTTPS on Apple’s URLSession, with no added dependency: one statement per request, the database in every request.
  • Typed query parameters ({name:Type}): values travel apart from the SQL.
  • Results read line by line once the query has finished, so an error at the end of a 200 OK is caught.
  • A cap on returned rows, written next to the figure it limits.
  • A session only for a batch that needs one, progress from system.processes, and stopping with KILL QUERY.
  • TLS with the same three choices as the other engines; through an SSH tunnel, the certificate is still checked against the profile’s host.

What it does not

  • The native TCP protocol (port 9000) and its format: the HTTP interface gives what Calíope needs without a binary protocol or a dependency.
  • gRPC and the interfaces that imitate MySQL or PostgreSQL.
  • Several statements per request, or a session per tab: two requests at once on one session are refused by the server.
  • Data in the request body and external tables: the app’s inserts travel as SQL.
  • Client certificates: a profile that carries them is refused.
  • Transactions: the server does not have them.