github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/plan/build_ddl_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  	"context"
    19  	"encoding/json"
    20  	"testing"
    21  
    22  	moruntime "github.com/matrixorigin/matrixone/pkg/common/runtime"
    23  	"github.com/matrixorigin/matrixone/pkg/util/executor"
    24  
    25  	"github.com/golang/mock/gomock"
    26  	"github.com/matrixorigin/matrixone/pkg/catalog"
    27  	"github.com/matrixorigin/matrixone/pkg/container/types"
    28  	"github.com/matrixorigin/matrixone/pkg/pb/plan"
    29  	"github.com/matrixorigin/matrixone/pkg/sql/parsers"
    30  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect"
    31  	"github.com/matrixorigin/matrixone/pkg/sql/parsers/tree"
    32  	"github.com/stretchr/testify/assert"
    33  )
    34  
    35  func TestBuildAlterView(t *testing.T) {
    36  	ctrl := gomock.NewController(t)
    37  	defer ctrl.Finish()
    38  
    39  	type arg struct {
    40  		obj   *ObjectRef
    41  		table *TableDef
    42  	}
    43  
    44  	sql1 := "alter view v as select a from a"
    45  	sql2 := "alter view v as select a from v"
    46  	sql3 := "alter view v as select a from vx"
    47  
    48  	store := make(map[string]arg)
    49  
    50  	vData, err := json.Marshal(ViewData{
    51  		"create view v as select a from a",
    52  		"db",
    53  	})
    54  	assert.NoError(t, err)
    55  
    56  	store["db.v"] = arg{&plan.ObjectRef{},
    57  		&plan.TableDef{
    58  			TableType: catalog.SystemViewRel,
    59  			ViewSql: &plan.ViewDef{
    60  				View: string(vData),
    61  			}},
    62  	}
    63  
    64  	vxData, err := json.Marshal(ViewData{
    65  		"create view vx as select a from v",
    66  		"db",
    67  	})
    68  	assert.NoError(t, err)
    69  	store["db.vx"] = arg{&plan.ObjectRef{},
    70  		&plan.TableDef{
    71  			TableType: catalog.SystemViewRel,
    72  			ViewSql: &plan.ViewDef{
    73  				View: string(vxData),
    74  			}},
    75  	}
    76  
    77  	store["db.a"] = arg{
    78  		&plan.ObjectRef{},
    79  		&plan.TableDef{
    80  			TableType: catalog.SystemOrdinaryRel,
    81  			Cols: []*ColDef{
    82  				{
    83  					Name: "a",
    84  					Typ: plan.Type{
    85  						Id:    int32(types.T_varchar),
    86  						Width: types.MaxVarcharLen,
    87  						Table: "a",
    88  					},
    89  				},
    90  			},
    91  		}}
    92  
    93  	store["db.verror"] = arg{&plan.ObjectRef{},
    94  		&plan.TableDef{
    95  			TableType: catalog.SystemViewRel},
    96  	}
    97  
    98  	ctx := NewMockCompilerContext2(ctrl)
    99  	ctx.EXPECT().GetUserName().Return("sys:dump").AnyTimes()
   100  	ctx.EXPECT().DefaultDatabase().Return("db").AnyTimes()
   101  	ctx.EXPECT().Resolve(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(
   102  		func(schemaName string, tableName string, snapshot Snapshot) (*ObjectRef, *TableDef) {
   103  			if schemaName == "" {
   104  				schemaName = "db"
   105  			}
   106  			x := store[schemaName+"."+tableName]
   107  			return x.obj, x.table
   108  		}).AnyTimes()
   109  	ctx.EXPECT().SetBuildingAlterView(gomock.Any(), gomock.Any(), gomock.Any()).AnyTimes()
   110  	ctx.EXPECT().ResolveVariable(gomock.Any(), gomock.Any(), gomock.Any()).Return("", nil).AnyTimes()
   111  	ctx.EXPECT().GetAccountId().Return(catalog.System_Account, nil).AnyTimes()
   112  	ctx.EXPECT().GetContext().Return(context.Background()).AnyTimes()
   113  	ctx.EXPECT().GetProcess().Return(nil).AnyTimes()
   114  	ctx.EXPECT().Stats(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
   115  	ctx.EXPECT().GetQueryingSubscription().Return(nil).AnyTimes()
   116  	ctx.EXPECT().DatabaseExists(gomock.Any(), gomock.Any()).Return(true).AnyTimes()
   117  	ctx.EXPECT().ResolveById(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
   118  	ctx.EXPECT().GetStatsCache().Return(nil).AnyTimes()
   119  	ctx.EXPECT().GetSnapshot().Return(nil).AnyTimes()
   120  	ctx.EXPECT().SetViews(gomock.Any()).AnyTimes()
   121  	ctx.EXPECT().SetSnapshot(gomock.Any()).AnyTimes()
   122  
   123  	ctx.EXPECT().GetRootSql().Return(sql1).AnyTimes()
   124  	stmt1, err := parsers.ParseOne(context.Background(), dialect.MYSQL, sql1, 1, 0)
   125  	assert.NoError(t, err)
   126  	_, err = buildAlterView(stmt1.(*tree.AlterView), ctx)
   127  	assert.NoError(t, err)
   128  
   129  	//direct recursive refrence
   130  	ctx.EXPECT().GetRootSql().Return(sql2).AnyTimes()
   131  	ctx.EXPECT().GetBuildingAlterView().Return(true, "db", "v").AnyTimes()
   132  	stmt2, err := parsers.ParseOne(context.Background(), dialect.MYSQL, sql2, 1, 0)
   133  	assert.NoError(t, err)
   134  	_, err = buildAlterView(stmt2.(*tree.AlterView), ctx)
   135  	assert.Error(t, err)
   136  	assert.EqualError(t, err, "internal error: there is a recursive reference to the view v")
   137  
   138  	//indirect recursive refrence
   139  	stmt3, err := parsers.ParseOne(context.Background(), dialect.MYSQL, sql3, 1, 0)
   140  	ctx.EXPECT().GetBuildingAlterView().Return(true, "db", "vx").AnyTimes()
   141  	assert.NoError(t, err)
   142  	_, err = buildAlterView(stmt3.(*tree.AlterView), ctx)
   143  	assert.Error(t, err)
   144  	assert.EqualError(t, err, "internal error: there is a recursive reference to the view v")
   145  
   146  	sql4 := "alter view noexists as select a from a"
   147  	stmt4, err := parsers.ParseOne(context.Background(), dialect.MYSQL, sql4, 1, 0)
   148  	assert.NoError(t, err)
   149  	_, err = buildAlterView(stmt4.(*tree.AlterView), ctx)
   150  	assert.Error(t, err)
   151  
   152  	sql5 := "alter view verror as select a from a"
   153  	stmt5, err := parsers.ParseOne(context.Background(), dialect.MYSQL, sql5, 1, 0)
   154  	assert.NoError(t, err)
   155  	_, err = buildAlterView(stmt5.(*tree.AlterView), ctx)
   156  	assert.Error(t, err)
   157  }
   158  
   159  func TestBuildLockTables(t *testing.T) {
   160  	ctrl := gomock.NewController(t)
   161  	defer ctrl.Finish()
   162  
   163  	type arg struct {
   164  		obj   *ObjectRef
   165  		table *TableDef
   166  	}
   167  
   168  	store := make(map[string]arg)
   169  
   170  	sql1 := "lock tables t1 read"
   171  	sql2 := "lock tables t1 read, t2 write"
   172  	sql3 := "lock tables t1 read, t1 write"
   173  
   174  	store["db.t1"] = arg{
   175  		&plan.ObjectRef{},
   176  		&plan.TableDef{
   177  			TableType: catalog.SystemOrdinaryRel,
   178  			Cols: []*ColDef{
   179  				{
   180  					Name: "a",
   181  					Typ: plan.Type{
   182  						Id:    int32(types.T_varchar),
   183  						Width: types.MaxVarcharLen,
   184  						Table: "t1",
   185  					},
   186  				},
   187  			},
   188  		}}
   189  
   190  	ctx := NewMockCompilerContext2(ctrl)
   191  	ctx.EXPECT().DefaultDatabase().Return("db").AnyTimes()
   192  	ctx.EXPECT().Resolve(gomock.Any(), gomock.Any(), gomock.Any()).DoAndReturn(
   193  		func(schemaName string, tableName string, snapshot Snapshot) (*ObjectRef, *TableDef) {
   194  			if schemaName == "" {
   195  				schemaName = "db"
   196  			}
   197  			x := store[schemaName+"."+tableName]
   198  			return x.obj, x.table
   199  		}).AnyTimes()
   200  	ctx.EXPECT().ResolveVariable(gomock.Any(), gomock.Any(), gomock.Any()).Return("", nil).AnyTimes()
   201  	ctx.EXPECT().GetAccountId().Return(catalog.System_Account, nil).AnyTimes()
   202  	ctx.EXPECT().GetContext().Return(context.Background()).AnyTimes()
   203  	ctx.EXPECT().GetProcess().Return(nil).AnyTimes()
   204  	ctx.EXPECT().Stats(gomock.Any(), gomock.Any()).Return(nil, nil).AnyTimes()
   205  
   206  	ctx.EXPECT().GetRootSql().Return(sql1).AnyTimes()
   207  	stmt1, err := parsers.ParseOne(context.Background(), dialect.MYSQL, sql1, 1, 0)
   208  	assert.NoError(t, err)
   209  	_, err = buildLockTables(stmt1.(*tree.LockTableStmt), ctx)
   210  	assert.NoError(t, err)
   211  
   212  	ctx.EXPECT().GetRootSql().Return(sql2).AnyTimes()
   213  	stmt2, err := parsers.ParseOne(context.Background(), dialect.MYSQL, sql2, 1, 0)
   214  	assert.NoError(t, err)
   215  	_, err = buildLockTables(stmt2.(*tree.LockTableStmt), ctx)
   216  	assert.Error(t, err)
   217  
   218  	store["db.t2"] = arg{
   219  		&plan.ObjectRef{},
   220  		&plan.TableDef{
   221  			TableType: catalog.SystemOrdinaryRel,
   222  			Cols: []*ColDef{
   223  				{
   224  					Name: "a",
   225  					Typ: plan.Type{
   226  						Id:    int32(types.T_varchar),
   227  						Width: types.MaxVarcharLen,
   228  						Table: "t2",
   229  					},
   230  				},
   231  			},
   232  		}}
   233  
   234  	_, err = buildLockTables(stmt2.(*tree.LockTableStmt), ctx)
   235  	assert.NoError(t, err)
   236  
   237  	ctx.EXPECT().GetRootSql().Return(sql3).AnyTimes()
   238  	stmt3, err := parsers.ParseOne(context.Background(), dialect.MYSQL, sql3, 1, 0)
   239  	assert.NoError(t, err)
   240  	_, err = buildLockTables(stmt3.(*tree.LockTableStmt), ctx)
   241  	assert.Error(t, err)
   242  }
   243  
   244  func TestBuildCreateTable(t *testing.T) {
   245  	mock := NewMockOptimizer(false)
   246  	rt := moruntime.DefaultRuntime()
   247  	moruntime.SetupProcessLevelRuntime(rt)
   248  	moruntime.ProcessLevelRuntime().SetGlobalVariables(moruntime.InternalSQLExecutor, executor.NewMemExecutor(func(sql string) (executor.Result, error) {
   249  		return executor.Result{}, nil
   250  	}))
   251  	sqls := []string{
   252  		`CREATE TABLE t3(
   253  					col1 INT NOT NULL,
   254  					col2 DATE NOT NULL UNIQUE KEY,
   255  					col3 INT NOT NULL,
   256  					col4 INT NOT NULL,
   257  					PRIMARY KEY (col1),
   258  					KEY(col3),
   259  					KEY(col3) )`,
   260  		`CREATE TABLE t2 (
   261  						col1 INT NOT NULL,
   262  						col2 DATE NOT NULL,
   263  						col3 INT NOT NULL,
   264  						col4 INT NOT NULL,
   265  						UNIQUE KEY (col1),
   266  						UNIQUE KEY (col3)
   267  					);`,
   268  		`CREATE TABLE t2 (
   269  						col1 INT NOT NULL,
   270  						col2 DATE NOT NULL,
   271  						col3 INT NOT NULL,
   272  						col4 INT NOT NULL,
   273  						UNIQUE KEY (col1),
   274  						UNIQUE KEY (col1, col3)
   275  					);`,
   276  		`CREATE TABLE t2 (
   277  					col1 INT NOT NULL KEY,
   278  					col2 DATE NOT NULL,
   279  					col3 INT NOT NULL,
   280  					col4 INT NOT NULL,
   281  					UNIQUE KEY (col1),
   282  					UNIQUE KEY (col1, col3)
   283  				);`,
   284  
   285  		`CREATE TABLE t2 (
   286  					col1 INT NOT NULL,
   287  					col2 DATE NOT NULL,
   288  					col3 INT NOT NULL,
   289  					col4 INT NOT NULL,
   290  					KEY (col1)
   291  				);`,
   292  
   293  		`CREATE TABLE t2 (
   294  					col1 INT NOT NULL KEY,
   295  					col2 DATE NOT NULL,
   296  					col3 INT NOT NULL,
   297  					col4 INT NOT NULL
   298  				);`,
   299  
   300  		`CREATE TABLE t2 (
   301  					col1 INT NOT NULL KEY,
   302  					col2 DATE NOT NULL,
   303  					col3 INT NOT NULL,
   304  					col4 INT NOT NULL,
   305  					KEY (col1)
   306  				);`,
   307  
   308  		`CREATE TABLE t2 (
   309  					col1 INT NOT NULL,
   310  					col2 DATE NOT NULL,
   311  					col3 INT NOT NULL,
   312  					col4 INT NOT NULL,
   313  					KEY (col1)
   314  				);`,
   315  
   316  		`CREATE TABLE t2 (
   317  					col1 INT NOT NULL KEY,
   318  					col2 DATE NOT NULL,
   319  					col3 INT NOT NULL,
   320  					col4 INT NOT NULL,
   321  					UNIQUE KEY (col1),
   322  					UNIQUE KEY (col1, col3)
   323  				);`,
   324  
   325  		`CREATE TABLE t1 (
   326  			col1 INT NOT NULL,
   327  			col2 DATE NOT NULL,
   328  			col3 INT NOT NULL,
   329  			col4 INT NOT NULL,
   330  			UNIQUE KEY (col1 DESC)
   331  		);`,
   332  
   333  		`CREATE TABLE t2 (
   334  			col1 INT NOT NULL,
   335  			col2 DATE NOT NULL,
   336  			col3 INT NOT NULL,
   337  			col4 INT NOT NULL,
   338  			UNIQUE KEY (col1 ASC)
   339  		);`,
   340  
   341  		"CREATE TABLE t2 (" +
   342  			"	`PRIMARY` INT NOT NULL, " +
   343  			"	col2 DATE NOT NULL, " +
   344  			"	col3 INT NOT NULL," +
   345  			"	col4 INT NOT NULL," +
   346  			"	UNIQUE KEY (`PRIMARY`)," +
   347  			"	UNIQUE KEY (`PRIMARY`, col3)" +
   348  			");",
   349  	}
   350  	runTestShouldPass(mock, t, sqls, false, false)
   351  }
   352  
   353  func TestBuildCreateTableError(t *testing.T) {
   354  	mock := NewMockOptimizer(false)
   355  	sqlerrs := []string{
   356  		`CREATE TABLE t1 (
   357  			col1 INT NOT NULL,
   358  			col2 DATE NOT NULL unique key,
   359  			col3 INT NOT NULL,
   360  			col4 INT NOT NULL,
   361  			PRIMARY KEY (col1),
   362  			unique key col2 (col3)
   363  		);`,
   364  
   365  		`CREATE TABLE t1 (
   366  			col1 INT NOT NULL,
   367  			col2 DATE NOT NULL,
   368  			col3 INT NOT NULL,
   369  			col4 INT NOT NULL,
   370  			PRIMARY KEY (col1),
   371  			unique key idx_sp1 (col2),
   372  			unique key idx_sp1 (col3)
   373  		);`,
   374  
   375  		`CREATE TABLE t1 (
   376  			col1 INT NOT NULL,
   377  			col2 DATE NOT NULL,
   378  			col3 INT NOT NULL,
   379  			col4 INT NOT NULL,
   380  			PRIMARY KEY (col1),
   381  			unique key idx_sp1 (col2),
   382  			key idx_sp1 (col3)
   383  		);`,
   384  
   385  		`CREATE TABLE t2 (
   386  			col1 INT NOT NULL,
   387  			col2 DATE NOT NULL UNIQUE KEY,
   388  			col3 INT NOT NULL,
   389  			col4 INT NOT NULL,
   390  			PRIMARY KEY (col1),
   391  			KEY col2 (col3)
   392  		);`,
   393  
   394  		`CREATE TABLE t2 (
   395  			col1 INT NOT NULL KEY,
   396  			col2 DATE NOT NULL KEY,
   397  			col3 INT NOT NULL,
   398  			col4 INT NOT NULL
   399  		);`,
   400  
   401  		`CREATE TABLE t3 (
   402  			col1 INT NOT NULL,
   403  			col2 DATE NOT NULL,
   404  			col3 INT NOT NULL,
   405  			col4 INT NOT NULL,
   406  			UNIQUE KEY uk1 ((col1 + col3))
   407  		);`,
   408  	}
   409  	runTestShouldError(mock, t, sqlerrs)
   410  }
   411  
   412  func TestBuildAlterTable(t *testing.T) {
   413  	mock := NewMockOptimizer(false)
   414  	// should pass
   415  	sqls := []string{
   416  		"ALTER TABLE emp ADD UNIQUE idx1 (empno, ename);",
   417  		"ALTER TABLE emp ADD UNIQUE INDEX idx1 (empno, ename);",
   418  		"ALTER TABLE emp ADD INDEX idx1 (ename, sal);",
   419  		"ALTER TABLE emp ADD INDEX idx2 (ename, sal DESC);",
   420  		"ALTER TABLE emp ADD UNIQUE INDEX idx1 (empno ASC);",
   421  		//"alter table emp drop foreign key fk1",
   422  		//"alter table nation add FOREIGN KEY fk_t1(n_nationkey) REFERENCES nation2(n_nationkey)",
   423  	}
   424  	runTestShouldPass(mock, t, sqls, false, false)
   425  }
   426  
   427  func TestBuildAlterTableError(t *testing.T) {
   428  	mock := NewMockOptimizer(false)
   429  	// should pass
   430  	sqls := []string{
   431  		"ALTER TABLE emp ADD UNIQUE idx1 ((empno+1) DESC, ename);",
   432  		"ALTER TABLE emp ADD INDEX idx2 (ename, (sal*30) DESC);",
   433  		"ALTER TABLE emp ADD UNIQUE INDEX idx1 ((empno+20), (sal*30));",
   434  	}
   435  	runTestShouldError(mock, t, sqls)
   436  }
   437  
   438  func TestCreateSingleTable(t *testing.T) {
   439  	sql := "create cluster table a (a int);"
   440  	mock := NewMockOptimizer(false)
   441  	logicPlan, err := buildSingleStmt(mock, t, sql)
   442  	if err != nil {
   443  		t.Fatalf("%+v", err)
   444  	}
   445  	outPutPlan(logicPlan, true, t)
   446  }
   447  
   448  func TestCreateTableAsSelect(t *testing.T) {
   449  	mock := NewMockOptimizer(false)
   450  	sqls := []string{"CREATE TABLE t1 (a int, b char(5)); CREATE TABLE t2 (c float) as select b, a from t1"}
   451  	runTestShouldPass(mock, t, sqls, false, false)
   452  }