moontidb

    TiDB for moondb — the moonmysql wire protocol, with the server's own capability report and version detection.

    tidb
    mysql
    distributed
    sql
    driver
    database
    htap
    moondb
    moonbit
    Download zip
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    11 hours ago
    Downloads
    14

    #moontidb

    TiDB for moondb — MySQL's wire protocol, MySQL's AsyncDriver, and the places where the server behind it is not MySQL, asked rather than assumed.

    moon add moonbitstack/moontidb

    async fn run() -> Unit raise {
    let db = @moontidb.connect("127.0.0.1", 4000, "root", "", "test")
    let server = @moontidb.server_of(db) // Server::Tidb
    let plan = @moontidb.capabilities_for(server) // multiple_result_sets: false
    db.execute("CREATE TABLE hero (id INT PRIMARY KEY, name TEXT)", []) |> ignore
    db.close()
    }

    #Why this is a package and not a paragraph

    TiDB answers MySQL's wire protocol and most of its SQL, so moonmysql already speaks to it — and this package contains no second protocol implementation. It answers the two questions the protocol cannot:

    • Which server is this? server_of(conn) runs SELECT VERSION() and reads the sentence. TiDB answers with a MySQL version and its own (8.0.11-TiDB-v8.5.0-serverless) for the benefit of old clients, so the string has to be read rather than taken at its first word. MariaDB is detected the same way.
    • What does it lack? capabilities_for(Server::Tidb) clears multiple_result_sets. CREATE PROCEDURE with a result set raises Unsupported type *resolve.NodeW (error 8108), so the multi-result-set path is empty there. Everything else the MySQL driver offers — prepared statements, savepoints, transactions, unsigned 64-bit columns — holds.

    #What holds, and what does not

    Verified against a real TiDB v8.5 in this repository's CI, by running the shared conformance matrix through this package's connect: 12 of 12, no skips.

    TiDB v8.5
    Prepared statements, binary protocolyes
    INSERT/UPDATE without a primary keyyes (hidden _tidb_rowid)
    Savepoints, transactionsyes
    Unsigned 64-bit columnsyes
    Stored procedures returning result setsno (error 8108)
    utf8 vs utf8mb3 spelling in the sessionTiDB reports utf8mb3 where MySQL reports utf8
    FLOAT rendered as textmore digits than MySQL's six

    The last two are cosmetic on the wire — the driver sends collation ids and decodes FLOAT by its column type — but they show up in a query that prints them, and they are the server's behaviour rather than the driver's.

    #License

    Apache-2.0 © Leo Cheng.

    Server

    pub(all) enum Server {
    Mysql
    Mariadb
    Tidb
    } derive(Eq)

    Which server is answering on the MySQL wire. TiDB reports a MySQL version and its own in the same string (8.0.11-TiDB-v8.5.0-…), so the sentence has to be read rather than assumed: a statement that works on MySQL 8 may not parse here, and one that works on TiDB may not exist there.

    Server::equal

    fn Server::equal(Server, Server) -> Bool

    Comparing two server names is the whole point of naming them.

    Server::from_version

    fn Server::from_version(version : String) -> Server

    The server a SELECT VERSION() answer names. The order matters: TiDB prefixes its answer with a MySQL version for the benefit of old clients, so tidb has to be looked for before the string is taken at face value.

    Server::name

    fn Server::name(self : Server) -> String

    Server::not_equal

    fn Server::not_equal(x : Server, y : Server) -> Bool

    Comparing two server names is the whole point of naming them.

    capabilities_for

    fn capabilities_for(server : Server) ->
    Capabilities

    What this server can do, as opposed to what the driver implements. On TiDB the one flag that has to go is multiple_result_sets: a stored procedure that returns a result set is rejected at CREATE PROCEDURE time, so query_multi has nothing to read. Everything else the MySQL driver offers — prepared statements, savepoints, transactions, unsigned 64-bit columns — holds.

    connect

    async fn connect(host : String, port : Int, user : String, password : String, database : String, tls? :
    Client
    ) ->
    MysqlConn

    Connect the way [@client.MysqlConn::connect] does — the protocol is the same one.

    server_of

    Which server is behind this connection, asked rather than assumed.

    version

    The server's own version sentence, as it answered.

    Source Files