Skip to content

sql: Select into []*T returns nil pointers, and a struct with an unexported field matching a column panics #4426

Description

@NitinKumar004

Summary

DB.Select (ctx.SQL.Select) has two problems with struct destinations:

  1. A []*T destination comes back with N nil pointers. The rows are counted but never scanned into the elements, and no error is reported.
  2. A struct with an unexported field that matches a column panics: reflect.Value.Interface: cannot return value obtained from unexported field or method.

Reproduction

In-process sqlite, table users(id, name) with rows (1,'a') and (2,'b'):

type User struct {
	ID   int
	Name string
}

var us []*User
db.Select(ctx, &us, "SELECT id, name FROM users")
// us[0] = <nil>, us[1] = <nil>

type Row struct {
	id   int // unexported
	Name string
}

var rs []Row
db.Select(ctx, &rs, "SELECT id, name FROM users")
// panic: reflect.Value.Interface: cannot return value obtained from unexported field or method
//   sql.(*DB).rowsToStruct db.go:345

Root cause

pkg/gofr/datasource/sql/db.go:

  • Pointer elements: selectSlice (line 266) only maps rows into structs when the element kind is Struct. For *T it falls through to rows.Scan with a **T. That fails, and the error is discarded, so a nil element is appended per row.
  • Unexported fields: rowsToStruct builds scan targets with v.Field(i).Addr().Interface() (line 345) for every field whose name matches a column. It never checks IsExported(), so the call panics on an unexported field.

Impact

  • []*Model is a very common Go idiom. With it, handlers silently get nil entries (and nil-pointer panics later) instead of data.
  • Models with private helper fields that happen to share a column name panic the request.

Suggested fix

  • In selectSlice, handle Elem().Kind() == Ptr && Elem().Elem().Kind() == Struct: allocate with reflect.New(elem.Elem()), fill it via rowsToStruct and append the pointer.
  • Skip fields that are unexported or tagged db:"-" in rowsToStruct, as encoding/json and sqlx do.
  • Log (or return) scan errors rather than dropping them.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions