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

Duplicate savepoint names resulting in partial rollbacks in nested transactions #7173

Closed
phroggyy opened this issue Aug 28, 2024 · 1 comment
Assignees
Labels
type:with reproduction steps with reproduction steps

Comments

@phroggyy
Copy link
Contributor

GORM Playground Link

go-gorm/playground#757

Description

When you wrap db.Transaction, go will only put that closure in memory once:

func Transaction(ctx context.Context, db *gorm.DB, apply func(ctx context.Context, db *gorm.DB) error) error {
	return db.
		WithContext(ctx).
		Transaction(func(db *gorm.DB) error {
			return apply(ctx, db)
		})
}

This means that the inner function passed to Transaction always has the same memory address.

This causes issues in https://github.com/go-gorm/gorm/blob/master/finisher_api.go#L626, where we use the memory address to decide the savepoint name.

With the current implementation, the following statements execute:

2024/08/28 11:32:41 /Users/leosjoberg/Code/open-source/gorm-playground/main_test.go:17 record not found
[0.155ms] [rows:0] SELECT * FROM `users` WHERE name = "jinzhu" AND `users`.`deleted_at` IS NULL ORDER BY `users`.`id` LIMIT 1

2024/08/28 11:32:41 /Users/leosjoberg/Code/Go/pkg/mod/gorm.io/driver/[email protected]/sqlite.go:237
[0.021ms] [rows:0] SAVEPOINT sp0x10050efe0

2024/08/28 11:32:41 /Users/leosjoberg/Code/open-source/gorm-playground/main_test.go:31
[1.206ms] [rows:1] INSERT INTO `users` (`created_at`,`updated_at`,`deleted_at`,`name`,`age`,`birthday`,`company_id`,`manager_id`,`active`) VALUES ("2024-08-28 11:32:41.299","2024-08-28 11:32:41.299",NULL,"jinzhu",0,NULL,NULL,NULL,false) RETURNING `id`
User created: 1
2024/08/28 11:32:41 /Users/leosjoberg/Code/Go/pkg/mod/gorm.io/driver/[email protected]/sqlite.go:237
[0.011ms] [rows:0] SAVEPOINT sp0x10050efe0

2024/08/28 11:32:41 /Users/leosjoberg/Code/open-source/gorm-playground/main_test.go:45 record not found
[0.143ms] [rows:0] SELECT * FROM `accounts` WHERE `accounts`.`id` = 1 AND `accounts`.`deleted_at` IS NULL ORDER BY `accounts`.`id` LIMIT 1

2024/08/28 11:32:41 /Users/leosjoberg/Code/Go/pkg/mod/gorm.io/driver/[email protected]/sqlite.go:242
[0.009ms] [rows:0] ROLLBACK TO SAVEPOINT sp0x10050efe0

2024/08/28 11:32:41 /Users/leosjoberg/Code/Go/pkg/mod/gorm.io/driver/[email protected]/sqlite.go:242
[0.006ms] [rows:0] ROLLBACK TO SAVEPOINT sp0x10050efe0

2024/08/28 11:32:41 /Users/leosjoberg/Code/open-source/gorm-playground/main_test.go:63
[0.194ms] [rows:1] SELECT * FROM `users` WHERE name = "jinzhu" AND `users`.`deleted_at` IS NULL ORDER BY `users`.`id` LIMIT 1

Note that we are rolling back to the same savepoint, making it impossible to rollback the INSERT statement.

A correct implementation will instead generate unique savepoints:


2024/08/28 11:24:38 /Users/leosjoberg/Code/open-source/gorm-playground/main_test.go:17 record not found
[1.964ms] [rows:0] SELECT * FROM "users" WHERE name = 'jinzhu' AND "users"."deleted_at" IS NULL ORDER BY "users"."id" LIMIT 1

2024/08/28 11:24:38 /Users/leosjoberg/Code/Go/pkg/mod/gorm.io/driver/[email protected]/postgres.go:269
[0.486ms] [rows:0] SAVEPOINT sp11014777973198018981

2024/08/28 11:24:38 /Users/leosjoberg/Code/open-source/gorm-playground/main_test.go:31
[21.092ms] [rows:1] INSERT INTO "users" ("created_at","updated_at","deleted_at","name","age","birthday","company_id","manager_id","active") VALUES ('2024-08-28 11:24:38.233','2024-08-28 11:24:38.233',NULL,'jinzhu',0,NULL,NULL,NULL,false) RETURNING "id"
User created: 1
2024/08/28 11:24:38 /Users/leosjoberg/Code/Go/pkg/mod/gorm.io/driver/[email protected]/postgres.go:269
[1.623ms] [rows:0] SAVEPOINT sp17326545142615515993

2024/08/28 11:24:38 /Users/leosjoberg/Code/open-source/gorm-playground/main_test.go:45 record not found
[1.504ms] [rows:0] SELECT * FROM "accounts" WHERE "accounts"."id" = 1 AND "accounts"."deleted_at" IS NULL ORDER BY "accounts"."id" LIMIT 1

2024/08/28 11:24:38 /Users/leosjoberg/Code/Go/pkg/mod/gorm.io/driver/[email protected]/postgres.go:274
[0.607ms] [rows:0] ROLLBACK TO SAVEPOINT sp17326545142615515993

2024/08/28 11:24:38 /Users/leosjoberg/Code/Go/pkg/mod/gorm.io/driver/[email protected]/postgres.go:274
[0.568ms] [rows:0] ROLLBACK TO SAVEPOINT sp11014777973198018981
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type:with reproduction steps with reproduction steps
Projects
None yet
Development

No branches or pull requests

4 participants
@jinzhu @phroggyy @a631807682 and others