diff --git a/Makefile b/Makefile index dcd1e6f623075131bd4bf8fd217df76397828a2f..ad46c8df407758958b426ca25cb80645fd639742 100644 --- a/Makefile +++ b/Makefile @@ -143,24 +143,6 @@ heuristic: doc go test github.com/XiaoMi/soar/advisor -v -update -run TestMergeConflictHeuristicRules docker stop soar-mysql 2>/dev/null || true -# Update vitess vendor -.PHONY: vitess -vitess: - @echo "$(CGREEN)Update vitess deps ...$(CEND)" - govendor fetch -v vitess.io/vitess/... - -# Update tidb vendor -.PHONY: tidb -tidb: - @echo "$(CGREEN)Update tidb deps ...$(CEND)" - govendor fetch -v github.com/pingcap/tidb/... - -# make pingcap parser -.PHONY: pingcap-parser -pingcap-parser: tidb - @echo "$(CGREEN)Update pingcap parser deps ...$(CEND)" - govendor fetch -v github.com/pingcap/parser/... - # Update all vendor .PHONY: vendor vendor: vitess pingcap-parser diff --git a/ast/rewrite.go b/ast/rewrite.go index 779b20ed3a19115df37e6832eea94949fdeb9182..f1c49e7eb30d03e83d7c3477d44cc10ac0dea808 100644 --- a/ast/rewrite.go +++ b/ast/rewrite.go @@ -52,6 +52,13 @@ func init() { Suggest: "select * from film where length > 100", Func: (*Rewrite).RewriteDML2Select, }, + { + Name: "reg2select", + Description: "使用正则的方式将数据库更新请求转换为只读查询请求,便于执行EXPLAIN", + Original: "DELETE FROM film WHERE length > 100", + Suggest: "select * from film where length > 100", + Func: (*Rewrite).RewriteReg2Select, + }, { Name: "star2columns", Description: "为SELECT *补全表的列信息", @@ -1619,6 +1626,24 @@ func (rw *Rewrite) RewriteDML2Select() *Rewrite { return rw } +func (rw *Rewrite) RewriteReg2Select() *Rewrite { + var pre = 9 + if len(rw.SQL) < pre { + // SQL to short no need convert + return rw + } + if strings.HasPrefix(strings.ToLower(rw.SQL[:pre]), "select") { + rw.NewSQL = rw.SQL + } + if strings.HasPrefix(strings.ToLower(rw.SQL[:pre]), "update") { + rw.NewSQL = regUpdate2Select(rw.SQL) + } + if strings.HasPrefix(strings.ToLower(rw.SQL[:pre]), "delete") { + rw.NewSQL = regDelete2Select(rw.SQL) + } + return rw +} + // delete2Select 将 Delete 语句改写成 Select func delete2Select(stmt *sqlparser.Delete) string { newSQL := &sqlparser.Select{ @@ -1632,6 +1657,17 @@ func delete2Select(stmt *sqlparser.Delete) string { return sqlparser.String(newSQL) } +// regDelete2Select convert delete to select by regexp +func regDelete2Select(sql string) string { + sql = strings.TrimSpace(sql) + sqlRegexp := regexp.MustCompile(`^(?i)delete\s+from\s+(.*)$`) + params := sqlRegexp.FindStringSubmatch(sql) + if len(params) > 1 { + return fmt.Sprintf(`select * from %s`, params[1]) + } + return sql +} + // update2Select 将 Update 语句改写成 Select func update2Select(stmt *sqlparser.Update) string { newSQL := &sqlparser.Select{ @@ -1646,6 +1682,17 @@ func update2Select(stmt *sqlparser.Update) string { return sqlparser.String(newSQL) } +// regUpdate2Select convert update to select by regexp +func regUpdate2Select(sql string) string { + sql = strings.TrimSpace(sql) + sqlRegexp := regexp.MustCompile(`^(?i)update\s+(.*)\s+set\s+(.*)\s+(where\s+.*)$`) + params := sqlRegexp.FindStringSubmatch(sql) + if len(params) > 2 { + return fmt.Sprintf(`select * from %s %s`, params[1], params[3]) + } + return sql +} + // insert2Select 将 Insert 语句改写成 Select func insert2Select(stmt *sqlparser.Insert) string { switch row := stmt.Rows.(type) { diff --git a/ast/rewrite_test.go b/ast/rewrite_test.go index 0e742df0027cb88124d8235a018dc344233977ba..cf072fbc014fbb90001632ee23c28b8fdadcaba4 100644 --- a/ast/rewrite_test.go +++ b/ast/rewrite_test.go @@ -587,6 +587,31 @@ func TestRewriteDML2Select(t *testing.T) { common.Log.Debug("Exiting function: %s", common.GetFunctionName()) } +func TestRewriteReg2Select(t *testing.T) { + common.Log.Debug("Entering function: %s", common.GetFunctionName()) + testSQL := []map[string]string{ + { + "input": "select 1 from dual", + "output": "select 1 from dual", + }, + { + "input": "delete from dual", + "output": "select * from dual", + }, + { + "input": "update tb set col = 1 where col = 2", + "output": "select * from tb where col = 2", + }, + } + for _, sql := range testSQL { + rw := NewRewrite(sql["input"]).RewriteReg2Select() + if rw.NewSQL != sql["output"] { + t.Errorf("want: %s\ngot: %s", sql["output"], rw.NewSQL) + } + } + common.Log.Debug("Exiting function: %s", common.GetFunctionName()) +} + func TestRewriteDistinctStar(t *testing.T) { common.Log.Debug("Entering function: %s", common.GetFunctionName()) testSQL := []map[string]string{ diff --git a/ast/testdata/TestListRewriteRules.golden b/ast/testdata/TestListRewriteRules.golden index e855f915a27d209ce8bc72a9eabd143673607874..0ac7cdc808022220756919b51ef294ab5efc7eb9 100644 --- a/ast/testdata/TestListRewriteRules.golden +++ b/ast/testdata/TestListRewriteRules.golden @@ -13,6 +13,20 @@ DELETE FROM film WHERE length > 100 * **Suggest**: +```sql +select * from film where length > 100 +``` +## reg2select +* **Description**:使用正则的方式将数据库更新请求转换为只读查询请求,便于执行EXPLAIN + +* **Original**: + +```sql +DELETE FROM film WHERE length > 100 +``` + +* **Suggest**: + ```sql select * from film where length > 100 ``` @@ -277,6 +291,12 @@ use sakila; "Original": "DELETE FROM film WHERE length \u003e 100", "Suggest": "select * from film where length \u003e 100" }, + { + "Name": "reg2select", + "Description": "使用正则的方式将数据库更新请求转换为只读查询请求,便于执行EXPLAIN", + "Original": "DELETE FROM film WHERE length \u003e 100", + "Suggest": "select * from film where length \u003e 100" + }, { "Name": "star2columns", "Description": "为SELECT *补全表的列信息", diff --git a/deps.sh b/deps.sh index 21a3e948d8f2f3712dba3502e774ac97bd48a1b1..63035804a1464f04d26ca675fb2344f7df8a446f 100755 --- a/deps.sh +++ b/deps.sh @@ -1,6 +1,6 @@ #!/bin/bash -NEEDED_COMMANDS="docker git go govendor retool bats" +NEEDED_COMMANDS="docker git go retool bats" for cmd in ${NEEDED_COMMANDS} ; do if ! command -v "${cmd}" &> /dev/null ; then