Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 54 additions & 13 deletions sqle/driver/mysql/rule/ai/rule_00075.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package ai

import (
"strings"

rulepkg "github.com/actiontech/sqle/sqle/driver/mysql/rule"
util "github.com/actiontech/sqle/sqle/driver/mysql/rule/ai/util"
driverV2 "github.com/actiontech/sqle/sqle/driver/v2"
Expand Down Expand Up @@ -41,40 +43,79 @@ func init() {

/*
==== Prompt start ====
In MySQL, you should check if the SQL violate the rule(SQLE00075): "In table definition, setting column-level specified charset or collation is prohibited".
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".
You should follow the following logic:

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
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
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
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
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
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
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
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
5. Generate a violation message as the checking result, including column names which violate the rule, if there is any violations
==== Prompt end ====
*/

// ==== Rule code start ====
func RuleSQLE00075(input *rulepkg.RuleHandlerInput) error {
violateColumns := []*ast.ColumnDef{}
var tableCharset string
var err error

switch stmt := input.Node.(type) {
case *ast.CreateTableStmt:
//"create table ..."
// Get table charset from CREATE TABLE statement
if charsetOption := util.GetTableOption(stmt.Options, ast.TableOptionCharset); charsetOption != nil {
tableCharset = charsetOption.StrValue
} else {
// If no table charset specified, get from schema default
tableCharset, err = input.Ctx.GetSchemaCharacter(stmt.Table, "")
if err != nil {
return err
}
}

// Check each column's charset against table charset
for _, col := range stmt.Cols {
//if the column has "CHARSET" or "COLLATE" specified, it is violate the rule
if util.IsColumnHasSpecifiedCharset(col) || util.IsColumnHasOption(col, ast.ColumnOptionCollate) {
violateColumns = append(violateColumns, col)
if util.IsColumnHasSpecifiedCharset(col) {
columnCharset := col.Tp.Charset
if !strings.EqualFold(columnCharset, tableCharset) {
violateColumns = append(violateColumns, col)
}
}
}

case *ast.AlterTableStmt:
// Get table charset from ALTER TABLE statement
tableCharset, err = input.Ctx.GetSchemaCharacter(stmt.Table, "")
if err != nil {
return err
}

// Check if table charset is being changed in this ALTER statement
for _, spec := range stmt.Specs {
// Use the last defined table character set
if spec.Tp == ast.AlterTableOption {
for _, option := range spec.Options {
if option.Tp == ast.TableOptionCharset {
tableCharset = option.StrValue
break
}
}
}
}

// Check columns in ALTER TABLE commands
for _, spec := range util.GetAlterTableCommandsByTypes(stmt, ast.AlterTableAddColumns, ast.AlterTableChangeColumn, ast.AlterTableModifyColumn) {
// "alter table ... add column ..." or "alter table ... modify column ..." or "alter table ... change column ..."
for _, col := range spec.NewColumns {
//if the column has "CHARSET" or "COLLATE" specified, it is violate the rule
if util.IsColumnHasSpecifiedCharset(col) || util.IsColumnHasOption(col, ast.ColumnOptionCollate) {
violateColumns = append(violateColumns, col)
if util.IsColumnHasSpecifiedCharset(col) {
columnCharset := col.Tp.Charset
if !strings.EqualFold(columnCharset, tableCharset) {
violateColumns = append(violateColumns, col)
}
}
}
}
}

if len(violateColumns) > 0 {
rulepkg.AddResult(input.Res, input.Rule, SQLE00075, util.JoinColumnNames(violateColumns))
}
Expand Down
84 changes: 51 additions & 33 deletions sqle/driver/mysql/rule_00075_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,76 +12,94 @@ func TestRuleSQLE00075(t *testing.T) {
ruleName := ai.SQLE00075
rule := rulepkg.AIRuleHandlerMap[ruleName].Rule

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

//create table, with charset, no collate
runSingleRuleInspectCase(rule, t, "create table, with charset, no collate", DefaultMysqlInspect(), `
//create table, with table charset utf8mb4, no column charset - should pass
runSingleRuleInspectCase(rule, t, "create table, with table charset utf8mb4, no column charset", DefaultMysqlInspect(), `
CREATE TABLE if not exists exist_db.not_exist_tb_1 (
id bigint unsigned DEFAULT 100 AUTO_INCREMENT,
a varchar(10),
PRIMARY KEY (id)
) CHARSET utf8mb4;
`, newTestResult())

//create table, with table charset utf8mb4, column charset utf8mb4 - should pass
runSingleRuleInspectCase(rule, t, "create table, with table charset utf8mb4, column charset utf8mb4", DefaultMysqlInspect(), `
CREATE TABLE if not exists exist_db.not_exist_tb_1 (
id bigint unsigned DEFAULT 100 AUTO_INCREMENT,
a varchar(10) CHARSET utf8mb4,
PRIMARY KEY (id)
);
) CHARSET utf8mb4;
`, newTestResult())

//create table, with table charset utf8mb4, column charset utf8 - should fail
runSingleRuleInspectCase(rule, t, "create table, with table charset utf8mb4, column charset utf8", DefaultMysqlInspect(), `
CREATE TABLE if not exists exist_db.not_exist_tb_1 (
id bigint unsigned DEFAULT 100 AUTO_INCREMENT,
a varchar(10) CHARSET utf8,
PRIMARY KEY (id)
) CHARSET utf8mb4;
`, newTestResult().addResult(ruleName, "a"))

//create table, with charset, with collate
runSingleRuleInspectCase(rule, t, "create table, with charset, with collate", DefaultMysqlInspect(), `
//create table, with table charset utf8, column charset utf8mb4 - should fail
runSingleRuleInspectCase(rule, t, "create table, with table charset utf8, column charset utf8mb4", DefaultMysqlInspect(), `
CREATE TABLE if not exists exist_db.not_exist_tb_1 (
id bigint unsigned DEFAULT 100 AUTO_INCREMENT,
a varchar(10) CHARSET utf8mb4 COLLATE utf8_general_ci,
a varchar(10) CHARSET utf8mb4,
PRIMARY KEY (id)
);
) CHARSET utf8;
`, newTestResult().addResult(ruleName, "a"))

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

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

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

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

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

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

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

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

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

Expand Down
Loading