Repository: go-gorm/gorm
Pull request #6484 (2023-07-27 09:21:05)

fix: rectify `SkipHooks` not working with `NewDB` set in Session method
<!--
Make sure these boxes checked before submitting your pull request.

For significant changes, please open an issue to make an agreement on an implementation design/plan first before starting it.
-->

- [x] Do only one thing
- [x] Non breaking API changes
- [x] Tested

### What did this pull request do?

When the `Session` method is invoked with `&gorm.Session{NewDB: true, SkipHooks: true}` object, it ignores the `SkipHooks`. This PR adds the `SkipHooks` in `getInstance` method.

### User Case Description

```go
// This will still call the associated hook currently. With this PR, hooks associated will not be called in this case.
db.Session(&gorm.Session{NewDB: true, SkipHooks: true}).First(&sampleObj)
```



Patch:
diff --git a/gorm.go b/gorm.go
index 9297850..203527a 100644
--- a/gorm.go
+++ b/gorm.go
@@ -399,11 +399,12 @@ func (db *DB) getInstance() *DB {
 		if db.clone == 1 {
 			// clone with new statement
 			tx.Statement = &Statement{
-				DB:       tx,
-				ConnPool: db.Statement.ConnPool,
-				Context:  db.Statement.Context,
-				Clauses:  map[string]clause.Clause{},
-				Vars:     make([]interface{}, 0, 8),
+				DB:        tx,
+				ConnPool:  db.Statement.ConnPool,
+				Context:   db.Statement.Context,
+				Clauses:   map[string]clause.Clause{},
+				Vars:      make([]interface{}, 0, 8),
+				SkipHooks: db.Statement.SkipHooks,
 			}
 		} else {
 			// with clone statement
diff --git a/logger/sql.go b/logger/sql.go
index bcacc7c..1521c1f 100644
--- a/logger/sql.go
+++ b/logger/sql.go
@@ -93,8 +93,10 @@ func ExplainSQL(sql string, numericPlaceholder *regexp.Regexp, escaper string, a
 			}
 		case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
 			vars[idx] = utils.ToString(v)
-		case float64, float32:
-			vars[idx] = fmt.Sprintf("%.6f", v)
+		case float32:
+			vars[idx] = strconv.FormatFloat(float64(v), 'f', -1, 32)
+		case float64:
+			vars[idx] = strconv.FormatFloat(v, 'f', -1, 64)
 		case string:
 			vars[idx] = escaper + strings.ReplaceAll(v, escaper, "\\"+escaper) + escaper
 		default:


Test patch:
diff --git a/logger/sql_test.go b/logger/sql_test.go
index c5b181a..e4a7274 100644
--- a/logger/sql_test.go
+++ b/logger/sql_test.go
@@ -57,44 +57,51 @@ func TestExplainSQL(t *testing.T) {
 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
 			NumericRegexp: nil,
 			Vars:          []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd},
-			Result:        `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass")`,
+			Result:        `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.99, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass")`,
 		},
 		{
 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
 			NumericRegexp: nil,
 			Vars:          []interface{}{"jinzhu?", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd},
-			Result:        `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu?", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass")`,
+			Result:        `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu?", 1, 999.99, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass")`,
 		},
 		{
 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values (@p1, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10, @p11)",
 			NumericRegexp: regexp.MustCompile(`@p(\d+)`),
 			Vars:          []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.com", myrole, pwd},
-			Result:        `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.com", "admin", "pass")`,
+			Result:        `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.99, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.com", "admin", "pass")`,
 		},
 		{
 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ($3, $4, $1, $2, $7, $8, $5, $6, $9, $10, $11)",
 			NumericRegexp: regexp.MustCompile(`\$(\d+)`),
 			Vars:          []interface{}{999.99, true, "jinzhu", 1, &tt, nil, []byte("12345"), tt, "w@g.com", myrole, pwd},
-			Result:        `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.com", "admin", "pass")`,
+			Result:        `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.99, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.com", "admin", "pass")`,
 		},
 		{
 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values (@p1, @p11, @p2, @p3, @p4, @p5, @p6, @p7, @p8, @p9, @p10)",
 			NumericRegexp: regexp.MustCompile(`@p(\d+)`),
 			Vars:          []interface{}{"jinzhu", 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.com", myrole, pwd, 1},
-			Result:        `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.com", "admin", "pass")`,
+			Result:        `create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass) values ("jinzhu", 1, 999.99, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.com", "admin", "pass")`,
 		},
 		{
 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
 			NumericRegexp: nil,
 			Vars:          []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd, js, es},
-			Result:        fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)),
+			Result:        fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.99, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)),
 		},
 		{
 			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
 			NumericRegexp: nil,
 			Vars:          []interface{}{"jinzhu", 1, 999.99, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd, &js, &es},
-			Result:        fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.990000, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)),
+			Result:        fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 999.99, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)),
 		},
