github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/interlock/insert_common.go (about) 1 // Copyright 2020 WHTCORPS INC, Inc. 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 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package interlock 15 16 import ( 17 "context" 18 "math" 19 20 "github.com/whtcorpsinc/BerolinaSQL/allegrosql" 21 "github.com/whtcorpsinc/BerolinaSQL/ast" 22 "github.com/whtcorpsinc/BerolinaSQL/perceptron" 23 "github.com/whtcorpsinc/errors" 24 "github.com/whtcorpsinc/milevadb/causet" 25 "github.com/whtcorpsinc/milevadb/causet/blocks" 26 "github.com/whtcorpsinc/milevadb/causetstore/einsteindb" 27 "github.com/whtcorpsinc/milevadb/config" 28 "github.com/whtcorpsinc/milevadb/dbs" 29 "github.com/whtcorpsinc/milevadb/ekv" 30 "github.com/whtcorpsinc/milevadb/memex" 31 "github.com/whtcorpsinc/milevadb/soliton/chunk" 32 "github.com/whtcorpsinc/milevadb/soliton/logutil" 33 "github.com/whtcorpsinc/milevadb/soliton/memory" 34 "github.com/whtcorpsinc/milevadb/spacetime/autoid" 35 "github.com/whtcorpsinc/milevadb/types" 36 "go.uber.org/zap" 37 ) 38 39 // InsertValues is the data to insert. 40 type InsertValues struct { 41 baseInterlockingDirectorate 42 43 rowCount uint64 44 curBatchCnt uint64 45 maxEventsInBatch uint64 46 lastInsertID uint64 47 48 SelectInterDirc InterlockingDirectorate 49 50 Block causet.Block 51 DeferredCausets []*ast.DeferredCausetName 52 Lists [][]memex.Expression 53 SetList []*memex.Assignment 54 55 GenExprs []memex.Expression 56 57 insertDeferredCausets []*causet.DeferredCauset 58 59 // defCausDefaultVals is used to causetstore casted default value. 60 // Because not every insert memex needs defCausDefaultVals, so we will init the buffer lazily. 61 defCausDefaultVals []defaultVal 62 evalBuffer chunk.MutEvent 63 evalBufferTypes []*types.FieldType 64 65 allAssignmentsAreConstant bool 66 67 hasRefDefCauss bool 68 hasExtraHandle bool 69 70 // Fill the autoID lazily to causet. This is used for being compatible with JDBC using getGeneratedKeys(). 71 // `insert|replace values` can guarantee consecutive autoID in a batch. 72 // Other memexs like `insert select from` don't guarantee consecutive autoID. 73 // https://dev.allegrosql.com/doc/refman/8.0/en/innodb-auto-increment-handling.html 74 lazyFillAutoID bool 75 memTracker *memory.Tracker 76 77 stats *runtimeStatsWithSnapshot 78 } 79 80 type defaultVal struct { 81 val types.Causet 82 // valid indicates whether the val is evaluated. We evaluate the default value lazily. 83 valid bool 84 } 85 86 type insertCommon interface { 87 insertCommon() *InsertValues 88 exec(ctx context.Context, rows [][]types.Causet) error 89 } 90 91 func (e *InsertValues) insertCommon() *InsertValues { 92 return e 93 } 94 95 func (e *InsertValues) exec(_ context.Context, _ [][]types.Causet) error { 96 panic("derived should overload exec function") 97 } 98 99 // initInsertDeferredCausets sets the explicitly specified defCausumns of an insert memex. There are three cases: 100 // There are three types of insert memexs: 101 // 1 insert ... values(...) --> name type defCausumn 102 // 2 insert ... set x=y... --> set type defCausumn 103 // 3 insert ... (select ..) --> name type defCausumn 104 // See https://dev.allegrosql.com/doc/refman/5.7/en/insert.html 105 func (e *InsertValues) initInsertDeferredCausets() error { 106 var defcaus []*causet.DeferredCauset 107 var missingDefCausName string 108 var err error 109 110 blockDefCauss := e.Block.DefCauss() 111 112 if len(e.SetList) > 0 { 113 // Process `set` type defCausumn. 114 defCausumns := make([]string, 0, len(e.SetList)) 115 for _, v := range e.SetList { 116 defCausumns = append(defCausumns, v.DefCausName.O) 117 } 118 defcaus, missingDefCausName = causet.FindDefCauss(blockDefCauss, defCausumns, e.Block.Meta().PKIsHandle) 119 if missingDefCausName != "" { 120 return errors.Errorf("INSERT INTO %s: unknown defCausumn %s", e.Block.Meta().Name.O, missingDefCausName) 121 } 122 if len(defcaus) == 0 { 123 return errors.Errorf("INSERT INTO %s: empty defCausumn", e.Block.Meta().Name.O) 124 } 125 } else if len(e.DeferredCausets) > 0 { 126 // Process `name` type defCausumn. 127 defCausumns := make([]string, 0, len(e.DeferredCausets)) 128 for _, v := range e.DeferredCausets { 129 defCausumns = append(defCausumns, v.Name.O) 130 } 131 defcaus, missingDefCausName = causet.FindDefCauss(blockDefCauss, defCausumns, e.Block.Meta().PKIsHandle) 132 if missingDefCausName != "" { 133 return errors.Errorf("INSERT INTO %s: unknown defCausumn %s", e.Block.Meta().Name.O, missingDefCausName) 134 } 135 } else { 136 // If e.DeferredCausets are empty, use all defCausumns instead. 137 defcaus = blockDefCauss 138 } 139 for _, defCaus := range defcaus { 140 if !defCaus.IsGenerated() { 141 e.insertDeferredCausets = append(e.insertDeferredCausets, defCaus) 142 } 143 if defCaus.Name.L == perceptron.ExtraHandleName.L { 144 if !e.ctx.GetStochastikVars().AllowWriteEventID { 145 return errors.Errorf("insert, uFIDelate and replace memexs for _milevadb_rowid are not supported.") 146 } 147 e.hasExtraHandle = true 148 break 149 } 150 } 151 152 // Check defCausumn whether is specified only once. 153 err = causet.CheckOnce(defcaus) 154 if err != nil { 155 return err 156 } 157 return nil 158 } 159 160 func (e *InsertValues) initEvalBuffer() { 161 numDefCauss := len(e.Block.DefCauss()) 162 if e.hasExtraHandle { 163 numDefCauss++ 164 } 165 e.evalBufferTypes = make([]*types.FieldType, numDefCauss) 166 for i, defCaus := range e.Block.DefCauss() { 167 e.evalBufferTypes[i] = &defCaus.FieldType 168 } 169 if e.hasExtraHandle { 170 e.evalBufferTypes[len(e.evalBufferTypes)-1] = types.NewFieldType(allegrosql.TypeLonglong) 171 } 172 e.evalBuffer = chunk.MutEventFromTypes(e.evalBufferTypes) 173 } 174 175 func (e *InsertValues) lazilyInitDefCausDefaultValBuf() (ok bool) { 176 if e.defCausDefaultVals != nil { 177 return true 178 } 179 180 // only if values count of insert memex is more than one, use defCausDefaultVals to causetstore 181 // casted default values has benefits. 182 if len(e.Lists) > 1 { 183 e.defCausDefaultVals = make([]defaultVal, len(e.Block.DefCauss())) 184 return true 185 } 186 187 return false 188 } 189 190 func (e *InsertValues) processSetList() error { 191 if len(e.SetList) > 0 { 192 if len(e.Lists) > 0 { 193 return errors.Errorf("INSERT INTO %s: set type should not use values", e.Block) 194 } 195 l := make([]memex.Expression, 0, len(e.SetList)) 196 for _, v := range e.SetList { 197 l = append(l, v.Expr) 198 } 199 e.Lists = append(e.Lists, l) 200 } 201 return nil 202 } 203 204 // insertEvents processes `insert|replace into values ()` or `insert|replace into set x=y` 205 func insertEvents(ctx context.Context, base insertCommon) (err error) { 206 e := base.insertCommon() 207 // For `insert|replace into set x=y`, process the set list here. 208 if err = e.processSetList(); err != nil { 209 return err 210 } 211 sessVars := e.ctx.GetStochastikVars() 212 batchSize := sessVars.DMLBatchSize 213 batchInsert := sessVars.BatchInsert && !sessVars.InTxn() && config.GetGlobalConfig().EnableBatchDML && batchSize > 0 214 215 e.lazyFillAutoID = true 216 evalEventFunc := e.fastEvalEvent 217 if !e.allAssignmentsAreConstant { 218 evalEventFunc = e.evalEvent 219 } 220 221 rows := make([][]types.Causet, 0, len(e.Lists)) 222 memUsageOfEvents := int64(0) 223 memTracker := e.memTracker 224 for i, list := range e.Lists { 225 e.rowCount++ 226 var event []types.Causet 227 event, err = evalEventFunc(ctx, list, i) 228 if err != nil { 229 return err 230 } 231 rows = append(rows, event) 232 if batchInsert && e.rowCount%uint64(batchSize) == 0 { 233 memUsageOfEvents = types.EstimatedMemUsage(rows[0], len(rows)) 234 memTracker.Consume(memUsageOfEvents) 235 // Before batch insert, fill the batch allocated autoIDs. 236 rows, err = e.lazyAdjustAutoIncrementCauset(ctx, rows) 237 if err != nil { 238 return err 239 } 240 if err = base.exec(ctx, rows); err != nil { 241 return err 242 } 243 rows = rows[:0] 244 memTracker.Consume(-memUsageOfEvents) 245 memUsageOfEvents = 0 246 if err = e.doBatchInsert(ctx); err != nil { 247 return err 248 } 249 } 250 } 251 if len(rows) != 0 { 252 memUsageOfEvents = types.EstimatedMemUsage(rows[0], len(rows)) 253 memTracker.Consume(memUsageOfEvents) 254 } 255 // Fill the batch allocated autoIDs. 256 rows, err = e.lazyAdjustAutoIncrementCauset(ctx, rows) 257 if err != nil { 258 return err 259 } 260 err = base.exec(ctx, rows) 261 if err != nil { 262 return err 263 } 264 memTracker.Consume(-memUsageOfEvents) 265 return nil 266 } 267 268 func (e *InsertValues) handleErr(defCaus *causet.DeferredCauset, val *types.Causet, rowIdx int, err error) error { 269 if err == nil { 270 return nil 271 } 272 273 // Convert the error with full messages. 274 var ( 275 defCausTp byte 276 defCausName string 277 ) 278 if defCaus != nil { 279 defCausTp = defCaus.Tp 280 defCausName = defCaus.Name.String() 281 } 282 283 if types.ErrDataTooLong.Equal(err) { 284 err = resetErrDataTooLong(defCausName, rowIdx+1, err) 285 } else if types.ErrOverflow.Equal(err) { 286 err = types.ErrWarnDataOutOfRange.GenWithStackByArgs(defCausName, rowIdx+1) 287 } else if types.ErrTruncated.Equal(err) { 288 err = types.ErrTruncated.GenWithStackByArgs(defCausName, rowIdx+1) 289 } else if types.ErrTruncatedWrongVal.Equal(err) || types.ErrWrongValue.Equal(err) { 290 valStr, err1 := val.ToString() 291 if err1 != nil { 292 logutil.BgLogger().Warn("truncate value failed", zap.Error(err1)) 293 } 294 err = causet.ErrTruncatedWrongValueForField.GenWithStackByArgs(types.TypeStr(defCausTp), valStr, defCausName, rowIdx+1) 295 } 296 297 if !e.ctx.GetStochastikVars().StmtCtx.DupKeyAsWarning { 298 return err 299 } 300 // TODO: should not filter all types of errors here. 301 e.handleWarning(err) 302 return nil 303 } 304 305 // evalEvent evaluates a to-be-inserted event. The value of the defCausumn may base on another defCausumn, 306 // so we use setValueForRefDeferredCauset to fill the empty event some default values when needFillDefaultValues is true. 307 func (e *InsertValues) evalEvent(ctx context.Context, list []memex.Expression, rowIdx int) ([]types.Causet, error) { 308 rowLen := len(e.Block.DefCauss()) 309 if e.hasExtraHandle { 310 rowLen++ 311 } 312 event := make([]types.Causet, rowLen) 313 hasValue := make([]bool, rowLen) 314 315 // For memexs like `insert into t set a = b + 1`. 316 if e.hasRefDefCauss { 317 if err := e.setValueForRefDeferredCauset(event, hasValue); err != nil { 318 return nil, err 319 } 320 } 321 322 e.evalBuffer.SetCausets(event...) 323 for i, expr := range list { 324 val, err := expr.Eval(e.evalBuffer.ToEvent()) 325 if err = e.handleErr(e.insertDeferredCausets[i], &val, rowIdx, err); err != nil { 326 return nil, err 327 } 328 val1, err := causet.CastValue(e.ctx, val, e.insertDeferredCausets[i].ToInfo(), false, false) 329 if err = e.handleErr(e.insertDeferredCausets[i], &val, rowIdx, err); err != nil { 330 return nil, err 331 } 332 333 offset := e.insertDeferredCausets[i].Offset 334 val1.Copy(&event[offset]) 335 hasValue[offset] = true 336 e.evalBuffer.SetCauset(offset, val1) 337 } 338 // Event may lack of generated defCausumn, autoIncrement defCausumn, empty defCausumn here. 339 return e.fillEvent(ctx, event, hasValue) 340 } 341 342 var emptyEvent chunk.Event 343 344 func (e *InsertValues) fastEvalEvent(ctx context.Context, list []memex.Expression, rowIdx int) ([]types.Causet, error) { 345 rowLen := len(e.Block.DefCauss()) 346 if e.hasExtraHandle { 347 rowLen++ 348 } 349 event := make([]types.Causet, rowLen) 350 hasValue := make([]bool, rowLen) 351 for i, expr := range list { 352 con := expr.(*memex.Constant) 353 val, err := con.Eval(emptyEvent) 354 if err = e.handleErr(e.insertDeferredCausets[i], &val, rowIdx, err); err != nil { 355 return nil, err 356 } 357 val1, err := causet.CastValue(e.ctx, val, e.insertDeferredCausets[i].ToInfo(), false, false) 358 if err = e.handleErr(e.insertDeferredCausets[i], &val, rowIdx, err); err != nil { 359 return nil, err 360 } 361 offset := e.insertDeferredCausets[i].Offset 362 event[offset], hasValue[offset] = val1, true 363 } 364 return e.fillEvent(ctx, event, hasValue) 365 } 366 367 // setValueForRefDeferredCauset set some default values for the event to eval the event value with other defCausumns, 368 // it follows these rules: 369 // 1. for nullable and no default value defCausumn, use NULL. 370 // 2. for nullable and have default value defCausumn, use it's default value. 371 // 3. for not null defCausumn, use zero value even in strict mode. 372 // 4. for auto_increment defCausumn, use zero value. 373 // 5. for generated defCausumn, use NULL. 374 func (e *InsertValues) setValueForRefDeferredCauset(event []types.Causet, hasValue []bool) error { 375 for i, c := range e.Block.DefCauss() { 376 d, err := e.getDefCausDefaultValue(i, c) 377 if err == nil { 378 event[i] = d 379 if !allegrosql.HasAutoIncrementFlag(c.Flag) { 380 // It is an interesting behavior in MyALLEGROSQL. 381 // If the value of auto ID is not explicit, MyALLEGROSQL use 0 value for auto ID when it is 382 // evaluated by another defCausumn, but it should be used once only. 383 // When we fill it as an auto ID defCausumn, it should be set as it used to be. 384 // So just keep `hasValue` false for auto ID, and the others set true. 385 hasValue[c.Offset] = true 386 } 387 } else if causet.ErrNoDefaultValue.Equal(err) { 388 event[i] = causet.GetZeroValue(c.ToInfo()) 389 hasValue[c.Offset] = false 390 } else if e.handleErr(c, &d, 0, err) != nil { 391 return err 392 } 393 } 394 return nil 395 } 396 397 func insertEventsFromSelect(ctx context.Context, base insertCommon) error { 398 // process `insert|replace into ... select ... from ...` 399 e := base.insertCommon() 400 selectInterDirc := e.children[0] 401 fields := retTypes(selectInterDirc) 402 chk := newFirstChunk(selectInterDirc) 403 iter := chunk.NewIterator4Chunk(chk) 404 rows := make([][]types.Causet, 0, chk.Capacity()) 405 406 sessVars := e.ctx.GetStochastikVars() 407 if !sessVars.StrictALLEGROSQLMode { 408 // If StrictALLEGROSQLMode is disabled and it is a insert-select memex, it also handle BadNullAsWarning. 409 sessVars.StmtCtx.BadNullAsWarning = true 410 } 411 batchSize := sessVars.DMLBatchSize 412 batchInsert := sessVars.BatchInsert && !sessVars.InTxn() && config.GetGlobalConfig().EnableBatchDML && batchSize > 0 413 memUsageOfEvents := int64(0) 414 memTracker := e.memTracker 415 for { 416 err := Next(ctx, selectInterDirc, chk) 417 if err != nil { 418 return err 419 } 420 if chk.NumEvents() == 0 { 421 break 422 } 423 chkMemUsage := chk.MemoryUsage() 424 memTracker.Consume(chkMemUsage) 425 for innerChunkEvent := iter.Begin(); innerChunkEvent != iter.End(); innerChunkEvent = iter.Next() { 426 innerEvent := innerChunkEvent.GetCausetEvent(fields) 427 e.rowCount++ 428 event, err := e.getEvent(ctx, innerEvent) 429 if err != nil { 430 return err 431 } 432 rows = append(rows, event) 433 if batchInsert && e.rowCount%uint64(batchSize) == 0 { 434 memUsageOfEvents = types.EstimatedMemUsage(rows[0], len(rows)) 435 memTracker.Consume(memUsageOfEvents) 436 if err = base.exec(ctx, rows); err != nil { 437 return err 438 } 439 rows = rows[:0] 440 memTracker.Consume(-memUsageOfEvents) 441 memUsageOfEvents = 0 442 if err = e.doBatchInsert(ctx); err != nil { 443 return err 444 } 445 } 446 } 447 448 if len(rows) != 0 { 449 memUsageOfEvents = types.EstimatedMemUsage(rows[0], len(rows)) 450 memTracker.Consume(memUsageOfEvents) 451 } 452 err = base.exec(ctx, rows) 453 if err != nil { 454 return err 455 } 456 rows = rows[:0] 457 memTracker.Consume(-memUsageOfEvents) 458 memTracker.Consume(-chkMemUsage) 459 } 460 return nil 461 } 462 463 func (e *InsertValues) doBatchInsert(ctx context.Context) error { 464 e.ctx.StmtCommit() 465 if err := e.ctx.NewTxn(ctx); err != nil { 466 // We should return a special error for batch insert. 467 return ErrBatchInsertFail.GenWithStack("BatchInsert failed with error: %v", err) 468 } 469 return nil 470 } 471 472 // getEvent gets the event which from `insert into select from` or `load data`. 473 // The input values from these two memexs are datums instead of 474 // memexs which are used in `insert into set x=y`. 475 func (e *InsertValues) getEvent(ctx context.Context, vals []types.Causet) ([]types.Causet, error) { 476 event := make([]types.Causet, len(e.Block.DefCauss())) 477 hasValue := make([]bool, len(e.Block.DefCauss())) 478 for i, v := range vals { 479 casted, err := causet.CastValue(e.ctx, v, e.insertDeferredCausets[i].ToInfo(), false, false) 480 if e.handleErr(nil, &v, 0, err) != nil { 481 return nil, err 482 } 483 484 offset := e.insertDeferredCausets[i].Offset 485 event[offset] = casted 486 hasValue[offset] = true 487 } 488 489 return e.fillEvent(ctx, event, hasValue) 490 } 491 492 // getDefCausDefaultValue gets the defCausumn default value. 493 func (e *InsertValues) getDefCausDefaultValue(idx int, defCaus *causet.DeferredCauset) (d types.Causet, err error) { 494 if !defCaus.DefaultIsExpr && e.defCausDefaultVals != nil && e.defCausDefaultVals[idx].valid { 495 return e.defCausDefaultVals[idx].val, nil 496 } 497 498 var defaultVal types.Causet 499 if defCaus.DefaultIsExpr && defCaus.DefaultExpr != nil { 500 defaultVal, err = causet.EvalDefCausDefaultExpr(e.ctx, defCaus.ToInfo(), defCaus.DefaultExpr) 501 } else { 502 defaultVal, err = causet.GetDefCausDefaultValue(e.ctx, defCaus.ToInfo()) 503 } 504 if err != nil { 505 return types.Causet{}, err 506 } 507 if initialized := e.lazilyInitDefCausDefaultValBuf(); initialized && !defCaus.DefaultIsExpr { 508 e.defCausDefaultVals[idx].val = defaultVal 509 e.defCausDefaultVals[idx].valid = true 510 } 511 512 return defaultVal, nil 513 } 514 515 // fillDefCausValue fills the defCausumn value if it is not set in the insert memex. 516 func (e *InsertValues) fillDefCausValue(ctx context.Context, causet types.Causet, idx int, defCausumn *causet.DeferredCauset, hasValue bool) (types.Causet, 517 error) { 518 if allegrosql.HasAutoIncrementFlag(defCausumn.Flag) { 519 if e.lazyFillAutoID { 520 // Handle hasValue info in autoIncrement defCausumn previously for lazy handle. 521 if !hasValue { 522 causet.SetNull() 523 } 524 // CausetStore the plain causet of autoIncrement defCausumn directly for lazy handle. 525 return causet, nil 526 } 527 d, err := e.adjustAutoIncrementCauset(ctx, causet, hasValue, defCausumn) 528 if err != nil { 529 return types.Causet{}, err 530 } 531 return d, nil 532 } 533 tblInfo := e.Block.Meta() 534 if dbs.IsAutoRandomDeferredCausetID(tblInfo, defCausumn.ID) { 535 d, err := e.adjustAutoRandomCauset(ctx, causet, hasValue, defCausumn) 536 if err != nil { 537 return types.Causet{}, err 538 } 539 return d, nil 540 } 541 if !hasValue { 542 d, err := e.getDefCausDefaultValue(idx, defCausumn) 543 if e.handleErr(defCausumn, &causet, 0, err) != nil { 544 return types.Causet{}, err 545 } 546 return d, nil 547 } 548 return causet, nil 549 } 550 551 // fillEvent fills generated defCausumns, auto_increment defCausumn and empty defCausumn. 552 // For NOT NULL defCausumn, it will return error or use zero value based on sql_mode. 553 // When lazyFillAutoID is true, fill event will lazily handle auto increment causet for lazy batch allocation. 554 // `insert|replace values` can guarantee consecutive autoID in a batch. 555 // Other memexs like `insert select from` don't guarantee consecutive autoID. 556 // https://dev.allegrosql.com/doc/refman/8.0/en/innodb-auto-increment-handling.html 557 func (e *InsertValues) fillEvent(ctx context.Context, event []types.Causet, hasValue []bool) ([]types.Causet, error) { 558 gDefCauss := make([]*causet.DeferredCauset, 0) 559 for i, c := range e.Block.DefCauss() { 560 var err error 561 // Evaluate the generated defCausumns later after real defCausumns set 562 if c.IsGenerated() { 563 gDefCauss = append(gDefCauss, c) 564 } else { 565 // Get the default value for all no value defCausumns, the auto increment defCausumn is different from the others. 566 if event[i], err = e.fillDefCausValue(ctx, event[i], i, c, hasValue[i]); err != nil { 567 return nil, err 568 } 569 if !e.lazyFillAutoID || (e.lazyFillAutoID && !allegrosql.HasAutoIncrementFlag(c.Flag)) { 570 if err = c.HandleBadNull(&event[i], e.ctx.GetStochastikVars().StmtCtx); err != nil { 571 return nil, err 572 } 573 } 574 } 575 } 576 for i, gDefCaus := range gDefCauss { 577 defCausIdx := gDefCaus.DeferredCausetInfo.Offset 578 val, err := e.GenExprs[i].Eval(chunk.MutEventFromCausets(event).ToEvent()) 579 if e.handleErr(gDefCaus, &val, 0, err) != nil { 580 return nil, err 581 } 582 event[defCausIdx], err = causet.CastValue(e.ctx, val, gDefCaus.ToInfo(), false, false) 583 if err != nil { 584 return nil, err 585 } 586 // Handle the bad null error. 587 if err = gDefCaus.HandleBadNull(&event[defCausIdx], e.ctx.GetStochastikVars().StmtCtx); err != nil { 588 return nil, err 589 } 590 } 591 return event, nil 592 } 593 594 // isAutoNull can help judge whether a causet is AutoIncrement Null quickly. 595 // This used to help lazyFillAutoIncrement to find consecutive N causet backwards for batch autoID alloc. 596 func (e *InsertValues) isAutoNull(ctx context.Context, d types.Causet, defCaus *causet.DeferredCauset) bool { 597 var err error 598 var recordID int64 599 if !d.IsNull() { 600 recordID, err = getAutoRecordID(d, &defCaus.FieldType, true) 601 if err != nil { 602 return false 603 } 604 } 605 // Use the value if it's not null and not 0. 606 if recordID != 0 { 607 return false 608 } 609 // Change NULL to auto id. 610 // Change value 0 to auto id, if NoAutoValueOnZero ALLEGROALLEGROSQL mode is not set. 611 if d.IsNull() || e.ctx.GetStochastikVars().ALLEGROSQLMode&allegrosql.ModeNoAutoValueOnZero == 0 { 612 return true 613 } 614 return false 615 } 616 617 func (e *InsertValues) hasAutoIncrementDeferredCauset() (int, bool) { 618 defCausIdx := -1 619 for i, c := range e.Block.DefCauss() { 620 if allegrosql.HasAutoIncrementFlag(c.Flag) { 621 defCausIdx = i 622 break 623 } 624 } 625 return defCausIdx, defCausIdx != -1 626 } 627 628 func (e *InsertValues) lazyAdjustAutoIncrementCausetInRetry(ctx context.Context, rows [][]types.Causet, defCausIdx int) ([][]types.Causet, error) { 629 // Get the autoIncrement defCausumn. 630 defCaus := e.Block.DefCauss()[defCausIdx] 631 // Consider the defCausIdx of autoIncrement in event are the same. 632 length := len(rows) 633 for i := 0; i < length; i++ { 634 autoCauset := rows[i][defCausIdx] 635 636 // autoID can be found in RetryInfo. 637 retryInfo := e.ctx.GetStochastikVars().RetryInfo 638 if retryInfo.Retrying { 639 id, err := retryInfo.GetCurrAutoIncrementID() 640 if err != nil { 641 return nil, err 642 } 643 autoCauset.SetAutoID(id, defCaus.Flag) 644 645 if err = defCaus.HandleBadNull(&autoCauset, e.ctx.GetStochastikVars().StmtCtx); err != nil { 646 return nil, err 647 } 648 rows[i][defCausIdx] = autoCauset 649 } 650 } 651 return rows, nil 652 } 653 654 // lazyAdjustAutoIncrementCauset is quite similar to adjustAutoIncrementCauset 655 // except it will cache auto increment causet previously for lazy batch allocation of autoID. 656 func (e *InsertValues) lazyAdjustAutoIncrementCauset(ctx context.Context, rows [][]types.Causet) ([][]types.Causet, error) { 657 // Not in lazyFillAutoID mode means no need to fill. 658 if !e.lazyFillAutoID { 659 return rows, nil 660 } 661 // No autoIncrement defCausumn means no need to fill. 662 defCausIdx, ok := e.hasAutoIncrementDeferredCauset() 663 if !ok { 664 return rows, nil 665 } 666 // autoID can be found in RetryInfo. 667 retryInfo := e.ctx.GetStochastikVars().RetryInfo 668 if retryInfo.Retrying { 669 return e.lazyAdjustAutoIncrementCausetInRetry(ctx, rows, defCausIdx) 670 } 671 // Get the autoIncrement defCausumn. 672 defCaus := e.Block.DefCauss()[defCausIdx] 673 // Consider the defCausIdx of autoIncrement in event are the same. 674 length := len(rows) 675 for i := 0; i < length; i++ { 676 autoCauset := rows[i][defCausIdx] 677 678 var err error 679 var recordID int64 680 if !autoCauset.IsNull() { 681 recordID, err = getAutoRecordID(autoCauset, &defCaus.FieldType, true) 682 if err != nil { 683 return nil, err 684 } 685 } 686 // Use the value if it's not null and not 0. 687 if recordID != 0 { 688 err = e.Block.RebaseAutoID(e.ctx, recordID, true, autoid.EventIDAllocType) 689 if err != nil { 690 return nil, err 691 } 692 e.ctx.GetStochastikVars().StmtCtx.InsertID = uint64(recordID) 693 retryInfo.AddAutoIncrementID(recordID) 694 rows[i][defCausIdx] = autoCauset 695 continue 696 } 697 698 // Change NULL to auto id. 699 // Change value 0 to auto id, if NoAutoValueOnZero ALLEGROALLEGROSQL mode is not set. 700 if autoCauset.IsNull() || e.ctx.GetStochastikVars().ALLEGROSQLMode&allegrosql.ModeNoAutoValueOnZero == 0 { 701 // Find consecutive num. 702 start := i 703 cnt := 1 704 for i+1 < length && e.isAutoNull(ctx, rows[i+1][defCausIdx], defCaus) { 705 i++ 706 cnt++ 707 } 708 // AllocBatchAutoIncrementValue allocates batch N consecutive autoIDs. 709 // The max value can be derived from adding the increment value to min for cnt-1 times. 710 min, increment, err := causet.AllocBatchAutoIncrementValue(ctx, e.Block, e.ctx, cnt) 711 if e.handleErr(defCaus, &autoCauset, cnt, err) != nil { 712 return nil, err 713 } 714 // It's compatible with allegrosql setting the first allocated autoID to lastInsertID. 715 // Cause autoID may be specified by user, judge only the first event is not suiblock. 716 if e.lastInsertID == 0 { 717 e.lastInsertID = uint64(min) 718 } 719 // Assign autoIDs to rows. 720 for j := 0; j < cnt; j++ { 721 offset := j + start 722 d := rows[offset][defCausIdx] 723 724 id := int64(uint64(min) + uint64(j)*uint64(increment)) 725 d.SetAutoID(id, defCaus.Flag) 726 retryInfo.AddAutoIncrementID(id) 727 728 // The value of d is adjusted by auto ID, so we need to cast it again. 729 d, err := causet.CastValue(e.ctx, d, defCaus.ToInfo(), false, false) 730 if err != nil { 731 return nil, err 732 } 733 rows[offset][defCausIdx] = d 734 } 735 continue 736 } 737 738 autoCauset.SetAutoID(recordID, defCaus.Flag) 739 retryInfo.AddAutoIncrementID(recordID) 740 741 // the value of d is adjusted by auto ID, so we need to cast it again. 742 autoCauset, err = causet.CastValue(e.ctx, autoCauset, defCaus.ToInfo(), false, false) 743 if err != nil { 744 return nil, err 745 } 746 rows[i][defCausIdx] = autoCauset 747 } 748 return rows, nil 749 } 750 751 func (e *InsertValues) adjustAutoIncrementCauset(ctx context.Context, d types.Causet, hasValue bool, c *causet.DeferredCauset) (types.Causet, error) { 752 retryInfo := e.ctx.GetStochastikVars().RetryInfo 753 if retryInfo.Retrying { 754 id, err := retryInfo.GetCurrAutoIncrementID() 755 if err != nil { 756 return types.Causet{}, err 757 } 758 d.SetAutoID(id, c.Flag) 759 return d, nil 760 } 761 762 var err error 763 var recordID int64 764 if !hasValue { 765 d.SetNull() 766 } 767 if !d.IsNull() { 768 recordID, err = getAutoRecordID(d, &c.FieldType, true) 769 if err != nil { 770 return types.Causet{}, err 771 } 772 } 773 // Use the value if it's not null and not 0. 774 if recordID != 0 { 775 err = e.Block.RebaseAutoID(e.ctx, recordID, true, autoid.EventIDAllocType) 776 if err != nil { 777 return types.Causet{}, err 778 } 779 e.ctx.GetStochastikVars().StmtCtx.InsertID = uint64(recordID) 780 retryInfo.AddAutoIncrementID(recordID) 781 return d, nil 782 } 783 784 // Change NULL to auto id. 785 // Change value 0 to auto id, if NoAutoValueOnZero ALLEGROALLEGROSQL mode is not set. 786 if d.IsNull() || e.ctx.GetStochastikVars().ALLEGROSQLMode&allegrosql.ModeNoAutoValueOnZero == 0 { 787 recordID, err = causet.AllocAutoIncrementValue(ctx, e.Block, e.ctx) 788 if e.handleErr(c, &d, 0, err) != nil { 789 return types.Causet{}, err 790 } 791 // It's compatible with allegrosql setting the first allocated autoID to lastInsertID. 792 // Cause autoID may be specified by user, judge only the first event is not suiblock. 793 if e.lastInsertID == 0 { 794 e.lastInsertID = uint64(recordID) 795 } 796 } 797 798 d.SetAutoID(recordID, c.Flag) 799 retryInfo.AddAutoIncrementID(recordID) 800 801 // the value of d is adjusted by auto ID, so we need to cast it again. 802 casted, err := causet.CastValue(e.ctx, d, c.ToInfo(), false, false) 803 if err != nil { 804 return types.Causet{}, err 805 } 806 return casted, nil 807 } 808 809 func getAutoRecordID(d types.Causet, target *types.FieldType, isInsert bool) (int64, error) { 810 var recordID int64 811 812 switch target.Tp { 813 case allegrosql.TypeFloat, allegrosql.TypeDouble: 814 f := d.GetFloat64() 815 if isInsert { 816 recordID = int64(math.Round(f)) 817 } else { 818 recordID = int64(f) 819 } 820 case allegrosql.TypeTiny, allegrosql.TypeShort, allegrosql.TypeInt24, allegrosql.TypeLong, allegrosql.TypeLonglong: 821 recordID = d.GetInt64() 822 default: 823 return 0, errors.Errorf("unexpected field type [%v]", target.Tp) 824 } 825 826 return recordID, nil 827 } 828 829 func (e *InsertValues) adjustAutoRandomCauset(ctx context.Context, d types.Causet, hasValue bool, c *causet.DeferredCauset) (types.Causet, error) { 830 retryInfo := e.ctx.GetStochastikVars().RetryInfo 831 if retryInfo.Retrying { 832 autoRandomID, err := retryInfo.GetCurrAutoRandomID() 833 if err != nil { 834 return types.Causet{}, err 835 } 836 d.SetAutoID(autoRandomID, c.Flag) 837 return d, nil 838 } 839 840 var err error 841 var recordID int64 842 if !hasValue { 843 d.SetNull() 844 } 845 if !d.IsNull() { 846 recordID, err = getAutoRecordID(d, &c.FieldType, true) 847 if err != nil { 848 return types.Causet{}, err 849 } 850 } 851 // Use the value if it's not null and not 0. 852 if recordID != 0 { 853 if !e.ctx.GetStochastikVars().AllowAutoRandExplicitInsert { 854 return types.Causet{}, dbs.ErrInvalidAutoRandom.GenWithStackByArgs(autoid.AutoRandomExplicitInsertDisabledErrMsg) 855 } 856 err = e.rebaseAutoRandomID(recordID, &c.FieldType) 857 if err != nil { 858 return types.Causet{}, err 859 } 860 e.ctx.GetStochastikVars().StmtCtx.InsertID = uint64(recordID) 861 d.SetAutoID(recordID, c.Flag) 862 retryInfo.AddAutoRandomID(recordID) 863 return d, nil 864 } 865 866 // Change NULL to auto id. 867 // Change value 0 to auto id, if NoAutoValueOnZero ALLEGROALLEGROSQL mode is not set. 868 if d.IsNull() || e.ctx.GetStochastikVars().ALLEGROSQLMode&allegrosql.ModeNoAutoValueOnZero == 0 { 869 _, err := e.ctx.Txn(true) 870 if err != nil { 871 return types.Causet{}, errors.Trace(err) 872 } 873 recordID, err = e.allocAutoRandomID(&c.FieldType) 874 if err != nil { 875 return types.Causet{}, err 876 } 877 // It's compatible with allegrosql setting the first allocated autoID to lastInsertID. 878 // Cause autoID may be specified by user, judge only the first event is not suiblock. 879 if e.lastInsertID == 0 { 880 e.lastInsertID = uint64(recordID) 881 } 882 } 883 884 d.SetAutoID(recordID, c.Flag) 885 retryInfo.AddAutoRandomID(recordID) 886 887 casted, err := causet.CastValue(e.ctx, d, c.ToInfo(), false, false) 888 if err != nil { 889 return types.Causet{}, err 890 } 891 return casted, nil 892 } 893 894 // allocAutoRandomID allocates a random id for primary key defCausumn. It assumes blockInfo.AutoRandomBits > 0. 895 func (e *InsertValues) allocAutoRandomID(fieldType *types.FieldType) (int64, error) { 896 alloc := e.Block.SlabPredictors(e.ctx).Get(autoid.AutoRandomType) 897 blockInfo := e.Block.Meta() 898 increment := e.ctx.GetStochastikVars().AutoIncrementIncrement 899 offset := e.ctx.GetStochastikVars().AutoIncrementOffset 900 _, autoRandomID, err := alloc.Alloc(blockInfo.ID, 1, int64(increment), int64(offset)) 901 if err != nil { 902 return 0, err 903 } 904 905 layout := autoid.NewAutoRandomIDLayout(fieldType, blockInfo.AutoRandomBits) 906 if blocks.OverflowShardBits(autoRandomID, blockInfo.AutoRandomBits, layout.TypeBitsLength, layout.HasSignBit) { 907 return 0, autoid.ErrAutoRandReadFailed 908 } 909 shard := e.ctx.GetStochastikVars().TxnCtx.GetShard(blockInfo.AutoRandomBits, layout.TypeBitsLength, layout.HasSignBit, 1) 910 autoRandomID |= shard 911 return autoRandomID, nil 912 } 913 914 func (e *InsertValues) rebaseAutoRandomID(recordID int64, fieldType *types.FieldType) error { 915 if recordID < 0 { 916 return nil 917 } 918 alloc := e.Block.SlabPredictors(e.ctx).Get(autoid.AutoRandomType) 919 blockInfo := e.Block.Meta() 920 921 layout := autoid.NewAutoRandomIDLayout(fieldType, blockInfo.AutoRandomBits) 922 autoRandomID := layout.IncrementalMask() & recordID 923 924 return alloc.Rebase(blockInfo.ID, autoRandomID, true) 925 } 926 927 func (e *InsertValues) handleWarning(err error) { 928 sc := e.ctx.GetStochastikVars().StmtCtx 929 sc.AppendWarning(err) 930 } 931 932 func (e *InsertValues) defCauslectRuntimeStatsEnabled() bool { 933 if e.runtimeStats != nil { 934 if e.stats == nil { 935 snapshotStats := &einsteindb.SnapshotRuntimeStats{} 936 e.stats = &runtimeStatsWithSnapshot{ 937 SnapshotRuntimeStats: snapshotStats, 938 } 939 e.ctx.GetStochastikVars().StmtCtx.RuntimeStatsDefCausl.RegisterStats(e.id, e.stats) 940 } 941 return true 942 } 943 return false 944 } 945 946 // batchCheckAndInsert checks rows with duplicate errors. 947 // All duplicate rows will be ignored and appended as duplicate warnings. 948 func (e *InsertValues) batchCheckAndInsert(ctx context.Context, rows [][]types.Causet, addRecord func(ctx context.Context, event []types.Causet) error) error { 949 // all the rows will be checked, so it is safe to set BatchCheck = true 950 e.ctx.GetStochastikVars().StmtCtx.BatchCheck = true 951 952 // Get keys need to be checked. 953 toBeCheckedEvents, err := getKeysNeedCheck(ctx, e.ctx, e.Block, rows) 954 if err != nil { 955 return err 956 } 957 958 txn, err := e.ctx.Txn(true) 959 if err != nil { 960 return err 961 } 962 963 if e.defCauslectRuntimeStatsEnabled() { 964 if snapshot := txn.GetSnapshot(); snapshot != nil { 965 snapshot.SetOption(ekv.DefCauslectRuntimeStats, e.stats.SnapshotRuntimeStats) 966 defer snapshot.DelOption(ekv.DefCauslectRuntimeStats) 967 } 968 } 969 970 // Fill cache using BatchGet, the following Get requests don't need to visit EinsteinDB. 971 if _, err = prefetchUniqueIndices(ctx, txn, toBeCheckedEvents); err != nil { 972 return err 973 } 974 975 // append warnings and get no duplicated error rows 976 for i, r := range toBeCheckedEvents { 977 skip := false 978 if r.handleKey != nil { 979 _, err := txn.Get(ctx, r.handleKey.newKey) 980 if err == nil { 981 e.ctx.GetStochastikVars().StmtCtx.AppendWarning(r.handleKey.dupErr) 982 continue 983 } 984 if !ekv.IsErrNotFound(err) { 985 return err 986 } 987 } 988 for _, uk := range r.uniqueKeys { 989 _, err := txn.Get(ctx, uk.newKey) 990 if err == nil { 991 // If duplicate keys were found in BatchGet, mark event = nil. 992 e.ctx.GetStochastikVars().StmtCtx.AppendWarning(uk.dupErr) 993 skip = true 994 break 995 } 996 if !ekv.IsErrNotFound(err) { 997 return err 998 } 999 } 1000 // If event was checked with no duplicate keys, 1001 // it should be add to values map for the further event check. 1002 // There may be duplicate keys inside the insert memex. 1003 if !skip { 1004 e.ctx.GetStochastikVars().StmtCtx.AddCopiedEvents(1) 1005 err = addRecord(ctx, rows[i]) 1006 if err != nil { 1007 return err 1008 } 1009 } 1010 } 1011 return nil 1012 } 1013 1014 func (e *InsertValues) addRecord(ctx context.Context, event []types.Causet) error { 1015 return e.addRecordWithAutoIDHint(ctx, event, 0) 1016 } 1017 1018 func (e *InsertValues) addRecordWithAutoIDHint(ctx context.Context, event []types.Causet, reserveAutoIDCount int) (err error) { 1019 vars := e.ctx.GetStochastikVars() 1020 if !vars.ConstraintCheckInPlace { 1021 vars.PresumeKeyNotExists = true 1022 } 1023 if reserveAutoIDCount > 0 { 1024 _, err = e.Block.AddRecord(e.ctx, event, causet.WithCtx(ctx), causet.WithReserveAutoIDHint(reserveAutoIDCount)) 1025 } else { 1026 _, err = e.Block.AddRecord(e.ctx, event, causet.WithCtx(ctx)) 1027 } 1028 vars.PresumeKeyNotExists = false 1029 if err != nil { 1030 return err 1031 } 1032 if e.lastInsertID != 0 { 1033 vars.SetLastInsertID(e.lastInsertID) 1034 } 1035 return nil 1036 }