github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/plan/build_ddl.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 "encoding/json" 19 "fmt" 20 "strconv" 21 "strings" 22 23 "github.com/matrixorigin/matrixone/pkg/catalog" 24 "github.com/matrixorigin/matrixone/pkg/common/moerr" 25 "github.com/matrixorigin/matrixone/pkg/container/types" 26 "github.com/matrixorigin/matrixone/pkg/defines" 27 "github.com/matrixorigin/matrixone/pkg/pb/plan" 28 "github.com/matrixorigin/matrixone/pkg/sql/parsers/dialect" 29 "github.com/matrixorigin/matrixone/pkg/sql/parsers/tree" 30 "github.com/matrixorigin/matrixone/pkg/sql/plan/function/operator" 31 "github.com/matrixorigin/matrixone/pkg/sql/util" 32 ) 33 34 func genViewTableDef(ctx CompilerContext, stmt *tree.Select) (*plan.TableDef, error) { 35 var tableDef plan.TableDef 36 37 // check view statement 38 stmtPlan, err := runBuildSelectByBinder(plan.Query_SELECT, ctx, stmt) 39 if err != nil { 40 return nil, err 41 } 42 43 query := stmtPlan.GetQuery() 44 cols := make([]*plan.ColDef, len(query.Nodes[query.Steps[len(query.Steps)-1]].ProjectList)) 45 for idx, expr := range query.Nodes[query.Steps[len(query.Steps)-1]].ProjectList { 46 cols[idx] = &plan.ColDef{ 47 Name: query.Headings[idx], 48 Alg: plan.CompressType_Lz4, 49 Typ: expr.Typ, 50 Default: &plan.Default{ 51 NullAbility: true, 52 Expr: nil, 53 OriginString: "", 54 }, 55 } 56 } 57 tableDef.Cols = cols 58 59 // Check alter and change the viewsql. 60 viewSql := ctx.GetRootSql() 61 if len(viewSql) != 0 { 62 if viewSql[0] == 'A' { 63 viewSql = strings.Replace(viewSql, "ALTER", "CREATE", 1) 64 } 65 if viewSql[0] == 'a' { 66 viewSql = strings.Replace(viewSql, "alter", "create", 1) 67 } 68 } 69 70 viewData, err := json.Marshal(ViewData{ 71 Stmt: viewSql, 72 DefaultDatabase: ctx.DefaultDatabase(), 73 }) 74 if err != nil { 75 return nil, err 76 } 77 tableDef.ViewSql = &plan.ViewDef{ 78 View: string(viewData), 79 } 80 properties := []*plan.Property{ 81 { 82 Key: catalog.SystemRelAttr_Kind, 83 Value: catalog.SystemViewRel, 84 }, 85 { 86 Key: catalog.SystemRelAttr_CreateSQL, 87 Value: ctx.GetRootSql(), 88 }, 89 } 90 tableDef.Defs = append(tableDef.Defs, &plan.TableDef_DefType{ 91 Def: &plan.TableDef_DefType_Properties{ 92 Properties: &plan.PropertiesDef{ 93 Properties: properties, 94 }, 95 }, 96 }) 97 98 return &tableDef, nil 99 } 100 101 func buildCreateView(stmt *tree.CreateView, ctx CompilerContext) (*Plan, error) { 102 viewName := stmt.Name.ObjectName 103 createTable := &plan.CreateTable{ 104 IfNotExists: stmt.IfNotExists, 105 TableDef: &TableDef{ 106 Name: string(viewName), 107 }, 108 } 109 110 // get database name 111 if len(stmt.Name.SchemaName) == 0 { 112 createTable.Database = "" 113 } else { 114 createTable.Database = string(stmt.Name.SchemaName) 115 } 116 117 tableDef, err := genViewTableDef(ctx, stmt.AsSource) 118 if err != nil { 119 return nil, err 120 } 121 122 createTable.TableDef.Cols = tableDef.Cols 123 createTable.TableDef.ViewSql = tableDef.ViewSql 124 createTable.TableDef.Defs = tableDef.Defs 125 126 return &Plan{ 127 Plan: &plan.Plan_Ddl{ 128 Ddl: &plan.DataDefinition{ 129 DdlType: plan.DataDefinition_CREATE_TABLE, 130 Definition: &plan.DataDefinition_CreateTable{ 131 CreateTable: createTable, 132 }, 133 }, 134 }, 135 }, nil 136 } 137 138 func buildCreateTable(stmt *tree.CreateTable, ctx CompilerContext) (*Plan, error) { 139 createTable := &plan.CreateTable{ 140 IfNotExists: stmt.IfNotExists, 141 Temporary: stmt.Temporary, 142 TableDef: &TableDef{ 143 Name: string(stmt.Table.ObjectName), 144 }, 145 } 146 147 // get database name 148 if len(stmt.Table.SchemaName) == 0 { 149 createTable.Database = ctx.DefaultDatabase() 150 } else { 151 createTable.Database = string(stmt.Table.SchemaName) 152 } 153 154 // set tableDef 155 err := buildTableDefs(stmt, ctx, createTable) 156 if err != nil { 157 return nil, err 158 } 159 160 // set option 161 for _, option := range stmt.Options { 162 switch opt := option.(type) { 163 case *tree.TableOptionProperties: 164 properties := make([]*plan.Property, len(opt.Preperties)) 165 for idx, property := range opt.Preperties { 166 properties[idx] = &plan.Property{ 167 Key: property.Key, 168 Value: property.Value, 169 } 170 } 171 createTable.TableDef.Defs = append(createTable.TableDef.Defs, &plan.TableDef_DefType{ 172 Def: &plan.TableDef_DefType_Properties{ 173 Properties: &plan.PropertiesDef{ 174 Properties: properties, 175 }, 176 }, 177 }) 178 // todo confirm: option data store like this? 179 case *tree.TableOptionComment: 180 if getNumOfCharacters(opt.Comment) > maxLengthOfTableComment { 181 return nil, moerr.NewInvalidInput(ctx.GetContext(), "comment for field '%s' is too long", createTable.TableDef.Name) 182 } 183 184 properties := []*plan.Property{ 185 { 186 Key: catalog.SystemRelAttr_Comment, 187 Value: opt.Comment, 188 }, 189 } 190 createTable.TableDef.Defs = append(createTable.TableDef.Defs, &plan.TableDef_DefType{ 191 Def: &plan.TableDef_DefType_Properties{ 192 Properties: &plan.PropertiesDef{ 193 Properties: properties, 194 }, 195 }, 196 }) 197 // these table options is not support in plan 198 // case *tree.TableOptionEngine, *tree.TableOptionSecondaryEngine, *tree.TableOptionCharset, 199 // *tree.TableOptionCollate, *tree.TableOptionAutoIncrement, *tree.TableOptionComment, 200 // *tree.TableOptionAvgRowLength, *tree.TableOptionChecksum, *tree.TableOptionCompression, 201 // *tree.TableOptionConnection, *tree.TableOptionPassword, *tree.TableOptionKeyBlockSize, 202 // *tree.TableOptionMaxRows, *tree.TableOptionMinRows, *tree.TableOptionDelayKeyWrite, 203 // *tree.TableOptionRowFormat, *tree.TableOptionStatsPersistent, *tree.TableOptionStatsAutoRecalc, 204 // *tree.TableOptionPackKeys, *tree.TableOptionTablespace, *tree.TableOptionDataDirectory, 205 // *tree.TableOptionIndexDirectory, *tree.TableOptionStorageMedia, *tree.TableOptionStatsSamplePages, 206 // *tree.TableOptionUnion, *tree.TableOptionEncryption: 207 // return nil, moerr.NewNotSupported("statement: '%v'", tree.String(stmt, dialect.MYSQL)) 208 default: 209 return nil, moerr.NewNotSupported(ctx.GetContext(), "statement: '%v'", tree.String(stmt, dialect.MYSQL)) 210 } 211 } 212 213 // After handleTableOptions, so begin the partitions processing depend on TableDef 214 if stmt.Param != nil { 215 for i := 0; i < len(stmt.Param.Option); i += 2 { 216 switch strings.ToLower(stmt.Param.Option[i]) { 217 case "endpoint", "region", "access_key_id", "secret_access_key", "bucket", "filepath", "compression", "format", "jsondata", "provider", "role_arn", "external_id": 218 default: 219 return nil, moerr.NewBadConfig(ctx.GetContext(), "the keyword '%s' is not support", strings.ToLower(stmt.Param.Option[i])) 220 } 221 } 222 if err := InitNullMap(stmt.Param, ctx); err != nil { 223 return nil, err 224 } 225 json_byte, err := json.Marshal(stmt.Param) 226 if err != nil { 227 return nil, err 228 } 229 properties := []*plan.Property{ 230 { 231 Key: catalog.SystemRelAttr_Kind, 232 Value: catalog.SystemExternalRel, 233 }, 234 { 235 Key: catalog.SystemRelAttr_CreateSQL, 236 Value: string(json_byte), 237 }, 238 } 239 createTable.TableDef.Defs = append(createTable.TableDef.Defs, &plan.TableDef_DefType{ 240 Def: &plan.TableDef_DefType_Properties{ 241 Properties: &plan.PropertiesDef{ 242 Properties: properties, 243 }, 244 }}) 245 } else { 246 kind := catalog.SystemOrdinaryRel 247 if stmt.IsClusterTable { 248 kind = catalog.SystemClusterRel 249 } 250 properties := []*plan.Property{ 251 { 252 Key: catalog.SystemRelAttr_Kind, 253 Value: kind, 254 }, 255 { 256 Key: catalog.SystemRelAttr_CreateSQL, 257 Value: ctx.GetRootSql(), 258 }, 259 } 260 createTable.TableDef.Defs = append(createTable.TableDef.Defs, &plan.TableDef_DefType{ 261 Def: &plan.TableDef_DefType_Properties{ 262 Properties: &plan.PropertiesDef{ 263 Properties: properties, 264 }, 265 }}) 266 } 267 268 builder := NewQueryBuilder(plan.Query_SELECT, ctx) 269 bindContext := NewBindContext(builder, nil) 270 271 // set partition(unsupport now) 272 if stmt.PartitionOption != nil { 273 nodeID := builder.appendNode(&plan.Node{ 274 NodeType: plan.Node_TABLE_SCAN, 275 Stats: nil, 276 ObjRef: nil, 277 TableDef: createTable.TableDef, 278 BindingTags: []int32{builder.genNewTag()}, 279 }, bindContext) 280 281 err = builder.addBinding(nodeID, tree.AliasClause{}, bindContext) 282 if err != nil { 283 return nil, err 284 } 285 partitionBinder := NewPartitionBinder(builder, bindContext) 286 err = buildPartitionByClause(partitionBinder, stmt, createTable.TableDef) 287 if err != nil { 288 return nil, err 289 } 290 } 291 292 return &Plan{ 293 Plan: &plan.Plan_Ddl{ 294 Ddl: &plan.DataDefinition{ 295 DdlType: plan.DataDefinition_CREATE_TABLE, 296 Definition: &plan.DataDefinition_CreateTable{ 297 CreateTable: createTable, 298 }, 299 }, 300 }, 301 }, nil 302 } 303 304 // buildPartitionByClause build partition by clause info and semantic check. 305 // Currently, sub partition and partition value verification are not supported 306 func buildPartitionByClause(partitionBinder *PartitionBinder, stmt *tree.CreateTable, tableDef *TableDef) (err error) { 307 switch stmt.PartitionOption.PartBy.PType.(type) { 308 case *tree.HashType: 309 err = buildHashPartition(partitionBinder, stmt, tableDef) 310 case *tree.KeyType: 311 err = buildKeyPartition(partitionBinder, stmt, tableDef) 312 case *tree.RangeType: 313 err = buildRangePartition(partitionBinder, stmt, tableDef) 314 case *tree.ListType: 315 err = buildListPartitiion(partitionBinder, stmt, tableDef) 316 } 317 return err 318 } 319 320 func buildTableDefs(stmt *tree.CreateTable, ctx CompilerContext, createTable *plan.CreateTable) error { 321 var primaryKeys []string 322 var indexs []string 323 colMap := make(map[string]*ColDef) 324 uniqueIndexInfos := make([]*tree.UniqueIndex, 0) 325 secondaryIndexInfos := make([]*tree.Index, 0) 326 for _, item := range stmt.Defs { 327 switch def := item.(type) { 328 case *tree.ColumnTableDef: 329 colType, err := getTypeFromAst(ctx.GetContext(), def.Type) 330 if err != nil { 331 return err 332 } 333 if colType.Id == int32(types.T_char) || colType.Id == int32(types.T_varchar) { 334 if colType.GetWidth() > types.MaxStringSize { 335 return moerr.NewInvalidInput(ctx.GetContext(), "string width (%d) is too long", colType.GetWidth()) 336 } 337 } 338 var pks []string 339 var comment string 340 var auto_incr bool 341 for _, attr := range def.Attributes { 342 switch attribute := attr.(type) { 343 case *tree.AttributePrimaryKey: 344 if colType.GetId() == int32(types.T_blob) { 345 return moerr.NewNotSupported(ctx.GetContext(), "blob type in primary key") 346 } 347 if colType.GetId() == int32(types.T_text) { 348 return moerr.NewNotSupported(ctx.GetContext(), "text type in primary key") 349 } 350 if colType.GetId() == int32(types.T_json) { 351 return moerr.NewNotSupported(ctx.GetContext(), fmt.Sprintf("JSON column '%s' cannot be in primary key", def.Name.Parts[0])) 352 } 353 pks = append(pks, def.Name.Parts[0]) 354 case *tree.AttributeComment: 355 comment = attribute.CMT.String() 356 if getNumOfCharacters(comment) > maxLengthOfColumnComment { 357 return moerr.NewInvalidInput(ctx.GetContext(), "comment for column '%s' is too long", def.Name.Parts[0]) 358 } 359 case *tree.AttributeAutoIncrement: 360 auto_incr = true 361 if !operator.IsInteger(types.T(colType.GetId())) { 362 return moerr.NewNotSupported(ctx.GetContext(), "the auto_incr column is only support integer type now") 363 } 364 case *tree.AttributeUnique, *tree.AttributeUniqueKey: 365 uniqueIndexInfos = append(uniqueIndexInfos, &tree.UniqueIndex{ 366 KeyParts: []*tree.KeyPart{ 367 { 368 ColName: def.Name, 369 }, 370 }, 371 }) 372 indexs = append(indexs, def.Name.Parts[0]) 373 } 374 } 375 if len(pks) > 0 { 376 if len(primaryKeys) > 0 { 377 return moerr.NewInvalidInput(ctx.GetContext(), "more than one primary key defined") 378 } 379 primaryKeys = pks 380 } 381 382 defaultValue, err := buildDefaultExpr(def, colType, ctx.GetProcess()) 383 if err != nil { 384 return err 385 } 386 if auto_incr && defaultValue.Expr != nil { 387 return moerr.NewInvalidInput(ctx.GetContext(), "invalid default value for '%s'", def.Name.Parts[0]) 388 } 389 390 onUpdateExpr, err := buildOnUpdate(def, colType, ctx.GetProcess()) 391 if err != nil { 392 return err 393 } 394 395 colType.AutoIncr = auto_incr 396 col := &ColDef{ 397 Name: def.Name.Parts[0], 398 Alg: plan.CompressType_Lz4, 399 Typ: colType, 400 Default: defaultValue, 401 OnUpdate: onUpdateExpr, 402 Comment: comment, 403 } 404 colMap[col.Name] = col 405 createTable.TableDef.Cols = append(createTable.TableDef.Cols, col) 406 case *tree.PrimaryKeyIndex: 407 if len(primaryKeys) > 0 { 408 return moerr.NewInvalidInput(ctx.GetContext(), "more than one primary key defined") 409 } 410 pksMap := map[string]bool{} 411 for _, key := range def.KeyParts { 412 name := key.ColName.Parts[0] // name of primary key column 413 if _, ok := pksMap[name]; ok { 414 return moerr.NewInvalidInput(ctx.GetContext(), "duplicate column name '%s' in primary key", name) 415 } 416 primaryKeys = append(primaryKeys, name) 417 pksMap[name] = true 418 indexs = append(indexs, name) 419 } 420 case *tree.Index: 421 secondaryIndexInfos = append(secondaryIndexInfos, def) 422 for _, key := range def.KeyParts { 423 name := key.ColName.Parts[0] 424 indexs = append(indexs, name) 425 } 426 427 case *tree.UniqueIndex: 428 uniqueIndexInfos = append(uniqueIndexInfos, def) 429 for _, key := range def.KeyParts { 430 name := key.ColName.Parts[0] 431 indexs = append(indexs, name) 432 } 433 case *tree.ForeignKey: 434 refer := def.Refer 435 fkDef := &plan.ForeignKeyDef{ 436 Name: def.Name, 437 Cols: make([]uint64, len(def.KeyParts)), 438 OnDelete: getRefAction(refer.OnDelete), 439 OnUpdate: getRefAction(refer.OnUpdate), 440 ForeignCols: make([]uint64, len(refer.KeyParts)), 441 } 442 443 // get fk columns of create table 444 fkCols := &plan.CreateTable_FkColName{ 445 Cols: make([]string, len(def.KeyParts)), 446 } 447 fkColTyp := make(map[int]*plan.Type) 448 fkColName := make(map[int]string) 449 for i, keyPart := range def.KeyParts { 450 getCol := false 451 colName := keyPart.ColName.Parts[0] 452 for _, col := range createTable.TableDef.Cols { 453 if col.Name == colName { 454 // need to reset to ColId after created. 455 fkDef.Cols[i] = 0 456 fkCols.Cols[i] = colName 457 fkColTyp[i] = col.Typ 458 fkColName[i] = colName 459 getCol = true 460 break 461 } 462 } 463 if !getCol { 464 return moerr.NewInternalError(ctx.GetContext(), "column '%v' no exists in the creating table '%v'", colName, createTable.TableDef.Name) 465 } 466 } 467 createTable.FkCols = append(createTable.FkCols, fkCols) 468 469 // get foreign table & their columns 470 fkTableName := string(refer.TableName.ObjectName) 471 fkDbName := string(refer.TableName.SchemaName) 472 if fkDbName == "" { 473 fkDbName = ctx.DefaultDatabase() 474 } 475 createTable.FkDbs = append(createTable.FkDbs, fkDbName) 476 createTable.FkTables = append(createTable.FkTables, fkTableName) 477 478 _, tableRef := ctx.Resolve(fkDbName, fkTableName) 479 if tableRef == nil { 480 return moerr.NewNoSuchTable(ctx.GetContext(), ctx.DefaultDatabase(), fkTableName) 481 } 482 483 fkDef.ForeignTbl = tableRef.TblId 484 columnIdPos := make(map[uint64]int) 485 columnNamePos := make(map[string]int) 486 uniqueColumn := make(map[string]uint64) 487 for i, col := range tableRef.Cols { 488 columnIdPos[col.ColId] = i 489 columnNamePos[col.Name] = i 490 if col.Primary { 491 uniqueColumn[col.Name] = col.ColId 492 } 493 } 494 if tableRef.Pkey != nil { 495 for _, colName := range tableRef.Pkey.Names { 496 uniqueColumn[colName] = tableRef.Cols[columnNamePos[colName]].ColId 497 } 498 } 499 500 // now tableRef.Indices is empty, you can not test it 501 for _, index := range tableRef.Indexes { 502 if index.Unique { 503 if len(index.Parts) == 1 { 504 uniqueColName := index.Parts[0] 505 colId := tableRef.Cols[columnNamePos[uniqueColName]].ColId 506 uniqueColumn[uniqueColName] = colId 507 } 508 } 509 } 510 511 for i, keyPart := range refer.KeyParts { 512 colName := keyPart.ColName.Parts[0] 513 if _, exists := columnNamePos[colName]; exists { 514 if colId, ok := uniqueColumn[colName]; ok { 515 // check column type 516 if tableRef.Cols[columnIdPos[colId]].Typ.Id != fkColTyp[i].Id { 517 return moerr.NewInternalError(ctx.GetContext(), "type of reference column '%v' is not match for column '%v'", colName, fkColName[i]) 518 } 519 fkDef.ForeignCols[i] = colId 520 } else { 521 return moerr.NewInternalError(ctx.GetContext(), "reference column '%v' is not unique constraint(Unique index or Primary Key)", colName) 522 } 523 } else { 524 return moerr.NewInternalError(ctx.GetContext(), "column '%v' no exists in table '%v'", colName, fkTableName) 525 } 526 } 527 createTable.TableDef.Fkeys = append(createTable.TableDef.Fkeys, fkDef) 528 529 case *tree.CheckIndex, *tree.FullTextIndex: 530 // unsupport in plan. will support in next version. 531 return moerr.NewNYI(ctx.GetContext(), "table def: '%v'", def) 532 default: 533 return moerr.NewNYI(ctx.GetContext(), "table def: '%v'", def) 534 } 535 } 536 537 //add cluster table attribute 538 if stmt.IsClusterTable { 539 if _, ok := colMap[util.GetClusterTableAttributeName()]; ok { 540 return moerr.NewInvalidInput(ctx.GetContext(), "the attribute account_id in the cluster table can not be defined directly by the user") 541 } 542 colType, err := getTypeFromAst(ctx.GetContext(), util.GetClusterTableAttributeType()) 543 if err != nil { 544 return err 545 } 546 colDef := &ColDef{ 547 Name: util.GetClusterTableAttributeName(), 548 Alg: plan.CompressType_Lz4, 549 Typ: colType, 550 NotNull: true, 551 Default: &plan.Default{ 552 Expr: &Expr{ 553 Expr: &plan.Expr_C{ 554 C: &Const{ 555 Isnull: false, 556 Value: &plan.Const_U32Val{U32Val: catalog.System_Account}, 557 }, 558 }, 559 Typ: &plan.Type{ 560 Id: colType.Id, 561 NotNullable: true, 562 }, 563 }, 564 NullAbility: false, 565 }, 566 Comment: "the account_id added by the mo", 567 } 568 colMap[util.GetClusterTableAttributeName()] = colDef 569 createTable.TableDef.Cols = append(createTable.TableDef.Cols, colDef) 570 } 571 572 pkeyName := "" 573 if len(primaryKeys) > 0 { 574 pKeyParts := make([]*ColDef, len(primaryKeys)) 575 for i, primaryKey := range primaryKeys { 576 if coldef, ok := colMap[primaryKey]; !ok { 577 return moerr.NewInvalidInput(ctx.GetContext(), "column '%s' doesn't exist in table", primaryKey) 578 } else { 579 pKeyParts[i] = coldef 580 } 581 } 582 if len(primaryKeys) == 1 { 583 pkeyName = primaryKeys[0] 584 for _, col := range createTable.TableDef.Cols { 585 if col.Name == pkeyName { 586 col.Primary = true 587 createTable.TableDef.Pkey = &PrimaryKeyDef{ 588 Names: primaryKeys, 589 PkeyColName: pkeyName, 590 } 591 break 592 } 593 } 594 } else { 595 pkeyName = util.BuildCompositePrimaryKeyColumnName(primaryKeys) 596 colDef := &ColDef{ 597 Name: pkeyName, 598 Alg: plan.CompressType_Lz4, 599 Typ: &Type{ 600 Id: int32(types.T_varchar), 601 Size: types.VarlenaSize, 602 Width: types.MaxVarcharLen, 603 }, 604 Default: &plan.Default{ 605 NullAbility: false, 606 Expr: nil, 607 OriginString: "", 608 }, 609 } 610 colDef.Primary = true 611 createTable.TableDef.Cols = append(createTable.TableDef.Cols, colDef) 612 colMap[pkeyName] = colDef 613 614 pkeyDef := &PrimaryKeyDef{ 615 Names: primaryKeys, 616 PkeyColName: pkeyName, 617 } 618 createTable.TableDef.Pkey = pkeyDef 619 } 620 for _, primaryKey := range primaryKeys { 621 colMap[primaryKey].Default.NullAbility = false 622 colMap[primaryKey].NotNull = true 623 } 624 } 625 626 //handle cluster by keys 627 if stmt.ClusterByOption != nil { 628 if stmt.Temporary { 629 return moerr.NewNotSupported(ctx.GetContext(), "cluster by with temporary table is not support") 630 } 631 if len(primaryKeys) > 0 { 632 return moerr.NewNotSupported(ctx.GetContext(), "cluster by with primary key is not support") 633 } 634 lenClusterBy := len(stmt.ClusterByOption.ColumnList) 635 var clusterByKeys []string 636 for i := 0; i < lenClusterBy; i++ { 637 colName := stmt.ClusterByOption.ColumnList[i].Parts[0] 638 if _, ok := colMap[colName]; !ok { 639 return moerr.NewInvalidInput(ctx.GetContext(), "column '%s' doesn't exist in table", colName) 640 } 641 clusterByKeys = append(clusterByKeys, colName) 642 } 643 644 clusterByColName := clusterByKeys[0] 645 if lenClusterBy == 1 { 646 for _, col := range createTable.TableDef.Cols { 647 if col.Name == clusterByColName { 648 col.ClusterBy = true 649 } 650 } 651 } else { 652 clusterByColName = util.BuildCompositeClusterByColumnName(clusterByKeys) 653 colDef := &ColDef{ 654 Name: clusterByColName, 655 Alg: plan.CompressType_Lz4, 656 ClusterBy: true, 657 Typ: &Type{ 658 Id: int32(types.T_varchar), 659 Size: types.VarlenaSize, 660 Width: types.MaxVarcharLen, 661 }, 662 Default: &plan.Default{ 663 NullAbility: true, 664 Expr: nil, 665 OriginString: "", 666 }, 667 } 668 createTable.TableDef.Cols = append(createTable.TableDef.Cols, colDef) 669 colMap[clusterByColName] = colDef 670 } 671 createTable.TableDef.ClusterBy = &plan.ClusterByDef{ 672 Name: clusterByColName, 673 } 674 } 675 676 // check index invalid on the type 677 // for example, the text type don't support index 678 for _, str := range indexs { 679 if _, ok := colMap[str]; !ok { 680 return moerr.NewInvalidInput(ctx.GetContext(), "column '%s' is not exist", str) 681 } 682 if colMap[str].Typ.Id == int32(types.T_blob) { 683 return moerr.NewNotSupported(ctx.GetContext(), fmt.Sprintf("BLOB column '%s' cannot be in index", str)) 684 } 685 if colMap[str].Typ.Id == int32(types.T_text) { 686 return moerr.NewNotSupported(ctx.GetContext(), fmt.Sprintf("TEXT column '%s' cannot be in index", str)) 687 } 688 if colMap[str].Typ.Id == int32(types.T_json) { 689 return moerr.NewNotSupported(ctx.GetContext(), fmt.Sprintf("JSON column '%s' cannot be in index", str)) 690 } 691 } 692 693 // build index table 694 if len(uniqueIndexInfos) != 0 { 695 err := buildUniqueIndexTable(createTable, uniqueIndexInfos, colMap, pkeyName, ctx) 696 if err != nil { 697 return err 698 } 699 } 700 if len(secondaryIndexInfos) != 0 { 701 err := buildSecondaryIndexDef(createTable, secondaryIndexInfos, colMap, ctx) 702 if err != nil { 703 return err 704 } 705 } 706 return nil 707 } 708 709 func getRefAction(typ tree.ReferenceOptionType) plan.ForeignKeyDef_RefAction { 710 switch typ { 711 case tree.REFERENCE_OPTION_CASCADE: 712 return plan.ForeignKeyDef_CASCADE 713 case tree.REFERENCE_OPTION_NO_ACTION: 714 return plan.ForeignKeyDef_NO_ACTION 715 case tree.REFERENCE_OPTION_RESTRICT: 716 return plan.ForeignKeyDef_RESTRICT 717 case tree.REFERENCE_OPTION_SET_NULL: 718 return plan.ForeignKeyDef_SET_NULL 719 case tree.REFERENCE_OPTION_SET_DEFAULT: 720 return plan.ForeignKeyDef_SET_DEFAULT 721 default: 722 return plan.ForeignKeyDef_RESTRICT 723 } 724 } 725 726 func buildUniqueIndexTable(createTable *plan.CreateTable, indexInfos []*tree.UniqueIndex, colMap map[string]*ColDef, pkeyName string, ctx CompilerContext) error { 727 nameCount := make(map[string]int) 728 729 for _, indexInfo := range indexInfos { 730 indexDef := &plan.IndexDef{} 731 indexDef.Unique = true 732 733 indexTableName, err := util.BuildIndexTableName(ctx.GetContext(), true) 734 735 if err != nil { 736 return err 737 } 738 tableDef := &TableDef{ 739 Name: indexTableName, 740 } 741 indexParts := make([]string, 0) 742 743 for _, keyPart := range indexInfo.KeyParts { 744 name := keyPart.ColName.Parts[0] 745 if _, ok := colMap[name]; !ok { 746 return moerr.NewInvalidInput(ctx.GetContext(), "column '%s' is not exist", name) 747 } 748 if colMap[name].Typ.Id == int32(types.T_blob) { 749 return moerr.NewNotSupported(ctx.GetContext(), fmt.Sprintf("BLOB column '%s' cannot be in index", name)) 750 } 751 if colMap[name].Typ.Id == int32(types.T_text) { 752 return moerr.NewNotSupported(ctx.GetContext(), fmt.Sprintf("TEXT column '%s' cannot be in index", name)) 753 } 754 if colMap[name].Typ.Id == int32(types.T_json) { 755 return moerr.NewNotSupported(ctx.GetContext(), fmt.Sprintf("JSON column '%s' cannot be in index", name)) 756 } 757 indexParts = append(indexParts, name) 758 } 759 760 var keyName string 761 if len(indexInfo.KeyParts) == 1 { 762 keyName = catalog.IndexTableIndexColName 763 colDef := &ColDef{ 764 Name: keyName, 765 Alg: plan.CompressType_Lz4, 766 Typ: &Type{ 767 Id: colMap[indexInfo.KeyParts[0].ColName.Parts[0]].Typ.Id, 768 Size: colMap[indexInfo.KeyParts[0].ColName.Parts[0]].Typ.Size, 769 Width: colMap[indexInfo.KeyParts[0].ColName.Parts[0]].Typ.Width, 770 }, 771 Default: &plan.Default{ 772 NullAbility: false, 773 Expr: nil, 774 OriginString: "", 775 }, 776 } 777 tableDef.Cols = append(tableDef.Cols, colDef) 778 tableDef.Pkey = &PrimaryKeyDef{ 779 Names: []string{keyName}, 780 PkeyColName: keyName, 781 } 782 } else { 783 keyName = catalog.IndexTableIndexColName 784 colDef := &ColDef{ 785 Name: keyName, 786 Alg: plan.CompressType_Lz4, 787 Typ: &Type{ 788 Id: int32(types.T_varchar), 789 Size: types.VarlenaSize, 790 Width: types.MaxVarcharLen, 791 }, 792 Default: &plan.Default{ 793 NullAbility: false, 794 Expr: nil, 795 OriginString: "", 796 }, 797 } 798 tableDef.Cols = append(tableDef.Cols, colDef) 799 tableDef.Pkey = &PrimaryKeyDef{ 800 Names: []string{keyName}, 801 PkeyColName: keyName, 802 } 803 } 804 if pkeyName != "" { 805 colDef := &ColDef{ 806 Name: catalog.IndexTablePrimaryColName, 807 Alg: plan.CompressType_Lz4, 808 Typ: colMap[pkeyName].Typ, 809 Default: &plan.Default{ 810 NullAbility: false, 811 Expr: nil, 812 OriginString: "", 813 }, 814 } 815 tableDef.Cols = append(tableDef.Cols, colDef) 816 } 817 if indexInfo.Name == "" { 818 firstPart := indexInfo.KeyParts[0].ColName.Parts[0] 819 nameCount[firstPart]++ 820 count := nameCount[firstPart] 821 indexName := firstPart 822 if count > 1 { 823 indexName = firstPart + "_" + strconv.Itoa(count) 824 } 825 indexDef.IndexName = indexName 826 } else { 827 indexDef.IndexName = indexInfo.Name 828 } 829 indexDef.IndexTableName = indexTableName 830 indexDef.Parts = indexParts 831 indexDef.TableExist = true 832 if indexInfo.IndexOption != nil { 833 indexDef.Comment = indexInfo.IndexOption.Comment 834 } else { 835 indexDef.Comment = "" 836 } 837 createTable.IndexTables = append(createTable.IndexTables, tableDef) 838 839 createTable.TableDef.Indexes = append(createTable.TableDef.Indexes, indexDef) 840 } 841 return nil 842 } 843 844 func buildSecondaryIndexDef(createTable *plan.CreateTable, indexInfos []*tree.Index, colMap map[string]*ColDef, ctx CompilerContext) error { 845 nameCount := make(map[string]int) 846 847 for _, indexInfo := range indexInfos { 848 indexDef := &plan.IndexDef{} 849 indexDef.Unique = false 850 851 indexParts := make([]string, 0) 852 853 for _, keyPart := range indexInfo.KeyParts { 854 name := keyPart.ColName.Parts[0] 855 if _, ok := colMap[name]; !ok { 856 return moerr.NewInvalidInput(ctx.GetContext(), "column '%s' is not exist", name) 857 } 858 if colMap[name].Typ.Id == int32(types.T_blob) { 859 return moerr.NewNotSupported(ctx.GetContext(), fmt.Sprintf("BLOB column '%s' cannot be in index", name)) 860 } 861 if colMap[name].Typ.Id == int32(types.T_text) { 862 return moerr.NewNotSupported(ctx.GetContext(), fmt.Sprintf("TEXT column '%s' cannot be in index", name)) 863 } 864 if colMap[name].Typ.Id == int32(types.T_json) { 865 return moerr.NewNotSupported(ctx.GetContext(), fmt.Sprintf("JSON column '%s' cannot be in index", name)) 866 } 867 indexParts = append(indexParts, name) 868 } 869 870 if indexInfo.Name == "" { 871 firstPart := indexInfo.KeyParts[0].ColName.Parts[0] 872 nameCount[firstPart]++ 873 count := nameCount[firstPart] 874 indexName := firstPart 875 if count > 1 { 876 indexName = firstPart + "_" + strconv.Itoa(count) 877 } 878 indexDef.IndexName = indexName 879 } else { 880 indexDef.IndexName = indexInfo.Name 881 } 882 indexDef.IndexTableName = "" 883 indexDef.Parts = indexParts 884 indexDef.TableExist = false 885 if indexInfo.IndexOption != nil { 886 indexDef.Comment = indexInfo.IndexOption.Comment 887 } else { 888 indexDef.Comment = "" 889 } 890 createTable.TableDef.Indexes = append(createTable.TableDef.Indexes, indexDef) 891 } 892 return nil 893 } 894 895 func buildTruncateTable(stmt *tree.TruncateTable, ctx CompilerContext) (*Plan, error) { 896 truncateTable := &plan.TruncateTable{} 897 898 truncateTable.Database = string(stmt.Name.SchemaName) 899 if truncateTable.Database == "" { 900 truncateTable.Database = ctx.DefaultDatabase() 901 } 902 truncateTable.Table = string(stmt.Name.ObjectName) 903 _, tableDef := ctx.Resolve(truncateTable.Database, truncateTable.Table) 904 if tableDef == nil { 905 return nil, moerr.NewNoSuchTable(ctx.GetContext(), truncateTable.Database, truncateTable.Table) 906 } else { 907 if len(tableDef.RefChildTbls) > 0 { 908 return nil, moerr.NewInternalError(ctx.GetContext(), "can not truncate table '%v' referenced by some foreign key constraint", truncateTable.Table) 909 } 910 911 if tableDef.ViewSql != nil { 912 return nil, moerr.NewNoSuchTable(ctx.GetContext(), truncateTable.Database, truncateTable.Table) 913 } 914 915 truncateTable.TableId = tableDef.TblId 916 if tableDef.Fkeys != nil { 917 for _, fk := range tableDef.Fkeys { 918 truncateTable.ForeignTbl = append(truncateTable.ForeignTbl, fk.ForeignTbl) 919 } 920 } 921 922 truncateTable.ClusterTable = &plan.ClusterTable{ 923 IsClusterTable: util.TableIsClusterTable(tableDef.GetTableType()), 924 } 925 926 //non-sys account can not truncate the cluster table 927 if truncateTable.GetClusterTable().GetIsClusterTable() && ctx.GetAccountId() != catalog.System_Account { 928 return nil, moerr.NewInternalError(ctx.GetContext(), "only the sys account can truncate the cluster table") 929 } 930 931 truncateTable.IndexTableNames = make([]string, 0) 932 if tableDef.Indexes != nil { 933 for _, indexdef := range tableDef.Indexes { 934 if indexdef.TableExist { 935 truncateTable.IndexTableNames = append(truncateTable.IndexTableNames, indexdef.IndexTableName) 936 } 937 } 938 } 939 } 940 941 return &Plan{ 942 Plan: &plan.Plan_Ddl{ 943 Ddl: &plan.DataDefinition{ 944 DdlType: plan.DataDefinition_TRUNCATE_TABLE, 945 Definition: &plan.DataDefinition_TruncateTable{ 946 TruncateTable: truncateTable, 947 }, 948 }, 949 }, 950 }, nil 951 } 952 953 func buildDropTable(stmt *tree.DropTable, ctx CompilerContext) (*Plan, error) { 954 dropTable := &plan.DropTable{ 955 IfExists: stmt.IfExists, 956 } 957 if len(stmt.Names) != 1 { 958 return nil, moerr.NewNotSupported(ctx.GetContext(), "drop multiple (%d) tables in one statement", len(stmt.Names)) 959 } 960 dropTable.Database = string(stmt.Names[0].SchemaName) 961 if dropTable.Database == "" { 962 dropTable.Database = ctx.DefaultDatabase() 963 } 964 dropTable.Table = string(stmt.Names[0].ObjectName) 965 966 _, tableDef := ctx.Resolve(dropTable.Database, dropTable.Table) 967 if tableDef == nil { 968 if !dropTable.IfExists { 969 return nil, moerr.NewNoSuchTable(ctx.GetContext(), dropTable.Database, dropTable.Table) 970 } 971 } else { 972 if len(tableDef.RefChildTbls) > 0 { 973 return nil, moerr.NewInternalError(ctx.GetContext(), "can not drop table '%v' referenced by some foreign key constraint", dropTable.Table) 974 } 975 976 isView := (tableDef.ViewSql != nil) 977 978 if isView && !dropTable.IfExists { 979 // drop table v0, v0 is view 980 return nil, moerr.NewNoSuchTable(ctx.GetContext(), dropTable.Database, dropTable.Table) 981 } else if isView { 982 // drop table if exists v0, v0 is view 983 dropTable.Table = "" 984 } 985 986 dropTable.ClusterTable = &plan.ClusterTable{ 987 IsClusterTable: util.TableIsClusterTable(tableDef.GetTableType()), 988 } 989 990 //non-sys account can not drop the cluster table 991 if dropTable.GetClusterTable().GetIsClusterTable() && ctx.GetAccountId() != catalog.System_Account { 992 return nil, moerr.NewInternalError(ctx.GetContext(), "only the sys account can drop the cluster table") 993 } 994 995 dropTable.TableId = tableDef.TblId 996 if tableDef.Fkeys != nil { 997 for _, fk := range tableDef.Fkeys { 998 dropTable.ForeignTbl = append(dropTable.ForeignTbl, fk.ForeignTbl) 999 } 1000 } 1001 1002 dropTable.IndexTableNames = make([]string, 0) 1003 if tableDef.Indexes != nil { 1004 for _, indexdef := range tableDef.Indexes { 1005 if indexdef.TableExist { 1006 dropTable.IndexTableNames = append(dropTable.IndexTableNames, indexdef.IndexTableName) 1007 } 1008 } 1009 } 1010 } 1011 return &Plan{ 1012 Plan: &plan.Plan_Ddl{ 1013 Ddl: &plan.DataDefinition{ 1014 DdlType: plan.DataDefinition_DROP_TABLE, 1015 Definition: &plan.DataDefinition_DropTable{ 1016 DropTable: dropTable, 1017 }, 1018 }, 1019 }, 1020 }, nil 1021 } 1022 1023 func buildDropView(stmt *tree.DropView, ctx CompilerContext) (*Plan, error) { 1024 dropTable := &plan.DropTable{ 1025 IfExists: stmt.IfExists, 1026 } 1027 if len(stmt.Names) != 1 { 1028 return nil, moerr.NewNotSupported(ctx.GetContext(), "drop multiple (%d) view", len(stmt.Names)) 1029 } 1030 dropTable.Database = string(stmt.Names[0].SchemaName) 1031 if dropTable.Database == "" { 1032 dropTable.Database = ctx.DefaultDatabase() 1033 } 1034 dropTable.Table = string(stmt.Names[0].ObjectName) 1035 1036 _, tableDef := ctx.Resolve(dropTable.Database, dropTable.Table) 1037 if tableDef == nil { 1038 if !dropTable.IfExists { 1039 return nil, moerr.NewBadView(ctx.GetContext(), dropTable.Database, dropTable.Table) 1040 } 1041 } else { 1042 if tableDef.ViewSql == nil { 1043 return nil, moerr.NewBadView(ctx.GetContext(), dropTable.Database, dropTable.Table) 1044 } 1045 } 1046 1047 return &Plan{ 1048 Plan: &plan.Plan_Ddl{ 1049 Ddl: &plan.DataDefinition{ 1050 DdlType: plan.DataDefinition_DROP_TABLE, 1051 Definition: &plan.DataDefinition_DropTable{ 1052 DropTable: dropTable, 1053 }, 1054 }, 1055 }, 1056 }, nil 1057 } 1058 1059 func buildCreateDatabase(stmt *tree.CreateDatabase, ctx CompilerContext) (*Plan, error) { 1060 if string(stmt.Name) == defines.TEMPORARY_DBNAME { 1061 return nil, moerr.NewInternalError(ctx.GetContext(), "this database name is used by mo temporary engine") 1062 } 1063 createDB := &plan.CreateDatabase{ 1064 IfNotExists: stmt.IfNotExists, 1065 Database: string(stmt.Name), 1066 } 1067 1068 return &Plan{ 1069 Plan: &plan.Plan_Ddl{ 1070 Ddl: &plan.DataDefinition{ 1071 DdlType: plan.DataDefinition_CREATE_DATABASE, 1072 Definition: &plan.DataDefinition_CreateDatabase{ 1073 CreateDatabase: createDB, 1074 }, 1075 }, 1076 }, 1077 }, nil 1078 } 1079 1080 func buildDropDatabase(stmt *tree.DropDatabase, ctx CompilerContext) (*Plan, error) { 1081 dropDB := &plan.DropDatabase{ 1082 IfExists: stmt.IfExists, 1083 Database: string(stmt.Name), 1084 } 1085 1086 return &Plan{ 1087 Plan: &plan.Plan_Ddl{ 1088 Ddl: &plan.DataDefinition{ 1089 DdlType: plan.DataDefinition_DROP_DATABASE, 1090 Definition: &plan.DataDefinition_DropDatabase{ 1091 DropDatabase: dropDB, 1092 }, 1093 }, 1094 }, 1095 }, nil 1096 } 1097 1098 func buildCreateIndex(stmt *tree.CreateIndex, ctx CompilerContext) (*Plan, error) { 1099 createIndex := &plan.CreateIndex{} 1100 if len(stmt.Table.SchemaName) == 0 { 1101 createIndex.Database = ctx.DefaultDatabase() 1102 } else { 1103 createIndex.Database = string(stmt.Table.SchemaName) 1104 } 1105 // check table 1106 tableName := string(stmt.Table.ObjectName) 1107 _, tableDef := ctx.Resolve(createIndex.Database, tableName) 1108 if tableDef == nil { 1109 return nil, moerr.NewNoSuchTable(ctx.GetContext(), createIndex.Database, tableName) 1110 } 1111 // check index 1112 indexName := string(stmt.Name) 1113 for _, def := range tableDef.Indexes { 1114 if def.IndexName == indexName { 1115 return nil, moerr.NewDuplicateKey(ctx.GetContext(), indexName) 1116 } 1117 } 1118 // build index 1119 var uIdx *tree.UniqueIndex 1120 var sIdx *tree.Index 1121 switch stmt.IndexCat { 1122 case tree.INDEX_CATEGORY_UNIQUE: 1123 uIdx = &tree.UniqueIndex{ 1124 Name: indexName, 1125 KeyParts: stmt.KeyParts, 1126 IndexOption: stmt.IndexOption, 1127 } 1128 case tree.INDEX_CATEGORY_NONE: 1129 sIdx = &tree.Index{ 1130 Name: indexName, 1131 KeyParts: stmt.KeyParts, 1132 IndexOption: stmt.IndexOption, 1133 } 1134 default: 1135 return nil, moerr.NewNotSupported(ctx.GetContext(), "statement: '%v'", tree.String(stmt, dialect.MYSQL)) 1136 } 1137 colMap := make(map[string]*ColDef) 1138 for _, col := range tableDef.Cols { 1139 colMap[col.Name] = col 1140 } 1141 // index.TableDef.Defs store info of index need to be modified 1142 // index.IndexTables store index table need to be created 1143 oriPriKeyName := GetTablePriKeyName(tableDef.Cols, tableDef.CompositePkey) 1144 createIndex.OriginTablePrimaryKey = oriPriKeyName 1145 1146 index := &plan.CreateTable{TableDef: &TableDef{}} 1147 if uIdx != nil { 1148 if err := buildUniqueIndexTable(index, []*tree.UniqueIndex{uIdx}, colMap, oriPriKeyName, ctx); err != nil { 1149 return nil, err 1150 } 1151 createIndex.TableExist = true 1152 } 1153 if sIdx != nil { 1154 if err := buildSecondaryIndexDef(index, []*tree.Index{sIdx}, colMap, ctx); err != nil { 1155 return nil, err 1156 } 1157 createIndex.TableExist = false 1158 } 1159 createIndex.Index = index 1160 createIndex.Table = tableName 1161 1162 return &Plan{ 1163 Plan: &plan.Plan_Ddl{ 1164 Ddl: &plan.DataDefinition{ 1165 DdlType: plan.DataDefinition_CREATE_INDEX, 1166 Definition: &plan.DataDefinition_CreateIndex{ 1167 CreateIndex: createIndex, 1168 }, 1169 }, 1170 }, 1171 }, nil 1172 } 1173 1174 func buildDropIndex(stmt *tree.DropIndex, ctx CompilerContext) (*Plan, error) { 1175 dropIndex := &plan.DropIndex{} 1176 if len(stmt.TableName.SchemaName) == 0 { 1177 dropIndex.Database = ctx.DefaultDatabase() 1178 } else { 1179 dropIndex.Database = string(stmt.TableName.SchemaName) 1180 } 1181 1182 // check table 1183 dropIndex.Table = string(stmt.TableName.ObjectName) 1184 _, tableDef := ctx.Resolve(dropIndex.Database, dropIndex.Table) 1185 if tableDef == nil { 1186 return nil, moerr.NewNoSuchTable(ctx.GetContext(), dropIndex.Database, dropIndex.Table) 1187 } 1188 1189 // check index 1190 dropIndex.IndexName = string(stmt.Name) 1191 found := false 1192 1193 for _, indexdef := range tableDef.Indexes { 1194 if dropIndex.IndexName == indexdef.IndexName { 1195 dropIndex.IndexTableName = indexdef.IndexTableName 1196 found = true 1197 break 1198 } 1199 } 1200 1201 if !found { 1202 return nil, moerr.NewInternalError(ctx.GetContext(), "not found index: %s", dropIndex.IndexName) 1203 } 1204 1205 return &Plan{ 1206 Plan: &plan.Plan_Ddl{ 1207 Ddl: &plan.DataDefinition{ 1208 DdlType: plan.DataDefinition_DROP_INDEX, 1209 Definition: &plan.DataDefinition_DropIndex{ 1210 DropIndex: dropIndex, 1211 }, 1212 }, 1213 }, 1214 }, nil 1215 } 1216 1217 // Get tabledef(col, viewsql, properties) for alterview. 1218 func buildAlterView(stmt *tree.AlterView, ctx CompilerContext) (*Plan, error) { 1219 viewName := string(stmt.Name.ObjectName) 1220 alterView := &plan.AlterView{ 1221 IfExists: stmt.IfExists, 1222 TableDef: &plan.TableDef{ 1223 Name: viewName, 1224 }, 1225 } 1226 // get database name 1227 if len(stmt.Name.SchemaName) == 0 { 1228 alterView.Database = "" 1229 } else { 1230 alterView.Database = string(stmt.Name.SchemaName) 1231 } 1232 if alterView.Database == "" { 1233 alterView.Database = ctx.DefaultDatabase() 1234 } 1235 1236 //step 1: check the view exists or not 1237 _, oldViewDef := ctx.Resolve(alterView.Database, viewName) 1238 if oldViewDef == nil { 1239 if !alterView.IfExists { 1240 return nil, moerr.NewBadView(ctx.GetContext(), 1241 alterView.Database, 1242 viewName) 1243 } 1244 } else { 1245 if oldViewDef.ViewSql == nil { 1246 return nil, moerr.NewBadView(ctx.GetContext(), 1247 alterView.Database, 1248 viewName) 1249 } 1250 } 1251 1252 //step 2: generate new view def 1253 ctx.SetBuildingAlterView(true, alterView.Database, viewName) 1254 //restore 1255 defer func() { 1256 ctx.SetBuildingAlterView(false, "", "") 1257 }() 1258 tableDef, err := genViewTableDef(ctx, stmt.AsSource) 1259 if err != nil { 1260 return nil, err 1261 } 1262 1263 alterView.TableDef.Cols = tableDef.Cols 1264 alterView.TableDef.ViewSql = tableDef.ViewSql 1265 alterView.TableDef.Defs = tableDef.Defs 1266 1267 return &Plan{ 1268 Plan: &plan.Plan_Ddl{ 1269 Ddl: &plan.DataDefinition{ 1270 DdlType: plan.DataDefinition_ALTER_VIEW, 1271 Definition: &plan.DataDefinition_AlterView{ 1272 AlterView: alterView, 1273 }, 1274 }, 1275 }, 1276 }, nil 1277 }