summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.bzrignore1
-rw-r--r--mysql-test/r/almost_full.result29
-rw-r--r--mysql-test/t/almost_full.test41
-rw-r--r--storage/myisam/mi_dynrec.c68
4 files changed, 139 insertions, 0 deletions
diff --git a/.bzrignore b/.bzrignore
index e1ad5a89015..7a8066fdba1 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -900,6 +900,7 @@ libmysql_r/.libs/libmysqlclient_r.lai
libmysql_r/.libs/libmysqlclient_r.so.15
libmysql_r/.libs/libmysqlclient_r.so.15.0.0
libmysql_r/acconfig.h
+libmysql_r/client_settings.h
libmysql_r/conf_to_src
libmysql_r/my_static.h
libmysql_r/mysys_priv.h
diff --git a/mysql-test/r/almost_full.result b/mysql-test/r/almost_full.result
new file mode 100644
index 00000000000..eb28f12fa51
--- /dev/null
+++ b/mysql-test/r/almost_full.result
@@ -0,0 +1,29 @@
+drop table if exists t1;
+set global myisam_data_pointer_size=2;
+CREATE TABLE t1 (a int auto_increment primary key not null, b longtext) ENGINE=MyISAM;
+DELETE FROM t1 WHERE a=1 or a=5;
+INSERT INTO t1 SET b=repeat('a',600);
+ERROR HY000: The table 't1' is full
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check warning Datafile is almost full, 65448 of 65534 used
+test.t1 check status OK
+UPDATE t1 SET b=repeat('a', 800) where a=10;
+ERROR HY000: The table 't1' is full
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check warning Datafile is almost full, 65448 of 65534 used
+test.t1 check status OK
+INSERT INTO t1 SET b=repeat('a',400);
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check warning Datafile is almost full, 65448 of 65534 used
+test.t1 check status OK
+DELETE FROM t1 WHERE a=2 or a=6;
+UPDATE t1 SET b=repeat('a', 600) where a=11;
+CHECK TABLE t1 EXTENDED;
+Table Op Msg_type Msg_text
+test.t1 check warning Datafile is almost full, 65448 of 65534 used
+test.t1 check status OK
+drop table t1;
+set global myisam_data_pointer_size=default;
diff --git a/mysql-test/t/almost_full.test b/mysql-test/t/almost_full.test
new file mode 100644
index 00000000000..5c67ab3c088
--- /dev/null
+++ b/mysql-test/t/almost_full.test
@@ -0,0 +1,41 @@
+#
+# Some special cases with empty tables
+#
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+set global myisam_data_pointer_size=2;
+CREATE TABLE t1 (a int auto_increment primary key not null, b longtext) ENGINE=MyISAM;
+
+--disable_query_log
+let $1= 303;
+while ($1)
+{
+ INSERT INTO t1 SET b=repeat('a',200);
+ dec $1;
+}
+--enable_query_log
+
+DELETE FROM t1 WHERE a=1 or a=5;
+
+--error 1114
+INSERT INTO t1 SET b=repeat('a',600);
+CHECK TABLE t1 EXTENDED;
+
+--error 1114
+UPDATE t1 SET b=repeat('a', 800) where a=10;
+CHECK TABLE t1 EXTENDED;
+
+INSERT INTO t1 SET b=repeat('a',400);
+CHECK TABLE t1 EXTENDED;
+
+DELETE FROM t1 WHERE a=2 or a=6;
+UPDATE t1 SET b=repeat('a', 600) where a=11;
+CHECK TABLE t1 EXTENDED;
+drop table t1;
+
+set global myisam_data_pointer_size=default;
+
+# End of 4.1 tests
diff --git a/storage/myisam/mi_dynrec.c b/storage/myisam/mi_dynrec.c
index cdd70abe9ad..9940cf62204 100644
--- a/storage/myisam/mi_dynrec.c
+++ b/storage/myisam/mi_dynrec.c
@@ -326,6 +326,29 @@ static int write_dynamic_record(MI_INFO *info, const uchar *record,
DBUG_ENTER("write_dynamic_record");
flag=0;
+
+ /*
+ Check if we have enough room for the new record.
+ First we do simplified check to make usual case faster.
+ Then we do more precise check for the space left.
+ Though it still is not absolutely precise, as
+ we always use MI_MAX_DYN_BLOCK_HEADER while it can be
+ less in the most of the cases.
+ */
+
+ if (unlikely(info->s->base.max_data_file_length -
+ info->state->data_file_length <
+ reclength + MI_MAX_DYN_BLOCK_HEADER))
+ {
+ if (info->s->base.max_data_file_length - info->state->data_file_length +
+ info->state->empty - info->state->del * MI_MAX_DYN_BLOCK_HEADER <
+ reclength + MI_MAX_DYN_BLOCK_HEADER)
+ {
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ DBUG_RETURN(1);
+ }
+ }
+
do
{
if (_mi_find_writepos(info,reclength,&filepos,&length))
@@ -762,6 +785,51 @@ static int update_dynamic_record(MI_INFO *info, my_off_t filepos, uchar *record,
DBUG_ENTER("update_dynamic_record");
flag=block_info.second_read=0;
+ /*
+ Check if we have enough room for the record.
+ First we do simplified check to make usual case faster.
+ Then we do more precise check for the space left.
+ Though it still is not absolutely precise, as
+ we always use MI_MAX_DYN_BLOCK_HEADER while it can be
+ less in the most of the cases.
+ */
+
+ /*
+ compare with just the reclength as we're going
+ to get some space from the old replaced record
+ */
+ if (unlikely(info->s->base.max_data_file_length -
+ info->state->data_file_length < reclength))
+ {
+ /*
+ let's read the old record's block to find out the length of the
+ old record
+ */
+ if ((error=_mi_get_block_info(&block_info,info->dfile,filepos))
+ & (BLOCK_DELETED | BLOCK_ERROR | BLOCK_SYNC_ERROR | BLOCK_FATAL_ERROR))
+ {
+ DBUG_PRINT("error",("Got wrong block info"));
+ if (!(error & BLOCK_FATAL_ERROR))
+ my_errno=HA_ERR_WRONG_IN_RECORD;
+ goto err;
+ }
+
+ /*
+ if new record isn't longer, we can go on safely
+ */
+ if (block_info.rec_len < reclength)
+ {
+ if (info->s->base.max_data_file_length - info->state->data_file_length +
+ info->state->empty - info->state->del * MI_MAX_DYN_BLOCK_HEADER <
+ reclength - block_info.rec_len + MI_MAX_DYN_BLOCK_HEADER)
+ {
+ my_errno=HA_ERR_RECORD_FILE_FULL;
+ goto err;
+ }
+ }
+ block_info.second_read=0;
+ }
+
while (reclength > 0)
{
if (filepos != info->s->state.dellink)