Skip to content

Commit 85f8bf7

Browse files
committed
Merging mysql-8.0 to mysql-trunk
2 parents 394cd2b + 193b781 commit 85f8bf7

File tree

5 files changed

+180
-25
lines changed

5 files changed

+180
-25
lines changed
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
CREATE TABLE `t`
2+
(`id` INT NOT NULL AUTO_INCREMENT,
3+
`b` LONGBLOB,
4+
PRIMARY KEY(`id`)) ENGINE=InnoDB;
5+
CREATE PROCEDURE p(p_num INT)
6+
BEGIN
7+
DECLARE v_i INT DEFAULT 0;
8+
REPEAT
9+
UPDATE t SET b:=REPEAT('a',FLOOR(1024*1024*4));
10+
UPDATE t SET b:='';
11+
SET v_i:=v_i+1;
12+
UNTIL v_i>p_num END REPEAT;
13+
END $
14+
SET @b:=repeat('b',4*1024*1024);
15+
INSERT INTO t(id,b) VALUES(1,@b);
16+
START TRANSACTION;
17+
CALL p(20);
18+
COMMIT;
19+
FLUSH TABLES `t` FOR EXPORT;
20+
UNLOCK TABLES;
21+
SET @fs1 = (SELECT file_size FROM information_schema.innodb_tablespaces
22+
WHERE name = 'test/t');
23+
START TRANSACTION;
24+
CALL p(20);
25+
COMMIT;
26+
FLUSH TABLES `t` FOR EXPORT;
27+
UNLOCK TABLES;
28+
SET @fs2 = (SELECT file_size FROM information_schema.innodb_tablespaces
29+
WHERE name = 'test/t');
30+
SET @growing = (SELECT (@fs2 - @fs1));
31+
SELECT @growing;
32+
@growing
33+
0
34+
START TRANSACTION;
35+
CALL p(20);
36+
ROLLBACK;
37+
FLUSH TABLES `t` FOR EXPORT;
38+
UNLOCK TABLES;
39+
SET @fs3 = (SELECT file_size FROM information_schema.innodb_tablespaces
40+
WHERE name = 'test/t');
41+
SET @growing = (SELECT (@fs3 - @fs2));
42+
SELECT @growing;
43+
@growing
44+
0
45+
DROP PROCEDURE p;
46+
DROP TABLE t;
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
2+
CREATE TABLE `t`
3+
(`id` INT NOT NULL AUTO_INCREMENT,
4+
`b` LONGBLOB,
5+
PRIMARY KEY(`id`)) ENGINE=InnoDB;
6+
7+
DELIMITER $;
8+
CREATE PROCEDURE p(p_num INT)
9+
BEGIN
10+
DECLARE v_i INT DEFAULT 0;
11+
REPEAT
12+
UPDATE t SET b:=REPEAT('a',FLOOR(1024*1024*4));
13+
UPDATE t SET b:='';
14+
SET v_i:=v_i+1;
15+
UNTIL v_i>p_num END REPEAT;
16+
END $
17+
DELIMITER ;$
18+
19+
SET @b:=repeat('b',4*1024*1024);
20+
INSERT INTO t(id,b) VALUES(1,@b);
21+
22+
START TRANSACTION;
23+
CALL p(20);
24+
COMMIT;
25+
26+
FLUSH TABLES `t` FOR EXPORT;
27+
UNLOCK TABLES;
28+
29+
SET @fs1 = (SELECT file_size FROM information_schema.innodb_tablespaces
30+
WHERE name = 'test/t');
31+
32+
START TRANSACTION;
33+
CALL p(20);
34+
COMMIT;
35+
36+
FLUSH TABLES `t` FOR EXPORT;
37+
UNLOCK TABLES;
38+
39+
SET @fs2 = (SELECT file_size FROM information_schema.innodb_tablespaces
40+
WHERE name = 'test/t');
41+
42+
SET @growing = (SELECT (@fs2 - @fs1));
43+
44+
SELECT @growing;
45+
46+
if (`SELECT @growing > 0`) {
47+
--echo Error: The ibd file 'test/t.ibd' is growing.
48+
49+
}
50+
51+
START TRANSACTION;
52+
CALL p(20);
53+
ROLLBACK;
54+
55+
FLUSH TABLES `t` FOR EXPORT;
56+
UNLOCK TABLES;
57+
58+
SET @fs3 = (SELECT file_size FROM information_schema.innodb_tablespaces
59+
WHERE name = 'test/t');
60+
61+
SET @growing = (SELECT (@fs3 - @fs2));
62+
63+
SELECT @growing;
64+
65+
if (`SELECT @growing > 0`) {
66+
--echo Error: The ibd file 'test/t.ibd' is growing.
67+
68+
}
69+
70+
DROP PROCEDURE p;
71+
DROP TABLE t;

storage/innobase/btr/btr0cur.cc

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3843,6 +3843,7 @@ dberr_t btr_cur_pessimistic_update(
38433843
ulint n_reserved = 0;
38443844
ulint n_ext;
38453845
ulint max_ins_size = 0;
3846+
trx_t *const trx = (thr == nullptr) ? nullptr : thr_get_trx(thr);
38463847

38473848
*offsets = NULL;
38483849
*big_rec = NULL;
@@ -3925,31 +3926,6 @@ dberr_t btr_cur_pessimistic_update(
39253926
ut_ad(rec_offs_validate(rec, index, *offsets));
39263927
n_ext += lob::btr_push_update_extern_fields(new_entry, update, entry_heap);
39273928

3928-
/* UNDO logging is also turned-off during normal operation on intrinsic
3929-
table so condition needs to ensure that table is not intrinsic. */
3930-
if ((flags & BTR_NO_UNDO_LOG_FLAG) && rec_offs_any_extern(*offsets) &&
3931-
!index->table->is_intrinsic()) {
3932-
/* We are in a transaction rollback undoing a row
3933-
update: we must free possible externally stored fields
3934-
which got new values in the update, if they are not
3935-
inherited values. They can be inherited if we have
3936-
updated the primary key to another value, and then
3937-
update it back again. */
3938-
3939-
ut_ad(big_rec_vec == NULL);
3940-
ut_ad(index->is_clustered());
3941-
ut_ad((flags & ~BTR_KEEP_POS_FLAG) ==
3942-
(BTR_NO_LOCKING_FLAG | BTR_CREATE_FLAG | BTR_KEEP_SYS_FLAG) ||
3943-
thr_get_trx(thr)->id == trx_id);
3944-
3945-
DBUG_EXECUTE_IF("ib_blob_update_rollback", DBUG_SUICIDE(););
3946-
RECOVERY_CRASH(99);
3947-
3948-
lob::BtrContext ctx(mtr, nullptr, index, rec, *offsets, block);
3949-
3950-
ctx.free_updated_extern_fields(trx_id, undo_no, update, true);
3951-
}
3952-
39533929
if (page_zip_rec_needs_ext(rec_get_converted_size(index, new_entry, n_ext),
39543930
page_is_comp(page), dict_index_get_n_fields(index),
39553931
block->page.size)) {
@@ -3982,6 +3958,34 @@ dberr_t btr_cur_pessimistic_update(
39823958
goto err_exit;
39833959
}
39843960

3961+
/* Check for an update that moved an ext field to inline */
3962+
lob::mark_not_partially_updatable(trx, index, update, mtr);
3963+
3964+
/* UNDO logging is also turned-off during normal operation on intrinsic
3965+
table so condition needs to ensure that table is not intrinsic. */
3966+
if ((flags & BTR_NO_UNDO_LOG_FLAG) && rec_offs_any_extern(*offsets) &&
3967+
!index->table->is_intrinsic()) {
3968+
/* We are in a transaction rollback undoing a row
3969+
update: we must free possible externally stored fields
3970+
which got new values in the update, if they are not
3971+
inherited values. They can be inherited if we have
3972+
updated the primary key to another value, and then
3973+
update it back again. */
3974+
3975+
ut_ad(big_rec_vec == NULL);
3976+
ut_ad(index->is_clustered());
3977+
ut_ad((flags & ~BTR_KEEP_POS_FLAG) ==
3978+
(BTR_NO_LOCKING_FLAG | BTR_CREATE_FLAG | BTR_KEEP_SYS_FLAG) ||
3979+
thr_get_trx(thr)->id == trx_id);
3980+
3981+
DBUG_EXECUTE_IF("ib_blob_update_rollback", DBUG_SUICIDE(););
3982+
RECOVERY_CRASH(99);
3983+
3984+
lob::BtrContext ctx(mtr, nullptr, index, rec, *offsets, block);
3985+
3986+
ctx.free_updated_extern_fields(trx_id, undo_no, update, true);
3987+
}
3988+
39853989
if (optim_err == DB_OVERFLOW) {
39863990
/* First reserve enough free space for the file segments
39873991
of the index tree, so that the update will not fail because

storage/innobase/include/lob0lob.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1587,6 +1587,15 @@ bool rec_check_lobref_space_id(dict_index_t *index, const rec_t *rec,
15871587
const ulint *offsets);
15881588
#endif /* UNIV_DEBUG */
15891589

1590+
/** Mark an LOB that it is not partially updatable anymore.
1591+
@param[in] trx the current transaction.
1592+
@param[in] index the clustered index to which the LOB belongs.
1593+
@param[in] update the update vector.
1594+
@param[in] mtr the mini transaction context.
1595+
@return DB_SUCCESS on success, error code on failure. */
1596+
dberr_t mark_not_partially_updatable(trx_t *trx, dict_index_t *index,
1597+
const upd_t *update, mtr_t *mtr);
1598+
15901599
} // namespace lob
15911600

15921601
#endif /* lob0lob_h */

storage/innobase/lob/lob0lob.cc

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1397,4 +1397,29 @@ bool rec_check_lobref_space_id(dict_index_t *index, const rec_t *rec,
13971397
}
13981398
#endif /* UNIV_DEBUG */
13991399

1400+
dberr_t mark_not_partially_updatable(trx_t *trx, dict_index_t *index,
1401+
const upd_t *update, mtr_t *mtr) {
1402+
const ulint n_fields = upd_get_n_fields(update);
1403+
1404+
for (ulint i = 0; i < n_fields; i++) {
1405+
const upd_field_t *ufield = upd_get_nth_field(update, i);
1406+
1407+
if (update->is_partially_updated(ufield->field_no)) {
1408+
continue;
1409+
}
1410+
1411+
const dfield_t *field = &ufield->new_val;
1412+
1413+
if (ufield->ext_in_old && !dfield_is_ext(field)) {
1414+
const dfield_t *old_field = &ufield->old_val;
1415+
byte *field_ref = old_field->blobref();
1416+
ref_t ref(field_ref);
1417+
ref.mark_not_partially_updatable(trx, mtr, index,
1418+
dict_table_page_size(index->table));
1419+
}
1420+
}
1421+
1422+
return (DB_SUCCESS);
1423+
}
1424+
14001425
} // namespace lob

0 commit comments

Comments
 (0)