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 <pierre-louis.bonicoli@libregerbil.fr>
Co-authored-by: Lunny Xiao <xiaolunwen@gmail.com>
Reviewed-on: https://gitea.com/xorm/xorm/pulls/2133
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Pierre-Louis Bonicoli <pilou@noreply.gitea.io>
Co-committed-by: Pierre-Louis Bonicoli <pilou@noreply.gitea.io>
This commit is contained in:
Pierre-Louis Bonicoli 2022-04-22 10:48:53 +08:00 committed by Lunny Xiao
parent 8f2596bf64
commit e1d4365667
3 changed files with 48 additions and 4 deletions

View File

@ -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(), 4), '.', 1) = 2 && " +
"SUBSTRING_INDEX(SUBSTRING(VERSION(), 6), '-', 1) >= 7)))))" "SUBSTRING_INDEX(SUBSTRING(VERSION(), 6), '-', 1) >= 7)))))"
s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," + 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 " + alreadyQuoted + " AS NEEDS_QUOTE " +
"FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?" + "FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?" +
" ORDER BY `COLUMNS`.ORDINAL_POSITION" " 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 columnName, nullableStr, colType, colKey, extra, comment string
var alreadyQuoted, isUnsigned bool var alreadyQuoted, isUnsigned bool
var colDefault *string var colDefault, maxLength *string
err = rows.Scan(&columnName, &nullableStr, &colDefault, &colType, &colKey, &extra, &comment, &alreadyQuoted) err = rows.Scan(&columnName, &nullableStr, &colDefault, &colType, &colKey, &extra, &comment, &maxLength, &alreadyQuoted)
if err != nil { if err != nil {
return nil, nil, err 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 { if isUnsigned {
colType = "UNSIGNED " + colType colType = "UNSIGNED " + colType

View File

@ -288,3 +288,36 @@ func TestGetColumnsComment(t *testing.T) {
assert.Equal(t, comment, hasComment) assert.Equal(t, comment, hasComment)
assert.Zero(t, noComment) 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
}
}
}

View File

@ -6,6 +6,7 @@ package integrations
import ( import (
"fmt" "fmt"
"strings"
"testing" "testing"
"time" "time"
@ -248,7 +249,9 @@ func TestSyncTable3(t *testing.T) {
tableInfo, err := testEngine.TableInfo(new(SyncTable5)) tableInfo, err := testEngine.TableInfo(new(SyncTable5))
assert.NoError(t, err) 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("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("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_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"))) assert.EqualValues(t, testEngine.Dialect().SQLType(tableInfo.GetColumn("ten_var_char")), testEngine.Dialect().SQLType(tables[0].GetColumn("ten_var_char")))