Commit be382b42 authored by unknown's avatar unknown

Fix for segmentation fault when updating a record having a small

BLOB whose size didn't change. Fix for probably impossible problem
in Recovery.


mysql-test/r/maria.result:
  result for new test
mysql-test/t/maria.test:
  testcase for a bug (used to segfault)
storage/maria/ma_blockrec.c:
  When writing a record, we put BLOBs into the head part if there is
  room for them. "Is there room" was first decided by
  !(tmp_data + length > end_of_data) (line 1894)
  but then was tested again as
  *blob_lengths < (ulong)(end_of_data - data). We see that in case of
  equality, the first condition was true but the second was not,
  so it was inconsistent and crashed later.
storage/maria/ma_recovery.c:
  When wondering if recovery should update the state (like state.records):
  if table was closed, its is_of_horizon was set to X, then
  table was reopened and a REDO was written. If this REDO had LSN
  X (as horizon is just a lower bound of the LSN of the next record),
  we have to apply it. In practice this equality probably could not
  happen because of LOGREC_FILE_ID would be written before the REDO.
parent 9c2ff270
...@@ -1966,3 +1966,10 @@ select t1,t2,length(t3),length(t4),length(t5),length(t6),t7,t8 from t2; ...@@ -1966,3 +1966,10 @@ select t1,t2,length(t3),length(t4),length(t5),length(t6),t7,t8 from t2;
t1 t2 length(t3) length(t4) length(t5) length(t6) t7 t8 t1 t2 length(t3) length(t4) length(t5) length(t6) t7 t8
1 a 256 256 4096 4096 1 a 256 256 4096 4096
drop table t1,t2; drop table t1,t2;
CREATE TABLE t1 (seq int, s1 int, s2 blob);
insert into t1 values (1, 1, MD5(1));
update t1 set s1=2 where seq=1;
check table t1 extended;
Table Op Msg_type Msg_text
test.t1 check status OK
drop table t1;
...@@ -1254,6 +1254,14 @@ check table t1,t2; ...@@ -1254,6 +1254,14 @@ check table t1,t2;
select t1,t2,length(t3),length(t4),length(t5),length(t6),t7,t8 from t2; select t1,t2,length(t3),length(t4),length(t5),length(t6),t7,t8 from t2;
drop table t1,t2; drop table t1,t2;
# Test UPDATE with small BLOB which fits on head page
CREATE TABLE t1 (seq int, s1 int, s2 blob);
insert into t1 values (1, 1, MD5(1));
update t1 set s1=2 where seq=1;
check table t1 extended;
drop table t1;
# End of 5.2 tests # End of 5.2 tests
--disable_result_log --disable_result_log
......
...@@ -1909,7 +1909,8 @@ static my_bool write_block_record(MARIA_HA *info, ...@@ -1909,7 +1909,8 @@ static my_bool write_block_record(MARIA_HA *info,
{ {
/* Still room on page; Copy as many blobs we can into this page */ /* Still room on page; Copy as many blobs we can into this page */
data= tmp_data; data= tmp_data;
for (; column < end_column && *blob_lengths < (ulong) (end_of_data - data); for (; column < end_column &&
*blob_lengths <= (ulong)(end_of_data - data);
column++, blob_lengths++) column++, blob_lengths++)
{ {
uchar *tmp_pos; uchar *tmp_pos;
......
...@@ -1193,7 +1193,7 @@ prototype_redo_exec_hook(UNDO_ROW_INSERT) ...@@ -1193,7 +1193,7 @@ prototype_redo_exec_hook(UNDO_ROW_INSERT)
if (info == NULL) if (info == NULL)
return 0; return 0;
set_undo_lsn_for_active_trans(rec->short_trid, rec->lsn); set_undo_lsn_for_active_trans(rec->short_trid, rec->lsn);
if (cmp_translog_addr(rec->lsn, info->s->state.is_of_horizon) > 0) if (cmp_translog_addr(rec->lsn, info->s->state.is_of_horizon) >= 0)
{ {
fprintf(tracef, " state older than record, updating rows' count\n"); fprintf(tracef, " state older than record, updating rows' count\n");
info->s->state.state.records++; info->s->state.state.records++;
...@@ -1216,7 +1216,7 @@ prototype_redo_exec_hook(UNDO_ROW_DELETE) ...@@ -1216,7 +1216,7 @@ prototype_redo_exec_hook(UNDO_ROW_DELETE)
if (info == NULL) if (info == NULL)
return 0; return 0;
set_undo_lsn_for_active_trans(rec->short_trid, rec->lsn); set_undo_lsn_for_active_trans(rec->short_trid, rec->lsn);
if (cmp_translog_addr(rec->lsn, info->s->state.is_of_horizon) > 0) if (cmp_translog_addr(rec->lsn, info->s->state.is_of_horizon) >= 0)
{ {
fprintf(tracef, " state older than record, updating rows' count\n"); fprintf(tracef, " state older than record, updating rows' count\n");
info->s->state.state.records--; info->s->state.state.records--;
...@@ -1234,7 +1234,7 @@ prototype_redo_exec_hook(UNDO_ROW_UPDATE) ...@@ -1234,7 +1234,7 @@ prototype_redo_exec_hook(UNDO_ROW_UPDATE)
if (info == NULL) if (info == NULL)
return 0; return 0;
set_undo_lsn_for_active_trans(rec->short_trid, rec->lsn); set_undo_lsn_for_active_trans(rec->short_trid, rec->lsn);
if (cmp_translog_addr(rec->lsn, info->s->state.is_of_horizon) > 0) if (cmp_translog_addr(rec->lsn, info->s->state.is_of_horizon) >= 0)
{ {
info->s->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED | info->s->state.changed|= STATE_CHANGED | STATE_NOT_ANALYZED |
STATE_NOT_OPTIMIZED_KEYS | STATE_NOT_SORTED_PAGES; STATE_NOT_OPTIMIZED_KEYS | STATE_NOT_SORTED_PAGES;
...@@ -1295,7 +1295,7 @@ prototype_redo_exec_hook(CLR_END) ...@@ -1295,7 +1295,7 @@ prototype_redo_exec_hook(CLR_END)
set_undo_lsn_for_active_trans(rec->short_trid, previous_undo_lsn); set_undo_lsn_for_active_trans(rec->short_trid, previous_undo_lsn);
fprintf(tracef, " CLR_END was about %s, undo_lsn now LSN (%lu,0x%lx)\n", fprintf(tracef, " CLR_END was about %s, undo_lsn now LSN (%lu,0x%lx)\n",
log_desc->name, LSN_IN_PARTS(previous_undo_lsn)); log_desc->name, LSN_IN_PARTS(previous_undo_lsn));
if (cmp_translog_addr(rec->lsn, info->s->state.is_of_horizon) > 0) if (cmp_translog_addr(rec->lsn, info->s->state.is_of_horizon) >= 0)
{ {
fprintf(tracef, " state older than record, updating rows' count\n"); fprintf(tracef, " state older than record, updating rows' count\n");
switch (undone_record_type) { switch (undone_record_type) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment