Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nil time.Time pointer works in insert, but not in update #23

Closed
aktau opened this issue Jul 31, 2014 · 4 comments
Closed

nil time.Time pointer works in insert, but not in update #23

aktau opened this issue Jul 31, 2014 · 4 comments

Comments

@aktau
Copy link

aktau commented Jul 31, 2014

I have this code:

type FeedArticle struct {
    Id          int64
    Feed        int64
    Reference   string
    Title       string
    Body        sql.NullString
    PublishedOn *time.Time
}

func (m *Model) MergeArticles(articles ...*FeedArticle) error {
    tx, err := m.db.Begin()
    if err != nil {
        return err
    }

    update, err := tx.Prepare(`
        UPDATE feed_articles
        SET    title         = $3::text
        ,      body          = $4::text
        ,      published_on  = $5::timestamptz
        WHERE  feed          = $2::integer
        AND    reference     = $1::text
    `)
    if err != nil {
        tx.Rollback()
        return err
    }

    insert, err := tx.Prepare(`
        INSERT INTO feed_articles (reference, feed, title, body, published_on)
        VALUES ($1::text, $2::integer, $3::text, $4::text, $5::timestamptz)
    `)
    if err != nil {
        tx.Rollback()
        return err
    }

    for _, a := range articles {
        // do a naive loop, later we should generate a bulk statement client
        // side
        fmt.Printf("Processing: %s, %d, %s, %v, %p\n", a.Reference, a.Feed,
            a.Title, a.Body, a.PublishedOn)
        res, err := update.ExecOne(a.Reference, a.Feed, a.Title, a.Body,
            a.PublishedOn)
        if err != nil {
            tx.Rollback()
            return err
        }

        // if we've managed to update an article, stop here
        if res.Affected() != 0 {
            continue
        }

        _, err = insert.ExecOne(a.Reference, a.Feed, a.Title, a.Body,
            a.PublishedOn)
        if err != nil {
            return err
        }

    }

    return tx.Commit()
}

And the second time I run it, it errors out with:

panic: runtime error: invalid memory address or nil pointer dereference
[signal 0xb code=0x1 addr=0x0 pc=0x5c23b0]

goroutine 16 [running]:
runtime.panic(0x777180, 0xa99cb3)
        /usr/lib/go/src/pkg/runtime/panic.c:279 +0xf5
github.com/go-pg/pg.assertOneAffected(0x0, 0xc208103938, 0x0, 0x0)
        /home/vagrant/go/src/github.com/go-pg/pg/db.go:388 +0x30
github.com/go-pg/pg.(*Stmt).ExecOne(0xc208140f80, 0xc208103938, 0x5, 0x5, 0x5, 0x0, 0x0)
        /home/vagrant/go/src/github.com/go-pg/pg/stmt.go:75 +0xa2
bitbucket.org/aktau/lumamodel.(*Model).MergeArticles(0xc2080384d8, 0xc208107b00, 0x12, 0x20, 0x0
, 0x0)

Note that the FeedArticle.PublishedOn member is a nil pointer in this invocation (I checked). What's string is: this seems to work for the INSERT. I checked after a first run and the row is present in the DB (and the PublishedOn column is NULL).

Am I doing something wrong?

(I'm using a pointer to time.Time because I couldn't find a sql.NullTime type).

@aktau
Copy link
Author

aktau commented Jul 31, 2014

After looking at the backtrace, this seems to have little to do with the *time.Time being nil.

What's also strange is that on the first run, with an empty database, the res value gives 1 (!) as the Affected value. While I'm positive that there's not row it could have possible matched... very strange.

It almost seems like the UPDATE statement is inserting rows... am I going crazy?

@aktau
Copy link
Author

aktau commented Jul 31, 2014

Could it be that somehow, there can only be one prepared statement active at a time? And that the INSERT statement is overriding the UPDATE statement?

@vmihailenco
Copy link
Member

Yeah, client did not support multiple statements in 1 transaction. Should be fixed by #24 . I will merge fix later today.

Also you are probably interested in RunInTransaction helper: http://godoc.org/gopkg.in/pg.v2#DB.RunInTransaction

vmihailenco added a commit that referenced this issue Aug 1, 2014
Support multiple statements within single connection. Fixes #23.
@aktau
Copy link
Author

aktau commented Aug 1, 2014

Also you are probably interested in RunInTransaction helper:

Indeed I was. I already switched to it when I saw it earlier (even before you mentioned it :)). The docs are a bit spartan, but that function name was clear enough. I'll learn to inspect go-pg's source better.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants