mariadb/myisam/mi_packrec.c
unknown d01f2efebf Portability fixes.
Let myisamchk generate a new checksum for compressed data.
Don't unconditionally force filenames to lower case on windows.
Update mysqltest to match 4.0 source (to get some of the new bug fixes into 3.23)


Docs/manual.texi:
  Link changes, and new comments about IA64 and about Sun workshop
client/mysqltest.c:
  Updated this to match the 4.0 source
include/config-win.h:
  Don't unconditionally force filenames to lower case on windows.
innobase/include/ut0ut.h:
  Portability fix
myisam/mi_cache.c:
  Fix problem where reported error number was -1
myisam/mi_check.c:
  Let myisamchk generate a new checksum for compressed data.
myisam/mi_packrec.c:
  Cleanup
myisam/myisamchk.c:
  Report checksum for compressed tables
mysql-test/t/bdb.test:
  Fix to match new mysqltest
mysql-test/t/err000001.test:
  Fix to match new mysqltest
mysql-test/t/fulltext.test:
  Fix to match new mysqltest
mysql-test/t/innodb.test:
  Fix to match new mysqltest
mysql-test/t/overflow.test:
  Fix to match new mysqltest
sql/ha_gemini.cc:
  Fix false -> FALSE
sql/share/estonian/errmsg.txt:
  Updated of translation
sql/share/swedish/errmsg.txt:
  Updated of translation
sql/sql_parse.cc:
  Don't unconditionally force filenames to lower case on windows.
sql/sql_table.cc:
  Don't unconditionally force filenames to lower case on windows.
sql/sql_test.cc:
  Write current directory when using 'mysqladmin debug'
strings/strto.c:
  Portability fix
strings/strtoll.c:
  Portability fix
strings/strtoul.c:
  Portability fix
strings/strtoull.c:
  Portability fix
2001-08-18 10:49:00 +03:00

1312 lines
35 KiB
C

