github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/plan/explain/explain_expr.go (about)

     1  // Copyright 2021 - 2022 Matrix Origin
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package explain
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  	"strconv"
    21  
    22  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    23  	"github.com/matrixorigin/matrixone/pkg/container/types"
    24  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    25  	"github.com/matrixorigin/matrixone/pkg/sql/plan/function"
    26  )
    27  
    28  func describeExpr(ctx context.Context, expr *plan.Expr, options *ExplainOptions) (string, error) {
    29  	var result string
    30  
    31  	switch exprImpl := expr.Expr.(type) {
    32  	case *plan.Expr_Col:
    33  		if len(exprImpl.Col.Name) > 0 {
    34  			result += exprImpl.Col.Name
    35  		} else {
    36  			result += "#["
    37  			result += strconv.FormatInt(int64(exprImpl.Col.RelPos), 10)
    38  			result += ","
    39  			result += strconv.FormatInt(int64(exprImpl.Col.ColPos), 10)
    40  			result += "]"
    41  		}
    42  	case *plan.Expr_C:
    43  		if exprImpl.C.Isnull {
    44  			result += "(null)"
    45  			break
    46  		}
    47  
    48  		switch val := exprImpl.C.Value.(type) {
    49  		case *plan.Const_I8Val:
    50  			result += strconv.FormatInt(int64(val.I8Val), 10)
    51  		case *plan.Const_I16Val:
    52  			result += strconv.FormatInt(int64(val.I16Val), 10)
    53  		case *plan.Const_I32Val:
    54  			result += strconv.FormatInt(int64(val.I32Val), 10)
    55  		case *plan.Const_I64Val:
    56  			result += strconv.FormatInt(val.I64Val, 10)
    57  		case *plan.Const_U8Val:
    58  			result += strconv.FormatUint(uint64(val.U8Val), 10)
    59  		case *plan.Const_U16Val:
    60  			result += strconv.FormatUint(uint64(val.U16Val), 10)
    61  		case *plan.Const_U32Val:
    62  			result += strconv.FormatUint(uint64(val.U32Val), 10)
    63  		case *plan.Const_U64Val:
    64  			result += strconv.FormatUint(val.U64Val, 10)
    65  
    66  		case *plan.Const_Fval:
    67  			result += strconv.FormatFloat(float64(val.Fval), 'f', -1, 32)
    68  
    69  		case *plan.Const_Dval:
    70  			result += strconv.FormatFloat(val.Dval, 'f', -1, 64)
    71  
    72  		case *plan.Const_Sval:
    73  			result += "'" + val.Sval + "'"
    74  
    75  		case *plan.Const_Bval:
    76  			result += strconv.FormatBool(val.Bval)
    77  		}
    78  
    79  	case *plan.Expr_F:
    80  		funcExpr := expr.Expr.(*plan.Expr_F)
    81  		funcDesc, err := funcExprExplain(ctx, funcExpr, expr.Typ, options)
    82  		if err != nil {
    83  			return result, err
    84  		}
    85  		result += funcDesc
    86  	case *plan.Expr_Sub:
    87  		subqryExpr := expr.Expr.(*plan.Expr_Sub)
    88  		result += "subquery nodeId = " + strconv.FormatInt(int64(subqryExpr.Sub.NodeId), 10)
    89  	case *plan.Expr_Corr:
    90  		result += "#["
    91  		result += strconv.FormatInt(int64(exprImpl.Corr.RelPos), 10)
    92  		result += ","
    93  		result += strconv.FormatInt(int64(exprImpl.Corr.ColPos), 10)
    94  		result += ":"
    95  		result += strconv.FormatInt(int64(exprImpl.Corr.Depth), 10)
    96  		result += "]"
    97  	case *plan.Expr_V:
    98  		if exprImpl.V.System {
    99  			if exprImpl.V.Global {
   100  				result += "@@global." + exprImpl.V.Name
   101  			} else {
   102  				result += "@@session." + exprImpl.V.Name
   103  			}
   104  		} else {
   105  			result += "@" + exprImpl.V.Name
   106  		}
   107  	case *plan.Expr_P:
   108  		panic("unimplement Expr_P")
   109  	case *plan.Expr_List:
   110  		exprlist := expr.Expr.(*plan.Expr_List)
   111  		if exprlist.List.List != nil {
   112  			exprListDescImpl := NewExprListDescribeImpl(exprlist.List.List)
   113  			desclist, err := exprListDescImpl.GetDescription(ctx, options)
   114  			if err != nil {
   115  				return result, err
   116  			}
   117  			result += desclist
   118  		}
   119  	default:
   120  		panic("error Expr")
   121  	}
   122  
   123  	return result, nil
   124  }
   125  
   126  // generator function expression(Expr_F) explain information
   127  func funcExprExplain(ctx context.Context, funcExpr *plan.Expr_F, Typ *plan.Type, options *ExplainOptions) (string, error) {
   128  	// SysFunsAndOperatorsMap
   129  	var result string
   130  	funcName := funcExpr.F.GetFunc().GetObjName()
   131  	funcDef := funcExpr.F.GetFunc()
   132  
   133  	funcProtoType, err := function.GetFunctionByID(ctx, funcDef.Obj&function.DistinctMask)
   134  	if err != nil {
   135  		return result, moerr.NewInvalidInput(ctx, "invalid function or opreator '%s'", funcName)
   136  	}
   137  
   138  	switch funcProtoType.GetLayout() {
   139  	case function.STANDARD_FUNCTION:
   140  		result += funcExpr.F.Func.GetObjName() + "("
   141  		if len(funcExpr.F.Args) > 0 {
   142  			var first = true
   143  			for _, v := range funcExpr.F.Args {
   144  				if !first {
   145  					result += ", "
   146  				}
   147  				first = false
   148  				exprDesc, err := describeExpr(ctx, v, options)
   149  				if err != nil {
   150  					return result, err
   151  				}
   152  				result += exprDesc
   153  			}
   154  		}
   155  		result += ")"
   156  	case function.UNARY_ARITHMETIC_OPERATOR:
   157  		var opertator string
   158  		if funcExpr.F.Func.GetObjName() == "UNARY_PLUS" {
   159  			opertator = "+"
   160  		} else {
   161  			opertator = "-"
   162  		}
   163  		describeExpr, err := describeExpr(ctx, funcExpr.F.Args[0], options)
   164  		if err != nil {
   165  			return result, err
   166  		}
   167  		result += "(" + opertator + describeExpr + ")"
   168  	case function.UNARY_LOGICAL_OPERATOR:
   169  		describeExpr, err := describeExpr(ctx, funcExpr.F.Args[0], options)
   170  		if err != nil {
   171  			return result, err
   172  		}
   173  		result += "(" + funcExpr.F.Func.GetObjName() + " " + describeExpr + ")"
   174  	case function.BINARY_ARITHMETIC_OPERATOR:
   175  		fallthrough
   176  	case function.BINARY_LOGICAL_OPERATOR:
   177  		fallthrough
   178  	case function.COMPARISON_OPERATOR:
   179  		left, err := describeExpr(ctx, funcExpr.F.Args[0], options)
   180  		if err != nil {
   181  			return result, err
   182  		}
   183  		right, err := describeExpr(ctx, funcExpr.F.Args[1], options)
   184  		if err != nil {
   185  			return result, err
   186  		}
   187  		result += "(" + left + " " + funcExpr.F.Func.GetObjName() + " " + right + ")"
   188  	case function.CAST_EXPRESSION:
   189  		describeExpr, err := describeExpr(ctx, funcExpr.F.Args[0], options)
   190  		if err != nil {
   191  			return result, err
   192  		}
   193  		tt := types.T(Typ.Id)
   194  		if tt == types.T_decimal64 || tt == types.T_decimal128 {
   195  			result += fmt.Sprintf("CAST(%s AS %s(%d, %d))", describeExpr, tt.String(), Typ.Precision, Typ.Scale)
   196  		} else {
   197  			result += "CAST(" + describeExpr + " AS " + tt.String() + ")"
   198  		}
   199  	case function.CASE_WHEN_EXPRESSION:
   200  		// TODO need rewrite to deal with case is nil
   201  		result += "CASE"
   202  		// case when expression has two part(case when condition and else exression)
   203  		condSize := len(funcExpr.F.Args) / 2
   204  		for i := 0; i < condSize; i++ {
   205  			whenExpr := funcExpr.F.Args[i]
   206  			thenExpr := funcExpr.F.Args[i+1]
   207  			whenExprDesc, err := describeExpr(ctx, whenExpr, options)
   208  			if err != nil {
   209  				return result, err
   210  			}
   211  			thenExprDesc, err := describeExpr(ctx, thenExpr, options)
   212  			if err != nil {
   213  				return result, err
   214  			}
   215  			result += " WHEN " + whenExprDesc + " THEN " + thenExprDesc
   216  		}
   217  
   218  		if len(funcExpr.F.Args)%2 == 1 {
   219  			lastIndex := len(funcExpr.F.Args) - 1
   220  			elseExpr := funcExpr.F.Args[lastIndex]
   221  			// get else expression
   222  			elseExprDesc, err := describeExpr(ctx, elseExpr, options)
   223  			if err != nil {
   224  				return result, err
   225  			}
   226  			result += " ELSE " + elseExprDesc
   227  		}
   228  		result += " END"
   229  	case function.IN_PREDICATE:
   230  		if len(funcExpr.F.Args) != 2 {
   231  			panic("Nested query predicate,such as in,exist,all,any parameter number error!")
   232  		}
   233  		descExpr, err := describeExpr(ctx, funcExpr.F.Args[0], options)
   234  		if err != nil {
   235  			return result, err
   236  		}
   237  		descExprlist, err := describeExpr(ctx, funcExpr.F.Args[1], options)
   238  		if err != nil {
   239  			return result, err
   240  		}
   241  		result += descExpr + " " + funcExpr.F.Func.GetObjName() + "(" + descExprlist + ")"
   242  	case function.EXISTS_ANY_PREDICATE:
   243  		describeExpr, err := describeExpr(ctx, funcExpr.F.Args[0], options)
   244  		if err != nil {
   245  			return result, err
   246  		}
   247  		result += funcExpr.F.Func.GetObjName() + "(" + describeExpr + ")"
   248  	case function.IS_NULL_EXPRESSION:
   249  		describeExpr, err := describeExpr(ctx, funcExpr.F.Args[0], options)
   250  		if err != nil {
   251  			return result, err
   252  		}
   253  		result += "(" + describeExpr + " IS NULL)"
   254  	case function.NOPARAMETER_FUNCTION:
   255  		result += funcExpr.F.Func.GetObjName()
   256  	case function.DATE_INTERVAL_EXPRESSION:
   257  		describeExpr, err := describeExpr(ctx, funcExpr.F.Args[0], options)
   258  		if err != nil {
   259  			return result, err
   260  		}
   261  		result += funcExpr.F.Func.GetObjName() + " " + describeExpr + ""
   262  	case function.EXTRACT_FUNCTION:
   263  		first, err := describeExpr(ctx, funcExpr.F.Args[0], options)
   264  		if err != nil {
   265  			return result, err
   266  		}
   267  		second, err := describeExpr(ctx, funcExpr.F.Args[1], options)
   268  		if err != nil {
   269  			return result, err
   270  		}
   271  
   272  		result += funcExpr.F.Func.GetObjName() + "(" + first + " from " + second + ")"
   273  	case function.UNKNOW_KIND_FUNCTION:
   274  		return result, moerr.NewInvalidInput(ctx, "explain contains UNKNOW_KIND_FUNCTION")
   275  	}
   276  	return result, nil
   277  }