|
1 | 1 | package ai |
2 | 2 |
|
3 | 3 | import ( |
| 4 | + "strings" |
| 5 | + |
4 | 6 | rulepkg "github.com/actiontech/sqle/sqle/driver/mysql/rule" |
5 | 7 | util "github.com/actiontech/sqle/sqle/driver/mysql/rule/ai/util" |
6 | 8 | driverV2 "github.com/actiontech/sqle/sqle/driver/v2" |
@@ -41,40 +43,79 @@ func init() { |
41 | 43 |
|
42 | 44 | /* |
43 | 45 | ==== 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". |
45 | 47 | You should follow the following logic: |
46 | 48 |
|
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 |
51 | 53 | 5. Generate a violation message as the checking result, including column names which violate the rule, if there is any violations |
52 | 54 | ==== Prompt end ==== |
53 | 55 | */ |
54 | 56 |
|
55 | 57 | // ==== Rule code start ==== |
56 | 58 | func RuleSQLE00075(input *rulepkg.RuleHandlerInput) error { |
57 | 59 | violateColumns := []*ast.ColumnDef{} |
| 60 | + var tableCharset string |
| 61 | + var err error |
| 62 | + |
58 | 63 | switch stmt := input.Node.(type) { |
59 | 64 | 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 |
61 | 77 | 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 | + } |
65 | 83 | } |
66 | 84 | } |
| 85 | + |
67 | 86 | 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 |
68 | 107 | 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 ..." |
70 | 108 | 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 | + } |
74 | 114 | } |
75 | 115 | } |
76 | 116 | } |
77 | 117 | } |
| 118 | + |
78 | 119 | if len(violateColumns) > 0 { |
79 | 120 | rulepkg.AddResult(input.Res, input.Rule, SQLE00075, util.JoinColumnNames(violateColumns)) |
80 | 121 | } |
|
0 commit comments