diff --git a/sqle/driver/mysql/audit_test.go b/sqle/driver/mysql/audit_test.go index 5f96772f0..1c4601343 100644 --- a/sqle/driver/mysql/audit_test.go +++ b/sqle/driver/mysql/audit_test.go @@ -2249,11 +2249,11 @@ ALTER TABLE exist_db.exist_tb_1 CHANGE COLUMN v2 v3 varchar(255) NOT NULL DEFAUL ) runSingleRuleInspectCase(rule, t, "alter_table: column without comment(1)", DefaultMysqlInspect(), -` + ` ALTER TABLE exist_db.exist_tb_1 MODIFY COLUMN v3 varchar(500) NOT NULL DEFAULT "modified unit test"; `, -newTestResult().addResult(rulepkg.DDLCheckColumnWithoutComment), -) + newTestResult().addResult(rulepkg.DDLCheckColumnWithoutComment), + ) } func TestCheckIndexPrefix(t *testing.T) { @@ -7225,7 +7225,7 @@ func TestMustUseLeftMostPrefix(t *testing.T) { { Name: "select-with-equal", Sql: `select * from exist_tb_9 where v2 = 1`, - TriggerRule: true, + TriggerRule: false, }, { Name: "select-with-equal", @@ -7250,7 +7250,7 @@ func TestMustUseLeftMostPrefix(t *testing.T) { { Name: "select-without-equal", Sql: `select * from exist_tb_9 where v2 in(1,2)`, - TriggerRule: true, + TriggerRule: false, }, { Name: "select-without-equal", @@ -7280,7 +7280,7 @@ func TestMustUseLeftMostPrefix(t *testing.T) { { Name: "join-with-equal", Sql: `select * from exist_tb_9 t9 join exist_tb_8 t8 on t9.id = t8.id where t9.v1 = 1 and t8.v2 > 1`, - TriggerRule: true, + TriggerRule: false, }, { Name: "join-with-equal", @@ -7296,7 +7296,7 @@ func TestMustUseLeftMostPrefix(t *testing.T) { { Name: "update-with-equal", Sql: `update exist_tb_9 set v4 = 1 where v2 = 1`, - TriggerRule: true, + TriggerRule: false, }, { Name: "update-with-equal", @@ -7326,7 +7326,7 @@ func TestMustUseLeftMostPrefix(t *testing.T) { { Name: "update-without-equal", Sql: `update exist_tb_9 set v4 = 1 where v2 in(1,2)`, - TriggerRule: true, + TriggerRule: false, }, { Name: "update-without-equal", @@ -7347,7 +7347,7 @@ func TestMustUseLeftMostPrefix(t *testing.T) { { Name: "delete-with-equal", Sql: `delete from exist_tb_9 where v2 = 1`, - TriggerRule: true, + TriggerRule: false, }, { Name: "delete-with-equal", @@ -7367,7 +7367,7 @@ func TestMustUseLeftMostPrefix(t *testing.T) { { Name: "delete-without-equal", Sql: `delete from exist_tb_9 where v2 > 1`, - TriggerRule: true, + TriggerRule: false, }, { Name: "delete-without-equal", @@ -7408,12 +7408,12 @@ func TestMustUseLeftMostPrefix(t *testing.T) { { Name: "select-union", Sql: `select * from exist_tb_9 where v1 = 1 and v2 = 1 union select * from exist_tb_8 where v2 = 1`, - TriggerRule: true, + TriggerRule: false, }, { Name: "select-union", Sql: `select * from exist_tb_9 where v2 = 1 union select * from exist_tb_8 where v2 = 1`, - TriggerRule: true, + TriggerRule: false, }, // select subquery { @@ -7441,6 +7441,21 @@ func TestMustUseLeftMostPrefix(t *testing.T) { Sql: `select * from exist_tb_9 where v3 > 100`, TriggerRule: false, }, + { + Name: "multiple index", + Sql: "select * from exist_db.exist_tb_11 where data_time2 = '12:00:00' and year_time = '2000'", + TriggerRule: false, + }, + { + Name: "incorrect use of composite index order", + Sql: "select * from exist_db.exist_tb_11 where upgrade_time = '2020-01-01 00:00:00' and create_time = '2020-01-01 00:00:00'", + TriggerRule: true, + }, + { + Name: "correct use of composite index order", + Sql: "select * from exist_db.exist_tb_11 where create_time = '2020-01-01 00:00:00' and upgrade_time = '2020-01-01 00:00:00'", + TriggerRule: false, + }, } rule := rulepkg.RuleHandlerMap[rulepkg.DMLMustUseLeftMostPrefix].Rule diff --git a/sqle/driver/mysql/rule/rule.go b/sqle/driver/mysql/rule/rule.go index 51f6751c7..d894dfe9c 100644 --- a/sqle/driver/mysql/rule/rule.go +++ b/sqle/driver/mysql/rule/rule.go @@ -5398,7 +5398,7 @@ func mustMatchLeftMostPrefix(input *RuleHandlerInput) error { addResult(input.Res, input.Rule, input.Rule.Name) } } else if input.Rule.Name == DMLMustUseLeftMostPrefix { - if !isColumnUseLeftMostPrefix(cols.AllCols, createTable.Constraints) { + if !isPassLeftmostPrefixCheck(cols.AllCols, createTable.Constraints) { addResult(input.Res, input.Rule, input.Rule.Name) } } @@ -5448,39 +5448,35 @@ func checkSingleIndex(allCols []string, constraint *ast.Constraint) bool { return false } -func isColumnUseLeftMostPrefix(allCols []string, constraints []*ast.Constraint) bool { - multiConstraints := make([]*ast.Constraint, 0) +func isPassLeftmostPrefixCheck(allCols []string, constraints []*ast.Constraint) bool { + if len(allCols) == 0 || len(constraints) == 0 { + return true + } + for _, constraint := range constraints { - if len(constraint.Keys) == 1 { - if checkSingleIndex(allCols, constraint) { - return true - } - continue + if len(constraint.Keys) == 1 && checkSingleIndex(allCols, constraint) { + return true + } + + if len(constraint.Keys) > 1 && constraint.Keys[0].Column.Name.L == allCols[0] { + return true } - multiConstraints = append(multiConstraints, constraint) } - walkConstraint := func(constraint *ast.Constraint) bool { - isCurrentIndexUsed := false - for i, key := range constraint.Keys { - for _, col := range allCols { - if col != key.Column.Name.L { - // 不是这个索引的字段,跳过 - continue - } - isCurrentIndexUsed = true - if i == 0 { - return true - } - } + + // where条件中的字段不在索引中,规则默认通过审核 + columnMap := make(map[string]struct{}) + for _, constraint := range constraints { + for _, key := range constraint.Keys { + columnMap[key.Column.Name.L] = struct{}{} } - return !isCurrentIndexUsed } - for _, constraint := range multiConstraints { - if !walkConstraint(constraint) { + for _, col := range allCols { + if _, ok := columnMap[col]; ok { return false } } + return true } diff --git a/sqle/driver/mysql/session/mock_context.go b/sqle/driver/mysql/session/mock_context.go index 3b2e715b4..23a2ba570 100644 --- a/sqle/driver/mysql/session/mock_context.go +++ b/sqle/driver/mysql/session/mock_context.go @@ -408,7 +408,10 @@ upgrade_time timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_T year_time year(4) NOT NULL DEFAULT '2020', data_time date NOT NULL DEFAULT '2020-01-01 00:00:00', data_time2 TIME NOT NULL DEFAULT '12:00:00', -PRIMARY KEY (id) USING BTREE +PRIMARY KEY (id) USING BTREE, +KEY idx_1 (data_time,data_time2), +KEY idx_2 (data_time2,year_time), +KEY idx_3 (create_time,upgrade_time) )ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT="unit test"; ` node, err := util.ParseOneSql(baseCreateQuery)