Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
rainie_yuyue
soar
提交
df9cfb4f
S
soar
项目概览
rainie_yuyue
/
soar
与 Fork 源项目一致
Fork自
Xiaomi / soar
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
S
soar
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
df9cfb4f
编写于
11月 11, 2020
作者:
martianzhang
浏览文件
操作
浏览文件
下载
差异文件
Merge branch 'dev' of github.com:XiaoMi/soar into dev
上级
3ed117ff
5c36e33c
变更
8
隐藏空白更改
内联
并排
Showing
8 changed file
with
83 addition
and
23 deletion
+83
-23
advisor/heuristic.go
advisor/heuristic.go
+35
-9
advisor/heuristic_test.go
advisor/heuristic_test.go
+7
-0
advisor/rules.go
advisor/rules.go
+4
-4
advisor/testdata/TestListHeuristicRules.golden
advisor/testdata/TestListHeuristicRules.golden
+2
-2
ast/testdata/TestSplitStatement.golden
ast/testdata/TestSplitStatement.golden
+1
-0
ast/token.go
ast/token.go
+2
-2
ast/token_test.go
ast/token_test.go
+2
-1
database/show.go
database/show.go
+30
-5
未找到文件。
advisor/heuristic.go
浏览文件 @
df9cfb4f
...
...
@@ -832,7 +832,7 @@ func (q *Query4Audit) RuleAddDefaultValue() Rule {
}
switch
c
.
Tp
.
Tp
{
case
mysql
.
TypeBlob
,
mysql
.
TypeTinyBlob
,
mysql
.
TypeMediumBlob
,
mysql
.
TypeLongBlob
:
case
mysql
.
TypeBlob
,
mysql
.
TypeTinyBlob
,
mysql
.
TypeMediumBlob
,
mysql
.
TypeLongBlob
,
mysql
.
TypeJSON
:
colDefault
=
true
}
...
...
@@ -855,7 +855,7 @@ func (q *Query4Audit) RuleAddDefaultValue() Rule {
}
switch
c
.
Tp
.
Tp
{
case
mysql
.
TypeBlob
,
mysql
.
TypeTinyBlob
,
mysql
.
TypeMediumBlob
,
mysql
.
TypeLongBlob
:
case
mysql
.
TypeBlob
,
mysql
.
TypeTinyBlob
,
mysql
.
TypeMediumBlob
,
mysql
.
TypeLongBlob
,
mysql
.
TypeJSON
:
colDefault
=
true
}
...
...
@@ -2729,8 +2729,14 @@ func (q *Query4Audit) RuleAlterCharset() Rule {
for
_
,
option
:=
range
spec
.
Options
{
if
option
.
Tp
==
tidb
.
TableOptionCharset
||
option
.
Tp
==
tidb
.
TableOptionCollate
{
rule
=
HeuristicRules
[
"ALT.001"
]
break
//增加CONVERT TO的判断
convertReg
,
_
:=
regexp
.
Compile
(
"convert to"
)
if
convertReg
.
Match
([]
byte
(
strings
.
ToLower
(
q
.
Query
)))
{
break
}
else
{
rule
=
HeuristicRules
[
"ALT.001"
]
break
}
}
}
}
...
...
@@ -2807,7 +2813,7 @@ func (q *Query4Audit) RuleBLOBNotNull() Rule {
continue
}
switch
col
.
Tp
.
Tp
{
case
mysql
.
TypeBlob
,
mysql
.
TypeTinyBlob
,
mysql
.
TypeMediumBlob
,
mysql
.
TypeLongBlob
:
case
mysql
.
TypeBlob
,
mysql
.
TypeTinyBlob
,
mysql
.
TypeMediumBlob
,
mysql
.
TypeLongBlob
,
mysql
.
TypeJSON
:
for
_
,
opt
:=
range
col
.
Options
{
if
opt
.
Tp
==
tidb
.
ColumnOptionNotNull
{
rule
=
HeuristicRules
[
"COL.012"
]
...
...
@@ -2830,7 +2836,7 @@ func (q *Query4Audit) RuleBLOBNotNull() Rule {
continue
}
switch
col
.
Tp
.
Tp
{
case
mysql
.
TypeBlob
,
mysql
.
TypeTinyBlob
,
mysql
.
TypeMediumBlob
,
mysql
.
TypeLongBlob
:
case
mysql
.
TypeBlob
,
mysql
.
TypeTinyBlob
,
mysql
.
TypeMediumBlob
,
mysql
.
TypeLongBlob
,
mysql
.
TypeJSON
:
for
_
,
opt
:=
range
col
.
Options
{
if
opt
.
Tp
==
tidb
.
ColumnOptionNotNull
{
rule
=
HeuristicRules
[
"COL.012"
]
...
...
@@ -3157,7 +3163,8 @@ func (q *Query4Audit) RuleColumnWithCharset() Rule {
for
_
,
tk
:=
range
tks
{
if
tk
.
Type
==
ast
.
TokenTypeWord
{
switch
strings
.
TrimSpace
(
strings
.
ToLower
(
tk
.
Val
))
{
case
"national"
,
"nvarchar"
,
"nchar"
,
"nvarchar("
,
"nchar("
,
"character"
:
//character移到后面检查
case
"national"
,
"nvarchar"
,
"nchar"
,
"nvarchar("
,
"nchar("
:
rule
=
HeuristicRules
[
"COL.014"
]
return
rule
}
...
...
@@ -3173,6 +3180,16 @@ func (q *Query4Audit) RuleColumnWithCharset() Rule {
continue
}
if
col
.
Tp
.
Charset
!=
""
||
col
.
Tp
.
Collate
!=
""
{
if
col
.
Tp
.
Charset
==
"binary"
||
col
.
Tp
.
Collate
==
"binary"
{
continue
}
else
{
rule
=
HeuristicRules
[
"COL.014"
]
break
}
}
//在这里检查character
characterReg
,
_
:=
regexp
.
Compile
(
"character set"
)
if
characterReg
.
Match
([]
byte
(
strings
.
ToLower
(
q
.
Query
)))
{
rule
=
HeuristicRules
[
"COL.014"
]
break
}
...
...
@@ -3187,6 +3204,15 @@ func (q *Query4Audit) RuleColumnWithCharset() Rule {
continue
}
if
col
.
Tp
.
Charset
!=
""
||
col
.
Tp
.
Collate
!=
""
{
if
col
.
Tp
.
Charset
==
"binary"
||
col
.
Tp
.
Collate
==
"binary"
{
continue
}
else
{
rule
=
HeuristicRules
[
"COL.014"
]
break
}
}
characterReg
,
_
:=
regexp
.
Compile
(
"character set"
)
if
characterReg
.
Match
([]
byte
(
strings
.
ToLower
(
q
.
Query
)))
{
rule
=
HeuristicRules
[
"COL.014"
]
break
}
...
...
@@ -3391,7 +3417,7 @@ func (q *Query4Audit) RuleBlobDefaultValue() Rule {
continue
}
switch
col
.
Tp
.
Tp
{
case
mysql
.
TypeBlob
,
mysql
.
TypeMediumBlob
,
mysql
.
TypeTinyBlob
,
mysql
.
TypeLongBlob
:
case
mysql
.
TypeBlob
,
mysql
.
TypeMediumBlob
,
mysql
.
TypeTinyBlob
,
mysql
.
TypeLongBlob
,
mysql
.
TypeJSON
:
for
_
,
opt
:=
range
col
.
Options
{
if
opt
.
Tp
==
tidb
.
ColumnOptionDefaultValue
&&
opt
.
Expr
.
GetType
()
.
Tp
!=
mysql
.
TypeNull
{
rule
=
HeuristicRules
[
"COL.015"
]
...
...
@@ -3410,7 +3436,7 @@ func (q *Query4Audit) RuleBlobDefaultValue() Rule {
continue
}
switch
col
.
Tp
.
Tp
{
case
mysql
.
TypeBlob
,
mysql
.
TypeMediumBlob
,
mysql
.
TypeTinyBlob
,
mysql
.
TypeLongBlob
:
case
mysql
.
TypeBlob
,
mysql
.
TypeMediumBlob
,
mysql
.
TypeTinyBlob
,
mysql
.
TypeLongBlob
,
mysql
.
TypeJSON
:
for
_
,
opt
:=
range
col
.
Options
{
if
opt
.
Tp
==
tidb
.
ColumnOptionDefaultValue
&&
opt
.
Expr
.
GetType
()
.
Tp
!=
mysql
.
TypeNull
{
rule
=
HeuristicRules
[
"COL.015"
]
...
...
advisor/heuristic_test.go
浏览文件 @
df9cfb4f
...
...
@@ -3265,17 +3265,24 @@ func TestRuleBlobDefaultValue(t *testing.T) {
sqls
:=
[][]
string
{
{
"CREATE TABLE `tb` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `c` blob NOT NULL DEFAULT '', PRIMARY KEY (`id`));"
,
"CREATE TABLE `tb` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `c` json NOT NULL DEFAULT '', PRIMARY KEY (`id`));"
,
"alter table `tb` add column `c` blob NOT NULL DEFAULT '';"
,
"alter table `tb` add column `c` json NOT NULL DEFAULT '';"
,
},
{
"CREATE TABLE `tb` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `c` blob NOT NULL, PRIMARY KEY (`id`));"
,
"CREATE TABLE `tb` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `c` json NOT NULL, PRIMARY KEY (`id`));"
,
"CREATE TABLE `tb` (`col` text NOT NULL);"
,
"alter table `tb` add column `c` blob NOT NULL;"
,
"alter table `tb` add column `c` json NOT NULL;"
,
"ALTER TABLE tb ADD COLUMN a BLOB DEFAULT NULL"
,
"ALTER TABLE tb ADD COLUMN a JSON DEFAULT NULL"
,
"CREATE TABLE tb ( a BLOB DEFAULT NULL)"
,
"CREATE TABLE tb ( a JSON DEFAULT NULL)"
,
"alter TABLE `tbl` add column `c` longblob;"
,
"alter TABLE `tbl` add column `c` text;"
,
"alter TABLE `tbl` add column `c` blob;"
,
"alter TABLE `tbl` add column `c` json;"
,
},
}
...
...
advisor/rules.go
浏览文件 @
df9cfb4f
...
...
@@ -523,8 +523,8 @@ func init() {
"COL.012"
:
{
Item
:
"COL.012"
,
Severity
:
"L5"
,
Summary
:
"
BLOB 和 TEXT
类型的字段不建议设置为 NOT NULL"
,
Content
:
`
BLOB 和 TEXT
类型的字段无法指定非 NULL 的默认值,如果添加了 NOT NULL 限制,写入数据时又未对该字段指定值可能导致写入失败。`
,
Summary
:
"
TEXT、BLOB 和 JSON
类型的字段不建议设置为 NOT NULL"
,
Content
:
`
TEXT、BLOB 和 JSON
类型的字段无法指定非 NULL 的默认值,如果添加了 NOT NULL 限制,写入数据时又未对该字段指定值可能导致写入失败。`
,
Case
:
"CREATE TABLE `tb`(`c` longblob NOT NULL);"
,
Func
:
(
*
Query4Audit
)
.
RuleBLOBNotNull
,
},
...
...
@@ -548,8 +548,8 @@ func init() {
"COL.015"
:
{
Item
:
"COL.015"
,
Severity
:
"L4"
,
Summary
:
"TEXT
和 BLOB
类型的字段不可指定非 NULL 的默认值"
,
Content
:
`MySQL 数据库中 TEXT
和 BLOB
类型的字段不可指定非 NULL 的默认值。TEXT最大长度为2^16-1个字符,MEDIUMTEXT最大长度为2^32-1个字符,LONGTEXT最大长度为2^64-1个字符。`
,
Summary
:
"TEXT
、BLOB 和 JSON
类型的字段不可指定非 NULL 的默认值"
,
Content
:
`MySQL 数据库中 TEXT
、BLOB 和 JSON
类型的字段不可指定非 NULL 的默认值。TEXT最大长度为2^16-1个字符,MEDIUMTEXT最大长度为2^32-1个字符,LONGTEXT最大长度为2^64-1个字符。`
,
Case
:
"CREATE TABLE `tbl` (`c` blob DEFAULT NULL);"
,
Func
:
(
*
Query4Audit
)
.
RuleBlobDefaultValue
,
},
...
...
advisor/testdata/TestListHeuristicRules.golden
浏览文件 @
df9cfb4f
...
...
@@ -476,7 +476,7 @@ select c1,c2,c3 from tbl where c4 is null or c4 <> 1
* **Item**:COL.012
* **Severity**:L5
* **Content**:
BLOB 和 TEXT
类型的字段无法指定非 NULL 的默认值,如果添加了 NOT NULL 限制,写入数据时又未对该字段指定值可能导致写入失败。
* **Content**:
TEXT、BLOB 和 JSON
类型的字段无法指定非 NULL 的默认值,如果添加了 NOT NULL 限制,写入数据时又未对该字段指定值可能导致写入失败。
* **Case**:
```sql
...
...
@@ -506,7 +506,7 @@ CREATE TABLE `tb2` ( `id` int(11) DEFAULT NULL, `col` char(10) CHARACTER SET utf
* **Item**:COL.015
* **Severity**:L4
* **Content**:MySQL 数据库中 TEXT
和 BLOB
类型的字段不可指定非 NULL 的默认值。TEXT最大长度为2^16-1个字符,MEDIUMTEXT最大长度为2^32-1个字符,LONGTEXT最大长度为2^64-1个字符。
* **Content**:MySQL 数据库中 TEXT
、BLOB 和 JSON
类型的字段不可指定非 NULL 的默认值。TEXT最大长度为2^16-1个字符,MEDIUMTEXT最大长度为2^32-1个字符,LONGTEXT最大长度为2^64-1个字符。
* **Case**:
```sql
...
...
ast/testdata/TestSplitStatement.golden
浏览文件 @
df9cfb4f
...
...
@@ -40,6 +40,7 @@ tb;
20 select /*!50000 1,*/ 1;
21 UPDATE xxx SET c1=' LOGGER.error(""); }' WHERE id = 2 ;
22 UPDATE `xxx` SET aaa='a;' WHERE `id` = 15;
23 UPDATE `xxx` SET aaa='a -- b' WHERE `id` = 15;
0 select * from test\G
1 select 'hello\Gworld', col from test\G
2 -- select * from test\Ghello
...
...
ast/token.go
浏览文件 @
df9cfb4f
...
...
@@ -862,12 +862,12 @@ func SplitStatement(buf []byte, delimiter []byte) (string, string, []byte) {
b
:=
buf
[
i
]
// single line comment
if
b
==
'-'
{
if
i
+
2
<
len
(
buf
)
&&
buf
[
i
+
1
]
==
'-'
&&
buf
[
i
+
2
]
==
' '
{
if
!
quoted
&&
i
+
2
<
len
(
buf
)
&&
buf
[
i
+
1
]
==
'-'
&&
buf
[
i
+
2
]
==
' '
{
singleLineComment
=
true
i
=
i
+
2
continue
}
if
i
+
2
<
len
(
buf
)
&&
i
==
0
&&
buf
[
i
+
1
]
==
'-'
&&
(
buf
[
i
+
2
]
==
'\n'
||
buf
[
i
+
2
]
==
'\r'
)
{
if
!
quoted
&&
i
+
2
<
len
(
buf
)
&&
i
==
0
&&
buf
[
i
+
1
]
==
'-'
&&
(
buf
[
i
+
2
]
==
'\n'
||
buf
[
i
+
2
]
==
'\r'
)
{
sql
=
"--
\n
"
break
}
...
...
ast/token_test.go
浏览文件 @
df9cfb4f
...
...
@@ -173,7 +173,8 @@ select col from tb;
[]
byte
(
`select /*!50000 1,*/ 1;`
),
// 20
[]
byte
(
`UPDATE xxx SET c1=' LOGGER.error(""); }' WHERE id = 2 ;`
),
// 21
[]
byte
(
"UPDATE `xxx` SET aaa='a;' WHERE `id` = 15;"
),
// 22
// []byte(`/* comment here */ SET MAX_JOIN_SIZE=#`), // 23
[]
byte
(
"UPDATE `xxx` SET aaa='a -- b' WHERE `id` = 15; UPDATE `xxx` SET aaa='c -- d' WHERE `id` = 16;"
),
// 23
// []byte(`/* comment here */ SET MAX_JOIN_SIZE=#`), // 24
}
// \G 分隔符
buf2s
:=
[][]
byte
{
...
...
database/show.go
浏览文件 @
df9cfb4f
...
...
@@ -70,6 +70,15 @@ type tableStatusRow struct {
Comment
[]
byte
// 注释
}
// 记录去除逗号类型是外健还是分区表
type
deleteComaType
int8
const
(
_
deleteComaType
=
iota
CS
PART
)
// newTableStat 构造 table Stat 对象
func
newTableStat
(
tableName
string
)
*
TableStatInfo
{
return
&
TableStatInfo
{
...
...
@@ -478,21 +487,37 @@ func (db *Connector) ShowCreateTable(tableName string) (string, error) {
if
len
(
lines
)
>
2
{
var
noConstraint
[]
string
relationReg
,
_
:=
regexp
.
Compile
(
"CONSTRAINT"
)
partitionReg
,
_
:=
regexp
.
Compile
(
"PARTITIONS"
)
var
DeleteComaT
deleteComaType
for
_
,
line
:=
range
lines
[
1
:
len
(
lines
)
-
1
]
{
if
relationReg
.
Match
([]
byte
(
line
))
{
DeleteComaT
=
CS
continue
}
else
if
partitionReg
.
Match
([]
byte
(
line
))
{
DeleteComaT
=
PART
}
line
=
strings
.
TrimSuffix
(
line
,
","
)
noConstraint
=
append
(
noConstraint
,
line
)
}
// 去除外键语句会使DDL中多一个','导致语法错误,要把多余的逗号去除
ddl
=
fmt
.
Sprint
(
lines
[
0
],
"
\n
"
,
strings
.
Join
(
noConstraint
,
",
\n
"
),
"
\n
"
,
lines
[
len
(
lines
)
-
1
],
)
// len(lines) > 2的判断方式有问题,如果是分区表也会判断成为外键语句,导致建表语句的逗号错乱
if
DeleteComaT
==
CS
{
ddl
=
fmt
.
Sprint
(
lines
[
0
],
"
\n
"
,
strings
.
Join
(
noConstraint
,
",
\n
"
),
"
\n
"
,
lines
[
len
(
lines
)
-
1
],
)
}
else
if
DeleteComaT
==
PART
{
ddl
=
fmt
.
Sprint
(
lines
[
0
],
"
\n
"
,
strings
.
Join
(
noConstraint
,
",
\n
"
),
"
\n
"
,
lines
[
len
(
lines
)
-
3
],
)
}
}
return
ddl
,
err
}
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录