github.com/matrixorigin/matrixone@v1.2.0/pkg/sql/compile/alter.go (about) 1 // Copyright 2023 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 compile 16 17 import ( 18 "fmt" 19 20 plan2 "github.com/matrixorigin/matrixone/pkg/sql/plan" 21 "go.uber.org/zap" 22 23 "github.com/matrixorigin/matrixone/pkg/catalog" 24 "github.com/matrixorigin/matrixone/pkg/common/moerr" 25 "github.com/matrixorigin/matrixone/pkg/pb/api" 26 "github.com/matrixorigin/matrixone/pkg/pb/lock" 27 "github.com/matrixorigin/matrixone/pkg/pb/plan" 28 "github.com/matrixorigin/matrixone/pkg/vm/engine" 29 ) 30 31 func (s *Scope) AlterTableCopy(c *Compile) error { 32 qry := s.Plan.GetDdl().GetAlterTable() 33 dbName := qry.Database 34 if dbName == "" { 35 dbName = c.db 36 } 37 tblName := qry.GetTableDef().GetName() 38 39 dbSource, err := c.e.Database(c.ctx, dbName, c.proc.TxnOperator) 40 if err != nil { 41 return err 42 } 43 44 originRel, err := dbSource.Relation(c.ctx, tblName, nil) 45 if err != nil { 46 return err 47 } 48 49 if c.proc.TxnOperator.Txn().IsPessimistic() { 50 var retryErr error 51 // 1. lock origin table metadata in catalog 52 if err = lockMoTable(c, dbName, tblName, lock.LockMode_Exclusive); err != nil { 53 if !moerr.IsMoErrCode(err, moerr.ErrTxnNeedRetry) && 54 !moerr.IsMoErrCode(err, moerr.ErrTxnNeedRetryWithDefChanged) { 55 return err 56 } 57 retryErr = err 58 } 59 60 // 2. lock origin table 61 var partitionTableNames []string 62 tableDef := qry.GetTableDef() 63 if tableDef.Partition != nil { 64 partitionTableNames = tableDef.Partition.PartitionTableNames 65 } 66 if err = lockTable(c.ctx, c.e, c.proc, originRel, dbName, partitionTableNames, true); err != nil { 67 if !moerr.IsMoErrCode(err, moerr.ErrTxnNeedRetry) && 68 !moerr.IsMoErrCode(err, moerr.ErrTxnNeedRetryWithDefChanged) { 69 return err 70 } 71 retryErr = err 72 } 73 if retryErr != nil { 74 return retryErr 75 } 76 } 77 78 // 3. create temporary replica table which doesn't have foreign key constraints 79 err = c.runSql(qry.CreateTmpTableSql) 80 if err != nil { 81 getLogger().Info("Create copy table for alter table", 82 zap.String("databaseName", c.db), 83 zap.String("origin tableName", qry.GetTableDef().Name), 84 zap.String("copy tableName", qry.CopyTableDef.Name), 85 zap.String("CreateTmpTableSql", qry.CreateTmpTableSql), 86 zap.Error(err)) 87 return err 88 } 89 90 // 4. copy the original table data to the temporary replica table 91 err = c.runSql(qry.InsertTmpDataSql) 92 if err != nil { 93 getLogger().Info("insert data to copy table for alter table", 94 zap.String("databaseName", c.db), 95 zap.String("origin tableName", qry.GetTableDef().Name), 96 zap.String("copy tableName", qry.CopyTableDef.Name), 97 zap.String("InsertTmpDataSql", qry.InsertTmpDataSql), 98 zap.Error(err)) 99 return err 100 } 101 102 // 5. drop original table 103 if err = dbSource.Delete(c.ctx, tblName); err != nil { 104 getLogger().Info("drop original table for alter table", 105 zap.String("databaseName", c.db), 106 zap.String("origin tableName", qry.GetTableDef().Name), 107 zap.String("copy tableName", qry.CopyTableDef.Name), 108 zap.Error(err)) 109 return err 110 } 111 112 // 5.1 delete all index objects of the table in mo_catalog.mo_indexes 113 if qry.Database != catalog.MO_CATALOG && qry.TableDef.Name != catalog.MO_INDEXES { 114 if qry.GetTableDef().Pkey != nil || len(qry.GetTableDef().Indexes) > 0 { 115 deleteSql := fmt.Sprintf(deleteMoIndexesWithTableIdFormat, qry.GetTableDef().TblId) 116 err = c.runSql(deleteSql) 117 if err != nil { 118 getLogger().Info("delete all index meta data of origin table in `mo_indexes` for alter table", 119 zap.String("databaseName", c.db), 120 zap.String("origin tableName", qry.GetTableDef().Name), 121 zap.String("delete all index sql", deleteSql), 122 zap.Error(err)) 123 124 return err 125 } 126 } 127 } 128 129 // 5.2 delete all index table of the original table 130 if qry.TableDef.Indexes != nil { 131 for _, indexdef := range qry.TableDef.Indexes { 132 if indexdef.TableExist { 133 if err = dbSource.Delete(c.ctx, indexdef.IndexTableName); err != nil { 134 getLogger().Info("delete all index table of origin table for alter table", 135 zap.String("databaseName", c.db), 136 zap.String("origin tableName", qry.GetTableDef().Name), 137 zap.String("origin tableName index table", indexdef.IndexTableName), 138 zap.Error(err)) 139 return err 140 } 141 } 142 } 143 } 144 145 //6. obtain relation for new tables 146 newRel, err := dbSource.Relation(c.ctx, qry.CopyTableDef.Name, nil) 147 if err != nil { 148 getLogger().Info("obtain new relation for copy table for alter table", 149 zap.String("databaseName", c.db), 150 zap.String("origin tableName", qry.GetTableDef().Name), 151 zap.String("copy table name", qry.CopyTableDef.Name), 152 zap.Error(err)) 153 return err 154 } 155 156 //-------------------------------------------------------------------------------------------------------------- 157 // 7. rename temporary replica table into the original table( Table Id remains unchanged) 158 copyTblName := qry.CopyTableDef.Name 159 req := api.NewRenameTableReq(newRel.GetDBID(c.ctx), newRel.GetTableID(c.ctx), copyTblName, tblName) 160 tmp, err := req.Marshal() 161 if err != nil { 162 return err 163 } 164 constraint := make([][]byte, 0) 165 constraint = append(constraint, tmp) 166 err = newRel.TableRenameInTxn(c.ctx, constraint) 167 if err != nil { 168 getLogger().Info("Rename copy tableName to origin tableName in for alter table", 169 zap.String("origin tableName", qry.GetTableDef().Name), 170 zap.String("copy table name", qry.CopyTableDef.Name), 171 zap.Error(err)) 172 return err 173 } 174 //-------------------------------------------------------------------------------------------------------------- 175 { 176 // 8. invoke reindex for the new table, if it contains ivf index. 177 multiTableIndexes := make(map[string]*MultiTableIndex) 178 newTableDef := newRel.CopyTableDef(c.ctx) 179 180 for _, indexDef := range newTableDef.Indexes { 181 if catalog.IsIvfIndexAlgo(indexDef.IndexAlgo) { 182 if _, ok := multiTableIndexes[indexDef.IndexName]; !ok { 183 multiTableIndexes[indexDef.IndexName] = &MultiTableIndex{ 184 IndexAlgo: catalog.ToLower(indexDef.IndexAlgo), 185 IndexDefs: make(map[string]*plan.IndexDef), 186 } 187 } 188 multiTableIndexes[indexDef.IndexName].IndexDefs[catalog.ToLower(indexDef.IndexAlgoTableType)] = indexDef 189 } 190 } 191 for _, multiTableIndex := range multiTableIndexes { 192 switch multiTableIndex.IndexAlgo { 193 case catalog.MoIndexIvfFlatAlgo.ToString(): 194 err = s.handleVectorIvfFlatIndex(c, multiTableIndex.IndexDefs, qry.Database, newTableDef, nil) 195 } 196 if err != nil { 197 getLogger().Info("invoke reindex for the new table for alter table", 198 zap.String("origin tableName", qry.GetTableDef().Name), 199 zap.String("copy table name", qry.CopyTableDef.Name), 200 zap.String("indexAlgo", multiTableIndex.IndexAlgo), 201 zap.Error(err)) 202 return err 203 } 204 } 205 } 206 207 // get and update the change mapping information of table colIds 208 if err = updateNewTableColId(c, newRel, qry.ChangeTblColIdMap); err != nil { 209 getLogger().Info("get and update the change mapping information of table colIds for alter table", 210 zap.String("origin tableName", qry.GetTableDef().Name), 211 zap.String("copy table name", qry.CopyTableDef.Name), 212 zap.Error(err)) 213 return err 214 } 215 216 if len(qry.CopyTableDef.RefChildTbls) > 0 { 217 // Restore the original table's foreign key child table ids to the copy table definition 218 if err = restoreNewTableRefChildTbls(c, newRel, qry.CopyTableDef.RefChildTbls); err != nil { 219 getLogger().Info("Restore original table's foreign key child table ids to copyTable definition for alter table", 220 zap.String("origin tableName", qry.GetTableDef().Name), 221 zap.String("copy table name", qry.CopyTableDef.Name), 222 zap.Error(err)) 223 return err 224 } 225 226 // update foreign key child table references to the current table 227 for _, tblId := range qry.CopyTableDef.RefChildTbls { 228 if err = updateTableForeignKeyColId(c, qry.ChangeTblColIdMap, tblId, originRel.GetTableID(c.ctx), newRel.GetTableID(c.ctx)); err != nil { 229 getLogger().Info("update foreign key child table references to the current table for alter table", 230 zap.String("origin tableName", qry.GetTableDef().Name), 231 zap.String("copy table name", qry.CopyTableDef.Name), 232 zap.Error(err)) 233 return err 234 } 235 } 236 } 237 238 if len(qry.TableDef.Fkeys) > 0 { 239 for _, fkey := range qry.CopyTableDef.Fkeys { 240 if err = notifyParentTableFkTableIdChange(c, fkey, originRel.GetTableID(c.ctx)); err != nil { 241 getLogger().Info("notify parent table foreign key TableId Change for alter table", 242 zap.String("origin tableName", qry.GetTableDef().Name), 243 zap.String("copy table name", qry.CopyTableDef.Name), 244 zap.Error(err)) 245 return err 246 } 247 } 248 } 249 return nil 250 } 251 252 func (s *Scope) AlterTable(c *Compile) (err error) { 253 qry := s.Plan.GetDdl().GetAlterTable() 254 if qry.AlgorithmType == plan.AlterTable_COPY { 255 err = s.AlterTableCopy(c) 256 } else { 257 err = s.AlterTableInplace(c) 258 } 259 if err != nil { 260 return err 261 } 262 263 if !plan2.IsFkBannedDatabase(qry.Database) { 264 //update the mo_foreign_keys 265 for _, sql := range qry.UpdateFkSqls { 266 err = c.runSql(sql) 267 if err != nil { 268 return err 269 } 270 } 271 } 272 273 return err 274 } 275 276 // updateTableForeignKeyColId update foreign key colid of child table references 277 func updateTableForeignKeyColId(c *Compile, changColDefMap map[uint64]*plan.ColDef, childTblId uint64, oldParentTblId uint64, newParentTblId uint64) error { 278 var childRelation engine.Relation 279 var err error 280 if childTblId == 0 { 281 //fk self refer does not update 282 return nil 283 } else { 284 _, _, childRelation, err = c.e.GetRelationById(c.ctx, c.proc.TxnOperator, childTblId) 285 if err != nil { 286 return err 287 } 288 } 289 oldCt, err := GetConstraintDef(c.ctx, childRelation) 290 if err != nil { 291 return err 292 } 293 for _, ct := range oldCt.Cts { 294 if def, ok1 := ct.(*engine.ForeignKeyDef); ok1 { 295 for i := 0; i < len(def.Fkeys); i++ { 296 fkey := def.Fkeys[i] 297 if fkey.ForeignTbl == oldParentTblId { 298 for j := 0; j < len(fkey.ForeignCols); j++ { 299 if newColDef, ok2 := changColDefMap[fkey.ForeignCols[j]]; ok2 { 300 fkey.ForeignCols[j] = newColDef.ColId 301 } 302 } 303 fkey.ForeignTbl = newParentTblId 304 } 305 } 306 } 307 } 308 return childRelation.UpdateConstraint(c.ctx, oldCt) 309 } 310 311 func updateNewTableColId(c *Compile, copyRel engine.Relation, changColDefMap map[uint64]*plan.ColDef) error { 312 engineDefs, err := copyRel.TableDefs(c.ctx) 313 if err != nil { 314 return err 315 } 316 for _, def := range engineDefs { 317 if attr, ok := def.(*engine.AttributeDef); ok { 318 for _, vColDef := range changColDefMap { 319 if vColDef.Name == attr.Attr.Name { 320 vColDef.ColId = attr.Attr.ID 321 break 322 } 323 } 324 } 325 } 326 return nil 327 } 328 329 // restoreNewTableRefChildTbls Restore the original table's foreign key child table ids to the copy table definition 330 func restoreNewTableRefChildTbls(c *Compile, copyRel engine.Relation, refChildTbls []uint64) error { 331 oldCt, err := GetConstraintDef(c.ctx, copyRel) 332 if err != nil { 333 return err 334 } 335 oldCt.Cts = append(oldCt.Cts, &engine.RefChildTableDef{ 336 Tables: refChildTbls, 337 }) 338 return copyRel.UpdateConstraint(c.ctx, oldCt) 339 } 340 341 // notifyParentTableFkTableIdChange Notify the parent table of changes in the tableid of the foreign key table 342 func notifyParentTableFkTableIdChange(c *Compile, fkey *plan.ForeignKeyDef, oldTableId uint64) error { 343 foreignTblId := fkey.ForeignTbl 344 _, _, fatherRelation, err := c.e.GetRelationById(c.ctx, c.proc.TxnOperator, foreignTblId) 345 if err != nil { 346 return err 347 } 348 oldCt, err := GetConstraintDef(c.ctx, fatherRelation) 349 if err != nil { 350 return err 351 } 352 for _, ct := range oldCt.Cts { 353 if def, ok1 := ct.(*engine.RefChildTableDef); ok1 { 354 for i := 0; i < len(def.Tables); i++ { 355 if def.Tables[i] == oldTableId { 356 // delete target element 357 def.Tables = append(def.Tables[:i], def.Tables[i+1:]...) 358 // Because the length of the slice has become shorter, it is necessary to move i forward 359 i-- 360 } 361 } 362 } 363 } 364 return fatherRelation.UpdateConstraint(c.ctx, oldCt) 365 }