Calíopeは、私が自分で書いたクライアントを通じて8種類のサーバと話します。どれも作り手が公開しているものから書きました。その仕様とドキュメント、あるいはOracleのように仕様を公開していない場合は、作り手が参照実装として名指ししているドライバです。他人のクライアントから書いたことは一度もありません。そしてどれも、Calíopeが使うものを実装し、それ以上は実装しません。このページでは各クライアントを3つの部分にまとめています:何をもとに書かれたか、何を話すか、何をあえて外しているか(その理由とともに)。
どの要約の裏にも、完全な仕様があります:すべてのメッセージ、すべてのサインイン方式、クライアントの組み立て方、そして実際のサーバに対するテストの方法。それはソースリポジトリにスペイン語で置かれ、説明しているコードとコミットのたびに照合されます。ドライバが変わったら、その変更が入る前に、ドキュメントを読み直さなければなりません。
MySQLとMariaDB
もとにしたもの
- OracleのMySQL Client/Server Protocolのドキュメント(現行版)と、MySQL 8.4リファレンスマニュアル。
- MariaDBのClient/Server Protocolのドキュメントと、各認証プラグインのページ。
- サインインのためのRFC 8032(Ed25519)、RFC 8017(RSA-OAEP)、RFC 8018(PBKDF2)。
話すもの
- ケイパビリティのネゴシエーションを伴う接続フェーズと、その途中で始まるTLS。
mysql_native_password、caching_sha2_password、client_ed25519、parsec、mysql_clear_passwordによるサインイン。最後のものはTLS上でのみ。- 1つの応答に複数の結果セットを含むテキストのクエリー(
COM_QUERY)。これでCALLが行を返せます。 - バイナリの行を返すプリペアドステートメント(
COM_STMT_PREPARE、COM_STMT_EXECUTE、COM_STMT_CLOSE):値はSQLとは別に送られます。 LOCAL INFILE。送るのは、あなたが選んだファイルだけです。- 影響を受けた行数、最後に挿入されたID、警告、トランザクションの状態を、サーバが自分の応答で報告するとおりに。
- 2本目の接続からの
KILL QUERYによる、実行中のクエリーの停止。
話さないもの
CLIENT_MULTI_STATEMENTS:一度も宣言しません。エディタは文を1つずつ送り、これをオフにしておけば、注入されたテキストが2つ目の文をつなげられません。- 圧縮とXプロトコル(ポート33060):どのツールも必要としません。
- サーバ側のカーソル:大きな結果は、代わりに1行ずつストリームで届きます。
- レプリケーション、
COM_CHANGE_USER、バイナリログのコマンド:どのツールも使いません。 - ほかのサインイン方式(
sha256_password、Kerberos、LDAP SASL、GSSAPI):方式の名前とともに拒否するので、何が足りないかがエラーでわかります。 - 暗号化されていない接続での平文のパスワード:決して送りません。
- MySQL 4.1より古いサーバ。
TiDBも
- TiDBはこれと同じプロトコルを話すので、この同じクライアントを通り、TiDB 8.5に対して測っています。その挨拶には
8.0.11-TiDB-v8.5.8が入っていて、プロファイルに何と書かれていても、このバージョン文字列でCalíopeは相手がTiDBだと知ります。 - TiDBの接続IDは64ビット幅になることがありますが、挨拶に入っているのは下位の32ビットだけで、それを使った
KILL QUERYは何も止めません。TiDBでは接続ごとに一度CONNECTION_ID()を尋ね、IDの全体でキャンセルします。 - TiDB独自のサインイン方式(
tidb_sm3_password、tidb_auth_token):話さず、ほかの方式と同じように、方式の名前とともに拒否します。 - ステータスポート(10080)とPrometheusのメトリクス:開いてトンネルを通さなければならない2つ目のポートです。SQLの接続で得られるものは表示し、残りはn/aと表示します。
PostgreSQL
もとにしたもの
- PostgreSQLのドキュメントのフロントエンド/バックエンドプロトコルの章(現行版。書いた時点ではPostgreSQL 18)。
- RFC 5802とRFC 7677(SCRAM-SHA-256)、RFC 4013とRFC 3454(SASLprep)。
話すもの
- 何よりも先に要求するTLS。サーバが拒否したら、平文では何も送りません。
- SCRAM-SHA-256、md5、平文のパスワードによるサインイン。最後のものはTLS上でのみ。
- シンプルクエリーと、パラメータをSQLとは別に送る拡張クエリー(
Parse、Bind、Execute)。 - すべての値をテキストで。
psqlが表示するのと同じテキストで、届いたそばから1行ずつ。 - 影響を受けた行数、すべてのフィールドを含むエラーと通知、そしてどの応答にも付くトランザクションの状態。
- サインイン時にサーバが渡すキーを使った
CancelRequestによるキャンセルと、接続がプールに戻る前のDISCARD ALL。
話さないもの
COPY:Calíopeは決して送りません。エディタで入力されたものは接続を閉じます。サーバが、決して来ないデータを待ってしまうからです。LISTEN/NOTIFY:通知は読んで捨てます。- Kerberos(GSSAPI)とSSPI:サンドボックスが与えないシステムのチケットが必要です。
- チャネルバインディング付きのSCRAM(
SCRAM-SHA-256-PLUS):サーバがこれを要求できないので、誰が入れるかについては何も変わりません。 - バイナリでの結果、名前付きカーソル、名前付きプリペアドステートメント、パイプライン:1つの接続で同時に送るリクエストは1つです。
- レプリケーションプロトコルと関数呼び出し。
- 暗号化されていない接続での平文のパスワード:決して送りません。
MongoDB
もとにしたもの
- BSONの仕様、バージョン1.1。
- MongoDB Wire Protocolのドキュメントとサーバのマニュアル。
- MongoDBがドキュメントとして公開しているドライバの仕様:
OP_MSG、ハンドシェイク、認証、接続文字列、DNSシードリストによる検出、Decimal128。 - RFC 5802、RFC 7677、RFC 4013、RFC 3986、RFC 2782。
話すもの
- Decimal128を含む、型ごとのBSON。
- MongoDB 4.0以降での
OP_MSGとhelloハンドシェイク。 - SCRAM-SHA-256とSCRAM-SHA-1によるサインイン。
- ほかのすべてのエンジンと同じポリシーのTLS。
- 接続文字列
mongodb://とmongodb+srv://。SRVとTXTのレコードはシステムのDNSで引きます。 helloの応答から見つけるレプリカセットのプライマリと、接続プール。
話さないもの
OP_MSG以外のメッセージ:古いものしか話さないサーバは4.0より古く、拒否します。- 圧縮とexhaustカーソル:どのコマンドも自分の応答を待ちます。
- セッション、トランザクション、変更ストリーム、再試行可能な書き込み、セカンダリからの読み取り:ツールが使わないので、すべてプライマリに向かいます。
- SCRAMではないサインイン方式(x.509、Kerberos、LDAP、AWS、OIDC):サーバが提示する方式をエラーが列挙します。
- 非推奨のBSONの型:読んで、サポート外として表示し、書き込むことはありません。
- 接続文字列のファイルのオプション(
tlsCAFile):サンドボックスはアプリにパスを読ませないので、証明書はプロファイルに入れます。 - SSHトンネル越しの
mongodb+srv://の名前:名前を解決するのはあなたのデバイスではなく、向こう側になってしまいます。
Redis
もとにしたもの
- RESP2とRESP3を扱うRESPプロトコルの仕様。
- クライアントが自分から送るコマンド(
HELLO、AUTH、SELECT、SCAN、CLUSTERのコマンド群)のためのRedisのコマンドリファレンス。 - Redisクラスタの仕様:スロット、ハッシュタグ、
MOVEDとASK。
話すもの
- すべての型のRESP2とRESP3。各応答は、位置によって自分のコマンドと対応づけます。
- ACLのユーザとそのパスワードによる、
HELLOまたはAUTHでのサインイン。 - 接続を貸し出すたびに適用する
SELECTと、ほかのすべてのエンジンと同じポリシーのTLS。 - クラスタモード:16,384のスロット、
MOVEDのあとの新しいマップ、1回限りのASK。 - 入力したすべてのコマンドを、サーバに届く前に一覧と照らし合わせるコンソール。
話さないもの
- コマンドのインライン形式:任意のバイトを運べません。
- Pub/subと
MONITOR:クライアントの中で購読するものは何もありません。 - トランザクション(
MULTI、WATCH)、タイムアウトのないブロッキングコマンド、CLIENT REPLY OFF、RESET、レプリケーションのコマンド:プールの接続はすべてのツールで共有され、これらはそこに状態を残してしまいます。 - クライアント側のキャッシュとSentinelによる検出:クライアントはプロファイルのアドレスに接続します。
- SSHトンネル越しのクラスタ:ノードはトンネルが届かないアドレスを告知するので、接続する前に拒否します。
Valkeyも
- ValkeyはRedisと同じようにRESP2とRESP3を話すので、この同じクライアントを通り、Valkey 8.0と9.1に対して、単独でも、スロットが移動中のクラスタでも測っています。
HELLOはserver valkeyと答え、それでCalíopeは2つのどちらと話しているかを知ります。 - Valkeyは
redis_mode:を公開しません。HELLOがなければ、モードはINFO serverのserver_mode:から読みます。 - Valkeyがその上に加えるもの(
COMMANDLOG、クラスタ内の番号付きデータベース):話しません。SLOWLOGは今もあり、「スローコマンド」が読むのはそれです。
SQL Server(TDS)
もとにしたもの
- Open Specification Promiseのもとで公開されている、Microsoftの[MS-TDS] Tabular Data Stream Protocol、2026年6月17日のリビジョン42.0。
- TDS 8.0と厳格な暗号化についてのSQL Serverのページと、そのALPNのためのRFC 7301。
geographyとgeometryの形式のための[MS-SSCLRT]。- 書くあいだ、オープンソースのSwiftクライアントの1つ、tds-nioを参考として読みました。そのコードは一切コピーしていません。
話すもの
- 常に暗号化:まずTDS 8.0の厳格モードで、最初のバイトからTLS 1.2以降のTLS。サーバが厳格モードを提示しないときは、PRELOGINの中でTDS 7.xのハンドシェイク。
- SQL Serverのログインによる、PRELOGINとLOGIN7(TDS 7.4)。
- バッチ(
SQL_BATCH)と、sp_executesqlへのRPCによるパラメータ化クエリー。型付きの値はSQLとは別に送ります。 - トークンストリーム:列、行、行数、エラー、メッセージ、環境の変更、そして空間型を含むSQL Serverの型。
ATTENTIONによるキャンセルと、接続がプールに戻る前のRESETCONNECTION。- バッチの区切りとしての
GO。SQL Server自身のツールと同じように、クライアントが扱います。
話さないもの
- MARS:1つの接続に1つのリクエスト、プールの利用者1人に1つの接続。
- Windows統合認証(SSPI、Kerberos、NTLM):ドメインと、サンドボックスにはないKerberosクライアントが必要です。
- Microsoft Entra ID:Microsoftに対するOAuthのフローで、別の製品です。
- 暗号化されていない接続や、ログインだけを暗号化する接続:拒否します。
- 一括読み込み、トランザクションマネージャのリクエスト、Always Onのルーティング:トランザクションはT-SQLとして、読み込みは
INSERTとして送ります。 text、ntext、image、hierarchyid、ユーザのCLR型:サポート外として表示します。
ClickHouse(HTTP)
もとにしたもの
- ClickHouseのドキュメントのHTTPインターフェイス、フォーマットと設定、クエリーパラメータの構文、システムテーブル。
- クエリー文字列をエンコードするためのRFC 3986。
- そしてサーバ自身。設定、関数、型を、自分の
systemテーブルで説明しています。
話すもの
- 依存関係を足さずに、Appleの
URLSessionの上でHTTPまたはHTTPS:リクエストごとに1つの文、どのリクエストにもデータベース。 - 型付きのクエリーパラメータ(
{name:Type}):値はSQLとは別に送ります。 - クエリーが終わってから1行ずつ読む結果。これで
200 OKの最後にあるエラーを捕まえます。 - 返す行数の上限。制限する数字のすぐ横に書きます。
- 必要なバッチのためだけのセッション、
system.processesからの進行状況、KILL QUERYによる停止。 - ほかのエンジンと同じ3つの選択肢のTLS。SSHトンネル越しでも、証明書はプロファイルのホストと照合します。
話さないもの
- ネイティブのTCPプロトコル(ポート9000)とその形式:HTTPインターフェイスで、Calíopeに必要なものが、バイナリプロトコルも依存関係もなしに得られます。
- gRPCと、MySQLやPostgreSQLをまねるインターフェイス。
- 1つのリクエストに複数の文、またはタブごとのセッション:1つのセッションへの同時の2つのリクエストは、サーバが拒否します。
- リクエスト本文のデータと外部テーブル:アプリの挿入はSQLとして送ります。
- クライアント証明書:それを持つプロファイルは拒否します。
- トランザクション:サーバにありません。
Oracle Database(TNS)
もとにしたもの
- Oracleはネットワークプロトコルの仕様を公開していません。公開していて、公式の参照として名指ししているのは、自社のPythonドライバpython-oracledbのThinモードのソースで、Universal Permissive License 1.0またはApache License 2.0のもとにあります。私は2026年10月6日時点の、固定したリビジョンのそれをもとに書いています。そこから派生したファイルはどれもそう明記し、そのライセンスはCalíopeのほかのサードパーティの通知とともに配布されます。
- Oracleのドキュメント:SQL言語リファレンス、データディクショナリビューのためのデータベースリファレンス、PL/SQLパッケージのリファレンス、Net Servicesリファレンス。
- ほかのOracleのクライアントは、どの言語のものも閉じたままにしました。
話すもの
- TCP上、またはシステムの証明書かプロファイルの証明書で検証するTLS(TCPS)上のTNS。SSHトンネル越しでも名前はプロファイルのホストと照合し、リスナーのリダイレクトにも従います。
- データベースのパスワードによるサインイン(O5LOGON)。
- 型付きの値をSQLとは別にした文と、バッチで届く行。
CLOBとBLOBは上限までまるごと読み、それを超えるとセルにはサイズが表示されます。 - 実行中の文のキャンセル。
話さないもの
- 帯域外のブレーク:SwiftNIOでは送れないので、キャンセルは常に帯域内で送ります。
- ウォレットとクライアント証明書、アクセストークン、Kerberos、オペレーティングシステムでのサインイン:サインインはパスワードで、TLSは一方向。クライアント証明書を持つプロファイルは拒否します。
- オブジェクト型、コレクション、
XMLTYPE、バイナリJSON、VECTOR、BFILEのデコード:代わりにセルが型の名前を示します。 - DRCP、ドライバ独自のセッションプール、パイプライン、高速認証。
- Advanced Queuing、2フェーズコミット、ダイレクトパス・ロード、変更通知。
tnsnames.oraとsqlnet.ora:ホスト、ポート、サービスはプロファイルが持ちます。
Apache CassandraとScyllaDB(CQL)
もとにしたもの
- Apache Cassandraプロジェクトが公開しているネイティブプロトコルv4の仕様。2025年4月3日の固定したリビジョン。
- ScyllaDBがプロトコルに加え、Calíopeが読むもの:
SUPPORTEDのSCYLLA_*キー。サーバに対して測っています。 - ほかのCassandraのクライアントは、どの言語のものも開いていません。
話すもの
- Cassandra 4.1以降とScyllaDB 2025.1以降が話す、ネイティブプロトコルのバージョン4。各応答は、ストリームによって自分のリクエストと対応づけます。
- パスワードによるサインイン(
PasswordAuthenticatorに対するSASLのPLAIN)、任意のクライアント証明書付きのTLS、SSHトンネル。 - 一貫性レベル付きのクエリー、
paging_stateによるページング、バインドする値のためのプリペアドステートメント、ロギングあり・なしのバッチ、要求に応じたトレース。 - すべてのCQLの型を、
cqlshと同じ書き方で。 - 両方のサーバに1つのドライバ:
OPTIONSにはサインインの前に答えが返り、その答えにあるSCYLLA_*キーで、Calíopeは2つのどちらと話しているかを知ります。
話さないもの
- プロトコルのバージョン5以降:Calíopeがサポートするどのバージョンでも、両方のサーバが話すのはバージョン4です。
- 圧縮と、そのイベントを伴う
REGISTER:デスクトップのクライアントには、どちらも用がありません。 - トークンを意識したルーティング:クライアントはプロファイルのコンタクトポイントか、その代替と話します。
- KerberosとLDAPによるサインイン。
ElasticsearchとOpenSearch(REST)
もとにしたもの
- Elasticが公開しているREST APIの仕様と、OpenSearchプロジェクトが公開している仕様。どちらも固定したリビジョン。
- 両者の公開APIドキュメント。どちらも十分に書いていないところは、Elasticsearch 9.5とOpenSearch 3.9のサーバそのものに対して測っています。
- Kibana、OpenSearch Dashboards、そしてどの言語の公式クライアントも開いていません。
話すもの
- Appleの
URLSessionの上で、HTTPまたはHTTPSによるREST API。依存関係は追加していません。Elasticsearch 8.18以降とOpenSearch 2.19以降に対応。 - ユーザーとパスワード、またはElasticsearchではAPIキーによるサインイン。接続時の
GET /の応答で、Calíopeはどちらと話しているかを知ります。 - 独自の認証局と任意のクライアント証明書付きのTLS。「どの証明書でも受け入れる」は決してしません。そしてSSHトンネル。
- Query DSLと、製品ごとの表形式の言語:両方でSQL、ElasticsearchでES|QL、OpenSearchでPPL。
話さないもの
- KibanaやOpenSearch Dashboardsの領分のもの:ダッシュボード、可視化、Discover、アラート。
- スナップショットの復元、再インデックス、ライフサイクルポリシー・テンプレート・パイプラインの編集、クラスター間レプリケーション。Calíopeはそれらを表示し、変更はサーバに任せます。
- 機械学習と類似度によるベクトル検索。ベクトルのフィールドは表示しますが、問い合わせはしません。
- 有料ライセンスが必要な機能。