DATA-DOG / go-txdb

Immutable transaction isolated sql driver for golang

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

DB CURRENT_TIMESTAMP is always the same

ivanovaleksey opened this issue · comments

Hello, thanks for the library!

I have been using it in tests for some time but today I noticed a strange behaviour.
In one of my test I insert 3 records one-by-one with created_at set by DB as DEFAULT CURRENT_TIMESTAMP.
Later I select those records with ORDER BY created_at. And records order is always messed up.
I investigated it a little bit and I noticed that all records have the same created_at value whereas with read DB it differs in few milliseconds.

I ended up with code snippet which demonstrates the problem:

func main() {
	const dsn = "postgres://postgres@localhost/test_db?sslmode=disable"
	txdb.Register("txdb", "postgres", dsn)

	db, err := sql.Open("txdb", "anywordhere")
	//db, err := sql.Open("postgres", dsn)
	if err != nil {
		log.Fatal(err)
	}

	probe(db)
	time.Sleep(1 * time.Second)
	probe(db)
}

func probe(db *sql.DB) {
	var ts time.Time
	err := db.QueryRow(`SELECT now()`).Scan(&ts)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(time.Now(), ts)
}

# => 2019-09-24 19:13:08.429564 +0300 MSK m=+0.009807600 2019-09-24 16:13:08.432757 +0000 UTC
# => 2019-09-24 19:13:09.436596 +0300 MSK m=+1.016829028 2019-09-24 16:13:08.432757 +0000 UTC

As you can see DB time is always the same.

Could you please help me to figure out what is going on? Is there any cache?
Thank you.

Hm interesting. Will need to have a look, but txdb has no caches. Though, it performs everything within a transaction. It may mean that postgres has some internal logic and whenever you do the select in the sane transaction it just gives the current time. Though it needs to be verified. But you can check this behavior the same within the transaction simply. It most likely is the driver internal logic issue or postgres

@l3pp4rd thanks for the reply!
Yes, I thought it could be due to transaction.
Seems like it is the case. I have found the same question. And also this SO answer.

This code snippet shows the behaviour

func main() {
	db, err := sql.Open("postgres", dsn)
	if err != nil {
		log.Fatal(err)
	}

	tx, err := db.Begin()
	if err != nil {
		log.Fatal(err)
	}

	probe(tx)
	time.Sleep(1 * time.Second)
	probe(tx)
}

func probe(tx *sql.Tx) {
	var ts time.Time
	err := tx.QueryRow(`SELECT now()`).Scan(&ts)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println(time.Now(), ts)
}
# => 2019-09-25 12:49:12.842344 +0300 MSK m=+0.020594338 2019-09-25 09:49:12.866152 +0000 UTC
# => 2019-09-25 12:49:13.846922 +0300 MSK m=+1.025170123 2019-09-25 09:49:12.866152 +0000 UTC

2019-09-25-130614

Here is the answer.

now() in postgres transaction, just uses old transaction_timestamp() which seems to be the start of transaction, no matter how many times you call it, it will be the same.
You have an option to use clock_timestamp() instead. This will work with your code no matter whether it will be transaction or not, because without using txdb, you may still endup using a transaction, which may result in the same issue. So instead use clock_timestamp()

@l3pp4rd yes, thanks for the help!