Skip to content

Commit c67969c

Browse files
authored
Merge pull request #3153 from actiontech/fix-rule-char-set
Fix rule char set
2 parents 4561731 + dbb088e commit c67969c

File tree

2 files changed

+105
-46
lines changed

2 files changed

+105
-46
lines changed

sqle/driver/mysql/rule/ai/rule_00075.go

Lines changed: 54 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package ai
22

33
import (
4+
"strings"
5+
46
rulepkg "github.com/actiontech/sqle/sqle/driver/mysql/rule"
57
util "github.com/actiontech/sqle/sqle/driver/mysql/rule/ai/util"
68
driverV2 "github.com/actiontech/sqle/sqle/driver/v2"
@@ -41,40 +43,79 @@ func init() {
4143

4244
/*
4345
==== Prompt start ====
44-
In MySQL, you should check if the SQL violate the rule(SQLE00075): "In table definition, setting column-level specified charset or collation is prohibited".
46+
In MySQL, you should check if the SQL violate the rule(SQLE00075): "Compare whether the character set of the specified table and columns in the statement are consistent".
4547
You should follow the following logic:
4648
47-
1. For "create table ..." statement, check every column, if it has no charset setting and no collation setting, otherwise, add the column name to violation-list
48-
2. For "alter table ... add column ..." statement, check the column, if it has no charset setting and no collation setting, otherwise, add the column name to violation-list
49-
3. For "alter table ... modify column ..." statement, check the modified column definition, if it has no charset setting and no collation setting, otherwise, add the column name to violation-list
50-
4. For "alter table ... change column ..." statement, check the new column's definition, if it has no charset setting and no collation setting, otherwise, add the column name to violation-list
49+
1. For "create table ..." statement, check if the table's charset is consistent with each column's charset. If a column has specified charset and it's different from table's charset, add the column name to violation-list
50+
2. For "alter table ... add column ..." statement, check if the table's charset is consistent with the new column's charset. If the column has specified charset and it's different from table's charset, add the column name to violation-list
51+
3. For "alter table ... modify column ..." statement, check if the table's charset is consistent with the modified column's charset. If the column has specified charset and it's different from table's charset, add the column name to violation-list
52+
4. For "alter table ... change column ..." statement, check if the table's charset is consistent with the new column's charset. If the column has specified charset and it's different from table's charset, add the column name to violation-list
5153
5. Generate a violation message as the checking result, including column names which violate the rule, if there is any violations
5254
==== Prompt end ====
5355
*/
5456

5557
// ==== Rule code start ====
5658
func RuleSQLE00075(input *rulepkg.RuleHandlerInput) error {
5759
violateColumns := []*ast.ColumnDef{}
60+
var tableCharset string
61+
var err error
62+
5863
switch stmt := input.Node.(type) {
5964
case *ast.CreateTableStmt:
60-
//"create table ..."
65+
// Get table charset from CREATE TABLE statement
66+
if charsetOption := util.GetTableOption(stmt.Options, ast.TableOptionCharset); charsetOption != nil {
67+
tableCharset = charsetOption.StrValue
68+
} else {
69+
// If no table charset specified, get from schema default
70+
tableCharset, err = input.Ctx.GetSchemaCharacter(stmt.Table, "")
71+
if err != nil {
72+
return err
73+
}
74+
}
75+
76+
// Check each column's charset against table charset
6177
for _, col := range stmt.Cols {
62-
//if the column has "CHARSET" or "COLLATE" specified, it is violate the rule
63-
if util.IsColumnHasSpecifiedCharset(col) || util.IsColumnHasOption(col, ast.ColumnOptionCollate) {
64-
violateColumns = append(violateColumns, col)
78+
if util.IsColumnHasSpecifiedCharset(col) {
79+
columnCharset := col.Tp.Charset
80+
if !strings.EqualFold(columnCharset, tableCharset) {
81+
violateColumns = append(violateColumns, col)
82+
}
6583
}
6684
}
85+
6786
case *ast.AlterTableStmt:
87+
// Get table charset from ALTER TABLE statement
88+
tableCharset, err = input.Ctx.GetSchemaCharacter(stmt.Table, "")
89+
if err != nil {
90+
return err
91+
}
92+
93+
// Check if table charset is being changed in this ALTER statement
94+
for _, spec := range stmt.Specs {
95+
// Use the last defined table character set
96+
if spec.Tp == ast.AlterTableOption {
97+
for _, option := range spec.Options {
98+
if option.Tp == ast.TableOptionCharset {
99+
tableCharset = option.StrValue
100+
break
101+
}
102+
}
103+
}
104+
}
105+
106+
// Check columns in ALTER TABLE commands
68107
for _, spec := range util.GetAlterTableCommandsByTypes(stmt, ast.AlterTableAddColumns, ast.AlterTableChangeColumn, ast.AlterTableModifyColumn) {
69-
// "alter table ... add column ..." or "alter table ... modify column ..." or "alter table ... change column ..."
70108
for _, col := range spec.NewColumns {
71-
//if the column has "CHARSET" or "COLLATE" specified, it is violate the rule
72-
if util.IsColumnHasSpecifiedCharset(col) || util.IsColumnHasOption(col, ast.ColumnOptionCollate) {
73-
violateColumns = append(violateColumns, col)
109+
if util.IsColumnHasSpecifiedCharset(col) {
110+
columnCharset := col.Tp.Charset
111+
if !strings.EqualFold(columnCharset, tableCharset) {
112+
violateColumns = append(violateColumns, col)
113+
}
74114
}
75115
}
76116
}
77117
}
118+
78119
if len(violateColumns) > 0 {
79120
rulepkg.AddResult(input.Res, input.Rule, SQLE00075, util.JoinColumnNames(violateColumns))
80121
}

sqle/driver/mysql/rule_00075_test.go

Lines changed: 51 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -12,76 +12,94 @@ func TestRuleSQLE00075(t *testing.T) {
1212
ruleName := ai.SQLE00075
1313
rule := rulepkg.AIRuleHandlerMap[ruleName].Rule
1414

15-
//create table, no charset, no collate
16-
runSingleRuleInspectCase(rule, t, "create table, no charset, no collate", DefaultMysqlInspect(), `
15+
//create table, no table charset, no column charset - should pass
16+
runSingleRuleInspectCase(rule, t, "create table, no table charset, no column charset", DefaultMysqlInspect(), `
1717
CREATE TABLE if not exists exist_db.not_exist_tb_1 (
1818
id bigint unsigned DEFAULT 100 AUTO_INCREMENT,
1919
a varchar(10),
2020
PRIMARY KEY (id)
2121
);
2222
`, newTestResult())
2323

24-
//create table, with charset, no collate
25-
runSingleRuleInspectCase(rule, t, "create table, with charset, no collate", DefaultMysqlInspect(), `
24+
//create table, with table charset utf8mb4, no column charset - should pass
25+
runSingleRuleInspectCase(rule, t, "create table, with table charset utf8mb4, no column charset", DefaultMysqlInspect(), `
26+
CREATE TABLE if not exists exist_db.not_exist_tb_1 (
27+
id bigint unsigned DEFAULT 100 AUTO_INCREMENT,
28+
a varchar(10),
29+
PRIMARY KEY (id)
30+
) CHARSET utf8mb4;
31+
`, newTestResult())
32+
33+
//create table, with table charset utf8mb4, column charset utf8mb4 - should pass
34+
runSingleRuleInspectCase(rule, t, "create table, with table charset utf8mb4, column charset utf8mb4", DefaultMysqlInspect(), `
2635
CREATE TABLE if not exists exist_db.not_exist_tb_1 (
2736
id bigint unsigned DEFAULT 100 AUTO_INCREMENT,
2837
a varchar(10) CHARSET utf8mb4,
2938
PRIMARY KEY (id)
30-
);
39+
) CHARSET utf8mb4;
40+
`, newTestResult())
41+
42+
//create table, with table charset utf8mb4, column charset utf8 - should fail
43+
runSingleRuleInspectCase(rule, t, "create table, with table charset utf8mb4, column charset utf8", DefaultMysqlInspect(), `
44+
CREATE TABLE if not exists exist_db.not_exist_tb_1 (
45+
id bigint unsigned DEFAULT 100 AUTO_INCREMENT,
46+
a varchar(10) CHARSET utf8,
47+
PRIMARY KEY (id)
48+
) CHARSET utf8mb4;
3149
`, newTestResult().addResult(ruleName, "a"))
3250

33-
//create table, with charset, with collate
34-
runSingleRuleInspectCase(rule, t, "create table, with charset, with collate", DefaultMysqlInspect(), `
51+
//create table, with table charset utf8, column charset utf8mb4 - should fail
52+
runSingleRuleInspectCase(rule, t, "create table, with table charset utf8, column charset utf8mb4", DefaultMysqlInspect(), `
3553
CREATE TABLE if not exists exist_db.not_exist_tb_1 (
3654
id bigint unsigned DEFAULT 100 AUTO_INCREMENT,
37-
a varchar(10) CHARSET utf8mb4 COLLATE utf8_general_ci,
55+
a varchar(10) CHARSET utf8mb4,
3856
PRIMARY KEY (id)
39-
);
57+
) CHARSET utf8;
4058
`, newTestResult().addResult(ruleName, "a"))
4159

42-
//alter table add column, no charset, no collate
43-
runSingleRuleInspectCase(rule, t, "alter table add column, no charset, no collate", DefaultMysqlInspect(), `
60+
//alter table add column, no table charset change, no column charset - should pass
61+
runSingleRuleInspectCase(rule, t, "alter table add column, no table charset change, no column charset", DefaultMysqlInspect(), `
4462
ALTER TABLE exist_db.exist_tb_1 ADD COLUMN a varchar(10) COMMENT "unit test";
4563
`, newTestResult())
4664

47-
//alter table add column, with charset, no collate
48-
runSingleRuleInspectCase(rule, t, "alter table add column, with charset, no collate", DefaultMysqlInspect(), `
65+
//alter table add column, no table charset change, column charset utf8mb4 - should pass (assuming table charset is utf8mb4)
66+
runSingleRuleInspectCase(rule, t, "alter table add column, no table charset change, column charset utf8mb4", DefaultMysqlInspect(), `
4967
ALTER TABLE exist_db.exist_tb_1 ADD COLUMN a varchar(10) CHARSET utf8mb4 COMMENT "unit test";
50-
`, newTestResult().addResult(ruleName, "a"))
68+
`, newTestResult())
5169

52-
//alter table add column, with charset, with collate
53-
runSingleRuleInspectCase(rule, t, "alter table add column, with charset, with collate", DefaultMysqlInspect(), `
54-
ALTER TABLE exist_db.exist_tb_1 ADD COLUMN a varchar(10) CHARSET utf8mb4 COLLATE utf8_general_ci COMMENT "unit test";
70+
//alter table add column, change table charset to utf8, column charset utf8mb4 - should fail
71+
runSingleRuleInspectCase(rule, t, "alter table add column, change table charset to utf8, column charset utf8mb4", DefaultMysqlInspect(), `
72+
ALTER TABLE exist_db.exist_tb_1 ADD COLUMN a varchar(10) CHARSET utf8mb4 COMMENT "unit test", CONVERT TO CHARACTER SET utf8;
5573
`, newTestResult().addResult(ruleName, "a"))
5674

57-
//alter table modify column, no charset, no collate
58-
runSingleRuleInspectCase(rule, t, "alter table modify column, no charset, no collate", DefaultMysqlInspect(), `
75+
//alter table modify column, no table charset change, no column charset - should pass
76+
runSingleRuleInspectCase(rule, t, "alter table modify column, no table charset change, no column charset", DefaultMysqlInspect(), `
5977
ALTER TABLE exist_db.exist_tb_1 MODIFY v1 varchar(10) COMMENT "unit test";
6078
`, newTestResult())
6179

62-
//alter table modify column, with charset, no collate
63-
runSingleRuleInspectCase(rule, t, "alter table modify column, with charset, no collate", DefaultMysqlInspect(), `
80+
//alter table modify column, no table charset change, column charset utf8mb4 - should pass (assuming table charset is utf8mb4)
81+
runSingleRuleInspectCase(rule, t, "alter table modify column, no table charset change, column charset utf8mb4", DefaultMysqlInspect(), `
6482
ALTER TABLE exist_db.exist_tb_1 MODIFY v1 varchar(10) CHARSET utf8mb4 COMMENT "unit test";
65-
`, newTestResult().addResult(ruleName, "v1"))
83+
`, newTestResult())
6684

67-
//alter table modify column, with charset, with collate
68-
runSingleRuleInspectCase(rule, t, "alter table modify column, with charset, with collate", DefaultMysqlInspect(), `
69-
ALTER TABLE exist_db.exist_tb_1 MODIFY v1 varchar(10) CHARSET utf8mb4 COLLATE utf8_general_ci COMMENT "unit test";
85+
//alter table modify column, change table charset to utf8, column charset utf8mb4 - should fail
86+
runSingleRuleInspectCase(rule, t, "alter table modify column, change table charset to utf8, column charset utf8mb4", DefaultMysqlInspect(), `
87+
ALTER TABLE exist_db.exist_tb_1 MODIFY v1 varchar(10) CHARSET utf8mb4 COMMENT "unit test", CONVERT TO CHARACTER SET utf8;
7088
`, newTestResult().addResult(ruleName, "v1"))
7189

72-
//alter table change column, no charset, no collate
73-
runSingleRuleInspectCase(rule, t, "alter table change column, no charset, no collate", DefaultMysqlInspect(), `
90+
//alter table change column, no table charset change, no column charset - should pass
91+
runSingleRuleInspectCase(rule, t, "alter table change column, no table charset change, no column charset", DefaultMysqlInspect(), `
7492
ALTER TABLE exist_db.exist_tb_1 CHANGE COLUMN v1 a varchar(10) COMMENT "unit test";
7593
`, newTestResult())
7694

77-
//alter table change column, with charset, no collate
78-
runSingleRuleInspectCase(rule, t, "alter table change column, with charset, no collate", DefaultMysqlInspect(), `
95+
//alter table change column, no table charset change, column charset utf8mb4 - should pass (assuming table charset is utf8mb4)
96+
runSingleRuleInspectCase(rule, t, "alter table change column, no table charset change, column charset utf8mb4", DefaultMysqlInspect(), `
7997
ALTER TABLE exist_db.exist_tb_1 CHANGE COLUMN v1 a varchar(10) CHARSET utf8mb4 COMMENT "unit test";
80-
`, newTestResult().addResult(ruleName, "a"))
98+
`, newTestResult())
8199

82-
//alter table change column, with charset, with collate
83-
runSingleRuleInspectCase(rule, t, "alter table change column, with charset, with collate", DefaultMysqlInspect(), `
84-
ALTER TABLE exist_db.exist_tb_1 CHANGE COLUMN v1 a varchar(10) CHARSET utf8mb4 COLLATE utf8_general_ci COMMENT "unit test";
100+
//alter table change column, change table charset to utf8, column charset utf8mb4 - should fail
101+
runSingleRuleInspectCase(rule, t, "alter table change column, change table charset to utf8, column charset utf8mb4", DefaultMysqlInspect(), `
102+
ALTER TABLE exist_db.exist_tb_1 CHANGE COLUMN v1 a varchar(10) CHARSET utf8mb4 COMMENT "unit test", CONVERT TO CHARACTER SET utf8;
85103
`, newTestResult().addResult(ruleName, "a"))
86104
}
87105

0 commit comments

Comments
 (0)