Skip to content

Commit

Permalink
feat:rule supports matching multiple combined indexes
Browse files Browse the repository at this point in the history
  • Loading branch information
taolx0 committed Dec 13, 2024
1 parent 91a5029 commit b09fbef
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 38 deletions.
39 changes: 27 additions & 12 deletions sqle/driver/mysql/audit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand Down Expand Up @@ -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",
Expand All @@ -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",
Expand All @@ -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",
Expand Down Expand Up @@ -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
{
Expand Down Expand Up @@ -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
Expand Down
46 changes: 21 additions & 25 deletions sqle/driver/mysql/rule/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
Expand Down Expand Up @@ -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
}

Expand Down
5 changes: 4 additions & 1 deletion sqle/driver/mysql/session/mock_context.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit b09fbef

Please sign in to comment.