bvinc / go-sqlite-lite

SQLite driver for the Go programming language

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Crash while insert prepared statement inside tx

tapir opened this issue · comments

package main

import (
	"fmt"
	"testing"

	"github.com/bvinc/go-sqlite-lite/sqlite3"
)

var (
	conn, _       = sqlite3.Open("Chinook_Sqlite.sqlite")
	createTemp, _ = conn.Prepare(`CREATE TEMP TABLE IF NOT EXISTS inTable_INTEGER (data INTEGER NOT NULL)`)
	dropTemp, _   = conn.Prepare(`DROP TABLE inTable_INTEGER`)
	insertTemp, _ = conn.Prepare(`INSERT INTO inTable_INTEGER (data) VALUES (?)`)
	customer, _   = conn.Prepare(`SELECT FirstName FROM Customer WHERE CustomerId IN (SELECT data FROM temp.inTable_INTEGER)`)
	ids           = []interface{}{34, 99, 9, 87, 61, 92, 58, 8, 40, 49, 12, 83, 74, 44, 27, 21, 12, 23, 38, 7, 53, 72, 75, 69, 66, 97, 72, 2, 48, 83}
)

func TestInsert(t *testing.T) {
	var res []interface{}
	conn.WithTx(func() error {
		if err := createTemp.Exec(); err != nil {
			t.Error(err)
		}
		for _, v := range ids {
			if err := insertTemp.Exec(v); err != nil {
				t.Error(err)
			}
		}
		for {
			hasRow, _ := customer.Step()
			if !hasRow {
				break
			}
			var r interface{}
			customer.Scan(&r)
			res = append(res, r)
		}
		dropTemp.Exec()
		customer.Reset()
		return nil
	})
	fmt.Println(len(res))
}

go test -v gives the error below for the line insertTemp.Exec(v)

[tapir@collin sql-builder]$ go test -v
=== RUN   TestInsert
--- FAIL: TestInsert (0.00s)
panic: runtime error: invalid memory address or nil pointer dereference [recovered]
        panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x10 pc=0x4f9ee4]

goroutine 5 [running]:
testing.tRunner.func1(0xc0000b2100)
        /usr/lib/go/src/testing/testing.go:792 +0x387
panic(0x5c1360, 0x6f7b40)
        /usr/lib/go/src/runtime/panic.go:513 +0x1b9
github.com/bvinc/go-sqlite-lite/sqlite3.(*Stmt).Bind(0x0, 0xc000044670, 0x1, 0x1, 0x0, 0x0)
        /home/tapir/Documents/Go/pkg/mod/github.com/bvinc/go-sqlite-lite@v0.5.0/sqlite3/sqlite3.go:826 +0x604
github.com/bvinc/go-sqlite-lite/sqlite3.(*Stmt).Exec(0x0, 0xc000044670, 0x1, 0x1, 0x0, 0x0)
        /home/tapir/Documents/Go/pkg/mod/github.com/bvinc/go-sqlite-lite@v0.5.0/sqlite3/sqlite3.go:794 +0x4d
gitlab.com/tapir/sql-builder.TestInsert.func1(0xc00008c360, 0x0)
        /home/tapir/Documents/sql-builder/sqlite_test.go:26 +0x14b
github.com/bvinc/go-sqlite-lite/sqlite3.(*Conn).WithTx(0xc00008c360, 0xc000044780, 0x6d1c50, 0x22)
        /home/tapir/Documents/Go/pkg/mod/github.com/bvinc/go-sqlite-lite@v0.5.0/sqlite3/sqlite3.go:474 +0xd3
gitlab.com/tapir/sql-builder.TestInsert(0xc0000b2100)
        /home/tapir/Documents/sql-builder/sqlite_test.go:21 +0x7d
testing.tRunner(0xc0000b2100, 0x5eff18)
        /usr/lib/go/src/testing/testing.go:827 +0xbf
created by testing.(*T).Run
        /usr/lib/go/src/testing/testing.go:878 +0x35c
exit status 2
FAIL    gitlab.com/tapir/sql-builder    0.005s

Thanks for this report. So what's happening is that sqlite requires an initialization function to work, sqlite3_initialize. We call this function in a package initialization init() function.

The problem is that global variables are initialized BEFORE the package initialization runs. That means that your sqlite3.Open is running before sqlite3_initialize(). To work around this, just move the sqlite3.Open call into the body of a function.

I'll leave this open to see if I can think of a better way to initialize sqlite.

Now that I look at it, my crash happened in Open, but your crash looks different. I need to look at this again.

My confusion happened because I pasted your test into my tests, and the init function hadn't been called yet.

Your ACTUAL problem is that you're not checking errors, and your dropTemp and insertTemp are failing. If you checked errors, you would see:

    main_test.go:23: sqlite3: no such table: inTable_INTEGER [1]
    main_test.go:27: sqlite3: no such table: inTable_INTEGER [1]
    main_test.go:31: sqlite3: no such table: Customer [1]

sqlite can't prepare a statement for a table that doesn't exist yet.