Skip to content

Commit

Permalink
sql/mysql: store mysql/mariadb charset/collate in internal package
Browse files Browse the repository at this point in the history
  • Loading branch information
a8m committed Jun 16, 2022
1 parent 6cfdae0 commit f49dc16
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 368 deletions.
372 changes: 36 additions & 336 deletions sql/mysql/diff.go

Large diffs are not rendered by default.

6 changes: 3 additions & 3 deletions sql/mysql/diff_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -307,18 +307,18 @@ func TestDiff_TableDiff(t *testing.T) {
var (
from = schema.NewTable("t1").
SetSchema(schema.New("public")).
SetCharset("utf8mb3").
SetCharset("utf8").
SetCollation("utf8_general_ci").
AddColumns(
schema.NewStringColumn("c1", "text").SetCharset("utf8mb3"),
schema.NewStringColumn("c1", "text").SetCharset("utf8"),
schema.NewStringColumn("c2", "text"),
)
to = schema.NewTable("t1").
SetSchema(schema.New("public")).
SetCollation("utf8_general_ci").
AddColumns(
schema.NewStringColumn("c1", "text"),
schema.NewStringColumn("c2", "text").SetCharset("utf8mb3"),
schema.NewStringColumn("c2", "text").SetCharset("utf8"),
)
)
return testcase{
Expand Down
93 changes: 64 additions & 29 deletions sql/mysql/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ package mysql

import (
"context"
"embed"
"encoding/json"
"fmt"
"net/url"
"strings"
Expand Down Expand Up @@ -61,14 +63,14 @@ func Open(db schema.ExecQuerier) (migrate.Driver, error) {
if c.tidb() {
return &Driver{
conn: c,
Differ: &sqlx.Diff{DiffDriver: &tdiff{diff{c}}},
Differ: &sqlx.Diff{DiffDriver: &tdiff{diff{conn: c}}},
Inspector: &tinspect{inspect{c}},
PlanApplier: &tplanApply{planApply{c}},
}, nil
}
return &Driver{
conn: c,
Differ: &sqlx.Diff{DiffDriver: &diff{c}},
Differ: &sqlx.Diff{DiffDriver: &diff{conn: c}},
Inspector: &inspect{c},
PlanApplier: &planApply{c},
}, nil
Expand Down Expand Up @@ -133,89 +135,107 @@ func acquire(ctx context.Context, conn schema.ExecQuerier, name string, timeout

// supportsCheck reports if the connected database supports
// the CHECK clause, and return the querying for getting them.
func (d *conn) supportsCheck() (string, bool) {
func (c *conn) supportsCheck() (string, bool) {
v, q := "8.0.16", myChecksQuery
if d.mariadb() {
if c.mariadb() {
v, q = "10.2.1", marChecksQuery
}
return q, d.gteV(v)
return q, c.gteV(v)
}

// supportsIndexExpr reports if the connected database supports
// index expressions (functional key part).
func (d *conn) supportsIndexExpr() bool {
return !d.mariadb() && d.gteV("8.0.13")
func (c *conn) supportsIndexExpr() bool {
return !c.mariadb() && c.gteV("8.0.13")
}

// supportsDisplayWidth reports if the connected database supports
// getting the display width information from the information schema.
func (d *conn) supportsDisplayWidth() bool {
func (c *conn) supportsDisplayWidth() bool {
// MySQL v8.0.19 dropped the display width
// information from the information schema
return d.mariadb() || d.ltV("8.0.19")
return c.mariadb() || c.ltV("8.0.19")
}

// supportsExprDefault reports if the connected database supports
// expressions in the DEFAULT clause on column definition.
func (d *conn) supportsExprDefault() bool {
func (c *conn) supportsExprDefault() bool {
v := "8.0.13"
if d.mariadb() {
if c.mariadb() {
v = "10.2.1"
}
return d.gteV(v)
return c.gteV(v)
}

// supportsEnforceCheck reports if the connected database supports
// the ENFORCED option in CHECK constraint syntax.
func (d *conn) supportsEnforceCheck() bool {
return !d.mariadb() && d.gteV("8.0.16")
func (c *conn) supportsEnforceCheck() bool {
return !c.mariadb() && c.gteV("8.0.16")
}

// supportsGeneratedColumns reports if the connected database
// supports the generated columns in information schema.
func (d *conn) supportsGeneratedColumns() bool {
func (c *conn) supportsGeneratedColumns() bool {
v := "5.7"
if d.mariadb() {
if c.mariadb() {
v = "10.2"
}
return d.gteV(v)
return c.gteV(v)
}

// supportsRenameColumn reports if the connected database
// supports the "RENAME COLUMN" clause.
func (d *conn) supportsRenameColumn() bool {
func (c *conn) supportsRenameColumn() bool {
v := "8"
if d.mariadb() {
if c.mariadb() {
v = "10.5.2"
}
return d.gteV(v)
return c.gteV(v)
}

// charsetToCollate returns the mapping from charset to its default collation.
func (c *conn) charsetToCollate() (map[string]string, error) {
name := "internal/charset2collate"
if c.mariadb() {
name += ".maria"
}
return decode(name)
}

// collateToCharset returns the mapping from a collation to its charset.
func (c *conn) collateToCharset() (map[string]string, error) {
name := "internal/collate2charset"
if c.mariadb() {
name += ".maria"
}
return decode(name)
}

// mariadb reports if the Driver is connected to a MariaDB database.
func (d *conn) mariadb() bool {
return strings.Index(d.version, "MariaDB") > 0
func (c *conn) mariadb() bool {
return strings.Index(c.version, "MariaDB") > 0
}

// tidb reports if the Driver is connected to a TiDB database.
func (d *conn) tidb() bool {
return strings.Index(d.version, "TiDB") > 0
func (c *conn) tidb() bool {
return strings.Index(c.version, "TiDB") > 0
}

// compareV returns an integer comparing two versions according to
// semantic version precedence.
func (d *conn) compareV(w string) int {
v := d.version
if d.mariadb() {
func (c *conn) compareV(w string) int {
v := c.version
if c.mariadb() {
v = v[:strings.Index(v, "MariaDB")-1]
}
return semver.Compare("v"+v, "v"+w)
}

// gteV reports if the connection version is >= w.
func (d *conn) gteV(w string) bool { return d.compareV(w) >= 0 }
func (c *conn) gteV(w string) bool { return c.compareV(w) >= 0 }

// ltV reports if the connection version is < w.
func (d *conn) ltV(w string) bool { return d.compareV(w) == -1 }
func (c *conn) ltV(w string) bool { return c.compareV(w) == -1 }

// unescape strings with backslashes returned
// for SQL expressions from information schema.
Expand Down Expand Up @@ -276,6 +296,21 @@ func dsn(u *url.URL) string {
return b.String()
}

//go:embed internal/*
var encoding embed.FS

func decode(name string) (map[string]string, error) {
f, err := encoding.Open(name)
if err != nil {
return nil, err
}
var m map[string]string
if err := json.NewDecoder(f).Decode(&m); err != nil {
return nil, fmt.Errorf("decode %q", name)
}
return m, nil
}

// MySQL standard column types as defined in its codebase. Name and order
// is organized differently than MySQL.
//
Expand Down
14 changes: 14 additions & 0 deletions sql/mysql/internal/.README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## Charset and Collation of MySQL and MariaDB latest versions

`collate2charset` and `collate2charset.maria` hold a mapping from the collation to their charset.

```sql
select json_objectagg(collation_name, character_set_name) from information_schema.collations\G;
```

`charset2collate` and `charset2collate.maria` hold a mapping from the charset to its default collation extracted
by the following query:

```sql
select json_objectagg(character_set_name, default_collate_name) from information_schema.character_sets\G;
```
1 change: 1 addition & 0 deletions sql/mysql/internal/charset2collate
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"gbk": "gbk_chinese_ci", "hp8": "hp8_english_ci", "big5": "big5_chinese_ci", "dec8": "dec8_swedish_ci", "sjis": "sjis_japanese_ci", "swe7": "swe7_swedish_ci", "ucs2": "ucs2_general_ci", "ujis": "ujis_japanese_ci", "utf8": "utf8_general_ci", "ascii": "ascii_general_ci", "cp850": "cp850_general_ci", "cp852": "cp852_general_ci", "cp866": "cp866_general_ci", "cp932": "cp932_japanese_ci", "euckr": "euckr_korean_ci", "greek": "greek_general_ci", "koi8r": "koi8r_general_ci", "koi8u": "koi8u_general_ci", "macce": "macce_general_ci", "utf16": "utf16_general_ci", "utf32": "utf32_general_ci", "binary": "binary", "cp1250": "cp1250_general_ci", "cp1251": "cp1251_general_ci", "cp1256": "cp1256_general_ci", "cp1257": "cp1257_general_ci", "gb2312": "gb2312_chinese_ci", "hebrew": "hebrew_general_ci", "latin1": "latin1_swedish_ci", "latin2": "latin2_general_ci", "latin5": "latin5_turkish_ci", "latin7": "latin7_general_ci", "tis620": "tis620_thai_ci", "eucjpms": "eucjpms_japanese_ci", "gb18030": "gb18030_chinese_ci", "geostd8": "geostd8_general_ci", "keybcs2": "keybcs2_general_ci", "utf16le": "utf16le_general_ci", "utf8mb4": "utf8mb4_0900_ai_ci", "armscii8": "armscii8_general_ci", "macroman": "macroman_general_ci"}
1 change: 1 addition & 0 deletions sql/mysql/internal/charset2collate.maria
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"big5":"big5_chinese_ci", "dec8":"dec8_swedish_ci", "cp850":"cp850_general_ci", "hp8":"hp8_english_ci", "koi8r":"koi8r_general_ci", "latin1":"latin1_swedish_ci", "latin2":"latin2_general_ci", "swe7":"swe7_swedish_ci", "ascii":"ascii_general_ci", "ujis":"ujis_japanese_ci", "sjis":"sjis_japanese_ci", "hebrew":"hebrew_general_ci", "tis620":"tis620_thai_ci", "euckr":"euckr_korean_ci", "koi8u":"koi8u_general_ci", "gb2312":"gb2312_chinese_ci", "greek":"greek_general_ci", "cp1250":"cp1250_general_ci", "gbk":"gbk_chinese_ci", "latin5":"latin5_turkish_ci", "armscii8":"armscii8_general_ci", "utf8mb3":"utf8mb3_general_ci", "ucs2":"ucs2_general_ci", "cp866":"cp866_general_ci", "keybcs2":"keybcs2_general_ci", "macce":"macce_general_ci", "macroman":"macroman_general_ci", "cp852":"cp852_general_ci", "latin7":"latin7_general_ci", "utf8mb4":"utf8mb4_general_ci", "cp1251":"cp1251_general_ci", "utf16":"utf16_general_ci", "utf16le":"utf16le_general_ci", "cp1256":"cp1256_general_ci", "cp1257":"cp1257_general_ci", "utf32":"utf32_general_ci", "binary":"binary", "geostd8":"geostd8_general_ci", "cp932":"cp932_japanese_ci", "eucjpms":"eucjpms_japanese_ci"}
1 change: 1 addition & 0 deletions sql/mysql/internal/collate2charset
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"binary": "binary", "gbk_bin": "gbk", "hp8_bin": "hp8", "big5_bin": "big5", "dec8_bin": "dec8", "sjis_bin": "sjis", "swe7_bin": "swe7", "ucs2_bin": "ucs2", "ujis_bin": "ujis", "utf8_bin": "utf8", "ascii_bin": "ascii", "cp850_bin": "cp850", "cp852_bin": "cp852", "cp866_bin": "cp866", "cp932_bin": "cp932", "euckr_bin": "euckr", "greek_bin": "greek", "koi8r_bin": "koi8r", "koi8u_bin": "koi8u", "macce_bin": "macce", "utf16_bin": "utf16", "utf32_bin": "utf32", "cp1250_bin": "cp1250", "cp1251_bin": "cp1251", "cp1256_bin": "cp1256", "cp1257_bin": "cp1257", "gb2312_bin": "gb2312", "hebrew_bin": "hebrew", "latin1_bin": "latin1", "latin2_bin": "latin2", "latin5_bin": "latin5", "latin7_bin": "latin7", "tis620_bin": "tis620", "eucjpms_bin": "eucjpms", "gb18030_bin": "gb18030", "geostd8_bin": "geostd8", "keybcs2_bin": "keybcs2", "utf16le_bin": "utf16le", "utf8mb4_bin": "utf8mb4", "armscii8_bin": "armscii8", "macroman_bin": "macroman", "ucs2_czech_ci": "ucs2", "ucs2_roman_ci": "ucs2", "utf8_czech_ci": "utf8", "utf8_roman_ci": "utf8", "gbk_chinese_ci": "gbk", "hp8_english_ci": "hp8", "tis620_thai_ci": "tis620", "ucs2_danish_ci": "ucs2", "ucs2_polish_ci": "ucs2", "ucs2_slovak_ci": "ucs2", "utf16_czech_ci": "utf16", "utf16_roman_ci": "utf16", "utf32_czech_ci": "utf32", "utf32_roman_ci": "utf32", "utf8_danish_ci": "utf8", "utf8_polish_ci": "utf8", "utf8_slovak_ci": "utf8", "big5_chinese_ci": "big5", "cp1250_czech_cs": "cp1250", "dec8_swedish_ci": "dec8", "euckr_korean_ci": "euckr", "latin2_czech_cs": "latin2", "swe7_swedish_ci": "swe7", "ucs2_general_ci": "ucs2", "ucs2_german2_ci": "ucs2", "ucs2_latvian_ci": "ucs2", "ucs2_persian_ci": "ucs2", "ucs2_sinhala_ci": "ucs2", "ucs2_spanish_ci": "ucs2", "ucs2_swedish_ci": "ucs2", "ucs2_turkish_ci": "ucs2", "ucs2_unicode_ci": "ucs2", "utf16_danish_ci": "utf16", "utf16_polish_ci": "utf16", "utf16_slovak_ci": "utf16", "utf32_danish_ci": "utf32", "utf32_polish_ci": "utf32", "utf32_slovak_ci": "utf32", "utf8_general_ci": "utf8", "utf8_german2_ci": "utf8", "utf8_latvian_ci": "utf8", "utf8_persian_ci": "utf8", "utf8_sinhala_ci": "utf8", "utf8_spanish_ci": "utf8", "utf8_swedish_ci": "utf8", "utf8_tolower_ci": "utf8", "utf8_turkish_ci": "utf8", "utf8_unicode_ci": "utf8", "ascii_general_ci": "ascii", "cp1250_polish_ci": "cp1250", "cp850_general_ci": "cp850", "cp852_general_ci": "cp852", "cp866_general_ci": "cp866", "greek_general_ci": "greek", "koi8r_general_ci": "koi8r", "koi8u_general_ci": "koi8u", "latin1_danish_ci": "latin1", "macce_general_ci": "macce", "sjis_japanese_ci": "sjis", "ucs2_croatian_ci": "ucs2", "ucs2_estonian_ci": "ucs2", "ucs2_romanian_ci": "ucs2", "ucs2_spanish2_ci": "ucs2", "ujis_japanese_ci": "ujis", "utf16_general_ci": "utf16", "utf16_german2_ci": "utf16", "utf16_latvian_ci": "utf16", "utf16_persian_ci": "utf16", "utf16_sinhala_ci": "utf16", "utf16_spanish_ci": "utf16", "utf16_swedish_ci": "utf16", "utf16_turkish_ci": "utf16", "utf16_unicode_ci": "utf16", "utf32_general_ci": "utf32", "utf32_german2_ci": "utf32", "utf32_latvian_ci": "utf32", "utf32_persian_ci": "utf32", "utf32_sinhala_ci": "utf32", "utf32_spanish_ci": "utf32", "utf32_swedish_ci": "utf32", "utf32_turkish_ci": "utf32", "utf32_unicode_ci": "utf32", "utf8_croatian_ci": "utf8", "utf8_estonian_ci": "utf8", "utf8_romanian_ci": "utf8", "utf8_spanish2_ci": "utf8", "utf8mb4_0900_bin": "utf8mb4", "utf8mb4_czech_ci": "utf8mb4", "utf8mb4_roman_ci": "utf8mb4", "cp1250_general_ci": "cp1250", "cp1251_general_ci": "cp1251", "cp1251_general_cs": "cp1251", "cp1256_general_ci": "cp1256", "cp1257_general_ci": "cp1257", "cp932_japanese_ci": "cp932", "gb2312_chinese_ci": "gb2312", "hebrew_general_ci": "hebrew", "latin1_general_ci": "latin1", "latin1_general_cs": "latin1", "latin1_german1_ci": "latin1", "latin1_german2_ci": "latin1", "latin1_spanish_ci": "latin1", "latin1_swedish_ci": "latin1", "latin2_general_ci": "latin2", "latin5_turkish_ci": "latin5", "latin7_general_ci": "latin7", "latin7_general_cs": "latin7", "ucs2_esperanto_ci": "ucs2", "ucs2_hungarian_ci": "ucs2", "ucs2_icelandic_ci": "ucs2", "ucs2_slovenian_ci": "ucs2", "utf16_croatian_ci": "utf16", "utf16_estonian_ci": "utf16", "utf16_romanian_ci": "utf16", "utf16_spanish2_ci": "utf16", "utf32_croatian_ci": "utf32", "utf32_estonian_ci": "utf32", "utf32_romanian_ci": "utf32", "utf32_spanish2_ci": "utf32", "utf8_esperanto_ci": "utf8", "utf8_hungarian_ci": "utf8", "utf8_icelandic_ci": "utf8", "utf8_slovenian_ci": "utf8", "utf8mb4_danish_ci": "utf8mb4", "utf8mb4_polish_ci": "utf8mb4", "utf8mb4_slovak_ci": "utf8mb4", "cp1250_croatian_ci": "cp1250", "gb18030_chinese_ci": "gb18030", "geostd8_general_ci": "geostd8", "keybcs2_general_ci": "keybcs2", "latin2_croatian_ci": "latin2", "latin7_estonian_cs": "latin7", "ucs2_lithuanian_ci": "ucs2", "ucs2_vietnamese_ci": "ucs2", "utf16_esperanto_ci": "utf16", "utf16_hungarian_ci": "utf16", "utf16_icelandic_ci": "utf16", "utf16_slovenian_ci": "utf16", "utf16le_general_ci": "utf16le", "utf32_esperanto_ci": "utf32", "utf32_hungarian_ci": "utf32", "utf32_icelandic_ci": "utf32", "utf32_slovenian_ci": "utf32", "utf8_lithuanian_ci": "utf8", "utf8_vietnamese_ci": "utf8", "utf8mb4_0900_ai_ci": "utf8mb4", "utf8mb4_0900_as_ci": "utf8mb4", "utf8mb4_0900_as_cs": "utf8mb4", "utf8mb4_general_ci": "utf8mb4", "utf8mb4_german2_ci": "utf8mb4", "utf8mb4_latvian_ci": "utf8mb4", "utf8mb4_persian_ci": "utf8mb4", "utf8mb4_sinhala_ci": "utf8mb4", "utf8mb4_spanish_ci": "utf8mb4", "utf8mb4_swedish_ci": "utf8mb4", "utf8mb4_turkish_ci": "utf8mb4", "utf8mb4_unicode_ci": "utf8mb4", "armscii8_general_ci": "armscii8", "cp1251_bulgarian_ci": "cp1251", "cp1251_ukrainian_ci": "cp1251", "eucjpms_japanese_ci": "eucjpms", "latin2_hungarian_ci": "latin2", "macroman_general_ci": "macroman", "ucs2_unicode_520_ci": "ucs2", "utf16_lithuanian_ci": "utf16", "utf16_vietnamese_ci": "utf16", "utf32_lithuanian_ci": "utf32", "utf32_vietnamese_ci": "utf32", "utf8_unicode_520_ci": "utf8", "utf8mb4_croatian_ci": "utf8mb4", "utf8mb4_estonian_ci": "utf8mb4", "utf8mb4_romanian_ci": "utf8mb4", "utf8mb4_spanish2_ci": "utf8mb4", "cp1257_lithuanian_ci": "cp1257", "utf16_unicode_520_ci": "utf16", "utf32_unicode_520_ci": "utf32", "utf8mb4_esperanto_ci": "utf8mb4", "utf8mb4_hungarian_ci": "utf8mb4", "utf8mb4_icelandic_ci": "utf8mb4", "utf8mb4_slovenian_ci": "utf8mb4", "utf8mb4_cs_0900_ai_ci": "utf8mb4", "utf8mb4_cs_0900_as_cs": "utf8mb4", "utf8mb4_da_0900_ai_ci": "utf8mb4", "utf8mb4_da_0900_as_cs": "utf8mb4", "utf8mb4_eo_0900_ai_ci": "utf8mb4", "utf8mb4_eo_0900_as_cs": "utf8mb4", "utf8mb4_es_0900_ai_ci": "utf8mb4", "utf8mb4_es_0900_as_cs": "utf8mb4", "utf8mb4_et_0900_ai_ci": "utf8mb4", "utf8mb4_et_0900_as_cs": "utf8mb4", "utf8mb4_hr_0900_ai_ci": "utf8mb4", "utf8mb4_hr_0900_as_cs": "utf8mb4", "utf8mb4_hu_0900_ai_ci": "utf8mb4", "utf8mb4_hu_0900_as_cs": "utf8mb4", "utf8mb4_is_0900_ai_ci": "utf8mb4", "utf8mb4_is_0900_as_cs": "utf8mb4", "utf8mb4_ja_0900_as_cs": "utf8mb4", "utf8mb4_la_0900_ai_ci": "utf8mb4", "utf8mb4_la_0900_as_cs": "utf8mb4", "utf8mb4_lithuanian_ci": "utf8mb4", "utf8mb4_lt_0900_ai_ci": "utf8mb4", "utf8mb4_lt_0900_as_cs": "utf8mb4", "utf8mb4_lv_0900_ai_ci": "utf8mb4", "utf8mb4_lv_0900_as_cs": "utf8mb4", "utf8mb4_pl_0900_ai_ci": "utf8mb4", "utf8mb4_pl_0900_as_cs": "utf8mb4", "utf8mb4_ro_0900_ai_ci": "utf8mb4", "utf8mb4_ro_0900_as_cs": "utf8mb4", "utf8mb4_ru_0900_ai_ci": "utf8mb4", "utf8mb4_ru_0900_as_cs": "utf8mb4", "utf8mb4_sk_0900_ai_ci": "utf8mb4", "utf8mb4_sk_0900_as_cs": "utf8mb4", "utf8mb4_sl_0900_ai_ci": "utf8mb4", "utf8mb4_sl_0900_as_cs": "utf8mb4", "utf8mb4_sv_0900_ai_ci": "utf8mb4", "utf8mb4_sv_0900_as_cs": "utf8mb4", "utf8mb4_tr_0900_ai_ci": "utf8mb4", "utf8mb4_tr_0900_as_cs": "utf8mb4", "utf8mb4_vi_0900_ai_ci": "utf8mb4", "utf8mb4_vi_0900_as_cs": "utf8mb4", "utf8mb4_vietnamese_ci": "utf8mb4", "utf8mb4_zh_0900_as_cs": "utf8mb4", "gb18030_unicode_520_ci": "gb18030", "utf8mb4_unicode_520_ci": "utf8mb4", "ucs2_general_mysql500_ci": "ucs2", "utf8_general_mysql500_ci": "utf8", "utf8mb4_de_pb_0900_ai_ci": "utf8mb4", "utf8mb4_de_pb_0900_as_cs": "utf8mb4", "utf8mb4_ja_0900_as_cs_ks": "utf8mb4", "utf8mb4_es_trad_0900_ai_ci": "utf8mb4", "utf8mb4_es_trad_0900_as_cs": "utf8mb4"}
Loading

0 comments on commit f49dc16

Please sign in to comment.