/* 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 */ #ifdef USE_PRAGMA_IMPLEMENTATION #pragma implementation // gcc: Class implementation #endif #include "mysql_priv.h" #ifdef HAVE_ISAM #include #include #include "ha_isam.h" #ifndef MASTER #include "../srclib/isam/isamdef.h" #else #include "../isam/isamdef.h" #endif /***************************************************************************** ** isam tables *****************************************************************************/ const char **ha_isam::bas_ext() const { static const char *ext[]= { ".ISM",".ISD", NullS }; return ext; } int ha_isam::open(const char *name, int mode, uint test_if_locked) { char name_buff[FN_REFLEN]; if (!(file=nisam_open(fn_format(name_buff,name,"","",2 | 4), mode, test_if_locked))) return (my_errno ? my_errno : -1); if (!(test_if_locked == HA_OPEN_WAIT_IF_LOCKED || test_if_locked == HA_OPEN_ABORT_IF_LOCKED)) (void) nisam_extra(file,HA_EXTRA_NO_WAIT_LOCK); info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST); if (!(test_if_locked & HA_OPEN_WAIT_IF_LOCKED)) (void) nisam_extra(file,HA_EXTRA_WAIT_LOCK); if (!table->db_record_offset) int_table_flags|=HA_REC_NOT_IN_SEQ; return (0); } int ha_isam::close(void) { return !nisam_close(file) ? 0 : my_errno ? my_errno : -1; } uint ha_isam::min_record_length(uint options) const { return (options & HA_OPTION_PACK_RECORD) ? 1 : 5; } int ha_isam::write_row(byte * buf) { statistic_increment(ha_write_count,&LOCK_status); if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) table->timestamp_field->set_time(); if (table->next_number_field && buf == table->record[0]) update_auto_increment(); return !nisam_write(file,buf) ? 0 : my_errno ? my_errno : -1; } int ha_isam::update_row(const byte * old_data, byte * new_data) { statistic_increment(ha_update_count,&LOCK_status); if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_UPDATE) table->timestamp_field->set_time(); return !nisam_update(file,old_data,new_data) ? 0 : my_errno ? my_errno : -1; } int ha_isam::delete_row(const byte * buf) { statistic_increment(ha_delete_count,&LOCK_status); return !nisam_delete(file,buf) ? 0 : my_errno ? my_errno : -1; } int ha_isam::index_read(byte * buf, const byte * key, uint key_len, enum ha_rkey_function find_flag) { statistic_increment(ha_read_key_count,&LOCK_status); int error=nisam_rkey(file, buf, active_index, key, key_len, find_flag); table->status=error ? STATUS_NOT_FOUND: 0; return !error ? 0 : my_errno ? my_errno : -1; } int ha_isam::index_read_idx(byte * buf, uint index, const byte * key, uint key_len, enum ha_rkey_function find_flag) { statistic_increment(ha_read_key_count,&LOCK_status); int error=nisam_rkey(file, buf, index, key, key_len, find_flag); table->status=error ? STATUS_NOT_FOUND: 0; return !error ? 0 : my_errno ? my_errno : -1; } int ha_isam::index_read_last(byte * buf, const byte * key, uint key_len) { statistic_increment(ha_read_key_count,&LOCK_status); int error=nisam_rkey(file, buf, active_index, key, key_len, HA_READ_PREFIX_LAST); table->status=error ? STATUS_NOT_FOUND: 0; return !error ? 0 : my_errno ? my_errno : -1; } int ha_isam::index_next(byte * buf) { statistic_increment(ha_read_next_count,&LOCK_status); int error=nisam_rnext(file,buf,active_index); table->status=error ? STATUS_NOT_FOUND: 0; return !error ? 0 : my_errno ? my_errno : HA_ERR_END_OF_FILE; } int ha_isam::index_prev(byte * buf) { statistic_increment(ha_read_prev_count,&LOCK_status); int error=nisam_rprev(file,buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; return !error ? 0 : my_errno ? my_errno : HA_ERR_END_OF_FILE; } int ha_isam::index_first(byte * buf) { statistic_increment(ha_read_first_count,&LOCK_status); int error=nisam_rfirst(file, buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; return !error ? 0 : my_errno ? my_errno : HA_ERR_END_OF_FILE; } int ha_isam::index_last(byte * buf) { statistic_increment(ha_read_last_count,&LOCK_status); int error=nisam_rlast(file, buf, active_index); table->status=error ? STATUS_NOT_FOUND: 0; return !error ? 0 : my_errno ? my_errno : HA_ERR_END_OF_FILE; } int ha_isam::rnd_init(bool scan) { return nisam_extra(file,HA_EXTRA_RESET) ? 0 : my_errno ? my_errno : -1;; } int ha_isam::rnd_next(byte *buf) { statistic_increment(ha_read_rnd_next_count,&LOCK_status); int error=nisam_rrnd(file, buf, NI_POS_ERROR); table->status=error ? STATUS_NOT_FOUND: 0; return !error ? 0 : my_errno ? my_errno : -1; } int ha_isam::rnd_pos(byte * buf, byte *pos) { statistic_increment(ha_read_rnd_count,&LOCK_status); int error=nisam_rrnd(file, buf, (ulong) ha_get_ptr(pos,ref_length)); table->status=error ? STATUS_NOT_FOUND: 0; return !error ? 0 : my_errno ? my_errno : -1; } void ha_isam::position(const byte *record) { my_off_t position=nisam_position(file); if (position == (my_off_t) ~ (ulong) 0) position=HA_OFFSET_ERROR; ha_store_ptr(ref, ref_length, position); } void ha_isam::info(uint flag) { N_ISAMINFO info; (void) nisam_info(file,&info,flag); if (flag & HA_STATUS_VARIABLE) { records = info.records; deleted = info.deleted; data_file_length=info.data_file_length; index_file_length=info.index_file_length; delete_length = info.delete_length; check_time = info.isamchk_time; mean_rec_length=info.mean_reclength; } if (flag & HA_STATUS_CONST) { max_data_file_length=info.max_data_file_length; max_index_file_length=info.max_index_file_length; create_time = info.create_time; sortkey = info.sortkey; block_size=nisam_block_size; table->keys = min(table->keys,info.keys); table->keys_in_use.set_prefix(table->keys); table->db_options_in_use= info.options; table->db_record_offset= (table->db_options_in_use & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? 0 : table->reclength; if (!table->tmp_table) { ulong *rec_per_key=info.rec_per_key; for (uint i=0 ; i < table->keys ; i++) { table->key_info[i].rec_per_key[table->key_info[i].key_parts-1]= *(rec_per_key++); } } ref_length=4; } if (flag & HA_STATUS_ERRKEY) { errkey = info.errkey; ha_store_ptr(dupp_ref, ref_length, info.dupp_key_pos); } if (flag & HA_STATUS_TIME) update_time = info.update_time; } int ha_isam::extra(enum ha_extra_function operation) { if ((specialflag & SPECIAL_SAFE_MODE || test_flags & TEST_NO_EXTRA) && (operation == HA_EXTRA_WRITE_CACHE || operation == HA_EXTRA_KEYREAD)) return 0; return nisam_extra(file,operation); } int ha_isam::external_lock(THD *thd, int lock_type) { if (!table->tmp_table) return nisam_lock_database(file,lock_type); return 0; } THR_LOCK_DATA **ha_isam::store_lock(THD *thd, THR_LOCK_DATA **to, enum thr_lock_type lock_type) { if (lock_type != TL_IGNORE && file->lock.type == TL_UNLOCK) file->lock.type=lock_type; *to++= &file->lock; return to; } int ha_isam::create(const char *name, register TABLE *form, HA_CREATE_INFO *create_info) { uint options=form->db_options_in_use; int error; uint i,j,recpos,minpos,fieldpos,temp_length,length; enum ha_base_keytype type; char buff[FN_REFLEN]; KEY *pos; N_KEYDEF keydef[MAX_KEY]; N_RECINFO *recinfo,*recinfo_pos; DBUG_ENTER("ha_isam::create"); type=HA_KEYTYPE_BINARY; // Keep compiler happy if (!(recinfo= (N_RECINFO*) my_malloc((form->fields*2+2)*sizeof(N_RECINFO), MYF(MY_WME)))) DBUG_RETURN(HA_ERR_OUT_OF_MEM); pos=form->key_info; for (i=0; i < form->keys ; i++, pos++) { keydef[i].base.flag= (pos->flags & HA_NOSAME); for (j=0 ; (int7) j < pos->key_parts ; j++) { keydef[i].seg[j].base.flag=pos->key_part[j].key_part_flag; Field *field=pos->key_part[j].field; type=field->key_type(); if ((options & HA_OPTION_PACK_KEYS || (pos->flags & (HA_PACK_KEY | HA_BINARY_PACK_KEY | HA_SPACE_PACK_USED))) && pos->key_part[j].length > 8 && (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_NUM || (type == HA_KEYTYPE_BINARY && !field->zero_pack()))) { if (j == 0) keydef[i].base.flag|=HA_PACK_KEY; if (!(field->flags & ZEROFILL_FLAG) && (field->type() == FIELD_TYPE_STRING || field->type() == FIELD_TYPE_VAR_STRING || ((int) (pos->key_part[j].length - field->decimals())) >= 4)) keydef[i].seg[j].base.flag|=HA_SPACE_PACK; } keydef[i].seg[j].base.type=(int) type; keydef[i].seg[j].base.start= pos->key_part[j].offset; keydef[i].seg[j].base.length= pos->key_part[j].length; } keydef[i].seg[j].base.type=(int) HA_KEYTYPE_END; /* End of key-parts */ } recpos=0; recinfo_pos=recinfo; while (recpos < (uint) form->reclength) { Field **field,*found=0; minpos=form->reclength; length=0; for (field=form->field ; *field ; field++) { if ((fieldpos=(*field)->offset()) >= recpos && fieldpos <= minpos) { /* skip null fields */ if (!(temp_length= (*field)->pack_length())) continue; /* Skip null-fields */ if (! found || fieldpos < minpos || (fieldpos == minpos && temp_length < length)) { minpos=fieldpos; found= *field; length=temp_length; } } } DBUG_PRINT("loop",("found: %lx recpos: %d minpos: %d length: %d", found,recpos,minpos,length)); if (recpos != minpos) { // Reserved space (Null bits?) recinfo_pos->base.type=(int) FIELD_NORMAL; recinfo_pos++->base.length= (uint16) (minpos-recpos); } if (! found) break; if (found->flags & BLOB_FLAG) { /* ISAM can only handle blob pointers of sizeof(char(*)) */ recinfo_pos->base.type= (int) FIELD_BLOB; if (options & HA_OPTION_LONG_BLOB_PTR) length= length-portable_sizeof_char_ptr+sizeof(char*); } else if (!(options & HA_OPTION_PACK_RECORD)) recinfo_pos->base.type= (int) FIELD_NORMAL; else if (found->zero_pack()) recinfo_pos->base.type= (int) FIELD_SKIP_ZERO; else recinfo_pos->base.type= (int) ((length <= 3 || (found->flags & ZEROFILL_FLAG)) ? FIELD_NORMAL : found->type() == FIELD_TYPE_STRING || found->type() == FIELD_TYPE_VAR_STRING ? FIELD_SKIP_ENDSPACE : FIELD_SKIP_PRESPACE); recinfo_pos++ ->base.length=(uint16) length; recpos=minpos+length; DBUG_PRINT("loop",("length: %d type: %d", recinfo_pos[-1].base.length,recinfo_pos[-1].base.type)); if ((found->flags & BLOB_FLAG) && (options & HA_OPTION_LONG_BLOB_PTR) && sizeof(char*) != portable_sizeof_char_ptr) { // Not used space recinfo_pos->base.type=(int) FIELD_ZERO; recinfo_pos++->base.length= (uint16) (portable_sizeof_char_ptr-sizeof(char*)); recpos+= (portable_sizeof_char_ptr-sizeof(char*)); } } recinfo_pos->base.type= (int) FIELD_LAST; /* End of fieldinfo */ error=nisam_create(fn_format(buff,name,"","",2+4+16),form->keys,keydef, recinfo,(ulong) form->max_rows, (ulong) form->min_rows, 0, 0, 0L); my_free((gptr) recinfo,MYF(0)); DBUG_RETURN(error); } static key_range no_range= { (byte*) 0, 0, HA_READ_KEY_EXACT }; ha_rows ha_isam::records_in_range(uint inx, key_range *min_key, key_range *max_key) { /* ISAM checks if 'key' pointer <> 0 to know if there is no range */ if (!min_key) min_key= &no_range; if (!max_key) max_key= &no_range; return (ha_rows) nisam_records_in_range(file, (int) inx, min_key->key, min_key->length, min_key->flag, max_key->key, max_key->length, max_key->flag); } #endif /* HAVE_ISAM */