github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/build_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  	"bytes"
    19  	"context"
    20  	"encoding/json"
    21  	"go/constant"
    22  	"os"
    23  	"strings"
    24  	"testing"
    25  
    26  	"github.com/matrixorigin/matrixone/pkg/container/types"
    27  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    28  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect/mysql"
    29  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    30  	"github.com/matrixorigin/matrixone/pkg/testutil"
    31  	"github.com/stretchr/testify/assert"
    32  )
    33  
    34  func BenchmarkInsert(b *testing.B) {
    35  	typ := types.T_varchar.ToType()
    36  	typ.Width = 1024
    37  	targetType := makePlan2Type(&typ)
    38  	targetType.Width = 1024
    39  
    40  	originStr := "0123456789"
    41  	testExpr := tree.NewNumValWithType(constant.MakeString(originStr), originStr, false, tree.P_char)
    42  	targetT := &plan.Expr{
    43  		Typ: targetType,
    44  		Expr: &plan.Expr_T{
    45  			T: &plan.TargetType{},
    46  		},
    47  	}
    48  	ctx := context.TODO()
    49  	for i := 0; i < b.N; i++ {
    50  		binder := NewDefaultBinder(ctx, nil, nil, targetType, nil)
    51  		expr, err := binder.BindExpr(testExpr, 0, true)
    52  		if err != nil {
    53  			break
    54  		}
    55  		_, err = forceCastExpr2(ctx, expr, typ, targetT)
    56  		if err != nil {
    57  			break
    58  		}
    59  	}
    60  }
    61  
    62  // only use in developing
    63  func TestSingleSQL(t *testing.T) {
    64  	// sql := "INSERT INTO NATION VALUES (1, 'NAME1',21, 'COMMENT1'), (2, 'NAME2', 22, 'COMMENT2')"
    65  	// sql := "insert into dept values (11, 'aa', 'bb')"
    66  	// sql := "delete from dept where deptno > 10"
    67  	// sql := "delete from nation where n_nationkey > 10"
    68  	// sql := "delete nation, nation2 from nation join nation2 on nation.n_name = nation2.n_name"
    69  	// sql := "update nation set n_name ='a' where n_nationkey > 10"
    70  	// sql := "update dept set deptno = 11 where deptno = 10"
    71  	sqls := []string{"prepare stmt1 from update nation set n_name = ? where n_nationkey = ?",
    72  		"prepare stmt1 from insert into  nation values (?, ?, ?, ?) ON DUPLICATE KEY UPDATE n_name=?"}
    73  	mock := NewMockOptimizer(true)
    74  
    75  	for _, sql := range sqls {
    76  		logicPlan, err := runOneStmt(mock, t, sql)
    77  		if err != nil {
    78  			t.Fatalf("%+v", err)
    79  		}
    80  		outPutPlan(logicPlan, true, t)
    81  	}
    82  }
    83  
    84  //Test Query Node Tree
    85  // func TestNodeTree(t *testing.T) {
    86  // 	type queryCheck struct {
    87  // 		steps    []int32                    //steps
    88  // 		nodeType map[int]plan.Node_NodeType //node_type in each node
    89  // 		children map[int][]int32            //children in each node
    90  // 	}
    91  
    92  // 	// map[sql string]checkData
    93  // 	nodeTreeCheckList := map[string]queryCheck{
    94  // 		"SELECT -1": {
    95  // 			steps: []int32{0},
    96  // 			nodeType: map[int]plan.Node_NodeType{
    97  // 				0: plan.Node_VALUE_SCAN,
    98  // 			},
    99  // 			children: nil,
   100  // 		},
   101  // 		"SELECT -1 from dual": {
   102  // 			steps: []int32{0},
   103  // 			nodeType: map[int]plan.Node_NodeType{
   104  // 				0: plan.Node_VALUE_SCAN,
   105  // 			},
   106  // 			children: nil,
   107  // 		},
   108  // 		// one node
   109  // 		"SELECT N_NAME FROM NATION WHERE N_REGIONKEY = 3": {
   110  // 			steps: []int32{0},
   111  // 			nodeType: map[int]plan.Node_NodeType{
   112  // 				0: plan.Node_TABLE_SCAN,
   113  // 			},
   114  // 			children: nil,
   115  // 		},
   116  // 		// two nodes- SCAN + SORT
   117  // 		"SELECT N_NAME FROM NATION WHERE N_REGIONKEY = 3 Order By N_REGIONKEY": {
   118  // 			steps: []int32{1},
   119  // 			nodeType: map[int]plan.Node_NodeType{
   120  // 				0: plan.Node_TABLE_SCAN,
   121  // 				1: plan.Node_SORT,
   122  // 			},
   123  // 			children: map[int][]int32{
   124  // 				1: {0},
   125  // 			},
   126  // 		},
   127  // 		// two nodes- SCAN + AGG(group by)
   128  // 		"SELECT N_NAME FROM NATION WHERE N_REGIONKEY = 3 Group By N_NAME": {
   129  // 			steps: []int32{1},
   130  // 			nodeType: map[int]plan.Node_NodeType{
   131  // 				0: plan.Node_TABLE_SCAN,
   132  // 				1: plan.Node_AGG,
   133  // 			},
   134  // 			children: map[int][]int32{
   135  // 				1: {0},
   136  // 			},
   137  // 		},
   138  // 		"select sum(n_nationkey) from nation": {
   139  // 			steps: []int32{1},
   140  // 			nodeType: map[int]plan.Node_NodeType{
   141  // 				0: plan.Node_TABLE_SCAN,
   142  // 				1: plan.Node_AGG,
   143  // 			},
   144  // 			children: map[int][]int32{
   145  // 				1: {0},
   146  // 			},
   147  // 		},
   148  // 		"select sum(n_nationkey) from nation order by sum(n_nationkey)": {
   149  // 			steps: []int32{2},
   150  // 			nodeType: map[int]plan.Node_NodeType{
   151  // 				0: plan.Node_TABLE_SCAN,
   152  // 				1: plan.Node_AGG,
   153  // 				2: plan.Node_SORT,
   154  // 			},
   155  // 			children: map[int][]int32{
   156  // 				1: {0},
   157  // 				2: {1},
   158  // 			},
   159  // 		},
   160  // 		// two nodes- SCAN + AGG(distinct)
   161  // 		"SELECT distinct N_NAME FROM NATION": {
   162  // 			steps: []int32{1},
   163  // 			nodeType: map[int]plan.Node_NodeType{
   164  // 				0: plan.Node_TABLE_SCAN,
   165  // 				1: plan.Node_AGG,
   166  // 			},
   167  // 			children: map[int][]int32{
   168  // 				1: {0},
   169  // 			},
   170  // 		},
   171  // 		// three nodes- SCAN + AGG(group by) + SORT
   172  // 		"SELECT N_NAME, count(*) as ttl FROM NATION Group By N_NAME Order By ttl": {
   173  // 			steps: []int32{2},
   174  // 			nodeType: map[int]plan.Node_NodeType{
   175  // 				0: plan.Node_TABLE_SCAN,
   176  // 				1: plan.Node_AGG,
   177  // 				2: plan.Node_SORT,
   178  // 			},
   179  // 			children: map[int][]int32{
   180  // 				1: {0},
   181  // 				2: {1},
   182  // 			},
   183  // 		},
   184  // 		// three nodes - SCAN, SCAN, JOIN
   185  // 		"SELECT N_NAME, N_REGIONKEY FROM NATION join REGION on NATION.N_REGIONKEY = REGION.R_REGIONKEY": {
   186  // 			steps: []int32{3},
   187  // 			nodeType: map[int]plan.Node_NodeType{
   188  // 				0: plan.Node_TABLE_SCAN,
   189  // 				1: plan.Node_TABLE_SCAN,
   190  // 				2: plan.Node_JOIN,
   191  // 				3: plan.Node_PROJECT,
   192  // 			},
   193  // 			children: map[int][]int32{
   194  // 				2: {0, 1},
   195  // 			},
   196  // 		},
   197  // 		// three nodes - SCAN, SCAN, JOIN  //use where for join condition
   198  // 		"SELECT N_NAME, N_REGIONKEY FROM NATION, REGION WHERE NATION.N_REGIONKEY = REGION.R_REGIONKEY": {
   199  // 			steps: []int32{3},
   200  // 			nodeType: map[int]plan.Node_NodeType{
   201  // 				0: plan.Node_TABLE_SCAN,
   202  // 				1: plan.Node_TABLE_SCAN,
   203  // 				2: plan.Node_JOIN,
   204  // 				3: plan.Node_PROJECT,
   205  // 			},
   206  // 			children: map[int][]int32{
   207  // 				2: {0, 1},
   208  // 				3: {2},
   209  // 			},
   210  // 		},
   211  // 		// 5 nodes - SCAN, SCAN, JOIN, SCAN, JOIN  //join three table
   212  // 		"SELECT l.L_ORDERKEY FROM CUSTOMER c, ORDERS o, LINEITEM l WHERE c.C_CUSTKEY = o.O_CUSTKEY and l.L_ORDERKEY = o.O_ORDERKEY and o.O_ORDERKEY < 10": {
   213  // 			steps: []int32{6},
   214  // 			nodeType: map[int]plan.Node_NodeType{
   215  // 				0: plan.Node_TABLE_SCAN,
   216  // 				1: plan.Node_TABLE_SCAN,
   217  // 				2: plan.Node_JOIN,
   218  // 				3: plan.Node_PROJECT,
   219  // 				4: plan.Node_TABLE_SCAN,
   220  // 				5: plan.Node_JOIN,
   221  // 				6: plan.Node_PROJECT,
   222  // 			},
   223  // 			children: map[int][]int32{
   224  // 				2: {0, 1},
   225  // 				3: {2},
   226  // 				5: {3, 4},
   227  // 				6: {5},
   228  // 			},
   229  // 		},
   230  // 		// 6 nodes - SCAN, SCAN, JOIN, SCAN, JOIN, SORT  //join three table
   231  // 		"SELECT l.L_ORDERKEY FROM CUSTOMER c, ORDERS o, LINEITEM l WHERE c.C_CUSTKEY = o.O_CUSTKEY and l.L_ORDERKEY = o.O_ORDERKEY and o.O_ORDERKEY < 10 order by c.C_CUSTKEY": {
   232  // 			steps: []int32{7},
   233  // 			nodeType: map[int]plan.Node_NodeType{
   234  // 				0: plan.Node_TABLE_SCAN,
   235  // 				1: plan.Node_TABLE_SCAN,
   236  // 				2: plan.Node_JOIN,
   237  // 				3: plan.Node_PROJECT,
   238  // 				4: plan.Node_TABLE_SCAN,
   239  // 				5: plan.Node_JOIN,
   240  // 				6: plan.Node_PROJECT,
   241  // 				7: plan.Node_SORT,
   242  // 			},
   243  // 			children: map[int][]int32{
   244  // 				2: {0, 1},
   245  // 				3: {2},
   246  // 				5: {3, 4},
   247  // 				6: {5},
   248  // 				7: {6},
   249  // 			},
   250  // 		},
   251  // 		// 3 nodes  //Derived table
   252  // 		"select c_custkey from (select c_custkey, count(C_NATIONKEY) ff from CUSTOMER group by c_custkey) a where ff > 0": {
   253  // 			steps: []int32{2},
   254  // 			nodeType: map[int]plan.Node_NodeType{
   255  // 				0: plan.Node_TABLE_SCAN,
   256  // 				1: plan.Node_AGG,
   257  // 				2: plan.Node_PROJECT,
   258  // 			},
   259  // 			children: map[int][]int32{
   260  // 				1: {0},
   261  // 				2: {1},
   262  // 			},
   263  // 		},
   264  // 		// 4 nodes  //Derived table
   265  // 		"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": {
   266  // 			steps: []int32{3},
   267  // 			nodeType: map[int]plan.Node_NodeType{
   268  // 				0: plan.Node_TABLE_SCAN,
   269  // 				1: plan.Node_AGG,
   270  // 				2: plan.Node_PROJECT,
   271  // 				3: plan.Node_SORT,
   272  // 			},
   273  // 			children: map[int][]int32{
   274  // 				1: {0},
   275  // 				2: {1},
   276  // 				3: {2},
   277  // 			},
   278  // 		},
   279  // 		// Derived table join normal table
   280  // 		"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 order By b.N_REGIONKEY": {
   281  // 			steps: []int32{6},
   282  // 			nodeType: map[int]plan.Node_NodeType{
   283  // 				0: plan.Node_TABLE_SCAN,
   284  // 				1: plan.Node_AGG,
   285  // 				2: plan.Node_PROJECT,
   286  // 				3: plan.Node_TABLE_SCAN,
   287  // 				4: plan.Node_JOIN,
   288  // 				5: plan.Node_PROJECT,
   289  // 				6: plan.Node_SORT,
   290  // 			},
   291  // 			children: map[int][]int32{
   292  // 				1: {0},
   293  // 				2: {1},
   294  // 				4: {2, 3},
   295  // 				5: {4},
   296  // 				6: {5},
   297  // 			},
   298  // 		},
   299  // 		// insert from values
   300  // 		"INSERT NATION (N_NATIONKEY, N_REGIONKEY, N_NAME) VALUES (1, 21, 'NAME1'), (2, 22, 'NAME2')": {
   301  // 			steps: []int32{1},
   302  // 			nodeType: map[int]plan.Node_NodeType{
   303  // 				0: plan.Node_VALUE_SCAN,
   304  // 				1: plan.Node_INSERT,
   305  // 			},
   306  // 			children: map[int][]int32{
   307  // 				1: {0},
   308  // 			},
   309  // 		},
   310  // 		// insert from select
   311  // 		"INSERT NATION SELECT * FROM NATION2": {
   312  // 			steps: []int32{1},
   313  // 			nodeType: map[int]plan.Node_NodeType{
   314  // 				0: plan.Node_TABLE_SCAN,
   315  // 				1: plan.Node_INSERT,
   316  // 			},
   317  // 			children: map[int][]int32{
   318  // 				1: {0},
   319  // 			},
   320  // 		},
   321  // 		// update
   322  // 		"UPDATE NATION SET N_NAME ='U1', N_REGIONKEY=N_REGIONKEY+2 WHERE N_NATIONKEY > 10 LIMIT 20": {
   323  // 			steps: []int32{1},
   324  // 			nodeType: map[int]plan.Node_NodeType{
   325  // 				0: plan.Node_TABLE_SCAN,
   326  // 				1: plan.Node_UPDATE,
   327  // 			},
   328  // 			children: map[int][]int32{
   329  // 				1: {0},
   330  // 			},
   331  // 		},
   332  // 		// delete
   333  // 		"DELETE FROM NATION WHERE N_NATIONKEY > 10 LIMIT 20": {
   334  // 			steps: []int32{1},
   335  // 			nodeType: map[int]plan.Node_NodeType{
   336  // 				0: plan.Node_TABLE_SCAN,
   337  // 				1: plan.Node_DELETE,
   338  // 			},
   339  // 		},
   340  // 		// uncorrelated subquery
   341  // 		"SELECT * FROM NATION where N_REGIONKEY > (select max(R_REGIONKEY) from REGION)": {
   342  // 			steps: []int32{0},
   343  // 			nodeType: map[int]plan.Node_NodeType{
   344  // 				0: plan.Node_TABLE_SCAN, //nodeid = 1  here is the subquery
   345  // 				1: plan.Node_TABLE_SCAN, //nodeid = 0, here is SELECT * FROM NATION where N_REGIONKEY > [subquery]
   346  // 			},
   347  // 			children: map[int][]int32{},
   348  // 		},
   349  // 		// correlated subquery
   350  // 		`SELECT * FROM NATION where N_REGIONKEY >
   351  // 			(select avg(R_REGIONKEY) from REGION where R_REGIONKEY < N_REGIONKEY group by R_NAME)
   352  // 		order by N_NATIONKEY`: {
   353  // 			steps: []int32{3},
   354  // 			nodeType: map[int]plan.Node_NodeType{
   355  // 				0: plan.Node_TABLE_SCAN, //nodeid = 1  subquery node,so,wo pop it to top
   356  // 				1: plan.Node_TABLE_SCAN, //nodeid = 0
   357  // 				2: plan.Node_AGG,        //nodeid = 2  subquery node,so,wo pop it to top
   358  // 				3: plan.Node_SORT,       //nodeid = 3
   359  // 			},
   360  // 			children: map[int][]int32{
   361  // 				2: {1}, //nodeid = 2, have children(NodeId=1, position=0)
   362  // 				3: {0}, //nodeid = 3, have children(NodeId=0, position=2)
   363  // 			},
   364  // 		},
   365  // 		// cte
   366  // 		`with tbl(col1, col2) as (select n_nationkey, n_name from nation) select * from tbl order by col2`: {
   367  // 			steps: []int32{1, 3},
   368  // 			nodeType: map[int]plan.Node_NodeType{
   369  // 				0: plan.Node_TABLE_SCAN,
   370  // 				1: plan.Node_MATERIAL,
   371  // 				2: plan.Node_MATERIAL_SCAN,
   372  // 				3: plan.Node_SORT,
   373  // 			},
   374  // 			children: map[int][]int32{
   375  // 				1: {0},
   376  // 				3: {2},
   377  // 			},
   378  // 		},
   379  // 	}
   380  
   381  // 	// run test and check node tree
   382  // 	for sql, check := range nodeTreeCheckList {
   383  // 		mock := NewMockOptimizer(false)
   384  // 		logicPlan, err := runOneStmt(mock, t, sql)
   385  // 		query := logicPlan.GetQuery()
   386  // 		if err != nil {
   387  // 			t.Fatalf("%+v, sql=%v", err, sql)
   388  // 		}
   389  // 		if len(query.Steps) != len(check.steps) {
   390  // 			t.Fatalf("run sql[%+v] error, root should be [%+v] but now is [%+v]", sql, check.steps, query.Steps)
   391  // 		}
   392  // 		for idx, step := range query.Steps {
   393  // 			if step != check.steps[idx] {
   394  // 				t.Fatalf("run sql[%+v] error, root should be [%+v] but now is [%+v]", sql, check.steps, query.Steps)
   395  // 			}
   396  // 		}
   397  // 		for idx, typ := range check.nodeType {
   398  // 			if idx >= len(query.Nodes) {
   399  // 				t.Fatalf("run sql[%+v] error, query.Nodes[%+v].NodeType not exist", sql, idx)
   400  // 			}
   401  // 			if query.Nodes[idx].NodeType != typ {
   402  // 				t.Fatalf("run sql[%+v] error, query.Nodes[%+v].NodeType should be [%+v] but now is [%+v]", sql, idx, typ, query.Nodes[idx].NodeType)
   403  // 			}
   404  // 		}
   405  // 		for idx, children := range check.children {
   406  // 			if idx >= len(query.Nodes) {
   407  // 				t.Fatalf("run sql[%+v] error, query.Nodes[%+v].NodeType not exist", sql, idx)
   408  // 			}
   409  // 			if !reflect.DeepEqual(query.Nodes[idx].Children, children) {
   410  // 				t.Fatalf("run sql[%+v] error, query.Nodes[%+v].Children should be [%+v] but now is [%+v]", sql, idx, children, query.Nodes[idx].Children)
   411  // 			}
   412  // 		}
   413  // 	}
   414  // }
   415  
   416  // test single table plan building
   417  func TestSingleTableSQLBuilder(t *testing.T) {
   418  	mock := NewMockOptimizer(false)
   419  	// should pass
   420  	sqls := []string{
   421  		"SELECT '1900-01-01 00:00:00' + INTERVAL 2147483648 SECOND",
   422  		"SELECT N_NAME, N_REGIONKEY FROM NATION WHERE N_REGIONKEY > 0 AND N_NAME LIKE '%AA' ORDER BY N_NAME DESC, N_REGIONKEY LIMIT 10, 20",
   423  		"SELECT N_NAME, N_REGIONKEY a FROM NATION WHERE N_REGIONKEY > 0 ORDER BY a DESC", //test alias
   424  		"SELECT NATION.N_NAME FROM NATION",                                       //test alias
   425  		"SELECT * FROM NATION",                                                   //test star
   426  		"SELECT a.* FROM NATION a",                                               //test star
   427  		"SELECT count(*) FROM NATION",                                            //test star
   428  		"SELECT count(*) FROM NATION group by N_NAME",                            //test star
   429  		"SELECT N_NAME, count(distinct N_REGIONKEY) FROM NATION group by N_NAME", //test distinct agg function
   430  		"SELECT N_NAME, MAX(N_REGIONKEY) FROM NATION GROUP BY N_NAME HAVING MAX(N_REGIONKEY) > 10", //test agg
   431  		"SELECT DISTINCT N_NAME FROM NATION", //test distinct
   432  		"select sum(n_nationkey) as s from nation order by s",
   433  		"select date_add(date '2001-01-01', interval 1 day) as a",
   434  		"select date_sub(date '2001-01-01', interval '1' day) as a",
   435  		"select date_add('2001-01-01', interval '1' day) as a",
   436  		"select n_name, count(*) from nation group by n_name order by 2 asc",
   437  		"select count(distinct 12)",
   438  		"select nullif(n_name, n_comment), ifnull(n_comment, n_name) from nation",
   439  
   440  		"select 18446744073709551500",
   441  		"select 0xffffffffffffffff",
   442  		"select 0xffff",
   443  
   444  		"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", //test more expr
   445  		"SELECT N_REGIONKEY FROM NATION where N_REGIONKEY >= N_NATIONKEY or (N_NAME like '%ddd' and N_REGIONKEY >0.5)",                                                    //test more expr
   446  		"SELECT N_REGIONKEY FROM NATION where N_REGIONKEY between 2 and 2 OR N_NATIONKEY not between 3 and 10",                                                            //test more expr
   447  		// "SELECT N_REGIONKEY FROM NATION where N_REGIONKEY is null and N_NAME is not null",
   448  		"SELECT N_REGIONKEY FROM NATION where N_REGIONKEY IN (1, 2)",  //test more expr
   449  		"SELECT N_REGIONKEY FROM NATION where N_REGIONKEY NOT IN (1)", //test more expr
   450  		"select N_REGIONKEY from nation group by N_REGIONKEY having abs(nation.N_REGIONKEY - 1) >10",
   451  
   452  		"SELECT -1",
   453  		"select date_add('1997-12-31 23:59:59',INTERVAL 100000 SECOND)",
   454  		"select date_sub('1997-12-31 23:59:59',INTERVAL 2 HOUR)",
   455  		"select @str_var, @int_var, @bool_var, @float_var, @null_var",
   456  		"select @str_var, @@global.int_var, @@session.bool_var",
   457  		"select n_name from nation where n_name != @str_var and n_regionkey > @int_var",
   458  		"select n_name from nation where n_name != @@global.str_var and n_regionkey > @@session.int_var",
   459  		"select distinct(n_name), ((abs(n_regionkey))) from nation",
   460  		"SET @var = abs(-1), @@session.string_var = 'aaa'",
   461  		"SET NAMES 'utf8mb4' COLLATE 'utf8mb4_general_ci'",
   462  		"SELECT DISTINCT N_NAME FROM NATION ORDER BY N_NAME", //test distinct with order by
   463  
   464  		"prepare stmt1 from select * from nation",
   465  		"prepare stmt1 from select * from nation where n_name = ?",
   466  		"prepare stmt1 from 'select * from nation where n_name = ?'",
   467  		"prepare stmt1 from 'insert into nation select * from nation2 where n_name = ?'",
   468  		"prepare stmt1 from 'select * from nation where n_name = ?'",
   469  		"prepare stmt1 from 'drop table if exists t1'",
   470  		"prepare stmt1 from 'create table t1 (a int)'",
   471  		"prepare stmt1 from select N_REGIONKEY from nation group by N_REGIONKEY having abs(nation.N_REGIONKEY - ?) > ?",
   472  		"execute stmt1",
   473  		"execute stmt1 using @str_var, @@global.int_var",
   474  		"deallocate prepare stmt1",
   475  		"drop prepare stmt1",
   476  		"select count(n_name) from nation limit 10",
   477  		"select l_shipdate + interval '1' day from lineitem",
   478  		"select interval '1' day + l_shipdate  from lineitem",
   479  		"select interval '1' day + cast('2022-02-02 00:00:00' as datetime)",
   480  		"select cast('2022-02-02 00:00:00' as datetime) + interval '1' day",
   481  		"select true is unknown",
   482  		"select null is not unknown",
   483  		"select 1 as c,  1/2, abs(-2)",
   484  
   485  		"select date('2022-01-01'), adddate(time'00:00:00', interval 1 day), subdate(time'00:00:00', interval 1 week), '2007-01-01' + interval 1 month, '2007-01-01' -  interval 1 hour",
   486  		"select 2222332222222223333333333333333333, 0x616263,-10, bit_and(2), bit_or(2), bit_xor(10.1), 'aaa' like '%a',str_to_date('04/31/2004', '%m/%d/%Y'),unix_timestamp(from_unixtime(2147483647))",
   487  		"select max(n_nationkey) over  (partition by N_REGIONKEY) from nation",
   488  		"select * from generate_series(1, 5) g",
   489  		"prepare stmt1 from select * from nation where n_name like ? or n_nationkey > 10 order by 2 limit '10'",
   490  
   491  		"values row(1,1), row(2,2), row(3,3) order by column_0 limit 2",
   492  		"select * from (values row(1,1), row(2,2), row(3,3)) a (c1, c2)",
   493  		"prepare stmt1 from select * from nation where n_name like ? or n_nationkey > 10 order by 2 limit '10' for update",
   494  	}
   495  	runTestShouldPass(mock, t, sqls, false, false)
   496  
   497  	// should error
   498  	sqls = []string{
   499  		"SELECT N_NAME, N_REGIONKEY FROM table_not_exist",                   //table not exist
   500  		"SELECT N_NAME, column_not_exist FROM NATION",                       //column not exist
   501  		"SELECT N_NAME, N_REGIONKEY a FROM NATION ORDER BY cccc",            //column alias not exist
   502  		"SELECT N_NAME, b.N_REGIONKEY FROM NATION a ORDER BY b.N_REGIONKEY", //table alias not exist
   503  		"SELECT N_NAME FROM NATION WHERE ffff(N_REGIONKEY) > 0",             //function name not exist
   504  		"SELECT NATION.N_NAME FROM NATION a",                                // mysql should error, but i don't think it is necesssary
   505  		"select n_nationkey, sum(n_nationkey) from nation",
   506  		"SET @var = abs(a)", // can't use column
   507  		"SET @var = avg(2)", // can't use agg function
   508  
   509  		"SELECT DISTINCT N_NAME FROM NATION GROUP BY N_REGIONKEY", //test distinct with group by
   510  		"SELECT DISTINCT N_NAME FROM NATION ORDER BY N_REGIONKEY", //test distinct with order by
   511  		"select count(n_name) from nation limit 10 for update",
   512  		//"select 18446744073709551500",                             //over int64
   513  		//"select 0xffffffffffffffff",                               //over int64
   514  	}
   515  	runTestShouldError(mock, t, sqls)
   516  }
   517  
   518  // test join table plan building
   519  func TestJoinTableSqlBuilder(t *testing.T) {
   520  	mock := NewMockOptimizer(false)
   521  
   522  	// should pass
   523  	sqls := []string{
   524  		"SELECT N_NAME,N_REGIONKEY FROM NATION join REGION on NATION.N_REGIONKEY = REGION.R_REGIONKEY",
   525  		"SELECT N_NAME, N_REGIONKEY FROM NATION join REGION on NATION.N_REGIONKEY = REGION.R_REGIONKEY WHERE NATION.N_REGIONKEY > 0",
   526  		"SELECT N_NAME, NATION2.R_REGIONKEY FROM NATION2 join REGION using(R_REGIONKEY) WHERE NATION2.R_REGIONKEY > 0",
   527  		"SELECT N_NAME, NATION2.R_REGIONKEY FROM NATION2 NATURAL JOIN REGION WHERE NATION2.R_REGIONKEY > 0",
   528  		"SELECT N_NAME FROM NATION NATURAL JOIN REGION",                                                                                                     //have no same column name but it's ok
   529  		"SELECT N_NAME,N_REGIONKEY FROM NATION a join REGION b on a.N_REGIONKEY = b.R_REGIONKEY WHERE a.N_REGIONKEY > 0",                                    //test alias
   530  		"SELECT l.L_ORDERKEY a FROM CUSTOMER c, ORDERS o, LINEITEM l WHERE c.C_CUSTKEY = o.O_CUSTKEY and l.L_ORDERKEY = o.O_ORDERKEY and o.O_ORDERKEY < 10", //join three tables
   531  		"SELECT c.* FROM CUSTOMER c, ORDERS o, LINEITEM l WHERE c.C_CUSTKEY = o.O_CUSTKEY and l.L_ORDERKEY = o.O_ORDERKEY",                                  //test star
   532  		"SELECT * FROM CUSTOMER c, ORDERS o, LINEITEM l WHERE c.C_CUSTKEY = o.O_CUSTKEY and l.L_ORDERKEY = o.O_ORDERKEY",                                    //test star
   533  		"SELECT a.* FROM NATION a join REGION b on a.N_REGIONKEY = b.R_REGIONKEY WHERE a.N_REGIONKEY > 0",                                                   //test star
   534  		"SELECT * FROM NATION a join REGION b on a.N_REGIONKEY = b.R_REGIONKEY WHERE a.N_REGIONKEY > 0",
   535  		"SELECT N_NAME, R_REGIONKEY FROM NATION2 join REGION using(R_REGIONKEY)",
   536  		"select nation.n_name from nation join nation2 on nation.n_name !='a' join region on nation.n_regionkey = region.r_regionkey",
   537  		"select * from nation, nation2, region",
   538  	}
   539  	runTestShouldPass(mock, t, sqls, false, false)
   540  
   541  	// should error
   542  	sqls = []string{
   543  		"SELECT N_NAME,N_REGIONKEY FROM NATION join REGION on NATION.N_REGIONKEY = REGION.NotExistColumn",                    //column not exist
   544  		"SELECT N_NAME, R_REGIONKEY FROM NATION join REGION using(R_REGIONKEY)",                                              //column not exist
   545  		"SELECT N_NAME,N_REGIONKEY FROM NATION a join REGION b on a.N_REGIONKEY = b.R_REGIONKEY WHERE aaaaa.N_REGIONKEY > 0", //table alias not exist
   546  		"select *", //No table used
   547  		"SELECT * FROM NATION a join REGION b on a.N_REGIONKEY = b.R_REGIONKEY WHERE a.N_REGIONKEY > 0 for update", //Not support
   548  		"select * from nation, nation2, region for update",                                                         // Not support
   549  	}
   550  	runTestShouldError(mock, t, sqls)
   551  }
   552  
   553  // test derived table plan building
   554  func TestDerivedTableSqlBuilder(t *testing.T) {
   555  	mock := NewMockOptimizer(false)
   556  	// should pass
   557  	sqls := []string{
   558  		"select c_custkey from (select c_custkey from CUSTOMER ) a",
   559  		"select c_custkey from (select c_custkey from CUSTOMER group by c_custkey ) a",
   560  		"select col1 from (select c_custkey from CUSTOMER group by c_custkey ) a(col1)",
   561  		"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",
   562  		"select col1 from (select c_custkey, count(C_NATIONKEY) ff from CUSTOMER group by c_custkey ) a(col1, col2) where col2 > 0 order by col1",
   563  		"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",
   564  		"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",
   565  		"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",
   566  	}
   567  	runTestShouldPass(mock, t, sqls, false, false)
   568  
   569  	// should error
   570  	sqls = []string{
   571  		"select C_NAME from (select c_custkey from CUSTOMER) a",                               //column not exist
   572  		"select c_custkey2222 from (select c_custkey from CUSTOMER group by c_custkey ) a",    //column not exist
   573  		"select col1 from (select c_custkey from CUSTOMER group by c_custkey ) a(col1, col2)", //column length not match
   574  		"select c_custkey from (select c_custkey from CUSTOMER group by c_custkey) a(col1)",   //column not exist
   575  		"select c_custkey from (select c_custkey from CUSTOMER ) a for update ",               //not support
   576  	}
   577  	runTestShouldError(mock, t, sqls)
   578  }
   579  
   580  // test derived table plan building
   581  func TestUnionSqlBuilder(t *testing.T) {
   582  	mock := NewMockOptimizer(false)
   583  	// should pass
   584  	sqls := []string{
   585  		"(select 1) union (select 1)",
   586  		"(((select n_nationkey from nation order by n_nationkey))) union (((select n_nationkey from nation order by n_nationkey)))",
   587  		"select 1 union select 2",
   588  		"select 1 union (select 2 union select 3)",
   589  		"(select 1 union select 2) union select 3 intersect select 4 order by 1",
   590  		"select 1 union select null",
   591  		"select n_name from nation intersect select n_name from nation2",
   592  		"select n_name from nation minus select n_name from nation2",
   593  		"select 1 union select 2 intersect select 2 union all select 1.1 minus select 22222",
   594  		"select 1 as a union select 2 order by a limit 1",
   595  		"select n_name from nation union select n_comment from nation order by n_name",
   596  		"with qn (foo, bar) as (select 1 as col, 2 as coll union select 4, 5) select qn1.bar from qn qn1",
   597  		"select n_name, n_comment from nation union all select n_name, n_comment from nation2",
   598  		"select n_name from nation intersect all select n_name from nation2",
   599  	}
   600  	runTestShouldPass(mock, t, sqls, false, false)
   601  
   602  	// should error
   603  	sqls = []string{
   604  		"select 1 union select 2, 'a'",
   605  		"select n_name as a from nation union select n_comment from nation order by n_name",
   606  		"select n_name from nation minus all select n_name from nation2", // not support
   607  	}
   608  	runTestShouldError(mock, t, sqls)
   609  }
   610  
   611  // test CTE plan building
   612  func TestCTESqlBuilder(t *testing.T) {
   613  	mock := NewMockOptimizer(false)
   614  
   615  	// should pass
   616  	sqls := []string{
   617  		"WITH qn AS (SELECT * FROM nation) SELECT * FROM qn;",
   618  		"with qn0 as (select 1), qn1 as (select * from qn0), qn2 as (select 1), qn3 as (select 1 from qn1, qn2) select 1 from qn3",
   619  
   620  		`WITH qn AS (select "outer" as a)
   621  		SELECT (WITH qn AS (SELECT "inner" as a) SELECT a from qn),
   622  		qn.a
   623  		FROM qn`,
   624  	}
   625  	runTestShouldPass(mock, t, sqls, false, false)
   626  
   627  	// should error
   628  	sqls = []string{
   629  		"WITH qn(a, b) AS (SELECT * FROM nation) SELECT * FROM qn;",
   630  		`with qn1 as (with qn3 as (select * from qn2) select * from qn3),
   631  		qn2 as (select 1)
   632  		select * from qn1`,
   633  
   634  		`WITH qn2 AS (SELECT a FROM qn WHERE a IS NULL or a>0),
   635  		qn AS (SELECT b as a FROM qn2)
   636  		SELECT qn.a  FROM qn`,
   637  	}
   638  	runTestShouldError(mock, t, sqls)
   639  }
   640  
   641  func TestInsert(t *testing.T) {
   642  	mock := NewMockOptimizer(false)
   643  	// should pass
   644  	sqls := []string{
   645  		"INSERT INTO NATION VALUES (1, 'NAME1',21, 'COMMENT1'), (2, 'NAME2', 22, 'COMMENT2')",
   646  		"INSERT INTO NATION (N_NATIONKEY, N_REGIONKEY, N_NAME, N_COMMENT) VALUES (1, 21, 'NAME1','comment1'), (2, 22, 'NAME2', 'comment2')",
   647  		"INSERT INTO NATION SELECT * FROM NATION2",
   648  	}
   649  	runTestShouldPass(mock, t, sqls, false, false)
   650  
   651  	// should error
   652  	sqls = []string{
   653  		"INSERT NATION VALUES (1, 'NAME1',21, 'COMMENT1'), ('NAME2', 22, 'COMMENT2')",                                // doesn't match value count
   654  		"INSERT NATION (N_NATIONKEY, N_REGIONKEY, N_NAME) VALUES (1, 'NAME1'), (2, 22, 'NAME2')",                     // doesn't match value count
   655  		"INSERT NATION (N_NATIONKEY, N_REGIONKEY, N_NAME2222) VALUES (1, 21, 'NAME1'), (2, 22, 'NAME2')",             // column not exist
   656  		"INSERT NATION333 (N_NATIONKEY, N_REGIONKEY, N_NAME2222) VALUES (1, 2, 'NAME1'), (2, 22, 'NAME2')",           // table not exist
   657  		"INSERT NATION (N_NATIONKEY, N_REGIONKEY, N_NAME2222) VALUES (1, 'should int32', 'NAME1'), (2, 22, 'NAME2')", // column type not match
   658  		"INSERT NATION (N_NATIONKEY, N_REGIONKEY, N_NAME2222) VALUES (1, 2.22, 'NAME1'), (2, 22, 'NAME2')",           // column type not match
   659  		"INSERT NATION (N_NATIONKEY, N_REGIONKEY, N_NAME2222) VALUES (1, 2, 'NAME1'), (2, 22, 'NAME2')",              // function expr not support now
   660  		"INSERT INTO region SELECT * FROM NATION2",                                                                   // column length not match
   661  		"INSERT INTO region SELECT 1, 2, 3, 4, 5, 6 FROM NATION2",                                                    // column length not match
   662  		"INSERT NATION333 (N_NATIONKEY, N_REGIONKEY, N_NAME2222) SELECT 1, 2, 3 FROM NATION2",                        // table not exist
   663  	}
   664  	runTestShouldError(mock, t, sqls)
   665  }
   666  
   667  func TestUpdate(t *testing.T) {
   668  	mock := NewMockOptimizer(true)
   669  	// should pass
   670  	sqls := []string{
   671  		"UPDATE NATION SET N_NAME ='U1', N_REGIONKEY=2",
   672  		"UPDATE NATION SET N_NAME ='U1', N_REGIONKEY=2 WHERE N_NATIONKEY > 10 LIMIT 20",
   673  		"UPDATE NATION SET N_NAME ='U1', N_REGIONKEY=N_REGIONKEY+2 WHERE N_NATIONKEY > 10 LIMIT 20",
   674  		"update NATION a join NATION2 b on a.N_REGIONKEY = b.R_REGIONKEY set a.N_NAME = 'aa'",
   675  		"prepare stmt1 from 'update nation set n_name = ? where n_nationkey > ?'",
   676  		"drop index idx1 on test_idx",
   677  	}
   678  	runTestShouldPass(mock, t, sqls, false, false)
   679  
   680  	// should error
   681  	sqls = []string{
   682  		"UPDATE NATION SET N_NAME2 ='U1', N_REGIONKEY=2",    // column not exist
   683  		"UPDATE NATION2222 SET N_NAME ='U1', N_REGIONKEY=2", // table not exist
   684  	}
   685  	runTestShouldError(mock, t, sqls)
   686  }
   687  
   688  func TestDelete(t *testing.T) {
   689  	mock := NewMockOptimizer(true)
   690  	// should pass
   691  	sqls := []string{
   692  		"DELETE FROM NATION",
   693  		"DELETE FROM NATION WHERE N_NATIONKEY > 10",
   694  		"DELETE FROM NATION WHERE N_NATIONKEY > 10 LIMIT 20",
   695  		"delete nation from nation left join nation2 on nation.n_nationkey = nation2.n_nationkey",
   696  		"delete from nation",
   697  		"delete nation, nation2 from nation join nation2 on nation.n_name = nation2.n_name",
   698  		"prepare stmt1 from 'delete from nation where n_nationkey > ?'",
   699  	}
   700  	runTestShouldPass(mock, t, sqls, false, false)
   701  
   702  	// should error
   703  	sqls = []string{
   704  		"DELETE FROM NATION2222",                     // table not exist
   705  		"DELETE FROM NATION WHERE N_NATIONKEY2 > 10", // column not found
   706  	}
   707  	runTestShouldError(mock, t, sqls)
   708  }
   709  
   710  func TestSubQuery(t *testing.T) {
   711  	mock := NewMockOptimizer(false)
   712  	// should pass
   713  	sqls := []string{
   714  		"SELECT * FROM NATION where N_REGIONKEY > (select max(R_REGIONKEY) from REGION)",                                 // unrelated
   715  		"SELECT * FROM NATION where N_REGIONKEY in (select max(R_REGIONKEY) from REGION)",                                // unrelated
   716  		"SELECT * FROM NATION where N_REGIONKEY not in (select max(R_REGIONKEY) from REGION)",                            // unrelated
   717  		"SELECT * FROM NATION where exists (select max(R_REGIONKEY) from REGION)",                                        // unrelated
   718  		"SELECT * FROM NATION where N_REGIONKEY > (select max(R_REGIONKEY) from REGION where R_REGIONKEY = N_REGIONKEY)", // related
   719  		//"DELETE FROM NATION WHERE N_NATIONKEY > 10",
   720  		`select
   721  		sum(l_extendedprice) / 7.0 as avg_yearly
   722  	from
   723  		lineitem,
   724  		part
   725  	where
   726  		p_partkey = l_partkey
   727  		and p_brand = 'Brand#54'
   728  		and p_container = 'LG BAG'
   729  		and l_quantity < (
   730  			select
   731  				0.2 * avg(l_quantity)
   732  			from
   733  				lineitem
   734  			where
   735  				l_partkey = p_partkey
   736  		);`, //tpch q17
   737  		"select * from nation where n_regionkey in (select r_regionkey from region) and n_nationkey not in (1,2) and n_nationkey = some (select n_nationkey from nation2)",
   738  	}
   739  	runTestShouldPass(mock, t, sqls, false, false)
   740  
   741  	// should error
   742  	sqls = []string{
   743  		"SELECT * FROM NATION where N_REGIONKEY > (select max(R_REGIONKEY) from REGION222)",                                 // table not exist
   744  		"SELECT * FROM NATION where N_REGIONKEY > (select max(R_REGIONKEY) from REGION where R_REGIONKEY < N_REGIONKEY222)", // column not exist
   745  		"SELECT * FROM NATION where N_REGIONKEY > (select max(R_REGIONKEY) from REGION where R_REGIONKEY < N_REGIONKEY)",    // related
   746  		"SELECT * FROM NATION where N_REGIONKEY > (select max(R_REGIONKEY) from REGION) for update",                         // not support
   747  	}
   748  	runTestShouldError(mock, t, sqls)
   749  }
   750  
   751  func TestMysqlCompatibilityMode(t *testing.T) {
   752  	mock := NewMockOptimizer(false)
   753  
   754  	sqls := []string{
   755  		"SELECT n_nationkey FROM NATION group by n_name",
   756  		"SELECT n_nationkey, min(n_name) FROM NATION",
   757  		"SELECT n_nationkey + 100 FROM NATION group by n_name",
   758  	}
   759  	// withou mysql compatibility
   760  	runTestShouldError(mock, t, sqls)
   761  	// with mysql compatibility
   762  	mock.ctxt.mysqlCompatible = true
   763  	runTestShouldPass(mock, t, sqls, false, false)
   764  }
   765  
   766  func TestTcl(t *testing.T) {
   767  	mock := NewMockOptimizer(false)
   768  	// should pass
   769  	sqls := []string{
   770  		"start transaction",
   771  		"start transaction read write",
   772  		"begin",
   773  		"commit and chain",
   774  		"commit and chain no release",
   775  		"rollback and chain",
   776  	}
   777  	runTestShouldPass(mock, t, sqls, false, false)
   778  
   779  	// should error
   780  	sqls = []string{}
   781  	runTestShouldError(mock, t, sqls)
   782  }
   783  
   784  func TestDdl(t *testing.T) {
   785  	mock := NewMockOptimizer(true)
   786  	// should pass
   787  	sqls := []string{
   788  		"create database db_name",               //db not exists and pass
   789  		"create database if not exists db_name", //db not exists but pass
   790  		"create database if not exists tpch",    //db exists and pass
   791  		"drop database if exists db_name",       //db not exists but pass
   792  		"drop database tpch",                    //db exists, pass
   793  		"create view v1 as select * from nation",
   794  
   795  		"create table tbl_name (t bool(20) comment 'dd', b int unsigned, c char(20), d varchar(20), primary key(b), index idx_t(c)) comment 'test comment'",
   796  		"create table if not exists tbl_name (b int default 20 primary key, c char(20) default 'ss', d varchar(20) default 'kkk')",
   797  		"create table if not exists nation (t bool(20), b int, c char(20), d varchar(20))",
   798  		"drop table if exists tbl_name",
   799  		"drop table if exists nation",
   800  		"drop table nation",
   801  		"drop table tpch.nation",
   802  		"drop table if exists tpch.tbl_not_exist",
   803  		"drop table if exists db_not_exist.tbl",
   804  		"drop view v1",
   805  		"truncate nation",
   806  		"truncate tpch.nation",
   807  		"truncate table nation",
   808  		"truncate table tpch.nation",
   809  		"create unique index idx_name on nation(n_regionkey)",
   810  		"create view v_nation as select n_nationkey,n_name,n_regionkey,n_comment from nation",
   811  		"CREATE TABLE t1(id INT PRIMARY KEY,name VARCHAR(25),deptId INT,CONSTRAINT fk_t1 FOREIGN KEY(deptId) REFERENCES nation(n_nationkey)) COMMENT='xxxxx'",
   812  		"create table t2(empno int unsigned,ename varchar(15),job varchar(10)) cluster by(empno,ename)",
   813  		"lock tables nation read",
   814  		"lock tables nation write, supplier read",
   815  		"unlock tables",
   816  		"alter table emp drop foreign key fk1",
   817  		"alter table nation add FOREIGN KEY fk_t1(n_nationkey) REFERENCES nation2(n_nationkey)",
   818  	}
   819  	runTestShouldPass(mock, t, sqls, false, false)
   820  
   821  	// should error
   822  	sqls = []string{
   823  		// "create database tpch",  // check in pipeline now
   824  		// "drop database db_name", // check in pipeline now
   825  		// "create table nation (t bool(20), b int, c char(20), d varchar(20))",             // check in pipeline now
   826  		"create table nation (b int primary key, c char(20) primary key, d varchar(20))", //Multiple primary key
   827  		"drop table tbl_name",           //table not exists in tpch
   828  		"drop table tpch.tbl_not_exist", //database not exists
   829  		"drop table db_not_exist.tbl",   //table not exists
   830  		"create table t6(empno int unsigned,ename varchar(15) auto_increment) cluster by(empno,ename)",
   831  		"lock tables t3 read",
   832  		"lock tables t1 read, t1 write",
   833  		"lock tables nation read, nation write",
   834  		"alter table nation drop foreign key fk1", //key not exists
   835  		"alter table nation add FOREIGN KEY fk_t1(col_not_exist) REFERENCES nation2(n_nationkey)",
   836  		"alter table nation add FOREIGN KEY fk_t1(n_nationkey) REFERENCES nation2(col_not_exist)",
   837  		"create table agg01 (col1 int, col2 enum('egwjqebwq', 'qwewqewqeqewq', 'weueiwqeowqehwgqjhenw') primary key)",
   838  	}
   839  	runTestShouldError(mock, t, sqls)
   840  }
   841  
   842  func TestShow(t *testing.T) {
   843  	mock := NewMockOptimizer(false)
   844  	// should pass
   845  	sqls := []string{
   846  		"show variables",
   847  		//"show create database tpch",
   848  		"show create table nation",
   849  		"show create table tpch.nation",
   850  		"show databases",
   851  		"show databases like '%d'",
   852  		"show databases where `database` = '11'",
   853  		"show databases where `database` = '11' or `database` = 'ddd'",
   854  		"show tables",
   855  		"show tables from tpch",
   856  		"show tables like '%dd'",
   857  		"show tables from tpch where `tables_in_tpch` = 'aa' or `tables_in_tpch` like '%dd'",
   858  		"show columns from nation",
   859  		"show full columns from nation",
   860  		"show columns from nation from tpch",
   861  		"show full columns from nation from tpch",
   862  		"show columns from nation where `field` like '%ff' or `type` = 1 or `null` = 0",
   863  		"show full columns from nation where `field` like '%ff' or `type` = 1 or `null` = 0",
   864  		"show create view v1",
   865  		"show create table v1",
   866  		"show table_number",
   867  		"show table_number from tpch",
   868  		"show column_number from nation",
   869  		"show config",
   870  		"show index from tpch.nation",
   871  		"show locks",
   872  		"show node list",
   873  		"show grants for ROLE role1",
   874  		"show function status",
   875  		"show function status like '%ff'",
   876  		"show snapshots",
   877  		"show snapshots where SNAPSHOT_NAME = 'snapshot_07'",
   878  		// "show procedure status",
   879  		// "show procedure status like '%ff'",
   880  		"show roles",
   881  		"show roles like '%ff'",
   882  		"show stages",
   883  		"show stages like 'my_stage%'",
   884  		// "show grants",
   885  	}
   886  	runTestShouldPass(mock, t, sqls, false, false)
   887  
   888  	// should error
   889  	sqls = []string{
   890  		"show create database db_not_exist",                    //db no exist
   891  		"show create table tpch.nation22",                      //table not exist
   892  		"show create view vvv",                                 //view not exist
   893  		"show databases where d ='a'",                          //Column not exist,  show databases only have one column named 'Database'
   894  		"show databases where `Databaseddddd` = '11'",          //column not exist
   895  		"show tables from tpch22222",                           //database not exist
   896  		"show tables from tpch where Tables_in_tpch222 = 'aa'", //column not exist
   897  		"show columns from nation_ddddd",                       //table not exist
   898  		"show full columns from nation_ddddd",
   899  		"show columns from nation_ddddd from tpch", //table not exist
   900  		"show full columns from nation_ddddd from tpch",
   901  		"show columns from nation where `Field22` like '%ff'", //column not exist
   902  		"show full columns from nation where `Field22` like '%ff'",
   903  		"show index from tpch.dddd",
   904  		"show table_number from tpch222",
   905  		"show column_number from nation222",
   906  	}
   907  	runTestShouldError(mock, t, sqls)
   908  }
   909  
   910  func TestResultColumns(t *testing.T) {
   911  	mock := NewMockOptimizer(false)
   912  	getColumns := func(sql string) []*ColDef {
   913  		logicPlan, err := runOneStmt(mock, t, sql)
   914  		if err != nil {
   915  			t.Fatalf("sql %s build plan error:%+v", sql, err)
   916  		}
   917  		return GetResultColumnsFromPlan(logicPlan)
   918  	}
   919  
   920  	returnNilSQL := []string{
   921  		"begin",
   922  		"commit",
   923  		"rollback",
   924  		"INSERT NATION VALUES (1, 'NAME1',21, 'COMMENT1'), (2, 'NAME2', 22, 'COMMENT2')",
   925  		// "UPDATE NATION SET N_NAME ='U1', N_REGIONKEY=2",
   926  		// "DELETE FROM NATION",
   927  		//"create database db_name",
   928  		//"drop database tpch",
   929  		//"create table tbl_name (b int unsigned, c char(20))",
   930  		//"drop table nation",
   931  	}
   932  	for _, sql := range returnNilSQL {
   933  		columns := getColumns(sql)
   934  		if columns != nil {
   935  			t.Fatalf("sql:%+v, return columns should be nil", sql)
   936  		}
   937  	}
   938  
   939  	returnColumnsSQL := map[string]string{
   940  		"SELECT N_NAME, N_REGIONKEY a FROM NATION WHERE N_REGIONKEY > 0 ORDER BY a DESC":            "N_NAME,a",
   941  		"select n_nationkey, sum(n_regionkey) from (select * from nation) sub group by n_nationkey": "n_nationkey,sum(n_regionkey)",
   942  		"show variables":            "Variable_name,Value",
   943  		"show create database tpch": "Database,Create Database",
   944  		"show create table nation":  "Table,Create Table",
   945  		"show databases":            "Database",
   946  		"show tables":               "Tables_in_tpch",
   947  		"show columns from nation":  "Field,Type,Null,Key,Default,Extra,Comment",
   948  	}
   949  	for sql, colsStr := range returnColumnsSQL {
   950  		cols := strings.Split(colsStr, ",")
   951  		columns := getColumns(sql)
   952  		if len(columns) != len(cols) {
   953  			t.Fatalf("sql:%+v, return columns should be [%s]", sql, colsStr)
   954  		}
   955  		for idx, col := range cols {
   956  			// now ast always change col_name to lower string. will be fixed soon
   957  			if !strings.EqualFold(columns[idx].Name, col) {
   958  				t.Fatalf("sql:%+v, return columns should be [%s]", sql, colsStr)
   959  			}
   960  		}
   961  	}
   962  }
   963  
   964  func TestResultColumns2(t *testing.T) {
   965  	mock := NewMockOptimizer(true)
   966  	getColumns := func(sql string) []*ColDef {
   967  		logicPlan, err := runOneStmt(mock, t, sql)
   968  		if err != nil {
   969  			t.Fatalf("sql %s build plan error:%+v", sql, err)
   970  		}
   971  		return GetResultColumnsFromPlan(logicPlan)
   972  	}
   973  
   974  	returnNilSQL := []string{
   975  		"create database db_name",
   976  		"drop database tpch",
   977  		"create table tbl_name (b int unsigned, c char(20))",
   978  		"drop table nation",
   979  	}
   980  	for _, sql := range returnNilSQL {
   981  		columns := getColumns(sql)
   982  		if columns != nil {
   983  			t.Fatalf("sql:%+v, return columns should be nil", sql)
   984  		}
   985  	}
   986  
   987  	returnColumnsSQL := map[string]string{
   988  		"SELECT N_NAME, N_REGIONKEY a FROM NATION WHERE N_REGIONKEY > 0 ORDER BY a DESC":            "N_NAME,a",
   989  		"select n_nationkey, sum(n_regionkey) from (select * from nation) sub group by n_nationkey": "n_nationkey,sum(n_regionkey)",
   990  		"show variables":            "Variable_name,Value",
   991  		"show create database tpch": "Database,Create Database",
   992  		"show create table nation":  "Table,Create Table",
   993  		"show databases":            "Database",
   994  		"show tables":               "Tables_in_tpch",
   995  		"show columns from nation":  "Field,Type,Null,Key,Default,Extra,Comment",
   996  	}
   997  	for sql, colsStr := range returnColumnsSQL {
   998  		cols := strings.Split(colsStr, ",")
   999  		columns := getColumns(sql)
  1000  		if len(columns) != len(cols) {
  1001  			t.Fatalf("sql:%+v, return columns should be [%s]", sql, colsStr)
  1002  		}
  1003  		for idx, col := range cols {
  1004  			// now ast always change col_name to lower string. will be fixed soon
  1005  			if !strings.EqualFold(columns[idx].Name, col) {
  1006  				t.Fatalf("sql:%+v, return columns should be [%s]", sql, colsStr)
  1007  			}
  1008  		}
  1009  	}
  1010  }
  1011  
  1012  func TestBuildUnnest(t *testing.T) {
  1013  	mock := NewMockOptimizer(false)
  1014  	sqls := []string{
  1015  		`select * from unnest('{"a":1}') as f`,
  1016  		`select * from unnest('{"a":1}', '') as f`,
  1017  		`select * from unnest('{"a":1}', '$', true) as f`,
  1018  	}
  1019  	runTestShouldPass(mock, t, sqls, false, false)
  1020  	errSqls := []string{
  1021  		`select * from unnest(t.t1.a)`,
  1022  		`select * from unnest(t.a, "$.b")`,
  1023  		`select * from unnest(t.a, "$.b", true)`,
  1024  		`select * from unnest(t.a) as f`,
  1025  		`select * from unnest(t.a, "$.b") as f`,
  1026  		`select * from unnest(t.a, "$.b", true) as f`,
  1027  		`select * from unnest('{"a":1}')`,
  1028  		`select * from unnest('{"a":1}', "$")`,
  1029  		`select * from unnest('{"a":1}', "", true)`,
  1030  	}
  1031  	runTestShouldError(mock, t, errSqls)
  1032  }
  1033  
  1034  func TestVisitRule(t *testing.T) {
  1035  	sql := "select * from nation where n_nationkey > 10 or n_nationkey=@int_var or abs(-1) > 1"
  1036  	mock := NewMockOptimizer(false)
  1037  	ctx := context.TODO()
  1038  	plan, err := runOneStmt(mock, t, sql)
  1039  	if err != nil {
  1040  		t.Fatalf("should not error, sql=%s", sql)
  1041  	}
  1042  	getParamRule := NewGetParamRule()
  1043  	vp := NewVisitPlan(plan, []VisitPlanRule{getParamRule})
  1044  	err = vp.Visit(context.TODO())
  1045  	if err != nil {
  1046  		t.Fatalf("should not error, sql=%s", sql)
  1047  	}
  1048  	getParamRule.SetParamOrder()
  1049  	args := getParamRule.params
  1050  
  1051  	resetParamOrderRule := NewResetParamOrderRule(args)
  1052  	vp = NewVisitPlan(plan, []VisitPlanRule{resetParamOrderRule})
  1053  	err = vp.Visit(ctx)
  1054  	if err != nil {
  1055  		t.Fatalf("should not error, sql=%s", sql)
  1056  	}
  1057  
  1058  	params := []*Expr{
  1059  		makePlan2Int64ConstExprWithType(10),
  1060  	}
  1061  	resetParamRule := NewResetParamRefRule(ctx, params)
  1062  	resetVarRule := NewResetVarRefRule(&mock.ctxt, testutil.NewProc())
  1063  	constantFoldRule := NewConstantFoldRule(&mock.ctxt)
  1064  	vp = NewVisitPlan(plan, []VisitPlanRule{resetParamRule, resetVarRule, constantFoldRule})
  1065  	err = vp.Visit(ctx)
  1066  	if err != nil {
  1067  		t.Fatalf("should not error, sql=%s", sql)
  1068  	}
  1069  }
  1070  
  1071  func getJSON(v any, t *testing.T) []byte {
  1072  	b, err := json.Marshal(v)
  1073  	if err != nil {
  1074  		t.Logf("%+v", v)
  1075  	}
  1076  	var out bytes.Buffer
  1077  	err = json.Indent(&out, b, "", "  ")
  1078  	if err != nil {
  1079  		t.Logf("%+v", v)
  1080  	}
  1081  	return out.Bytes()
  1082  }
  1083  
  1084  func testDeepCopy(logicPlan *Plan) {
  1085  	switch logicPlan.Plan.(type) {
  1086  	case *plan.Plan_Query:
  1087  		_ = DeepCopyPlan(logicPlan)
  1088  	case *plan.Plan_Ddl:
  1089  		_ = DeepCopyPlan(logicPlan)
  1090  	case *plan.Plan_Dcl:
  1091  	}
  1092  }
  1093  
  1094  func outPutPlan(logicPlan *Plan, toFile bool, t *testing.T) {
  1095  	var json []byte
  1096  	switch logicPlan.Plan.(type) {
  1097  	case *plan.Plan_Query:
  1098  		json = getJSON(logicPlan.GetQuery(), t)
  1099  	case *plan.Plan_Tcl:
  1100  		json = getJSON(logicPlan.GetTcl(), t)
  1101  	case *plan.Plan_Ddl:
  1102  		json = getJSON(logicPlan.GetDdl(), t)
  1103  	case *plan.Plan_Dcl:
  1104  		json = getJSON(logicPlan.GetDcl(), t)
  1105  	}
  1106  	if toFile {
  1107  		err := os.WriteFile("/tmp/mo_plan_test.json", json, 0777)
  1108  		if err != nil {
  1109  			t.Logf("%+v", err)
  1110  		}
  1111  	} else {
  1112  		t.Logf(string(json))
  1113  	}
  1114  }
  1115  
  1116  func runOneStmt(opt Optimizer, t *testing.T, sql string) (*Plan, error) {
  1117  	stmts, err := mysql.Parse(opt.CurrentContext().GetContext(), sql, 1, 0)
  1118  	if err != nil {
  1119  		t.Fatalf("%+v", err)
  1120  	}
  1121  	// this sql always return one stmt
  1122  	ctx := opt.CurrentContext()
  1123  	return BuildPlan(ctx, stmts[0], false)
  1124  }
  1125  
  1126  func runTestShouldPass(opt Optimizer, t *testing.T, sqls []string, printJSON bool, toFile bool) {
  1127  	for _, sql := range sqls {
  1128  		logicPlan, err := runOneStmt(opt, t, sql)
  1129  		if err != nil {
  1130  			t.Fatalf("%+v, sql=%v", err, sql)
  1131  		}
  1132  		testDeepCopy(logicPlan)
  1133  		if printJSON {
  1134  			outPutPlan(logicPlan, toFile, t)
  1135  		}
  1136  	}
  1137  }
  1138  
  1139  func runTestShouldError(opt Optimizer, t *testing.T, sqls []string) {
  1140  	for _, sql := range sqls {
  1141  		_, err := runOneStmt(opt, t, sql)
  1142  		if err == nil {
  1143  			t.Fatalf("should error, but pass: %v", sql)
  1144  		}
  1145  	}
  1146  }
  1147  
  1148  func Test_mergeContexts(t *testing.T) {
  1149  	b1 := NewBinding(0, 1, "db", "a", 0, nil, nil, nil, false, nil)
  1150  	bc1 := NewBindContext(nil, nil)
  1151  	bc1.bindings = append(bc1.bindings, b1)
  1152  
  1153  	b2 := NewBinding(1, 2, "db", "a", 0, nil, nil, nil, false, nil)
  1154  	bc2 := NewBindContext(nil, nil)
  1155  	bc2.bindings = append(bc2.bindings, b2)
  1156  
  1157  	bc := NewBindContext(nil, nil)
  1158  
  1159  	//a merge a
  1160  	err := bc.mergeContexts(context.Background(), bc1, bc2)
  1161  	assert.Error(t, err)
  1162  	assert.EqualError(t, err, "invalid input: table 'a' specified more than once")
  1163  
  1164  	//a merge b
  1165  	b3 := NewBinding(2, 3, "db", "b", 0, nil, nil, nil, false, nil)
  1166  	bc3 := NewBindContext(nil, nil)
  1167  	bc3.bindings = append(bc3.bindings, b3)
  1168  
  1169  	err = bc.mergeContexts(context.Background(), bc1, bc3)
  1170  	assert.NoError(t, err)
  1171  
  1172  	// a merge a, ctx is  nil
  1173  	var ctx context.Context
  1174  	err = bc.mergeContexts(ctx, bc1, bc2)
  1175  	assert.Error(t, err)
  1176  	assert.EqualError(t, err, "invalid input: table 'a' specified more than once")
  1177  }