package pg_test
import (
"strings"
. "github.com/onsi/ginkgo"
. "github.com/onsi/gomega"
"github.com/go-pg/pg"
)
var _ = Describe("Tx", func() {
var db *pg.DB
BeforeEach(func() {
db = pg.Connect(pgOptions())
})
AfterEach(func() {
err := db.Close()
Expect(err).NotTo(HaveOccurred())
})
It("reconnects on bad connection", func() {
cn, err := db.Pool().Get()
Expect(err).NotTo(HaveOccurred())
cn.SetNetConn(&badConn{})
db.Pool().Put(cn)
tx, err := db.Begin()
Expect(err).NotTo(HaveOccurred())
err = tx.Rollback()
Expect(err).NotTo(HaveOccurred())
})
It("supports multiple statements", func() {
tx, err := db.Begin()
Expect(err).NotTo(HaveOccurred())
stmt1, err := tx.Prepare(`SELECT 'test_multi_prepare_tx1'`)
Expect(err).NotTo(HaveOccurred())
stmt2, err := tx.Prepare(`SELECT 'test_multi_prepare_tx2'`)
Expect(err).NotTo(HaveOccurred())
var s1 string
_, err = stmt1.QueryOne(pg.Scan(&s1))
Expect(err).NotTo(HaveOccurred())
Expect(s1).To(Equal("test_multi_prepare_tx1"))
var s2 string
_, err = stmt2.QueryOne(pg.Scan(&s2))
Expect(err).NotTo(HaveOccurred())
Expect(s2).To(Equal("test_multi_prepare_tx2"))
err = tx.Rollback()
Expect(err).NotTo(HaveOccurred())
})
It("supports CopyFrom and CopyIn", func() {
data := "hello\t5\nworld\t5\nfoo\t3\nbar\t3\n"
_, err := db.Exec("DROP TABLE IF EXISTS test_copy_from")
Expect(err).NotTo(HaveOccurred())
_, err = db.Exec("CREATE TABLE test_copy_from(word text, len int)")
Expect(err).NotTo(HaveOccurred())
tx1, err := db.Begin()
Expect(err).NotTo(HaveOccurred())
tx2, err := db.Begin()
Expect(err).NotTo(HaveOccurred())
r := strings.NewReader(data)
res, err := tx1.CopyFrom(r, "COPY test_copy_from FROM STDIN")
Expect(err).NotTo(HaveOccurred())
Expect(res.RowsAffected()).To(Equal(4))
var count int
_, err = tx1.QueryOne(pg.Scan(&count), "SELECT COUNT(*) FROM test_copy_from")
Expect(err).NotTo(HaveOccurred())
Expect(count).To(Equal(4))
_, err = tx2.QueryOne(pg.Scan(&count), "SELECT COUNT(*) FROM test_copy_from")
Expect(err).NotTo(HaveOccurred())
Expect(count).To(Equal(0))
err = tx1.Commit()
Expect(err).NotTo(HaveOccurred())
_, err = tx2.QueryOne(pg.Scan(&count), "SELECT COUNT(*) FROM test_copy_from")
Expect(err).NotTo(HaveOccurred())
Expect(count).To(Equal(4)) // assuming READ COMMITTED
err = tx2.Rollback()
Expect(err).NotTo(HaveOccurred())
_, err = db.Exec("DROP TABLE IF EXISTS test_copy_from")
Expect(err).NotTo(HaveOccurred())
})
It("supports CopyFrom and CopyIn with errors", func() {
// too many fields on second line
data := "hello\t5\nworld\t5\t6\t8\t9\nfoo\t3\nbar\t3\n"
_, err := db.Exec("DROP TABLE IF EXISTS test_copy_from")
Expect(err).NotTo(HaveOccurred())
_, err = db.Exec("CREATE TABLE test_copy_from(word text, len int)")
Expect(err).NotTo(HaveOccurred())
_, err = db.Exec("INSERT INTO test_copy_from VALUES ('xxx', 3)")
Expect(err).NotTo(HaveOccurred())
tx1, err := db.Begin()
Expect(err).NotTo(HaveOccurred())
tx2, err := db.Begin()
Expect(err).NotTo(HaveOccurred())
_, err = tx1.Exec("INSERT INTO test_copy_from VALUES ('yyy', 3)")
Expect(err).NotTo(HaveOccurred())
r := strings.NewReader(data)
_, err = tx1.CopyFrom(r, "COPY test_copy_from FROM STDIN")
Expect(err).To(HaveOccurred())
var count int
_, err = tx1.QueryOne(pg.Scan(&count), "SELECT COUNT(*) FROM test_copy_from")
Expect(err).To(HaveOccurred()) // transaction has errors, cannot proceed
_, err = tx2.QueryOne(pg.Scan(&count), "SELECT COUNT(*) FROM test_copy_from")
Expect(err).NotTo(HaveOccurred())
Expect(count).To(Equal(1))
err = tx1.Commit()
Expect(err).NotTo(HaveOccurred()) // actually ROLLBACK happens here
_, err = tx2.QueryOne(pg.Scan(&count), "SELECT COUNT(*) FROM test_copy_from")
Expect(err).NotTo(HaveOccurred())
Expect(count).To(Equal(1)) // other transaction was rolled back so it's not 2 and not 6
err = tx2.Rollback()
Expect(err).NotTo(HaveOccurred())
_, err = db.Exec("DROP TABLE IF EXISTS test_copy_from")
Expect(err).NotTo(HaveOccurred())
})
})