常见使用语句
# 查看创建表帮助文档
> HELP CREATE TABLE;
# 查看 ALTER 进度状态
> SHOW ALTER TABLE COLUMN;
# 取消 ALTER 进度
> CANCEL ALTER TABLE COLUMN FROM table1
# 查看 ALTER 相关命令
> HELP ALTER TABLE
语法解析过程
Doris SQL 解析具体包括了五个步骤:词法分析,语法分析,生成单机逻辑计划,生成分布式逻辑计划,生成物理执行计划。
具体代码实现上包含以下五个步骤:Parse, Analyze, SinglePlan, DistributedPlan, Schedule。如下图所示:
上图中未提及 Parse
过程,而该过程在 Doris
系统中语法解析分为三个阶段 jflex
词法分析、java cup parser
进行语法分析、生成抽象语法树(AST
),AST
是种树状结构,将不同的查询语句 select
, insert
, show
, set
, alter table
, create table
等经过 Parse
阶段后生成不同的数据结构(SelectStmt
, InsertStmt
, ShowStmt
, SetStmt
, AlterStmt
, AlterTableStmt
, CreateTableStmt
等)之后,根据语法规则进行逻辑处理即可。
因此整体流程下来即如下图:
注
使用 SqlParserUtils
实现 sql
解析过程,如下是 parse
结果实例:
String originStmt = "select username, sum(distinct link) from tbl_event_log group by username;";
SqlScanner input = new SqlScanner(new StringReader(originStmt), ctx.getSessionVariable().getSqlMode());
SqlParser parser = new SqlParser(input);
StatementBase statementBase = SqlParserUtils.getFirstStmt(parser);
注
实际解析过程在 org.apache.doris.qe.StmtExecutor
类进行解析,然后生成执行计划,实例如下:
String sql7 = "select * from db1.tbl1 where k1='a' and k4=1\n"
+ "except distinct\n"
+ "select * from db1.tbl1 where k1='a' and k4=1\n"
+ "except\n"
+ "select * from db1.tbl1 where k1='a' and k4=2\n"
+ "except\n"
+ "(select * from db1.tbl1 where k1='a' and k4=2)\n"
+ "order by 3 limit 3";
StmtExecutor stmtExecutor7 = new StmtExecutor(ctx, sql7);
stmtExecutor7.execute();
Planner planner7 = stmtExecutor7.planner();
List<PlanFragment> fragments7 = planner7.getFragments();
String plan7 = planner7.getExplainString(fragments7, new ExplainOptions(false, false));
注
Doris
解析过程如下所示:
# 在 org.apache.doris.qe.ConnectProcessor 类 handleQuery() 函数中获取 sql 内容,并将 sql 转化为 StatementBase 列表
// process COM_QUERY statement,
// 只有在与请求客户端交互出现问题时候才抛出异常
private void handleQuery() {
// ... 省略 ....
originStmt = new String(bytes, 1, ending, "UTF-8");
// ... 省略 ....
String sqlHash = DigestUtils.md5Hex(originStmt);
ctx.setSqlHash(sqlHash);
// 匹配数据 block 规则, 如果符合 block 规则则取消执行
Catalog.getCurrentCatalog().getSqlBlockRuleMgr().matchSql(originStmt, sqlHash, ctx.getQualifiedUser());
// ... 省略 ....
ctx.getAuditEventBuilder().reset();
ctx.getAuditEventBuilder()
.setTimestamp(System.currentTimeMillis())
.setClientIp(ctx.getMysqlChannel().getRemoteHostPortString())
.setUser(ctx.getQualifiedUser())
.setDb(ctx.getDatabase())
.setSqlHash(ctx.getSqlHash());
// execute this query.
StatementBase parsedStmt = null;
List<Pair<StatementBase, Data.PQueryStatistics>> auditInfoList = Lists.newArrayList();
boolean alreadyAddedToAuditInfoList = false;
try {
// 分析语法并将其转化为相应的 StatementBase 类
List<StatementBase> stmts = analyze(originStmt);
for (int i = 0; i < stmts.size(); ++i) {
alreadyAddedToAuditInfoList = false;
ctx.getState().reset();
if (i > 0) {
ctx.resetReturnRows();
}
parsedStmt = stmts.get(i);
parsedStmt.setOrigStmt(new OriginStatement(originStmt, i));
parsedStmt.setUserInfo(ctx.getCurrentUserIdentity());
// 将 StatementBase 类封装为 StmtExecutor 类
executor = new StmtExecutor(ctx, parsedStmt);
ctx.setExecutor(executor);
// 将 StatementBase 类解析为执行计划
executor.execute();
if (i != stmts.size() - 1) {
ctx.getState().serverStatus |= MysqlServerStatusFlag.SERVER_MORE_RESULTS_EXISTS;
finalizeCommand();
}
auditInfoList.add(new Pair<>(executor.getParsedStmt(), executor.getQueryStatisticsForAuditLog()));
alreadyAddedToAuditInfoList = true;
}
} catch (IOException e) {
// ... 省略 ....
}