Commit 69d519e9 authored by unknown's avatar unknown

merge from MyISAM into Maria (last step of merge of 5.1 into Maria).

Tests: "maria" and "ps_maria" fail like before merge (assertions),
"ma_test_all" fails like before merge (ma_test2 segfaults, I'll try
to find out why).


mysys/mf_pagecache.c:
  using a more distinctive tag
storage/maria/ha_maria.cc:
  merge from MyISAM into Maria
storage/maria/ma_check.c:
  merge from MyISAM into Maria
storage/maria/ma_close.c:
  TODO as a word
storage/maria/ma_create.c:
  merge from MyISAM into Maria
storage/maria/ma_delete_all.c:
  TODO as a word
storage/maria/ma_delete_table.c:
  TODO as a word
storage/maria/ma_dynrec.c:
  merge from MyISAM into Maria
storage/maria/ma_extra.c:
  merge from MyISAM into Maria
storage/maria/ma_ft_boolean_search.c:
  merge from MyISAM into Maria
storage/maria/ma_locking.c:
  merge from MyISAM into Maria
storage/maria/ma_loghandler.c:
  fix for compiler warning
storage/maria/ma_open.c:
  merge from MyISAM into Maria.
  I will ask Monty to check the ASKMONTY-marked piece of code.
storage/maria/ma_packrec.c:
  merge from MyISAM into Maria
storage/maria/ma_range.c:
  merge from MyISAM into Maria
storage/maria/ma_rename.c:
  TODO as a word
storage/maria/ma_rt_index.c:
  merge from MyISAM into Maria
storage/maria/ma_rt_split.c:
  merge from MyISAM into Maria
storage/maria/ma_search.c:
  merge from MyISAM into Maria
storage/maria/ma_sort.c:
  merge from MyISAM into Maria
storage/maria/ma_update.c:
  merge from MyISAM into Maria
storage/maria/ma_write.c:
  merge from MyISAM into Maria
storage/maria/maria_chk.c:
  merge from MyISAM into Maria
storage/maria/maria_def.h:
  merge from MyISAM into Maria
storage/maria/maria_pack.c:
  merge from MyISAM into Maria
storage/maria/unittest/ma_test_loghandler_pagecache-t.c:
  fix for compiler warning
storage/myisam/ha_myisam.cc:
  merge from MyISAM into Maria
storage/myisammrg/ha_myisammrg.cc:
  merge from MyISAM into Maria
