SSMSJM
SSMSJM

Reputation: 159

sql.Scan not returning ErrNoRows error when it should

I have a function GetAccount which is generated by sqlc.

When I call GetAccount(/*unused id*/), An ErrNoRows error should be returned. Instead I am getting no error and an Account with default values (zeros and empty strings) returned.

GetAccount implementation:

const getAccount = `-- name: GetAccount :one
SELECT id, owner, balance, currency, created_at
FROM accounts
WHERE id = $1
`

func (q *Queries) GetAccount(ctx context.Context, id int64) (Account, error) {
    row := q.db.QueryRowContext(ctx, getAccount, id)
    var i Account
    err := row.Scan(
      &i.ID,
      &i.Owner,
      &i.Balance,
      &i.Currency,
      &i.CreatedAt,
    )
    return i, err
}

Why I am not getting any error when there are no rows to return?

Edit:

As requested, here is how I am calling GetAccount. It is a Gin request handler.

type getAccountRequest struct {
    ID int64 `uri:"id" binding:"required,min=1"`
}

func (server *Server) getAccount(ctx *gin.Context) {
    var request getAccountRequest
    err := ctx.ShouldBindUri(&request)
    if err != nil {
        ctx.JSON(http.StatusBadRequest, errorResponse(err))
        return
    }

    account, err := server.store.GetAccount(ctx, request.ID) //<-called here
    if err == sql.ErrNoRows {
        ctx.JSON(http.StatusNotFound, errorResponse(err))
        return
    } else if err != nil {
        ctx.JSON(http.StatusInternalServerError, errorResponse(err))
        return
    }
    ctx.JSON(http.StatusOK, account)
}

Edit 2:

For clarity, when I say

An ErrNoRows error should be returned

I state this because of the call to row.Scan which should produce the error.

Documentation:

func (r *Row) Scan(dest ...any) error

Scan copies the columns from the matched row into the values pointed at by dest. See the documentation on Rows.Scan for details. If more than one row matches the query, Scan uses the first row and discards the rest. If no row matches the query, Scan returns ErrNoRows.

Upvotes: 2

Views: 1844

Answers (1)

Mihai
Mihai

Reputation: 10717

You are overwriting the sql error:

    account, err := server.store.GetAccount(ctx, request.ID) //<-called here
    err = ctx.ShouldBindUri(&request)
    if err == sql.ErrNoRows {

You should check the error immediately after the GetAccount call:

    account, err := server.store.GetAccount(ctx, request.ID) //<-called here
    if err == sql.ErrNoRows {

Upvotes: 1

Related Questions