Skip to content

Commit

Permalink
charset: fix incorrect result when querying in-txn updates when new c…
Browse files Browse the repository at this point in the history
…ollation is enabled (#18703)

Co-authored-by: crazycs <crazycs520@gmail.com>
  • Loading branch information
bb7133 and crazycs520 authored Jul 21, 2020
1 parent 55ac421 commit 187271d
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 1 deletion.
132 changes: 132 additions & 0 deletions expression/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6587,3 +6587,135 @@ func (s *testIntegrationSuite) TestIssue17727(c *C) {
tk.MustQuery("execute stmt using @a;").Check(testkit.Rows("1591940878"))
tk.MustQuery("select @@last_plan_from_cache;").Check(testkit.Rows("1"))
}

func (s *testIntegrationSerialSuite) TestIssue18702(c *C) {
collate.SetNewCollationEnabledForTest(true)
defer collate.SetNewCollationEnabledForTest(false)
tk := testkit.NewTestKit(c, s.store)

tk.MustExec("use test;")
tk.MustExec("DROP TABLE IF EXISTS t;")
// test unique index
tk.MustExec(`CREATE TABLE t (
a bigint(20) PRIMARY KEY,
b varchar(50) COLLATE utf8_general_ci DEFAULT NULL,
c int,
d int,
UNIQUE KEY idx_bc(b, c)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
`)
// test without untouched flag.
tk.MustExec("INSERT INTO t VALUES (1, 'A', 10, 1), (2, 'B', 20, 1);")
tk.MustExec("BEGIN;")
tk.MustExec("UPDATE t SET c = 5 WHERE c = 10;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc) WHERE b = 'A';").Check(testkit.Rows("1 A 5 1"))
tk.MustExec("ROLLBACK;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc);").Check(testkit.Rows("1 A 10 1", "2 B 20 1"))

// test with untouched flag.
tk.MustExec("BEGIN;")
tk.MustExec("UPDATE t SET d = 5 WHERE c = 10;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc) WHERE b = 'A';").Check(testkit.Rows("1 A 10 5"))
tk.MustExec("ROLLBACK;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc);").Check(testkit.Rows("1 A 10 1", "2 B 20 1"))

// test update handle
tk.MustExec("BEGIN;")
tk.MustExec("UPDATE t SET a = 3 WHERE a = 1;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc) WHERE b = 'A';").Check(testkit.Rows("3 A 10 1"))
tk.MustExec("ROLLBACK;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc);").Check(testkit.Rows("1 A 10 1", "2 B 20 1"))

// test with INSERT ... ON DUPLICATE KEY UPDATE
tk.MustExec("BEGIN;")
tk.MustExec("INSERT INTO t VALUES (1, 'A', 10, 1) ON DUPLICATE KEY UPDATE c = 5;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc) WHERE b = 'A';").Check(testkit.Rows("1 A 5 1"))
tk.MustExec("ROLLBACK;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc);").Check(testkit.Rows("1 A 10 1", "2 B 20 1"))

tk.MustExec("BEGIN;")
tk.MustExec("INSERT INTO t VALUES (1, 'A', 10, 1) ON DUPLICATE KEY UPDATE b = 'C'")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc) WHERE b = 'c';").Check(testkit.Rows("1 C 10 1"))
tk.MustExec("ROLLBACK;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc);").Check(testkit.Rows("1 A 10 1", "2 B 20 1"))

// test update handle
tk.MustExec("BEGIN;")
tk.MustExec("INSERT INTO t VALUES (1, 'A', 10, 1) ON DUPLICATE KEY UPDATE a = 3")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc) WHERE b = 'A';").Check(testkit.Rows("3 A 10 1"))
tk.MustExec("ROLLBACK;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc);").Check(testkit.Rows("1 A 10 1", "2 B 20 1"))

// test with REPLACE INTO
tk.MustExec("BEGIN;")
tk.MustExec("REPLACE INTO t VALUES (1, 'A', 5, 1);")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc) WHERE b = 'A';").Check(testkit.Rows("1 A 5 1"))
tk.MustExec("ROLLBACK;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc);").Check(testkit.Rows("1 A 10 1", "2 B 20 1"))

// test update handle
tk.MustExec("BEGIN;")
tk.MustExec("REPLACE INTO t VALUES (3, 'A', 10, 1);")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc) WHERE b = 'A';").Check(testkit.Rows("3 A 10 1"))
tk.MustExec("ROLLBACK;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc);").Check(testkit.Rows("1 A 10 1", "2 B 20 1"))

