github.com/matrixorigin/matrixone@v0.7.0/pkg/sql/colexec/constraint_util.go (about) 1 // Copyright 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 colexec 16 17 import ( 18 "context" 19 "fmt" 20 21 "github.com/matrixorigin/matrixone/pkg/catalog" 22 "github.com/matrixorigin/matrixone/pkg/common/moerr" 23 "github.com/matrixorigin/matrixone/pkg/container/batch" 24 "github.com/matrixorigin/matrixone/pkg/container/nulls" 25 "github.com/matrixorigin/matrixone/pkg/container/types" 26 "github.com/matrixorigin/matrixone/pkg/container/vector" 27 "github.com/matrixorigin/matrixone/pkg/pb/plan" 28 "github.com/matrixorigin/matrixone/pkg/sql/util" 29 "github.com/matrixorigin/matrixone/pkg/vm/engine" 30 "github.com/matrixorigin/matrixone/pkg/vm/process" 31 ) 32 33 type tableInfo struct { 34 hasAutoCol bool 35 pkPos int 36 updateNameToPos map[string]int 37 compositePkey string 38 clusterBy string 39 attrs []string 40 idxList []int32 41 } 42 43 func FilterAndDelByRowId(proc *process.Process, bat *batch.Batch, idxList []int32, rels []engine.Relation) (uint64, error) { 44 var affectedRows uint64 45 for i, idx := range idxList { 46 delBatch := filterRowIdForDel(proc, bat, int(idx)) 47 affectedRows = affectedRows + uint64(delBatch.Length()) 48 if delBatch.Length() > 0 { 49 err := rels[i].Delete(proc.Ctx, delBatch, catalog.Row_ID) 50 if err != nil { 51 delBatch.Clean(proc.Mp()) 52 return 0, err 53 } 54 } 55 delBatch.Clean(proc.Mp()) 56 } 57 return affectedRows, nil 58 } 59 60 func FilterAndUpdateByRowId( 61 eg engine.Engine, 62 proc *process.Process, 63 bat *batch.Batch, 64 idxList [][]int32, 65 rels []engine.Relation, 66 ref []*plan.ObjectRef, 67 tableDefs []*plan.TableDef, 68 updateCols []map[string]int32, 69 parentIdxs []map[string]int32, 70 uniqueRels [][]engine.Relation, 71 ) (uint64, error) { 72 var affectedRows uint64 73 var delBatch *batch.Batch 74 var updateBatch *batch.Batch 75 var err error 76 defer func() { 77 if delBatch != nil { 78 delBatch.Clean(proc.Mp()) 79 } 80 if updateBatch != nil { 81 updateBatch.Clean(proc.Mp()) 82 } 83 }() 84 85 for i, setIdxList := range idxList { 86 // get attrs, hasAutoCol 87 tableDef := tableDefs[i] 88 updateCol := updateCols[i] 89 uniqueRel := uniqueRels[i] 90 var parentIdx map[string]int32 // nil means don't need check parent constraint 91 if len(parentIdxs) > 0 { 92 parentIdx = parentIdxs[i] 93 } 94 info := getInfoForInsertAndUpdate(tableDef, updateCol) 95 96 delBatch, updateBatch, err = filterRowIdForUpdate(proc, bat, setIdxList, info.attrs, parentIdx) 97 if err != nil { 98 return 0, err 99 } 100 if delBatch == nil && updateBatch == nil { 101 continue 102 } 103 affectedRows = affectedRows + uint64(delBatch.Length()) 104 if delBatch.Length() > 0 { 105 // delete old rows 106 err = rels[i].Delete(proc.Ctx, delBatch, catalog.Row_ID) 107 if err != nil { 108 return 0, err 109 } 110 111 // fill auto incr column 112 if info.hasAutoCol { 113 if err = UpdateInsertBatch(eg, proc.Ctx, proc, tableDef.Cols, updateBatch, uint64(ref[i].Obj), ref[i].SchemaName, tableDef.Name); err != nil { 114 return 0, err 115 } 116 } 117 118 // check new rows not null 119 err := batchDataNotNullCheck(updateBatch, tableDef, proc.Ctx) 120 if err != nil { 121 return 0, err 122 } 123 124 // append hidden columns 125 if info.compositePkey != "" { 126 util.FillCompositeClusterByBatch(updateBatch, info.compositePkey, proc) 127 } 128 if info.clusterBy != "" && util.JudgeIsCompositeClusterByColumn(info.clusterBy) { 129 util.FillCompositeClusterByBatch(updateBatch, info.clusterBy, proc) 130 } 131 132 // write unique key table 133 writeUniqueTable(nil, eg, proc, updateBatch, tableDef, ref[i].SchemaName, info.updateNameToPos, info.pkPos, uniqueRel) 134 135 // write origin table 136 err = rels[i].Write(proc.Ctx, updateBatch) 137 if err != nil { 138 return 0, err 139 } 140 } 141 } 142 return affectedRows, nil 143 } 144 145 func writeUniqueTable(s3Container *WriteS3Container, eg engine.Engine, proc *process.Process, updateBatch *batch.Batch, 146 tableDef *plan.TableDef, dbName string, updateNameToPos map[string]int, pkPos int, rels []engine.Relation) error { 147 var ukBatch *batch.Batch 148 149 defer func() { 150 if ukBatch != nil { 151 ukBatch.Clean(proc.Mp()) 152 } 153 }() 154 155 uIdx := 0 156 if tableDef.Indexes != nil { 157 for _, indexdef := range tableDef.Indexes { 158 if indexdef.Unique { 159 partsLength := len(indexdef.Parts) 160 uniqueColumnPos := make([]int, partsLength) 161 for p, column := range indexdef.Parts { 162 uniqueColumnPos[p] = updateNameToPos[column] 163 } 164 165 colCount := len(uniqueColumnPos) 166 if pkPos == -1 { 167 //have no pk 168 ukBatch = batch.New(true, []string{catalog.IndexTableIndexColName}) 169 } else { 170 ukBatch = batch.New(true, []string{catalog.IndexTableIndexColName, catalog.IndexTablePrimaryColName}) 171 } 172 173 var vec *vector.Vector 174 var bitMap *nulls.Nulls 175 if colCount == 1 { 176 idx := uniqueColumnPos[0] 177 vec, bitMap = util.CompactSingleIndexCol(updateBatch.Vecs[idx], proc) 178 } else { 179 vs := make([]*vector.Vector, colCount) 180 for vIdx, pIdx := range uniqueColumnPos { 181 vs[vIdx] = updateBatch.Vecs[pIdx] 182 } 183 vec, bitMap = util.SerialWithCompacted(vs, proc) 184 } 185 ukBatch.SetVector(0, vec) 186 ukBatch.SetZs(vec.Length(), proc.Mp()) 187 188 if pkPos != -1 { 189 // have pk, append pk vector 190 vec = util.CompactPrimaryCol(updateBatch.Vecs[pkPos], bitMap, proc) 191 ukBatch.SetVector(1, vec) 192 } 193 194 // db, err := eg.Database(proc.Ctx, dbName, proc.TxnOperator) 195 // if err != nil { 196 // return err 197 // } 198 // rel, err := db.Relation(proc.Ctx, tblName) 199 // if err != nil { 200 // return err 201 // } 202 203 if s3Container == nil { 204 rel := rels[uIdx] 205 err := rel.Write(proc.Ctx, ukBatch) 206 if err != nil { 207 return err 208 } 209 uIdx++ 210 } else { 211 uIdx++ 212 s3Container.WriteS3Batch(ukBatch, proc, uIdx) 213 } 214 } else { 215 continue 216 } 217 } 218 } 219 return nil 220 } 221 222 func filterRowIdForDel(proc *process.Process, bat *batch.Batch, idx int) *batch.Batch { 223 retVec := vector.New(types.T_Rowid.ToType()) 224 rowIdMap := make(map[types.Rowid]struct{}) 225 for i, r := range vector.MustTCols[types.Rowid](bat.Vecs[idx]) { 226 if !bat.Vecs[idx].Nsp.Contains(uint64(i)) { 227 rowIdMap[r] = struct{}{} 228 } 229 } 230 rowIdList := make([]types.Rowid, len(rowIdMap)) 231 i := 0 232 for rowId := range rowIdMap { 233 rowIdList[i] = rowId 234 i++ 235 } 236 vector.AppendFixed(retVec, rowIdList, proc.Mp()) 237 retBatch := batch.New(true, []string{catalog.Row_ID}) 238 retBatch.SetZs(retVec.Length(), proc.Mp()) 239 retBatch.SetVector(0, retVec) 240 return retBatch 241 } 242 243 func filterRowIdForUpdate(proc *process.Process, bat *batch.Batch, idxList []int32, attrs []string, parentIdx map[string]int32) (*batch.Batch, *batch.Batch, error) { 244 rowIdMap := make(map[types.Rowid]struct{}) 245 var rowSkip []bool 246 foundRowId := false 247 for i, idx := range idxList { 248 if bat.Vecs[idx].Typ.Oid == types.T_Rowid { 249 for j, r := range vector.MustTCols[types.Rowid](bat.Vecs[idx]) { 250 if _, exist := rowIdMap[r]; exist { 251 rowSkip = append(rowSkip, true) 252 } else if bat.Vecs[idx].Nsp.Contains(uint64(j)) { 253 rowSkip = append(rowSkip, true) 254 } else { 255 rowIdMap[r] = struct{}{} 256 rowSkip = append(rowSkip, false) 257 } 258 } 259 foundRowId = true 260 idxList = append(idxList[:i], idxList[i+1:]...) 261 break 262 } 263 } 264 if !foundRowId { 265 return nil, nil, moerr.NewInternalError(proc.Ctx, "need rowid vector for update") 266 } 267 batLen := len(rowIdMap) 268 if batLen == 0 { 269 return nil, nil, nil 270 } 271 272 // get delete batch 273 delVec := vector.New(types.T_Rowid.ToType()) 274 rowIdList := make([]types.Rowid, len(rowIdMap)) 275 i := 0 276 for rowId := range rowIdMap { 277 rowIdList[i] = rowId 278 i++ 279 } 280 mp := proc.Mp() 281 vector.AppendFixed(delVec, rowIdList, mp) 282 delBatch := batch.New(true, []string{catalog.Row_ID}) 283 delBatch.SetVector(0, delVec) 284 delBatch.SetZs(batLen, mp) 285 286 // get update batch 287 updateBatch, err := GetUpdateBatch(proc, bat, idxList, batLen, attrs, rowSkip, parentIdx) 288 if err != nil { 289 delBatch.Clean(proc.Mp()) 290 return nil, nil, err 291 } 292 293 return delBatch, updateBatch, nil 294 } 295 296 func GetUpdateBatch(proc *process.Process, bat *batch.Batch, idxList []int32, batLen int, attrs []string, rowSkip []bool, parentIdx map[string]int32) (*batch.Batch, error) { 297 updateBatch := batch.New(true, attrs) 298 var toVec *vector.Vector 299 var err error 300 301 for i, idx := range idxList { 302 fromVec := bat.Vecs[idx] 303 colName := attrs[i] 304 305 // if update values is not null, but parent is null, throw error 306 if parentIdx != nil { 307 if pIdx, exists := parentIdx[colName]; exists { 308 parentVec := bat.Vecs[pIdx] 309 if fromVec.IsConst() { 310 if !fromVec.IsScalarNull() { 311 if rowSkip == nil { 312 for j := 0; j < batLen; j++ { 313 if parentVec.Nsp.Contains(uint64(j)) { 314 return nil, moerr.NewInternalError(proc.Ctx, "Cannot add or update a child row: a foreign key constraint fails") 315 } 316 } 317 } else { 318 for j := 0; j < batLen; j++ { 319 if !rowSkip[j] && parentVec.Nsp.Contains(uint64(j)) { 320 return nil, moerr.NewInternalError(proc.Ctx, "Cannot add or update a child row: a foreign key constraint fails") 321 } 322 } 323 } 324 } 325 } else { 326 if rowSkip == nil { 327 for j := 0; j < fromVec.Length(); j++ { 328 if !fromVec.Nsp.Contains(uint64(j)) && parentVec.Nsp.Contains(uint64(j)) { 329 return nil, moerr.NewInternalError(proc.Ctx, "Cannot add or update a child row: a foreign key constraint fails") 330 } 331 } 332 } else { 333 for j := 0; j < fromVec.Length(); j++ { 334 if !rowSkip[j] && !fromVec.Nsp.Contains(uint64(j)) && parentVec.Nsp.Contains(uint64(j)) { 335 return nil, moerr.NewInternalError(proc.Ctx, "Cannot add or update a child row: a foreign key constraint fails") 336 } 337 } 338 } 339 } 340 } 341 } 342 343 if fromVec.IsConst() { 344 toVec = vector.New(bat.Vecs[idx].Typ) 345 if fromVec.IsScalarNull() { 346 defVal := vector.GetInitConstVal(bat.Vecs[idx].Typ) 347 for j := 0; j < batLen; j++ { 348 err := toVec.Append(defVal, true, proc.Mp()) 349 if err != nil { 350 updateBatch.Clean(proc.Mp()) 351 return nil, err 352 } 353 } 354 } else { 355 err = vector.CopyConst(toVec, fromVec, batLen, proc.Mp()) 356 if err != nil { 357 updateBatch.Clean(proc.Mp()) 358 return nil, err 359 } 360 } 361 } else { 362 toVec = vector.New(bat.Vecs[idx].Typ) 363 if rowSkip == nil { 364 for j := 0; j < fromVec.Length(); j++ { 365 vector.UnionOne(toVec, fromVec, int64(j), proc.Mp()) 366 } 367 } else { 368 for j := 0; j < fromVec.Length(); j++ { 369 if !rowSkip[j] { 370 vector.UnionOne(toVec, fromVec, int64(j), proc.Mp()) 371 } 372 } 373 } 374 } 375 updateBatch.SetVector(int32(i), toVec) 376 } 377 updateBatch.SetZs(batLen, proc.Mp()) 378 return updateBatch, nil 379 } 380 381 func getInfoForInsertAndUpdate(tableDef *plan.TableDef, updateCol map[string]int32) *tableInfo { 382 info := &tableInfo{ 383 hasAutoCol: false, 384 pkPos: -1, 385 updateNameToPos: make(map[string]int), 386 compositePkey: "", 387 clusterBy: "", 388 attrs: make([]string, 0, len(tableDef.Cols)), 389 idxList: make([]int32, 0, len(tableDef.Cols)), 390 } 391 if tableDef.CompositePkey != nil { 392 info.compositePkey = tableDef.CompositePkey.Name 393 } 394 if tableDef.ClusterBy != nil { 395 info.clusterBy = tableDef.ClusterBy.Name 396 } 397 pos := 0 398 for j, col := range tableDef.Cols { 399 if col.Typ.AutoIncr { 400 if updateCol == nil { // update statement 401 info.hasAutoCol = true 402 } else if _, ok := updateCol[col.Name]; ok { // insert statement 403 info.hasAutoCol = true 404 } 405 } 406 if info.compositePkey == "" && col.Name != catalog.Row_ID && col.Primary { 407 info.pkPos = j 408 } 409 if col.Name != catalog.Row_ID { 410 info.attrs = append(info.attrs, col.Name) 411 info.idxList = append(info.idxList, int32(pos)) 412 info.updateNameToPos[col.Name] = pos 413 pos++ 414 } 415 } 416 if info.compositePkey != "" { 417 info.pkPos = pos 418 } 419 420 return info 421 } 422 423 func InsertBatch( 424 container *WriteS3Container, 425 eg engine.Engine, 426 proc *process.Process, 427 bat *batch.Batch, 428 rel engine.Relation, 429 ref *plan.ObjectRef, 430 tableDef *plan.TableDef, 431 parentIdx map[string]int32, 432 uniqueRel []engine.Relation) (uint64, error) { 433 var insertBatch *batch.Batch 434 var err error 435 affectedRows := bat.Vecs[0].Length() 436 defer func() { 437 if insertBatch != nil { 438 insertBatch.Clean(proc.Mp()) 439 } 440 }() 441 442 info := getInfoForInsertAndUpdate(tableDef, nil) 443 444 //get insert batch 445 insertBatch, err = GetUpdateBatch(proc, bat, info.idxList, bat.Length(), info.attrs, nil, parentIdx) 446 if err != nil { 447 return 0, err 448 } 449 450 // fill auto incr column 451 if info.hasAutoCol { 452 if err = UpdateInsertBatch(eg, proc.Ctx, proc, tableDef.Cols, insertBatch, uint64(ref.Obj), ref.SchemaName, tableDef.Name); err != nil { 453 return 0, err 454 } 455 } 456 457 // check new rows not null 458 err = batchDataNotNullCheck(insertBatch, tableDef, proc.Ctx) 459 if err != nil { 460 return 0, err 461 } 462 463 // append hidden columns 464 if info.compositePkey != "" { 465 util.FillCompositeClusterByBatch(insertBatch, info.compositePkey, proc) 466 } 467 if info.clusterBy != "" && util.JudgeIsCompositeClusterByColumn(info.clusterBy) { 468 util.FillCompositeClusterByBatch(insertBatch, info.clusterBy, proc) 469 } 470 471 if container != nil { 472 // write to s3 473 err = container.WriteS3Batch(insertBatch, proc, 0) 474 if err != nil { 475 return 0, err 476 } 477 478 err = writeUniqueTable(container, eg, proc, insertBatch, tableDef, ref.SchemaName, info.updateNameToPos, info.pkPos, uniqueRel) 479 if err != nil { 480 return 0, err 481 } 482 483 } else { 484 // write unique key table 485 err = writeUniqueTable(nil, eg, proc, insertBatch, tableDef, ref.SchemaName, info.updateNameToPos, info.pkPos, uniqueRel) 486 if err != nil { 487 return 0, err 488 } 489 490 // write origin table 491 err = rel.Write(proc.Ctx, insertBatch) 492 } 493 494 if err != nil { 495 return 0, err 496 } 497 498 return uint64(affectedRows), nil 499 } 500 501 func batchDataNotNullCheck(tmpBat *batch.Batch, tableDef *plan.TableDef, ctx context.Context) error { 502 compNameMap := make(map[string]struct{}) 503 if tableDef.CompositePkey != nil { 504 names := util.SplitCompositePrimaryKeyColumnName(tableDef.CompositePkey.Name) 505 for _, name := range names { 506 compNameMap[name] = struct{}{} 507 } 508 } 509 510 for j := range tmpBat.Vecs { 511 nsp := tmpBat.Vecs[j].Nsp 512 if tableDef.Cols[j].Default != nil && !tableDef.Cols[j].Default.NullAbility { 513 if nulls.Any(nsp) { 514 return moerr.NewConstraintViolation(ctx, fmt.Sprintf("Column '%s' cannot be null", tmpBat.Attrs[j])) 515 } 516 } 517 if _, ok := compNameMap[tmpBat.Attrs[j]]; ok { 518 if nulls.Any(nsp) { 519 return moerr.NewConstraintViolation(ctx, fmt.Sprintf("Column '%s' cannot be null", tmpBat.Attrs[j])) 520 } 521 } 522 } 523 return nil 524 }