I want to initialize a package-wide variable in some Go code to connect to a database, but I keep getting a nil pointer exception, so clearly the assignment isn't occurring properly. This throws an error:
package main
import (
"fmt"
"database/sql"
_ "github.com/lib/pq"
)
var connection *sql.DB
func init() {
connectionString := "host=172.17.0.3 dbname=postgres user=postgres password=postgres port=5432 sslmode=disable"
connection, err := sql.Open(
"postgres",
connectionString,
)
check(err)
err = connection.Ping()
check(err)
}
func main() {
TestConnect()
}
func TestConnect() {
var pid int
err := connection.QueryRow("SELECT pg_backend_pid()").Scan(&pid)
check(err)
fmt.Printf("pid: %v", pid)
}
func check(err error) {
if err != nil {
panic(err)
}
}
Here's the error:
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x0 pc=0x4c1a1a]
goroutine 1 [running]:
database/sql.(*DB).conn(0x0, 0x70b7c0, 0xc4200102b8, 0x1, 0xc420055e08, 0x4c28df, 0xc4200b0000)
/usr/local/go/src/database/sql/sql.go:896 +0x3a
database/sql.(*DB).query(0x0, 0x70b7c0, 0xc4200102b8, 0x630335, 0x17, 0x0, 0x0, 0x0, 0x101, 0x741c80, ...)
/usr/local/go/src/database/sql/sql.go:1245 +0x5b
database/sql.(*DB).QueryContext(0x0, 0x70b7c0, 0xc4200102b8, 0x630335, 0x17, 0x0, 0x0, 0x0, 0x0, 0x8, ...)
/usr/local/go/src/database/sql/sql.go:1227 +0xb8
database/sql.(*DB).QueryRowContext(0x0, 0x70b7c0, 0xc4200102b8, 0x630335, 0x17, 0x0, 0x0, 0x0, 0xc420010cb0)
/usr/local/go/src/database/sql/sql.go:1317 +0x90
database/sql.(*DB).QueryRow(0x0, 0x630335, 0x17, 0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/database/sql/sql.go:1325 +0x7c
main.TestConnect()
/home/tom/go/src/go-rest/ignore/connect.go:32 +0x82
main.main()
/home/tom/go/src/go-rest/ignore/connect.go:26 +0x20
exit status 2
However, if I switch it up so I can use the =
operator on connection
instead of :=
...
package main
import (
"fmt"
"database/sql"
_ "github.com/lib/pq"
)
var connection *sql.DB
func init() {
connectionString, err := GetConnectionString()
connection, err = sql.Open(
"postgres",
connectionString,
)
check(err)
err = connection.Ping()
check(err)
}
func main() {
TestConnect()
}
func TestConnect() {
var pid int
err := connection.QueryRow("SELECT pg_backend_pid()").Scan(&pid)
check(err)
fmt.Printf("pid: %v", pid)
}
func GetConnectionString() (string, error) {
return "host=172.17.0.3 dbname=postgres user=postgres password=postgres port=5432 sslmode=disable", nil
}
func check(err error) {
if err != nil {
panic(err)
}
}
Then everything works as expected, and the variable is properly assigned. Because the err
variable is previously undefined, I have to use :=
for assignment, but this seems to assume that I'm initializing a function-scoped connection
variable, and not trying to assign to the package-scoped connection
variable. Is there a way to force this assignment in Go? As it stands, I need to write useless, boilerplate code to get this to work the right way, and it seems like there should be a better way.
Of course, the possibility also stands that I'm trying to do something that I perhaps shouldn't be. Based on my research though, this guide seems to suggest using a package-wide database connection is better then creating / closing connections as needed.