tom__bo’s Blog

MySQL!! MySQL!! @tom__bo

8.0.22のprepared statementの調査続き1

tombo2.hatenablog.com

↑についてリノベ8.0.22で話した。

このとき、MTG中にそれぞれが試してみるとgoだと動く、rubyだと応答がなくなるという話をしていた。
tmtmさんがRuby, Cで追実験した結果をブログにしてくれていたので、僕もgoの結果を書いておこうと思う。

tmtms.hatenablog.com

結果を先に書くと、dockerで公式イメージの8.0.22に対して実行するとドキュメント通りsortはされないが結果は帰ってきた。 goのdriverの実装を見てからブログを書こうと思って放置していたが、ここまでの結果だけをとりあえず書きます。

go実験コード

// main.go
package main

import (
    "database/sql"
    "fmt"
    _ "github.com/go-sql-driver/mysql"
    "log"
)

type Tbl struct {
    id int64
    c1 int64
}

func main() {
    // db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:33061)/sample")
    db, err := sql.Open("mysql", "root:root@tcp(127.0.0.1:33068)/sample")
    if err != nil {
        log.Fatal("db error.")
        fmt.Println(err.Error())
    }
    defer db.Close()

    q := "select id,c1 from t1 order by ?"
    stmt, err := db.Prepare(q)
    if err != nil {
        log.Fatal("prepare error.")
        fmt.Println(err.Error())
    }
    defer stmt.Close()

    rows, err := stmt.Query(2)
    if err != nil {
        log.Fatal("prepare exec error.")
        fmt.Println(err.Error())
    }

    // rows, err := db.Query("select id,c1 from t1 order by ?", 2)
    // if err != nil {
    //     log.Fatal(err)
    // }

    for rows.Next() {
        t := Tbl{}
        if err := rows.Scan(&t.id, &t.c1); err != nil {
            log.Fatal(err)
        }
        fmt.Println(t)
    }
}

ここでは明示的にdb.Prepare()を使ったが、sql.Open()のオプションで ?interpolateParams=true を指定しないとdefaultではdb.Query()も内部的にprepared statementとして実行される。

cf: https://github.com/go-sql-driver/mysql#interpolateparams

MTG中はコメントアウトしてる部分の方で実行してwiresharkでもprepared statementになっていることを確認した。

結果

どちらも手元のdockerで確認(go version go1.15.2 darwin/amd64)

  • 8.0.21
% go run main.go
{5 12}
{3 25}
{1 62}
{4 77}
{2 82}
  • 8.0.22
% go run main.go
{1 85}
{2 41}
{3 52}
{4 37}
{5 30}

8.0.22ではorder byは効いていないが結果は返ってくる