Repository: go-gorm/gorm
Pull request #4521 (2021-07-13 18:36:43)

Fix create index with comments in MySQL
<!--
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?

Fix create index with comments in MySQL.

https://dev.mysql.com/doc/refman/8.0/en/create-table.html
https://dev.mysql.com/doc/refman/8.0/en/create-index.html

<!--
provide a general description of the code changes in your pull request
-->

### User Case Description

https://gorm.io/docs/indexes.html#Index-Tag

<!-- Your use case -->



Patch:
diff --git a/clause/select.go b/clause/select.go
index b93b876..d8e9f80 100644
--- a/clause/select.go
+++ b/clause/select.go
@@ -43,3 +43,17 @@ func (s Select) MergeClause(clause *Clause) {
 		clause.Expression = s
 	}
 }
+
+// CommaExpression represents a group of expressions separated by commas.
+type CommaExpression struct {
+	Exprs []Expression
+}
+
+func (comma CommaExpression) Build(builder Builder) {
+	for idx, expr := range comma.Exprs {
+		if idx > 0 {
+			_, _ = builder.WriteString(", ")
+		}
+		expr.Build(builder)
+	}
+}
diff --git a/migrator/migrator.go b/migrator/migrator.go
index 03ffdd0..7c7405b 100644
--- a/migrator/migrator.go
+++ b/migrator/migrator.go
@@ -195,6 +195,10 @@ func (m Migrator) CreateTable(values ...interface{}) error {
 					}
 					createTableSQL += "INDEX ? ?"
 
+					if idx.Comment != "" {
+						createTableSQL += fmt.Sprintf(" COMMENT '%s'", idx.Comment)
+					}
+
 					if idx.Option != "" {
 						createTableSQL += " " + idx.Option
 					}
@@ -601,6 +605,10 @@ func (m Migrator) CreateIndex(value interface{}, name string) error {
 				createIndexSQL += " USING " + idx.Type
 			}
 
+			if idx.Comment != "" {
+				createIndexSQL += fmt.Sprintf(" COMMENT '%s'", idx.Comment)
+			}
+
 			if idx.Option != "" {
 				createIndexSQL += " " + idx.Option
 			}
diff --git a/prepare_stmt.go b/prepare_stmt.go
index 48a614b..5faea99 100644
--- a/prepare_stmt.go
+++ b/prepare_stmt.go
@@ -35,7 +35,7 @@ func (db *PreparedStmtDB) Close() {
 	for _, query := range db.PreparedSQL {
 		if stmt, ok := db.Stmts[query]; ok {
 			delete(db.Stmts, query)
-			stmt.Close()
+			go stmt.Close()
 		}
 	}
 
@@ -56,7 +56,7 @@ func (db *PreparedStmtDB) prepare(ctx context.Context, conn ConnPool, isTransact
 		db.Mux.Unlock()
 		return stmt, nil
 	} else if ok {
-		stmt.Close()
+		go stmt.Close()
 	}
 
 	stmt, err := conn.PrepareContext(ctx, query)
@@ -83,7 +83,7 @@ func (db *PreparedStmtDB) ExecContext(ctx context.Context, query string, args ..
 		result, err = stmt.ExecContext(ctx, args...)
 		if err != nil {
 			db.Mux.Lock()
-			stmt.Close()
+			go stmt.Close()
 			delete(db.Stmts, query)
 			db.Mux.Unlock()
 		}
@@ -97,7 +97,7 @@ func (db *PreparedStmtDB) QueryContext(ctx context.Context, query string, args .
 		rows, err = stmt.QueryContext(ctx, args...)
 		if err != nil {
 			db.Mux.Lock()
-			stmt.Close()
+			go stmt.Close()
 			delete(db.Stmts, query)
 			db.Mux.Unlock()
 		}
@@ -138,7 +138,7 @@ func (tx *PreparedStmtTX) ExecContext(ctx context.Context, query string, args ..
 		result, err = tx.Tx.StmtContext(ctx, stmt.Stmt).ExecContext(ctx, args...)
 		if err != nil {
 			tx.PreparedStmtDB.Mux.Lock()
-			stmt.Close()
+			go stmt.Close()
 			delete(tx.PreparedStmtDB.Stmts, query)
 			tx.PreparedStmtDB.Mux.Unlock()
 		}
@@ -152,7 +152,7 @@ func (tx *PreparedStmtTX) QueryContext(ctx context.Context, query string, args .
 		rows, err = tx.Tx.Stmt(stmt.Stmt).QueryContext(ctx, args...)
 		if err != nil {
 			tx.PreparedStmtDB.Mux.Lock()
-			stmt.Close()
+			go stmt.Close()
 			delete(tx.PreparedStmtDB.Stmts, query)
 			tx.PreparedStmtDB.Mux.Unlock()
 		}


Test patch:
diff --git a/clause/select_test.go b/clause/select_test.go
index b729643..9fce078 100644
--- a/clause/select_test.go
+++ b/clause/select_test.go
@@ -31,6 +31,18 @@ func TestSelect(t *testing.T) {
 			}, clause.From{}},
 			"SELECT `name` FROM `users`", nil,
 		},
+		{
+			[]clause.Interface{clause.Select{
+				Expression: clause.CommaExpression{
+					Exprs: []clause.Expression{
+						clause.NamedExpr{"?", []interface{}{clause.Column{Name: "id"}}},
+						clause.NamedExpr{"?", []interface{}{clause.Column{Name: "name"}}},
+						clause.NamedExpr{"LENGTH(?)", []interface{}{clause.Column{Name: "mobile"}}},
+					},
+				},
+			}, clause.From{}},
+			"SELECT `id`, `name`, LENGTH(`mobile`) FROM `users`", nil,
+		},
 	}
 
 	for idx, result := range results {
diff --git a/tests/migrate_test.go b/tests/migrate_test.go
index 4da3856..599ca85 100644
--- a/tests/migrate_test.go
+++ b/tests/migrate_test.go
@@ -142,17 +142,36 @@ func TestSmartMigrateColumn(t *testing.T) {
 
 }
 
-func TestMigrateWithComment(t *testing.T) {
-	type UserWithComment struct {
+func TestMigrateWithColumnComment(t *testing.T) {
+	type UserWithColumnComment struct {
 		gorm.Model
-		Name string `gorm:"size:111;index:,comment:这是一个index;comment:this is a 字段"`
+		Name string `gorm:"size:111;comment:this is a 字段"`
 	}
 
-	if err := DB.Migrator().DropTable(&UserWithComment{}); err != nil {
+	if err := DB.Migrator().DropTable(&UserWithColumnComment{}); err != nil {
 		t.Fatalf("Failed to drop table, got error %v", err)
 	}
 
-	if err := DB.AutoMigrate(&UserWithComment{}); err != nil {
+	if err := DB.AutoMigrate(&UserWithColumnComment{}); err != nil {
+		t.Fatalf("Failed to auto migrate, but got error %v", err)
+	}
+}
+
+func TestMigrateWithIndexComment(t *testing.T) {
+	if DB.Dialector.Name() != "mysql" {
+		t.Skip()
+	}
+
+	type UserWithIndexComment struct {
+		gorm.Model
+		Name string `gorm:"size:111;index:,comment:这是一个index"`
+	}
+
+	if err := DB.Migrator().DropTable(&UserWithIndexComment{}); err != nil {
+		t.Fatalf("Failed to drop table, got error %v", err)
+	}
+
+	if err := DB.AutoMigrate(&UserWithIndexComment{}); err != nil {
 		t.Fatalf("Failed to auto migrate, but got error %v", err)
 	}
 }