Skip to content
Snippets Groups Projects
Unverified Commit ff4cfcf0 authored by qingxinhome's avatar qingxinhome Committed by GitHub
Browse files

Add explain for DML (#2549)

parent 8b3731fb
No related branches found
No related tags found
No related merge requests found
......@@ -903,11 +903,7 @@ func (mce *MysqlCmdExecutor) handleAnalyzeStmt(stmt *tree.AnalyzeStmt) error {
}
func (mce *MysqlCmdExecutor) handleExplainStmt(stmt *tree.ExplainStmt) error {
es := &explain.ExplainOptions{
Verbose: false,
Anzlyze: false,
Format: explain.EXPLAIN_FORMAT_TEXT,
}
es := explain.NewExplainDefaultOptions()
for _, v := range stmt.Options {
if strings.EqualFold(v.Name, "VERBOSE") {
......@@ -941,19 +937,24 @@ func (mce *MysqlCmdExecutor) handleExplainStmt(stmt *tree.ExplainStmt) error {
}
}
//get CompilerContext
ctx := plan2.NewMockCompilerContext()
qry, err := plan2.BuildPlan(ctx, stmt.Statement)
//get query optimizer and execute Optimize
mockOptimizer := plan2.NewMockOptimizer()
qry, err := mockOptimizer.Optimize(stmt.Statement)
if err != nil {
//fmt.Sprintf("build Query statement error: '%v'", tree.String(stmt, dialect.MYSQL))
return errors.New(errno.SyntaxErrororAccessRuleViolation, fmt.Sprintf("Build Query statement error:'%v'", tree.String(stmt.Statement, dialect.MYSQL)))
logutil.Errorf("build query plan and optimize failed, error: %v", err)
return errors.New(errno.SyntaxErrororAccessRuleViolation, fmt.Sprintf("build query plan and optimize failed:'%v'", err))
}
// build explain data buffer
buffer := explain.NewExplainDataBuffer()
// generator query explain
explainQuery := explain.NewExplainQueryImpl(qry.GetQuery())
explainQuery.ExplainPlan(buffer, es)
explainQuery := explain.NewExplainQueryImpl(qry)
err = explainQuery.ExplainPlan(buffer, es)
if err != nil {
logutil.Errorf("explain Query statement error: %v", err)
return errors.New(errno.SyntaxErrororAccessRuleViolation, fmt.Sprintf("explain Query statement error:%v", err))
}
session := mce.GetSession()
protocol := session.GetMysqlProtocol()
......
// Copyright 2021 Matrix Origin
// Copyright 2021 - 2022 Matrix Origin
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
......@@ -15,55 +15,79 @@
package explain
import (
"fmt"
"github.com/matrixorigin/matrixone/pkg/errno"
"github.com/matrixorigin/matrixone/pkg/pb/plan"
"github.com/matrixorigin/matrixone/pkg/sql/errors"
"github.com/matrixorigin/matrixone/pkg/sql/plan2"
"strconv"
)
func DescribeExpr(expr *plan.Expr) string {
func describeExpr(expr *plan.Expr, options *ExplainOptions) (string, error) {
var result string
switch expr.Expr.(type) {
case *plan.Expr_Col:
colExpr := expr.Expr.(*plan.Expr_Col)
result += colExpr.Col.GetName()
case *plan.Expr_C:
constExpr := expr.Expr.(*plan.Expr_C)
if intConst, ok := constExpr.C.Value.(*plan.Const_Ival); ok {
result += fmt.Sprintf("%v", intConst.Ival)
}
if floatConst, ok := constExpr.C.Value.(*plan.Const_Dval); ok {
result += fmt.Sprintf("%v", floatConst.Dval)
}
if expr.Expr == nil {
result += expr.Alias
} else {
switch expr.Expr.(type) {
case *plan.Expr_Col:
colExpr := expr.Expr.(*plan.Expr_Col)
result += colExpr.Col.GetName()
case *plan.Expr_C:
constExpr := expr.Expr.(*plan.Expr_C)
if intConst, ok := constExpr.C.Value.(*plan.Const_Ival); ok {
result += strconv.FormatInt(intConst.Ival, 10)
}
if floatConst, ok := constExpr.C.Value.(*plan.Const_Dval); ok {
result += strconv.FormatFloat(floatConst.Dval, 'f', -1, 64)
}
if strConst, ok := constExpr.C.Value.(*plan.Const_Sval); ok {
result += fmt.Sprintf("%v", strConst.Sval)
}
case *plan.Expr_F:
funcExpr := expr.Expr.(*plan.Expr_F)
result += FuncExprExplain(funcExpr)
case *plan.Expr_V:
return "unimplement Expr_V"
case *plan.Expr_P:
return "unimplement Expr_P"
case *plan.Expr_List:
return "unimplement Expr_List"
default:
return "error Expr"
if strConst, ok := constExpr.C.Value.(*plan.Const_Sval); ok {
result += "'" + strConst.Sval + "'"
}
case *plan.Expr_F:
funcExpr := expr.Expr.(*plan.Expr_F)
funcDesc, err := funcExprExplain(funcExpr, expr.Typ, options)
if err != nil {
return result, err
}
result += funcDesc
case *plan.Expr_Sub:
subqryExpr := expr.Expr.(*plan.Expr_Sub)
result += "subquery nodeId = " + strconv.FormatInt(int64(subqryExpr.Sub.NodeId), 10)
case *plan.Expr_Corr:
result += expr.Expr.(*plan.Expr_Corr).Corr.GetName()
case *plan.Expr_V:
panic("unimplement Expr_V")
case *plan.Expr_P:
panic("unimplement Expr_P")
case *plan.Expr_List:
exprlist := expr.Expr.(*plan.Expr_List)
if exprlist.List.List != nil {
exprListDescImpl := NewExprListDescribeImpl(exprlist.List.List)
desclist, err := exprListDescImpl.GetDescription(options)
if err != nil {
return result, err
}
result += desclist
}
default:
panic("error Expr")
}
}
return result
return result, nil
}
func FuncExprExplain(funcExpr *plan.Expr_F) string {
func funcExprExplain(funcExpr *plan.Expr_F, Typ *plan.Type, options *ExplainOptions) (string, error) {
//SysFunsAndOperatorsMap
var result string
funcName := funcExpr.F.GetFunc().GetObjName()
// Get function explain type
funcProtoType, ok := plan2.BuiltinFunctionsMap[funcName]
if !ok {
panic("unkonw expression")
return result, errors.New(errno.InvalidName, "invalid function or opreator name '"+funcName+"'")
}
switch funcProtoType.Kind {
switch funcProtoType.Layout {
case plan2.STANDARD_FUNCTION:
result += funcExpr.F.Func.GetObjName() + "("
if len(funcExpr.F.Args) > 0 {
......@@ -73,7 +97,11 @@ func FuncExprExplain(funcExpr *plan.Expr_F) string {
result += ", "
}
first = false
result += DescribeExpr(v)
exprDesc, err := describeExpr(v, options)
if err != nil {
return result, err
}
result += exprDesc
}
}
result += ")"
......@@ -84,29 +112,130 @@ func FuncExprExplain(funcExpr *plan.Expr_F) string {
} else {
opertator = "-"
}
result += opertator + DescribeExpr(funcExpr.F.Args[0])
case plan2.BINARY_ARITHMETIC_OPERATOR:
result += DescribeExpr(funcExpr.F.Args[0]) + " " + funcExpr.F.Func.GetObjName() + " " + DescribeExpr(funcExpr.F.Args[1])
describeExpr, err := describeExpr(funcExpr.F.Args[0], options)
if err != nil {
return result, err
}
result += "(" + opertator + describeExpr + ")"
case plan2.UNARY_LOGICAL_OPERATOR:
result += funcExpr.F.Func.GetObjName() + " " + DescribeExpr(funcExpr.F.Args[0])
describeExpr, err := describeExpr(funcExpr.F.Args[0], options)
if err != nil {
return result, err
}
result += "(" + funcExpr.F.Func.GetObjName() + " " + describeExpr + ")"
case plan2.BINARY_ARITHMETIC_OPERATOR:
fallthrough
case plan2.BINARY_LOGICAL_OPERATOR:
result += DescribeExpr(funcExpr.F.Args[0]) + " " + funcExpr.F.Func.GetObjName() + " " + DescribeExpr(funcExpr.F.Args[1])
fallthrough
case plan2.COMPARISON_OPERATOR:
result += DescribeExpr(funcExpr.F.Args[0]) + " " + funcExpr.F.Func.GetObjName() + " " + DescribeExpr(funcExpr.F.Args[1])
left, err := describeExpr(funcExpr.F.Args[0], options)
if err != nil {
return result, err
}
right, err := describeExpr(funcExpr.F.Args[1], options)
if err != nil {
return result, err
}
result += "(" + left + " " + funcExpr.F.Func.GetObjName() + " " + right + ")"
case plan2.CAST_EXPRESSION:
// panic("CAST_EXPRESSION is not support now")
describeExpr, err := describeExpr(funcExpr.F.Args[0], options)
if err != nil {
return result, err
}
result += "CAST(" + describeExpr + " AS " + plan.Type_TypeId_name[int32(Typ.Id)] + ")"
case plan2.CASE_WHEN_EXPRESSION:
panic("CASE_WHEN_EXPRESSION is not support now")
case plan2.BETWEEN_AND_EXPRESSION:
panic("CASE_WHEN_EXPRESSION is not support now")
case plan2.IN_EXISTS_EXPRESSION:
panic("CASE_WHEN_EXPRESSION is not support now")
result += "CASE"
// case when expression has three part (case expression, when expression, else expression)
if len(funcExpr.F.Args) != 3 {
return result, errors.New(errno.SyntaxErrororAccessRuleViolation, "case expression parameter number error")
}
// case expression can be null
if funcExpr.F.Args[0] != nil {
// get case expression
caseDesc, err := describeExpr(funcExpr.F.Args[0], options)
if err != nil {
return result, err
}
result += " " + caseDesc
}
// get when expression
var whenExpr *plan.Expr = funcExpr.F.Args[1]
var whenlist *plan.Expr_List = whenExpr.Expr.(*plan.Expr_List)
var list *plan.ExprList = whenlist.List
for i := 0; i < len(list.List); i++ {
whenThenExpr := list.List[i].Expr.(*plan.Expr_List)
if len(whenThenExpr.List.List) != 2 {
return result, errors.New(errno.SyntaxErrororAccessRuleViolation, "case when expression parameter number is not equal to 2")
}
whenExprDesc, err := describeExpr(whenThenExpr.List.List[0], options)
if err != nil {
return result, err
}
thenExprDesc, err := describeExpr(whenThenExpr.List.List[1], options)
if err != nil {
return result, err
}
result += " WHEN " + whenExprDesc + " THEN " + thenExprDesc
}
// when expression can be null
if funcExpr.F.Args[2] != nil {
// get else expression
elseExprDesc, err := describeExpr(funcExpr.F.Args[2], options)
if err != nil {
return result, err
}
result += " ELSE " + elseExprDesc
}
result += " END"
case plan2.IN_PREDICATE:
if len(funcExpr.F.Args) != 2 {
panic("Nested query predicate,such as in,exist,all,any parameter number error!")
}
descExpr, err := describeExpr(funcExpr.F.Args[0], options)
if err != nil {
return result, err
}
descExprlist, err := describeExpr(funcExpr.F.Args[1], options)
if err != nil {
return result, err
}
result += descExpr + " " + funcExpr.F.Func.GetObjName() + "(" + descExprlist + ")"
case plan2.EXISTS_ANY_PREDICATE:
describeExpr, err := describeExpr(funcExpr.F.Args[0], options)
if err != nil {
return result, err
}
result += funcExpr.F.Func.GetObjName() + "(" + describeExpr + ")"
case plan2.IS_NULL_EXPRESSION:
result += DescribeExpr(funcExpr.F.Args[0]) + " IS NULL"
describeExpr, err := describeExpr(funcExpr.F.Args[0], options)
if err != nil {
return result, err
}
result += "(" + describeExpr + " IS NULL)"
case plan2.NOPARAMETER_FUNCTION:
result += funcExpr.F.Func.GetObjName()
case plan2.DATE_INTERVAL_EXPRESSION:
describeExpr, err := describeExpr(funcExpr.F.Args[0], options)
if err != nil {
return result, err
}
result += funcExpr.F.Func.GetObjName() + " " + describeExpr + ""
case plan2.EXTRACT_FUNCTION:
first, err := describeExpr(funcExpr.F.Args[0], options)
if err != nil {
return result, err
}
second, err := describeExpr(funcExpr.F.Args[1], options)
if err != nil {
return result, err
}
result += funcExpr.F.Func.GetObjName() + "(" + first + " from " + second + ")"
case plan2.UNKNOW_KIND_FUNCTION:
panic("UNKNOW_KIND_FUNCTION is not support now")
return result, errors.New(errno.UndefinedFunction, "UNKNOW_KIND_FUNCTION is not support now")
}
return result
return result, nil
}
// Copyright 2021 Matrix Origin
// Copyright 2021 - 2022 Matrix Origin
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
......@@ -14,7 +14,12 @@
package explain
import "github.com/matrixorigin/matrixone/pkg/pb/plan"
import (
"github.com/matrixorigin/matrixone/pkg/errno"
"github.com/matrixorigin/matrixone/pkg/pb/plan"
"github.com/matrixorigin/matrixone/pkg/sql/errors"
"strconv"
)
var _ NodeDescribe = &NodeDescribeImpl{}
......@@ -28,21 +33,24 @@ func NewNodeDescriptionImpl(node *plan.Node) *NodeDescribeImpl {
}
}
func (ndesc *NodeDescribeImpl) GetNodeBasicInfo(options *ExplainOptions) string {
func (ndesc *NodeDescribeImpl) GetNodeBasicInfo(options *ExplainOptions) (string, error) {
var result string
var pname string /* node type name for text output */
// Get the Node Name
switch ndesc.Node.NodeType {
case plan.Node_UNKNOWN:
pname = "UnKnow Node"
case plan.Node_VALUE_SCAN:
pname = "Value Scan"
pname = "Values Scan"
case plan.Node_TABLE_SCAN:
pname = "Table Scan"
case plan.Node_FUNCTION_SCAN:
pname = "Function Scan"
case plan.Node_EXTERNAL_SCAN:
pname = "External Scan"
case plan.Node_MATERIAL_SCAN:
pname = "Material Scan"
case plan.Node_PROJECT:
pname = "Project"
case plan.Node_EXTERNAL_FUNCTION:
......@@ -79,27 +87,40 @@ func (ndesc *NodeDescribeImpl) GetNodeBasicInfo(options *ExplainOptions) string
pname = "Gather"
case plan.Node_ASSERT:
pname = "Assert"
case plan.Node_INSERT:
pname = "Insert"
case plan.Node_UPDATE:
pname = "Update"
case plan.Node_DELETE:
pname = "Delete"
default:
pname = "???"
panic("error node type")
}
// Get Node's operator object info ,such as table, view
if options.Format == EXPLAIN_FORMAT_TEXT {
result += pname
switch ndesc.Node.NodeType {
case plan.Node_VALUE_SCAN:
fallthrough
result += " \"*VALUES*\" "
case plan.Node_TABLE_SCAN:
fallthrough
case plan.Node_FUNCTION_SCAN:
fallthrough
case plan.Node_EXTERNAL_SCAN:
fallthrough
case plan.Node_MATERIAL_SCAN:
fallthrough
case plan.Node_INSERT:
fallthrough
case plan.Node_UPDATE:
fallthrough
case plan.Node_DELETE:
result += " on "
if ndesc.Node.ObjRef != nil {
objRefImpl := NewObjRefDescribeImpl(ndesc.Node.ObjRef)
result += objRefImpl.GetDescription(options)
result += ndesc.Node.ObjRef.GetDbName() + "." + ndesc.Node.ObjRef.GetObjName()
} else if ndesc.Node.TableDef != nil {
tableDefImpl := NewTableDefDescribeImpl(ndesc.Node.TableDef)
result += tableDefImpl.GetDescription(options)
result += ndesc.Node.TableDef.GetName()
}
case plan.Node_PROJECT:
fallthrough
......@@ -144,65 +165,109 @@ func (ndesc *NodeDescribeImpl) GetNodeBasicInfo(options *ExplainOptions) string
}
}
// Get Costs info of Node
if options.Format == EXPLAIN_FORMAT_TEXT {
result += " (cost=%.2f..%.2f rows=%.0f width=%f)"
} else {
//TODO implement me
panic("implement me")
} else if options.Format == EXPLAIN_FORMAT_JSON {
return result, errors.New(errno.FeatureNotSupported, "unimplement explain format json")
} else if options.Format == EXPLAIN_FORMAT_DOT {
return result, errors.New(errno.FeatureNotSupported, "unimplement explain format dot")
}
return result
return result, nil
}
func (ndesc *NodeDescribeImpl) GetExtraInfo(options *ExplainOptions) []string {
func (ndesc *NodeDescribeImpl) GetExtraInfo(options *ExplainOptions) ([]string, error) {
lines := make([]string, 0)
// Get Sort list info
if ndesc.Node.OrderBy != nil {
orderByInfo := ndesc.GetOrderByInfo(options)
orderByInfo, err := ndesc.GetOrderByInfo(options)
if err != nil {
return nil, err
}
lines = append(lines, orderByInfo)
}
// Get Join Condition info
if ndesc.Node.OnList != nil {
joinOnInfo := ndesc.GetJoinConditionInfo(options)
joinOnInfo, err := ndesc.GetJoinConditionInfo(options)
if err != nil {
return nil, err
}
lines = append(lines, joinOnInfo)
}
// Get Group key info
if ndesc.Node.GroupBy != nil {
groupByInfo := ndesc.GetGroupByInfo(options)
groupByInfo, err := ndesc.GetGroupByInfo(options)
if err != nil {
return nil, err
}
lines = append(lines, groupByInfo)
}
// Get Filter list info
if ndesc.Node.WhereList != nil {
filterInfo := ndesc.GetWhereConditionInfo(options)
filterInfo, err := ndesc.GetWhereConditionInfo(options)
if err != nil {
return nil, err
}
lines = append(lines, filterInfo)
}
// Get Limit And Offset info
if ndesc.Node.Limit != nil {
var temp string
limitInfo := DescribeExpr(ndesc.Node.Limit)
limitInfo, err := describeExpr(ndesc.Node.Limit, options)
if err != nil {
return nil, err
}
temp += "Limit: " + limitInfo
if ndesc.Node.Offset != nil {
offsetInfo := DescribeExpr(ndesc.Node.Offset)
offsetInfo, err := describeExpr(ndesc.Node.Offset, options)
if err != nil {
return nil, err
}
temp += ", Offset: " + offsetInfo
}
lines = append(lines, temp)
}
return lines
if ndesc.Node.UpdateList != nil {
updateListDesc := &UpdateListDescribeImpl{
UpdateList: ndesc.Node.UpdateList,
}
updatedesc, err := updateListDesc.GetDescription(options)
if err != nil {
return nil, err
}
lines = append(lines, "Set columns with("+updatedesc+")")
}
return lines, nil
}
func (ndesc *NodeDescribeImpl) GetProjectListInfo(options *ExplainOptions) string {
func (ndesc *NodeDescribeImpl) GetProjectListInfo(options *ExplainOptions) (string, error) {
var result string = "Output:"
exprs := NewExprListDescribeImpl(ndesc.Node.ProjectList)
result += exprs.GetDescription(options)
return result
describe, err := exprs.GetDescription(options)
if err != nil {
return result, err
}
result += describe
return result, nil
}
func (ndesc *NodeDescribeImpl) GetJoinConditionInfo(options *ExplainOptions) string {
func (ndesc *NodeDescribeImpl) GetJoinConditionInfo(options *ExplainOptions) (string, error) {
var result string = "Join Cond:"
exprs := NewExprListDescribeImpl(ndesc.Node.OnList)
result += exprs.GetDescription(options)
return result
describe, err := exprs.GetDescription(options)
if err != nil {
return result, err
}
result += describe
return result, nil
}
func (ndesc *NodeDescribeImpl) GetWhereConditionInfo(options *ExplainOptions) string {
func (ndesc *NodeDescribeImpl) GetWhereConditionInfo(options *ExplainOptions) (string, error) {
var result string = "Filter: "
if options.Format == EXPLAIN_FORMAT_TEXT {
var first bool = true
......@@ -211,15 +276,21 @@ func (ndesc *NodeDescribeImpl) GetWhereConditionInfo(options *ExplainOptions) st
result += " AND "
}
first = false
result += DescribeExpr(v)
descV, err := describeExpr(v, options)
if err != nil {
return result, err
}
result += descV
}
} else {
panic("implement me")
} else if options.Format == EXPLAIN_FORMAT_JSON {
return result, errors.New(errno.FeatureNotSupported, "unimplement explain format json")
} else if options.Format == EXPLAIN_FORMAT_DOT {
return result, errors.New(errno.FeatureNotSupported, "unimplement explain format dot")
}
return result
return result, nil
}
func (ndesc *NodeDescribeImpl) GetGroupByInfo(options *ExplainOptions) string {
func (ndesc *NodeDescribeImpl) GetGroupByInfo(options *ExplainOptions) (string, error) {
var result string = "Group Key:"
if options.Format == EXPLAIN_FORMAT_TEXT {
var first bool = true
......@@ -228,15 +299,21 @@ func (ndesc *NodeDescribeImpl) GetGroupByInfo(options *ExplainOptions) string {
result += ", "
}
first = false
result += DescribeExpr(v)
descV, err := describeExpr(v, options)
if err != nil {
return result, err
}
result += descV
}
} else {
panic("implement me")
} else if options.Format == EXPLAIN_FORMAT_JSON {
return result, errors.New(errno.FeatureNotSupported, "unimplement explain format json")
} else if options.Format == EXPLAIN_FORMAT_DOT {
return result, errors.New(errno.FeatureNotSupported, "unimplement explain format dot")
}
return result
return result, nil
}
func (ndesc *NodeDescribeImpl) GetOrderByInfo(options *ExplainOptions) string {
func (ndesc *NodeDescribeImpl) GetOrderByInfo(options *ExplainOptions) (string, error) {
var result string = "Sort Key:"
if options.Format == EXPLAIN_FORMAT_TEXT {
var first bool = true
......@@ -246,29 +323,40 @@ func (ndesc *NodeDescribeImpl) GetOrderByInfo(options *ExplainOptions) string {
}
first = false
orderByDescImpl := NewOrderByDescribeImpl(v)
result += orderByDescImpl.GetDescription(options)
describe, err := orderByDescImpl.GetDescription(options)
if err != nil {
return result, err
}
result += describe
}
} else {
panic("implement me")
} else if options.Format == EXPLAIN_FORMAT_JSON {
return result, errors.New(errno.FeatureNotSupported, "unimplement explain format json")
} else if options.Format == EXPLAIN_FORMAT_DOT {
return result, errors.New(errno.FeatureNotSupported, "unimplement explain format dot")
}
return result
return result, nil
}
var _ NodeElemDescribe = &CostDescribeImpl{}
var _ NodeElemDescribe = &ExprListDescribeImpl{}
var _ NodeElemDescribe = &OrderByDescribeImpl{}
var _ NodeElemDescribe = &WinSpecDescribeImpl{}
var _ NodeElemDescribe = &TableDefDescribeImpl{}
var _ NodeElemDescribe = &ObjRefDescribeImpl{}
var _ NodeElemDescribe = &RowsetDataDescribeImpl{}
var _ NodeElemDescribe = &UpdateListDescribeImpl{}
type CostDescribeImpl struct {
Cost *Cost
Cost *plan.Cost
}
func (c *CostDescribeImpl) GetDescription(options *ExplainOptions) string {
//TODO implement me
panic("implement me")
func (c *CostDescribeImpl) GetDescription(options *ExplainOptions) (string, error) {
//(cost=11.75..13.15 rows=140 width=4)
var result string = "(cost=" +
strconv.FormatFloat(c.Cost.Start, 'f', 2, 64) +
".." + strconv.FormatFloat(c.Cost.Total, 'f', 2, 64) +
" rows=" + strconv.FormatFloat(c.Cost.Card, 'f', 2, 64) +
" ndv=" + strconv.FormatFloat(c.Cost.Ndv, 'f', 2, 64) +
" width=" + strconv.FormatFloat(c.Cost.Rowsize, 'f', 0, 64)
return result, nil
}
type ExprListDescribeImpl struct {
......@@ -281,7 +369,7 @@ func NewExprListDescribeImpl(ExprList []*plan.Expr) *ExprListDescribeImpl {
}
}
func (e *ExprListDescribeImpl) GetDescription(options *ExplainOptions) string {
func (e *ExprListDescribeImpl) GetDescription(options *ExplainOptions) (string, error) {
var first bool = true
var result string = " "
if options.Format == EXPLAIN_FORMAT_TEXT {
......@@ -290,12 +378,18 @@ func (e *ExprListDescribeImpl) GetDescription(options *ExplainOptions) string {
result += ", "
}
first = false
result += DescribeExpr(v)
descV, err := describeExpr(v, options)
if err != nil {
return result, err
}
result += descV
}
} else {
panic("implement me")
} else if options.Format == EXPLAIN_FORMAT_JSON {
return result, errors.New(errno.FeatureNotSupported, "unimplement explain format json")
} else if options.Format == EXPLAIN_FORMAT_DOT {
return result, errors.New(errno.FeatureNotSupported, "unimplement explain format dot")
}
return result
return result, nil
}
type OrderByDescribeImpl struct {
......@@ -308,63 +402,71 @@ func NewOrderByDescribeImpl(OrderBy *plan.OrderBySpec) *OrderByDescribeImpl {
}
}
func (o *OrderByDescribeImpl) GetDescription(options *ExplainOptions) string {
func (o *OrderByDescribeImpl) GetDescription(options *ExplainOptions) (string, error) {
var result string = " "
result += DescribeExpr(o.OrderBy.GetOrderBy())
descExpr, err := describeExpr(o.OrderBy.GetOrderBy(), options)
if err != nil {
return result, err
}
result += descExpr
flagKey := int32(o.OrderBy.GetOrderByFlags())
orderbyFlag := plan.OrderBySpec_OrderByFlag_name[flagKey]
result += " " + orderbyFlag
return result
return result, nil
}
type WinSpecDescribeImpl struct {
WinSpec *plan.WindowSpec
}
func (w *WinSpecDescribeImpl) GetDescription(options *ExplainOptions) string {
func (w *WinSpecDescribeImpl) GetDescription(options *ExplainOptions) (string, error) {
//TODO implement me
panic("implement me")
}
type TableDefDescribeImpl struct {
TableDef *plan.TableDef
type RowsetDataDescribeImpl struct {
RowsetData *plan.RowsetData
}
func NewTableDefDescribeImpl(TableDef *plan.TableDef) *TableDefDescribeImpl {
return &TableDefDescribeImpl{
TableDef: TableDef,
}
}
func (t *TableDefDescribeImpl) GetDescription(options *ExplainOptions) string {
if t.TableDef != nil {
return t.TableDef.GetName()
func (r *RowsetDataDescribeImpl) GetDescription(options *ExplainOptions) (string, error) {
var result string
var first bool = true
for index := range r.RowsetData.Cols {
if !first {
result += ", "
}
first = false
result += "\"*VALUES*\".column" + strconv.Itoa(index+1)
}
return ""
return result, nil
}
type ObjRefDescribeImpl struct {
ObjRef *plan.ObjectRef
type UpdateListDescribeImpl struct {
UpdateList *plan.UpdateList
}
func NewObjRefDescribeImpl(ObjRef *plan.ObjectRef) *ObjRefDescribeImpl {
return &ObjRefDescribeImpl{
ObjRef: ObjRef,
func (u *UpdateListDescribeImpl) GetDescription(options *ExplainOptions) (string, error) {
//u.UpdateList.Columns
var result string
var first bool = true
if len(u.UpdateList.Columns) != len(u.UpdateList.Values) {
panic("update node number of columns and values is not equal")
}
}
func (o *ObjRefDescribeImpl) GetDescription(options *ExplainOptions) string {
if o.ObjRef != nil {
return o.ObjRef.DbName + "." + o.ObjRef.GetObjName()
for i, columnExpr := range u.UpdateList.Columns {
if !first {
result += ", "
}
colstr, err := describeExpr(columnExpr, options)
if err != nil {
return result, err
}
valstr, err := describeExpr(u.UpdateList.Values[i], options)
if err != nil {
return result, err
}
result += colstr + " = " + valstr
first = false
}
return ""
}
type RowsetDataDescribeImpl struct {
RowsetData *RowsetData
}
func (r *RowsetDataDescribeImpl) GetDescription(options *ExplainOptions) string {
//TODO implement me
panic("implement me")
return result, nil
}
// Copyright 2021 Matrix Origin
// Copyright 2021 - 2022 Matrix Origin
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
......@@ -15,7 +15,10 @@
package explain
import (
"github.com/matrixorigin/matrixone/pkg/errno"
"github.com/matrixorigin/matrixone/pkg/logutil"
"github.com/matrixorigin/matrixone/pkg/pb/plan"
"github.com/matrixorigin/matrixone/pkg/sql/errors"
)
var _ ExplainQuery = &ExplainQueryImpl{}
......@@ -30,58 +33,96 @@ func NewExplainQueryImpl(query *plan.Query) *ExplainQueryImpl {
}
}
func traversalPlan(node *plan.Node, Nodes []*plan.Node, settings *FormatSettings, options *ExplainOptions) {
if node == nil {
return
}
explainStep(node, settings, options)
settings.level++
if len(node.Children) > 0 {
for _, childIndex := range node.Children {
traversalPlan(Nodes[childIndex], Nodes, settings, options)
}
}
settings.level--
}
func (e *ExplainQueryImpl) ExplainPlan(buffer *ExplainDataBuffer, options *ExplainOptions) {
func (e *ExplainQueryImpl) ExplainPlan(buffer *ExplainDataBuffer, options *ExplainOptions) error {
var Nodes []*plan.Node = e.QueryPlan.Nodes
for _, rootNodeId := range e.QueryPlan.Steps {
// logutil.Infof("------------------------------------Query Plan-%v ---------------------------------------------", index)
for index, rootNodeId := range e.QueryPlan.Steps {
logutil.Infof("------------------------------------Query Plan-%v ---------------------------------------------", index)
settings := FormatSettings{
buffer: buffer,
offset: 0,
indent: 2,
level: 0,
}
traversalPlan(Nodes[rootNodeId], Nodes, &settings, options)
err := traversalPlan(Nodes[rootNodeId], Nodes, &settings, options)
if err != nil {
return err
}
}
return nil
}
func (e *ExplainQueryImpl) ExplainAnalyze(buffer *ExplainDataBuffer, options *ExplainOptions) {
func (e *ExplainQueryImpl) ExplainAnalyze(buffer *ExplainDataBuffer, options *ExplainOptions) error {
//TODO implement me
panic("implement me")
}
func explainStep(step *plan.Node, settings *FormatSettings, options *ExplainOptions) {
func explainStep(step *plan.Node, settings *FormatSettings, options *ExplainOptions) error {
nodedescImpl := NewNodeDescriptionImpl(step)
if options.Format == EXPLAIN_FORMAT_TEXT {
basicNodeInfo := nodedescImpl.GetNodeBasicInfo(options)
basicNodeInfo, err := nodedescImpl.GetNodeBasicInfo(options)
if err != nil {
return nil
}
settings.buffer.PushNewLine(basicNodeInfo, true, settings.level)
// Process verbose optioan information , "Output:"
if options.Verbose {
projecrtInfo := nodedescImpl.GetProjectListInfo(options)
settings.buffer.PushNewLine(projecrtInfo, false, settings.level)
if nodedescImpl.Node.GetProjectList() != nil {
projecrtInfo, err := nodedescImpl.GetProjectListInfo(options)
if err != nil {
return err
}
settings.buffer.PushNewLine(projecrtInfo, false, settings.level)
}
if nodedescImpl.Node.NodeType == plan.Node_VALUE_SCAN {
rowsetDataDescImpl := &RowsetDataDescribeImpl{
RowsetData: nodedescImpl.Node.RowsetData,
}
rowsetInfo, err := rowsetDataDescImpl.GetDescription(options)
if err != nil {
return err
}
rowdatadesc := "Output: " + rowsetInfo
settings.buffer.PushNewLine(rowdatadesc, false, settings.level)
}
}
extraInfo := nodedescImpl.GetExtraInfo(options)
// Get other node descriptions, such as "Filter:", "Group Key:", "Sort Key:"
extraInfo, err := nodedescImpl.GetExtraInfo(options)
if err != nil {
return err
}
for _, line := range extraInfo {
settings.buffer.PushNewLine(line, false, settings.level)
}
} else if options.Format == EXPLAIN_FORMAT_JSON {
panic("implement me")
return errors.New(errno.FeatureNotSupported, "unimplement explain format json")
} else if options.Format == EXPLAIN_FORMAT_DOT {
panic("implement me")
return errors.New(errno.FeatureNotSupported, "unimplement explain format dot")
}
return nil
}
func traversalPlan(node *plan.Node, Nodes []*plan.Node, settings *FormatSettings, options *ExplainOptions) error {
if node == nil {
return nil
}
err := explainStep(node, settings, options)
if err != nil {
return err
}
settings.level++
// Recursive traversal Query Plan
if len(node.Children) > 0 {
for _, childIndex := range node.Children {
err = traversalPlan(Nodes[childIndex], Nodes, settings, options)
if err != nil {
return err
}
}
}
settings.level--
return nil
}
......@@ -16,20 +16,24 @@ package explain
import (
"fmt"
"strings"
"testing"
"github.com/matrixorigin/matrixone/pkg/errno"
"github.com/matrixorigin/matrixone/pkg/sql/errors"
"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect"
"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect/mysql"
"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
"github.com/matrixorigin/matrixone/pkg/sql/plan2"
"strings"
"testing"
)
func TestSingleSql(t *testing.T) {
//input := "explain verbose SELECT * FROM NATION a join REGION b on a.N_REGIONKEY = b.R_REGIONKEY WHERE abs(a.N_REGIONKEY) > 0"
input := "explain verbose SELECT DISTINCT N_NAME FROM NATION limit 10"
//input := "explain verbose SELECT N_REGIONKEY + 2 as a, N_REGIONKEY/2, N_REGIONKEY* N_NATIONKEY, N_REGIONKEY % N_NATIONKEY, N_REGIONKEY - N_NATIONKEY FROM NATION WHERE -N_NATIONKEY < -20"
//input := "explain verbose SELECT N_REGIONKEY + 2 as a FROM NATION WHERE -N_NATIONKEY < -20"
//input := "explain verbose select c_custkey from (select c_custkey from CUSTOMER group by c_custkey ) a"
//input := "explain SELECT N_NAME, N_REGIONKEY FROM NATION WHERE abs(N_REGIONKEY) > 0 AND N_NAME LIKE '%AA'"
//input := "explain verbose SELECT N_NAME, N_REGIONKEY a FROM NATION WHERE N_NATIONKEY > 0 AND N_NATIONKEY < 10"
input := "explain verbose SELECT N_NAME, N_REGIONKEY a FROM NATION WHERE N_NATIONKEY > 0 OR N_NATIONKEY < 10"
mock := plan2.NewMockOptimizer()
err := runOneStmt(mock, t, input)
if err != nil {
......@@ -42,7 +46,9 @@ func TestBasicSqlExplain(t *testing.T) {
"explain verbose SELECT N_NAME,N_REGIONKEY, 23 as a FROM NATION",
"explain verbose SELECT N_NAME,abs(N_REGIONKEY), 23 as a FROM NATION",
"explain SELECT N_NAME, N_REGIONKEY a FROM NATION WHERE N_NATIONKEY > 0 OR N_NATIONKEY < 10",
"explain verbose SELECT N_NAME, N_REGIONKEY a FROM NATION WHERE N_NATIONKEY > 0 OR N_NATIONKEY < 10",
"explain SELECT N_NAME, N_REGIONKEY a FROM NATION WHERE N_NATIONKEY > 0 AND N_NATIONKEY < 10",
"explain verbose SELECT N_NAME, N_REGIONKEY a FROM NATION WHERE N_NATIONKEY > 0 AND N_NATIONKEY < 10",
"explain verbose SELECT N_NAME, N_REGIONKEY a FROM NATION WHERE N_NATIONKEY > 0 AND N_NATIONKEY < 10 ORDER BY N_NAME, N_REGIONKEY DESC",
"explain verbose SELECT count(*) FROM NATION group by N_NAME",
"explain verbose SELECT N_NAME, MAX(N_REGIONKEY) FROM NATION GROUP BY N_NAME HAVING MAX(N_REGIONKEY) > 10",
......@@ -121,9 +127,49 @@ func TestJoinQuery(t *testing.T) {
runTestShouldPass(mockOptimizer, t, sqls)
}
// Nested query
// Nested query <no pass>
func TestNestedQuery(t *testing.T) {
sqls := []string{
"explain verbose SELECT * FROM NATION where N_REGIONKEY > (select max(R_REGIONKEY) from REGION)",
"explain SELECT * FROM NATION where N_REGIONKEY > (select max(R_REGIONKEY) from REGION where R_REGIONKEY < N_REGIONKEY)",
`explain verbose select
sum(l_extendedprice) / 7.0 as avg_yearly
from
lineitem,
part
where
p_partkey = l_partkey
and p_brand = 'Brand#54'
and p_container = 'LG BAG'
and l_quantity < (
select
0.2 * avg(l_quantity)
from
lineitem
where
l_partkey = p_partkey
);`, //tpch q17
}
mockOptimizer := plan2.NewMockOptimizer()
runTestShouldPass(mockOptimizer, t, sqls)
}
// Test Derived Table Query
func TestDerivedTableQuery(t *testing.T) {
sqls := []string{
"explain select c_custkey from (select c_custkey from CUSTOMER group by c_custkey ) a",
"explain verbose select c_custkey from (select c_custkey from CUSTOMER group by c_custkey ) a",
"explain select c_custkey from (select c_custkey, count(C_NATIONKEY) ff from CUSTOMER group by c_custkey ) a where ff > 0 order by c_custkey",
"explain verbose select c_custkey from (select c_custkey, count(C_NATIONKEY) ff from CUSTOMER group by c_custkey ) a where ff > 0 order by c_custkey",
"explain select c_custkey from (select c_custkey, count(C_NATIONKEY) ff from CUSTOMER group by c_custkey ) a join NATION b on a.c_custkey = b.N_REGIONKEY where b.N_NATIONKEY > 10",
"explain verbose select c_custkey from (select c_custkey, count(C_NATIONKEY) ff from CUSTOMER group by c_custkey ) a join NATION b on a.c_custkey = b.N_REGIONKEY where b.N_NATIONKEY > 10",
"explain select a.* from (select c_custkey, count(C_NATIONKEY) ff from CUSTOMER group by c_custkey ) a join NATION b on a.c_custkey = b.N_REGIONKEY where b.N_NATIONKEY > 10",
"explain verbose select a.* from (select c_custkey, count(C_NATIONKEY) ff from CUSTOMER group by c_custkey ) a join NATION b on a.c_custkey = b.N_REGIONKEY where b.N_NATIONKEY > 10",
"explain select * from (select c_custkey, count(C_NATIONKEY) ff from CUSTOMER group by c_custkey ) a join NATION b on a.c_custkey = b.N_REGIONKEY where b.N_NATIONKEY > 10",
"explain verbose select * from (select c_custkey, count(C_NATIONKEY) ff from CUSTOMER group by c_custkey ) a join NATION b on a.c_custkey = b.N_REGIONKEY where b.N_NATIONKEY > 10",
}
mockOptimizer := plan2.NewMockOptimizer()
runTestShouldPass(mockOptimizer, t, sqls)
}
// Collection query
......@@ -131,6 +177,45 @@ func TestCollectionQuery(t *testing.T) {
}
func TestDMLInsert(t *testing.T) {
sqls := []string{
"explain INSERT NATION VALUES (1, 'NAME1',21, 'COMMENT1'), (2, 'NAME2', 22, 'COMMENT2')",
"explain verbose INSERT NATION VALUES (1, 'NAME1',21, 'COMMENT1'), (2, 'NAME2', 22, 'COMMENT2')",
"explain INSERT NATION (N_NATIONKEY, N_REGIONKEY, N_NAME) VALUES (1, 21, 'NAME1'), (2, 22, 'NAME2')",
"explain verbose INSERT NATION (N_NATIONKEY, N_REGIONKEY, N_NAME) VALUES (1, 21, 'NAME1'), (2, 22, 'NAME2')",
"explain INSERT INTO NATION SELECT * FROM NATION2",
"explain verbose INSERT INTO NATION SELECT * FROM NATION2",
}
mockOptimizer := plan2.NewMockOptimizer()
runTestShouldPass(mockOptimizer, t, sqls)
}
func TestDMLUpdate(t *testing.T) {
sqls := []string{
"explain UPDATE NATION SET N_NAME ='U1', N_REGIONKEY=2",
"explain verbose UPDATE NATION SET N_NAME ='U1', N_REGIONKEY=2",
"explain UPDATE NATION SET N_NAME ='U1', N_REGIONKEY=2 WHERE N_NATIONKEY > 10 LIMIT 20",
"explain verbose UPDATE NATION SET N_NAME ='U1', N_REGIONKEY=2 WHERE N_NATIONKEY > 10 LIMIT 20",
"explain UPDATE NATION SET N_NAME ='U1', N_REGIONKEY=N_REGIONKEY+2 WHERE N_NATIONKEY > 10 LIMIT 20",
"explain verbose UPDATE NATION SET N_NAME ='U1', N_REGIONKEY=N_REGIONKEY+2 WHERE N_NATIONKEY > 10 LIMIT 20",
}
mockOptimizer := plan2.NewMockOptimizer()
runTestShouldPass(mockOptimizer, t, sqls)
}
func TestDMLDelete(t *testing.T) {
sqls := []string{
"explain DELETE FROM NATION",
"explain verbose DELETE FROM NATION",
"explain DELETE FROM NATION WHERE N_NATIONKEY > 10",
"explain verbose DELETE FROM NATION WHERE N_NATIONKEY > 10",
"explain DELETE FROM NATION WHERE N_NATIONKEY > 10 LIMIT 20",
"explain verbose DELETE FROM NATION WHERE N_NATIONKEY > 10 LIMIT 20",
}
mockOptimizer := plan2.NewMockOptimizer()
runTestShouldPass(mockOptimizer, t, sqls)
}
func runTestShouldPass(opt plan2.Optimizer, t *testing.T, sqls []string) {
for _, sql := range sqls {
err := runOneStmt(opt, t, sql)
......@@ -141,19 +226,14 @@ func runTestShouldPass(opt plan2.Optimizer, t *testing.T, sqls []string) {
}
func runOneStmt(opt plan2.Optimizer, t *testing.T, sql string) error {
// t.Logf("SQL: %v\n", sql)
t.Logf("SQL: %v\n", sql)
stmts, err := mysql.Parse(sql)
if err != nil {
t.Fatalf("%+v", err)
}
if stmt, ok := stmts[0].(*tree.ExplainStmt); ok {
es := &ExplainOptions{
Verbose: false,
Anzlyze: false,
Format: EXPLAIN_FORMAT_TEXT,
}
es := NewExplainDefaultOptions()
for _, v := range stmt.Options {
if strings.EqualFold(v.Name, "VERBOSE") {
if strings.EqualFold(v.Value, "TRUE") || v.Value == "NULL" {
......@@ -190,13 +270,16 @@ func runOneStmt(opt plan2.Optimizer, t *testing.T, sql string) error {
ctx := opt.CurrentContext()
logicPlan, err := plan2.BuildPlan(ctx, stmt.Statement)
if err != nil {
fmt.Printf("Build Query Plan error: '%v'", tree.String(stmt, dialect.MYSQL))
t.Errorf("Build Query Plan error: '%v'", tree.String(stmt, dialect.MYSQL))
return err
}
buffer := NewExplainDataBuffer()
explainQuery := NewExplainQueryImpl(logicPlan.GetQuery())
explainQuery.ExplainPlan(buffer, es)
// t.Logf("\n")
err = explainQuery.ExplainPlan(buffer, es)
if err != nil {
t.Errorf("explain Query Plan error: '%v'", tree.String(stmt, dialect.MYSQL))
return err
}
}
return nil
}
// Copyright 2021 - 2022 Matrix Origin
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package explain
import (
"fmt"
"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
"github.com/matrixorigin/matrixone/pkg/sql/plan2"
"os"
"path/filepath"
"runtime"
"testing"
"github.com/matrixorigin/matrixone/pkg/sql/parsers"
"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect"
)
func Test_TPCH_Plan2(t *testing.T) {
mock := plan2.NewMockOptimizer()
es := &ExplainOptions{
Verbose: true,
Anzlyze: false,
Format: EXPLAIN_FORMAT_TEXT,
}
_, fn, _, _ := runtime.Caller(0)
dir := filepath.Dir(filepath.Dir(fn))
ddlf, err := os.ReadFile(dir + "/tpch/ddl.sql")
if err != nil {
t.Errorf("Cannot open ddl file, error %v", err)
}
ddls, err := parsers.Parse(dialect.MYSQL, string(ddlf))
if ddls == nil || err != nil {
t.Errorf("DDL Parser failed, error %v", err)
}
/*
BROKEN: Will crash.
for _, ast := range ddls {
_, err := mock.Optimize(ast)
if err == nil {
t.Logf("Optimizer failed, NYI")
}
}
*/
//test simple sql
qf, err := os.ReadFile(dir + "/tpch/simple.sql")
t.Logf("# tpch file: /tpch/simple.sql")
if err != nil {
t.Errorf("Cannot open queries file, error %v", err)
}
qs, err := parsers.Parse(dialect.MYSQL, string(qf))
if qs == nil || err != nil {
t.Errorf("Query Parser failed, error %v", err)
}
for _, ast := range qs {
out := tree.String(ast, dialect.MYSQL)
t.Logf("SQL: %v\n", out)
query, err := mock.Optimize(ast)
if err != nil {
t.Errorf("Optimizer failed, NYI")
}
buffer := NewExplainDataBuffer()
explainQuery := NewExplainQueryImpl(query)
err = explainQuery.ExplainPlan(buffer, es)
if err != nil {
t.Errorf("explain failed, WXL")
}
}
//test tpch query
for qn := 1; qn <= 22; qn += 1 {
//qn := 15
qnf, err := os.ReadFile(fmt.Sprintf("%s/tpch/q%d.sql", dir, qn))
if err != nil {
t.Errorf("Cannot open file of query %d, error %v", qn, err)
}
t.Logf("--<%d> tpch file: %s/tpch/q%d.sql\n", qn, dir, qn)
t.Logf("SQL : %v \n", string(qnf))
qns, err := parsers.Parse(dialect.MYSQL, string(qnf))
if qns == nil || err != nil {
t.Errorf("Query %d Parser failed, error %v", qn, err)
}
for _, ast := range qns {
query, err := mock.Optimize(ast)
if err != nil {
t.Errorf("Optimizer %d failed, error %v", qn, err)
}
buffer := NewExplainDataBuffer()
explainQuery := NewExplainQueryImpl(query)
err = explainQuery.ExplainPlan(buffer, es)
if err != nil {
t.Errorf("explain failed, WXL")
}
}
}
}
// Copyright 2021 Matrix Origin
// Copyright 2021 - 2022 Matrix Origin
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
......@@ -15,41 +15,27 @@
package explain
import (
"fmt"
"github.com/matrixorigin/matrixone/pkg/logutil"
"strings"
"github.com/matrixorigin/matrixone/pkg/pb/plan"
)
//type TableDef plan.TableDef
//type ObjectRef plan.ObjectRef
type Cost plan.Cost
type Const plan.Const
//type Expr plan.Expr
//type Node plan.Node
type RowsetData plan.RowsetData
//type Query plan.Query
type ExplainQuery interface {
ExplainPlan(buffer *ExplainDataBuffer, options *ExplainOptions)
ExplainAnalyze(buffer *ExplainDataBuffer, options *ExplainOptions)
ExplainPlan(buffer *ExplainDataBuffer, options *ExplainOptions) error
ExplainAnalyze(buffer *ExplainDataBuffer, options *ExplainOptions) error
}
type NodeDescribe interface {
GetNodeBasicInfo(options *ExplainOptions) string
GetExtraInfo(options *ExplainOptions) []string
GetProjectListInfo(options *ExplainOptions) string
GetJoinConditionInfo(options *ExplainOptions) string
GetWhereConditionInfo(options *ExplainOptions) string
GetOrderByInfo(options *ExplainOptions) string
GetGroupByInfo(options *ExplainOptions) string
GetNodeBasicInfo(options *ExplainOptions) (string, error)
GetExtraInfo(options *ExplainOptions) ([]string, error)
GetProjectListInfo(options *ExplainOptions) (string, error)
GetJoinConditionInfo(options *ExplainOptions) (string, error)
GetWhereConditionInfo(options *ExplainOptions) (string, error)
GetOrderByInfo(options *ExplainOptions) (string, error)
GetGroupByInfo(options *ExplainOptions) (string, error)
}
type NodeElemDescribe interface {
GetDescription(options *ExplainOptions) string
GetDescription(options *ExplainOptions) (string, error)
}
type FormatSettings struct {
......@@ -60,12 +46,11 @@ type FormatSettings struct {
}
type ExplainDataBuffer struct {
Start int
End int
CurrentLine int
NodeSize int
LineWidthLimit int
Lines []string
Start int
End int
CurrentLine int
NodeSize int
Lines []string
}
func NewExplainDataBuffer() *ExplainDataBuffer {
......@@ -78,11 +63,6 @@ func NewExplainDataBuffer() *ExplainDataBuffer {
}
}
// Generates a string describing a ExplainDataBuffer.
func (buf *ExplainDataBuffer) ToString() string {
return fmt.Sprintf("ExplainDataBuffer{start: %d, end: %d, lines: %s, NodeSize: %d}", buf.Start, buf.End, buf.Lines, buf.NodeSize)
}
func (buf *ExplainDataBuffer) AppendCurrentLine(temp string) {
if buf.CurrentLine != -1 && buf.CurrentLine < len(buf.Lines) {
buf.Lines[buf.CurrentLine] += temp
......@@ -120,20 +100,10 @@ func (buf *ExplainDataBuffer) PushNewLine(line string, isNewNode bool, level int
}
buf.CurrentLine++
buf.Lines = append(buf.Lines, prefix+line)
// logutil.Infof(buf.Lines[buf.CurrentLine])
logutil.Infof(buf.Lines[buf.CurrentLine])
buf.End++
}
func (buf *ExplainDataBuffer) IsFull() bool {
return false
//TODO
}
func (buf *ExplainDataBuffer) Empty() bool {
return false
//TODO
}
type ExplainFormat int32
const (
......@@ -149,14 +119,10 @@ type ExplainOptions struct {
Format ExplainFormat
}
func NewExplainPlanOptions() *ExplainOptions {
return nil
}
type QueryPlanSetting struct {
Name string
Optimize bool
JSON bool
DOT bool
QueryPlanOptions ExplainOptions
func NewExplainDefaultOptions() *ExplainOptions {
return &ExplainOptions{
Verbose: false,
Anzlyze: false,
Format: EXPLAIN_FORMAT_TEXT,
}
}
......@@ -43,27 +43,31 @@ import (
type FunctionSig struct {
Name string
Flag plan.Function_FuncFlag
Kind FunctionKind
Layout FuncExplainLayout
ArgTypeClass []plan.Type_TypeId
ArgType []int8
}
type FunctionKind int32
type FuncExplainLayout int32
const (
STANDARD_FUNCTION FunctionKind = 0
UNARY_ARITHMETIC_OPERATOR FunctionKind = 1
BINARY_ARITHMETIC_OPERATOR FunctionKind = 2
UNARY_LOGICAL_OPERATOR FunctionKind = 3
BINARY_LOGICAL_OPERATOR FunctionKind = 4
COMPARISON_OPERATOR FunctionKind = 5
CAST_EXPRESSION FunctionKind = 6
CASE_WHEN_EXPRESSION FunctionKind = 7
BETWEEN_AND_EXPRESSION FunctionKind = 8
IN_EXISTS_EXPRESSION FunctionKind = 9
IS_NULL_EXPRESSION FunctionKind = 10
NOPARAMETER_FUNCTION FunctionKind = 11
UNKNOW_KIND_FUNCTION FunctionKind = 12
STANDARD_FUNCTION FuncExplainLayout = 0 //standard function
UNARY_ARITHMETIC_OPERATOR FuncExplainLayout = 1 //unary arithmetic operator
BINARY_ARITHMETIC_OPERATOR FuncExplainLayout = 2 //binary arithmetic operator
UNARY_LOGICAL_OPERATOR FuncExplainLayout = 3 // unary logical operator
BINARY_LOGICAL_OPERATOR FuncExplainLayout = 4 // binary logical operator
COMPARISON_OPERATOR FuncExplainLayout = 5 // comparison operator
CAST_EXPRESSION FuncExplainLayout = 6 // cast expression
CASE_WHEN_EXPRESSION FuncExplainLayout = 7 // case when expression
BETWEEN_AND_EXPRESSION FuncExplainLayout = 8
IN_PREDICATE FuncExplainLayout = 9 //query 'in' predicate
EXISTS_ANY_PREDICATE FuncExplainLayout = 10 //query predicate,such as exist,all,any
IS_NULL_EXPRESSION FuncExplainLayout = 11 // is null expression
NOPARAMETER_FUNCTION FuncExplainLayout = 12 // noparameter function
DATE_INTERVAL_EXPRESSION FuncExplainLayout = 13 // date expression,interval expression
EXTRACT_FUNCTION FuncExplainLayout = 14 // extract function,such as extract(MONTH/DAY/HOUR/MINUTE/SECOND FROM p)
POSITION_FUNCTION FuncExplainLayout = 15 // position function, such as POSITION(substr IN str)
UNKNOW_KIND_FUNCTION FuncExplainLayout = 16
)
// Functions shipped by system.
......@@ -144,8 +148,8 @@ var BuiltinFunctions = [...]*FunctionSig{
{"DATEDIFF", plan.Function_STRICT, STANDARD_FUNCTION, []plan.Type_TypeId{plan.Type_INT64, plan.Type_VARCHAR, plan.Type_ANYTIME}, []int8{1, 2, 2}},
{"DENSE_RANK", plan.Function_WIN, STANDARD_FUNCTION, []plan.Type_TypeId{plan.Type_INT32}, []int8{}},
{"ENDSWITH", plan.Function_STRICT, UNKNOW_KIND_FUNCTION, []plan.Type_TypeId{plan.Type_BOOL, plan.Type_VARCHAR}, []int8{1, 1}},
{"EXP", plan.Function_STRICT, UNKNOW_KIND_FUNCTION, []plan.Type_TypeId{plan.Type_FLOAT64}, []int8{0}},
{"ENDSWITH", plan.Function_STRICT, STANDARD_FUNCTION, []plan.Type_TypeId{plan.Type_BOOL, plan.Type_VARCHAR}, []int8{1, 1}},
{"EXP", plan.Function_STRICT, STANDARD_FUNCTION, []plan.Type_TypeId{plan.Type_FLOAT64}, []int8{0}},
{"FIRST_VALUE", plan.Function_AGG, STANDARD_FUNCTION, []plan.Type_TypeId{plan.Type_ANY}, []int8{0}},
{"FLOOR", plan.Function_STRICT, STANDARD_FUNCTION, []plan.Type_TypeId{plan.Type_ANYNUMBER, plan.Type_INT32}, []int8{0, -1}},
......@@ -163,7 +167,7 @@ var BuiltinFunctions = [...]*FunctionSig{
{"ILIKE", plan.Function_STRICT, UNKNOW_KIND_FUNCTION, []plan.Type_TypeId{plan.Type_BOOL, plan.Type_VARCHAR}, []int8{1, 1}},
{"ILIKE_ALL", plan.Function_STRICT | plan.Function_VARARG, UNKNOW_KIND_FUNCTION, []plan.Type_TypeId{plan.Type_VARCHAR}, []int8{0, 0}},
{"ILIKE_ANY", plan.Function_STRICT | plan.Function_VARARG, UNKNOW_KIND_FUNCTION, []plan.Type_TypeId{plan.Type_VARCHAR}, []int8{0, 0}},
{"IN", plan.Function_STRICT, STANDARD_FUNCTION, []plan.Type_TypeId{plan.Type_BOOL, plan.Type_ANY, plan.Type_ARRAY}, []int8{1, 2}},
{"IN", plan.Function_STRICT, IN_PREDICATE, []plan.Type_TypeId{plan.Type_BOOL, plan.Type_ANY, plan.Type_ARRAY}, []int8{1, 2}},
{"LAG", plan.Function_WIN, STANDARD_FUNCTION, []plan.Type_TypeId{plan.Type_ANY, plan.Type_INT32, plan.Type_ANY}, []int8{1, 2}},
{"LAST_VALUE", plan.Function_AGG, STANDARD_FUNCTION, []plan.Type_TypeId{plan.Type_ANY}, []int8{0}},
......@@ -190,8 +194,8 @@ var BuiltinFunctions = [...]*FunctionSig{
{"NTILE", plan.Function_WIN, UNKNOW_KIND_FUNCTION, []plan.Type_TypeId{plan.Type_INT32}, []int8{0}},
{"NULLIF", plan.Function_WIN, UNKNOW_KIND_FUNCTION, []plan.Type_TypeId{plan.Type_ANY}, []int8{0, 0}},
{"PERCENT_RANK", plan.Function_WIN, UNKNOW_KIND_FUNCTION, []plan.Type_TypeId{plan.Type_INT32}, []int8{}},
{"POSITION", plan.Function_STRICT, UNKNOW_KIND_FUNCTION, []plan.Type_TypeId{plan.Type_INT32, plan.Type_VARCHAR}, []int8{1, 1, 0}},
{"PERCENT_RANK", plan.Function_WIN, STANDARD_FUNCTION, []plan.Type_TypeId{plan.Type_INT32}, []int8{}},
{"POSITION", plan.Function_STRICT, POSITION_FUNCTION, []plan.Type_TypeId{plan.Type_INT32, plan.Type_VARCHAR}, []int8{1, 1, 0}},
{"POW", plan.Function_STRICT, STANDARD_FUNCTION, []plan.Type_TypeId{plan.Type_FLOAT64}, []int8{0, 0}},
{"RADIAN", plan.Function_STRICT, STANDARD_FUNCTION, []plan.Type_TypeId{plan.Type_FLOAT64}, []int8{0}},
......@@ -225,17 +229,17 @@ var BuiltinFunctions = [...]*FunctionSig{
{"UNIFORM", plan.Function_VOLATILE, STANDARD_FUNCTION, []plan.Type_TypeId{plan.Type_FLOAT64}, []int8{0, 0}},
{"UPPER", plan.Function_STRICT, STANDARD_FUNCTION, []plan.Type_TypeId{plan.Type_VARCHAR}, []int8{0}},
{"VAR_POP", plan.Function_AGG, UNKNOW_KIND_FUNCTION, []plan.Type_TypeId{plan.Type_FLOAT64}, []int8{0}},
{"VAR_SAMPLE", plan.Function_AGG, UNKNOW_KIND_FUNCTION, []plan.Type_TypeId{plan.Type_FLOAT64}, []int8{0}},
{"VAR_POP", plan.Function_AGG, STANDARD_FUNCTION, []plan.Type_TypeId{plan.Type_FLOAT64}, []int8{0}},
{"VAR_SAMPLE", plan.Function_AGG, STANDARD_FUNCTION, []plan.Type_TypeId{plan.Type_FLOAT64}, []int8{0}},
//add for subquery
{"EXISTS", plan.Function_STRICT, IN_EXISTS_EXPRESSION, []plan.Type_TypeId{plan.Type_BOOL, plan.Type_ARRAY}, []int8{1}},
{"ALL", plan.Function_STRICT, UNKNOW_KIND_FUNCTION, []plan.Type_TypeId{plan.Type_BOOL, plan.Type_ARRAY}, []int8{1}},
{"ANY", plan.Function_STRICT, UNKNOW_KIND_FUNCTION, []plan.Type_TypeId{plan.Type_BOOL, plan.Type_ARRAY}, []int8{1}},
{"EXISTS", plan.Function_STRICT, EXISTS_ANY_PREDICATE, []plan.Type_TypeId{plan.Type_BOOL, plan.Type_ARRAY}, []int8{1}},
{"ALL", plan.Function_STRICT, EXISTS_ANY_PREDICATE, []plan.Type_TypeId{plan.Type_BOOL, plan.Type_ARRAY}, []int8{1}},
{"ANY", plan.Function_STRICT, EXISTS_ANY_PREDICATE, []plan.Type_TypeId{plan.Type_BOOL, plan.Type_ARRAY}, []int8{1}},
//add for tpch
{"DATE", plan.Function_STRICT, UNKNOW_KIND_FUNCTION, []plan.Type_TypeId{plan.Type_DATE, plan.Type_VARCHAR}, []int8{1}},
{"INTERVAL", plan.Function_STRICT, UNKNOW_KIND_FUNCTION, []plan.Type_TypeId{plan.Type_INTERVAL, plan.Type_VARCHAR}, []int8{1}},
{"EXTRACT", plan.Function_STRICT, UNKNOW_KIND_FUNCTION, []plan.Type_TypeId{plan.Type_ANYTIME, plan.Type_VARCHAR}, []int8{1, 0}},
{"SUBSTRING", plan.Function_STRICT, UNKNOW_KIND_FUNCTION, []plan.Type_TypeId{plan.Type_VARCHAR, plan.Type_ANYINT}, []int8{0, 1, 1}},
{"DATE", plan.Function_STRICT, DATE_INTERVAL_EXPRESSION, []plan.Type_TypeId{plan.Type_DATE, plan.Type_VARCHAR}, []int8{1}},
{"INTERVAL", plan.Function_STRICT, DATE_INTERVAL_EXPRESSION, []plan.Type_TypeId{plan.Type_INTERVAL, plan.Type_VARCHAR}, []int8{1}},
{"EXTRACT", plan.Function_STRICT, EXTRACT_FUNCTION, []plan.Type_TypeId{plan.Type_ANYTIME, plan.Type_VARCHAR}, []int8{1, 0}},
{"SUBSTRING", plan.Function_STRICT, STANDARD_FUNCTION, []plan.Type_TypeId{plan.Type_VARCHAR, plan.Type_ANYINT}, []int8{0, 1, 1}},
}
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment