bun icon indicating copy to clipboard operation
bun copied to clipboard

fix: handle invalid value on fieldByIndex

Open EllaFoxo opened this issue 2 years ago • 5 comments

When using deep Relation() with Scan(ctx), if the value we're scanning is invalid (usually zero), then bun currently panics when attempting v.Field(idx)

Let's handle that correctly before trying to apply it.

EllaFoxo avatar May 17 '22 11:05 EllaFoxo

Thanks! Any chance you can add a test or demonstrate how to reproduce this?

vmihailenco avatar Jun 08 '22 07:06 vmihailenco

Shall do that next week on my midsummer break! Things have been busy; sorry for the delayed reply

EllaFoxo avatar Jun 14 '22 07:06 EllaFoxo

@tinyfluffs thank you in advance!

vmihailenco avatar Jun 14 '22 10:06 vmihailenco

Hello! Is it possible to hope that this PR will get into the release?

lakkinzimusic avatar Aug 31 '22 13:08 lakkinzimusic

We are waiting for a test that demonstrates why we need this PR. @lakkinzimusic perhaps you have one?

vmihailenco avatar Sep 02 '22 12:09 vmihailenco

We are waiting for a test that demonstrates why we need this PR. @lakkinzimusic perhaps you have one?

	"context"
	"database/sql"
	"encoding/json"
	"fmt"
	"log"

	"github.com/uptrace/bun"
	"github.com/uptrace/bun/dialect/sqlitedialect"
	"github.com/uptrace/bun/driver/sqliteshim"
	"github.com/uptrace/bun/extra/bundebug"
)

func main() {
	ctx := context.Background()

	// Open an in-memory SQLite database.
	sqlite, err := sql.Open(sqliteshim.ShimName, "file::memory:?cache=shared")
	if err != nil {
		panic(err)
	}

	// Create a Bun db on top of it.
	db := bun.NewDB(sqlite, sqlitedialect.New())

	// Print all queries to stdout.
	db.AddQueryHook(bundebug.NewQueryHook(bundebug.WithVerbose(true)))

	// create and insert data
	db.NewCreateTable().Model((*SampleTable)(nil)).Exec(ctx)
	db.NewInsert().Model(&Data).Exec(ctx)

	var st []SampleTable

	err = db.NewSelect().Model(&st).
		Relation("FirstChild").
		Relation("FirstChild.FirstChild").
		Scan(ctx)
	if err != nil {
		log.Println(err)
	}

	res, _ := json.MarshalIndent(st, "", "  ")
	fmt.Println(string(res))
}

type SampleTable struct {
	bun.BaseModel `bun:"table:sample_table"`
	ID            int `bun:",autoincrement,pk"`
	FirstChildID  int
	FirstChild    *SampleTable `bun:"rel:has-one,join:first_child_id=id"`
}

var Data = []SampleTable{
	{FirstChildID: 0},
}

nilsocket avatar May 17 '23 19:05 nilsocket

Hi @vmihailenco , above I have pasted the reproducible program.

I'm facing the similar problem.

I think it's better to check for m.struct.IsValid() in m.scanColumn() along with m.isNil(), before calling field.ScanValue().

Something like this:

if !m.strct.IsValid() || (src == nil && m.isNil()) {
    return true, nil
}

Thank you.

nilsocket avatar May 18 '23 03:05 nilsocket

@nilsocket this is what I get when I run your program

[bun]  10:51:32.521   CREATE TABLE           1.07ms  CREATE TABLE "sample_table" ("id" INTEGER NOT NULL, "first_child_id" INTEGER, PRIMARY KEY ("id"))
[bun]  10:51:32.521   INSERT                  143µs  INSERT INTO "sample_table" ("first_child_id") VALUES (0) RETURNING "id"
[bun]  10:51:32.521   SELECT                  132µs  SELECT "sample_table"."id", "sample_table"."first_child_id", "first_child"."id" AS "first_child__id", "first_child"."first_child_id" AS "first_child__first_child_id", "first_child__first_child"."id" AS "first_child__first_child__id", "first_child__first_child"."first_child_id" AS "first_child__first_child__first_child_id" FROM "sample_table" LEFT JOIN "sample_table" AS "first_child" ON ("first_child"."id" = "sample_table"."first_child_id") LEFT JOIN "sample_table" AS "first_child__first_child" ON ("first_child__first_child"."id" = "first_child"."first_child_id")
[
  {
    "ID": 1,
    "FirstChildID": 0,
    "FirstChild": null
  }
]

Is there anything worng?

vmihailenco avatar Sep 10 '23 07:09 vmihailenco