From cb067669f8ef64b2b2cabb2c70e7c78ee272aedb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E8=B6=85?= Date: Mon, 8 Jan 2024 12:22:53 +0800 Subject: [PATCH] This is an automated cherry-pick of #50134 Signed-off-by: ti-chi-bot --- pkg/executor/write.go | 357 +++++++ .../r/executor/partition/write.result | 842 +++++++++++++++++ .../integrationtest/r/executor/update.result | 893 ++++++++++++++++++ .../t/executor/partition/write.test | 621 ++++++++++++ 4 files changed, 2713 insertions(+) create mode 100644 pkg/executor/write.go create mode 100644 tests/integrationtest/r/executor/partition/write.result create mode 100644 tests/integrationtest/r/executor/update.result create mode 100644 tests/integrationtest/t/executor/partition/write.test diff --git a/pkg/executor/write.go b/pkg/executor/write.go new file mode 100644 index 0000000000000..05c7a48064934 --- /dev/null +++ b/pkg/executor/write.go @@ -0,0 +1,357 @@ +// Copyright 2016 PingCAP, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package executor + +import ( + "context" + "strings" + + "github.com/pingcap/errors" + "github.com/pingcap/tidb/pkg/errno" + "github.com/pingcap/tidb/pkg/executor/internal/exec" + "github.com/pingcap/tidb/pkg/expression" + "github.com/pingcap/tidb/pkg/infoschema" + "github.com/pingcap/tidb/pkg/kv" + "github.com/pingcap/tidb/pkg/meta/autoid" + "github.com/pingcap/tidb/pkg/parser/ast" + "github.com/pingcap/tidb/pkg/parser/model" + "github.com/pingcap/tidb/pkg/parser/mysql" + "github.com/pingcap/tidb/pkg/parser/terror" + "github.com/pingcap/tidb/pkg/sessionctx" + "github.com/pingcap/tidb/pkg/sessionctx/variable" + "github.com/pingcap/tidb/pkg/table" + "github.com/pingcap/tidb/pkg/tablecodec" + "github.com/pingcap/tidb/pkg/types" + "github.com/pingcap/tidb/pkg/util/collate" + "github.com/pingcap/tidb/pkg/util/memory" + "github.com/pingcap/tidb/pkg/util/tracing" +) + +var ( + _ exec.Executor = &UpdateExec{} + _ exec.Executor = &DeleteExec{} + _ exec.Executor = &InsertExec{} + _ exec.Executor = &ReplaceExec{} + _ exec.Executor = &LoadDataExec{} +) + +// updateRecord updates the row specified by the handle `h`, from `oldData` to `newData`. +// `modified` means which columns are really modified. It's used for secondary indices. +// Length of `oldData` and `newData` equals to length of `t.WritableCols()`. +// The return values: +// 1. changed (bool) : does the update really change the row values. e.g. update set i = 1 where i = 1; +// 2. err (error) : error in the update. +func updateRecord( + ctx context.Context, sctx sessionctx.Context, h kv.Handle, oldData, newData []types.Datum, modified []bool, + t table.Table, + onDup bool, _ *memory.Tracker, fkChecks []*FKCheckExec, fkCascades []*FKCascadeExec, +) (bool, error) { + r, ctx := tracing.StartRegionEx(ctx, "executor.updateRecord") + defer r.End() + + sc := sctx.GetSessionVars().StmtCtx + changed, handleChanged := false, false + // onUpdateSpecified is for "UPDATE SET ts_field = old_value", the + // timestamp field is explicitly set, but not changed in fact. + onUpdateSpecified := make(map[int]bool) + + // We can iterate on public columns not writable columns, + // because all of them are sorted by their `Offset`, which + // causes all writable columns are after public columns. + + // Handle the bad null error. + for i, col := range t.Cols() { + var err error + if err = col.HandleBadNull(sc.ErrCtx(), &newData[i], 0); err != nil { + return false, err + } + } + + // Handle exchange partition + tbl := t.Meta() + if tbl.ExchangePartitionInfo != nil && tbl.GetPartitionInfo() == nil { + if err := checkRowForExchangePartition(sctx, newData, tbl); err != nil { + return false, err + } + } + + // Compare datum, then handle some flags. + for i, col := range t.Cols() { + // We should use binary collation to compare datum, otherwise the result will be incorrect. + cmp, err := newData[i].Compare(sc.TypeCtx(), &oldData[i], collate.GetBinaryCollator()) + if err != nil { + return false, err + } + if cmp != 0 { + changed = true + modified[i] = true + // Rebase auto increment id if the field is changed. + if mysql.HasAutoIncrementFlag(col.GetFlag()) { + recordID, err := getAutoRecordID(newData[i], &col.FieldType, false) + if err != nil { + return false, err + } + if err = t.Allocators(sctx).Get(autoid.AutoIncrementType).Rebase(ctx, recordID, true); err != nil { + return false, err + } + } + if col.IsPKHandleColumn(t.Meta()) { + handleChanged = true + // Rebase auto random id if the field is changed. + if err := rebaseAutoRandomValue(ctx, sctx, t, &newData[i], col); err != nil { + return false, err + } + } + if col.IsCommonHandleColumn(t.Meta()) { + handleChanged = true + } + } else { + if mysql.HasOnUpdateNowFlag(col.GetFlag()) && modified[i] { + // It's for "UPDATE t SET ts = ts" and ts is a timestamp. + onUpdateSpecified[i] = true + } + modified[i] = false + } + } + + sc.AddTouchedRows(1) + // If no changes, nothing to do, return directly. + if !changed { + // See https://dev.mysql.com/doc/refman/5.7/en/mysql-real-connect.html CLIENT_FOUND_ROWS + if sctx.GetSessionVars().ClientCapability&mysql.ClientFoundRows > 0 { + sc.AddAffectedRows(1) + } + keySet := lockRowKey + if sctx.GetSessionVars().LockUnchangedKeys { + keySet |= lockUniqueKeys + } + _, err := addUnchangedKeysForLockByRow(sctx, t, h, oldData, keySet) + return false, err + } + + // Fill values into on-update-now fields, only if they are really changed. + for i, col := range t.Cols() { + if mysql.HasOnUpdateNowFlag(col.GetFlag()) && !modified[i] && !onUpdateSpecified[i] { + v, err := expression.GetTimeValue(sctx, strings.ToUpper(ast.CurrentTimestamp), col.GetType(), col.GetDecimal(), nil) + if err != nil { + return false, err + } + newData[i] = v + modified[i] = true + // Only TIMESTAMP and DATETIME columns can be automatically updated, so it cannot be PKIsHandle. + // Ref: https://dev.mysql.com/doc/refman/8.0/en/timestamp-initialization.html + if col.IsPKHandleColumn(t.Meta()) { + return false, errors.Errorf("on-update-now column should never be pk-is-handle") + } + if col.IsCommonHandleColumn(t.Meta()) { + handleChanged = true + } + } + } + + // If handle changed, remove the old then add the new record, otherwise update the record. + if handleChanged { + // For `UPDATE IGNORE`/`INSERT IGNORE ON DUPLICATE KEY UPDATE` + // we use the staging buffer so that we don't need to precheck the existence of handle or unique keys by sending + // extra kv requests, and the remove action will not take effect if there are conflicts. + if updated, err := func() (bool, error) { + txn, err := sctx.Txn(true) + if err != nil { + return false, err + } + memBuffer := txn.GetMemBuffer() + sh := memBuffer.Staging() + defer memBuffer.Cleanup(sh) + + if err = t.RemoveRecord(sctx, h, oldData); err != nil { + return false, err + } + + _, err = t.AddRecord(sctx, newData, table.IsUpdate, table.WithCtx(ctx)) + if err != nil { + return false, err + } + memBuffer.Release(sh) + return true, nil + }(); err != nil { + if terr, ok := errors.Cause(err).(*terror.Error); sctx.GetSessionVars().StmtCtx.IgnoreNoPartition && ok && (terr.Code() == errno.ErrNoPartitionForGivenValue || terr.Code() == errno.ErrRowDoesNotMatchGivenPartitionSet) { + sctx.GetSessionVars().StmtCtx.AppendWarning(err) + return false, nil + } + return updated, err + } + } else { + // Update record to new value and update index. + if err := t.UpdateRecord(ctx, sctx, h, oldData, newData, modified); err != nil { + if terr, ok := errors.Cause(err).(*terror.Error); sctx.GetSessionVars().StmtCtx.IgnoreNoPartition && ok && (terr.Code() == errno.ErrNoPartitionForGivenValue || terr.Code() == errno.ErrRowDoesNotMatchGivenPartitionSet) { + sctx.GetSessionVars().StmtCtx.AppendWarning(err) + return false, nil + } + return false, err + } + if sctx.GetSessionVars().LockUnchangedKeys { + // Lock unique keys when handle unchanged + if _, err := addUnchangedKeysForLockByRow(sctx, t, h, oldData, lockUniqueKeys); err != nil { + return false, err + } + } + } + for _, fkt := range fkChecks { + err := fkt.updateRowNeedToCheck(sc, oldData, newData) + if err != nil { + return false, err + } + } + for _, fkc := range fkCascades { + err := fkc.onUpdateRow(sc, oldData, newData) + if err != nil { + return false, err + } + } + if onDup { + sc.AddAffectedRows(2) + } else { + sc.AddAffectedRows(1) + } + sc.AddUpdatedRows(1) + sc.AddCopiedRows(1) + + return true, nil +} + +const ( + lockRowKey = 1 << iota + lockUniqueKeys +) + +func addUnchangedKeysForLockByRow( + sctx sessionctx.Context, t table.Table, h kv.Handle, row []types.Datum, keySet int, +) (int, error) { + txnCtx := sctx.GetSessionVars().TxnCtx + if !txnCtx.IsPessimistic || keySet == 0 { + return 0, nil + } + count := 0 + physicalID := t.Meta().ID + if pt, ok := t.(table.PartitionedTable); ok { + p, err := pt.GetPartitionByRow(sctx, row) + if err != nil { + return 0, err + } + physicalID = p.GetPhysicalID() + } + if keySet&lockRowKey > 0 { + unchangedRowKey := tablecodec.EncodeRowKeyWithHandle(physicalID, h) + txnCtx.AddUnchangedKeyForLock(unchangedRowKey) + count++ + } + if keySet&lockUniqueKeys > 0 { + stmtCtx := sctx.GetSessionVars().StmtCtx + clustered := t.Meta().HasClusteredIndex() + for _, idx := range t.Indices() { + meta := idx.Meta() + if !meta.Unique || !meta.IsPublic() || (meta.Primary && clustered) { + continue + } + ukVals, err := idx.FetchValues(row, nil) + if err != nil { + return count, err + } + unchangedUniqueKey, _, err := tablecodec.GenIndexKey( + stmtCtx.TimeZone(), + idx.TableMeta(), + meta, + physicalID, + ukVals, + h, + nil, + ) + err = stmtCtx.HandleError(err) + if err != nil { + return count, err + } + txnCtx.AddUnchangedKeyForLock(unchangedUniqueKey) + count++ + } + } + return count, nil +} + +func rebaseAutoRandomValue( + ctx context.Context, sctx sessionctx.Context, t table.Table, newData *types.Datum, col *table.Column, +) error { + tableInfo := t.Meta() + if !tableInfo.ContainsAutoRandomBits() { + return nil + } + recordID, err := getAutoRecordID(*newData, &col.FieldType, false) + if err != nil { + return err + } + if recordID < 0 { + return nil + } + shardFmt := autoid.NewShardIDFormat(&col.FieldType, tableInfo.AutoRandomBits, tableInfo.AutoRandomRangeBits) + // Set bits except incremental_bits to zero. + recordID = recordID & shardFmt.IncrementalMask() + return t.Allocators(sctx).Get(autoid.AutoRandomType).Rebase(ctx, recordID, true) +} + +// resetErrDataTooLong reset ErrDataTooLong error msg. +// types.ErrDataTooLong is produced in types.ProduceStrWithSpecifiedTp, there is no column info in there, +// so we reset the error msg here, and wrap old err with errors.Wrap. +func resetErrDataTooLong(colName string, rowIdx int, _ error) error { + newErr := types.ErrDataTooLong.GenWithStack("Data too long for column '%v' at row %v", colName, rowIdx) + return newErr +} + +// checkRowForExchangePartition is only used for ExchangePartition by non-partitionTable during write only state. +// It check if rowData inserted or updated violate partition definition or checkConstraints of partitionTable. +func checkRowForExchangePartition(sctx sessionctx.Context, row []types.Datum, tbl *model.TableInfo) error { + is := sctx.GetDomainInfoSchema().(infoschema.InfoSchema) + pt, tableFound := is.TableByID(tbl.ExchangePartitionInfo.ExchangePartitionTableID) + if !tableFound { + return errors.Errorf("exchange partition process table by id failed") + } + p, ok := pt.(table.PartitionedTable) + if !ok { + return errors.Errorf("exchange partition process assert table partition failed") + } + err := p.CheckForExchangePartition( + sctx, + pt.Meta().Partition, + row, + tbl.ExchangePartitionInfo.ExchangePartitionDefID, + tbl.ID, + ) + if err != nil { + return err + } + if variable.EnableCheckConstraint.Load() { + type CheckConstraintTable interface { + CheckRowConstraint(sctx sessionctx.Context, rowToCheck []types.Datum) error + } + cc, ok := pt.(CheckConstraintTable) + if !ok { + return errors.Errorf("exchange partition process assert check constraint failed") + } + err := cc.CheckRowConstraint(sctx, row) + if err != nil { + // TODO: make error include ExchangePartition info. + return err + } + } + return nil +} diff --git a/tests/integrationtest/r/executor/partition/write.result b/tests/integrationtest/r/executor/partition/write.result new file mode 100644 index 0000000000000..97d5330aa2e1c --- /dev/null +++ b/tests/integrationtest/r/executor/partition/write.result @@ -0,0 +1,842 @@ +# TestWriteListPartitionTable2 +# test for write list partition when the partition expression is complicated and contain generated column. +set @@session.tidb_enable_list_partition = ON; +drop table if exists t; +create table t (id int, name varchar(10),b int generated always as (length(name)+1) virtual) +partition by list (id*2 + b*b + b*b - b*b*2 - abs(id)) ( +partition p0 values in (3,5,6,9,17), +partition p1 values in (1,2,10,11,19,20), +partition p2 values in (4,12,13,14,18), +partition p3 values in (7,8,15,16,27,null) +); +analyze table t; +## Test add unique index failed. +insert into t (id,name) values (1, 'a'),(1,'b'); +alter table t add unique index idx (id,b); +Error 1062 (23000): Duplicate entry '1-2' for key 't.idx' +## Test add unique index success. +delete from t where name='b'; +alter table t add unique index idx (id,b); +## --------------------------Test insert--------------------------- +## Test insert 1 partition. +delete from t; +insert into t (id,name) values (1, 'a'),(2,'b'),(10,'c'); +select id,name from t partition(p1) order by id; +id name +1 a +2 b +10 c +## Test insert multi-partitions. +delete from t; +insert into t (id,name) values (1, 'a'),(3,'c'),(4,'e'); +select id,name from t partition(p0) order by id; +id name +3 c +select id,name from t partition(p1) order by id; +id name +1 a +select id,name from t partition(p2) order by id; +id name +4 e +select id,name from t partition(p3) order by id; +id name +## Test insert on duplicate. +insert into t (id,name) values (1, 'd'), (3,'f'),(5,'g') on duplicate key update name='x'; +select id,name from t partition(p0) order by id; +id name +3 x +5 g +select id,name from t partition(p1) order by id; +id name +1 x +select id,name from t partition(p2) order by id; +id name +4 e +select id,name from t partition(p3) order by id; +id name +## Test insert on duplicate error +insert into t (id,name) values (3, 'a'), (11,'x') on duplicate key update id=id+1; +Error 1062 (23000): Duplicate entry '4-2' for key 't.idx' +select id,name from t order by id; +id name +1 x +3 x +4 e +5 g +## Test insert ignore with duplicate +insert ignore into t (id,name) values (1, 'b'), (5,'a'),(null,'y'); +show warnings; +Level Code Message +Warning 1062 Duplicate entry '1-2' for key 't.idx' +Warning 1062 Duplicate entry '5-2' for key 't.idx' +select id,name from t partition(p0) order by id; +id name +3 x +5 g +select id,name from t partition(p1) order by id; +id name +1 x +select id,name from t partition(p2) order by id; +id name +4 e +select id,name from t partition(p3) order by id; +id name +NULL y +## Test insert ignore without duplicate +insert ignore into t (id,name) values (15, 'a'),(17,'a'); +select id,name from t partition(p0,p1,p2) order by id; +id name +1 x +3 x +4 e +5 g +17 a +select id,name from t partition(p3) order by id; +id name +NULL y +15 a +## Test insert meet no partition error. +insert into t (id,name) values (100, 'd'); +Error 1526 (HY000): Table has no partition for value 100 +## --------------------------Test update--------------------------- +## Test update 1 partition. +delete from t; +insert into t (id,name) values (1, 'a'),(2,'b'),(3,'c'); +update t set name='b' where id=2;; +select id,name from t partition(p1); +id name +1 a +2 b +update t set name='x' where id in (1,2); +select id,name from t partition(p1); +id name +1 x +2 x +update t set name='y' where id < 3; +select id,name from t order by id; +id name +1 y +2 y +3 c +## Test update meet duplicate error. +update t set id=2 where id = 1; +Error 1062 (23000): Duplicate entry '2-2' for key 't.idx' +select id,name from t order by id; +id name +1 y +2 y +3 c +## Test update multi-partitions +update t set name='z' where id in (1,2,3);; +select id,name from t order by id; +id name +1 z +2 z +3 z +update t set name='a' limit 3; +select id,name from t order by id; +id name +1 a +2 a +3 a +update t set id=id*10 where id in (1,2); +select id,name from t order by id; +id name +3 a +10 a +20 a +## Test update meet duplicate error. +update t set id=id+17 where id in (3,10); +Error 1062 (23000): Duplicate entry '20-2' for key 't.idx' +select id,name from t order by id; +id name +3 a +10 a +20 a +## Test update meet no partition error. +update t set id=id*2 where id in (3,20); +Error 1526 (HY000): Table has no partition for value 40 +select id,name from t order by id; +id name +3 a +10 a +20 a +## --------------------------Test replace--------------------------- +## Test replace 1 partition. +delete from t; +replace into t (id,name) values (1, 'a'),(2,'b'); +select id,name from t order by id; +id name +1 a +2 b +## Test replace multi-partitions. +replace into t (id,name) values (3, 'c'),(4,'d'),(7,'f'); +select id,name from t partition(p0) order by id; +id name +3 c +select id,name from t partition(p1) order by id; +id name +1 a +2 b +select id,name from t partition(p2) order by id; +id name +4 d +select id,name from t partition(p3) order by id; +id name +7 f +## Test replace on duplicate. +replace into t (id,name) values (1, 'x'),(7,'x'); +select id,name from t order by id; +id name +1 x +2 b +3 c +4 d +7 x +## Test replace meet no partition error. +replace into t (id,name) values (10,'x'),(50,'x'); +Error 1526 (HY000): Table has no partition for value 50 +select id,name from t order by id; +id name +1 x +2 b +3 c +4 d +7 x +## --------------------------Test delete--------------------------- +## Test delete 1 partition. +delete from t where id = 3; +select id,name from t partition(p0) order by id; +id name +delete from t where id in (1,2); +select id,name from t partition(p1) order by id; +id name +## Test delete multi-partitions. +delete from t where id in (4,7,10,11); +select id,name from t; +id name +insert into t (id,name) values (3, 'c'),(4,'d'),(7,'f'); +delete from t where id < 10; +select id,name from t; +id name +insert into t (id,name) values (3, 'c'),(4,'d'),(7,'f'); +delete from t limit 3; +select id,name from t; +id name +set @@session.tidb_enable_list_partition = default; +# TestWriteListColumnsPartitionTable1 +set @@session.tidb_enable_list_partition = ON; +drop table if exists t; +create table t (id int, name varchar(10)) partition by list columns (id) ( +partition p0 values in (3,5,6,9,17), +partition p1 values in (1,2,10,11,19,20), +partition p2 values in (4,12,13,14,18), +partition p3 values in (7,8,15,16,null) +); +analyze table t; +## Test add unique index failed. +insert into t values (1, 'a'),(1,'b'); +alter table t add unique index idx (id); +Error 1062 (23000): Duplicate entry '1' for key 't.idx' +## Test add unique index success. +delete from t where name='b'; +alter table t add unique index idx (id); +## --------------------------Test insert--------------------------- +## Test insert 1 partition. +delete from t; +insert into t values (1, 'a'),(2,'b'),(10,'c'); +select * from t partition(p1) order by id; +id name +1 a +2 b +10 c +## Test insert multi-partitions. +delete from t; +insert into t values (1, 'a'),(3,'c'),(4,'e'); +select * from t partition(p0) order by id; +id name +3 c +select * from t partition(p1) order by id; +id name +1 a +select * from t partition(p2) order by id; +id name +4 e +select * from t partition(p3) order by id; +id name +## Test insert on duplicate. +insert into t values (1, 'd'), (3,'f'),(5,'g') on duplicate key update name='x'; +select * from t partition(p0) order by id; +id name +3 x +5 g +select * from t partition(p1) order by id; +id name +1 x +select * from t partition(p2) order by id; +id name +4 e +select * from t partition(p3) order by id; +id name +## Test insert on duplicate error +insert into t values (3, 'a'), (11,'x') on duplicate key update id=id+1; +Error 1062 (23000): Duplicate entry '4' for key 't.idx' +select * from t order by id; +id name +1 x +3 x +4 e +5 g +## Test insert ignore with duplicate +insert ignore into t values (1, 'b'), (5,'a'),(null,'y'); +show warnings; +Level Code Message +Warning 1062 Duplicate entry '1' for key 't.idx' +Warning 1062 Duplicate entry '5' for key 't.idx' +select * from t partition(p0) order by id; +id name +3 x +5 g +select * from t partition(p1) order by id; +id name +1 x +select * from t partition(p2) order by id; +id name +4 e +select * from t partition(p3) order by id; +id name +NULL y +## Test insert ignore without duplicate +insert ignore into t values (15, 'a'),(17,'a'); +select * from t partition(p0,p1,p2) order by id; +id name +1 x +3 x +4 e +5 g +17 a +select * from t partition(p3) order by id; +id name +NULL y +15 a +## Test insert meet no partition error. +insert into t values (100, 'd'); +Error 1526 (HY000): Table has no partition for value from column_list +## --------------------------Test update--------------------------- +## Test update 1 partition. +delete from t; +insert into t values (1, 'a'),(2,'b'),(3,'c'); +update t set name='b' where id=2;; +select * from t partition(p1); +id name +1 a +2 b +update t set name='x' where id in (1,2); +select * from t partition(p1); +id name +1 x +2 x +update t set name='y' where id < 3; +select * from t order by id; +id name +1 y +2 y +3 c +## Test update meet duplicate error. +update t set id=2 where id = 1; +Error 1062 (23000): Duplicate entry '2' for key 't.idx' +select * from t order by id; +id name +1 y +2 y +3 c +## Test update multi-partitions +update t set name='z' where id in (1,2,3);; +select * from t order by id; +id name +1 z +2 z +3 z +update t set name='a' limit 3; +select * from t order by id; +id name +1 a +2 a +3 a +update t set id=id*10 where id in (1,2); +select * from t order by id; +id name +3 a +10 a +20 a +## Test update meet duplicate error. +update t set id=id+17 where id in (3,10); +Error 1062 (23000): Duplicate entry '20' for key 't.idx' +select * from t order by id; +id name +3 a +10 a +20 a +## Test update meet no partition error. +update t set id=id*2 where id in (3,20); +Error 1526 (HY000): Table has no partition for value from column_list +select * from t order by id; +id name +3 a +10 a +20 a +## --------------------------Test replace--------------------------- +## Test replace 1 partition. +delete from t; +replace into t values (1, 'a'),(2,'b'); +select * from t order by id; +id name +1 a +2 b +## Test replace multi-partitions. +replace into t values (3, 'c'),(4,'d'),(7,'f'); +select * from t partition(p0) order by id; +id name +3 c +select * from t partition(p1) order by id; +id name +1 a +2 b +select * from t partition(p2) order by id; +id name +4 d +select * from t partition(p3) order by id; +id name +7 f +## Test replace on duplicate. +replace into t values (1, 'x'),(7,'x'); +select * from t order by id; +id name +1 x +2 b +3 c +4 d +7 x +## Test replace meet no partition error. +replace into t values (10,'x'),(100,'x'); +Error 1526 (HY000): Table has no partition for value from column_list +select * from t order by id; +id name +1 x +2 b +3 c +4 d +7 x +## --------------------------Test delete--------------------------- +## Test delete 1 partition. +delete from t where id = 3; +select * from t partition(p0) order by id; +id name +delete from t where id in (1,2); +select * from t partition(p1) order by id; +id name +## Test delete multi-partitions. +delete from t where id in (4,7,10,11); +select * from t; +id name +insert into t values (3, 'c'),(4,'d'),(7,'f'); +delete from t where id < 10; +select * from t; +id name +insert into t values (3, 'c'),(4,'d'),(7,'f'); +delete from t limit 3; +select * from t; +id name +set @@session.tidb_enable_list_partition = default; +set tidb_opt_fix_control = "44262:ON"; +drop table if exists replace_test; +create table replace_test (id int PRIMARY KEY AUTO_INCREMENT, c1 int, c2 int, c3 int default 1) +partition by range (id) ( +PARTITION p0 VALUES LESS THAN (3), +PARTITION p1 VALUES LESS THAN (5), +PARTITION p2 VALUES LESS THAN (7), +PARTITION p3 VALUES LESS THAN (9)); +replace replace_test (c1) values (1),(2),(NULL); +affected rows: 3 +info: Records: 3 Duplicates: 0 Warnings: 0 +begin; +replace replace_test (c1) values (); +Error 1136 (21S01): Column count doesn't match value count at row 1 +rollback; +begin; +replace replace_test (c1, c2) values (1,2),(1); +Error 1136 (21S01): Column count doesn't match value count at row 2 +rollback; +begin; +replace replace_test (xxx) values (3); +Error 1054 (42S22): Unknown column 'xxx' in 'field list' +rollback; +begin; +replace replace_test_xxx (c1) values (); +Error 1146 (42S02): Table 'executor__partition__write.replace_test_xxx' doesn't exist +rollback; +replace replace_test set c1 = 3; +affected rows: 1 +info: +begin; +replace replace_test set c1 = 4, c1 = 5; +Error 1110 (42000): Column 'c1' specified twice +rollback; +begin; +replace replace_test set xxx = 6; +Error 1054 (42S22): Unknown column 'xxx' in 'field list' +rollback; +drop table if exists replace_test_1; +create table replace_test_1 (id int, c1 int) partition by range (id) ( +PARTITION p0 VALUES LESS THAN (4), +PARTITION p1 VALUES LESS THAN (6), +PARTITION p2 VALUES LESS THAN (8), +PARTITION p3 VALUES LESS THAN (10), +PARTITION p4 VALUES LESS THAN (100)); +replace replace_test_1 select id, c1 from replace_test; +affected rows: 4 +info: Records: 4 Duplicates: 0 Warnings: 0 +drop table if exists replace_test_2; +create table replace_test_2 (id int, c1 int) partition by range (id) ( +PARTITION p0 VALUES LESS THAN (10), +PARTITION p1 VALUES LESS THAN (50), +PARTITION p2 VALUES LESS THAN (100), +PARTITION p3 VALUES LESS THAN (300)); +replace replace_test_2 select id, c1 from replace_test union select id * 10, c1 * 10 from replace_test; +affected rows: 8 +info: Records: 8 Duplicates: 0 Warnings: 0 +begin; +replace replace_test_2 select c1 from replace_test; +Error 1136 (21S01): Column count doesn't match value count at row 1 +rollback; +drop table if exists replace_test_3; +create table replace_test_3 (c1 int, c2 int, UNIQUE INDEX (c2)) partition by range (c2) ( +PARTITION p0 VALUES LESS THAN (4), +PARTITION p1 VALUES LESS THAN (7), +PARTITION p2 VALUES LESS THAN (11)); +replace into replace_test_3 set c2=8; +affected rows: 1 +info: +replace into replace_test_3 set c2=8; +affected rows: 1 +info: +replace into replace_test_3 set c1=8, c2=8; +affected rows: 2 +info: +replace into replace_test_3 set c2=NULL; +affected rows: 1 +info: +replace into replace_test_3 set c2=NULL; +affected rows: 1 +info: +drop table if exists replace_test_4; +create table replace_test_4 (c1 int, c2 int, c3 int, UNIQUE INDEX (c1, c2)) partition by range (c1) ( +PARTITION p0 VALUES LESS THAN (4), +PARTITION p1 VALUES LESS THAN (7), +PARTITION p2 VALUES LESS THAN (11)); +replace into replace_test_4 set c2=NULL; +affected rows: 1 +info: +replace into replace_test_4 set c2=NULL; +affected rows: 1 +info: +drop table if exists replace_test_5; +create table replace_test_5 (c1 int, c2 int, c3 int, PRIMARY KEY (c1, c2)) partition by range (c2) ( +PARTITION p0 VALUES LESS THAN (4), +PARTITION p1 VALUES LESS THAN (7), +PARTITION p2 VALUES LESS THAN (11)); +replace into replace_test_5 set c1=1, c2=2; +affected rows: 1 +info: +replace into replace_test_5 set c1=1, c2=2; +affected rows: 1 +info: +drop table if exists tIssue989; +CREATE TABLE tIssue989 (a int, b int, KEY(a), UNIQUE KEY(b)) partition by range (b) ( +PARTITION p1 VALUES LESS THAN (100), +PARTITION p2 VALUES LESS THAN (200)); +insert into tIssue989 (a, b) values (1, 2); +affected rows: 1 +info: +replace into tIssue989(a, b) values (111, 2); +affected rows: 2 +info: +select * from tIssue989; +a b +111 2 +set tidb_opt_fix_control = default; +set tidb_opt_fix_control = "44262:ON"; +drop table if exists t; +create table t (id int not null default 1, name varchar(255)) +PARTITION BY RANGE ( id ) ( +PARTITION p0 VALUES LESS THAN (6), +PARTITION p1 VALUES LESS THAN (11), +PARTITION p2 VALUES LESS THAN (16), +PARTITION p3 VALUES LESS THAN (21)); +insert INTO t VALUES (1, "hello"); +insert INTO t VALUES (7, "hello"); +## update non partition column +UPDATE t SET name = "abc" where id > 0; +affected rows: 2 +info: Rows matched: 2 Changed: 2 Warnings: 0 +SELECT * from t order by id limit 2; +id name +1 abc +7 abc +## update partition column +update t set id = id + 1; +affected rows: 2 +info: Rows matched: 2 Changed: 2 Warnings: 0 +SELECT * from t order by id limit 2; +id name +2 abc +8 abc +## update partition column, old and new record locates on different partitions +update t set id = 20 where id = 8; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 +SELECT * from t order by id limit 2; +id name +2 abc +20 abc +## table option is auto-increment +drop table if exists t; +create table t (id int not null auto_increment, name varchar(255), primary key(id)) +PARTITION BY RANGE ( id ) ( +PARTITION p0 VALUES LESS THAN (6), +PARTITION p1 VALUES LESS THAN (11), +PARTITION p2 VALUES LESS THAN (16), +PARTITION p3 VALUES LESS THAN (21)); +insert into t(name) values ('aa'); +update t set id = 8 where name = 'aa'; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 +insert into t(name) values ('bb'); +select * from t; +id name +8 aa +9 bb +update t set id = null where name = 'aa'; +Error 1048 (23000): Column 'id' cannot be null +## Test that in a transaction, when a constraint failed in an update statement, the record is not inserted. +drop table if exists t; +create table t (id int, name int unique) +PARTITION BY RANGE ( name ) ( +PARTITION p0 VALUES LESS THAN (6), +PARTITION p1 VALUES LESS THAN (11), +PARTITION p2 VALUES LESS THAN (16), +PARTITION p3 VALUES LESS THAN (21)); +insert t values (1, 1), (2, 2); +update t set name = 1 where id = 2; +Error 1062 (23000): Duplicate entry '1' for key 't.name' +select * from t; +id name +1 1 +2 2 +## test update ignore for pimary key +drop table if exists t; +create table t(a bigint, primary key (a)) +PARTITION BY RANGE (a) ( +PARTITION p0 VALUES LESS THAN (6), +PARTITION p1 VALUES LESS THAN (11)); +insert into t values (5); +insert into t values (7); +update ignore t set a = 5 where a = 7; +SHOW WARNINGS; +Level Code Message +Warning 1062 Duplicate entry '5' for key 't.PRIMARY' +select * from t order by a; +a +5 +7 +## test update ignore for truncate as warning +update ignore t set a = 1 where a = (select '2a'); +SHOW WARNINGS; +Level Code Message +Warning 1292 Truncated incorrect DOUBLE value: '2a' +Warning 1292 Truncated incorrect DOUBLE value: '2a' +## test update ignore for unique key +drop table if exists t; +create table t(a bigint, unique key I_uniq (a)) +PARTITION BY RANGE (a) ( +PARTITION p0 VALUES LESS THAN (6), +PARTITION p1 VALUES LESS THAN (11)); +insert into t values (5); +insert into t values (7); +update ignore t set a = 5 where a = 7; +affected rows: 0 +info: Rows matched: 1 Changed: 0 Warnings: 1 +SHOW WARNINGS; +Level Code Message +Warning 1062 Duplicate entry '5' for key 't.I_uniq' +select * from t order by a; +a +5 +7 +set tidb_opt_fix_control = default; +drop table if exists t; +set tidb_opt_fix_control = "44262:ON"; +CREATE TABLE t (id int not null default 1, name varchar(255), index(id)) +PARTITION BY RANGE ( id ) ( +PARTITION p0 VALUES LESS THAN (6), +PARTITION p1 VALUES LESS THAN (11), +PARTITION p2 VALUES LESS THAN (16), +PARTITION p3 VALUES LESS THAN (21)); +insert into t values (1, "hello"),(2, "hello"),(3, "hello"),(4, "hello"),(5, "hello"),(6, "hello"),(7, "hello"),(8, "hello"),(9, "hello"),(10, "hello"),(11, "hello"),(12, "hello"),(13, "hello"),(14, "hello"),(15, "hello"),(16, "hello"),(17, "hello"),(18, "hello"),(19, "hello"),(20, "hello"); +delete from t where id = 2 limit 1; +affected rows: 1 +info: +## Test delete with false condition +delete from t where 0; +affected rows: 0 +info: +insert into t values (2, 'abc'); +delete from t where t.id = 2 limit 1; +affected rows: 1 +info: +## Test delete ignore +insert into t values (2, 'abc'); +delete from t where id = (select '2a'); +Error 1292 (22007): Truncated incorrect DOUBLE value: '2a' +delete ignore from t where id = (select '2a'); +affected rows: 1 +info: +SHOW WARNINGS; +Level Code Message +Warning 1292 Truncated incorrect DOUBLE value: '2a' +Warning 1292 Truncated incorrect DOUBLE value: '2a' +## Test delete without using index, involve multiple partitions. +delete from t ignore index(id) where id >= 13 and id <= 17; +affected rows: 5 +info: +admin check table t; +delete from t; +affected rows: 14 +info: +## Fix that partitioned table should not use PointGetPlan. +drop table if exists t1; +create table t1 (c1 bigint, c2 bigint, c3 bigint, primary key(c1)) partition by range (c1) (partition p0 values less than (3440)); +insert into t1 values (379, 379, 379); +delete from t1 where c1 = 379; +affected rows: 1 +info: +drop table t1; +set tidb_opt_fix_control=default; +set @@session.tidb_enable_table_partition = '1'; +drop table if exists replace_test; +create table replace_test (id int PRIMARY KEY AUTO_INCREMENT, c1 int, c2 int, c3 int default 1) +partition by hash(id) partitions 4; +replace replace_test (c1) values (1),(2),(NULL); +begin; +replace replace_test (c1) values (); +Error 1136 (21S01): Column count doesn't match value count at row 1 +rollback; +begin; +replace replace_test (c1, c2) values (1,2),(1); +Error 1136 (21S01): Column count doesn't match value count at row 2 +rollback; +begin; +replace replace_test (xxx) values (3); +Error 1054 (42S22): Unknown column 'xxx' in 'field list' +rollback; +begin; +replace replace_test_xxx (c1) values (); +Error 1146 (42S02): Table 'executor__partition__write.replace_test_xxx' doesn't exist +rollback; +begin; +replace replace_test set c1 = 4, c1 = 5; +Error 1110 (42000): Column 'c1' specified twice +rollback; +begin; +replace replace_test set xxx = 6; +Error 1054 (42S22): Unknown column 'xxx' in 'field list' +rollback; +replace replace_test set c1 = 3; +replace replace_test set c1 = 4; +replace replace_test set c1 = 5; +replace replace_test set c1 = 6; +replace replace_test set c1 = 7; +drop table if exists replace_test_1; +create table replace_test_1 (id int, c1 int) partition by hash(id) partitions 5; +replace replace_test_1 select id, c1 from replace_test; +drop table if exists replace_test_2; +create table replace_test_2 (id int, c1 int) partition by hash(id) partitions 6; +replace replace_test_1 select id, c1 from replace_test union select id * 10, c1 * 10 from replace_test; +begin; +replace replace_test_1 select c1 from replace_test; +Error 1136 (21S01): Column count doesn't match value count at row 1 +rollback; +drop table if exists replace_test_3; +create table replace_test_3 (c1 int, c2 int, UNIQUE INDEX (c2)) partition by hash(c2) partitions 7; +replace into replace_test_3 set c2=8; +replace into replace_test_3 set c2=8; +affected rows: 1 +info: +replace into replace_test_3 set c1=8, c2=8; +affected rows: 2 +info: +replace into replace_test_3 set c2=NULL; +replace into replace_test_3 set c2=NULL; +affected rows: 1 +info: +replace into replace_test_3 set c2=0; +replace into replace_test_3 set c2=1; +replace into replace_test_3 set c2=2; +replace into replace_test_3 set c2=3; +replace into replace_test_3 set c2=4; +replace into replace_test_3 set c2=5; +replace into replace_test_3 set c2=6; +replace into replace_test_3 set c2=7; +replace into replace_test_3 set c2=8; +replace into replace_test_3 set c2=9; +select count(*) from replace_test_3; +count(*) +12 +drop table if exists replace_test_4; +create table replace_test_4 (c1 int, c2 int, c3 int, UNIQUE INDEX (c1, c2)) partition by hash(c1) partitions 8; +replace into replace_test_4 set c2=NULL; +replace into replace_test_4 set c2=NULL; +affected rows: 1 +info: +drop table if exists replace_test_5; +create table replace_test_5 (c1 int, c2 int, c3 int, PRIMARY KEY (c1, c2)) partition by hash (c2) partitions 9; +replace into replace_test_5 set c1=1, c2=2; +replace into replace_test_5 set c1=1, c2=2; +affected rows: 1 +info: +drop table if exists tIssue989; +CREATE TABLE tIssue989 (a int, b int, KEY(a), UNIQUE KEY(b)) partition by hash (b) partitions 10; +insert into tIssue989 (a, b) values (1, 2); +replace into tIssue989(a, b) values (111, 2); +select * from tIssue989; +a b +111 2 +set @@session.tidb_enable_table_partition = default; +drop table if exists insert_update_ignore_test; +create table insert_update_ignore_test (a int) partition by range (a) (partition p0 values less than (100), partition p1 values less than (200)); +insert ignore into insert_update_ignore_test values(1000); +show warnings where Message not like '%disable dynamic pruning%'; +Level Code Message +Warning 1526 Table has no partition for value 1000 +insert ignore into insert_update_ignore_test partition(p0) values(101); +show warnings where Message not like '%disable dynamic pruning%'; +Level Code Message +Warning 1748 Found a row not matching the given partition set +select * from insert_update_ignore_test; +a +insert into insert_update_ignore_test values(1); +update ignore insert_update_ignore_test set a=1000; +show warnings where Message not like '%disable dynamic pruning%'; +Level Code Message +Warning 1526 Table has no partition for value 1000 +select * from insert_update_ignore_test; +a +1 +update ignore insert_update_ignore_test partition(p0) set a=101; +show warnings where Message not like '%disable dynamic pruning%'; +Level Code Message +Warning 1748 Found a row not matching the given partition set +select * from insert_update_ignore_test; +a +1 +drop table insert_update_ignore_test; diff --git a/tests/integrationtest/r/executor/update.result b/tests/integrationtest/r/executor/update.result new file mode 100644 index 0000000000000..547b159443ecd --- /dev/null +++ b/tests/integrationtest/r/executor/update.result @@ -0,0 +1,893 @@ +drop table if exists t; +create table t(a bigint, b bigint as (a+1)); +begin; +insert into t(a) values(1); +update t set b=6 where b=2; +Error 3105 (HY000): The value specified for generated column 'b' in table 't' is not allowed. +commit; +select * from t; +a b +1 2 +drop table if exists t1, t2, t3; +create table t1(id int primary key auto_increment, n int); +create table t2(id int primary key, n float auto_increment, key I_n(n)); +create table t3(id int primary key, n double auto_increment, key I_n(n)); +insert into t1 set n = 1; +select * from t1 where id = 1; +id n +1 1 +update t1 set id = id+1; +select * from t1 where id = 2; +id n +2 1 +insert into t1 set n = 2; +select * from t1 where id = 3; +id n +3 2 +update t1 set id = id + '1.1' where id = 3; +select * from t1 where id = 4; +id n +4 2 +insert into t1 set n = 3; +select * from t1 where id = 5; +id n +5 3 +update t1 set id = id + '0.5' where id = 5; +select * from t1 where id = 6; +id n +6 3 +insert into t1 set n = 4; +select * from t1 where id = 7; +id n +7 4 +insert into t2 set id = 1; +select * from t2 where id = 1; +id n +1 1 +update t2 set n = n+1; +select * from t2 where id = 1; +id n +1 2 +insert into t2 set id = 2; +select * from t2 where id = 2; +id n +2 3 +update t2 set n = n + '2.2'; +select * from t2 where id = 2; +id n +2 5.2 +insert into t2 set id = 3; +select * from t2 where id = 3; +id n +3 6 +update t2 set n = n + '0.5' where id = 3; +select * from t2 where id = 3; +id n +3 6.5 +insert into t2 set id = 4; +select * from t2 where id = 4; +id n +4 7 +insert into t3 set id = 1; +select * from t3 where id = 1; +id n +1 1 +update t3 set n = n+1; +select * from t3 where id = 1; +id n +1 2 +insert into t3 set id = 2; +select * from t3 where id = 2; +id n +2 3 +update t3 set n = n + '3.3'; +select * from t3 where id = 2; +id n +2 6.3 +insert into t3 set id = 3; +select * from t3 where id = 3; +id n +3 7 +update t3 set n = n + '0.5' where id = 3; +select * from t3 where id = 3; +id n +3 7.5 +insert into t3 set id = 4; +select * from t3 where id = 4; +id n +4 8 +drop table if exists t; +drop database if exists test2; +create database test2; +create table t(a int, b int generated always as (a+1) virtual); +create table test2.t(a int, b int generated always as (a+1) virtual); +update t, test2.t set executor__update.t.a=1; +drop database test2; +drop table if exists t1, t2; +create table t1 (c_str varchar(40)); +create table t2 (c_str varchar(40)); +insert into t1 values ('Alice'); +insert into t2 values ('Bob'); +select t1.c_str, t2.c_str from t1, t2 where t1.c_str <= t2.c_str; +c_str c_str +Alice Bob +update t1, t2 set t1.c_str = t2.c_str, t2.c_str = t1.c_str where t1.c_str <= t2.c_str; +select t1.c_str, t2.c_str from t1, t2 where t1.c_str <= t2.c_str; +c_str c_str +drop table if exists t; +create table t (a int, b int); +insert into t values(1, 2); +select * from t; +a b +1 2 +update t set a=b, b=a; +select * from t; +a b +2 1 +drop table if exists t; +create table t (a int, b int); +insert into t values (1,3); +select * from t; +a b +1 3 +update t set a=b, b=a; +select * from t; +a b +3 1 +drop table if exists t; +create table t (a int, b int, c int as (-a) virtual, d int as (-b) stored); +insert into t(a, b) values (10, 11), (20, 22); +select * from t; +a b c d +10 11 -10 -11 +20 22 -20 -22 +update t set a=b, b=a; +select * from t; +a b c d +11 10 -11 -10 +22 20 -22 -20 +update t set b=30, a=b; +select * from t; +a b c d +10 30 -10 -30 +20 30 -20 -30 +drop table if exists t; +create table t(x int, y int); +insert into t values(); +update t t1, t t2 set t2.y=1, t1.x=2; +select * from t; +x y +2 1 +update t t1, t t2 set t1.x=t2.y, t2.y=t1.x; +select * from t; +x y +1 2 +drop table if exists t; +create table t(x int, y int, z int as (x+10) stored, w int as (y-10) virtual); +insert into t(x, y) values(1, 2), (3, 4); +update t t1, t t2 set t2.y=1, t1.x=2 where t1.x=1; +select * from t; +x y z w +2 1 12 -9 +3 1 13 -9 +update t t1, t t2 set t1.x=5, t2.y=t1.x where t1.x=3; +select * from t; +x y z w +2 3 12 -7 +5 3 15 -7 +drop table if exists t; +create table t(a int, b int, c int as (a+b) stored); +insert into t(a, b) values (1, 2); +update t t1, t t2 set t2.a=3; +select * from t; +a b c +3 2 5 +update t t1, t t2 set t1.a=4, t2.b=5; +select * from t; +a b c +4 5 9 +drop table if exists t; +create table t (a int primary key); +insert into t values (1), (2); +update t set a=a+2; +select * from t; +a +3 +4 +update t m, t n set m.a = n.a+10 where m.a=n.a; +select * from t; +a +13 +14 +drop table if exists t; +create table t (a int primary key, b int); +insert into t values (1,3), (2,4); +update t m, t n set m.a = n.a+10, n.b = m.b+1 where m.a=n.a; +Error 1706 (HY000): Primary key/partition key update is not allowed since the table is updated both as 'm' and 'n'. +drop table if exists t; +create table t (a int, b int, c int, primary key(a, b)); +insert into t values (1,3,5), (2,4,6); +update t m, t n set m.a = n.a+10, m.b = n.b+10 where m.a=n.a; +select * from t; +a b c +11 13 5 +12 14 6 +update t m, t n, t q set q.c=m.a+n.b, n.c = m.a+1, m.c = n.b+1 where m.b=n.b AND m.a=q.a; +select * from t; +a b c +11 13 24 +12 14 26 +update t m, t n, t q set m.a = m.a+1, n.c = n.c-1, q.c = q.a+q.b where m.b=n.b and n.b=q.b; +Error 1706 (HY000): Primary key/partition key update is not allowed since the table is updated both as 'm' and 'n'. +set tidb_enable_clustered_index = on; +drop table if exists t; +create table t(id varchar(200) primary key, v int); +insert into t(id, v) values ('abc', 233); +select id, v from t where id = 'abc'; +id v +abc 233 +update t set id = 'dfg' where id = 'abc'; +select * from t; +id v +dfg 233 +update t set id = 'aaa', v = 333 where id = 'dfg'; +select * from t where id = 'aaa'; +id v +aaa 333 +update t set v = 222 where id = 'aaa'; +select * from t where id = 'aaa'; +id v +aaa 222 +insert into t(id, v) values ('bbb', 111); +update t set id = 'bbb' where id = 'aaa'; +Error 1062 (23000): Duplicate entry 'bbb' for key 't.PRIMARY' +drop table if exists ut3pk; +create table ut3pk(id1 varchar(200), id2 varchar(200), v int, id3 int, primary key(id1, id2, id3)); +insert into ut3pk(id1, id2, v, id3) values ('aaa', 'bbb', 233, 111); +select id1, id2, id3, v from ut3pk where id1 = 'aaa' and id2 = 'bbb' and id3 = 111; +id1 id2 id3 v +aaa bbb 111 233 +update ut3pk set id1 = 'abc', id2 = 'bbb2', id3 = 222, v = 555 where id1 = 'aaa' and id2 = 'bbb' and id3 = 111; +select id1, id2, id3, v from ut3pk where id1 = 'abc' and id2 = 'bbb2' and id3 = 222; +id1 id2 id3 v +abc bbb2 222 555 +select id1, id2, id3, v from ut3pk; +id1 id2 id3 v +abc bbb2 222 555 +update ut3pk set v = 666 where id1 = 'abc' and id2 = 'bbb2' and id3 = 222; +select id1, id2, id3, v from ut3pk; +id1 id2 id3 v +abc bbb2 222 666 +insert into ut3pk(id1, id2, id3, v) values ('abc', 'bbb3', 222, 777); +update ut3pk set id2 = 'bbb3' where id1 = 'abc' and id2 = 'bbb2' and id3 = 222; +Error 1062 (23000): Duplicate entry 'abc-bbb3-222' for key 'ut3pk.PRIMARY' +drop table if exists ut1pku; +create table ut1pku(id varchar(200) primary key, uk int, v int, unique key ukk(uk)); +insert into ut1pku(id, uk, v) values('a', 1, 2), ('b', 2, 3); +select * from ut1pku; +id uk v +a 1 2 +b 2 3 +update ut1pku set uk = 3 where id = 'a'; +select * from ut1pku; +id uk v +a 3 2 +b 2 3 +update ut1pku set uk = 2 where id = 'a'; +Error 1062 (23000): Duplicate entry '2' for key 'ut1pku.ukk' +select * from ut1pku; +id uk v +a 3 2 +b 2 3 +drop table if exists t; +create table t(a char(10) primary key, b char(10)); +insert into t values('a', 'b'); +update t set a='c' where t.a='a' and b='b'; +select * from t; +a b +c b +drop table if exists s; +create table s (a int, b int, c int, primary key (a, b)); +insert s values (3, 3, 3), (5, 5, 5); +update s set c = 10 where a = 3; +select * from s; +a b c +3 3 10 +5 5 5 +set tidb_enable_clustered_index = default; +set tidb_enable_clustered_index = on; +drop table if exists t; +create table t(id varchar(200) primary key, v int); +insert into t(id, v) values ('abc', 233); +delete from t where id = 'abc'; +select * from t; +id v +select * from t where id = 'abc'; +id v +drop table if exists it3pk; +create table it3pk(id1 varchar(200), id2 varchar(200), v int, id3 int, primary key(id1, id2, id3)); +insert into it3pk(id1, id2, v, id3) values ('aaa', 'bbb', 233, 111); +delete from it3pk where id1 = 'aaa' and id2 = 'bbb' and id3 = 111; +select * from it3pk; +id1 id2 v id3 +select * from it3pk where id1 = 'aaa' and id2 = 'bbb' and id3 = 111; +id1 id2 v id3 +insert into it3pk(id1, id2, v, id3) values ('aaa', 'bbb', 433, 111); +select * from it3pk where id1 = 'aaa' and id2 = 'bbb' and id3 = 111; +id1 id2 v id3 +aaa bbb 433 111 +drop table if exists dt3pku; +create table dt3pku(id varchar(200) primary key, uk int, v int, unique key uuk(uk)); +insert into dt3pku(id, uk, v) values('a', 1, 2); +delete from dt3pku where id = 'a'; +select * from dt3pku; +id uk v +insert into dt3pku(id, uk, v) values('a', 1, 2); +drop table if exists s1; +create table s1 (a int, b int, c int, primary key (a, b)); +insert s1 values (3, 3, 3), (5, 5, 5); +delete from s1 where a = 3; +select * from s1; +a b c +5 5 5 +set tidb_enable_clustered_index = default; +set tidb_enable_clustered_index = on; +drop table if exists rt1pk; +create table rt1pk(id varchar(200) primary key, v int); +replace into rt1pk(id, v) values('abc', 1); +select * from rt1pk; +id v +abc 1 +replace into rt1pk(id, v) values('bbb', 233), ('abc', 2); +select * from rt1pk; +id v +abc 2 +bbb 233 +drop table if exists rt3pk; +create table rt3pk(id1 timestamp, id2 time, v int, id3 year, primary key(id1, id2, id3)); +replace into rt3pk(id1, id2,id3, v) values('2018-01-01 11:11:11', '22:22:22', '2019', 1); +select * from rt3pk; +id1 id2 v id3 +2018-01-01 11:11:11 22:22:22 1 2019 +replace into rt3pk(id1, id2, id3, v) values('2018-01-01 11:11:11', '22:22:22', '2019', 2); +select * from rt3pk; +id1 id2 v id3 +2018-01-01 11:11:11 22:22:22 2 2019 +drop table if exists rt1pk1u; +create table rt1pk1u(id varchar(200) primary key, uk int, v int, unique key uuk(uk)); +replace into rt1pk1u(id, uk, v) values("abc", 2, 1); +select * from rt1pk1u; +id uk v +abc 2 1 +replace into rt1pk1u(id, uk, v) values("aaa", 2, 11); +select * from rt1pk1u; +id uk v +aaa 2 11 +set tidb_enable_clustered_index = default; +drop table if exists t; +create table t(ts int(10) unsigned NULL DEFAULT NULL); +insert into t values(1); +update t set ts = IF(ts < (0 - ts), 1,1) where ts>0; +Error 1690 (22003): BIGINT UNSIGNED value is out of range in '(0 - executor__update.t.ts)' +drop table if exists tt; +create table tt (m0 varchar(64), status tinyint not null); +insert into tt values('1',0),('1',0),('1',0); +update tt a inner join (select m0 from tt where status!=1 group by m0 having count(*)>1) b on a.m0=b.m0 set a.status=1; +drop table if exists t1; +create table t1(id int, a int unsigned); +set sql_mode=''; +insert into t1 values(1, 10), (2, 20); +update t1 set a='-1' where id=1; +update t1 set a='1000000000000000000' where id=2; +select id, a from t1 order by id asc; +id a +1 0 +2 4294967295 +set sql_mode=default; +drop table if exists t1; +create table t1(id int primary key, name varchar(40)); +insert into t1 values(1, 'abc'); +begin pessimistic; +begin pessimistic; +update t1 set name='xyz' where id=1; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 +select * from t1 where id = 1; +id name +1 xyz +commit; +update t1 set name='xyz' where id=1; +affected rows: 0 +info: Rows matched: 1 Changed: 0 Warnings: 0 +select * from t1 where id = 1; +id name +1 abc +select * from t1 where id = 1 for update; +id name +1 xyz +select * from t1 where id in (1, 2); +id name +1 abc +select * from t1 where id in (1, 2) for update; +id name +1 xyz +commit; +drop table if exists update_test; +create table update_test(id int not null default 1, name varchar(255), PRIMARY KEY(id)); +insert INTO update_test VALUES (1, "hello"); +insert into update_test values (2, "hello"); +UPDATE update_test SET name = "abc" where id > 0; +affected rows: 2 +info: Rows matched: 2 Changed: 2 Warnings: 0 +begin; +SELECT * from update_test limit 2; +id name +1 abc +2 abc +commit; +UPDATE update_test SET name = "foo"; +affected rows: 2 +info: Rows matched: 2 Changed: 2 Warnings: 0 +begin; +drop table if exists update_test; +commit; +begin; +create table update_test(id int not null auto_increment, name varchar(255), primary key(id)); +insert into update_test(name) values ('aa'); +update update_test set id = 8 where name = 'aa'; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 +insert into update_test(name) values ('bb'); +commit; +begin; +select * from update_test; +id name +8 aa +9 bb +commit; +begin; +drop table if exists update_test; +commit; +begin; +create table update_test(id int not null auto_increment, name varchar(255), index(id)); +insert into update_test(name) values ('aa'); +update update_test set id = null where name = 'aa'; +Error 1048 (23000): Column 'id' cannot be null +drop table update_test; +create table update_test(id int); +begin; +insert into update_test(id) values (1); +update update_test set id = 2 where id = 1 limit 1; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 +select * from update_test; +id +2 +commit; +drop table if exists update_unique; +create table update_unique (id int primary key, name int unique); +insert update_unique values (1, 1), (2, 2); +begin; +update update_unique set name = 1 where id = 2; +Error 1062 (23000): Duplicate entry '1' for key 'update_unique.name' +commit; +select * from update_unique; +id name +1 1 +2 2 +drop table if exists t; +create table t(a bigint, primary key (a)); +insert into t values (1); +insert into t values (2); +update ignore t set a = 1 where a = 2; +affected rows: 0 +info: Rows matched: 1 Changed: 0 Warnings: 1 +SHOW WARNINGS; +Level Code Message +Warning 1062 Duplicate entry '1' for key 't.PRIMARY' +select * from t; +a +1 +2 +update ignore t set a = 1 where a = (select '2a'); +SHOW WARNINGS; +Level Code Message +Warning 1292 Truncated incorrect DOUBLE value: '2a' +Warning 1292 Truncated incorrect DOUBLE value: '2a' +Warning 1062 Duplicate entry '1' for key 't.PRIMARY' +update ignore t set a = 42 where a = 2; +select * from t; +a +1 +42 +drop table if exists t; +create table t(a bigint, unique key I_uniq (a)); +insert into t values (1); +insert into t values (2); +update ignore t set a = 1 where a = 2; +affected rows: 0 +info: Rows matched: 1 Changed: 0 Warnings: 1 +SHOW WARNINGS; +Level Code Message +Warning 1062 Duplicate entry '1' for key 't.I_uniq' +select * from t; +a +1 +2 +drop table if exists t; +set @@session.tidb_enable_list_partition = ON; +create table t (a int) partition by list (a) (partition p0 values in (0,1)); +analyze table t; +insert ignore into t values (1); +update ignore t set a=2 where a=1; +affected rows: 0 +info: Rows matched: 1 Changed: 0 Warnings: 1 +drop table if exists t; +create table t (a int key) partition by list (a) (partition p0 values in (0,1)); +insert ignore into t values (1); +update ignore t set a=2 where a=1; +affected rows: 0 +info: Rows matched: 1 Changed: 0 Warnings: 1 +set @@session.tidb_enable_list_partition = default; +drop table if exists t; +create table t(id integer auto_increment, t1 datetime, t2 datetime, primary key (id)); +insert into t(t1, t2) values('2000-10-01 01:01:01', '2017-01-01 10:10:10'); +select * from t; +id t1 t2 +1 2000-10-01 01:01:01 2017-01-01 10:10:10 +update t set t1 = '2017-10-01 10:10:11', t2 = date_add(t1, INTERVAL 10 MINUTE) where id = 1; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 +select * from t; +id t1 t2 +1 2017-10-01 10:10:11 2000-10-01 01:11:01 +drop table if exists tt1; +CREATE TABLE `tt1` (`a` int(11) NOT NULL,`b` varchar(32) DEFAULT NULL,`c` varchar(32) DEFAULT NULL,PRIMARY KEY (`a`),UNIQUE KEY `b_idx` (`b`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin; +insert into tt1 values(1, 'a', 'a'); +insert into tt1 values(2, 'd', 'b'); +select * from tt1; +a b c +1 a a +2 d b +update tt1 set a=5 where c='b'; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 +select * from tt1; +a b c +1 a a +5 d b +drop table if exists tsup; +CREATE TABLE `tsup` (`a` int,`ts` TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,KEY `idx` (`ts`)); +set @@sql_mode=''; +insert into tsup values(1, '0000-00-00 00:00:00'); +update tsup set a=5; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 +select t1.ts = t2.ts from (select ts from tsup use index (idx)) as t1, (select ts from tsup use index ()) as t2; +t1.ts = t2.ts +1 +update tsup set ts='2019-01-01'; +select ts from tsup; +ts +2019-01-01 00:00:00 +set @@sql_mode=default; +drop table if exists decimals; +create table decimals (a decimal(20, 0) not null); +insert into decimals values (201); +update decimals set a = a + 1.23; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 1 +show warnings; +Level Code Message +Warning 1292 Truncated incorrect DECIMAL value: '202.23' +select * from decimals; +a +202 +drop table t; +CREATE TABLE `t` ( `c1` year DEFAULT NULL, `c2` year DEFAULT NULL, `c3` date DEFAULT NULL, `c4` datetime DEFAULT NULL, KEY `idx` (`c1`,`c2`)); +UPDATE t SET c2=16777215 WHERE c1>= -8388608 AND c1 < -9 ORDER BY c1 LIMIT 2; +update (select * from t) t set c1 = 1111111; +Error 1288 (HY000): The target table t of the UPDATE is not updatable +drop table if exists t; +create table t (i int not null default 10); +insert into t values (1); +update ignore t set i = null; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 1 +SHOW WARNINGS; +Level Code Message +Warning 1048 Column 'i' cannot be null +select * from t; +i +0 +drop table t; +create table t (k int, v int); +update t, (select * from t) as b set b.k = t.k; +Error 1288 (HY000): The target table b of the UPDATE is not updatable +update t, (select * from t) as b set t.k = b.k; +drop table if exists t1; +CREATE TABLE t1 (c1 float); +INSERT INTO t1 SET c1 = 1; +UPDATE t1 SET c1 = 1.2 WHERE c1=1; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 +drop table if exists t; +create table t (c1 float(1,1)); +insert into t values (0.0); +update t set c1 = 2.0; +Error 1264 (22003): Out of range value for column 'c1' at row 1 +drop table if exists t; +create table t(a datetime not null, b datetime); +insert into t value('1999-12-12', '1999-12-13'); +set @@sql_mode=''; +select * from t; +a b +1999-12-12 00:00:00 1999-12-13 00:00:00 +update t set a = ''; +select * from t; +a b +0000-00-00 00:00:00 1999-12-13 00:00:00 +update t set b = ''; +select * from t; +a b +0000-00-00 00:00:00 0000-00-00 00:00:00 +set @@sql_mode=default; +drop view if exists v; +create view v as select * from t; +update v set a = '2000-11-11'; +Error 1288 (HY000): The target table v of the UPDATE is not updatable +drop view v; +drop sequence if exists seq; +create sequence seq; +update seq set minvalue=1; +Error 1054 (42S22): Unknown column 'minvalue' in 'field list' +drop sequence seq; +drop table if exists t1, t2; +create table t1(a int, b int, c int, d int, e int, index idx(a)); +create table t2(a int, b int, c int); +update t1 join t2 on t1.a=t2.a set t1.a=1 where t2.b=1 and t2.c=2; +drop table if exists t1, t2; +create table t1 (a int default 1, b int default 2); +insert into t1 values (10, 10), (20, 20); +update t1 set a=default where b=10; +select * from t1; +a b +1 10 +20 20 +update t1 set a=30, b=default where a=20; +select * from t1; +a b +1 10 +30 2 +update t1 set a=default, b=default where a=30; +select * from t1; +a b +1 10 +1 2 +insert into t1 values (40, 40); +update t1 set a=default, b=default; +select * from t1; +a b +1 2 +1 2 +1 2 +update t1 set a=default(b), b=default(a); +select * from t1; +a b +2 1 +2 1 +2 1 +create table t2 (a int default 1, b int generated always as (-a) virtual, c int generated always as (-a) stored); +insert into t2 values (10, default, default), (20, default, default); +update t2 set b=default; +select * from t2; +a b c +10 -10 -10 +20 -20 -20 +update t2 set a=30, b=default where a=10; +select * from t2; +a b c +30 -30 -30 +20 -20 -20 +update t2 set c=default, a=40 where c=-20; +select * from t2; +a b c +30 -30 -30 +40 -40 -40 +update t2 set a=default, b=default, c=default where b=-30; +select * from t2; +a b c +1 -1 -1 +40 -40 -40 +update t2 set a=default(a), b=default, c=default; +select * from t2; +a b c +1 -1 -1 +1 -1 -1 +update t2 set a=default(b), b=default, c=default; +select * from t2; +a b c +NULL NULL NULL +NULL NULL NULL +update t2 set b=default(a); +Error 3105 (HY000): The value specified for generated column 'b' in table 't2' is not allowed. +update t2 set a=default(a), c=default(c); +select * from t2; +a b c +1 -1 -1 +1 -1 -1 +update t2 set a=default(b), b=default(b); +select * from t2; +a b c +NULL NULL NULL +NULL NULL NULL +update t2 set a=default(a), c=default(c); +select * from t2; +a b c +1 -1 -1 +1 -1 -1 +update t2 set a=default(a), c=default(a); +Error 3105 (HY000): The value specified for generated column 'c' in table 't2' is not allowed. +drop table t1, t2; +drop table if exists msg, detail; +create table msg (id varchar(8), b int, status int, primary key (id, b)); +insert msg values ('abc', 1, 1); +create table detail (id varchar(8), start varchar(8), status int, index idx_start(start)); +insert detail values ('abc', '123', 2); +UPDATE msg SET msg.status = (SELECT detail.status FROM detail WHERE msg.id = detail.id); +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 +admin check table msg; +drop table if exists ttt; +CREATE TABLE ttt (id bigint(20) NOT NULL, host varchar(30) NOT NULL, PRIMARY KEY (id), UNIQUE KEY i_host (host)); +insert into ttt values (8,8),(9,9); +begin; +update ttt set id = 0, host='9' where id = 9 limit 1; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 +delete from ttt where id = 0 limit 1; +select * from ttt use index (i_host) order by host; +id host +8 8 +update ttt set id = 0, host='8' where id = 8 limit 1; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 +delete from ttt where id = 0 limit 1; +select * from ttt use index (i_host) order by host; +id host +commit; +admin check table ttt; +drop table ttt; +drop table if exists a; +create table a(id int auto_increment, a int default null, primary key(id)); +insert into a values (1, 1001), (2, 1001), (10001, 1), (3, 1); +update a set id = id*10 where a = 1001; +affected rows: 2 +info: Rows matched: 2 Changed: 2 Warnings: 0 +drop table a; +create table a ( a bigint, b bigint); +insert into a values (1, 1001), (2, 1001), (10001, 1), (3, 1); +update a set a = a*10 where b = 1001; +affected rows: 2 +info: Rows matched: 2 Changed: 2 Warnings: 0 +drop table if exists items, month; +CREATE TABLE items (id int, price TEXT); +insert into items values (11, "items_price_11"), (12, "items_price_12"), (13, "items_price_13"); +affected rows: 3 +info: Records: 3 Duplicates: 0 Warnings: 0 +CREATE TABLE month (mid int, mprice TEXT); +insert into month values (11, "month_price_11"), (22, "month_price_22"), (13, "month_price_13"); +affected rows: 3 +info: Records: 3 Duplicates: 0 Warnings: 0 +UPDATE items, month SET items.price=month.mprice WHERE items.id=month.mid; +affected rows: 2 +info: Rows matched: 2 Changed: 2 Warnings: 0 +begin; +SELECT * FROM items; +id price +11 month_price_11 +12 items_price_12 +13 month_price_13 +commit; +UPDATE items join month on items.id=month.mid SET items.price=month.mid; +affected rows: 2 +info: Rows matched: 2 Changed: 2 Warnings: 0 +begin; +SELECT * FROM items; +id price +11 11 +12 items_price_12 +13 13 +commit; +UPDATE items T0 join month T1 on T0.id=T1.mid SET T0.price=T1.mprice; +affected rows: 2 +info: Rows matched: 2 Changed: 2 Warnings: 0 +begin; +SELECT * FROM items; +id price +11 month_price_11 +12 items_price_12 +13 month_price_13 +commit; +DROP TABLE IF EXISTS t1, t2; +create table t1 (c int); +create table t2 (c varchar(256)); +insert into t1 values (1), (2); +insert into t2 values ("a"), ("b"); +update t1, t2 set t1.c = 10, t2.c = "abc"; +affected rows: 4 +info: Rows matched: 4 Changed: 4 Warnings: 0 +DROP TABLE IF EXISTS t1, t2; +create table t1 (c1 int); +create table t2 (c2 int); +insert into t1 values (1), (2); +insert into t2 values (1), (2); +update t1, t2 set t1.c1 = 10, t2.c2 = 2 where t2.c2 = 1; +affected rows: 3 +info: Rows matched: 3 Changed: 3 Warnings: 0 +select * from t1; +c1 +10 +10 +drop table if exists t; +create table t (a int, b int); +insert into t values(1, 1), (2, 2), (3, 3); +affected rows: 3 +info: Records: 3 Duplicates: 0 Warnings: 0 +update t m, t n set m.a = m.a + 1; +affected rows: 3 +info: Rows matched: 3 Changed: 3 Warnings: 0 +select * from t; +a b +2 1 +3 2 +4 3 +update t m, t n set n.a = n.a - 1, n.b = n.b + 1; +affected rows: 3 +info: Rows matched: 3 Changed: 3 Warnings: 0 +select * from t; +a b +1 2 +2 3 +3 4 +drop table if exists update_modified; +create table update_modified (col_1 int, col_2 enum('a', 'b')); +set SQL_MODE=''; +insert into update_modified values (0, 3); +SELECT * FROM update_modified; +col_1 col_2 +0 +set SQL_MODE=STRICT_ALL_TABLES; +update update_modified set col_1 = 1; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 +SELECT * FROM update_modified; +col_1 col_2 +1 +update update_modified set col_1 = 2, col_2 = 'c'; +Error 1265 (01000): Data truncated for column '%s' at row %d +SELECT * FROM update_modified; +col_1 col_2 +1 +update update_modified set col_1 = 3, col_2 = 'a'; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 +SELECT * FROM update_modified; +col_1 col_2 +3 a +drop table if exists update_with_diff_type; +CREATE TABLE update_with_diff_type (a int, b JSON); +INSERT INTO update_with_diff_type VALUES(3, '{"a": "测试"}'); +UPDATE update_with_diff_type SET a = '300'; +affected rows: 1 +info: Rows matched: 1 Changed: 1 Warnings: 0 +SELECT a FROM update_with_diff_type; +a +300 +UPDATE update_with_diff_type SET b = '{"a": "\\u6d4b\\u8bd5"}'; +affected rows: 0 +info: Rows matched: 1 Changed: 0 Warnings: 0 +SELECT b FROM update_with_diff_type; +b +{"a": "测试"} +set SQL_MODE=default; diff --git a/tests/integrationtest/t/executor/partition/write.test b/tests/integrationtest/t/executor/partition/write.test new file mode 100644 index 0000000000000..79feccc409042 --- /dev/null +++ b/tests/integrationtest/t/executor/partition/write.test @@ -0,0 +1,621 @@ +--echo # TestWriteListPartitionTable2 +--echo # test for write list partition when the partition expression is complicated and contain generated column. +set @@session.tidb_enable_list_partition = ON; +drop table if exists t; +create table t (id int, name varchar(10),b int generated always as (length(name)+1) virtual) + partition by list (id*2 + b*b + b*b - b*b*2 - abs(id)) ( + partition p0 values in (3,5,6,9,17), + partition p1 values in (1,2,10,11,19,20), + partition p2 values in (4,12,13,14,18), + partition p3 values in (7,8,15,16,27,null) +); + +analyze table t; + +--echo ## Test add unique index failed. +insert into t (id,name) values (1, 'a'),(1,'b'); +--error 1062 +alter table t add unique index idx (id,b); +--echo ## Test add unique index success. +delete from t where name='b'; +alter table t add unique index idx (id,b); + +--echo ## --------------------------Test insert--------------------------- +--echo ## Test insert 1 partition. +delete from t; +insert into t (id,name) values (1, 'a'),(2,'b'),(10,'c'); +select id,name from t partition(p1) order by id; +--echo ## Test insert multi-partitions. +delete from t; +insert into t (id,name) values (1, 'a'),(3,'c'),(4,'e'); +select id,name from t partition(p0) order by id; +select id,name from t partition(p1) order by id; +select id,name from t partition(p2) order by id; +select id,name from t partition(p3) order by id; +--echo ## Test insert on duplicate. +insert into t (id,name) values (1, 'd'), (3,'f'),(5,'g') on duplicate key update name='x'; +select id,name from t partition(p0) order by id; +select id,name from t partition(p1) order by id; +select id,name from t partition(p2) order by id; +select id,name from t partition(p3) order by id; +--echo ## Test insert on duplicate error +--error 1062 +insert into t (id,name) values (3, 'a'), (11,'x') on duplicate key update id=id+1; +select id,name from t order by id; +--echo ## Test insert ignore with duplicate +insert ignore into t (id,name) values (1, 'b'), (5,'a'),(null,'y'); +show warnings; +select id,name from t partition(p0) order by id; +select id,name from t partition(p1) order by id; +select id,name from t partition(p2) order by id; +select id,name from t partition(p3) order by id; +--echo ## Test insert ignore without duplicate +insert ignore into t (id,name) values (15, 'a'),(17,'a'); +select id,name from t partition(p0,p1,p2) order by id; +select id,name from t partition(p3) order by id; +--echo ## Test insert meet no partition error. +--error 1526 +insert into t (id,name) values (100, 'd'); + +--echo ## --------------------------Test update--------------------------- +--echo ## Test update 1 partition. +delete from t; +insert into t (id,name) values (1, 'a'),(2,'b'),(3,'c'); +update t set name='b' where id=2;; +select id,name from t partition(p1); +update t set name='x' where id in (1,2); +select id,name from t partition(p1); +update t set name='y' where id < 3; +select id,name from t order by id; +--echo ## Test update meet duplicate error. +--error 1062 +update t set id=2 where id = 1; +select id,name from t order by id; + +--echo ## Test update multi-partitions +update t set name='z' where id in (1,2,3);; +select id,name from t order by id; +update t set name='a' limit 3; +select id,name from t order by id; +update t set id=id*10 where id in (1,2); +select id,name from t order by id; +--echo ## Test update meet duplicate error. +--error 1062 +update t set id=id+17 where id in (3,10); +select id,name from t order by id; +--echo ## Test update meet no partition error. +--error 1526 +update t set id=id*2 where id in (3,20); +select id,name from t order by id; + +--echo ## --------------------------Test replace--------------------------- +--echo ## Test replace 1 partition. +delete from t; +replace into t (id,name) values (1, 'a'),(2,'b'); +select id,name from t order by id; +--echo ## Test replace multi-partitions. +replace into t (id,name) values (3, 'c'),(4,'d'),(7,'f'); +select id,name from t partition(p0) order by id; +select id,name from t partition(p1) order by id; +select id,name from t partition(p2) order by id; +select id,name from t partition(p3) order by id; +--echo ## Test replace on duplicate. +replace into t (id,name) values (1, 'x'),(7,'x'); +select id,name from t order by id; +--echo ## Test replace meet no partition error. +--error 1526 +replace into t (id,name) values (10,'x'),(50,'x'); +select id,name from t order by id; + +--echo ## --------------------------Test delete--------------------------- +--echo ## Test delete 1 partition. +delete from t where id = 3; +select id,name from t partition(p0) order by id; +delete from t where id in (1,2); +select id,name from t partition(p1) order by id; +--echo ## Test delete multi-partitions. +delete from t where id in (4,7,10,11); +select id,name from t; +insert into t (id,name) values (3, 'c'),(4,'d'),(7,'f'); +delete from t where id < 10; +select id,name from t; +insert into t (id,name) values (3, 'c'),(4,'d'),(7,'f'); +delete from t limit 3; +select id,name from t; +set @@session.tidb_enable_list_partition = default; + +--echo # TestWriteListColumnsPartitionTable1 +set @@session.tidb_enable_list_partition = ON; + +drop table if exists t; +create table t (id int, name varchar(10)) partition by list columns (id) ( + partition p0 values in (3,5,6,9,17), + partition p1 values in (1,2,10,11,19,20), + partition p2 values in (4,12,13,14,18), + partition p3 values in (7,8,15,16,null) +); + +analyze table t; + +--echo ## Test add unique index failed. +insert into t values (1, 'a'),(1,'b'); +--error 1062 +alter table t add unique index idx (id); +--echo ## Test add unique index success. +delete from t where name='b'; +alter table t add unique index idx (id); + +--echo ## --------------------------Test insert--------------------------- +--echo ## Test insert 1 partition. +delete from t; +insert into t values (1, 'a'),(2,'b'),(10,'c'); +select * from t partition(p1) order by id; +--echo ## Test insert multi-partitions. +delete from t; +insert into t values (1, 'a'),(3,'c'),(4,'e'); +select * from t partition(p0) order by id; +select * from t partition(p1) order by id; +select * from t partition(p2) order by id; +select * from t partition(p3) order by id; +--echo ## Test insert on duplicate. +insert into t values (1, 'd'), (3,'f'),(5,'g') on duplicate key update name='x'; +select * from t partition(p0) order by id; +select * from t partition(p1) order by id; +select * from t partition(p2) order by id; +select * from t partition(p3) order by id; +--echo ## Test insert on duplicate error +--error 1062 +insert into t values (3, 'a'), (11,'x') on duplicate key update id=id+1; +select * from t order by id; +--echo ## Test insert ignore with duplicate +insert ignore into t values (1, 'b'), (5,'a'),(null,'y'); +show warnings; +select * from t partition(p0) order by id; +select * from t partition(p1) order by id; +select * from t partition(p2) order by id; +select * from t partition(p3) order by id; +--echo ## Test insert ignore without duplicate +insert ignore into t values (15, 'a'),(17,'a'); +select * from t partition(p0,p1,p2) order by id; +select * from t partition(p3) order by id; +--echo ## Test insert meet no partition error. +--error 1526 +insert into t values (100, 'd'); + +--echo ## --------------------------Test update--------------------------- +--echo ## Test update 1 partition. +delete from t; +insert into t values (1, 'a'),(2,'b'),(3,'c'); +update t set name='b' where id=2;; +select * from t partition(p1); +update t set name='x' where id in (1,2); +select * from t partition(p1); +update t set name='y' where id < 3; +select * from t order by id; +--echo ## Test update meet duplicate error. +--error 1062 +update t set id=2 where id = 1; +select * from t order by id; + +--echo ## Test update multi-partitions +update t set name='z' where id in (1,2,3);; +select * from t order by id; +update t set name='a' limit 3; +select * from t order by id; +update t set id=id*10 where id in (1,2); +select * from t order by id; +--echo ## Test update meet duplicate error. +--error 1062 +update t set id=id+17 where id in (3,10); +select * from t order by id; +--echo ## Test update meet no partition error. +--error 1526 +update t set id=id*2 where id in (3,20); +select * from t order by id; + +--echo ## --------------------------Test replace--------------------------- +--echo ## Test replace 1 partition. +delete from t; +replace into t values (1, 'a'),(2,'b'); +select * from t order by id; +--echo ## Test replace multi-partitions. +replace into t values (3, 'c'),(4,'d'),(7,'f'); +select * from t partition(p0) order by id; +select * from t partition(p1) order by id; +select * from t partition(p2) order by id; +select * from t partition(p3) order by id; +--echo ## Test replace on duplicate. +replace into t values (1, 'x'),(7,'x'); +select * from t order by id; +--echo ## Test replace meet no partition error. +--error 1526 +replace into t values (10,'x'),(100,'x'); +select * from t order by id; + +--echo ## --------------------------Test delete--------------------------- +--echo ## Test delete 1 partition. +delete from t where id = 3; +select * from t partition(p0) order by id; +delete from t where id in (1,2); +select * from t partition(p1) order by id; +--echo ## Test delete multi-partitions. +delete from t where id in (4,7,10,11); +select * from t; +insert into t values (3, 'c'),(4,'d'),(7,'f'); +delete from t where id < 10; +select * from t; +insert into t values (3, 'c'),(4,'d'),(7,'f'); +delete from t limit 3; +select * from t; + +set @@session.tidb_enable_list_partition = default; + + +# TestPartitionedTableReplace +set tidb_opt_fix_control = "44262:ON"; +drop table if exists replace_test; +create table replace_test (id int PRIMARY KEY AUTO_INCREMENT, c1 int, c2 int, c3 int default 1) + partition by range (id) ( + PARTITION p0 VALUES LESS THAN (3), + PARTITION p1 VALUES LESS THAN (5), + PARTITION p2 VALUES LESS THAN (7), + PARTITION p3 VALUES LESS THAN (9)); +--enable_info +replace replace_test (c1) values (1),(2),(NULL); +--disable_info +begin; +-- error 1136 +replace replace_test (c1) values (); +rollback; +begin; +-- error 1136 +replace replace_test (c1, c2) values (1,2),(1); +rollback; +begin; +-- error 1054 +replace replace_test (xxx) values (3); +rollback; +begin; +-- error 1146 +replace replace_test_xxx (c1) values (); +rollback; +--enable_info +replace replace_test set c1 = 3; +--disable_info +begin; +-- error 1110 +replace replace_test set c1 = 4, c1 = 5; +rollback; +begin; +-- error 1054 +replace replace_test set xxx = 6; +rollback; + +drop table if exists replace_test_1; +create table replace_test_1 (id int, c1 int) partition by range (id) ( + PARTITION p0 VALUES LESS THAN (4), + PARTITION p1 VALUES LESS THAN (6), + PARTITION p2 VALUES LESS THAN (8), + PARTITION p3 VALUES LESS THAN (10), + PARTITION p4 VALUES LESS THAN (100)); +--enable_info +replace replace_test_1 select id, c1 from replace_test; +--disable_info + +drop table if exists replace_test_2; +create table replace_test_2 (id int, c1 int) partition by range (id) ( + PARTITION p0 VALUES LESS THAN (10), + PARTITION p1 VALUES LESS THAN (50), + PARTITION p2 VALUES LESS THAN (100), + PARTITION p3 VALUES LESS THAN (300)); +--enable_info +replace replace_test_2 select id, c1 from replace_test union select id * 10, c1 * 10 from replace_test; +--disable_info +begin; +-- error 1136 +replace replace_test_2 select c1 from replace_test; +rollback; + +drop table if exists replace_test_3; +create table replace_test_3 (c1 int, c2 int, UNIQUE INDEX (c2)) partition by range (c2) ( + PARTITION p0 VALUES LESS THAN (4), + PARTITION p1 VALUES LESS THAN (7), + PARTITION p2 VALUES LESS THAN (11)); +--enable_info +replace into replace_test_3 set c2=8; +replace into replace_test_3 set c2=8; +replace into replace_test_3 set c1=8, c2=8; +replace into replace_test_3 set c2=NULL; +replace into replace_test_3 set c2=NULL; +--disable_info + +drop table if exists replace_test_4; +create table replace_test_4 (c1 int, c2 int, c3 int, UNIQUE INDEX (c1, c2)) partition by range (c1) ( + PARTITION p0 VALUES LESS THAN (4), + PARTITION p1 VALUES LESS THAN (7), + PARTITION p2 VALUES LESS THAN (11)); +--enable_info +replace into replace_test_4 set c2=NULL; +replace into replace_test_4 set c2=NULL; +--disable_info + +drop table if exists replace_test_5; +create table replace_test_5 (c1 int, c2 int, c3 int, PRIMARY KEY (c1, c2)) partition by range (c2) ( + PARTITION p0 VALUES LESS THAN (4), + PARTITION p1 VALUES LESS THAN (7), + PARTITION p2 VALUES LESS THAN (11)); +--enable_info +replace into replace_test_5 set c1=1, c2=2; +replace into replace_test_5 set c1=1, c2=2; +--disable_info + +drop table if exists tIssue989; +CREATE TABLE tIssue989 (a int, b int, KEY(a), UNIQUE KEY(b)) partition by range (b) ( + PARTITION p1 VALUES LESS THAN (100), + PARTITION p2 VALUES LESS THAN (200)); +--enable_info +insert into tIssue989 (a, b) values (1, 2); +replace into tIssue989(a, b) values (111, 2); +--disable_info +select * from tIssue989; + +set tidb_opt_fix_control = default; + + +# TestPartitionedTableUpdate +set tidb_opt_fix_control = "44262:ON"; +drop table if exists t; +create table t (id int not null default 1, name varchar(255)) + PARTITION BY RANGE ( id ) ( + PARTITION p0 VALUES LESS THAN (6), + PARTITION p1 VALUES LESS THAN (11), + PARTITION p2 VALUES LESS THAN (16), + PARTITION p3 VALUES LESS THAN (21)); +insert INTO t VALUES (1, "hello"); +insert INTO t VALUES (7, "hello"); + +--echo ## update non partition column +--enable_info +UPDATE t SET name = "abc" where id > 0; +--disable_info +SELECT * from t order by id limit 2; + +--echo ## update partition column +--enable_info +update t set id = id + 1; +--disable_info +SELECT * from t order by id limit 2; + +--echo ## update partition column, old and new record locates on different partitions +--enable_info +update t set id = 20 where id = 8; +--disable_info +SELECT * from t order by id limit 2; + +--echo ## table option is auto-increment +drop table if exists t; +create table t (id int not null auto_increment, name varchar(255), primary key(id)) + PARTITION BY RANGE ( id ) ( + PARTITION p0 VALUES LESS THAN (6), + PARTITION p1 VALUES LESS THAN (11), + PARTITION p2 VALUES LESS THAN (16), + PARTITION p3 VALUES LESS THAN (21)); +insert into t(name) values ('aa'); +--enable_info +update t set id = 8 where name = 'aa'; +--disable_info +insert into t(name) values ('bb'); +select * from t; +-- error 1048 +update t set id = null where name = 'aa'; + +--echo ## Test that in a transaction, when a constraint failed in an update statement, the record is not inserted. +drop table if exists t; +create table t (id int, name int unique) + PARTITION BY RANGE ( name ) ( + PARTITION p0 VALUES LESS THAN (6), + PARTITION p1 VALUES LESS THAN (11), + PARTITION p2 VALUES LESS THAN (16), + PARTITION p3 VALUES LESS THAN (21)); +insert t values (1, 1), (2, 2); +-- error 1062 +update t set name = 1 where id = 2; +select * from t; + +--echo ## test update ignore for pimary key +drop table if exists t; +create table t(a bigint, primary key (a)) + PARTITION BY RANGE (a) ( + PARTITION p0 VALUES LESS THAN (6), + PARTITION p1 VALUES LESS THAN (11)); +insert into t values (5); +insert into t values (7); +update ignore t set a = 5 where a = 7; +SHOW WARNINGS; +select * from t order by a; + +--echo ## test update ignore for truncate as warning +update ignore t set a = 1 where a = (select '2a'); +SHOW WARNINGS; + +--echo ## test update ignore for unique key +drop table if exists t; +create table t(a bigint, unique key I_uniq (a)) + PARTITION BY RANGE (a) ( + PARTITION p0 VALUES LESS THAN (6), + PARTITION p1 VALUES LESS THAN (11)); +insert into t values (5); +insert into t values (7); +--enable_info +update ignore t set a = 5 where a = 7; +--disable_info +SHOW WARNINGS; +select * from t order by a; +set tidb_opt_fix_control = default; + + +# TestPartitionedTableDelete +drop table if exists t; +set tidb_opt_fix_control = "44262:ON"; +CREATE TABLE t (id int not null default 1, name varchar(255), index(id)) + PARTITION BY RANGE ( id ) ( + PARTITION p0 VALUES LESS THAN (6), + PARTITION p1 VALUES LESS THAN (11), + PARTITION p2 VALUES LESS THAN (16), + PARTITION p3 VALUES LESS THAN (21)); +insert into t values (1, "hello"),(2, "hello"),(3, "hello"),(4, "hello"),(5, "hello"),(6, "hello"),(7, "hello"),(8, "hello"),(9, "hello"),(10, "hello"),(11, "hello"),(12, "hello"),(13, "hello"),(14, "hello"),(15, "hello"),(16, "hello"),(17, "hello"),(18, "hello"),(19, "hello"),(20, "hello"); +--enable_info +delete from t where id = 2 limit 1; + +--echo ## Test delete with false condition +delete from t where 0; +--disable_info + +insert into t values (2, 'abc'); +--enable_info +delete from t where t.id = 2 limit 1; +--disable_info + +--echo ## Test delete ignore +insert into t values (2, 'abc'); +## TODO: https://github.com/pingcap/tidb/issues/48120 +--replace_regex /INTEGER/DOUBLE/ +-- error 1292 +delete from t where id = (select '2a'); +--enable_info +delete ignore from t where id = (select '2a'); +--disable_info +SHOW WARNINGS; + +--echo ## Test delete without using index, involve multiple partitions. +--enable_info +delete from t ignore index(id) where id >= 13 and id <= 17; +--disable_info + +admin check table t; +--enable_info +delete from t; +--disable_info + +--echo ## Fix that partitioned table should not use PointGetPlan. +drop table if exists t1; +create table t1 (c1 bigint, c2 bigint, c3 bigint, primary key(c1)) partition by range (c1) (partition p0 values less than (3440)); +insert into t1 values (379, 379, 379); +--enable_info +delete from t1 where c1 = 379; +--disable_info +drop table t1; + +set tidb_opt_fix_control=default; + + +# TestHashPartitionedTableReplace +set @@session.tidb_enable_table_partition = '1'; +drop table if exists replace_test; +create table replace_test (id int PRIMARY KEY AUTO_INCREMENT, c1 int, c2 int, c3 int default 1) + partition by hash(id) partitions 4; +replace replace_test (c1) values (1),(2),(NULL); +begin; +-- error 1136 +replace replace_test (c1) values (); +rollback; +begin; +-- error 1136 +replace replace_test (c1, c2) values (1,2),(1); +rollback; +begin; +-- error 1054 +replace replace_test (xxx) values (3); +rollback; +begin; +-- error 1146 +replace replace_test_xxx (c1) values (); +rollback; +begin; +-- error 1110 +replace replace_test set c1 = 4, c1 = 5; +rollback; +begin; +-- error 1054 +replace replace_test set xxx = 6; +rollback; +replace replace_test set c1 = 3; +replace replace_test set c1 = 4; +replace replace_test set c1 = 5; +replace replace_test set c1 = 6; +replace replace_test set c1 = 7; + +drop table if exists replace_test_1; +create table replace_test_1 (id int, c1 int) partition by hash(id) partitions 5; +replace replace_test_1 select id, c1 from replace_test; + +drop table if exists replace_test_2; +create table replace_test_2 (id int, c1 int) partition by hash(id) partitions 6; +replace replace_test_1 select id, c1 from replace_test union select id * 10, c1 * 10 from replace_test; +begin; +-- error 1136 +replace replace_test_1 select c1 from replace_test; +rollback; + +drop table if exists replace_test_3; +create table replace_test_3 (c1 int, c2 int, UNIQUE INDEX (c2)) partition by hash(c2) partitions 7; +replace into replace_test_3 set c2=8; +--enable_info +replace into replace_test_3 set c2=8; +replace into replace_test_3 set c1=8, c2=8; +--disable_info +replace into replace_test_3 set c2=NULL; +--enable_info +replace into replace_test_3 set c2=NULL; +--disable_info + +replace into replace_test_3 set c2=0; +replace into replace_test_3 set c2=1; +replace into replace_test_3 set c2=2; +replace into replace_test_3 set c2=3; +replace into replace_test_3 set c2=4; +replace into replace_test_3 set c2=5; +replace into replace_test_3 set c2=6; +replace into replace_test_3 set c2=7; +replace into replace_test_3 set c2=8; +replace into replace_test_3 set c2=9; +select count(*) from replace_test_3; + +drop table if exists replace_test_4; +create table replace_test_4 (c1 int, c2 int, c3 int, UNIQUE INDEX (c1, c2)) partition by hash(c1) partitions 8; +replace into replace_test_4 set c2=NULL; +--enable_info +replace into replace_test_4 set c2=NULL; +--disable_info + +drop table if exists replace_test_5; +create table replace_test_5 (c1 int, c2 int, c3 int, PRIMARY KEY (c1, c2)) partition by hash (c2) partitions 9; +replace into replace_test_5 set c1=1, c2=2; +--enable_info +replace into replace_test_5 set c1=1, c2=2; +--disable_info + +drop table if exists tIssue989; +CREATE TABLE tIssue989 (a int, b int, KEY(a), UNIQUE KEY(b)) partition by hash (b) partitions 10; +insert into tIssue989 (a, b) values (1, 2); +replace into tIssue989(a, b) values (111, 2); +select * from tIssue989; + +set @@session.tidb_enable_table_partition = default; + +## test partition insert/update ignore to invalid partition +drop table if exists insert_update_ignore_test; +create table insert_update_ignore_test (a int) partition by range (a) (partition p0 values less than (100), partition p1 values less than (200)); +insert ignore into insert_update_ignore_test values(1000); +show warnings where Message not like '%disable dynamic pruning%'; +insert ignore into insert_update_ignore_test partition(p0) values(101); +show warnings where Message not like '%disable dynamic pruning%'; +select * from insert_update_ignore_test; +insert into insert_update_ignore_test values(1); +update ignore insert_update_ignore_test set a=1000; +show warnings where Message not like '%disable dynamic pruning%'; +select * from insert_update_ignore_test; +update ignore insert_update_ignore_test partition(p0) set a=101; +show warnings where Message not like '%disable dynamic pruning%'; +select * from insert_update_ignore_test; +drop table insert_update_ignore_test;