Skip to content

Driver hangs on Next() with some tricky MySQL query #253

Closed
@arvenil

Description

@arvenil

Hi,

I'm trying to run some tricky MySQL query, and it would be nice if anyone could help me with problem I encounter.

I'm trying to run EXPLAIN FORMAT=JSON query but only if it is supported by MySQL version. To do that, in theory, I can use conditional comments e.g. /*!50605 <SQL code to be run since version 5.6.5>*/

Below is an example of what I'm talking about

mysql> SHOW VARIABLES LIKE "version";
+---------------+-------------+
| Variable_name | Value       |
+---------------+-------------+
| version       | 5.6.19-67.0 |
+---------------+-------------+
1 row in set (0,00 sec)

mysql> /*!50605 EXPLAIN FORMAT=JSON SELECT 1*/;
+-------------------------------------------------------------------------------------------------------+
| EXPLAIN                                                                                               |
+-------------------------------------------------------------------------------------------------------+
| {
  "query_block": {
    "select_id": 1,
    "table": {
      "message": "No tables used"
    }
  }
} |
+-------------------------------------------------------------------------------------------------------+
1 row in set, 1 warning (0,00 sec)

mysql> /*!60605 EXPLAIN FORMAT=JSON SELECT 1*/;
Query OK, 0 rows affected (0,00 sec)

Since I have version 5.6.19 then code /*!50605 (>= 5.6.5) executes explain and code /*!60605 (>= 6.6.5) doesn't.

Here are also live examples on sql fiddle:
http://sqlfiddle.com/#!2/d41d8/40716/0 version 5.5.32
http://sqlfiddle.com/#!9/d41d8/788/0 version 5.6.6

However I'm unable to get similar results with go sql driver. It hangs in case where it should return 0 rows. Here is an example code (http://play.golang.org/p/ksY-FFHg7n):

package main

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

func main() {
    db, err := sql.Open("mysql", "@/")
    fmt.Println(err)
    var json string
    err = db.QueryRow("/*!50605 EXPLAIN FORMAT=JSON SELECT 1*/").Scan(&json)
    fmt.Println(err)
    fmt.Println(json)
}

Correct result when condition is fulfilled:

<nil>
<nil>
{
  "query_block": {
    "select_id": 1,
    "table": {
      "message": "No tables used"
    }
  }
}

Incorrect result when condition is not fulfilled:

go run main.go 
<nil>
(HANGS HERE, JUST AFTER FIRST NIL,  MANUALLY INTERRUPTED WITH SIGQUIT)
^\SIGQUIT: quit
PC=0x42bdc3

goroutine 17 [syscall]:
runtime.notetsleepg(0x7fa4fc0d4f60, 0xdf8475800)
    /usr/local/go/src/pkg/runtime/lock_futex.c:198 +0x46 fp=0x7fa4fc0d4f38 sp=0x7fa4fc0d4f08
runtime.MHeap_Scavenger()
    /usr/local/go/src/pkg/runtime/mheap.c:532 +0xa3 fp=0x7fa4fc0d4fa8 sp=0x7fa4fc0d4f38
runtime.goexit()
    /usr/local/go/src/pkg/runtime/proc.c:1445 fp=0x7fa4fc0d4fb0 sp=0x7fa4fc0d4fa8
created by runtime.main
    /usr/local/go/src/pkg/runtime/proc.c:207

goroutine 16 [IO wait]:
net.runtime_pollWait(0x7fa4fc246508, 0x72, 0x0)
    /usr/local/go/src/pkg/runtime/netpoll.goc:146 +0x66
net.(*pollDesc).Wait(0xc208028140, 0x72, 0x0, 0x0)
    /usr/local/go/src/pkg/net/fd_poll_runtime.go:84 +0x46
net.(*pollDesc).WaitRead(0xc208028140, 0x0, 0x0)
    /usr/local/go/src/pkg/net/fd_poll_runtime.go:89 +0x42
