Below is the list of changes that have just been committed into a local
4.0 repository of monty. When monty does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet
1.2104 05/05/13 11:11:50 monty@stripped +5 -0
Change create_field->offset to store offset from start of fields, independent of null bits.
Count null_bits separately from field offsets and adjust them in case of primary key parts.
(Previously a CREATE TABLE with a lot of null fields that was part of a primary key caused MySQL to wrongly count the number of bytes needed to store null bits)
This is a more complete bug fix for #6236
sql/unireg.cc
1.20 05/05/13 11:11:48 monty@stripped +50 -33
Change create_field->offset to store offset from start of fields, independent of null bits.
Count null_bits separately from field offsets and adjust them in case of primary key parts.
sql/sql_table.cc
1.195 05/05/13 11:11:48 monty@stripped +14 -23
Change create_field->offset to store offset from start of fields, independent of null bits.
Count null_bits separately from field offsets and adjust them in case of primary key parts.
sql/handler.h
1.94 05/05/13 11:11:48 monty@stripped +1 -0
Add counter for null fields
mysql-test/t/alter_table.test
1.22 05/05/13 11:11:48 monty@stripped +17 -0
More test for bug #6236 (CREATE TABLE didn't properly count not null columns for primary keys)
mysql-test/r/alter_table.result
1.21 05/05/13 11:11:48 monty@stripped +16 -0
More test for bug #6236 (CREATE TABLE didn't properly count not null columns for primary keys)
# This is a BitKeeper patch. What follows are the unified diffs for the
# set of deltas contained in the patch. The rest of the patch, the part
# that BitKeeper cares about, is below these diffs.
# User: monty
# Host: narttu.mysql.com
# Root: /home/my/mysql-4.0
--- 1.93/sql/handler.h 2004-03-26 22:34:49 +02:00
+++ 1.94/sql/handler.h 2005-05-13 11:11:48 +03:00
@@ -164,6 +164,7 @@
SQL_LIST merge_list;
enum db_type db_type;
enum row_type row_type;
+ uint null_bits; /* NULL bits at start of record */
uint options; /* OR of HA_CREATE_ options */
uint raid_type,raid_chunks;
uint merge_insert_method;
--- 1.194/sql/sql_table.cc 2005-05-08 23:02:04 +03:00
+++ 1.195/sql/sql_table.cc 2005-05-13 11:11:48 +03:00
@@ -363,7 +363,7 @@
create_field *sql_field,*dup_field;
int error= -1;
uint db_options,field,null_fields,blob_columns;
- ulong pos;
+ ulong record_offset;
KEY *key_info,*key_info_buffer;
KEY_PART_INFO *key_part_info;
int auto_increment=0;
@@ -418,10 +418,9 @@
}
it2.rewind();
}
- /* If fixed row records, we need one bit to check for deleted rows */
- if (!(db_options & HA_OPTION_PACK_RECORD))
- null_fields++;
- pos=(null_fields+7)/8;
+
+ /* record_offset will be increased with 'length-of-null-bits' later */
+ record_offset= 0;
it.rewind();
while ((sql_field=it++))
@@ -478,10 +477,10 @@
}
if (!(sql_field->flags & NOT_NULL_FLAG))
sql_field->pack_flag|=FIELDFLAG_MAYBE_NULL;
- sql_field->offset= pos;
+ sql_field->offset= record_offset;
if (MTYP_TYPENR(sql_field->unireg_check) == Field::NEXT_NUMBER)
auto_increment++;
- pos+=sql_field->pack_length;
+ record_offset+= sql_field->pack_length;
}
if (auto_increment > 1)
{
@@ -578,11 +577,12 @@
column->field_name);
DBUG_RETURN(-1);
}
- /* for fulltext keys keyseg length is 1 for blobs (it's ignored in
- ft code anyway, and 0 (set to column width later) for char's.
- it has to be correct col width for char's, as char data are not
- prefixed with length (unlike blobs, where ft code takes data length
- from a data prefix, ignoring column->length).
+ /*
+ for fulltext keys keyseg length is 1 for blobs (it's ignored in
+ ft code anyway, and 0 (set to column width later) for char's.
+ it has to be correct col width for char's, as char data are not
+ prefixed with length (unlike blobs, where ft code takes data length
+ from a data prefix, ignoring column->length).
*/
if (key->type == Key::FULLTEXT)
column->length=test(f_is_blob(sql_field->pack_flag));
@@ -609,6 +609,7 @@
/* Implicitly set primary key fields to NOT NULL for ISO conf. */
sql_field->flags|= NOT_NULL_FLAG;
sql_field->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
+ null_fields--;
}
else
key_info->flags|= HA_NULL_PART_KEY;
@@ -765,6 +766,7 @@
if (thd->sql_mode & MODE_NO_DIR_IN_CREATE)
create_info->data_file_name= create_info->index_file_name= 0;
create_info->table_options=db_options;
+ create_info->null_bits= null_fields;
if (rea_create_table(path, create_info, fields, key_count,
key_info_buffer))
@@ -1828,17 +1830,6 @@
cfield->length != cfield->pack_length ||
cfield->pack_length <= key_part_length))
key_part_length=0; // Use whole field
- }
- if (!(cfield->flags & NOT_NULL_FLAG))
- {
- if (key_type == Key::PRIMARY)
- {
- /* Implicitly set primary key fields to NOT NULL for ISO conf. */
- cfield->flags|= NOT_NULL_FLAG;
- cfield->pack_flag&= ~FIELDFLAG_MAYBE_NULL;
- }
- else
- key_info->flags|= HA_NULL_PART_KEY;
}
key_parts.push_back(new key_part_spec(cfield->field_name,
key_part_length));
--- 1.19/sql/unireg.cc 2004-02-19 19:36:52 +02:00
+++ 1.20/sql/unireg.cc 2005-05-13 11:11:48 +03:00
@@ -32,18 +32,21 @@
static uchar * pack_screens(List<create_field> &create_fields,
uint *info_length, uint *screens, bool small_file);
-static uint pack_keys(uchar *keybuff,uint key_count, KEY *key_info);
+static uint pack_keys(uchar *keybuff,uint key_count, KEY *key_info,
+ ulong data_offset);
static bool pack_header(uchar *forminfo, enum db_type table_type,
List<create_field> &create_fields,
uint info_length, uint screens, uint table_options,
- handler *file);
+ ulong data_offset, handler *file);
static uint get_interval_id(uint *int_count,List<create_field> &create_fields,
create_field *last_field);
-static bool pack_fields(File file, List<create_field> &create_fields);
+static bool pack_fields(File file, List<create_field> &create_fields,
+ ulong data_offset);
static bool make_empty_rec(int file, enum db_type table_type,
uint table_options,
List<create_field> &create_fields,
- uint reclength,uint null_fields);
+ uint reclength, uint null_fields,
+ ulong data_offset);
int rea_create_table(my_string file_name,
@@ -53,7 +56,7 @@
{
uint reclength,info_length,screens,key_info_length,maxlength,null_fields;
File file;
- ulong filepos;
+ ulong filepos, data_offset;
uchar fileinfo[64],forminfo[288],*keybuff;
TYPELIB formnames;
uchar *screen_buff;
@@ -64,8 +67,15 @@
if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,0)))
DBUG_RETURN(1);
db_file=get_new_handler((TABLE*) 0, create_info->db_type);
+
+ /* If fixed row records, we need one bit to check for deleted rows */
+ if (!(create_info->table_options & HA_OPTION_PACK_RECORD))
+ create_info->null_bits++;
+ data_offset= (create_info->null_bits + 7) / 8;
+
if (pack_header(forminfo, create_info->db_type,create_fields,info_length,
- screens, create_info->table_options, db_file))
+ screens, create_info->table_options,
+ data_offset, db_file))
{
NET *net=my_pthread_getspecific_ptr(NET*,THR_NET);
my_free((gptr) screen_buff,MYF(0));
@@ -77,7 +87,7 @@
if (!(screen_buff=pack_screens(create_fields,&info_length,&screens,1)))
DBUG_RETURN(1);
if (pack_header(forminfo, create_info->db_type, create_fields,info_length,
- screens, create_info->table_options, db_file))
+ screens, create_info->table_options, data_offset, db_file))
{
my_free((gptr) screen_buff,MYF(0));
DBUG_RETURN(1);
@@ -95,7 +105,7 @@
uint key_buff_length=uint2korr(fileinfo+14);
keybuff=(uchar*) my_alloca(key_buff_length);
- key_info_length=pack_keys(keybuff,keys,key_info);
+ key_info_length= pack_keys(keybuff, keys, key_info, data_offset);
VOID(get_form_pos(file,fileinfo,&formnames));
if (!(filepos=make_new_entry(file,fileinfo,&formnames,"")))
goto err;
@@ -117,13 +127,13 @@
(ulong) uint2korr(fileinfo+6)+ (ulong) key_buff_length,
MY_SEEK_SET,MYF(0)));
if (make_empty_rec(file,create_info->db_type,create_info->table_options,
- create_fields,reclength,null_fields))
+ create_fields,reclength, null_fields, data_offset))
goto err;
VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
if (my_write(file,(byte*) forminfo,288,MYF_RW) ||
my_write(file,(byte*) screen_buff,info_length,MYF_RW) ||
- pack_fields(file,create_fields))
+ pack_fields(file, create_fields, data_offset))
goto err;
#ifdef HAVE_CRYPTED_FRM
@@ -248,7 +258,8 @@
/* Pack keyinfo and keynames to keybuff for save in form-file. */
-static uint pack_keys(uchar *keybuff,uint key_count,KEY *keyinfo)
+static uint pack_keys(uchar *keybuff, uint key_count, KEY *keyinfo,
+ ulong data_offset)
{
uint key_parts,length;
uchar *pos, *keyname_pos, *key_alg_pos;
@@ -273,10 +284,13 @@
key_part++)
{
- DBUG_PRINT("loop",("field: %d startpos: %ld length: %ld",
- key_part->fieldnr,key_part->offset,key_part->length));
+ uint offset;
+ DBUG_PRINT("loop",("field: %d startpos: %lu length: %ld",
+ key_part->fieldnr, key_part->offset + data_offset,
+ key_part->length));
int2store(pos,key_part->fieldnr+1+FIELD_NAME_USED);
- int2store(pos+2,key_part->offset+1);
+ offset= (uint) (key_part->offset+data_offset+1);
+ int2store(pos+2, offset);
pos[4]=0; // Sort order
int2store(pos+5,key_part->key_type);
int2store(pos+7,key_part->length);
@@ -316,8 +330,8 @@
static bool pack_header(uchar *forminfo, enum db_type table_type,
List<create_field> &create_fields,
- uint info_length, uint screens,uint table_options,
- handler *file)
+ uint info_length, uint screens, uint table_options,
+ ulong data_offset, handler *file)
{
uint length,int_count,int_length,no_empty, int_parts,
time_stamp_pos,null_fields;
@@ -351,10 +365,10 @@
if ((MTYP_TYPENR(field->unireg_check) == Field::TIMESTAMP_FIELD ||
f_packtype(field->pack_flag) == (int) FIELD_TYPE_TIMESTAMP) &&
!time_stamp_pos)
- time_stamp_pos=(int) field->offset+1;
+ time_stamp_pos= (uint) field->offset+ (uint) data_offset + 1;
length=field->pack_length;
- if ((int) field->offset+length > reclength)
- reclength=(int) field->offset+length;
+ if ((uint) field->offset+ (uint) data_offset+ length > reclength)
+ reclength=(uint) (field->offset+ data_offset + length);
n_length+= (ulong) strlen(field->field_name)+1;
field->interval_id=0;
if (field->interval)
@@ -440,7 +454,8 @@
/* Save fields, fieldnames and intervals */
-static bool pack_fields(File file,List<create_field> &create_fields)
+static bool pack_fields(File file, List<create_field> &create_fields,
+ ulong data_offset)
{
reg2 uint i;
uint int_count;
@@ -455,11 +470,13 @@
int_count=0;
while ((field=it++))
{
+ uint recpos;
buff[0]= (uchar) field->row;
buff[1]= (uchar) field->col;
buff[2]= (uchar) field->sc_length;
buff[3]= (uchar) field->length;
- uint recpos=(uint) field->offset+1;
+ /* The +1 is here becasue the col offset in .frm file have offset 1 */
+ recpos= field->offset+1 + (uint) data_offset;
int2store(buff+4,recpos);
int2store(buff+6,field->pack_flag);
int2store(buff+8,field->unireg_check);
@@ -519,11 +536,12 @@
static bool make_empty_rec(File file,enum db_type table_type,
uint table_options,
List<create_field> &create_fields,
- uint reclength, uint null_fields)
+ uint reclength, uint null_fields,
+ ulong data_offset)
{
int error;
Field::utype type;
- uint firstpos,null_count,null_length;
+ uint firstpos,null_count;
uchar *buff,*null_pos;
TABLE table;
create_field *field;
@@ -547,17 +565,16 @@
firstpos=reclength;
null_count=0;
if (!(table_options & HA_OPTION_PACK_RECORD))
- {
- null_fields++; // Need one bit for delete mark
- null_count++;
- }
- bfill(buff,(null_length=(null_fields+7)/8),255);
+ null_count++; // Need one bit for delete mark
+ DBUG_ASSERT(data_offset == ((null_fields + null_count + 7) / 8));
+ bfill(buff, (uint) data_offset, 255);
null_pos=buff;
List_iterator<create_field> it(create_fields);
while ((field=it++))
{
- Field *regfield=make_field((char*) buff+field->offset,field->length,
+ Field *regfield=make_field((char*) buff+field->offset + data_offset,
+ field->length,
field->flags & NOT_NULL_FLAG ? 0:
null_pos+null_count/8,
1 << (null_count & 7),
@@ -570,9 +587,9 @@
if (!(field->flags & NOT_NULL_FLAG))
null_count++;
- if ((uint) field->offset < firstpos &&
+ if ((uint) (field->offset + data_offset) < firstpos &&
regfield->type() != FIELD_TYPE_NULL)
- firstpos= field->offset;
+ firstpos= field->offset + data_offset;
type= (Field::utype) MTYP_TYPENR(field->unireg_check);
@@ -596,8 +613,8 @@
}
/* Fill not used startpos */
- bfill((byte*) buff+null_length,firstpos-null_length,255);
- error=(int) my_write(file,(byte*) buff,(uint) reclength,MYF_RW);
+ bfill((byte*) buff+data_offset, firstpos- (uint) data_offset, 255);
+ error=(int) my_write(file,(byte*) buff, (uint) reclength,MYF_RW);
my_free((gptr) buff,MYF(MY_FAE));
delete handler;
DBUG_RETURN(error);
--- 1.20/mysql-test/r/alter_table.result 2005-05-08 23:02:03 +03:00
+++ 1.21/mysql-test/r/alter_table.result 2005-05-13 11:11:48 +03:00
@@ -406,3 +406,19 @@
PRIMARY KEY (`a`)
) TYPE=MRG_MyISAM UNION=(t1)
drop table if exists t1, t2;
+create table t1 (a int, b int, c int, d int, e int, f int, g int, h int,i int, primary key (a,b,c,d,e,f,g,i,h)) engine=MyISAM;
+insert into t1 (a) values(1);
+show table status like 't1';
+Name Type Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Create_options Comment
+t1 MyISAM Fixed 1 37 37 X X X X X X X X
+alter table t1 modify a int;
+show table status like 't1';
+Name Type Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Create_options Comment
+t1 MyISAM Fixed 1 37 37 X X X X X X X X
+drop table t1;
+create table t1 (a int not null, b int not null, c int not null, d int not null, e int not null, f int not null, g int not null, h int not null,i int not null, primary key (a,b,c,d,e,f,g,i,h)) engine=MyISAM;
+insert into t1 (a) values(1);
+show table status like 't1';
+Name Type Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Create_options Comment
+t1 MyISAM Fixed 1 37 37 X X X X X X X X
+drop table t1;
--- 1.21/mysql-test/t/alter_table.test 2005-05-08 23:02:04 +03:00
+++ 1.22/mysql-test/t/alter_table.test 2005-05-13 11:11:48 +03:00
@@ -267,3 +267,20 @@
alter table t1 modify a varchar(10) not null;
show create table t2;
drop table if exists t1, t2;
+
+# The following is also part of bug #6236 (CREATE TABLE didn't properly count
+# not null columns for primary keys)
+
+create table t1 (a int, b int, c int, d int, e int, f int, g int, h int,i int, primary key (a,b,c,d,e,f,g,i,h)) engine=MyISAM;
+insert into t1 (a) values(1);
+--replace_column 7 X 8 X 9 X 10 X 11 X 12 X 13 X 14 X
+show table status like 't1';
+alter table t1 modify a int;
+--replace_column 7 X 8 X 9 X 10 X 11 X 12 X 13 X 14 X
+show table status like 't1';
+drop table t1;
+create table t1 (a int not null, b int not null, c int not null, d int not null, e int not null, f int not null, g int not null, h int not null,i int not null, primary key (a,b,c,d,e,f,g,i,h)) engine=MyISAM;
+insert into t1 (a) values(1);
+--replace_column 7 X 8 X 9 X 10 X 11 X 12 X 13 X 14 X
+show table status like 't1';
+drop table t1;
| Thread |
|---|
| • bk commit into 4.0 tree (monty:1.2104) | monty | 13 May |