From 50a0bc2e110b4200d01c4b3dee9e1929e9f71df6 Mon Sep 17 00:00:00 2001 From: Leon Zhang Date: Fri, 30 Aug 2019 12:00:13 +0800 Subject: [PATCH] support new heuristic rules check COL.014 support NVARCHAR COL.013 support zero time --- advisor/heuristic.go | 34 ++++++++++++++++++++++++++++++++-- advisor/heuristic_test.go | 5 +++++ advisor/rules.go | 4 ++-- doc/heuristic.md | 4 ++-- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/advisor/heuristic.go b/advisor/heuristic.go index 0bffd64..aee6fc9 100644 --- a/advisor/heuristic.go +++ b/advisor/heuristic.go @@ -27,9 +27,11 @@ import ( "github.com/XiaoMi/soar/ast" "github.com/XiaoMi/soar/common" "github.com/XiaoMi/soar/database" + "github.com/gedex/inflector" "github.com/percona/go-mysql/query" tidb "github.com/pingcap/parser/ast" + "github.com/pingcap/parser/format" "github.com/pingcap/parser/mysql" "github.com/tidwall/gjson" "vitess.io/vitess/go/vt/sqlparser" @@ -2870,11 +2872,20 @@ func (q *Query4Audit) RuleTimestampDefault() Rule { if col.Tp == nil { continue } - if col.Tp.Tp == mysql.TypeTimestamp { + switch col.Tp.Tp { + case mysql.TypeTimestamp, mysql.TypeDate, mysql.TypeDatetime, mysql.TypeNewDate: hasDefault := false + var sb strings.Builder + ctx := format.NewRestoreCtx(format.DefaultRestoreFlags, &sb) for _, option := range col.Options { if option.Tp == tidb.ColumnOptionDefaultValue { hasDefault = true + if err := option.Restore(ctx); err == nil { + if strings.HasPrefix(sb.String(), `DEFAULT '0`) || + strings.HasPrefix(sb.String(), `DEFAULT 0`) { + hasDefault = false + } + } } } if !hasDefault { @@ -2894,11 +2905,20 @@ func (q *Query4Audit) RuleTimestampDefault() Rule { if col.Tp == nil { continue } - if col.Tp.Tp == mysql.TypeTimestamp { + var sb strings.Builder + ctx := format.NewRestoreCtx(format.DefaultRestoreFlags, &sb) + switch col.Tp.Tp { + case mysql.TypeTimestamp, mysql.TypeDate, mysql.TypeDatetime, mysql.TypeNewDate: hasDefault := false for _, option := range col.Options { if option.Tp == tidb.ColumnOptionDefaultValue { hasDefault = true + if err := option.Restore(ctx); err == nil { + if strings.HasPrefix(sb.String(), `DEFAULT '0`) || + strings.HasPrefix(sb.String(), `DEFAULT 0`) { + hasDefault = false + } + } } } if !hasDefault { @@ -2938,6 +2958,16 @@ func (q *Query4Audit) RuleAutoIncrementInitNotZero() Rule { // RuleColumnWithCharset COL.014 func (q *Query4Audit) RuleColumnWithCharset() Rule { var rule = q.RuleOK() + tks := ast.Tokenize(q.Query) + for _, tk := range tks { + if tk.Type == ast.TokenTypeWord { + switch strings.TrimSpace(strings.ToLower(tk.Val)) { + case "national", "nvarchar", "nchar", "nvarchar(", "nchar(", "character": + rule = HeuristicRules["COL.014"] + return rule + } + } + } switch q.Stmt.(type) { case *sqlparser.DDL: for _, tiStmt := range q.TiStmt { diff --git a/advisor/heuristic_test.go b/advisor/heuristic_test.go index fe68747..66e2660 100644 --- a/advisor/heuristic_test.go +++ b/advisor/heuristic_test.go @@ -2769,6 +2769,9 @@ func TestRuleTimestampDefault(t *testing.T) { { "CREATE TABLE tbl( `id` bigint not null, `create_time` timestamp) ENGINE=InnoDB DEFAULT CHARSET=utf8;", "ALTER TABLE t1 MODIFY b timestamp NOT NULL;", + `ALTER TABLE t1 ADD c_time timestamp NOT NULL default "0000-00-00"`, + `ALTER TABLE t1 ADD c_time timestamp NOT NULL default 0`, + `ALTER TABLE t1 ADD c_time datetime NOT NULL default 0`, }, { "CREATE TABLE tbl (`id` bigint not null, `update_time` timestamp default current_timestamp)", @@ -2850,6 +2853,8 @@ func TestRuleColumnWithCharset(t *testing.T) { { "CREATE TABLE `tb2` ( `id` int(11) DEFAULT NULL, `col` char(10) CHARACTER SET utf8 DEFAULT NULL)", "alter table tb2 change col col char(10) CHARACTER SET utf8 DEFAULT NULL;", + "CREATE TABLE tb (a nvarchar(10))", + "CREATE TABLE tb (a nchar(10))", }, // 反面的例子 { diff --git a/advisor/rules.go b/advisor/rules.go index 245d8bb..192be66 100644 --- a/advisor/rules.go +++ b/advisor/rules.go @@ -523,8 +523,8 @@ func init() { "COL.013": { Item: "COL.013", Severity: "L4", - Summary: "TIMESTAMP 类型未设置默认值", - Content: `TIMESTAMP 类型未设置默认值`, + Summary: "TIMESTAMP 类型默认值检查异常", + Content: `TIMESTAMP 类型建议设置默认值,且不建议使用 0 或 0000-00-00 00:00:00 作为默认值。可以考虑使用 1970-08-02 01:01:01`, Case: "CREATE TABLE tbl( `id` bigint not null, `create_time` timestamp);", Func: (*Query4Audit).RuleTimestampDefault, }, diff --git a/doc/heuristic.md b/doc/heuristic.md index ae4dfce..574ef79 100644 --- a/doc/heuristic.md +++ b/doc/heuristic.md @@ -472,11 +472,11 @@ select c1,c2,c3 from tbl where c4 is null or c4 <> 1 ```sql CREATE TABLE `tb`(`c` longblob NOT NULL); ``` -## TIMESTAMP 类型未设置默认值 +## TIMESTAMP 类型默认值检查异常 * **Item**:COL.013 * **Severity**:L4 -* **Content**:TIMESTAMP 类型未设置默认值 +* **Content**:TIMESTAMP 类型建议设置默认值,且不建议使用 0 或 0000-00-00 00:00:00 作为默认值。可以考虑使用 1970-08-02 01:01:01 * **Case**: ```sql -- GitLab