+		{
+			SQL:           "create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
+			NumericRegexp: nil,
+			Vars:          []interface{}{"jinzhu", 1, 0.1753607109, true, []byte("12345"), tt, &tt, nil, "w@g.\"com", myrole, pwd, &js, &es},
+			Result:        fmt.Sprintf(`create table users (name, age, height, actived, bytes, create_at, update_at, deleted_at, email, role, pass, json_struct, example_struct) values ("jinzhu", 1, 0.1753607109, true, "12345", "2020-02-23 11:10:10", "2020-02-23 11:10:10", NULL, "w@g.\"com", "admin", "pass", %v, %v)`, format(jsVal, `"`), format(esVal, `"`)),
+		},
+
 	}
 
 	for idx, r := range results {
diff --git a/tests/helper_test.go b/tests/helper_test.go
index c34e357..1a4874e 100644
--- a/tests/helper_test.go
+++ b/tests/helper_test.go
@@ -265,6 +265,10 @@ func isTiDB() bool {
 	return os.Getenv("GORM_DIALECT") == "tidb"
 }
 
+func isMysql() bool {
+	return os.Getenv("GORM_DIALECT") == "mysql"
+}
+
 func db(unscoped bool) *gorm.DB {
 	if unscoped {
 		return DB.Unscoped()
diff --git a/tests/migrate_test.go b/tests/migrate_test.go
index 69f8641..849e2b7 100644
--- a/tests/migrate_test.go
+++ b/tests/migrate_test.go
@@ -1598,3 +1598,48 @@ func TestMigrateExistingBoolColumnPG(t *testing.T) {
 		}
 	}
 }
+
+func TestTableType(t *testing.T) {
+	// currently it is only supported for mysql driver
+	if !isMysql() {
+		return
+	}
+
+	const tblName = "cities"
+	const tblSchema = "gorm"
+	const tblType = "BASE TABLE"
+	const tblComment = "foobar comment"
+
+	type City struct {
+		gorm.Model
+		Name string `gorm:"unique"`
+	}
+
+	DB.Migrator().DropTable(&City{})
+
+	if err := DB.Set("gorm:table_options", fmt.Sprintf("ENGINE InnoDB COMMENT '%s'", tblComment)).AutoMigrate(&City{}); err != nil {
+		t.Fatalf("failed to migrate cities tables, got error: %v", err)
+	}
+
+	tableType, err := DB.Table("cities").Migrator().TableType(&City{})
+	if err != nil {
+		t.Fatalf("failed to get table type, got error %v", err)
+	}
+
+	if tableType.Schema() != tblSchema {
+		t.Fatalf("expected tblSchema to be %s but got %s", tblSchema, tableType.Schema())
+	}
+
+	if tableType.Name() != tblName {
+		t.Fatalf("expected table name to be %s but got %s", tblName, tableType.Name())
+	}
+
+	if tableType.Type() != tblType {
+		t.Fatalf("expected table type to be %s but got %s", tblType, tableType.Type())
+	}
+
+	comment, ok := tableType.Comment()
+	if !ok || comment != tblComment {
+		t.Fatalf("expected comment %s got %s", tblComment, comment)
+	}
+}