From e1d43656672824d61332eeec7d529402dcc5e0bf Mon Sep 17 00:00:00 2001 From: Pierre-Louis Bonicoli Date: Fri, 22 Apr 2022 10:48:53 +0800 Subject: [PATCH] MySQL/MariaDB: return max length for text columns (#2133) MySQL/MariaDB: return max length for text columns using `CHARACTER_MAXIMUM_LENGTH`. Tests: * add an integration test: `TestGetColumnsLength` * update `TestSyncTable3` since `TableInfo` isn't able to provide the column size Co-authored-by: Pierre-Louis Bonicoli Co-authored-by: Lunny Xiao Reviewed-on: https://gitea.com/xorm/xorm/pulls/2133 Reviewed-by: Lunny Xiao Co-authored-by: Pierre-Louis Bonicoli Co-committed-by: Pierre-Louis Bonicoli --- dialects/mysql.go | 14 +++++++++--- integrations/engine_test.go | 33 +++++++++++++++++++++++++++++ integrations/session_schema_test.go | 5 ++++- 3 files changed, 48 insertions(+), 4 deletions(-) diff --git a/dialects/mysql.go b/dialects/mysql.go index 1fad3fee..56ba66c7 100644 --- a/dialects/mysql.go +++ b/dialects/mysql.go @@ -399,7 +399,7 @@ func (db *mysql) GetColumns(queryer core.Queryer, ctx context.Context, tableName "(SUBSTRING_INDEX(SUBSTRING(VERSION(), 4), '.', 1) = 2 && " + "SUBSTRING_INDEX(SUBSTRING(VERSION(), 6), '-', 1) >= 7)))))" s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," + - " `COLUMN_KEY`, `EXTRA`, `COLUMN_COMMENT`, " + + " `COLUMN_KEY`, `EXTRA`, `COLUMN_COMMENT`, `CHARACTER_MAXIMUM_LENGTH`, " + alreadyQuoted + " AS NEEDS_QUOTE " + "FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?" + " ORDER BY `COLUMNS`.ORDINAL_POSITION" @@ -418,8 +418,8 @@ func (db *mysql) GetColumns(queryer core.Queryer, ctx context.Context, tableName var columnName, nullableStr, colType, colKey, extra, comment string var alreadyQuoted, isUnsigned bool - var colDefault *string - err = rows.Scan(&columnName, &nullableStr, &colDefault, &colType, &colKey, &extra, &comment, &alreadyQuoted) + var colDefault, maxLength *string + err = rows.Scan(&columnName, &nullableStr, &colDefault, &colType, &colKey, &extra, &comment, &maxLength, &alreadyQuoted) if err != nil { return nil, nil, err } @@ -478,6 +478,14 @@ func (db *mysql) GetColumns(queryer core.Queryer, ctx context.Context, tableName } } } + } else { + switch colType { + case "MEDIUMTEXT", "LONGTEXT", "TEXT": + len1, err = strconv.Atoi(*maxLength) + if err != nil { + return nil, nil, err + } + } } if isUnsigned { colType = "UNSIGNED " + colType diff --git a/integrations/engine_test.go b/integrations/engine_test.go index 997c8962..905c4f24 100644 --- a/integrations/engine_test.go +++ b/integrations/engine_test.go @@ -288,3 +288,36 @@ func TestGetColumnsComment(t *testing.T) { assert.Equal(t, comment, hasComment) assert.Zero(t, noComment) } + +func TestGetColumnsLength(t *testing.T) { + var max_length int + switch testEngine.Dialect().URI().DBType { + case + schemas.POSTGRES: + max_length = 0 + case + schemas.MYSQL: + max_length = 65535 + default: + t.Skip() + return + } + + type TestLengthStringStruct struct { + Content string `xorm:"TEXT NOT NULL"` + } + + assertSync(t, new(TestLengthStringStruct)) + + tables, err := testEngine.DBMetas() + assert.NoError(t, err) + tableLengthStringName := testEngine.GetColumnMapper().Obj2Table("TestLengthStringStruct") + for _, table := range tables { + if table.Name == tableLengthStringName { + col := table.GetColumn("content") + assert.Equal(t, col.Length, max_length) + assert.Zero(t, col.Length2) + break + } + } +} diff --git a/integrations/session_schema_test.go b/integrations/session_schema_test.go index 7dc0af76..3212d027 100644 --- a/integrations/session_schema_test.go +++ b/integrations/session_schema_test.go @@ -6,6 +6,7 @@ package integrations import ( "fmt" + "strings" "testing" "time" @@ -248,7 +249,9 @@ func TestSyncTable3(t *testing.T) { tableInfo, err := testEngine.TableInfo(new(SyncTable5)) assert.NoError(t, err) assert.EqualValues(t, testEngine.Dialect().SQLType(tableInfo.GetColumn("name")), testEngine.Dialect().SQLType(tables[0].GetColumn("name"))) - assert.EqualValues(t, testEngine.Dialect().SQLType(tableInfo.GetColumn("text")), testEngine.Dialect().SQLType(tables[0].GetColumn("text"))) + /* Engine.DBMetas() returns the size of the column from the database but Engine.TableInfo() might not be able to guess the column size. + For example using MySQL/MariaDB: when utf-8 charset is used, "`xorm:"TEXT(21846)`" creates a MEDIUMTEXT column not a TEXT column. */ + assert.True(t, testEngine.Dialect().SQLType(tables[0].GetColumn("text")) == testEngine.Dialect().SQLType(tableInfo.GetColumn("text")) || strings.HasPrefix(testEngine.Dialect().SQLType(tables[0].GetColumn("text")), testEngine.Dialect().SQLType(tableInfo.GetColumn("text"))+"(")) assert.EqualValues(t, testEngine.Dialect().SQLType(tableInfo.GetColumn("char")), testEngine.Dialect().SQLType(tables[0].GetColumn("char"))) assert.EqualValues(t, testEngine.Dialect().SQLType(tableInfo.GetColumn("ten_char")), testEngine.Dialect().SQLType(tables[0].GetColumn("ten_char"))) assert.EqualValues(t, testEngine.Dialect().SQLType(tableInfo.GetColumn("ten_var_char")), testEngine.Dialect().SQLType(tables[0].GetColumn("ten_var_char")))