func (s *testIndexChangeSuite) checkDropWriteOnly(d *ddl, ctx context.Context, publicTbl, writeTbl table.Table) error { // WriteOnlyTable insert t values (8, 8) _, err := writeTbl.AddRecord(ctx, types.MakeDatums(8, 8)) if err != nil { return errors.Trace(err) } err = checkIndexExists(ctx, publicTbl, 8, 8, true) if err != nil { return errors.Trace(err) } // WriteOnlyTable update t set c2 = 7 where c1 = 8 and c2 = 8 err = writeTbl.UpdateRecord(ctx, 8, types.MakeDatums(8, 8), types.MakeDatums(8, 7), touchedMap(writeTbl)) if err != nil { return errors.Trace(err) } err = checkIndexExists(ctx, publicTbl, 7, 8, true) if err != nil { return errors.Trace(err) } // WriteOnlyTable delete t where c1 = 8 err = writeTbl.RemoveRecord(ctx, 8, types.MakeDatums(8, 7)) if err != nil { return errors.Trace(err) } err = checkIndexExists(ctx, publicTbl, 7, 8, false) if err != nil { return errors.Trace(err) } return nil }
func (s *testColumnChangeSuite) checkAddPublic(d *ddl, ctx context.Context, writeOnlyTable, publicTable table.Table) error { // publicTable Insert t values (4, 4, 4) h, err := publicTable.AddRecord(ctx, types.MakeDatums(4, 4, 4)) if err != nil { return errors.Trace(err) } err = ctx.CommitTxn() if err != nil { return errors.Trace(err) } // writeOnlyTable update t set c1 = 3 where c1 = 4 oldRow, err := writeOnlyTable.RowWithCols(ctx, h, writeOnlyTable.WritableCols()) if err != nil { return errors.Trace(err) } if len(oldRow) != 3 { return errors.Errorf("%v", oldRow) } newRow := types.MakeDatums(3, 4, oldRow[2].GetValue()) err = writeOnlyTable.UpdateRecord(ctx, h, oldRow, newRow, touchedMap(writeOnlyTable)) if err != nil { return errors.Trace(err) } err = ctx.CommitTxn() if err != nil { return errors.Trace(err) } // publicTable select * from t, make sure the new c3 value 4 is not overwritten to default value 3. err = checkResult(ctx, publicTable, testutil.RowsWithSep(" ", "2 3 3", "3 4 4")) if err != nil { return errors.Trace(err) } return nil }
func (s *testIndexChangeSuite) checkDropDeleteOnly(d *ddl, ctx context.Context, writeTbl, delTbl table.Table) error { // WriteOnlyTable insert t values (9, 9) _, err := writeTbl.AddRecord(ctx, types.MakeDatums(9, 9)) if err != nil { return errors.Trace(err) } err = checkIndexExists(ctx, writeTbl, 9, 9, true) // DeleteOnlyTable insert t values (10, 10) _, err = delTbl.AddRecord(ctx, types.MakeDatums(10, 10)) if err != nil { return errors.Trace(err) } err = checkIndexExists(ctx, writeTbl, 10, 10, false) if err != nil { return errors.Trace(err) } // DeleteOnlyTable update t set c2 = 10 where c1 = 9 err = delTbl.UpdateRecord(ctx, 9, types.MakeDatums(9, 9), types.MakeDatums(9, 10), touchedMap(delTbl)) if err != nil { return errors.Trace(err) } err = checkIndexExists(ctx, writeTbl, 9, 9, false) if err != nil { return errors.Trace(err) } err = checkIndexExists(ctx, writeTbl, 10, 9, false) if err != nil { return errors.Trace(err) } return nil }
func (s *testIndexChangeSuite) checkAddPublic(d *ddl, ctx context.Context, writeTbl, publicTbl table.Table) error { // WriteOnlyTable: insert t values (6, 6) _, err := writeTbl.AddRecord(ctx, types.MakeDatums(6, 6)) if err != nil { return errors.Trace(err) } err = checkIndexExists(ctx, publicTbl, 6, 6, true) if err != nil { return errors.Trace(err) } // PublicTable: insert t values (7, 7) _, err = publicTbl.AddRecord(ctx, types.MakeDatums(7, 7)) if err != nil { return errors.Trace(err) } err = checkIndexExists(ctx, publicTbl, 7, 7, true) if err != nil { return errors.Trace(err) } // WriteOnlyTable: update t set c2 = 5 where c1 = 7 and c2 = 7 err = writeTbl.UpdateRecord(ctx, 7, types.MakeDatums(7, 7), types.MakeDatums(7, 5), touchedMap(writeTbl)) if err != nil { return errors.Trace(err) } err = checkIndexExists(ctx, publicTbl, 5, 7, true) if err != nil { return errors.Trace(err) } err = checkIndexExists(ctx, publicTbl, 7, 7, false) if err != nil { return errors.Trace(err) } // WriteOnlyTable: delete t where c1 = 6 err = writeTbl.RemoveRecord(ctx, 6, types.MakeDatums(6, 6)) if err != nil { return errors.Trace(err) } err = checkIndexExists(ctx, publicTbl, 6, 6, false) var rows [][]types.Datum publicTbl.IterRecords(ctx, publicTbl.FirstKey(), publicTbl.Cols(), func(h int64, data []types.Datum, cols []*table.Column) (bool, error) { rows = append(rows, data) return true, nil }) if len(rows) == 0 { return errors.New("table is empty") } for _, row := range rows { idxVal := row[1].GetInt64() handle := row[0].GetInt64() err = checkIndexExists(ctx, publicTbl, idxVal, handle, true) if err != nil { return errors.Trace(err) } } return nil }
// execExecSelect implements `insert table select ... from ...`. func (s *InsertValues) execSelect(t table.Table, cols []*column.Col, ctx context.Context) (rset.Recordset, error) { r, err := s.Sel.Plan(ctx) if err != nil { return nil, errors.Trace(err) } defer r.Close() if len(r.GetFields()) != len(cols) { return nil, errors.Errorf("Column count %d doesn't match value count %d", len(cols), len(r.GetFields())) } var bufRecords [][]interface{} var lastInsertIds []uint64 for { var row *plan.Row row, err = r.Next(ctx) if err != nil { return nil, errors.Trace(err) } if row == nil { break } data0 := make([]interface{}, len(t.Cols())) marked := make(map[int]struct{}, len(cols)) for i, d := range row.Data { data0[cols[i].Offset] = d marked[cols[i].Offset] = struct{}{} } if err = s.initDefaultValues(ctx, t, data0, marked); err != nil { return nil, errors.Trace(err) } if err = column.CastValues(ctx, data0, cols); err != nil { return nil, errors.Trace(err) } if err = column.CheckNotNull(t.Cols(), data0); err != nil { return nil, errors.Trace(err) } var v interface{} v, err = types.Clone(data0) if err != nil { return nil, errors.Trace(err) } bufRecords = append(bufRecords, v.([]interface{})) lastInsertIds = append(lastInsertIds, variable.GetSessionVars(ctx).LastInsertID) } for i, r := range bufRecords { variable.GetSessionVars(ctx).SetLastInsertID(lastInsertIds[i]) if _, err = t.AddRecord(ctx, r); err != nil { return nil, errors.Trace(err) } } return nil, nil }
func insertData(tbl table.Table, rows [][]types.Datum) error { for _, r := range rows { _, err := tbl.AddRecord(nil, r) if err != nil { return errors.Trace(err) } } return nil }
// execExecSelect implements `insert table select ... from ...`. func (s *InsertIntoStmt) execSelect(t table.Table, cols []*column.Col, ctx context.Context) (_ rset.Recordset, err error) { r, err := s.Sel.Plan(ctx) if err != nil { return nil, errors.Trace(err) } else if len(r.GetFields()) != len(cols) { return nil, errors.Errorf("Column count %d doesn't match value count %d", len(cols), len(r.GetFields())) } var bufRecords [][]interface{} var lastInsertIds []uint64 err = r.Do(ctx, func(_ interface{}, data []interface{}) (more bool, err error) { data0 := make([]interface{}, len(t.Cols())) marked := make(map[int]struct{}, len(cols)) for i, d := range data { data0[cols[i].Offset] = d marked[cols[i].Offset] = struct{}{} } if err = s.initDefaultValues(ctx, t, t.Cols(), data0, marked); err != nil { return false, errors.Trace(err) } if err = column.CastValues(ctx, data0, cols); err != nil { return false, errors.Trace(err) } if err = column.CheckNotNull(t.Cols(), data0); err != nil { return false, errors.Trace(err) } v, err := types.Clone(data0) if err != nil { return false, errors.Trace(err) } bufRecords = append(bufRecords, v.([]interface{})) lastInsertIds = append(lastInsertIds, variable.GetSessionVars(ctx).LastInsertID) return true, nil }) if err != nil { return nil, errors.Trace(err) } for i, r := range bufRecords { variable.GetSessionVars(ctx).SetLastInsertID(lastInsertIds[i]) if _, err = t.AddRecord(ctx, r); err != nil { return nil, errors.Trace(err) } } return nil, nil }
func (s *testColumnChangeSuite) checkAddWriteOnly(d *ddl, ctx context.Context, deleteOnlyTable, writeOnlyTable table.Table) error { // WriteOnlyTable: insert t values (2, 3) _, err := writeOnlyTable.AddRecord(ctx, types.MakeDatums(2, 3)) if err != nil { return errors.Trace(err) } err = ctx.CommitTxn() if err != nil { return errors.Trace(err) } err = checkResult(ctx, writeOnlyTable, testutil.RowsWithSep(" ", "1 2 <nil>", "2 3 3")) if err != nil { return errors.Trace(err) } // DeleteOnlyTable: select * from t err = checkResult(ctx, deleteOnlyTable, testutil.RowsWithSep(" ", "1 2", "2 3")) if err != nil { return errors.Trace(err) } // WriteOnlyTable: update t set c1 = 2 where c1 = 1 h, _, err := writeOnlyTable.Seek(ctx, 0) if err != nil { return errors.Trace(err) } err = writeOnlyTable.UpdateRecord(ctx, h, types.MakeDatums(1, 2), types.MakeDatums(2, 2), touchedMap(writeOnlyTable)) if err != nil { return errors.Trace(err) } err = ctx.CommitTxn() if err != nil { return errors.Trace(err) } // After we update the first row, its default value is also set. err = checkResult(ctx, writeOnlyTable, testutil.RowsWithSep(" ", "2 2 3", "2 3 3")) if err != nil { return errors.Trace(err) } // DeleteOnlyTable: delete from t where c2 = 2 err = deleteOnlyTable.RemoveRecord(ctx, h, types.MakeDatums(2, 2)) if err != nil { return errors.Trace(err) } err = ctx.CommitTxn() if err != nil { return errors.Trace(err) } // After delete table has deleted the first row, check the WriteOnly table records. err = checkResult(ctx, writeOnlyTable, testutil.RowsWithSep(" ", "2 3 3")) return errors.Trace(err) }
func (s *testColumnChangeSuite) testAddColumnNoDefault(c *C, ctx context.Context, d *ddl, tblInfo *model.TableInfo) { d.close() tc := &testDDLCallback{} // set up hook prevState := model.StateNone var checkErr error var writeOnlyTable, publicTable table.Table tc.onJobUpdated = func(job *model.Job) { if job.SchemaState == prevState { return } prevState = job.SchemaState var err error switch job.SchemaState { case model.StateWriteOnly: writeOnlyTable, err = getCurrentTable(d, s.dbInfo.ID, tblInfo.ID) if err != nil { checkErr = errors.Trace(err) } case model.StatePublic: publicTable, err = getCurrentTable(d, s.dbInfo.ID, tblInfo.ID) if err != nil { checkErr = errors.Trace(err) } _, err = writeOnlyTable.AddRecord(ctx, types.MakeDatums(10, 10)) if err != nil { checkErr = errors.Trace(err) } } } d.hook = tc d.start() job := testCreateColumn(c, ctx, d, s.dbInfo, tblInfo, "c3", &ast.ColumnPosition{Tp: ast.ColumnPositionNone}, nil) c.Assert(errors.ErrorStack(checkErr), Equals, "") testCheckJobDone(c, d, job, true) }
func updateRecord(ctx context.Context, h int64, oldData, newData []types.Datum, assignFlag []bool, t table.Table, offset int, onDuplicateUpdate bool) error { cols := t.Cols() touched := make(map[int]bool, len(cols)) assignExists := false sc := ctx.GetSessionVars().StmtCtx var newHandle types.Datum for i, hasSetExpr := range assignFlag { if !hasSetExpr { if onDuplicateUpdate { newData[i] = oldData[i] } continue } if i < offset || i >= offset+len(cols) { // The assign expression is for another table, not this. continue } colIndex := i - offset col := cols[colIndex] if col.IsPKHandleColumn(t.Meta()) { newHandle = newData[i] } if mysql.HasAutoIncrementFlag(col.Flag) { if newData[i].IsNull() { return errors.Errorf("Column '%v' cannot be null", col.Name.O) } val, err := newData[i].ToInt64(sc) if err != nil { return errors.Trace(err) } t.RebaseAutoID(val, true) } touched[colIndex] = true assignExists = true } // If no assign list for this table, no need to update. if !assignExists { return nil } // Check whether new value is valid. if err := table.CastValues(ctx, newData, cols, false); err != nil { return errors.Trace(err) } if err := table.CheckNotNull(cols, newData); err != nil { return errors.Trace(err) } // If row is not changed, we should do nothing. rowChanged := false for i := range oldData { if !touched[i] { continue } n, err := newData[i].CompareDatum(sc, oldData[i]) if err != nil { return errors.Trace(err) } if n != 0 { rowChanged = true break } } if !rowChanged { // See https://dev.mysql.com/doc/refman/5.7/en/mysql-real-connect.html CLIENT_FOUND_ROWS if ctx.GetSessionVars().ClientCapability&mysql.ClientFoundRows > 0 { sc.AddAffectedRows(1) } return nil } var err error if !newHandle.IsNull() { err = t.RemoveRecord(ctx, h, oldData) if err != nil { return errors.Trace(err) } _, err = t.AddRecord(ctx, newData) } else { // Update record to new value and update index. err = t.UpdateRecord(ctx, h, oldData, newData, touched) } if err != nil { return errors.Trace(err) } dirtyDB := getDirtyDB(ctx) tid := t.Meta().ID dirtyDB.deleteRow(tid, h) dirtyDB.addRow(tid, h, newData) // Record affected rows. if !onDuplicateUpdate { sc.AddAffectedRows(1) } else { sc.AddAffectedRows(2) } return nil }
func updateRecord(ctx context.Context, h int64, data []interface{}, t table.Table, updateColumns map[int]*expression.Assignment, evalMap map[interface{}]interface{}, offset int, onDuplicateUpdate bool) error { if err := t.LockRow(ctx, h); err != nil { return errors.Trace(err) } cols := t.Cols() oldData := data newData := make([]interface{}, len(cols)) touched := make(map[int]bool, len(cols)) copy(newData, oldData) assignExists := false var newHandle interface{} for i, asgn := range updateColumns { if i < offset || i >= offset+len(cols) { // The assign expression is for another table, not this. continue } val, err := asgn.Expr.Eval(ctx, evalMap) if err != nil { return errors.Trace(err) } colIndex := i - offset col := cols[colIndex] if col.IsPKHandleColumn(t.Meta()) { newHandle = val } touched[colIndex] = true newData[colIndex] = val assignExists = true } // If no assign list for this table, no need to update. if !assignExists { return nil } // Check whether new value is valid. if err := column.CastValues(ctx, newData, cols); err != nil { return errors.Trace(err) } if err := column.CheckNotNull(cols, newData); err != nil { return errors.Trace(err) } // If row is not changed, we should do nothing. rowChanged := false for i := range oldData { if !touched[i] { continue } n, err := types.Compare(newData[i], oldData[i]) if err != nil { return errors.Trace(err) } if n != 0 { rowChanged = true break } } if !rowChanged { // See: https://dev.mysql.com/doc/refman/5.7/en/mysql-real-connect.html CLIENT_FOUND_ROWS if variable.GetSessionVars(ctx).ClientCapability&mysql.ClientFoundRows > 0 { variable.GetSessionVars(ctx).AddAffectedRows(1) } return nil } var err error if newHandle != nil { err = t.RemoveRecord(ctx, h, oldData) if err != nil { return errors.Trace(err) } _, err = t.AddRecord(ctx, newData) } else { // Update record to new value and update index. err = t.UpdateRecord(ctx, h, oldData, newData, touched) } if err != nil { return errors.Trace(err) } // Record affected rows. if !onDuplicateUpdate { variable.GetSessionVars(ctx).AddAffectedRows(1) } else { variable.GetSessionVars(ctx).AddAffectedRows(2) } return nil }
func (s *testIndexChangeSuite) checkAddWriteOnly(d *ddl, ctx context.Context, delOnlyTbl, writeOnlyTbl table.Table) error { // DeleteOnlyTable: insert t values (4, 4); _, err := delOnlyTbl.AddRecord(ctx, types.MakeDatums(4, 4)) if err != nil { return errors.Trace(err) } err = checkIndexExists(ctx, writeOnlyTbl, 4, 4, false) if err != nil { return errors.Trace(err) } // WriteOnlyTable: insert t values (5, 5); _, err = writeOnlyTbl.AddRecord(ctx, types.MakeDatums(5, 5)) if err != nil { return errors.Trace(err) } err = checkIndexExists(ctx, writeOnlyTbl, 5, 5, true) if err != nil { return errors.Trace(err) } // WriteOnlyTable: update t set c2 = 1 where c1 = 4 and c2 = 4 err = writeOnlyTbl.UpdateRecord(ctx, 4, types.MakeDatums(4, 4), types.MakeDatums(4, 1), touchedMap(writeOnlyTbl)) if err != nil { return errors.Trace(err) } err = checkIndexExists(ctx, writeOnlyTbl, 1, 4, true) if err != nil { return errors.Trace(err) } // DeleteOnlyTable: update t set c2 = 3 where c1 = 4 and c2 = 1 err = delOnlyTbl.UpdateRecord(ctx, 4, types.MakeDatums(4, 1), types.MakeDatums(4, 3), touchedMap(writeOnlyTbl)) if err != nil { return errors.Trace(err) } // old value index not exists. err = checkIndexExists(ctx, writeOnlyTbl, 1, 4, false) if err != nil { return errors.Trace(err) } // new value index not exists. err = checkIndexExists(ctx, writeOnlyTbl, 3, 4, false) if err != nil { return errors.Trace(err) } // WriteOnlyTable: delete t where c1 = 4 and c2 = 3 err = writeOnlyTbl.RemoveRecord(ctx, 4, types.MakeDatums(4, 3)) if err != nil { return errors.Trace(err) } err = checkIndexExists(ctx, writeOnlyTbl, 3, 4, false) if err != nil { return errors.Trace(err) } // DeleteOnlyTable: delete t where c1 = 5 err = delOnlyTbl.RemoveRecord(ctx, 5, types.MakeDatums(5, 5)) if err != nil { return errors.Trace(err) } err = checkIndexExists(ctx, writeOnlyTbl, 5, 5, false) if err != nil { return errors.Trace(err) } return nil }