If erro != nil when erro = &{<nil> 0xc420052720}

Hey guys,

I got a problem with the code below,

erro := db.QueryRow(“INSERT INTO …”, …)
if erro != nil {
log.Fatal(erro)
}

When I run the application, the result for log.Fatal(erro) is &{<nil> 0xc420052720}… but if erro is nil, why entered in IF clause?

It’s my first app in golang, I have never seen golang before… maybe my question was stupid.

That code is saying to log.Fatal(err) if err is NOT nil.

!= means not equal to. Hope that helps :slight_smile:

yes Radovskyb… but erro is nil and is entering in if… the forum interpreted < and > wrong (like a html tag) sorry … the value for erro is &{<nil> 0xc420052720}

Oh ok I see what you are saying, but just so you know, all values contain their interface type and their values, so in this case it is not actually nil. Only one of the values in that case are nil, so it’s not comparable to an actual nil value.

You should check out this talk here, it will explain it better than I can :slight_smile:

You should really watch the whole thing, but at the very watch from 13min in, where he explains when nil is not actually nil.

Also can I ask what sql driver you are using? I can have a look for you and let you know what you need to change to get the desired result.

Edit: I actually think I was wrong above and that the error being returned is just a type with 2 values and that the first value is nil in this case. But either way, when I know what driver you are using I can help you :slight_smile:

Edit 2: Lastly, you should be using db.Exec to insert and not QueryRow if you are not retrieving and values back and just want to simply insert into the database.

Oh gee sorry I’m stupid, I just realized the actual issue after my last edit below. You are calling db.QueryRow which is not returning an error, but an *sql.Row, you need to use db.Exec.

Here’s a simple full example using an sqlite3 driver:

package main

import (
	"database/sql"
	"fmt"
	"log"

	_ "github.com/mattn/go-sqlite3"
)

func main() {
	db, err := sql.Open("sqlite3", "database.db")
	if err != nil {
		log.Fatalln(err)
	}
	defer db.Close()

	res, err := db.Exec(`CREATE TABLE users (
		id INTEGER PRIMARY KEY AUTOINCREMENT, 
		username VARCHAR(255)
	);`)
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println(res.RowsAffected())

	res, err = db.Exec("INSERT INTO users (username) VALUES (?)", "Benjamin")
	if err != nil {
		log.Fatalln(err)
	}
	fmt.Println(res.LastInsertId())
}

Hey Benjamin
Firstly I wanna write thank you very much… I will watch the video after this post.

Yes I suppose that I need use db.Exec… and there are parts of the code that I used db.Exec for updates and deletes (o.O)

so… I’m using github.com/go-sql-driver/mysql

Yes, I agree: QueryRow never return nil. I’ve checked (sorry )[1]… but now I have another question, lol. if QueryRow never return nil, why is there err != nil below? (I will search more about the type returned by QueryRow and the behavior of switch statement in golang.


err := QueryRow(..........)
switch {
    case err == sql.ErrNoRows:
            log.Printf("No user with that ID.")
    case err != nil:
            log.Fatal(err)
    default:
            fmt.Printf("Username is %s\n", username)
    }


And, based on web site of the driver [2], they explains about the return of QueryRow and why is need add another check inside the IF below.

var name string
err = db.QueryRow("select name from users where id = ?", 1).Scan(&name)
if err != nil {
	log.Fatal(err)
}
fmt.Println(name)


Thank you Benjamin


[1] https://golang.org/pkg/database/sql/#DB.QueryRow
[2] http://go-database-sql.org/errors.html

Hey @Marcos_Machado, sql.QueryRow returns an *sql.Rows object and not an error :slight_smile:

So it should actually be rows := sql.QueryRow(...).

But when you attach .Scan at the end of QueryRow, it uses the *sql.Rows object and scans any rows into the object you pass in and then Scan is actually returning an error, not QueryRow.

Hi, guys! I would like to help. What @radovskyb said is true. To summarize it all:

  1. QueryRow() will return *sql.Row
  2. QueryRow().Scan() will return error

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.