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 }