I have the following file structure:
models/db.go
type DB struct {
*sql.DB
}
var db *DB
func init() {
dbinfo := fmt.Sprintf("user=%s password=%s dbname=%s sslmode=disable",
DB_USER, DB_PASSWORD, DB_NAME)
db, err := NewDB(dbinfo)
checkErr(err)
rows, err := db.Query("SELECT * FROM profile")
checkErr(err)
fmt.Println(rows)
}
func NewDB(dataSourceName string) (*DB, error) {
db, err := sql.Open("postgres", dataSourceName)
if err != nil {
return nil, err
}
if err = db.Ping(); err != nil {
return nil, err
}
return &DB{db}, nil
}
models/db_util.go
func (p *Profile) InsertProfile() {
if db != nil {
_, err := db.Exec(...)
checkErr(err)
} else {
fmt.Println("DB object is NULL")
}
}
When I try to access db
in InsertProfile
function, it says NULL ptr exception
. How do I access the db
in db_utils.go
?
I would not like to capitalize db
(as it would give access to all the packages).
I am getting the QUERY returned from the db
in init()
correctly.
icza has already correctly answered your specific problem but it's worth adding some additional explanation on what you're doing wrong so you understand how not to make the mistake in the future. In Go, the syntax
:=
for assignment creates new variables with the names to the left of the:=
, possibly shadowing package, or even parent scope function/method variables. As an example:Note Go has no way to delete or unset a variable, so once you have shadowed a higher scope variables (such as by creating a function scope variable of the same name as a package scope variable), there is no way to access the higher scope variable within that code block.
Also be aware that
:=
is a shorthand forvar foo =
. Both act in exactly the same way, however:=
is only valid syntax within a function or method, while thevar
syntax is valid everywhere.Edit: The problem is that you used Short variable declaration
:=
and you just stored the created*DB
value in a local variable and not in the global one.This line:
Creates 2 local variables:
db
anderr
, and this localdb
has nothing to do with your globaldb
variable. Your global variable will remainnil
. You have to assign the created*DB
to the global variable. Do not use short variable declaration but simple assignment, e.g:Original answer follows.
It's a pointer type, you have to initialize it before you use it. The zero value for pointer types is
nil
.You don't have to export it (that's what starting it with a capital letter does). Note that it doesn't matter that you have multiple files as long as they are part of the same package, they can access identifiers defined in one another.
A good solution would be to do it in the package
init()
function which is called automatically.Note that
sql.Open()
may just validate its arguments without creating a connection to the database. To verify that the data source name is valid, callDB.Ping()
.For example: