github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/build_expr_test.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 plan
    16  
    17  import (
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/matrixorigin/matrixone/pkg/container/batch"
    22  	"github.com/matrixorigin/matrixone/pkg/sql/colexec"
    23  	"github.com/matrixorigin/matrixone/pkg/testutil"
    24  	"github.com/stretchr/testify/require"
    25  
    26  	"github.com/matrixorigin/matrixone/pkg/common/moerr"
    27  	"github.com/matrixorigin/matrixone/pkg/container/types"
    28  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    29  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect/mysql"
    30  	"github.com/smartystreets/goconvey/convey"
    31  )
    32  
    33  func TestExpr_1(t *testing.T) {
    34  	convey.Convey("selectAndStmt succ", t, func() {
    35  		mock := NewMockOptimizer(false)
    36  		params := []bool{false, true}
    37  		input := []string{"select 0 and 1 from dual;",
    38  			"select false and 1 from dual;",
    39  			"select false and true from dual;",
    40  			"select 0 and true from dual;"}
    41  
    42  		for i := 0; i < len(input); i++ {
    43  			pl, err := runOneExprStmt(mock, t, input[i])
    44  			if err != nil {
    45  				t.Fatalf("%+v", err)
    46  			}
    47  			query, ok := pl.Plan.(*plan.Plan_Query)
    48  			if !ok {
    49  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right"))
    50  			}
    51  			expr := query.Query.Nodes[1].ProjectList[0]
    52  			exprF, ok := expr.Expr.(*plan.Expr_F)
    53  			if !ok {
    54  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right"))
    55  			}
    56  			convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool)
    57  			convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, "and")
    58  			for j, arg := range exprF.F.Args {
    59  				convey.So(arg.Typ.Id, convey.ShouldEqual, types.T_bool)
    60  				exprC, ok := arg.Expr.(*plan.Expr_Lit)
    61  				if !ok {
    62  					t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right"))
    63  				}
    64  				constB, ok := exprC.Lit.Value.(*plan.Literal_Bval)
    65  				if !ok {
    66  					t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right"))
    67  				}
    68  				convey.So(constB.Bval, convey.ShouldEqual, params[j])
    69  			}
    70  		}
    71  	})
    72  }
    73  
    74  func TestExpr_2(t *testing.T) {
    75  	convey.Convey("selectORStmt succ", t, func() {
    76  		mock := NewMockOptimizer(false)
    77  		params := []bool{false, true}
    78  		input := []string{"select 0 or 1 from dual;",
    79  			"select false or 1 from dual;",
    80  			"select false or true from dual;",
    81  			"select 0 or true from dual;"}
    82  
    83  		for i := 0; i < len(input); i++ {
    84  			pl, err := runOneExprStmt(mock, t, input[i])
    85  			if err != nil {
    86  				t.Fatalf("%+v", err)
    87  			}
    88  			query, ok := pl.Plan.(*plan.Plan_Query)
    89  			if !ok {
    90  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right"))
    91  			}
    92  			expr := query.Query.Nodes[1].ProjectList[0]
    93  			exprF, ok := expr.Expr.(*plan.Expr_F)
    94  			if !ok {
    95  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right"))
    96  			}
    97  			convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool)
    98  			convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, "or")
    99  			for j, arg := range exprF.F.Args {
   100  				convey.So(arg.Typ.Id, convey.ShouldEqual, types.T_bool)
   101  				exprC, ok := arg.Expr.(*plan.Expr_Lit)
   102  				if !ok {
   103  					t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right"))
   104  				}
   105  				constB, ok := exprC.Lit.Value.(*plan.Literal_Bval)
   106  				if !ok {
   107  					t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right"))
   108  				}
   109  				convey.So(constB.Bval, convey.ShouldEqual, params[j])
   110  			}
   111  		}
   112  	})
   113  }
   114  
   115  func TestExpr_3(t *testing.T) {
   116  	convey.Convey("selectNotStmt succ", t, func() {
   117  		mock := NewMockOptimizer(false)
   118  		params := []bool{false, false, true, true}
   119  		input := []string{"select not 0 from dual;",
   120  			"select not false from dual;",
   121  			"select not 1 from dual;",
   122  			"select not true from dual;"}
   123  
   124  		for i := 0; i < len(input); i++ {
   125  			pl, err := runOneExprStmt(mock, t, input[i])
   126  			if err != nil {
   127  				t.Fatalf("%+v", err)
   128  			}
   129  			query, ok := pl.Plan.(*plan.Plan_Query)
   130  			if !ok {
   131  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right"))
   132  			}
   133  			expr := query.Query.Nodes[1].ProjectList[0]
   134  			exprF, ok := expr.Expr.(*plan.Expr_F)
   135  			if !ok {
   136  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right"))
   137  			}
   138  			convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool)
   139  			convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, "not")
   140  			for _, arg := range exprF.F.Args {
   141  				convey.So(arg.Typ.Id, convey.ShouldEqual, types.T_bool)
   142  				exprC, ok := arg.Expr.(*plan.Expr_Lit)
   143  				if !ok {
   144  					t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right"))
   145  				}
   146  				constB, ok := exprC.Lit.Value.(*plan.Literal_Bval)
   147  				if !ok {
   148  					t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right"))
   149  				}
   150  				convey.So(constB.Bval, convey.ShouldEqual, params[i])
   151  			}
   152  		}
   153  	})
   154  }
   155  
   156  func TestExpr_4(t *testing.T) {
   157  	convey.Convey("selectEqualStmt succ", t, func() {
   158  		mock := NewMockOptimizer(false)
   159  		// var params []bool = []bool{false, false, true, true}
   160  		input := []string{"select 0 = 1 from dual;",
   161  			"select 1 = 1 from dual;",
   162  			"select true = false from dual;",
   163  			"select true = 1 from dual;",
   164  			"select 0 = false from dual;"}
   165  
   166  		for i := 0; i < len(input); i++ {
   167  			pl, err := runOneExprStmt(mock, t, input[i])
   168  			if err != nil {
   169  				t.Fatalf("%+v", err)
   170  			}
   171  			query, ok := pl.Plan.(*plan.Plan_Query)
   172  			if !ok {
   173  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right"))
   174  			}
   175  			expr := query.Query.Nodes[1].ProjectList[0]
   176  			exprF, ok := expr.Expr.(*plan.Expr_F)
   177  			if !ok {
   178  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right"))
   179  			}
   180  			convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool)
   181  			convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, "=")
   182  		}
   183  	})
   184  }
   185  
   186  func TestExpr_5(t *testing.T) {
   187  	convey.Convey("selectLessStmt succ", t, func() {
   188  		mock := NewMockOptimizer(false)
   189  		// var params []bool = []bool{false, false, true, true}
   190  		input := []string{"select 0 < 1 from dual;",
   191  			"select 1 < 1 from dual;",
   192  			"select 1 < 0 from dual;"}
   193  
   194  		for i := 0; i < len(input); i++ {
   195  			pl, err := runOneExprStmt(mock, t, input[i])
   196  			if err != nil {
   197  				t.Fatalf("%+v", err)
   198  			}
   199  			query, ok := pl.Plan.(*plan.Plan_Query)
   200  			if !ok {
   201  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right"))
   202  			}
   203  			expr := query.Query.Nodes[1].ProjectList[0]
   204  			exprF, ok := expr.Expr.(*plan.Expr_F)
   205  			if !ok {
   206  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right"))
   207  			}
   208  			convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool)
   209  			convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, "<")
   210  		}
   211  	})
   212  }
   213  
   214  func TestExpr_6(t *testing.T) {
   215  	convey.Convey("selectLessEqualStmt succ", t, func() {
   216  		mock := NewMockOptimizer(false)
   217  		// var params []bool = []bool{false, false, true, true}
   218  		input := []string{"select 0 <= 1 from dual;",
   219  			"select 1 <= 1 from dual;",
   220  			"select 1 <= 0 from dual;"}
   221  
   222  		for i := 0; i < len(input); i++ {
   223  			pl, err := runOneExprStmt(mock, t, input[i])
   224  			if err != nil {
   225  				t.Fatalf("%+v", err)
   226  			}
   227  			query, ok := pl.Plan.(*plan.Plan_Query)
   228  			if !ok {
   229  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right"))
   230  			}
   231  			expr := query.Query.Nodes[1].ProjectList[0]
   232  			exprF, ok := expr.Expr.(*plan.Expr_F)
   233  			if !ok {
   234  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right"))
   235  			}
   236  			convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool)
   237  			convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, "<=")
   238  		}
   239  	})
   240  }
   241  
   242  func TestExpr_7(t *testing.T) {
   243  	convey.Convey("selectGreatStmt succ", t, func() {
   244  		mock := NewMockOptimizer(false)
   245  		// var params []bool = []bool{false, false, true, true}
   246  		input := []string{"select 0 > 1 from dual;",
   247  			"select 1 > 1 from dual;",
   248  			"select 1 > 0 from dual;"}
   249  
   250  		for i := 0; i < len(input); i++ {
   251  			pl, err := runOneExprStmt(mock, t, input[i])
   252  			if err != nil {
   253  				t.Fatalf("%+v", err)
   254  			}
   255  			query, ok := pl.Plan.(*plan.Plan_Query)
   256  			if !ok {
   257  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right"))
   258  			}
   259  			expr := query.Query.Nodes[1].ProjectList[0]
   260  			exprF, ok := expr.Expr.(*plan.Expr_F)
   261  			if !ok {
   262  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right"))
   263  			}
   264  			convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool)
   265  			convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, ">")
   266  		}
   267  	})
   268  }
   269  
   270  func TestExpr_8(t *testing.T) {
   271  	convey.Convey("selectGreatEqualStmt succ", t, func() {
   272  		mock := NewMockOptimizer(false)
   273  		// var params []bool = []bool{false, false, true, true}
   274  		input := []string{"select 0 >= 1 from dual;",
   275  			"select 1 >= 1 from dual;",
   276  			"select 1 >= 0 from dual;"}
   277  
   278  		for i := 0; i < len(input); i++ {
   279  			pl, err := runOneExprStmt(mock, t, input[i])
   280  			if err != nil {
   281  				t.Fatalf("%+v", err)
   282  			}
   283  			query, ok := pl.Plan.(*plan.Plan_Query)
   284  			if !ok {
   285  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right"))
   286  			}
   287  			expr := query.Query.Nodes[1].ProjectList[0]
   288  			exprF, ok := expr.Expr.(*plan.Expr_F)
   289  			if !ok {
   290  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right"))
   291  			}
   292  			convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool)
   293  			convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, ">=")
   294  		}
   295  	})
   296  }
   297  
   298  func TestExpr_9(t *testing.T) {
   299  	convey.Convey("selectGreatEqualStmt succ", t, func() {
   300  		mock := NewMockOptimizer(false)
   301  		// var params []bool = []bool{false, false, true, true}
   302  		input := []string{"select 0 != 1 from dual;",
   303  			"select 1 != 1 from dual;",
   304  			"select 1 != 0 from dual;",
   305  			"select 0 <> 1 from dual;",
   306  			"select 1 <> 1 from dual;",
   307  			"select 1 <> 0 from dual;"}
   308  
   309  		for i := 0; i < len(input); i++ {
   310  			pl, err := runOneExprStmt(mock, t, input[i])
   311  			if err != nil {
   312  				t.Fatalf("%+v", err)
   313  			}
   314  			query, ok := pl.Plan.(*plan.Plan_Query)
   315  			if !ok {
   316  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right"))
   317  			}
   318  			expr := query.Query.Nodes[1].ProjectList[0]
   319  			exprF, ok := expr.Expr.(*plan.Expr_F)
   320  			if !ok {
   321  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right"))
   322  			}
   323  			convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool)
   324  			convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, "<>")
   325  		}
   326  	})
   327  }
   328  
   329  func TestExpr_A(t *testing.T) {
   330  	convey.Convey("selectAndStmt succ", t, func() {
   331  		mock := NewMockOptimizer(false)
   332  		// var params []bool = []bool{false, false, true, true}
   333  		input := []string{"select 0 < 1 and 1 > 0 from dual;",
   334  			"select 0 < 1 or 1 > 0 from dual;",
   335  			"select not 0 < 1 from dual;"}
   336  		name := []string{"and", "or", "not"}
   337  		for i := 0; i < len(input); i++ {
   338  			pl, err := runOneExprStmt(mock, t, input[i])
   339  			if err != nil {
   340  				t.Fatalf("%+v", err)
   341  			}
   342  			query, ok := pl.Plan.(*plan.Plan_Query)
   343  			if !ok {
   344  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right"))
   345  			}
   346  			expr := query.Query.Nodes[1].ProjectList[0]
   347  			exprF, ok := expr.Expr.(*plan.Expr_F)
   348  			if !ok {
   349  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right"))
   350  			}
   351  			convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool)
   352  			convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, name[i])
   353  			for _, arg := range exprF.F.Args {
   354  				convey.So(arg.Typ.Id, convey.ShouldEqual, types.T_bool)
   355  			}
   356  		}
   357  	})
   358  }
   359  
   360  func TestExpr_B(t *testing.T) {
   361  	convey.Convey("selectAndStmt succ", t, func() {
   362  		mock := NewMockOptimizer(false)
   363  		// var params []bool = []bool{false, false, true, true}
   364  		input := []string{"select 0 < 1 and 1 > 0 && not false from dual;"}
   365  		for i := 0; i < len(input); i++ {
   366  			pl, err := runOneExprStmt(mock, t, input[i])
   367  			if err != nil {
   368  				t.Fatalf("%+v", err)
   369  			}
   370  			query, ok := pl.Plan.(*plan.Plan_Query)
   371  			if !ok {
   372  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "return type is not right"))
   373  			}
   374  			expr := query.Query.Nodes[1].ProjectList[0]
   375  			exprF, ok := expr.Expr.(*plan.Expr_F)
   376  			if !ok {
   377  				t.Fatalf("%+v", moerr.NewInternalError(mock.ctxt.GetContext(), "the parse expr type is not right"))
   378  			}
   379  			convey.So(expr.Typ.Id, convey.ShouldEqual, types.T_bool)
   380  			convey.So(exprF.F.Func.ObjName, convey.ShouldEqual, "and")
   381  			for _, arg := range exprF.F.Args {
   382  				convey.So(arg.Typ.Id, convey.ShouldEqual, types.T_bool)
   383  			}
   384  		}
   385  	})
   386  }
   387  
   388  func runOneExprStmt(opt Optimizer, t *testing.T, sql string) (*plan.Plan, error) {
   389  	stmts, err := mysql.Parse(opt.CurrentContext().GetContext(), sql, 1, 0)
   390  	if err != nil {
   391  		return nil, err
   392  	}
   393  	ctx := opt.CurrentContext()
   394  
   395  	var pl *plan.Plan
   396  	for _, ast := range stmts {
   397  		pl, err = BuildPlan(ctx, ast, false)
   398  		if err != nil {
   399  			return nil, err
   400  		}
   401  	}
   402  	return pl, nil
   403  }
   404  
   405  func makeTimeExpr(s string, p int32) *plan.Expr {
   406  	dt, _ := types.ParseTime(s, 0)
   407  	return &plan.Expr{
   408  		Typ: plan.Type{
   409  			Id:    int32(types.T_time),
   410  			Scale: p,
   411  		},
   412  		Expr: &plan.Expr_Lit{
   413  			Lit: &plan.Literal{
   414  				Value: &plan.Literal_Timeval{
   415  					Timeval: int64(dt),
   416  				},
   417  			},
   418  		},
   419  	}
   420  }
   421  
   422  func makeDateExpr(s string) *plan.Expr {
   423  	dt, _ := types.ParseDateCast(s)
   424  	return &plan.Expr{
   425  		Typ: plan.Type{
   426  			Id: int32(types.T_date),
   427  		},
   428  		Expr: &plan.Expr_Lit{
   429  			Lit: &plan.Literal{
   430  				Value: &plan.Literal_Dateval{
   431  					Dateval: int32(dt),
   432  				},
   433  			},
   434  		},
   435  	}
   436  }
   437  
   438  func makeTimestampExpr(s string, p int32, loc *time.Location) *plan.Expr {
   439  	dt, _ := types.ParseTimestamp(loc, s, p)
   440  	return &plan.Expr{
   441  		Typ: plan.Type{
   442  			Id: int32(types.T_timestamp),
   443  		},
   444  		Expr: &plan.Expr_Lit{
   445  			Lit: &plan.Literal{
   446  				Value: &plan.Literal_Timestampval{
   447  					Timestampval: int64(dt),
   448  				},
   449  			},
   450  		},
   451  	}
   452  }
   453  func makeDatetimeExpr(s string, p int32) *plan.Expr {
   454  	dt, _ := types.ParseDatetime(s, p)
   455  	return &plan.Expr{
   456  		Typ: plan.Type{
   457  			Id: int32(types.T_datetime),
   458  		},
   459  		Expr: &plan.Expr_Lit{
   460  			Lit: &plan.Literal{
   461  				Value: &plan.Literal_Datetimeval{
   462  					Datetimeval: int64(dt),
   463  				},
   464  			},
   465  		},
   466  	}
   467  }
   468  
   469  func TestTime(t *testing.T) {
   470  	s := "12:34:56"
   471  	e := makeTimeExpr(s, 0)
   472  	bat := batch.NewWithSize(1)
   473  	bat.SetRowCount(1)
   474  	executor, err := colexec.NewExpressionExecutor(testutil.NewProc(), e)
   475  	require.NoError(t, err)
   476  	r, err := executor.Eval(testutil.NewProc(), []*batch.Batch{bat})
   477  	require.NoError(t, err)
   478  	require.Equal(t, 1, r.Length())
   479  }
   480  
   481  func TestDatetime(t *testing.T) {
   482  	s := "2019-12-12 12:34:56"
   483  	e := makeDatetimeExpr(s, 0)
   484  	bat := batch.NewWithSize(1)
   485  	bat.SetRowCount(1)
   486  	executor, err := colexec.NewExpressionExecutor(testutil.NewProc(), e)
   487  	require.NoError(t, err)
   488  	r, err := executor.Eval(testutil.NewProc(), []*batch.Batch{bat})
   489  	require.NoError(t, err)
   490  	require.Equal(t, 1, r.Length())
   491  }
   492  func TestTimestamp(t *testing.T) {
   493  	s := "2019-12-12 12:34:56"
   494  	e := makeTimestampExpr(s, 0, time.Local)
   495  	bat := batch.NewWithSize(1)
   496  	bat.SetRowCount(1)
   497  	executor, err := colexec.NewExpressionExecutor(testutil.NewProc(), e)
   498  	require.NoError(t, err)
   499  	r, err := executor.Eval(testutil.NewProc(), []*batch.Batch{bat})
   500  	require.NoError(t, err)
   501  	require.Equal(t, 1, r.Length())
   502  }
   503  func TestDate(t *testing.T) {
   504  	s := "2019-12-12"
   505  	e := makeDateExpr(s)
   506  	bat := batch.NewWithSize(1)
   507  	bat.SetRowCount(1)
   508  	executor, err := colexec.NewExpressionExecutor(testutil.NewProc(), e)
   509  	require.NoError(t, err)
   510  	r, err := executor.Eval(testutil.NewProc(), []*batch.Batch{bat})
   511  	require.NoError(t, err)
   512  	require.Equal(t, 1, r.Length())
   513  }