// test non-unique index
tk.MustExec("DROP TABLE IF EXISTS t;")
tk.MustExec(`CREATE TABLE t (
a bigint(20) PRIMARY KEY,
b varchar(50) COLLATE utf8_general_ci DEFAULT NULL,
c int,
d int,
KEY idx_bc(b, c)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_general_ci;
`)
// test without untouched flag.
tk.MustExec("INSERT INTO t VALUES (1, 'A', 10, 1), (2, 'B', 20, 1);")
tk.MustExec("BEGIN;")
tk.MustExec("UPDATE t SET c = 5 WHERE c = 10;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc) WHERE b = 'A';").Check(testkit.Rows("1 A 5 1"))
tk.MustExec("ROLLBACK;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc);").Check(testkit.Rows("1 A 10 1", "2 B 20 1"))

// test with untouched flag.
tk.MustExec("BEGIN;")
tk.MustExec("UPDATE t SET d = 5 WHERE c = 10;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc) WHERE b = 'A';").Check(testkit.Rows("1 A 10 5"))
tk.MustExec("ROLLBACK;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc);").Check(testkit.Rows("1 A 10 1", "2 B 20 1"))

// test with INSERT ... ON DUPLICATE KEY UPDATE
tk.MustExec("BEGIN;")
tk.MustExec("INSERT INTO t VALUES (1, 'A', 10, 1) ON DUPLICATE KEY UPDATE c = 5;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc) WHERE b = 'A';").Check(testkit.Rows("1 A 5 1"))
tk.MustExec("ROLLBACK;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc);").Check(testkit.Rows("1 A 10 1", "2 B 20 1"))

tk.MustExec("BEGIN;")
tk.MustExec("INSERT INTO t VALUES (1, 'A', 10, 1) ON DUPLICATE KEY UPDATE b = 'C'")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc) WHERE b = 'c';").Check(testkit.Rows("1 C 10 1"))
tk.MustExec("ROLLBACK;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc);").Check(testkit.Rows("1 A 10 1", "2 B 20 1"))

// test update handle
tk.MustExec("BEGIN;")
tk.MustExec("INSERT INTO t VALUES (1, 'A', 10, 1) ON DUPLICATE KEY UPDATE a = 3")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc) WHERE b = 'A';").Check(testkit.Rows("3 A 10 1"))
tk.MustExec("ROLLBACK;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc);").Check(testkit.Rows("1 A 10 1", "2 B 20 1"))

// test with REPLACE INTO
tk.MustExec("BEGIN;")
tk.MustExec("REPLACE INTO t VALUES (1, 'A', 5, 1);")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc) WHERE b = 'A';").Check(testkit.Rows("1 A 5 1"))
tk.MustExec("ROLLBACK;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc);").Check(testkit.Rows("1 A 10 1", "2 B 20 1"))

// test update handle
tk.MustExec("BEGIN;")
tk.MustExec("REPLACE INTO t VALUES (3, 'A', 10, 1);")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc) WHERE b = 'A';").Check(testkit.Rows("1 A 10 1", "3 A 10 1"))
tk.MustExec("ROLLBACK;")
tk.MustQuery("SELECT * FROM t FORCE INDEX(idx_bc);").Check(testkit.Rows("1 A 10 1", "2 B 20 1"))
}
14 changes: 13 additions & 1 deletion tablecodec/tablecodec.go
Original file line number Diff line number Diff line change
Expand Up @@ -717,12 +717,24 @@ func DecodeIndexHandle(key, value []byte, colsLen int, pkTp *types.FieldType) (i
return d.GetInt64(), nil

} else if len(value) >= 8 {
return DecodeIndexValueAsHandle(value)
return decodeHandleInIndexValue(value)
}
// Should never execute to here.
return 0, errors.Errorf("no handle in index key: %v, value: %v", key, value)
}

func decodeHandleInIndexValue(value []byte) (int64, error) {
if len(value) > MaxOldEncodeValueLen {
tailLen := value[0]
if tailLen >= 8 {
return DecodeIndexValueAsHandle(value[len(value)-int(tailLen):])
}
// Should never executed to here, since the handle is encoded in IndexKey.
return 0, errors.Errorf("no handle in index value: %v", value)
}
return DecodeIndexValueAsHandle(value)
}

// DecodeIndexValueAsHandle uses to decode index value as handle id.
func DecodeIndexValueAsHandle(data []byte) (int64, error) {
var h int64
Expand Down

0 comments on commit 187271d

Please sign in to comment.