net.(*netFD).Read(0xc2080280e0, 0xc208068000, 0x1000, 0x1000, 0x0, 0x7fa4fc2453f0, 0xb)
    /usr/local/go/src/pkg/net/fd_unix.go:232 +0x34c
net.(*conn).Read(0xc20803c028, 0xc208068000, 0x1000, 0x1000, 0x0, 0x0, 0x0)
    /usr/local/go/src/pkg/net/net.go:122 +0xe7
github.com/go-sql-driver/mysql.(*buffer).fill(0xc208048200, 0x4, 0x0, 0x0)
    /home/kdz/local/libs/go/src/github.com/go-sql-driver/mysql/buffer.go:55 +0x25b
github.com/go-sql-driver/mysql.(*buffer).readNext(0xc208048200, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0)
    /home/kdz/local/libs/go/src/github.com/go-sql-driver/mysql/buffer.go:76 +0x6c
github.com/go-sql-driver/mysql.(*mysqlConn).readPacket(0xc208048200, 0x0, 0x0, 0x0, 0x0, 0x0)
    /home/kdz/local/libs/go/src/github.com/go-sql-driver/mysql/packets.go:30 +0x9d
github.com/go-sql-driver/mysql.(*textRows).readRow(0xc2080420a0, 0x770b00, 0x0, 0x0, 0x0, 0x0)
    /home/kdz/local/libs/go/src/github.com/go-sql-driver/mysql/packets.go:588 +0x68
github.com/go-sql-driver/mysql.(*textRows).Next(0xc2080420a0, 0x770b00, 0x0, 0x0, 0x0, 0x0)
    /home/kdz/local/libs/go/src/github.com/go-sql-driver/mysql/rows.go:80 +0x8c
database/sql.(*Rows).Next(0xc208004240, 0x59dce0)
    /usr/local/go/src/pkg/database/sql/sql.go:1542 +0xe5
database/sql.(*Row).Scan(0xc2080420c0, 0x7fa4fc0b6f20, 0x1, 0x1, 0x0, 0x0)
    /usr/local/go/src/pkg/database/sql/sql.go:1660 +0x23c
main.main()
    /home/kdz/local/libs/go/src/github.com/arvenil/db/main.go:14 +0x1bd

goroutine 19 [finalizer wait]:
runtime.park(0x4132c0, 0x770568, 0x76f049)
    /usr/local/go/src/pkg/runtime/proc.c:1369 +0x89
runtime.parkunlock(0x770568, 0x76f049)
    /usr/local/go/src/pkg/runtime/proc.c:1385 +0x3b
runfinq()
    /usr/local/go/src/pkg/runtime/mgc0.c:2644 +0xcf
runtime.goexit()
    /usr/local/go/src/pkg/runtime/proc.c:1445

goroutine 20 [chan receive]:
database/sql.(*DB).connectionOpener(0xc208048100)
    /usr/local/go/src/pkg/database/sql/sql.go:583 +0x48
created by database/sql.Open
    /usr/local/go/src/pkg/database/sql/sql.go:442 +0x27c

rax     0xfffffffffffffffc
rbx     0x0
rcx     0xffffffffffffffff
rdx     0x0
rdi     0x7fa4fc0d4f60
rsi     0x0
rbp     0x3c
rsp     0x7fa4fc0d4ea0
r8      0x0
r9      0x0
r10     0x7fa4fc0d4ed0
r11     0x216
r12     0x5ed9a0
r13     0x7fff47c715e0
r14     0x0
r15     0x0
rip     0x42bdc3
rflags  0x216
cs      0x33
fs      0x0
gs      0x0
exit status 2

First, I've tried to rewrite code to use Query instead of QueryRow, but it hang on Next() (as you can actually see in stacktrace).

Any ideas if this is bug in driver, MySQL or maybe in my code?

EDIT: tried with old version of driver and with 1.2 7094cf0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions