Compare commits

...

7 Commits

3 changed files with 97 additions and 1 deletions

View File

@ -8,13 +8,60 @@ package mysql
import (
"context"
"strings"
"github.com/gogf/gf/v2/database/gdb"
)
// DoFilter handles the sql before posts it to database.
// This method helps handle MySQL-specific issues including key length limitations.
//
// For MySQL tables using utf8mb4 charset, this method automatically adds ROW_FORMAT=DYNAMIC
// to CREATE TABLE statements to prevent "Specified key was too long; max key length is 1000 bytes" errors.
// This is particularly important for compatibility when upgrading from older GoFrame versions.
func (d *Driver) DoFilter(
ctx context.Context, link gdb.Link, sql string, args []any,
) (newSql string, newArgs []any, err error) {
return d.Core.DoFilter(ctx, link, sql, args)
newSql, newArgs, err = d.Core.DoFilter(ctx, link, sql, args)
if err != nil {
return newSql, newArgs, err
}
// Handle MySQL-specific SQL filtering to prevent key length issues
// This is particularly important for compatibility between GoFrame versions
newSql = d.handleMySQLKeyLengthCompatibility(newSql)
return newSql, newArgs, err
}
// handleMySQLKeyLengthCompatibility modifies SQL statements to be more compatible
// with MySQL key length limitations, especially for upgrade scenarios from older GoFrame versions
func (d *Driver) handleMySQLKeyLengthCompatibility(sql string) string {
// For CREATE TABLE statements with utf8mb4 charset, ensure key length compatibility
// This helps prevent "Specified key was too long; max key length is 1000 bytes" errors
sqlUpper := strings.ToUpper(sql)
sqlLower := strings.ToLower(sql)
if strings.Contains(sqlUpper, "CREATE TABLE") &&
(strings.Contains(sqlLower, "utf8mb4") || strings.Contains(sqlLower, "charset=utf8mb4")) {
// Add ROW_FORMAT=DYNAMIC to enable larger key prefixes when using utf8mb4
if !strings.Contains(sqlUpper, "ROW_FORMAT") {
// Insert ROW_FORMAT=DYNAMIC before ENGINE clause if it exists
if strings.Contains(sqlUpper, "ENGINE=") {
sql = strings.Replace(sql, "ENGINE=", "ROW_FORMAT=DYNAMIC ENGINE=", 1)
} else if strings.Contains(sqlUpper, "ENGINE ") {
// Handle case where there's a space after ENGINE
sql = strings.Replace(sql, "ENGINE ", "ROW_FORMAT=DYNAMIC ENGINE ", 1)
} else {
// Append ROW_FORMAT=DYNAMIC at the end of CREATE TABLE statement
sql = strings.TrimSuffix(strings.TrimSpace(sql), ";")
sql += " ROW_FORMAT=DYNAMIC"
if !strings.HasSuffix(sql, ";") {
sql += ";"
}
}
}
}
return sql
}

View File

@ -47,12 +47,14 @@ func configNodeToSource(config *gdb.ConfigNode) string {
"%s:%s@%s(%s%s)/%s?charset=%s",
config.User, config.Pass, config.Protocol, config.Host, portStr, config.Name, config.Charset,
)
if config.Timezone != "" {
if strings.Contains(config.Timezone, "/") {
config.Timezone = url.QueryEscape(config.Timezone)
}
source = fmt.Sprintf("%s&loc=%s", source, config.Timezone)
}
if config.Extra != "" {
source = fmt.Sprintf("%s&%s", source, config.Extra)
}

View File

@ -0,0 +1,47 @@
// Test case for MySQL key length issue #4382
package mysql_test
import (
"testing"
"github.com/gogf/gf/v2/test/gtest"
)
// Test_Issue4382_KeyLengthLimit tests the MySQL key length limitation issue
// This test reproduces the issue reported in #4382 where upgrading from GoFrame 2.6 to 2.9
// causes "Specified key was too long; max key length is 1000 bytes" error
func Test_Issue4382_KeyLengthLimit(t *testing.T) {
gtest.C(t, func(t *gtest.T) {
// This test should not fail due to key length limitations
// when using proper MySQL configuration
table := createTable("test_key_length")
defer dropTable(table)
// Try to create a table with potentially long keys (using utf8mb4)
// This scenario could trigger the key length issue
longTableSQL := `
CREATE TABLE test_long_keys (
id INT PRIMARY KEY AUTO_INCREMENT,
long_field_1 VARCHAR(255) CHARACTER SET utf8mb4,
long_field_2 VARCHAR(255) CHARACTER SET utf8mb4,
KEY idx_long_composite (long_field_1, long_field_2)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
`
_, err := db.Exec(ctx, "DROP TABLE IF EXISTS test_long_keys")
t.AssertNil(err)
// This should not fail with key length error in GoFrame 2.9
// Our DoFilter enhancement should automatically add ROW_FORMAT=DYNAMIC
_, err = db.Exec(ctx, longTableSQL)
if err != nil {
// If we get the specific key length error, this confirms the issue
// With our fix, this should not happen
t.Logf("Error creating table: %v", err)
}
t.AssertNil(err)
// Clean up
db.Exec(ctx, "DROP TABLE IF EXISTS test_long_keys")
})
}