Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Xiaomi
soar
提交
c9ee5b48
S
soar
项目概览
Xiaomi
/
soar
大约 1 年 前同步成功
通知
387
Star
8512
Fork
1328
代码
文件
提交
分支
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,发现更多精彩内容 >>
提交
c9ee5b48
编写于
11月 20, 2018
作者:
L
liipx
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
add reportTool, fix chardet
上级
9d7ec0f3
变更
3
隐藏空白更改
内联
并排
Showing
3 changed file
with
95 addition
and
78 deletion
+95
-78
cmd/soar/soar.go
cmd/soar/soar.go
+13
-69
cmd/soar/tool.go
cmd/soar/tool.go
+81
-8
common/chardet.go
common/chardet.go
+1
-1
未找到文件。
cmd/soar/soar.go
浏览文件 @
c9ee5b48
...
@@ -19,7 +19,6 @@ package main
...
@@ -19,7 +19,6 @@ package main
import
(
import
(
"encoding/json"
"encoding/json"
"fmt"
"fmt"
"io/ioutil"
"os"
"os"
"strings"
"strings"
...
@@ -41,7 +40,7 @@ func main() {
...
@@ -41,7 +40,7 @@ func main() {
var
sql
string
// 单条评审指定的 sql 或 explain
var
sql
string
// 单条评审指定的 sql 或 explain
sqlCounter
:=
1
// SQL 计数器
sqlCounter
:=
1
// SQL 计数器
lineCounter
:=
1
// 行计数器
lineCounter
:=
1
// 行计数器
var
alterS
ql
s
[]
string
// 待评审的 SQL 中所有 ALTER 请求
var
alterS
QL
s
[]
string
// 待评审的 SQL 中所有 ALTER 请求
alterTableTimes
:=
make
(
map
[
string
]
int
)
// 待评审的 SQL 中同一经表 ALTER 请求计数器
alterTableTimes
:=
make
(
map
[
string
]
int
)
// 待评审的 SQL 中同一经表 ALTER 请求计数器
suggestMerged
:=
make
(
map
[
string
]
map
[
string
]
advisor
.
Rule
)
// 优化建议去重, key 为 sql 的 fingerprint.ID
suggestMerged
:=
make
(
map
[
string
]
map
[
string
]
advisor
.
Rule
)
// 优化建议去重, key 为 sql 的 fingerprint.ID
...
@@ -49,7 +48,9 @@ func main() {
...
@@ -49,7 +48,9 @@ func main() {
initConfig
()
initConfig
()
// 命令行帮助工具,如 -list-report-types, -check-config等。
// 命令行帮助工具,如 -list-report-types, -check-config等。
helpTools
()
if
isContinue
,
exitCode
:=
helpTools
();
!
isContinue
{
os
.
Exit
(
exitCode
)
}
// 环境初始化,连接检查线上环境+构建测试环境
// 环境初始化,连接检查线上环境+构建测试环境
vEnv
,
rEnv
:=
env
.
BuildEnv
()
vEnv
,
rEnv
:=
env
.
BuildEnv
()
...
@@ -83,76 +84,19 @@ func main() {
...
@@ -83,76 +84,19 @@ func main() {
}
}
// 读入待优化 SQL ,当配置文件或命令行参数未指定 SQL 时从管道读取
// 读入待优化 SQL ,当配置文件或命令行参数未指定 SQL 时从管道读取
if
common
.
Config
.
Query
==
""
{
buf
:=
initQuery
(
common
.
Config
.
Query
)
// check stdin is pipe or terminal
lineCounter
+=
ast
.
LeftNewLines
([]
byte
(
buf
))
// https://stackoverflow.com/questions/22744443/check-if-there-is-something-to-read-on-stdin-in-golang
buf
=
strings
.
TrimSpace
(
buf
)
stat
,
err
:=
os
.
Stdin
.
Stat
()
if
stat
==
nil
{
common
.
Log
.
Critical
(
"os.Stdin.Stat Error: %v"
,
err
)
os
.
Exit
(
1
)
}
if
(
stat
.
Mode
()
&
os
.
ModeCharDevice
)
!=
0
{
// stdin is from a terminal
fmt
.
Println
(
"Args format error, use --help see how to use it!"
)
os
.
Exit
(
1
)
}
// read from pipe
var
data
[]
byte
data
,
err
=
ioutil
.
ReadAll
(
os
.
Stdin
)
if
err
!=
nil
{
common
.
Log
.
Critical
(
"ioutil.ReadAll Error: %v"
,
err
)
}
lineCounter
+=
ast
.
LeftNewLines
(
data
)
sql
=
strings
.
TrimSpace
(
string
(
data
))
}
else
{
if
_
,
err
=
os
.
Stat
(
common
.
Config
.
Query
);
err
==
nil
{
var
data
[]
byte
data
,
err
=
ioutil
.
ReadFile
(
common
.
Config
.
Query
)
if
err
!=
nil
{
common
.
Log
.
Critical
(
"ioutil.ReadFile Error: %v"
,
err
)
}
lineCounter
+=
ast
.
LeftNewLines
(
data
)
sql
=
strings
.
TrimSpace
(
string
(
data
))
}
else
{
lineCounter
+=
ast
.
LeftNewLines
([]
byte
(
common
.
Config
.
Query
))
sql
=
strings
.
TrimSpace
(
common
.
Config
.
Query
)
}
}
// remove bom from file header
// remove bom from file header
var
bom
[]
byte
var
bom
[]
byte
sql
,
bom
=
common
.
RemoveBOM
([]
byte
(
sql
))
buf
,
bom
=
common
.
RemoveBOM
([]
byte
(
buf
))
switch
common
.
Config
.
ReportType
{
if
isContinue
,
exitCode
:=
reportTool
(
buf
,
bom
);
!
isContinue
{
case
"html"
:
os
.
Exit
(
exitCode
)
// HTML 格式输入 CSS 加载
fmt
.
Println
(
common
.
MarkdownHTMLHeader
())
case
"md2html"
:
// markdown2html 转换小工具
fmt
.
Println
(
common
.
MarkdownHTMLHeader
())
fmt
.
Println
(
common
.
Markdown2HTML
(
sql
))
return
case
"explain-digest"
:
// 当用户输入为 EXPLAIN 信息,只对 Explain 信息进行分析
// 注意: 这里只能处理一条 SQL 的 EXPLAIN 信息,用户一次反馈多条 SQL 的 EXPLAIN 信息无法处理
advisor
.
DigestExplainText
(
sql
)
return
case
"chardet"
:
// Get charset of input
charset
:=
common
.
CheckCharsetByBOM
(
bom
)
if
charset
==
""
{
charset
=
common
.
Chardet
([]
byte
(
sql
))
}
fmt
.
Println
(
charset
)
return
case
"remove-comment"
:
fmt
.
Println
(
string
(
database
.
RemoveSQLComments
([]
byte
(
sql
))))
return
}
}
// 逐条SQL给出优化建议
// 逐条SQL给出优化建议
lineCounter
+=
ast
.
LeftNewLines
([]
byte
(
sql
))
buf
:=
strings
.
TrimSpace
(
sql
)
for
;
;
sqlCounter
++
{
for
;
;
sqlCounter
++
{
var
id
string
// fingerprint.ID
var
id
string
// fingerprint.ID
heuristicSuggest
:=
make
(
map
[
string
]
advisor
.
Rule
)
// 启发式建议
heuristicSuggest
:=
make
(
map
[
string
]
advisor
.
Rule
)
// 启发式建议
...
@@ -411,7 +355,7 @@ func main() {
...
@@ -411,7 +355,7 @@ func main() {
// 依赖上下文件的 SQL 重写,如:多条 ALTER SQL 合并
// 依赖上下文件的 SQL 重写,如:多条 ALTER SQL 合并
// vitess 对 DDL 语法的支持不好,大部分 DDL 会语法解析出错,但即使出错了还是会生成一个 stmt 而且里面的 db.table 还是准确的。
// vitess 对 DDL 语法的支持不好,大部分 DDL 会语法解析出错,但即使出错了还是会生成一个 stmt 而且里面的 db.table 还是准确的。
alterS
qls
=
append
(
alterSql
s
,
sql
)
alterS
QLs
=
append
(
alterSQL
s
,
sql
)
alterTbl
:=
ast
.
AlterAffectTable
(
stmt
)
alterTbl
:=
ast
.
AlterAffectTable
(
stmt
)
if
alterTbl
!=
""
&&
alterTbl
!=
"dual"
{
if
alterTbl
!=
""
&&
alterTbl
!=
"dual"
{
if
_
,
ok
:=
alterTableTimes
[
alterTbl
];
ok
{
if
_
,
ok
:=
alterTableTimes
[
alterTbl
];
ok
{
...
@@ -477,7 +421,7 @@ func main() {
...
@@ -477,7 +421,7 @@ func main() {
// 同一张表的多条 ALTER 语句合并为一条
// 同一张表的多条 ALTER 语句合并为一条
if
ast
.
RewriteRuleMatch
(
"mergealter"
)
{
if
ast
.
RewriteRuleMatch
(
"mergealter"
)
{
for
_
,
v
:=
range
ast
.
MergeAlterTables
(
alterS
ql
s
...
)
{
for
_
,
v
:=
range
ast
.
MergeAlterTables
(
alterS
QL
s
...
)
{
fmt
.
Println
(
strings
.
TrimSpace
(
v
))
fmt
.
Println
(
strings
.
TrimSpace
(
v
))
}
}
return
return
...
...
cmd/soar/tool.go
浏览文件 @
c9ee5b48
...
@@ -18,6 +18,7 @@ package main
...
@@ -18,6 +18,7 @@ package main
import
(
import
(
"fmt"
"fmt"
"io/ioutil"
"os"
"os"
"path/filepath"
"path/filepath"
"strings"
"strings"
...
@@ -109,41 +110,113 @@ func checkConfig() int {
...
@@ -109,41 +110,113 @@ func checkConfig() int {
}
}
// helpTools help tools in cmd flags
// helpTools help tools in cmd flags
func
helpTools
()
{
func
helpTools
()
(
isContinue
bool
,
exitCode
int
)
{
// environment error check, eg. MySQL password error
// environment error check, eg. MySQL password error
if
common
.
CheckConfig
{
if
common
.
CheckConfig
{
os
.
Exit
(
checkConfig
()
)
return
false
,
checkConfig
(
)
}
}
// 打印 SOAR 版本信息
// 打印 SOAR 版本信息
if
common
.
PrintVersion
{
if
common
.
PrintVersion
{
common
.
SoarVersion
()
common
.
SoarVersion
()
os
.
Exit
(
0
)
return
false
,
0
}
}
// 打印已加载配置的各配置项,检查配置是否生效
// 打印已加载配置的各配置项,检查配置是否生效
if
common
.
PrintConfig
{
if
common
.
PrintConfig
{
common
.
PrintConfiguration
()
common
.
PrintConfiguration
()
os
.
Exit
(
0
)
return
false
,
0
}
}
// 打印支持启发式建议
// 打印支持启发式建议
if
common
.
Config
.
ListHeuristicRules
{
if
common
.
Config
.
ListHeuristicRules
{
advisor
.
ListHeuristicRules
(
advisor
.
HeuristicRules
)
advisor
.
ListHeuristicRules
(
advisor
.
HeuristicRules
)
os
.
Exit
(
0
)
return
false
,
0
}
}
// 打印支持的 SQL 重写规则
// 打印支持的 SQL 重写规则
if
common
.
Config
.
ListRewriteRules
{
if
common
.
Config
.
ListRewriteRules
{
ast
.
ListRewriteRules
(
ast
.
RewriteRules
)
ast
.
ListRewriteRules
(
ast
.
RewriteRules
)
os
.
Exit
(
0
)
return
false
,
0
}
}
// 打印所有的测试 SQL
// 打印所有的测试 SQL
if
common
.
Config
.
ListTestSqls
{
if
common
.
Config
.
ListTestSqls
{
advisor
.
ListTestSQLs
()
advisor
.
ListTestSQLs
()
os
.
Exit
(
0
)
return
false
,
0
}
}
// 打印支持的 report-type
// 打印支持的 report-type
if
common
.
Config
.
ListReportTypes
{
if
common
.
Config
.
ListReportTypes
{
common
.
ListReportTypes
()
common
.
ListReportTypes
()
os
.
Exit
(
0
)
return
false
,
0
}
}
return
true
,
0
}
// reportTool tools in report type
func
reportTool
(
sql
string
,
bom
[]
byte
)
(
isContinue
bool
,
exitCode
int
)
{
switch
common
.
Config
.
ReportType
{
case
"html"
:
// HTML 格式输入 CSS 加载
fmt
.
Println
(
common
.
MarkdownHTMLHeader
())
return
true
,
0
case
"md2html"
:
// markdown2html 转换小工具
fmt
.
Println
(
common
.
MarkdownHTMLHeader
())
fmt
.
Println
(
common
.
Markdown2HTML
(
sql
))
return
false
,
0
case
"explain-digest"
:
// 当用户输入为 EXPLAIN 信息,只对 Explain 信息进行分析
// 注意: 这里只能处理一条 SQL 的 EXPLAIN 信息,用户一次反馈多条 SQL 的 EXPLAIN 信息无法处理
advisor
.
DigestExplainText
(
sql
)
return
false
,
0
case
"chardet"
:
// Get charset of input
charset
:=
common
.
CheckCharsetByBOM
(
bom
)
if
charset
==
""
{
charset
=
common
.
Chardet
([]
byte
(
sql
))
}
fmt
.
Println
(
charset
)
return
false
,
0
case
"remove-comment"
:
fmt
.
Println
(
string
(
database
.
RemoveSQLComments
([]
byte
(
sql
))))
return
false
,
0
default
:
return
true
,
0
}
}
// initQuery
func
initQuery
(
query
string
)
string
{
// 读入待优化 SQL ,当配置文件或命令行参数未指定 SQL 时从管道读取
if
query
==
""
{
// check stdin is pipe or terminal
// https://stackoverflow.com/questions/22744443/check-if-there-is-something-to-read-on-stdin-in-golang
stat
,
err
:=
os
.
Stdin
.
Stat
()
if
stat
==
nil
{
common
.
Log
.
Critical
(
"os.Stdin.Stat Error: %v"
,
err
)
os
.
Exit
(
1
)
}
if
(
stat
.
Mode
()
&
os
.
ModeCharDevice
)
!=
0
{
// stdin is from a terminal
fmt
.
Println
(
"Args format error, use --help see how to use it!"
)
os
.
Exit
(
1
)
}
// read from pipe
var
data
[]
byte
data
,
err
=
ioutil
.
ReadAll
(
os
.
Stdin
)
if
err
!=
nil
{
common
.
Log
.
Critical
(
"ioutil.ReadAll Error: %v"
,
err
)
}
return
string
(
data
)
}
if
_
,
err
:=
os
.
Stat
(
query
);
err
==
nil
{
var
data
[]
byte
data
,
err
=
ioutil
.
ReadFile
(
query
)
if
err
!=
nil
{
common
.
Log
.
Critical
(
"ioutil.ReadFile Error: %v"
,
err
)
}
return
string
(
data
)
}
return
query
}
}
func
shutdown
(
vEnv
*
env
.
VirtualEnv
)
{
func
shutdown
(
vEnv
*
env
.
VirtualEnv
)
{
...
...
common/chardet.go
浏览文件 @
c9ee5b48
...
@@ -42,7 +42,7 @@ func Chardet(buf []byte) string {
...
@@ -42,7 +42,7 @@ func Chardet(buf []byte) string {
// SOAR's main user speak Chinese, GB-18030, UTF-8 are higher suggested
// SOAR's main user speak Chinese, GB-18030, UTF-8 are higher suggested
for
_
,
r
:=
range
result
{
for
_
,
r
:=
range
result
{
if
confidence
>
=
r
.
Confidence
&&
r
.
Confidence
!=
0
{
if
confidence
>
r
.
Confidence
&&
r
.
Confidence
!=
0
{
return
charset
return
charset
}
}
confidence
=
r
.
Confidence
confidence
=
r
.
Confidence
...
...
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录