/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* Functions to compressed records */
#include "myisamdef.h"
#define IS_CHAR ((uint) 32768) /* Bit if char (not offset) in tree */
#if INT_MAX > 65536L
#define BITS_SAVED 32
#define MAX_QUICK_TABLE_BITS 9 /* Because we may shift in 24 bits */
#else
#define BITS_SAVED 16
#define MAX_QUICK_TABLE_BITS 6
#endif
#define get_bit(BU) ((BU)->bits ? \
(BU)->current_byte & ((mi_bit_type) 1 << --(BU)->bits) :\
(fill_buffer(BU), (BU)->bits= BITS_SAVED-1,\
(BU)->current_byte & ((mi_bit_type) 1 << (BITS_SAVED-1))))
#define skipp_to_next_byte(BU) ((BU)->bits&=~7)
#define get_bits(BU,count) (((BU)->bits >= count) ? (((BU)->current_byte >> ((BU)->bits-=count)) & mask[count]) : fill_and_get_bits(BU,count))
#define decode_bytes_test_bit(bit) \
if (low_byte & (1 << (7-bit))) \
pos++; \
if (*pos & IS_CHAR) \
{ bits-=(bit+1); break; } \
pos+= *pos
static void read_huff_table(MI_BIT_BUFF *bit_buff,MI_DECODE_TREE *decode_tree,
uint16 **decode_table,byte **intervall_buff,
uint16 *tmp_buff);
static void make_quick_table(uint16 *to_table,uint16 *decode_table,
uint *next_free,uint value,uint bits,
uint max_bits);
static void fill_quick_table(uint16 *table,uint bits, uint max_bits,
uint value);
static uint copy_decode_table(uint16 *to_pos,uint offset,
uint16 *decode_table);
static uint find_longest_bitstream(uint16 *table);
static void (*get_unpack_function(MI_COLUMNDEF *rec))(MI_COLUMNDEF *field,
MI_BIT_BUFF *buff,
uchar *to,
uchar *end);
static void uf_zerofill_skipp_zero(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to,uchar *end);
static void uf_skipp_zero(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to,uchar *end);
static void uf_space_normal(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to,uchar *end);
static void uf_space_endspace_selected(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to, uchar *end);
static void uf_endspace_selected(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to,uchar *end);
static void uf_space_endspace(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to,uchar *end);
static void uf_endspace(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to,uchar *end);
static void uf_space_prespace_selected(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to, uchar *end);
static void uf_prespace_selected(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to,uchar *end);
static void uf_space_prespace(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to,uchar *end);
static void uf_prespace(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to,uchar *end);
static void uf_zerofill_normal(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to,uchar *end);
static void uf_constant(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to,uchar *end);
static void uf_intervall(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to,uchar *end);
static void uf_zero(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to,uchar *end);
static void uf_blob(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
uchar *to, uchar *end);
static void uf_varchar(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
uchar *to, uchar *end);
static void decode_bytes(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,
uchar *to,uchar *end);
static uint decode_pos(MI_BIT_BUFF *bit_buff,MI_DECODE_TREE *decode_tree);
static void init_bit_buffer(MI_BIT_BUFF *bit_buff,uchar *buffer,uint length);
static uint fill_and_get_bits(MI_BIT_BUFF *bit_buff,uint count);
static void fill_buffer(MI_BIT_BUFF *bit_buff);
static uint max_bit(uint value);
#ifdef HAVE_MMAP
static uchar *_mi_mempack_get_block_info(MI_INFO *myisam,MI_BLOCK_INFO *info,
uchar *header);
#endif
static mi_bit_type mask[]=
{
0x00000000,
0x00000001, 0x00000003, 0x00000007, 0x0000000f,
0x0000001f, 0x0000003f, 0x0000007f, 0x000000ff,
0x000001ff, 0x000003ff, 0x000007ff, 0x00000fff,
0x00001fff, 0x00003fff, 0x00007fff, 0x0000ffff,
#if BITS_SAVED > 16
0x0001ffff, 0x0003ffff, 0x0007ffff, 0x000fffff,
0x001fffff, 0x003fffff, 0x007fffff, 0x00ffffff,
0x01ffffff, 0x03ffffff, 0x07ffffff, 0x0fffffff,
0x1fffffff, 0x3fffffff, 0x7fffffff, 0xffffffff,
#endif
};
/* Read all packed info, allocate memory and fix field structs */
my_bool _mi_read_pack_info(MI_INFO *info, pbool fix_keys)
{
File file;
int diff_length;
uint i,trees,huff_tree_bits,rec_reflength,length;
uint16 *decode_table,*tmp_buff;
ulong elements,intervall_length;
char *disk_cache,*intervall_buff;
uchar header[32];
MYISAM_SHARE *share=info->s;
MI_BIT_BUFF bit_buff;
DBUG_ENTER("_mi_read_pack_info");
if (myisam_quick_table_bits < 4)
myisam_quick_table_bits=4;
else if (myisam_quick_table_bits > MAX_QUICK_TABLE_BITS)
myisam_quick_table_bits=MAX_QUICK_TABLE_BITS;
file=info->dfile;
my_errno=0;
if (my_read(file,(byte*) header,sizeof(header),MYF(MY_NABP)))
{
if (!my_errno)
my_errno=HA_ERR_END_OF_FILE;
DBUG_RETURN(1);
}
if (memcmp((byte*) header,(byte*) myisam_pack_file_magic,4))
{
my_errno=HA_ERR_WRONG_IN_RECORD;
DBUG_RETURN(1);
}
share->pack.header_length= uint4korr(header+4);
share->min_pack_length=(uint) uint4korr(header+8);
share->max_pack_length=(uint) uint4korr(header+12);
set_if_bigger(share->base.pack_reclength,share->max_pack_length);
elements=uint4korr(header+16);
intervall_length=uint4korr(header+20);
trees=uint2korr(header+24);
share->pack.ref_length=header[26];
rec_reflength=header[27];
diff_length=(int) rec_reflength - (int) share->base.rec_reflength;
if (fix_keys)
share->rec_reflength=rec_reflength;
share->base.min_block_length=share->min_pack_length+share->pack.ref_length;
if (!(share->decode_trees=(MI_DECODE_TREE*)
my_malloc((uint) (trees*sizeof(MI_DECODE_TREE)+
intervall_length*sizeof(byte)),
MYF(MY_WME))))
DBUG_RETURN(1);
intervall_buff=(byte*) (share->decode_trees+trees);
length=(uint) (elements*2+trees*(1 << myisam_quick_table_bits));
if (!(share->decode_tables=(uint16*)
my_malloc((length+512)*sizeof(uint16)+
(uint) (share->pack.header_length+7),
MYF(MY_WME | MY_ZEROFILL))))
{
my_free((gptr) share->decode_trees,MYF(0));
DBUG_RETURN(1);
}
tmp_buff=share->decode_tables+length;
disk_cache=(byte*) (tmp_buff+512);
if (my_read(file,disk_cache,
(uint) (share->pack.header_length-sizeof(header)),
MYF(MY_NABP)))
{
my_free((gptr) share->decode_trees,MYF(0));
my_free((gptr) share->decode_tables,MYF(0));
DBUG_RETURN(1);
}
huff_tree_bits=max_bit(trees ? trees-1 : 0);
init_bit_buffer(&bit_buff, (uchar*) disk_cache,
(uint) (share->pack.header_length-sizeof(header)));
/* Read new info for each field */
for (i=0 ; i < share->base.fields ; i++)
{
share->rec[i].base_type=(enum en_fieldtype) get_bits(&bit_buff,5);
share->rec[i].pack_type=(uint) get_bits(&bit_buff,6);
share->rec[i].space_length_bits=get_bits(&bit_buff,5);
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);
}
skipp_to_next_byte(&bit_buff);
decode_table=share->decode_tables;
for (i=0 ; i < trees ; i++)
read_huff_table(&bit_buff,share->decode_trees+i,&decode_table,
&intervall_buff,tmp_buff);
decode_table=(uint16*)
my_realloc((gptr) share->decode_tables,
(uint) ((byte*) decode_table - (byte*) share->decode_tables),
MYF(MY_HOLD_ON_ERROR));
{
long diff=PTR_BYTE_DIFF(decode_table,share->decode_tables);
share->decode_tables=decode_table;
for (i=0 ; i < trees ; i++)
share->decode_trees[i].table=ADD_TO_PTR(share->decode_trees[i].table,
diff,
uint16*);
}
/* Fix record-ref-length for keys */
if (fix_keys)
{
for (i=0 ; i < share->base.keys ; i++)
{
share->keyinfo[i].keylength+=(uint16) diff_length;
share->keyinfo[i].minlength+=(uint16) diff_length;
share->keyinfo[i].maxlength+=(uint16) diff_length;
share->keyinfo[i].seg[share->keyinfo[i].keysegs].length=
(uint16) rec_reflength;
}
}
if (bit_buff.error || bit_buff.pos < bit_buff.end)
{ /* info_length was wrong */
my_errno=HA_ERR_WRONG_IN_RECORD;
my_free((gptr) share->decode_trees,MYF(0));
my_free((gptr) share->decode_tables,MYF(0));
DBUG_RETURN(1);
}
DBUG_RETURN(0);
}
/* Read on huff-code-table from datafile */
static void read_huff_table(MI_BIT_BUFF *bit_buff, MI_DECODE_TREE *decode_tree,
uint16 **decode_table, byte **intervall_buff,
uint16 *tmp_buff)
{
uint min_chr,elements,char_bits,offset_bits,size,intervall_length,table_bits,
next_free_offset;
uint16 *ptr,*end;
LINT_INIT(ptr);
if (!get_bits(bit_buff,1))
{
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;
}
else
{
min_chr=0;
elements=get_bits(bit_buff,15);
intervall_length=get_bits(bit_buff,16);
char_bits=get_bits(bit_buff,5);
offset_bits=get_bits(bit_buff,5);
decode_tree->quick_table_bits=0;
ptr= *decode_table;
}
size=elements*2-2;
for (end=ptr+size ; ptr < end ; ptr++)
{
if (get_bit(bit_buff))
*ptr= (uint16) get_bits(bit_buff,offset_bits);
else
*ptr= (uint16) (IS_CHAR + (get_bits(bit_buff,char_bits) + min_chr));
}
skipp_to_next_byte(bit_buff);
decode_tree->table= *decode_table;
decode_tree->intervalls= *intervall_buff;
if (! intervall_length)
{
table_bits=find_longest_bitstream(tmp_buff);
if (table_bits > myisam_quick_table_bits)
table_bits=myisam_quick_table_bits;
next_free_offset= (1 << table_bits);
make_quick_table(*decode_table,tmp_buff,&next_free_offset,0,table_bits,
table_bits);
(*decode_table)+= next_free_offset;
decode_tree->quick_table_bits=table_bits;
}
else
{
(*decode_table)=end;
bit_buff->pos-= bit_buff->bits/8;
memcpy(*intervall_buff,bit_buff->pos,(size_t) intervall_length);
(*intervall_buff)+=intervall_length;
bit_buff->pos+=intervall_length;
bit_buff->bits=0;
}
return;
}
static void make_quick_table(uint16 *to_table, uint16 *decode_table,
uint *next_free_offset, uint value, uint bits,
uint max_bits)
{
if (!bits--)
{
to_table[value]= (uint16) *next_free_offset;
*next_free_offset=copy_decode_table(to_table, *next_free_offset,
decode_table);
return;
}
if (!(*decode_table & IS_CHAR))
{
make_quick_table(to_table,decode_table+ *decode_table,
next_free_offset,value,bits,max_bits);
}
else
fill_quick_table(to_table+value,bits,max_bits,(uint) *decode_table);
decode_table++;
value|= (1 << bits);
if (!(*decode_table & IS_CHAR))
{
make_quick_table(to_table,decode_table+ *decode_table,
next_free_offset,value,bits,max_bits);
}
else
fill_quick_table(to_table+value,bits,max_bits,(uint) *decode_table);
return;
}
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) ;
}
static uint copy_decode_table(uint16 *to_pos, uint offset,
uint16 *decode_table)
{
uint prev_offset;
prev_offset= offset;
if (!(*decode_table & IS_CHAR))
{
to_pos[offset]=2;
offset=copy_decode_table(to_pos,offset+2,decode_table+ *decode_table);
}
else
{
to_pos[offset]= *decode_table;
offset+=2;
}
decode_table++;
if (!(*decode_table & IS_CHAR))
{
to_pos[prev_offset+1]=(uint16) (offset-prev_offset-1);
offset=copy_decode_table(to_pos,offset,decode_table+ *decode_table);
}
else
to_pos[prev_offset+1]= *decode_table;
return offset;
}
static uint find_longest_bitstream(uint16 *table)
{
uint length=1,length2;
if (!(*table & IS_CHAR))
length=find_longest_bitstream(table+ *table)+1;
table++;
if (!(*table & IS_CHAR))
{
length2=find_longest_bitstream(table+ *table)+1;
length=max(length,length2);
}
return length;
}
/* Read record from datafile */
/* Returns length of packed record, -1 if error */
int _mi_read_pack_record(MI_INFO *info, my_off_t filepos, byte *buf)
{
MI_BLOCK_INFO block_info;
File file;
DBUG_ENTER("mi_read_pack_record");
if (filepos == HA_OFFSET_ERROR)
DBUG_RETURN(-1); /* _search() didn't find record */
file=info->dfile;
if (_mi_pack_get_block_info(info, &block_info, file, filepos,
info->rec_buff))
goto err;
if (my_read(file,(byte*) info->rec_buff + block_info.offset ,
block_info.rec_len - block_info.offset, MYF(MY_NABP)))
goto panic;
info->update|= HA_STATE_AKTIV;
DBUG_RETURN(_mi_pack_rec_unpack(info,buf,info->rec_buff,block_info.rec_len));
panic:
my_errno=HA_ERR_WRONG_IN_RECORD;
err:
DBUG_RETURN(-1);
}
int _mi_pack_rec_unpack(register MI_INFO *info, register byte *to, byte *from,
ulong reclength)
{
byte *end_field;
reg3 MI_COLUMNDEF *end;
MI_COLUMNDEF *current_field;
MYISAM_SHARE *share=info->s;
DBUG_ENTER("_mi_pack_rec_unpack");
init_bit_buffer(&info->bit_buff, (uchar*) from,reclength);
for (current_field=share->rec, end=current_field+share->base.fields ;
current_field < end ;
current_field++,to=end_field)
{
end_field=to+current_field->length;
(*current_field->unpack)(current_field,&info->bit_buff,(uchar*) to,
(uchar*) end_field);
}
if (! info->bit_buff.error &&
info->bit_buff.pos - info->bit_buff.bits/8 == info->bit_buff.end)
DBUG_RETURN(0);
info->update&= ~HA_STATE_AKTIV;
DBUG_RETURN(my_errno=HA_ERR_WRONG_IN_RECORD);
} /* _mi_pack_rec_unpack */
/* Return function to unpack field */
static void (*get_unpack_function(MI_COLUMNDEF *rec))
(MI_COLUMNDEF *, MI_BIT_BUFF *, uchar *, uchar *)
{
switch (rec->base_type) {
case FIELD_SKIPP_ZERO:
if (rec->pack_type & PACK_TYPE_ZERO_FILL)
return &uf_zerofill_skipp_zero;
return &uf_skipp_zero;
case FIELD_NORMAL:
if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
return &uf_space_normal;
if (rec->pack_type & PACK_TYPE_ZERO_FILL)
return &uf_zerofill_normal;
return &decode_bytes;
case FIELD_SKIPP_ENDSPACE:
if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
{
if (rec->pack_type & PACK_TYPE_SELECTED)
return &uf_space_endspace_selected;
return &uf_space_endspace;
}
if (rec->pack_type & PACK_TYPE_SELECTED)
return &uf_endspace_selected;
return &uf_endspace;
case FIELD_SKIPP_PRESPACE:
if (rec->pack_type & PACK_TYPE_SPACE_FIELDS)
{
if (rec->pack_type & PACK_TYPE_SELECTED)
return &uf_space_prespace_selected;
return &uf_space_prespace;
}
if (rec->pack_type & PACK_TYPE_SELECTED)
return &uf_prespace_selected;
return &uf_prespace;
case FIELD_CONSTANT:
return &uf_constant;
case FIELD_INTERVALL:
return &uf_intervall;
case FIELD_ZERO:
case FIELD_CHECK:
return &uf_zero;
case FIELD_BLOB:
return &uf_blob;
case FIELD_VARCHAR:
return &uf_varchar;
case FIELD_LAST:
default:
return 0; /* This should never happend */
}
}
/* De different functions to unpack a field */
static void uf_zerofill_skipp_zero(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
uchar *to, uchar *end)
{
if (get_bit(bit_buff))
bzero((char*) to,(uint) (end-to));
else
{
end-=rec->space_length_bits;
decode_bytes(rec,bit_buff,to,end);
bzero((char*) end,rec->space_length_bits);
}
}
static void uf_skipp_zero(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to,
uchar *end)
{
if (get_bit(bit_buff))
bzero((char*) to,(uint) (end-to));
else
decode_bytes(rec,bit_buff,to,end);
}
static void uf_space_normal(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to,
uchar *end)
{
if (get_bit(bit_buff))
bfill((byte*) to,(end-to),' ');
else
decode_bytes(rec,bit_buff,to,end);
}
static void uf_space_endspace_selected(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
uchar *to, uchar *end)
{
uint spaces;
if (get_bit(bit_buff))
bfill((byte*) to,(end-to),' ');
else
{
if (get_bit(bit_buff))
{
if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
{
bit_buff->error=1;
return;
}
if (to+spaces != end)
decode_bytes(rec,bit_buff,to,end-spaces);
bfill((byte*) end-spaces,spaces,' ');
}
else
decode_bytes(rec,bit_buff,to,end);
}
}
static void uf_endspace_selected(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
uchar *to, uchar *end)
{
uint spaces;
if (get_bit(bit_buff))
{
if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
{
bit_buff->error=1;
return;
}
if (to+spaces != end)
decode_bytes(rec,bit_buff,to,end-spaces);
bfill((byte*) end-spaces,spaces,' ');
}
else
decode_bytes(rec,bit_buff,to,end);
}
static void uf_space_endspace(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to,
uchar *end)
{
uint spaces;
if (get_bit(bit_buff))
bfill((byte*) to,(end-to),' ');
else
{
if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
{
bit_buff->error=1;
return;
}
if (to+spaces != end)
decode_bytes(rec,bit_buff,to,end-spaces);
bfill((byte*) end-spaces,spaces,' ');
}
}
static void uf_endspace(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to,
uchar *end)
{
uint spaces;
if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
{
bit_buff->error=1;
return;
}
if (to+spaces != end)
decode_bytes(rec,bit_buff,to,end-spaces);
bfill((byte*) end-spaces,spaces,' ');
}
static void uf_space_prespace_selected(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
uchar *to, uchar *end)
{
uint spaces;
if (get_bit(bit_buff))
bfill((byte*) to,(end-to),' ');
else
{
if (get_bit(bit_buff))
{
if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
{
bit_buff->error=1;
return;
}
bfill((byte*) to,spaces,' ');
if (to+spaces != end)
decode_bytes(rec,bit_buff,to+spaces,end);
}
else
decode_bytes(rec,bit_buff,to,end);
}
}
static void uf_prespace_selected(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
uchar *to, uchar *end)
{
uint spaces;
if (get_bit(bit_buff))
{
if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
{
bit_buff->error=1;
return;
}
bfill((byte*) to,spaces,' ');
if (to+spaces != end)
decode_bytes(rec,bit_buff,to+spaces,end);
}
else
decode_bytes(rec,bit_buff,to,end);
}
static void uf_space_prespace(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to,
uchar *end)
{
uint spaces;
if (get_bit(bit_buff))
bfill((byte*) to,(end-to),' ');
else
{
if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
{
bit_buff->error=1;
return;
}
bfill((byte*) to,spaces,' ');
if (to+spaces != end)
decode_bytes(rec,bit_buff,to+spaces,end);
}
}
static void uf_prespace(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to,
uchar *end)
{
uint spaces;
if ((spaces=get_bits(bit_buff,rec->space_length_bits))+to > end)
{
bit_buff->error=1;
return;
}
bfill((byte*) to,spaces,' ');
if (to+spaces != end)
decode_bytes(rec,bit_buff,to+spaces,end);
}
static void uf_zerofill_normal(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to,
uchar *end)
{
end-=rec->space_length_bits;
decode_bytes(rec,bit_buff,(uchar*) to,end);
bzero((char*) end,rec->space_length_bits);
}
static void uf_constant(MI_COLUMNDEF *rec,
MI_BIT_BUFF *bit_buff __attribute__((unused)),
uchar *to,
uchar *end)
{
memcpy(to,rec->huff_tree->intervalls,(size_t) (end-to));
}
static void uf_intervall(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to,
uchar *end)
{
reg1 uint field_length=(uint) (end-to);
memcpy(to,rec->huff_tree->intervalls+field_length*decode_pos(bit_buff,
rec->huff_tree),
(size_t) field_length);
}
/*ARGSUSED*/
static void uf_zero(MI_COLUMNDEF *rec __attribute__((unused)),
MI_BIT_BUFF *bit_buff __attribute__((unused)),
uchar *to, uchar *end)
{
bzero((char*) to,(uint) (end-to));
}
static void uf_blob(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
uchar *to, uchar *end)
{
if (get_bit(bit_buff))
bzero((byte*) to,(end-to));
else
{
ulong length=get_bits(bit_buff,rec->space_length_bits);
uint pack_length=(uint) (end-to)-mi_portable_sizeof_char_ptr;
decode_bytes(rec,bit_buff,bit_buff->blob_pos,bit_buff->blob_pos+length);
_my_store_blob_length((byte*) to,pack_length,length);
memcpy_fixed((char*) to+pack_length,(char*) &bit_buff->blob_pos,
sizeof(char*));
bit_buff->blob_pos+=length;
}
}
static void uf_varchar(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff,
uchar *to, uchar *end __attribute__((unused)))
{
if (get_bit(bit_buff))
to[0]=to[1]=0; /* Zero lengths */
else
{
ulong length=get_bits(bit_buff,rec->space_length_bits);
int2store(to,length);
decode_bytes(rec,bit_buff,to+2,to+2+length);
}
}
/* Functions to decode of buffer of bits */
#if BITS_SAVED == 64
static void decode_bytes(MI_COLUMNDEF *rec,MI_BIT_BUFF *bit_buff,uchar *to,
uchar *end)
{
reg1 uint bits,low_byte;
reg3 uint16 *pos;
reg4 uint table_bits,table_and;
MI_DECODE_TREE *decode_tree;
decode_tree=rec->decode_tree;
bits=bit_buff->bits; /* Save in reg for quicker access */
table_bits=decode_tree->quick_table_bits;
table_and= (1 << table_bits)-1;
do
{
if (bits <= 32)
{
if (bit_buff->pos > bit_buff->end+4)
return; /* Can't be right */
bit_buff->current_byte= (bit_buff->current_byte << 32) +
((((uint) bit_buff->pos[3])) +
(((uint) bit_buff->pos[2]) << 8) +
(((uint) bit_buff->pos[1]) << 16) +
(((uint) bit_buff->pos[0]) << 24));
bit_buff->pos+=4;
bits+=32;
}
/* First use info in 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)
{
*to++ = (low_byte & 255); /* Found char in quick table */
bits-= ((low_byte >> 8) & 31); /* Remove bits used */
}
else
{ /* Map through rest of decode-table */
pos=decode_tree->table+low_byte;
bits-=table_bits;
for (;;)
{
low_byte=(uint) (bit_buff->current_byte >> (bits-8));
decode_bytes_test_bit(0);
decode_bytes_test_bit(1);
decode_bytes_test_bit(2);
decode_bytes_test_bit(3);
decode_bytes_test_bit(4);
decode_bytes_test_bit(5);
decode_bytes_test_bit(6);
decode_bytes_test_bit(7);
bits-=8;
}
*to++ = *pos;
}
} while (to != end);
bit_buff->bits=bits;
return;
}
#else
static void decode_bytes(MI_COLUMNDEF *rec, MI_BIT_BUFF *bit_buff, uchar *to, uchar *end)
{
reg1 uint bits,low_byte;
reg3 uint16 *pos;
reg4 uint table_bits,table_and;
MI_DECODE_TREE *decode_tree;
decode_tree=rec->huff_tree;
bits=bit_buff->bits; /* Save in reg for quicker access */
table_bits=decode_tree->quick_table_bits;
table_and= (1 << table_bits)-1;
do
{
if (bits < table_bits)
{
if (bit_buff->pos > bit_buff->end+1)
return; /* Can't be right */
#if BITS_SAVED == 32
bit_buff->current_byte= (bit_buff->current_byte << 24) +
(((uint) ((uchar) bit_buff->pos[2]))) +
(((uint) ((uchar) bit_buff->pos[1])) << 8) +
(((uint) ((uchar) bit_buff->pos[0])) << 16);
bit_buff->pos+=3;
bits+=24;
#else
if (bits) /* We must have at leasts 9 bits */
{
bit_buff->current_byte= (bit_buff->current_byte << 8) +
(uint) ((uchar) bit_buff->pos[0]);
bit_buff->pos++;
bits+=8;
}
else
{
bit_buff->current_byte= ((uint) ((uchar) bit_buff->pos[0]) << 8) +
((uint) ((uchar) bit_buff->pos[1]));
bit_buff->pos+=2;
bits+=16;
}
#endif
}
/* First use info in quick_table */
low_byte=(bit_buff->current_byte >> (bits - table_bits)) & table_and;
low_byte=decode_tree->table[low_byte];
if (low_byte & IS_CHAR)
{
*to++ = (low_byte & 255); /* Found char in quick table */
bits-= ((low_byte >> 8) & 31); /* Remove bits used */
}
else
{ /* Map through rest of decode-table */
pos=decode_tree->table+low_byte;
bits-=table_bits;
for (;;)
{
if (bits < 8)
{ /* We don't need to check end */
#if BITS_SAVED == 32
bit_buff->current_byte= (bit_buff->current_byte << 24) +
(((uint) ((uchar) bit_buff->pos[2]))) +
(((uint) ((uchar) bit_buff->pos[1])) << 8) +
(((uint) ((uchar) bit_buff->pos[0])) << 16);
bit_buff->pos+=3;
bits+=24;
#else
bit_buff->current_byte= (bit_buff->current_byte << 8) +
(uint) ((uchar) bit_buff->pos[0]);
bit_buff->pos+=1;
bits+=8;
#endif
}
low_byte=(uint) (bit_buff->current_byte >> (bits-8));
decode_bytes_test_bit(0);
decode_bytes_test_bit(1);
decode_bytes_test_bit(2);
decode_bytes_test_bit(3);
decode_bytes_test_bit(4);
decode_bytes_test_bit(5);
decode_bytes_test_bit(6);
decode_bytes_test_bit(7);
bits-=8;
}
*to++ = (uchar) *pos;
}
} while (to != end);
bit_buff->bits=bits;
return;
}
#endif /* BIT_SAVED == 64 */
static uint decode_pos(MI_BIT_BUFF *bit_buff, MI_DECODE_TREE *decode_tree)
{
uint16 *pos=decode_tree->table;
for (;;)
{
if (get_bit(bit_buff))
pos++;
if (*pos & IS_CHAR)
return (uint) (*pos & ~IS_CHAR);
pos+= *pos;
}
}
int _mi_read_rnd_pack_record(MI_INFO *info, byte *buf,
register my_off_t filepos,
my_bool skip_deleted_blocks)
{
uint b_type;
MI_BLOCK_INFO block_info;
MYISAM_SHARE *share=info->s;
DBUG_ENTER("_mi_read_rnd_pack_record");
if (filepos >= info->state->data_file_length)
{
my_errno= HA_ERR_END_OF_FILE;
goto err;
}
if (info->opt_flag & READ_CACHE_USED)
{
if (_mi_read_cache(&info->rec_cache,(byte*) block_info.header,filepos,
share->pack.ref_length, skip_deleted_blocks))
goto err;
b_type=_mi_pack_get_block_info(info,&block_info,-1, filepos, NullS);
}
else
b_type=_mi_pack_get_block_info(info,&block_info,info->dfile,filepos,
info->rec_buff);
if (b_type)
goto err; /* Error code is already set */
#ifndef DBUG_OFF
if (block_info.rec_len > share->max_pack_length)
{
my_errno=HA_ERR_WRONG_IN_RECORD;
goto err;
}
#endif
if (info->opt_flag & READ_CACHE_USED)
{
if (_mi_read_cache(&info->rec_cache,(byte*) info->rec_buff,
block_info.filepos, block_info.rec_len,
skip_deleted_blocks))
goto err;
}
else
{
if (my_read(info->dfile,(byte*) info->rec_buff + block_info.offset,
block_info.rec_len-block_info.offset,
MYF(MY_NABP)))
goto err;
}
info->packed_length=block_info.rec_len;
info->lastpos=filepos;
info->nextpos=block_info.filepos+block_info.rec_len;
info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
DBUG_RETURN (_mi_pack_rec_unpack(info,buf,info->rec_buff,
block_info.rec_len));
err:
DBUG_RETURN(my_errno);
}
/* Read and process header from a huff-record-file */
uint _mi_pack_get_block_info(MI_INFO *myisam, MI_BLOCK_INFO *info, File file,
my_off_t filepos, char *rec_buff)
{
uchar *header=info->header;
uint head_length,ref_length;
LINT_INIT(ref_length);
if (file >= 0)
{
ref_length=myisam->s->pack.ref_length;
/*
We can't use my_pread() here because mi_read_rnd_pack_record assumes
position is ok
*/
VOID(my_seek(file,filepos,MY_SEEK_SET,MYF(0)));
if (my_read(file,(char*) header,ref_length,MYF(MY_NABP)))
return BLOCK_FATAL_ERROR;
DBUG_DUMP("header",(byte*) header,ref_length);
}
if (header[0] < 254)
{
info->rec_len=header[0];
head_length=1;
}
else if (header[0] == 254)
{
info->rec_len=uint2korr(header+1);
head_length=3;
}
else
{
info->rec_len=uint3korr(header+1);
head_length=4;
}
if (myisam->s->base.blobs)
{
if (header[head_length] < 254)
{
info->blob_len=header[head_length];
head_length++;
}
else if (header[head_length] == 254)
{
info->blob_len=uint2korr(header+head_length+1);
head_length+=3;
}
else
{
info->blob_len=uint3korr(header+head_length+1);
head_length+=4;
}
if (!(mi_fix_rec_buff_for_blob(myisam,info->rec_len + info->blob_len)))
return BLOCK_FATAL_ERROR; /* not enough memory */
myisam->bit_buff.blob_pos=(uchar*) myisam->rec_buff+info->rec_len;
myisam->blob_length=info->blob_len;
}
info->filepos=filepos+head_length;
if (file > 0)
{
info->offset=min(info->rec_len, ref_length - head_length);
memcpy(rec_buff, header+head_length, info->offset);
}
return 0;
}
/* rutines for bit buffer */
/* Note buffer must be 6 byte bigger than longest row */
static void init_bit_buffer(MI_BIT_BUFF *bit_buff, uchar *buffer, uint length)
{
bit_buff->pos=buffer;
bit_buff->end=buffer+length;
bit_buff->bits=bit_buff->error=0;
bit_buff->current_byte=0; /* Avoid purify errors */
}
static uint fill_and_get_bits(MI_BIT_BUFF *bit_buff, uint count)
{
uint tmp;
count-=bit_buff->bits;
tmp=(bit_buff->current_byte & mask[bit_buff->bits]) << count;
fill_buffer(bit_buff);
bit_buff->bits=BITS_SAVED - count;
return tmp+(bit_buff->current_byte >> (BITS_SAVED - count));
}
/* Fill in empty bit_buff->current_byte from buffer */
/* Sets bit_buff->error if buffer is exhausted */
static void fill_buffer(MI_BIT_BUFF *bit_buff)
{
if (bit_buff->pos >= bit_buff->end)
{
bit_buff->error= 1;
bit_buff->current_byte=0;
return;
}
#if BITS_SAVED == 64
bit_buff->current_byte= ((((uint) ((uchar) bit_buff->pos[7]))) +
(((uint) ((uchar) bit_buff->pos[6])) << 8) +
(((uint) ((uchar) bit_buff->pos[5])) << 16) +
(((uint) ((uchar) bit_buff->pos[4])) << 24) +
((ulonglong)
((((uint) ((uchar) bit_buff->pos[3]))) +
(((uint) ((uchar) bit_buff->pos[2])) << 8) +
(((uint) ((uchar) bit_buff->pos[1])) << 16) +
(((uint) ((uchar) bit_buff->pos[0])) << 24)) << 32));
bit_buff->pos+=8;
#else
#if BITS_SAVED == 32
bit_buff->current_byte= (((uint) ((uchar) bit_buff->pos[3])) +
(((uint) ((uchar) bit_buff->pos[2])) << 8) +
(((uint) ((uchar) bit_buff->pos[1])) << 16) +
(((uint) ((uchar) bit_buff->pos[0])) << 24));
bit_buff->pos+=4;
#else
bit_buff->current_byte= (uint) (((uint) ((uchar) bit_buff->pos[1]))+
(((uint) ((uchar) bit_buff->pos[0])) << 8));
bit_buff->pos+=2;
#endif
#endif
}
/* Get number of bits neaded to represent value */
static uint max_bit(register uint value)
{
reg2 uint power=1;
while ((value>>=1))
power++;
return (power);
}
/*****************************************************************************
Some redefined functions to handle files when we are using memmap
*****************************************************************************/
#ifdef HAVE_MMAP
#include <sys/mman.h>
static int _mi_read_mempack_record(MI_INFO *info,my_off_t filepos,byte *buf);
static int _mi_read_rnd_mempack_record(MI_INFO*, byte *,my_off_t, my_bool);
#ifndef MAP_NORESERVE
#define MAP_NORESERVE 0 /* For irix */
#endif
#ifndef MAP_FAILED
#define MAP_FAILED -1
#endif
my_bool _mi_memmap_file(MI_INFO *info)
{
byte *file_map;
MYISAM_SHARE *share=info->s;
DBUG_ENTER("mi_memmap_file");
if (!info->s->file_map)
{
if (my_seek(info->dfile,0L,MY_SEEK_END,MYF(0)) <
share->state.state.data_file_length+MEMMAP_EXTRA_MARGIN)
{
DBUG_PRINT("warning",("File isn't extended for memmap"));
DBUG_RETURN(0);
}
file_map=(byte*)
mmap(0,share->state.state.data_file_length+MEMMAP_EXTRA_MARGIN,PROT_READ,
MAP_SHARED | MAP_NORESERVE,info->dfile,0L);
if (file_map == (byte*) MAP_FAILED)
{
DBUG_PRINT("warning",("mmap failed: errno: %d",errno));
my_errno=errno;
DBUG_RETURN(0);
}
info->s->file_map=file_map;
}
info->opt_flag|= MEMMAP_USED;
info->read_record=share->read_record=_mi_read_mempack_record;
share->read_rnd=_mi_read_rnd_mempack_record;
DBUG_RETURN(1);
}
void _mi_unmap_file(MI_INFO *info)
{
VOID(munmap((caddr_t) info->s->file_map,
(size_t) info->s->state.state.data_file_length+
MEMMAP_EXTRA_MARGIN));
}
static uchar *_mi_mempack_get_block_info(MI_INFO *myisam,MI_BLOCK_INFO *info,
uchar *header)
{
if (header[0] < 254)
info->rec_len= *header++;
else if (header[0] == 254)
{
info->rec_len=uint2korr(header+1);
header+=3;
}
else
{
info->rec_len=uint3korr(header+1);
header+=4;
}
if (myisam->s->base.blobs)
{
if (header[0] < 254)
{
info->blob_len= *header++;
}
else if (header[0] == 254)
{
info->blob_len=uint2korr(header+1);
header+=3;
}
else
{
info->blob_len=uint3korr(header+1);
header+=4;
}
/* mi_fix_rec_buff_for_blob sets my_errno on error */
if (!(mi_fix_rec_buff_for_blob(myisam,info->blob_len)))
return 0; /* not enough memory */
myisam->bit_buff.blob_pos=(uchar*) myisam->rec_buff;
}
return header;
}
static int _mi_read_mempack_record(MI_INFO *info, my_off_t filepos, byte *buf)
{
MI_BLOCK_INFO block_info;
MYISAM_SHARE *share=info->s;
byte *pos;
DBUG_ENTER("mi_read_mempack_record");
if (filepos == HA_OFFSET_ERROR)
DBUG_RETURN(-1); /* _search() didn't find record */
if (!(pos= (byte*) _mi_mempack_get_block_info(info,&block_info,
(uchar*) share->file_map+
filepos)))
DBUG_RETURN(-1);
DBUG_RETURN(_mi_pack_rec_unpack(info, buf, pos, block_info.rec_len));
}
/*ARGSUSED*/
static int _mi_read_rnd_mempack_record(MI_INFO *info, byte *buf,
register my_off_t filepos,
my_bool skip_deleted_blocks
__attribute__((unused)))
{
MI_BLOCK_INFO block_info;
MYISAM_SHARE *share=info->s;
byte *pos,*start;
DBUG_ENTER("_mi_read_rnd_mempack_record");
if (filepos >= share->state.state.data_file_length)
{
my_errno=HA_ERR_END_OF_FILE;
goto err;
}
if (!(pos= (byte*) _mi_mempack_get_block_info(info,&block_info,
(uchar*)
(start=share->file_map+
filepos))))
goto err;
#ifndef DBUG_OFF
if (block_info.rec_len > info->s->max_pack_length)
{
my_errno=HA_ERR_WRONG_IN_RECORD;
goto err;
}
#endif
info->packed_length=block_info.rec_len;
info->lastpos=filepos;
info->nextpos=filepos+(uint) (pos-start)+block_info.rec_len;
info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED;
DBUG_RETURN (_mi_pack_rec_unpack(info,buf,pos, block_info.rec_len));
err:
DBUG_RETURN(my_errno);
}
#endif /* HAVE_MMAP */
/* Save length of row */
uint save_pack_length(byte *block_buff,ulong length)
{
if (length < 254)
{
*(uchar*) block_buff= (uchar) length;
return 1;
}
if (length <= 65535)
{
*(uchar*) block_buff=254;
int2store(block_buff+1,(uint) length);
return 3;
}
*(uchar*) block_buff=255;
int3store(block_buff+1,(ulong) length);
return 4;
}