parent 417a0aa9
......@@ -3228,7 +3228,8 @@ my_bool pagecache_write(PAGECACHE *pagecache,
int rc=
#endif
/*
QQ: We are doing an unlock here, so need to give the page its rec_lsn
RECOVERY TODO BUG We are doing an unlock here, so need to give the
page its rec_lsn
*/
make_lock_and_pin(pagecache, block,
write_lock_change_table[lock].unlock_lock,
......@@ -3590,8 +3591,8 @@ static int flush_pagecache_blocks_int(PAGECACHE *pagecache,
else
{
/* Link the block into a list of blocks 'in switch' */
/* QQ:
#warning this unlink_changed() is a serious problem for
/*
RECOVERY TODO BUG this unlink_changed() is a serious problem for
Maria's Checkpoint: it removes a page from the list of dirty
pages, while it's still dirty. A solution is to abandon
first_in_switch, just wait for this page to be
......
......@@ -108,6 +108,315 @@ static void _ma_check_print_msg(HA_CHECK *param, const char *msg_type,
return;
}
/*
Convert TABLE object to Maria key and column definition
SYNOPSIS
table2maria()
table_arg in TABLE object.
keydef_out out Maria key definition.
recinfo_out out Maria column definition.
records_out out Number of fields.
DESCRIPTION
This function will allocate and initialize Maria key and column
definition for further use in ma_create or for a check for underlying
table conformance in merge engine.
RETURN VALUE
0 OK
!0 error code
*/
int table2maria(TABLE *table_arg, MARIA_KEYDEF **keydef_out,
MARIA_COLUMNDEF **recinfo_out, uint *records_out)
{
uint i, j, recpos, minpos, fieldpos, temp_length, length;
enum ha_base_keytype type= HA_KEYTYPE_BINARY;
byte *record;
KEY *pos;
MARIA_KEYDEF *keydef;
MARIA_COLUMNDEF *recinfo, *recinfo_pos;
HA_KEYSEG *keyseg;
TABLE_SHARE *share= table_arg->s;
uint options= share->db_options_in_use;
DBUG_ENTER("table2maria");
if (!(my_multi_malloc(MYF(MY_WME),
recinfo_out, (share->fields * 2 + 2) * sizeof(MARIA_COLUMNDEF),
keydef_out, share->keys * sizeof(MARIA_KEYDEF),
&keyseg,
(share->key_parts + share->keys) * sizeof(HA_KEYSEG),
NullS)))
DBUG_RETURN(HA_ERR_OUT_OF_MEM); /* purecov: inspected */
keydef= *keydef_out;
recinfo= *recinfo_out;
pos= table_arg->key_info;
for (i= 0; i < share->keys; i++, pos++)
{
keydef[i].flag= (pos->flags & (HA_NOSAME | HA_FULLTEXT | HA_SPATIAL));
keydef[i].key_alg= pos->algorithm == HA_KEY_ALG_UNDEF ?
(pos->flags & HA_SPATIAL ? HA_KEY_ALG_RTREE : HA_KEY_ALG_BTREE) :
pos->algorithm;
keydef[i].block_length= pos->block_size;
keydef[i].seg= keyseg;
keydef[i].keysegs= pos->key_parts;
for (j= 0; j < pos->key_parts; j++)
{
Field *field= pos->key_part[j].field;
type= field->key_type();
keydef[i].seg[j].flag= pos->key_part[j].key_part_flag;
if (options & HA_OPTION_PACK_KEYS ||
(pos->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY |
HA_SPACE_PACK_USED)))
{
if (pos->key_part[j].length > 8 &&
(type == HA_KEYTYPE_TEXT ||
type == HA_KEYTYPE_NUM ||
(type == HA_KEYTYPE_BINARY && !field->zero_pack())))
{
/* No blobs here */
if (j == 0)
keydef[i].flag|= HA_PACK_KEY;
if (!(field->flags & ZEROFILL_FLAG) &&
(field->type() == MYSQL_TYPE_STRING ||
field->type() == MYSQL_TYPE_VAR_STRING ||
((int) (pos->key_part[j].length - field->decimals())) >= 4))
keydef[i].seg[j].flag|= HA_SPACE_PACK;
}
else if (j == 0 && (!(pos->flags & HA_NOSAME) || pos->key_length > 16))
keydef[i].flag|= HA_BINARY_PACK_KEY;
}
keydef[i].seg[j].type= (int) type;
keydef[i].seg[j].start= pos->key_part[j].offset;
keydef[i].seg[j].length= pos->key_part[j].length;
keydef[i].seg[j].bit_start= keydef[i].seg[j].bit_end=
keydef[i].seg[j].bit_length= 0;
keydef[i].seg[j].bit_pos= 0;
keydef[i].seg[j].language= field->charset()->number;
if (field->null_ptr)
{
keydef[i].seg[j].null_bit= field->null_bit;
keydef[i].seg[j].null_pos= (uint) (field->null_ptr-
(uchar*) table_arg->record[0]);
}
else
{
keydef[i].seg[j].null_bit= 0;
keydef[i].seg[j].null_pos= 0;
}
if (field->type() == MYSQL_TYPE_BLOB ||
field->type() == MYSQL_TYPE_GEOMETRY)
{
keydef[i].seg[j].flag|= HA_BLOB_PART;
/* save number of bytes used to pack length */
keydef[i].seg[j].bit_start= (uint) (field->pack_length() -
share->blob_ptr_size);
}
else if (field->type() == MYSQL_TYPE_BIT)
{
keydef[i].seg[j].bit_length= ((Field_bit *) field)->bit_len;
keydef[i].seg[j].bit_start= ((Field_bit *) field)->bit_ofs;
keydef[i].seg[j].bit_pos= (uint) (((Field_bit *) field)->bit_ptr -
(uchar*) table_arg->record[0]);
}
}
keyseg+= pos->key_parts;
}
if (table_arg->found_next_number_field)
keydef[share->next_number_index].flag|= HA_AUTO_KEY;
record= table_arg->record[0];
recpos= 0;
recinfo_pos= recinfo;
while (recpos < (uint) share->reclength)
{
Field **field, *found= 0;
minpos= share->reclength;
length= 0;
for (field= table_arg->field; *field; field++)
{
if ((fieldpos= (*field)->offset(record)) >= recpos &&
fieldpos <= minpos)
{
/* skip null fields */
if (!(temp_length= (*field)->pack_length_in_rec()))
continue; /* Skip null-fields */
if (! found || fieldpos < minpos ||
(fieldpos == minpos && temp_length < length))
{
minpos= fieldpos;
found= *field;
length= temp_length;
}
}
}
DBUG_PRINT("loop", ("found: 0x%lx recpos: %d minpos: %d length: %d",
(long) found, recpos, minpos, length));
if (recpos != minpos)
{ // Reserved space (Null bits?)
bzero((char*) recinfo_pos, sizeof(*recinfo_pos));
recinfo_pos->type= FIELD_NORMAL;
recinfo_pos++->length= (uint16) (minpos - recpos);
}
if (!found)
break;
if (found->flags & BLOB_FLAG)
recinfo_pos->type= FIELD_BLOB;
else if (found->type() == MYSQL_TYPE_VARCHAR)
recinfo_pos->type= FIELD_VARCHAR;
else if (!(options & HA_OPTION_PACK_RECORD))
recinfo_pos->type= FIELD_NORMAL;
else if (found->zero_pack())
recinfo_pos->type= FIELD_SKIP_ZERO;
else
recinfo_pos->type= ((length <= 3 ||
(found->flags & ZEROFILL_FLAG)) ?
FIELD_NORMAL :
found->type() == MYSQL_TYPE_STRING ||
found->type() == MYSQL_TYPE_VAR_STRING ?
FIELD_SKIP_ENDSPACE :
FIELD_SKIP_PRESPACE);
if (found->null_ptr)
{
recinfo_pos->null_bit= found->null_bit;
recinfo_pos->null_pos= (uint) (found->null_ptr -
(uchar*) table_arg->record[0]);
}
else
{
recinfo_pos->null_bit= 0;
recinfo_pos->null_pos= 0;
}
(recinfo_pos++)->length= (uint16) length;
recpos= minpos + length;
DBUG_PRINT("loop", ("length: %d type: %d",
recinfo_pos[-1].length,recinfo_pos[-1].type));
}
*records_out= (uint) (recinfo_pos - recinfo);
DBUG_RETURN(0);
}
/*
Check for underlying table conformance
SYNOPSIS
maria_check_definition()
t1_keyinfo in First table key definition
t1_recinfo in First table record definition
t1_keys in Number of keys in first table
t1_recs in Number of records in first table
t2_keyinfo in Second table key definition
t2_recinfo in Second table record definition
t2_keys in Number of keys in second table
t2_recs in Number of records in second table
strict in Strict check switch
DESCRIPTION
This function compares two Maria definitions. By intention it was done
to compare merge table definition against underlying table definition.
It may also be used to compare dot-frm and MAI definitions of Maria
table as well to compare different Maria table definitions.
For merge table it is not required that number of keys in merge table
must exactly match number of keys in underlying table. When calling this
function for underlying table conformance check, 'strict' flag must be
set to false, and converted merge definition must be passed as t1_*.
Otherwise 'strict' flag must be set to 1 and it is not required to pass
converted dot-frm definition as t1_*.
RETURN VALUE
0 - Equal definitions.
1 - Different definitions.
NOTES
This is currently not used. In MyISAM the corresponding function
(myisam_check_definition()) is used only by MERGE tables
(in ha_myisammrg.cc).
*/
int maria_check_definition(MARIA_KEYDEF *t1_keyinfo,
MARIA_COLUMNDEF *t1_recinfo,
uint t1_keys, uint t1_recs,
MARIA_KEYDEF *t2_keyinfo,
MARIA_COLUMNDEF *t2_recinfo,
uint t2_keys, uint t2_recs, bool strict)
{
uint i, j;
DBUG_ENTER("maria_check_definition");
if ((strict ? t1_keys != t2_keys : t1_keys > t2_keys))
{
DBUG_PRINT("error", ("Number of keys differs: t1_keys=%u, t2_keys=%u",
t1_keys, t2_keys));
DBUG_RETURN(1);
}
if (t1_recs != t2_recs)
{
DBUG_PRINT("error", ("Number of recs differs: t1_recs=%u, t2_recs=%u",
t1_recs, t2_recs));
DBUG_RETURN(1);
}
for (i= 0; i < t1_keys; i++)
{
HA_KEYSEG *t1_keysegs= t1_keyinfo[i].seg;
HA_KEYSEG *t2_keysegs= t2_keyinfo[i].seg;
if (t1_keyinfo[i].keysegs != t2_keyinfo[i].keysegs ||
t1_keyinfo[i].key_alg != t2_keyinfo[i].key_alg)
{
DBUG_PRINT("error", ("Key %d has different definition", i));
DBUG_PRINT("error", ("t1_keysegs=%d, t1_key_alg=%d",
t1_keyinfo[i].keysegs, t1_keyinfo[i].key_alg));
DBUG_PRINT("error", ("t2_keysegs=%d, t2_key_alg=%d",
t2_keyinfo[i].keysegs, t2_keyinfo[i].key_alg));
DBUG_RETURN(1);
}
for (j= t1_keyinfo[i].keysegs; j--;)
{
if (t1_keysegs[j].type != t2_keysegs[j].type ||
t1_keysegs[j].language != t2_keysegs[j].language ||
t1_keysegs[j].null_bit != t2_keysegs[j].null_bit ||
t1_keysegs[j].length != t2_keysegs[j].length)
{
DBUG_PRINT("error", ("Key segment %d (key %d) has different "
"definition", j, i));
DBUG_PRINT("error", ("t1_type=%d, t1_language=%d, t1_null_bit=%d, "
"t1_length=%d",
t1_keysegs[j].type, t1_keysegs[j].language,
t1_keysegs[j].null_bit, t1_keysegs[j].length));
DBUG_PRINT("error", ("t2_type=%d, t2_language=%d, t2_null_bit=%d, "
"t2_length=%d",
t2_keysegs[j].type, t2_keysegs[j].language,
t2_keysegs[j].null_bit, t2_keysegs[j].length));
DBUG_RETURN(1);
}
}
}
for (i= 0; i < t1_recs; i++)
{
MARIA_COLUMNDEF *t1_rec= &t1_recinfo[i];
MARIA_COLUMNDEF *t2_rec= &t2_recinfo[i];
if (t1_rec->type != t2_rec->type ||
t1_rec->length != t2_rec->length ||
t1_rec->null_bit != t2_rec->null_bit)
{
DBUG_PRINT("error", ("Field %d has different definition", i));
DBUG_PRINT("error", ("t1_type=%d, t1_length=%d, t1_null_bit=%d",
t1_rec->type, t1_rec->length, t1_rec->null_bit));
DBUG_PRINT("error", ("t2_type=%d, t2_length=%d, t2_null_bit=%d",
t2_rec->type, t2_rec->length, t2_rec->null_bit));
DBUG_RETURN(1);
}
}
DBUG_RETURN(0);
}
extern "C" {
volatile int *_ma_killed_ptr(HA_CHECK *param)
......@@ -315,17 +624,33 @@ bool ha_maria::check_if_locking_is_allowed(uint sql_command,
int ha_maria::open(const char *name, int mode, uint test_if_locked)
{
uint i;
#ifdef NOT_USED
/*
If the user wants to have memory mapped data files, add an
open_flag. Do not memory map temporary tables because they are
expected to be inserted and thus extended a lot. Memory mapping is
efficient for files that keep their size, but very inefficient for
growing files. Using an open_flag instead of calling ma_extra(...
HA_EXTRA_MMAP ...) after maxs_open() has the advantage that the
mapping is not repeated for every open, but just done on the initial
open, when the MyISAM share is created. Everytime the server
requires to open a new instance of a table it calls this method. We
will always supply HA_OPEN_MMAP for a permanent table. However, the
Maria storage engine will ignore this flag if this is a secondary
open of a table that is in use by other threads already (if the
Maria share exists already).
*/
if (!(test_if_locked & HA_OPEN_TMP_TABLE) && opt_maria_use_mmap)
test_if_locked|= HA_OPEN_MMAP;
#endif
if (!(file= maria_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
return (my_errno ? my_errno : -1);
if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
VOID(maria_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0));
#ifdef NOT_USED
if (!(test_if_locked & HA_OPEN_TMP_TABLE) && opt_maria_use_mmap)
VOID(maria_extra(file, HA_EXTRA_MMAP, 0));
#endif
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED))
VOID(maria_extra(file, HA_EXTRA_WAIT_LOCK, 0));
......@@ -684,11 +1009,11 @@ int ha_maria::optimize(THD * thd, HA_CHECK_OPT *check_opt)
}
int ha_maria::repair(THD *thd, HA_CHECK &param, bool optimize)
int ha_maria::repair(THD *thd, HA_CHECK &param, bool do_optimize)
{
int error= 0;
uint local_testflag= param.testflag;
bool optimize_done= !optimize, statistics_done= 0;
bool optimize_done= !do_optimize, statistics_done= 0;
const char *old_proc_info= thd->proc_info;
char fixed_name[FN_REFLEN];
MARIA_SHARE *share= file->s;
......@@ -712,7 +1037,7 @@ int ha_maria::repair(THD *thd, HA_CHECK &param, bool optimize)
DBUG_RETURN(HA_ADMIN_FAILED);
}
if (!optimize ||
if (!do_optimize ||
((file->state->del || share->state.split != file->state->records) &&
(!(param.testflag & T_QUICK) ||
!(share->state.changed & STATE_NOT_OPTIMIZED_KEYS))))
......@@ -1364,47 +1689,47 @@ int ha_maria::rnd_pos(byte * buf, byte *pos)
void ha_maria::position(const byte * record)
{
my_off_t position= maria_position(file);
my_store_ptr(ref, ref_length, position);
my_off_t row_position= maria_position(file);
my_store_ptr(ref, ref_length, row_position);
}
int ha_maria::info(uint flag)
{
MARIA_INFO info;
MARIA_INFO maria_info;
char name_buff[FN_REFLEN];
(void) maria_status(file, &info, flag);
(void) maria_status(file, &maria_info, flag);
if (flag & HA_STATUS_VARIABLE)
{
stats.records= info.records;
stats.deleted= info.deleted;
stats.data_file_length= info.data_file_length;
stats.index_file_length= info.index_file_length;
stats.delete_length= info.delete_length;
stats.check_time= info.check_time;
stats.mean_rec_length= info.mean_reclength;
stats.records= maria_info.records;
stats.deleted= maria_info.deleted;
stats.data_file_length= maria_info.data_file_length;
stats.index_file_length= maria_info.index_file_length;
stats.delete_length= maria_info.delete_length;
stats.check_time= maria_info.check_time;
stats.mean_rec_length= maria_info.mean_reclength;
}
if (flag & HA_STATUS_CONST)
{
TABLE_SHARE *share= table->s;
stats.max_data_file_length= info.max_data_file_length;
stats.max_index_file_length= info.max_index_file_length;
stats.create_time= info.create_time;
ref_length= info.reflength;
share->db_options_in_use= info.options;
stats.max_data_file_length= maria_info.max_data_file_length;
stats.max_index_file_length= maria_info.max_index_file_length;
stats.create_time= maria_info.create_time;
ref_length= maria_info.reflength;
share->db_options_in_use= maria_info.options;
stats.block_size= maria_block_size;
/* Update share */
if (share->tmp_table == NO_TMP_TABLE)
pthread_mutex_lock(&share->mutex);
share->keys_in_use.set_prefix(share->keys);
share->keys_in_use.intersect_extended(info.key_map);
share->keys_in_use.intersect_extended(maria_info.key_map);
share->keys_for_keyread.intersect(share->keys_in_use);
share->db_record_offset= info.record_offset;
share->db_record_offset= maria_info.record_offset;
if (share->key_parts)
memcpy((char*) table->key_info[0].rec_per_key,
(char*) info.rec_per_key,
(char*) maria_info.rec_per_key,
sizeof(table->key_info[0].rec_per_key) * share->key_parts);
if (share->tmp_table == NO_TMP_TABLE)
pthread_mutex_unlock(&share->mutex);
......@@ -1414,21 +1739,23 @@ int ha_maria::info(uint flag)
if table is symlinked (Ie; Real name is not same as generated name)
*/
data_file_name= index_file_name= 0;
fn_format(name_buff, file->filename, "", MARIA_NAME_DEXT, MY_APPEND_EXT);
if (strcmp(name_buff, info.data_file_name))
data_file_name= info.data_file_name;
fn_format(name_buff, file->filename, "", MARIA_NAME_IEXT, MY_APPEND_EXT);
if (strcmp(name_buff, info.index_file_name))
index_file_name= info.index_file_name;
fn_format(name_buff, file->filename, "", MARIA_NAME_DEXT,
MY_APPEND_EXT | MY_UNPACK_FILENAME);
if (strcmp(name_buff, maria_info.data_file_name))
data_file_name=maria_info.data_file_name;
fn_format(name_buff, file->filename, "", MARIA_NAME_IEXT,
MY_APPEND_EXT | MY_UNPACK_FILENAME);
if (strcmp(name_buff, maria_info.index_file_name))
index_file_name=maria_info.index_file_name;
}
if (flag & HA_STATUS_ERRKEY)
{
errkey= info.errkey;
my_store_ptr(dup_ref, ref_length, info.dup_key_pos);
errkey= maria_info.errkey;
my_store_ptr(dup_ref, ref_length, maria_info.dup_key_pos);
}
/* Faster to always update, than to do it based on flag */
stats.update_time= info.update_time;
stats.auto_increment_value= info.auto_increment;
stats.update_time= maria_info.update_time;
stats.auto_increment_value= maria_info.auto_increment;
return 0;
}
......@@ -1500,208 +1827,50 @@ void ha_maria::update_create_info(HA_CREATE_INFO *create_info)
int ha_maria::create(const char *name, register TABLE *table_arg,
HA_CREATE_INFO *info)
HA_CREATE_INFO *ha_create_info)
{
int error;
uint i, j, recpos, minpos, fieldpos, temp_length, length, create_flags= 0;
bool found_real_auto_increment= 0;
enum ha_base_keytype type;
uint create_flags= 0, records, i;
char buff[FN_REFLEN];
byte *record;
KEY *pos;
MARIA_KEYDEF *keydef;
MARIA_COLUMNDEF *recinfo, *recinfo_pos;
HA_KEYSEG *keyseg;
MARIA_COLUMNDEF *recinfo;
MARIA_CREATE_INFO create_info;
TABLE_SHARE *share= table_arg->s;
uint options= share->db_options_in_use;
enum data_file_type row_type;
DBUG_ENTER("ha_maria::create");
type= HA_KEYTYPE_BINARY; // Keep compiler happy
if (!(my_multi_malloc(MYF(MY_WME),
&recinfo, (share->fields * 2 + 2) *
sizeof(MARIA_COLUMNDEF),
&keydef, share->keys * sizeof(MARIA_KEYDEF),
&keyseg,
((share->key_parts + share->keys) *
sizeof(HA_KEYSEG)), NullS)))
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
pos= table_arg->key_info;
for (i= 0; i < share->keys; i++, pos++)
{
if (pos->flags & HA_USES_PARSER)
create_flags |= HA_CREATE_RELIES_ON_SQL_LAYER;
keydef[i].flag= (pos->flags & (HA_NOSAME | HA_FULLTEXT | HA_SPATIAL));
keydef[i].key_alg= pos->algorithm == HA_KEY_ALG_UNDEF ?
(pos->flags & HA_SPATIAL ? HA_KEY_ALG_RTREE : HA_KEY_ALG_BTREE) :
pos->algorithm;
keydef[i].block_length= pos->block_size;
keydef[i].seg= keyseg;
keydef[i].keysegs= pos->key_parts;
for (j= 0; j < pos->key_parts; j++)
{
Field *field= pos->key_part[j].field;
type= field->key_type();
keydef[i].seg[j].flag= pos->key_part[j].key_part_flag;
if (options & HA_OPTION_PACK_KEYS ||
(pos->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY |
HA_SPACE_PACK_USED)))
{
if (pos->key_part[j].length > 8 &&
(type == HA_KEYTYPE_TEXT ||
type == HA_KEYTYPE_NUM ||
(type == HA_KEYTYPE_BINARY && !field->zero_pack())))
{
/* No blobs here */
if (j == 0)
keydef[i].flag |= HA_PACK_KEY;
if (!(field->flags & ZEROFILL_FLAG) &&
(field->type() == MYSQL_TYPE_STRING ||
field->type() == MYSQL_TYPE_VAR_STRING ||
((int) (pos->key_part[j].length - field->decimals())) >= 4))
keydef[i].seg[j].flag |= HA_SPACE_PACK;
}
else if (j == 0 && (!(pos->flags & HA_NOSAME) || pos->key_length > 16))
keydef[i].flag |= HA_BINARY_PACK_KEY;
}
keydef[i].seg[j].type= (int) type;
keydef[i].seg[j].start= pos->key_part[j].offset;
keydef[i].seg[j].length= pos->key_part[j].length;
keydef[i].seg[j].bit_start= keydef[i].seg[j].bit_end=
keydef[i].seg[j].bit_length= 0;
keydef[i].seg[j].bit_pos= 0;
keydef[i].seg[j].language= field->charset()->number;
if (field->null_ptr)
{
keydef[i].seg[j].null_bit= field->null_bit;
keydef[i].seg[j].null_pos= (uint) (field->null_ptr -
(uchar *) table_arg->record[0]);
}
else
{
keydef[i].seg[j].null_bit= 0;
keydef[i].seg[j].null_pos= 0;
}
if (field->type() == FIELD_TYPE_BLOB ||
field->type() == FIELD_TYPE_GEOMETRY)
{
keydef[i].seg[j].flag |= HA_BLOB_PART;
/* save number of bytes used to pack length */
keydef[i].seg[j].bit_start= (uint) (field->pack_length() -
share->blob_ptr_size);
}
else if (field->type() == FIELD_TYPE_BIT)
{
keydef[i].seg[j].bit_length= ((Field_bit *) field)->bit_len;
keydef[i].seg[j].bit_start= ((Field_bit *) field)->bit_ofs;
keydef[i].seg[j].bit_pos= (uint) (((Field_bit *) field)->bit_ptr -
(uchar *) table_arg->record[0]);
}
}
keyseg += pos->key_parts;
}
if (table_arg->found_next_number_field)
{
keydef[share->next_number_index].flag |= HA_AUTO_KEY;
found_real_auto_increment= share->next_number_key_offset == 0;
}
record= table_arg->record[0];
recpos= 0;
recinfo_pos= recinfo;
while (recpos < (uint) share->reclength)
for (i= 0; i < share->keys; i++)
{
Field **field, *found= 0;
minpos= share->reclength;
length= 0;
for (field= table_arg->field; *field; field++)
if (table_arg->key_info[i].flags & HA_USES_PARSER)
{
if ((fieldpos=(*field)->offset(record)) >= recpos &&
fieldpos <= minpos)
{
/* skip null fields */
if (!(temp_length= (*field)->pack_length_in_rec()))
continue; /* Skip null-fields */
if (!found || fieldpos < minpos ||
(fieldpos == minpos && temp_length < length))
{
minpos= fieldpos;
found= *field;
length= temp_length;
}
}
}
DBUG_PRINT("loop", ("found: 0x%lx recpos: %d minpos: %d length: %d",
(long) found, recpos, minpos, length));
if (recpos != minpos)
{ // Reserved space (Null bits?)
bzero((char*) recinfo_pos, sizeof(*recinfo_pos));
recinfo_pos->type= FIELD_NORMAL;
recinfo_pos++->length= (uint16) (minpos - recpos);
}
if (!found)
create_flags|= HA_CREATE_RELIES_ON_SQL_LAYER;
break;
if (found->flags & BLOB_FLAG)
recinfo_pos->type= FIELD_BLOB;
else if (found->type() == MYSQL_TYPE_VARCHAR)
recinfo_pos->type= FIELD_VARCHAR;
else if (!(options & HA_OPTION_PACK_RECORD))
recinfo_pos->type= FIELD_NORMAL;
else if (found->zero_pack())
recinfo_pos->type= FIELD_SKIP_ZERO;
else
recinfo_pos->type= ((length <= 3 ||
(found->flags & ZEROFILL_FLAG)) ?
FIELD_NORMAL :
found->type() == MYSQL_TYPE_STRING ||
found->type() == MYSQL_TYPE_VAR_STRING ?
FIELD_SKIP_ENDSPACE : FIELD_SKIP_PRESPACE);
if (found->null_ptr)
{
recinfo_pos->null_bit= found->null_bit;
recinfo_pos->null_pos= (uint) (found->null_ptr -
(uchar *) table_arg->record[0]);
}
else
{
recinfo_pos->null_bit= 0;
recinfo_pos->null_pos= 0;
}
(recinfo_pos++)->length= (uint16) length;
recpos= minpos + length;
DBUG_PRINT("loop", ("length: %d type: %d",
recinfo_pos[-1].length, recinfo_pos[-1].type));
}
MARIA_CREATE_INFO create_info;
if ((error= table2maria(table_arg, &keydef, &recinfo, &records)))
DBUG_RETURN(error); /* purecov: inspected */
bzero((char*) &create_info, sizeof(create_info));
create_info.max_rows= share->max_rows;
create_info.reloc_rows= share->min_rows;
create_info.with_auto_increment= found_real_auto_increment;
create_info.auto_increment= (info->auto_increment_value ?
info->auto_increment_value - 1 : (ulonglong) 0);
create_info.with_auto_increment= share->next_number_key_offset == 0;
create_info.auto_increment= (ha_create_info->auto_increment_value ?
ha_create_info->auto_increment_value -1 :
(ulonglong) 0);
create_info.data_file_length= ((ulonglong) share->max_rows *
share->avg_row_length);
create_info.data_file_name= info->data_file_name;
create_info.index_file_name= info->index_file_name;
create_info.data_file_name= ha_create_info->data_file_name;
create_info.index_file_name= ha_create_info->index_file_name;
if (info->options & HA_LEX_CREATE_TMP_TABLE)
create_flags |= HA_CREATE_TMP_TABLE;
if (ha_create_info->options & HA_LEX_CREATE_TMP_TABLE)
create_flags|= HA_CREATE_TMP_TABLE;
if (options & HA_OPTION_PACK_RECORD)
create_flags |= HA_PACK_RECORD;
create_flags|= HA_PACK_RECORD;
if (options & HA_OPTION_CHECKSUM)
create_flags |= HA_CREATE_CHECKSUM;
create_flags|= HA_CREATE_CHECKSUM;
if (options & HA_OPTION_DELAY_KEY_WRITE)
create_flags |= HA_CREATE_DELAY_KEY_WRITE;
create_flags|= HA_CREATE_DELAY_KEY_WRITE;
switch (info->row_type) {
switch (ha_create_info->row_type) {
case ROW_TYPE_FIXED:
row_type= STATIC_RECORD;
break;
......@@ -1718,9 +1887,10 @@ int ha_maria::create(const char *name, register TABLE *table_arg,
error=
maria_create(fn_format(buff, name, "", "",
MY_UNPACK_FILENAME | MY_APPEND_EXT),
row_type, share->keys, keydef, (uint) (recinfo_pos - recinfo),
recinfo, 0, (MARIA_UNIQUEDEF *) 0, &create_info,
create_flags);
row_type, share->keys, keydef,
records, recinfo,
0, (MARIA_UNIQUEDEF *) 0,
&create_info, create_flags);
my_free((gptr) recinfo, MYF(0));
DBUG_RETURN(error);
......
......@@ -2310,6 +2310,12 @@ int maria_sort_index(HA_CHECK *param, register MARIA_HA *info, my_string name)
MARIA_STATE_INFO old_state;
DBUG_ENTER("maria_sort_index");
/* cannot sort index files with R-tree indexes */
for (key= 0,keyinfo= &share->keyinfo[0]; key < share->base.keys ;
key++,keyinfo++)
if (keyinfo->key_alg == HA_KEY_ALG_RTREE)
DBUG_RETURN(0);
if (!(param->testflag & T_SILENT))
printf("- Sorting index for MARIA-table '%s'\n",name);
......@@ -2402,6 +2408,8 @@ static int sort_one_index(HA_CHECK *param, MARIA_HA *info,
char llbuff[22];
DBUG_ENTER("sort_one_index");
/* cannot walk over R-tree indices */
DBUG_ASSERT(keyinfo->key_alg != HA_KEY_ALG_RTREE);
new_page_pos=param->new_file_pos;
param->new_file_pos+=keyinfo->block_length;
......
......@@ -59,7 +59,7 @@ int maria_close(register MARIA_HA *info)
}
flag= !--share->reopen;
/*
RECOVERYTODO:
RECOVERY TODO:
If "flag" is TRUE, in the line below we are going to make the table
unknown to future checkpoints, so it needs to have fsync'ed itself
entirely (bitmap, pages, etc) at this point.
......
......@@ -921,7 +921,7 @@ int maria_create(const char *name, enum data_file_type record_type,
if (my_close(file,MYF(0)))
goto err;
/*
RECOVERYTODO
RECOVERY TODO
Write a log record describing the CREATE operation (just the file
names, link names, and the full header's content).
For this record to be of any use for Recovery, we need the upper
......@@ -967,18 +967,19 @@ uint maria_get_pointer_length(ulonglong file_length, uint def)
if (file_length) /* If not default */
{
#ifdef NOT_YET_READY_FOR_8_BYTE_POINTERS
if (file_length >= (longlong) 1 << 56)
if (file_length >= (ULL(1) << 56))
def=8;
else
#endif
if (file_length >= (longlong) 1 << 48)
if (file_length >= (ULL(1) << 48))
def=7;
if (file_length >= (longlong) 1 << 40)
else if (file_length >= (ULL(1) << 40))
def=6;
else if (file_length >= (longlong) 1 << 32)
else if (file_length >= (ULL(1) << 32))
def=5;
else if (file_length >= (1L << 24))
else if (file_length >= (ULL(1) << 24))
def=4;
else if (file_length >= (1L << 16))
else if (file_length >= (ULL(1) << 16))
def=3;
else
def=2;
......
......@@ -30,7 +30,7 @@ int maria_delete_all_rows(MARIA_HA *info)
{
DBUG_RETURN(my_errno=EACCES);
}
/* LOCKTODO take X-lock on table here */
/* LOCK TODO take X-lock on table here */
if (_ma_readinfo(info,F_WRLCK,1))
DBUG_RETURN(my_errno);
if (_ma_mark_file_changed(info))
......@@ -54,7 +54,7 @@ int maria_delete_all_rows(MARIA_HA *info)
*/
flush_key_blocks(share->key_cache, share->kfile, FLUSH_IGNORE_CHANGED);
/*
RECOVERYTODO Log the two chsize and header modifications and force the
RECOVERY TODO Log the two chsize and header modifications and force the
log. So that if crash between the two chsize, we finish the work at
Recovery. For this scenario:
"TRUNCATE TABLE t1; DROP TABLE t1; RENAME TABLE t2 to t1; crash;"
......@@ -66,7 +66,7 @@ int maria_delete_all_rows(MARIA_HA *info)
my_chsize(share->kfile, share->base.keystart, 0, MYF(MY_WME)) )
goto err;
/*
RECOVERYTODO Consider updating ZeroDirtyPagesLSN here. It is
RECOVERY TODO Consider updating ZeroDirtyPagesLSN here. It is
not a necessity (it is one only in RENAME commands) but an optional
optimization which will allow some REDO skipping at Recovery.
*/
......@@ -78,7 +78,7 @@ int maria_delete_all_rows(MARIA_HA *info)
rw_unlock(&info->s->mmap_lock);
#endif
/*
RECOVERYTODO Until we have the TRUNCATE log record and take it into
RECOVERY TODO Until we have the TRUNCATE log record and take it into
account for log-low-water-mark calculation and use it in Recovery, we need
to sync.
*/
......@@ -90,10 +90,10 @@ int maria_delete_all_rows(MARIA_HA *info)
err:
{
int save_errno=my_errno;
/* RECOVERYTODO log the header modifications */
/* RECOVERY TODO log the header modifications */
VOID(_ma_writeinfo(info,WRITEINFO_UPDATE_KEYFILE));
info->update|=HA_STATE_WRITTEN; /* Buffer changed */
/* RECOVERYTODO until we log above we have to sync */
/* RECOVERY TODO until we log above we have to sync */
if (_ma_sync_table_files(info) && !save_errno)
save_errno= my_errno;
allow_break(); /* Allow SIGHUP & SIGINT */
......
......@@ -31,7 +31,7 @@ int maria_delete_table(const char *name)
#ifdef EXTRA_DEBUG
_ma_check_table_is_closed(name,"delete");
#endif
/* LOCKTODO take X-lock on table here */
/* LOCK TODO take X-lock on table here */
#ifdef USE_RAID
{
MARIA_HA *info;
......@@ -61,7 +61,7 @@ int maria_delete_table(const char *name)
fn_format(from,name,"",MARIA_NAME_IEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT);
/*
RECOVERYTODO log the two deletes below.
RECOVERY TODO log the two deletes below.
Then do the file deletions.
For this log record to be of any use for Recovery, we need the upper MySQL
layer to be crash-safe in DDLs; when it is we should reconsider the moment
......
......@@ -69,6 +69,14 @@ my_bool _ma_dynmap_file(MARIA_HA *info, my_off_t size)
DBUG_PRINT("warning", ("File is too large for mmap"));
DBUG_RETURN(1);
}
/*
Ingo wonders if it is good to use MAP_NORESERVE. From the Linux man page:
MAP_NORESERVE
Do not reserve swap space for this mapping. When swap space is
reserved, one has the guarantee that it is possible to modify the
mapping. When swap space is not reserved one might get SIGSEGV
upon a write if no physical memory is available.
*/
info->s->file_map= (byte*)
my_mmap(0, (size_t)(size + MEMMAP_EXTRA_MARGIN),
info->s->mode==O_RDONLY ? PROT_READ :
......@@ -252,7 +260,7 @@ my_bool _ma_write_blob_record(MARIA_HA *info, const byte *record)
_ma_calc_total_blob_length(info,record)+ extra);
if (!(rec_buff=(byte*) my_alloca(reclength)))
{
my_errno=ENOMEM;
my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
return(1);
}
reclength2= _ma_rec_pack(info,
......@@ -289,7 +297,7 @@ my_bool _ma_update_blob_record(MARIA_HA *info, MARIA_RECORD_POS pos,
#endif
if (!(rec_buff=(byte*) my_alloca(reclength)))
{
my_errno=ENOMEM;
my_errno= HA_ERR_OUT_OF_MEM; /* purecov: inspected */
return(1);
}
reclength= _ma_rec_pack(info,rec_buff+ALIGN_SIZE(MARIA_MAX_DYN_BLOCK_HEADER),
......@@ -1225,8 +1233,10 @@ ulong _ma_rec_unpack(register MARIA_HA *info, register byte *to, byte *from,
{
uint size_length=rec_length- maria_portable_sizeof_char_ptr;
ulong blob_length= _ma_calc_blob_length(size_length,from);
if ((ulong) (from_end-from) - size_length < blob_length ||
min_pack_length > (uint) (from_end -(from+size_length+blob_length)))
ulong from_left= (ulong) (from_end - from);
if (from_left < size_length ||
from_left - size_length < blob_length ||
from_left - size_length - blob_length < min_pack_length)
goto err;
memcpy((byte*) to,(byte*) from,(size_t) size_length);
from+=size_length;
......
......@@ -355,7 +355,12 @@ int maria_extra(MARIA_HA *info, enum ha_extra_function function,
case HA_EXTRA_MMAP:
#ifdef HAVE_MMAP
pthread_mutex_lock(&share->intern_lock);
if (!share->file_map)
/*
Memory map the data file if it is not already mapped and if there
are no other threads using this table. intern_lock prevents other
threads from starting to use the table while we are mapping it.
*/
if (!share->file_map && (share->tot_locks == 1))
{
if (_ma_dynmap_file(info, share->state.state.data_file_length))
{
......
......@@ -676,7 +676,7 @@ static void _ftb_climb_the_tree(FTB *ftb, FTB_WORD *ftbw, FT_SEG_ITERATOR *ftsi_
FT_SEG_ITERATOR ftsi;
FTB_EXPR *ftbe;
float weight=ftbw->weight;
int yn=ftbw->flags, ythresh, mode=(ftsi_orig != 0);
int yn_flag= ftbw->flags, ythresh, mode=(ftsi_orig != 0);
my_off_t curdoc=ftbw->docid[mode];
struct st_mysql_ftparser *parser= ftb->keynr == NO_SUCH_KEY ?
&ft_default_parser :
......@@ -693,13 +693,13 @@ static void _ftb_climb_the_tree(FTB *ftb, FTB_WORD *ftbw, FT_SEG_ITERATOR *ftsi_
}
if (ftbe->nos)
break;
if (yn & FTB_FLAG_YES)
if (yn_flag & FTB_FLAG_YES)
{
weight /= ftbe->ythresh;
ftbe->cur_weight += weight;
if ((int) ++ftbe->yesses == ythresh)
{
yn=ftbe->flags;
yn_flag=ftbe->flags;
weight=ftbe->cur_weight*ftbe->weight;
if (mode && ftbe->phrase)
{
......@@ -720,14 +720,14 @@ static void _ftb_climb_the_tree(FTB *ftb, FTB_WORD *ftbw, FT_SEG_ITERATOR *ftsi_
break;
}
else
if (yn & FTB_FLAG_NO)
if (yn_flag & FTB_FLAG_NO)
{
/*
NOTE: special sort function of queue assures that all
(yn & FTB_FLAG_NO) != 0
(yn_flag & FTB_FLAG_NO) != 0
events for every particular subexpression will
"auto-magically" happen BEFORE all the
(yn & FTB_FLAG_YES) != 0 events. So no
(yn_flag & FTB_FLAG_YES) != 0 events. So no
already matched expression can become not-matched again.
*/
++ftbe->nos;
......@@ -740,8 +740,8 @@ static void _ftb_climb_the_tree(FTB *ftb, FTB_WORD *ftbw, FT_SEG_ITERATOR *ftsi_
ftbe->cur_weight += weight;
if ((int) ftbe->yesses < ythresh)
break;
if (!(yn & FTB_FLAG_WONLY))
yn= ((int) ftbe->yesses++ == ythresh) ? ftbe->flags : FTB_FLAG_WONLY ;
if (!(yn_flag & FTB_FLAG_WONLY))
yn_flag= ((int) ftbe->yesses++ == ythresh) ? ftbe->flags : FTB_FLAG_WONLY ;
weight*= ftbe->weight;
}
}
......
......@@ -291,6 +291,15 @@ void _ma_update_status(void* param)
}
}
void _ma_restore_status(void *param)
{
MARIA_HA *info= (MARIA_HA*) param;
info->state= &info->s->state.state;
info->append_insert_at_end= 0;
}
void _ma_copy_status(void* to,void *from)
{
((MARIA_HA*) to)->state= &((MARIA_HA*) from)->save_state;
......
......@@ -799,7 +799,7 @@ static void translog_put_sector_protection(byte *page,
static uint32 translog_crc(byte *area, uint length)
{
return crc32(0L, area, length);
return crc32(0L, (unsigned char*) area, length);
}
......
......@@ -310,7 +310,13 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
for (j=0 ; j < share->keyinfo[i].keysegs; j++,pos++)
{
disk_pos=_ma_keyseg_read(disk_pos, pos);
if (pos->flag & HA_BLOB_PART &&
! (share->options & (HA_OPTION_COMPRESS_RECORD |
HA_OPTION_PACK_RECORD)))
{
my_errno= HA_ERR_CRASHED;
goto err;
}
if (pos->type == HA_KEYTYPE_TEXT ||
pos->type == HA_KEYTYPE_VARTEXT1 ||
pos->type == HA_KEYTYPE_VARTEXT2)
......@@ -346,11 +352,11 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
}
else
{
uint j;
uint k;
share->keyinfo[i].seg=pos;
for (j=0; j < FT_SEGS; j++)
for (k=0; k < FT_SEGS; k++)
{
*pos= ft_keysegs[j];
*pos= ft_keysegs[k];
pos[0].language= pos[-1].language;
if (!(pos[0].charset= pos[-1].charset))
{
......@@ -444,6 +450,32 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
}
}
share->rec[i].type=(int) FIELD_LAST; /* End marker */
#ifdef ASKMONTY
/*
This code was added to mi_open.c in this cset:
"ChangeSet 1.1616.2941.5 2007/01/22 16:34:58 svoj@mysql.com
BUG#24401 - MySQL server crashes if you try to retrieve data from
corrupted table
Accessing a table with corrupted column definition results in server
crash.
This is fixed by refusing to open such tables. Affects MyISAM only.
No test case, since it requires crashed table.
storage/myisam/mi_open.c 1.80.2.10 2007/01/22 16:34:57 svoj@mysql.com
Refuse to open MyISAM table with summary columns length bigger than
length of the record."
The problem is that the "offset" variable was removed (by Monty in the
rows-in-block patch). Monty will know how to merge that.
Guilhem will make sure to notify him.
*/
if (offset > share->base.reclength)
{
/* purecov: begin inspected */
my_errno= HA_ERR_CRASHED;
goto err;
/* purecov: end */
}
#endif /* ASKMONTY */
if (_ma_open_datafile(&info, share, -1))
goto err;
......@@ -465,6 +497,22 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
_ma_setup_functions(share);
if ((*share->once_init)(share, info.dfile))
goto err;
if (open_flags & HA_OPEN_MMAP)
{
info.s= share;
if (_ma_dynmap_file(&info, share->state.state.data_file_length))
{
/* purecov: begin inspected */
/* Ignore if mmap fails. Use file I/O instead. */
DBUG_PRINT("warning", ("mmap failed: errno: %d", errno));
/* purecov: end */
}
else
{
share->file_read= _ma_mmap_pread;
share->file_write= _ma_mmap_pwrite;
}
}
share->is_log_table= FALSE;
#ifdef THREAD
thr_lock_init(&share->lock);
......@@ -491,6 +539,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
share->lock.get_status=_ma_get_status;
share->lock.copy_status=_ma_copy_status;
share->lock.update_status=_ma_update_status;
share->lock.restore_status=_ma_restore_status;
share->lock.check_status=_ma_check_status;
}
}
......
......@@ -20,7 +20,10 @@
#define IS_CHAR ((uint) 32768) /* Bit if char (not offset) in tree */
#if INT_MAX > 65536L
/* Some definitions to keep in sync with maria_pack.c */
#define HEAD_LENGTH 32 /* Length of fixed header */
#if INT_MAX > 32767
#define BITS_SAVED 32
#define MAX_QUICK_TABLE_BITS 9 /* Because we may shift in 24 bits */
#else
......@@ -42,6 +45,7 @@
{ bits-=(bit+1); break; } \
pos+= *pos
/* Size in uint16 of a Huffman tree for byte compression of 256 byte values. */
#define OFFSET_TABLE_SIZE 512
static my_bool _ma_read_pack_info(MARIA_SHARE *share, File file,
......@@ -169,7 +173,7 @@ static my_bool _ma_read_pack_info(MARIA_SHARE *share, File file,
uint16 *decode_table,*tmp_buff;
ulong elements,intervall_length;
char *disk_cache,*intervall_buff;
uchar header[32];
uchar header[HEAD_LENGTH];
MARIA_BIT_BUFF bit_buff;
DBUG_ENTER("_ma_read_pack_info");
......@@ -185,12 +189,13 @@ static my_bool _ma_read_pack_info(MARIA_SHARE *share, File file,
my_errno=HA_ERR_END_OF_FILE;
goto err0;
}
/* Only the first three bytes of magic number are independent of version. */
if (memcmp((byte*) header, (byte*) maria_pack_file_magic, 3))
{
my_errno=HA_ERR_WRONG_IN_RECORD;
goto err0;
}
share->pack.version= header[3];
share->pack.version= header[3]; /* fourth byte of magic number */
share->pack.header_length= uint4korr(header+4);
share->min_pack_length=(uint) uint4korr(header+8);
share->max_pack_length=(uint) uint4korr(header+12);
......@@ -206,7 +211,23 @@ static my_bool _ma_read_pack_info(MARIA_SHARE *share, File file,
share->base.min_block_length=share->min_pack_length+1;
if (share->min_pack_length > 254)
share->base.min_block_length+=2;
DBUG_PRINT("info", ("fixed header length: %u", HEAD_LENGTH));
DBUG_PRINT("info", ("total header length: %lu", share->pack.header_length));
DBUG_PRINT("info", ("pack file version: %u", share->pack.version));
DBUG_PRINT("info", ("min pack length: %lu", share->min_pack_length));
DBUG_PRINT("info", ("max pack length: %lu", share->max_pack_length));
DBUG_PRINT("info", ("elements of all trees: %lu", elements));
DBUG_PRINT("info", ("distinct values bytes: %lu", intervall_length));
DBUG_PRINT("info", ("number of code trees: %u", trees));
DBUG_PRINT("info", ("bytes for record lgt: %u", share->pack.ref_length));
DBUG_PRINT("info", ("record pointer length: %u", rec_reflength));
/*
Memory segment #1:
- Decode tree heads
- Distinct column values
*/
if (!(share->decode_trees=(MARIA_DECODE_TREE*)
my_malloc((uint) (trees*sizeof(MARIA_DECODE_TREE)+
intervall_length*sizeof(byte)),
......@@ -214,10 +235,18 @@ static my_bool _ma_read_pack_info(MARIA_SHARE *share, File file,
goto err0;
intervall_buff=(byte*) (share->decode_trees+trees);
/*
Memory segment #2:
- Decode tables
- Quick decode tables
- Temporary decode table
- Compressed data file header cache
This segment will be reallocated after construction of the tables.
*/
length=(uint) (elements*2+trees*(1 << maria_quick_table_bits));
if (!(share->decode_tables=(uint16*)
my_malloc((length+OFFSET_TABLE_SIZE)*sizeof(uint16)+
(uint) (share->pack.header_length+7),
(uint) (share->pack.header_length - sizeof(header)),
MYF(MY_WME | MY_ZEROFILL))))
goto err1;
tmp_buff=share->decode_tables+length;
......@@ -240,17 +269,26 @@ static my_bool _ma_read_pack_info(MARIA_SHARE *share, File file,
share->rec[i].huff_tree=share->decode_trees+(uint) get_bits(&bit_buff,
huff_tree_bits);
share->rec[i].unpack= get_unpack_function(share->rec+i);
DBUG_PRINT("info", ("col: %2u type: %2u pack: %u slbits: %2u",
i, share->rec[i].base_type, share->rec[i].pack_type,
share->rec[i].space_length_bits));
}
skip_to_next_byte(&bit_buff);
/*
Construct the decoding tables from the file header. Keep track of
the used memory.
*/
decode_table=share->decode_tables;
for (i=0 ; i < trees ; i++)
if (read_huff_table(&bit_buff,share->decode_trees+i,&decode_table,
&intervall_buff,tmp_buff))
goto err3;
/* Reallocate the decoding tables to the used size. */
decode_table=(uint16*)
my_realloc((gptr) share->decode_tables,
(uint) ((byte*) decode_table - (byte*) share->decode_tables),
MYF(MY_HOLD_ON_ERROR));
/* Fix the table addresses in the tree heads. */
{
long diff=PTR_BYTE_DIFF(decode_table,share->decode_tables);
share->decode_tables=decode_table;
......@@ -296,8 +334,23 @@ static my_bool _ma_read_pack_info(MARIA_SHARE *share, File file,
}
/* Read on huff-code-table from datafile */
/*
Read a huff-code-table from datafile.
SYNOPSIS
read_huff_table()
bit_buff Bit buffer pointing at start of the
decoding table in the file header cache.
decode_tree Pointer to the decode tree head.
decode_table IN/OUT Address of a pointer to the next free space.
intervall_buff IN/OUT Address of a pointer to the next unused values.
tmp_buff Buffer for temporary extraction of a full
decoding table as read from bit_buff.
RETURN
0 OK.
1 Error.
*/
static uint read_huff_table(MARIA_BIT_BUFF *bit_buff,
MARIA_DECODE_TREE *decode_tree,
uint16 **decode_table, byte **intervall_buff,
......@@ -306,19 +359,33 @@ static uint read_huff_table(MARIA_BIT_BUFF *bit_buff,
uint min_chr,elements,char_bits,offset_bits,size,intervall_length,table_bits,
next_free_offset;
uint16 *ptr,*end;
DBUG_ENTER("read_huff_table");
LINT_INIT(ptr);
if (!get_bits(bit_buff,1))
{
/* Byte value compression. */
min_chr=get_bits(bit_buff,8);
elements=get_bits(bit_buff,9);
char_bits=get_bits(bit_buff,5);
offset_bits=get_bits(bit_buff,5);
intervall_length=0;
ptr=tmp_buff;
ptr=tmp_buff;
DBUG_PRINT("info", ("byte value compression"));
DBUG_PRINT("info", ("minimum byte value: %u", min_chr));
DBUG_PRINT("info", ("number of tree nodes: %u", elements));
DBUG_PRINT("info", ("bits for values: %u", char_bits));
DBUG_PRINT("info", ("bits for tree offsets: %u", offset_bits));
if (elements > 256)
{
DBUG_PRINT("error", ("ERROR: illegal number of tree elements: %u",
elements));
DBUG_RETURN(1);
}
}
else
{
/* Distinct column value compression. */
min_chr=0;
elements=get_bits(bit_buff,15);
intervall_length=get_bits(bit_buff,16);
......@@ -326,13 +393,28 @@ static uint read_huff_table(MARIA_BIT_BUFF *bit_buff,
offset_bits=get_bits(bit_buff,5);
decode_tree->quick_table_bits=0;
ptr= *decode_table;
DBUG_PRINT("info", ("distinct column value compression"));
DBUG_PRINT("info", ("number of tree nodes: %u", elements));
DBUG_PRINT("info", ("value buffer length: %u", intervall_length));
DBUG_PRINT("info", ("bits for value index: %u", char_bits));
DBUG_PRINT("info", ("bits for tree offsets: %u", offset_bits));
}
size=elements*2-2;
DBUG_PRINT("info", ("tree size in uint16: %u", size));
DBUG_PRINT("info", ("tree size in bytes: %u",
size * (uint) sizeof(uint16)));
for (end=ptr+size ; ptr < end ; ptr++)
{
if (get_bit(bit_buff))
{
*ptr= (uint16) get_bits(bit_buff,offset_bits);
if ((ptr + *ptr >= end) || !*ptr)
{
DBUG_PRINT("error", ("ERROR: illegal pointer in decode tree"));
DBUG_RETURN(1);
}
}
else
*ptr= (uint16) (IS_CHAR + (get_bits(bit_buff,char_bits) + min_chr));
}
......@@ -342,11 +424,15 @@ static uint read_huff_table(MARIA_BIT_BUFF *bit_buff,
decode_tree->intervalls= *intervall_buff;
if (! intervall_length)
{
table_bits=find_longest_bitstream(tmp_buff, tmp_buff+OFFSET_TABLE_SIZE);
if (table_bits == (uint) ~0)
return 1;
/* Byte value compression. ptr started from tmp_buff. */
/* Find longest Huffman code from begin to end of tree in bits. */
table_bits= find_longest_bitstream(tmp_buff, ptr);
if (table_bits >= OFFSET_TABLE_SIZE)
DBUG_RETURN(1);
if (table_bits > maria_quick_table_bits)
table_bits=maria_quick_table_bits;
DBUG_PRINT("info", ("table bits: %u", table_bits));
next_free_offset= (1 << table_bits);
make_quick_table(*decode_table,tmp_buff,&next_free_offset,0,table_bits,
table_bits);
......@@ -355,96 +441,265 @@ static uint read_huff_table(MARIA_BIT_BUFF *bit_buff,
}
else
{
/* Distinct column value compression. ptr started from *decode_table */
(*decode_table)=end;
/*
get_bits() moves some bytes to a cache buffer in advance. May need
to step back.
*/
bit_buff->pos-= bit_buff->bits/8;
/* Copy the distinct column values from the buffer. */
memcpy(*intervall_buff,bit_buff->pos,(size_t) intervall_length);
(*intervall_buff)+=intervall_length;
bit_buff->pos+=intervall_length;
bit_buff->bits=0;
}
return 0;
DBUG_RETURN(0);
}
/*
Make a quick_table for faster decoding.
SYNOPSIS
make_quick_table()
to_table Target quick_table and remaining decode table.
decode_table Source Huffman (sub-)tree within tmp_buff.
next_free_offset IN/OUT Next free offset from to_table.
Starts behind quick_table on the top-level.
value Huffman bits found so far.
bits Remaining bits to be collected.
max_bits Total number of bits to collect (table_bits).
DESCRIPTION
The quick table is an array of 16-bit values. There exists one value
for each possible code representable by max_bits (table_bits) bits.
In most cases table_bits is 9. So there are 512 16-bit values.
If the high-order bit (16) is set (IS_CHAR) then the array slot for
this value is a valid Huffman code for a resulting byte value.
The low-order 8 bits (1..8) are the resulting byte value.
Bits 9..14 are the length of the Huffman code for this byte value.
This means so many bits from the input stream were needed to
represent this byte value. The remaining bits belong to later
Huffman codes. This also means that for every Huffman code shorter
than table_bits there are multiple entires in the array, which
differ just in the unused bits.
If the high-order bit (16) is clear (0) then the remaining bits are
the position of the remaining Huffman decode tree segment behind the
quick table.
RETURN
void
*/
static void make_quick_table(uint16 *to_table, uint16 *decode_table,
uint *next_free_offset, uint value, uint bits,
uint max_bits)
{
DBUG_ENTER("make_quick_table");
/*
When down the table to the requested maximum, copy the rest of the
Huffman table.
*/
if (!bits--)
{
/*
Remaining left Huffman tree segment starts behind quick table.
Remaining right Huffman tree segment starts behind left segment.
*/
to_table[value]= (uint16) *next_free_offset;
/*
Re-construct the remaining Huffman tree segment at
next_free_offset in to_table.
*/
*next_free_offset=copy_decode_table(to_table, *next_free_offset,
decode_table);
return;
DBUG_VOID_RETURN;
}
/* Descent on the left side. Left side bits are clear (0). */
if (!(*decode_table & IS_CHAR))
{
/* Not a leaf. Follow the pointer. */
make_quick_table(to_table,decode_table+ *decode_table,
next_free_offset,value,bits,max_bits);
}
else
{
/*
A leaf. A Huffman code is complete. Fill the quick_table
array for all possible bit strings starting with this Huffman
code.
*/
fill_quick_table(to_table+value,bits,max_bits,(uint) *decode_table);
}
/* Descent on the right side. Right side bits are set (1). */
decode_table++;
value|= (1 << bits);
if (!(*decode_table & IS_CHAR))
{
/* Not a leaf. Follow the pointer. */
make_quick_table(to_table,decode_table+ *decode_table,
next_free_offset,value,bits,max_bits);
}
else
{
/*
A leaf. A Huffman code is complete. Fill the quick_table
array for all possible bit strings starting with this Huffman
code.
*/
fill_quick_table(to_table+value,bits,max_bits,(uint) *decode_table);
return;
}
DBUG_VOID_RETURN;
}
/*
Fill quick_table for all possible values starting with this Huffman code.
SYNOPSIS
fill_quick_table()
table Target quick_table position.
bits Unused bits from max_bits.
max_bits Total number of bits to collect (table_bits).
value The byte encoded by the found Huffman code.
DESCRIPTION
Fill the segment (all slots) of the quick_table array with the
resulting value for the found Huffman code. There are as many slots
as there are combinations representable by the unused bits.
In most cases we use 9 table bits. Assume a 3-bit Huffman code. Then
there are 6 unused bits. Hence we fill 2**6 = 64 slots with the
value.
RETURN
void
*/
static void fill_quick_table(uint16 *table, uint bits, uint max_bits,
uint value)
{
uint16 *end;
value|=(max_bits-bits) << 8;
for (end=table+ (1 << bits) ;
table < end ;
*table++ = (uint16) value | IS_CHAR) ;
DBUG_ENTER("fill_quick_table");
/*
Bits 1..8 of value represent the decoded byte value.
Bits 9..14 become the length of the Huffman code for this byte value.
Bit 16 flags a valid code (IS_CHAR).
*/
value|= (max_bits - bits) << 8 | IS_CHAR;
for (end= table + (uint) (((uint) 1 << bits)); table < end; table++)
{
*table= (uint16) value;
}
DBUG_VOID_RETURN;
}
/*
Reconstruct a decode subtree at the target position.
SYNOPSIS
copy_decode_table()
to_pos Target quick_table and remaining decode table.
offset Next free offset from to_pos.
decode_table Source Huffman subtree within tmp_buff.
NOTE
Pointers in the decode tree are relative to the pointers position.
RETURN
next free offset from to_pos.
*/
static uint copy_decode_table(uint16 *to_pos, uint offset,
uint16 *decode_table)
{
uint prev_offset;
prev_offset= offset;
uint prev_offset= offset;
DBUG_ENTER("copy_decode_table");
/* Descent on the left side. */
if (!(*decode_table & IS_CHAR))
{
/* Set a pointer to the next target node. */
to_pos[offset]=2;
/* Copy the left hand subtree there. */
offset=copy_decode_table(to_pos,offset+2,decode_table+ *decode_table);
}
else
{
/* Copy the byte value. */
to_pos[offset]= *decode_table;
/* Step behind this node. */
offset+=2;
}
decode_table++;
/* Descent on the right side. */
decode_table++;
if (!(*decode_table & IS_CHAR))
{
/* Set a pointer to the next free target node. */
to_pos[prev_offset+1]=(uint16) (offset-prev_offset-1);
/* Copy the right hand subtree to the entry of that node. */
offset=copy_decode_table(to_pos,offset,decode_table+ *decode_table);
}
else
{
/* Copy the byte value. */
to_pos[prev_offset+1]= *decode_table;
return offset;
}
DBUG_RETURN(offset);
}
/*
Find the length of the longest Huffman code in this table in bits.
SYNOPSIS
find_longest_bitstream()
table Code (sub-)table start.
end End of code table.
IMPLEMENTATION
Recursively follow the branch(es) of the code pair on every level of
the tree until two byte values (and no branch) are found. Add one to
each level when returning back from each recursion stage.
'end' is used for error checking only. A clean tree terminates
before reaching 'end'. Hence the exact value of 'end' is not too
important. However having it higher than necessary could lead to
misbehaviour should 'next' jump into the dirty area.
RETURN
length Length of longest Huffman code in bits.
>= OFFSET_TABLE_SIZE Error, broken tree. It does not end before 'end'.
*/
static uint find_longest_bitstream(uint16 *table, uint16 *end)
{
uint length=1,length2;
uint length=1;
uint length2;
if (!(*table & IS_CHAR))
{
uint16 *next= table + *table;
if (next > end || next == table)
return ~0;
{
DBUG_PRINT("error", ("ERROR: illegal pointer in decode tree"));
return OFFSET_TABLE_SIZE;
}
length=find_longest_bitstream(next, end)+1;
}
table++;
......@@ -452,8 +707,11 @@ static uint find_longest_bitstream(uint16 *table, uint16 *end)
{
uint16 *next= table + *table;
if (next > end || next == table)
return ~0;
length2=find_longest_bitstream(table+ *table, end)+1;
{
DBUG_PRINT("error", ("ERROR: illegal pointer in decode tree"));
return OFFSET_TABLE_SIZE;
}
length2= find_longest_bitstream(next, end) + 1;
length=max(length,length2);
}
return length;
......@@ -901,18 +1159,46 @@ static void decode_bytes(MARIA_COLUMNDEF *rec,MARIA_BIT_BUFF *bit_buff,
bit_buff->pos+=4;
bits+=32;
}
/* First use info in quick_table */
/*
First use info in quick_table.
The quick table is an array of 16-bit values. There exists one
value for each possible code representable by table_bits bits.
In most cases table_bits is 9. So there are 512 16-bit values.
If the high-order bit (16) is set (IS_CHAR) then the array slot
for this value is a valid Huffman code for a resulting byte value.
The low-order 8 bits (1..8) are the resulting byte value.
Bits 9..14 are the length of the Huffman code for this byte value.
This means so many bits from the input stream were needed to
represent this byte value. The remaining bits belong to later
Huffman codes. This also means that for every Huffman code shorter
than table_bits there are multiple entires in the array, which
differ just in the unused bits.
If the high-order bit (16) is clear (0) then the remaining bits are
the position of the remaining Huffman decode tree segment behind the
quick table.
*/
low_byte=(uint) (bit_buff->current_byte >> (bits - table_bits)) & table_and;
low_byte=decode_tree->table[low_byte];
if (low_byte & IS_CHAR)
{
/*
All Huffman codes of less or equal table_bits length are in the
quick table. This is one of them.
*/
*to++ = (char) (low_byte & 255); /* Found char in quick table */
bits-= ((low_byte >> 8) & 31); /* Remove bits used */
}
else
{ /* Map through rest of decode-table */
/* This means that the Huffman code must be longer than table_bits. */
pos=decode_tree->table+low_byte;
bits-=table_bits;
/* NOTE: decode_bytes_test_bit() is a macro wich contains a break !!! */
for (;;)
{
low_byte=(uint) (bit_buff->current_byte >> (bits-8));
......@@ -1140,6 +1426,11 @@ uint _ma_pack_get_block_info(MARIA_HA *maria, MARIA_BIT_BUFF *bit_buff,
{
head_length+= read_pack_length((uint) maria->s->pack.version,
header + head_length, &info->blob_len);
/*
Ensure that the record buffer is big enough for the compressed
record plus all expanded blobs. [We do not have an extra buffer
for the resulting blobs. Sigh.]
*/
if (_ma_alloc_buffer(rec_buff_p, rec_buff_size_p,
info->rec_len + info->blob_len +
maria->s->base.extra_rec_buff_size))
......
......@@ -170,6 +170,7 @@ static double _ma_search_pos(register MARIA_HA *info,
byte *keypos, *buff;
double offset;
DBUG_ENTER("_ma_search_pos");
LINT_INIT(max_keynr);
if (pos == HA_OFFSET_ERROR)
DBUG_RETURN(0.5);
......
......@@ -33,7 +33,7 @@ int maria_rename(const char *old_name, const char *new_name)
_ma_check_table_is_closed(old_name,"rename old_table");
_ma_check_table_is_closed(new_name,"rename new table2");
#endif
/* LOCKTODO take X-lock on table here */
/* LOCK TODO take X-lock on table here */
#ifdef USE_RAID
{
MARIA_HA *info;
......@@ -51,7 +51,7 @@ int maria_rename(const char *old_name, const char *new_name)
fn_format(from,old_name,"",MARIA_NAME_IEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT);
fn_format(to,new_name,"",MARIA_NAME_IEXT,MY_UNPACK_FILENAME|MY_APPEND_EXT);
/*
RECOVERYTODO log the two renames below. Update
RECOVERY TODO log the two renames below. Update
ZeroDirtyPagesLSN of the table on disk (=> sync the files), this is
needed so that Recovery does not pick a wrong table.
Then do the file renames.
......
......@@ -637,8 +637,6 @@ static int maria_rtree_insert_level(MARIA_HA *info, uint keynr, byte *key,
if ((old_root = info->s->state.key_root[keynr]) == HA_OFFSET_ERROR)
{
int res;
if ((old_root = _ma_new(info, keyinfo, DFLT_INIT_HITS)) == HA_OFFSET_ERROR)
return -1;
info->keybuff_used = 1;
......@@ -929,7 +927,6 @@ int maria_rtree_delete(MARIA_HA *info, uint keynr, byte *key, uint key_length)
ulong i;
for (i = 0; i < ReinsertList.n_pages; ++i)
{
uint nod_flag;
byte *page_buf, *k, *last;
if (!(page_buf = (byte*) my_alloca((uint)keyinfo->block_length)))
......
......@@ -188,6 +188,10 @@ static int split_maria_rtree_node(SplitStruct *node, int n_entries,
int next_node;
int i;
SplitStruct *end = node + n_entries;
LINT_INIT(a);
LINT_INIT(b);
LINT_INIT(next);
LINT_INIT(next_node);
if (all_size < min_size * 2)
{
......
......@@ -477,9 +477,9 @@ int _ma_prefix_search(MARIA_HA *info, register MARIA_KEYDEF *keyinfo,
else
{
/* We have to compare k and vseg as if they were space extended */
uchar *end= k+ (cmplen - len);
for ( ; k < end && *k == ' '; k++) ;
if (k == end)
uchar *k_end= k+ (cmplen - len);
for ( ; k < k_end && *k == ' '; k++) ;
if (k == k_end)
goto cmp_rest; /* should never happen */
if ((uchar) *k < (uchar) ' ')
{
......@@ -491,15 +491,15 @@ int _ma_prefix_search(MARIA_HA *info, register MARIA_KEYDEF *keyinfo,
}
else if (len > cmplen)
{
uchar *end;
uchar *vseg_end;
if ((nextflag & SEARCH_PREFIX) && key_len_left == 0)
goto fix_flag;
/* We have to compare k and vseg as if they were space extended */
for (end=vseg + (len-cmplen) ;
vseg < end && *vseg == (byte) ' ';
for (vseg_end= vseg + (len-cmplen) ;
vseg < vseg_end && *vseg == (byte) ' ';
vseg++, matched++) ;
DBUG_ASSERT(vseg < end);
DBUG_ASSERT(vseg < vseg_end);
if ((uchar) *vseg > (uchar) ' ')
{
......
......@@ -221,9 +221,9 @@ int _ma_create_index_by_sort(MARIA_SORT_PARAM *info, my_bool no_messages,
if (my_b_inited(&tempfile_for_exceptions))
{
MARIA_HA *index=info->sort_info->info;
MARIA_HA *idx=info->sort_info->info;
uint keyno=info->key;
uint key_length, ref_length=index->s->rec_reflength;
uint key_length, ref_length=idx->s->rec_reflength;
if (!no_messages)
printf(" - Adding exceptions\n"); /* purecov: tested */
......@@ -236,7 +236,7 @@ int _ma_create_index_by_sort(MARIA_SORT_PARAM *info, my_bool no_messages,
&& !my_b_read(&tempfile_for_exceptions,(byte*)sort_keys,
(uint) key_length))
{
if (_ma_ck_write(index,keyno,(byte*) sort_keys,key_length-ref_length))
if (_ma_ck_write(idx,keyno,(byte*) sort_keys,key_length-ref_length))
goto err;
}
}
......
......@@ -206,7 +206,8 @@ int maria_update(register MARIA_HA *info, const byte *oldrec, byte *newrec)
err:
DBUG_PRINT("error",("key: %d errno: %d",i,my_errno));
save_errno=my_errno;
if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_RECORD_FILE_FULL)
if (my_errno == HA_ERR_FOUND_DUPP_KEY || my_errno == HA_ERR_OUT_OF_MEM ||
my_errno == HA_ERR_RECORD_FILE_FULL)
{
info->errkey= (int) i;
flag=0;
......
......@@ -205,7 +205,8 @@ int maria_write(MARIA_HA *info, byte *record)
fatal_error= 0;
if (my_errno == HA_ERR_FOUND_DUPP_KEY ||
my_errno == HA_ERR_RECORD_FILE_FULL ||
my_errno == HA_ERR_NULL_IN_SPATIAL)
my_errno == HA_ERR_NULL_IN_SPATIAL ||
my_errno == HA_ERR_OUT_OF_MEM)
{
if (info->bulk_insert)
{
......@@ -629,6 +630,7 @@ int _ma_split_page(register MARIA_HA *info, register MARIA_KEYDEF *keyinfo,
my_off_t new_pos;
MARIA_KEY_PARAM s_temp;
DBUG_ENTER("maria_split_page");
LINT_INIT(after_key);
DBUG_DUMP("buff",(byte*) buff,maria_getint(buff));
if (info->s->keyinfo+info->lastinx == keyinfo)
......
......@@ -727,6 +727,7 @@ get_one_option(int optid,
case 2:
method_conv= MI_STATS_METHOD_IGNORE_NULLS;
break;
default: assert(0); /* Impossible */
}
check_param.stats_method= method_conv;
break;
......
......@@ -817,6 +817,7 @@ my_bool _ma_unique_comp(MARIA_UNIQUEDEF *def, const byte *a, const byte *b,
my_bool null_are_equal);
void _ma_get_status(void *param, int concurrent_insert);
void _ma_update_status(void *param);
void _ma_restore_status(void *param);
void _ma_copy_status(void *to, void *from);
my_bool _ma_check_status(void *param);
......
......@@ -2696,8 +2696,9 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
}
case FIELD_VARCHAR:
{
uint pack_length= HA_VARCHAR_PACKLENGTH(count->field_length-1);
ulong col_length= (pack_length == 1 ? (uint) *(uchar*) start_pos :
uint var_pack_length= HA_VARCHAR_PACKLENGTH(count->field_length-1);
ulong col_length= (var_pack_length == 1 ?
(uint) *(uchar*) start_pos :
uint2korr(start_pos));
/* Empty varchar are encoded with a single 1 bit. */
if (!col_length)
......@@ -2707,7 +2708,7 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
}
else
{
byte *end=start_pos+pack_length+col_length;
byte *end= start_pos + var_pack_length + col_length;
DBUG_PRINT("fields", ("FIELD_VARCHAR not empty, bits: 1"));
write_bits(0,1);
/* Write the varchar length. */
......@@ -2715,7 +2716,7 @@ static int compress_isam_file(PACK_MRG_INFO *mrg, HUFF_COUNTS *huff_counts)
col_length, count->length_bits));
write_bits(col_length,count->length_bits);
/* Encode the varchar bytes. */
for (start_pos+=pack_length ; start_pos < end ; start_pos++)
for (start_pos+= var_pack_length ; start_pos < end ; start_pos++)
{
DBUG_PRINT("fields",
("value: 0x%02x code: 0x%s bits: %2u bin: %s",
......
......@@ -21,7 +21,7 @@ static PAGECACHE_FILE file1;
int main(int argc, char *argv[])
{
uint pagen;
uchar long_tr_id[6];
byte long_tr_id[6];
PAGECACHE pagecache;
LSN lsn;
MY_STAT st, *stat;
......
......@@ -293,7 +293,7 @@ int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out,
Check for underlying table conformance
SYNOPSIS
check_definition()
myisam_check_definition()
t1_keyinfo in First table key definition
t1_recinfo in First table record definition
t1_keys in Number of keys in first table
......@@ -323,13 +323,13 @@ int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out,
1 - Different definitions.
*/
int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
int myisam_check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
uint t1_keys, uint t1_recs,
MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
uint t2_keys, uint t2_recs, bool strict)
{
uint i, j;
DBUG_ENTER("check_definition");
DBUG_ENTER("myisam_check_definition");
if ((strict ? t1_keys != t2_keys : t1_keys > t2_keys))
{
DBUG_PRINT("error", ("Number of keys differs: t1_keys=%u, t2_keys=%u",
......
......@@ -48,9 +48,11 @@ static const char *ha_myisammrg_exts[] = {
};
extern int table2myisam(TABLE *table_arg, MI_KEYDEF **keydef_out,
MI_COLUMNDEF **recinfo_out, uint *records_out);
extern int check_definition(MI_KEYDEF *t1_keyinfo, MI_COLUMNDEF *t1_recinfo,
extern int myisam_check_definition(MI_KEYDEF *t1_keyinfo,
MI_COLUMNDEF *t1_recinfo,
uint t1_keys, uint t1_recs,
MI_KEYDEF *t2_keyinfo, MI_COLUMNDEF *t2_recinfo,
MI_KEYDEF *t2_keyinfo,
MI_COLUMNDEF *t2_recinfo,
uint t2_keys, uint t2_recs, bool strict);
const char **ha_myisammrg::bas_ext() const
......@@ -115,7 +117,7 @@ int ha_myisammrg::open(const char *name, int mode, uint test_if_locked)
}
for (u_table= file->open_tables; u_table < file->end_table; u_table++)
{
if (check_definition(keyinfo, recinfo, keys, recs,
if (myisam_check_definition(keyinfo, recinfo, keys, recs,
u_table->table->s->keyinfo, u_table->table->s->rec,
u_table->table->s->base.keys,
u_table->table->s->base.fields, false))
......
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