Calíopeのアプリアイコン

私が書くドライバ

8つのクライアント。どれも、作り手が公開しているものから書いています。

Calíopeは、私が自分で書いたクライアントを通じて8種類のサーバと話します。どれも作り手が公開しているものから書きました。その仕様とドキュメント、あるいはOracleのように仕様を公開していない場合は、作り手が参照実装として名指ししているドライバです。他人のクライアントから書いたことは一度もありません。そしてどれも、Calíopeが使うものを実装し、それ以上は実装しません。このページでは各クライアントを3つの部分にまとめています:何をもとに書かれたか、何を話すか、何をあえて外しているか(その理由とともに)。

どの要約の裏にも、完全な仕様があります:すべてのメッセージ、すべてのサインイン方式、クライアントの組み立て方、そして実際のサーバに対するテストの方法。それはソースリポジトリにスペイン語で置かれ、説明しているコードとコミットのたびに照合されます。ドライバが変わったら、その変更が入る前に、ドキュメントを読み直さなければなりません。

MySQLとMariaDB

もとにしたもの

話すもの

  • ケイパビリティのネゴシエーションを伴う接続フェーズと、その途中で始まる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

もとにしたもの

話すもの

  • 何よりも先に要求する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

もとにしたもの

話すもの

  • 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。各応答は、位置によって自分のコマンドと対応づけます。
  • 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)

もとにしたもの

話すもの

  • 常に暗号化:まず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)

もとにしたもの

話すもの

  • 依存関係を足さずに、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はそれらを表示し、変更はサーバに任せます。
  • 機械学習と類似度によるベクトル検索。ベクトルのフィールドは表示しますが、問い合わせはしません。
  • 有料ライセンスが必要な機能。