int _mi_read_static_record(register MI_INFO *info, register my_off_t pos, register uchar *record) { int error; if (pos != HA_OFFSET_ERROR) { if (info->opt_flag & WRITE_CACHE_USED && info->rec_cache.pos_in_file <= pos && flush_io_cache(&info->rec_cache)) return(-1); info->rec_cache.seek_not_done=1; /* We have done a seek */ error=info->s->file_read(info, record, info->s->base.reclength, pos,MYF(MY_NABP)) != 0; fast_mi_writeinfo(info); if (! error) { if (!*record) { my_errno=HA_ERR_RECORD_DELETED; return(1); /* Record is deleted */ } info->update|= HA_STATE_AKTIV; /* Record is read */ return(0); } return(-1); /* Error on read */ } fast_mi_writeinfo(info); /* No such record */ return(-1); }
ha_rows mi_records_in_range(MI_INFO *info, int inx, key_range *min_key, key_range *max_key) { ha_rows start_pos,end_pos,res; DBUG_ENTER("mi_records_in_range"); if ((inx = _mi_check_index(info,inx)) < 0) DBUG_RETURN(HA_POS_ERROR); if (fast_mi_readinfo(info)) DBUG_RETURN(HA_POS_ERROR); info->update&= (HA_STATE_CHANGED+HA_STATE_ROW_CHANGED); if (info->s->concurrent_insert) rw_rdlock(&info->s->key_root_lock[inx]); switch(info->s->keyinfo[inx].key_alg){ #ifdef HAVE_RTREE_KEYS case HA_KEY_ALG_RTREE: { uchar * key_buff; uint start_key_len; /* The problem is that the optimizer doesn't support RTree keys properly at the moment. Hope this will be fixed some day. But now NULL in the min_key means that we didn't make the task for the RTree key and expect BTree functionality from it. As it's not able to handle such request we return the error. */ if (!min_key) { res= HA_POS_ERROR; break; } key_buff= info->lastkey+info->s->base.max_key_length; start_key_len= _mi_pack_key(info,inx, key_buff, (uchar*) min_key->key, min_key->keypart_map, (HA_KEYSEG**) 0); res= rtree_estimate(info, inx, key_buff, start_key_len, myisam_read_vec[min_key->flag]); res= res ? res : 1; /* Don't return 0 */ break; } #endif case HA_KEY_ALG_BTREE: default: start_pos= (min_key ? _mi_record_pos(info, min_key->key, min_key->keypart_map, min_key->flag) : (ha_rows) 0); end_pos= (max_key ? _mi_record_pos(info, max_key->key, max_key->keypart_map, max_key->flag) : info->state->records + (ha_rows) 1); res= (end_pos < start_pos ? (ha_rows) 0 : (end_pos == start_pos ? (ha_rows) 1 : end_pos-start_pos)); if (start_pos == HA_POS_ERROR || end_pos == HA_POS_ERROR) res=HA_POS_ERROR; } if (info->s->concurrent_insert) rw_unlock(&info->s->key_root_lock[inx]); fast_mi_writeinfo(info); DBUG_PRINT("info",("records: %ld",(ulong) (res))); DBUG_RETURN(res); }
int _mi_read_rnd_static_record(MI_INFO *info, uchar *buf, register my_off_t filepos, my_bool skip_deleted_blocks) { int locked,error,cache_read; uint cache_length; MYISAM_SHARE *share=info->s; DBUG_ENTER("_mi_read_rnd_static_record"); cache_read=0; cache_length=0; if (info->opt_flag & WRITE_CACHE_USED && (info->rec_cache.pos_in_file <= filepos || skip_deleted_blocks) && flush_io_cache(&info->rec_cache)) DBUG_RETURN(my_errno); if (info->opt_flag & READ_CACHE_USED) { /* Cache in use */ if (filepos == my_b_tell(&info->rec_cache) && (skip_deleted_blocks || !filepos)) { cache_read=1; /* Read record using cache */ cache_length=(uint) (info->rec_cache.read_end - info->rec_cache.read_pos); } else info->rec_cache.seek_not_done=1; /* Filepos is changed */ } locked=0; if (info->lock_type == F_UNLCK) { if (filepos >= info->state->data_file_length) { /* Test if new records */ if (_mi_readinfo(info,F_RDLCK,0)) DBUG_RETURN(my_errno); locked=1; } else { /* We don't nead new info */ #ifndef UNSAFE_LOCKING if ((! cache_read || share->base.reclength > cache_length) && share->tot_locks == 0) { /* record not in cache */ if (my_lock(share->kfile,F_RDLCK,0L,F_TO_EOF, MYF(MY_SEEK_NOT_DONE) | info->lock_wait)) DBUG_RETURN(my_errno); locked=1; } #else info->tmp_lock_type=F_RDLCK; #endif } } if (filepos >= info->state->data_file_length) { DBUG_PRINT("test",("filepos: %ld (%ld) records: %ld del: %ld", (long) filepos/share->base.reclength, (long) filepos, (long) info->state->records, (long) info->state->del)); fast_mi_writeinfo(info); DBUG_RETURN(my_errno=HA_ERR_END_OF_FILE); } info->lastpos= filepos; info->nextpos= filepos+share->base.pack_reclength; if (! cache_read) /* No cacheing */ { if ((error=_mi_read_static_record(info,filepos,buf))) { if (error > 0) error=my_errno=HA_ERR_RECORD_DELETED; else error=my_errno; } DBUG_RETURN(error); } /* Read record with caching. If my_b_read() returns TRUE, less than the requested bytes have been read. In this case rec_cache.error is either -1 for a read error, or contains the number of bytes copied into the buffer. */ error=my_b_read(&info->rec_cache,(uchar*) buf,share->base.reclength); if (info->s->base.pack_reclength != info->s->base.reclength && !error) { char tmp[8]; /* Skill fill bytes */ error=my_b_read(&info->rec_cache,(uchar*) tmp, info->s->base.pack_reclength - info->s->base.reclength); } if (locked) (void) _mi_writeinfo(info,0); /* Unlock keyfile */ if (!error) { if (!buf[0]) { /* Record is removed */ DBUG_RETURN(my_errno=HA_ERR_RECORD_DELETED); } /* Found and may be updated */ info->update|= HA_STATE_AKTIV | HA_STATE_KEY_CHANGED; DBUG_RETURN(0); } /* error is TRUE. my_errno should be set if rec_cache.error == -1 */ if (info->rec_cache.error != -1 || my_errno == 0) { /* If we could not get a full record, we either have a broken record, or are at end of file. */ if (info->rec_cache.error == 0) my_errno= HA_ERR_END_OF_FILE; else my_errno= HA_ERR_WRONG_IN_RECORD; } DBUG_RETURN(my_errno); /* Something wrong (EOF?) */ }
int mi_status(MI_INFO *info, register MI_ISAMINFO *x, uint flag) { MY_STAT state; MYISAM_SHARE *share=info->s; DBUG_ENTER("mi_status"); x->recpos = info->lastpos; if (flag == HA_STATUS_POS) DBUG_RETURN(0); /* Compatible with ISAM */ if (!(flag & HA_STATUS_NO_LOCK)) { pthread_mutex_lock(&share->intern_lock); VOID(_mi_readinfo(info,F_RDLCK,0)); fast_mi_writeinfo(info); pthread_mutex_unlock(&share->intern_lock); } if (flag & HA_STATUS_VARIABLE) { x->records = info->state->records; x->deleted = info->state->del; x->delete_length = info->state->empty; x->data_file_length =info->state->data_file_length; x->index_file_length=info->state->key_file_length; x->keys = share->state.header.keys; x->check_time = share->state.check_time; x->mean_reclength= x->records ? (ulong) ((x->data_file_length - x->delete_length) / x->records) : (ulong) share->min_pack_length; } if (flag & HA_STATUS_ERRKEY) { x->errkey = info->errkey; x->dupp_key_pos= info->dupp_key_pos; } if (flag & HA_STATUS_CONST) { x->reclength = share->base.reclength; x->max_data_file_length=share->base.max_data_file_length; x->max_index_file_length=info->s->base.max_key_file_length; x->filenr = info->dfile; x->options = share->options; x->create_time=share->state.create_time; x->reflength= mi_get_pointer_length(share->base.max_data_file_length, myisam_data_pointer_size); x->record_offset= ((share->options & (HA_OPTION_PACK_RECORD | HA_OPTION_COMPRESS_RECORD)) ? 0L : share->base.pack_reclength); x->sortkey= -1; /* No clustering */ x->rec_per_key = share->state.rec_per_key_part; x->key_map = share->state.key_map; x->data_file_name = share->data_file_name; x->index_file_name = share->index_file_name; /* The following should be included even if we are not compiling with USE_RAID as the client must be able to request it! */ x->raid_type= share->base.raid_type; x->raid_chunks= share->base.raid_chunks; x->raid_chunksize= share->base.raid_chunksize; } if ((flag & HA_STATUS_TIME) && !my_fstat(info->dfile,&state,MYF(0))) x->update_time=state.st_mtime; else x->update_time=0; if (flag & HA_STATUS_AUTO) { x->auto_increment= share->state.auto_increment+1; if (!x->auto_increment) /* This shouldn't happen */ x->auto_increment= ~(ulonglong) 0; } DBUG_RETURN(0); }
int mi_rnext(MI_INFO *info, uchar *buf, int inx) { int error,changed; uint flag; ICP_RESULT icp_res= ICP_MATCH; uint update_mask= HA_STATE_NEXT_FOUND; DBUG_ENTER("mi_rnext"); if ((inx = _mi_check_index(info,inx)) < 0) DBUG_RETURN(my_errno); flag=SEARCH_BIGGER; /* Read next */ if (info->lastpos == HA_OFFSET_ERROR && info->update & HA_STATE_PREV_FOUND) flag=0; /* Read first */ if (fast_mi_readinfo(info)) DBUG_RETURN(my_errno); if (info->s->concurrent_insert) mysql_rwlock_rdlock(&info->s->key_root_lock[inx]); changed=_mi_test_if_changed(info); if (!flag) { switch(info->s->keyinfo[inx].key_alg){ #ifdef HAVE_RTREE_KEYS case HA_KEY_ALG_RTREE: error=rtree_get_first(info,inx,info->lastkey_length); break; #endif case HA_KEY_ALG_BTREE: default: error=_mi_search_first(info,info->s->keyinfo+inx, info->s->state.key_root[inx]); break; } /* "search first" failed. This means we have no pivot for "search next", or in other words MI_INFO::lastkey is likely uninitialized. Normally SQL layer would never request "search next" if "search first" failed. But HANDLER may do anything. As mi_rnext() without preceding mi_rkey()/mi_rfirst() equals to mi_rfirst(), we must restore original state as if failing mi_rfirst() was not called. */ if (error) update_mask|= HA_STATE_PREV_FOUND; } else { switch (info->s->keyinfo[inx].key_alg) { #ifdef HAVE_RTREE_KEYS case HA_KEY_ALG_RTREE: /* Note that rtree doesn't support that the table may be changed since last call, so we do need to skip rows inserted by other threads like in btree */ error= rtree_get_next(info,inx,info->lastkey_length); break; #endif case HA_KEY_ALG_BTREE: default: if (!changed) error= _mi_search_next(info,info->s->keyinfo+inx,info->lastkey, info->lastkey_length,flag, info->s->state.key_root[inx]); else error= _mi_search(info,info->s->keyinfo+inx,info->lastkey, USE_WHOLE_KEY,flag, info->s->state.key_root[inx]); } } if (!error) { while ((info->s->concurrent_insert && info->lastpos >= info->state->data_file_length) || (info->index_cond_func && (icp_res= mi_check_index_cond(info, inx, buf)) == ICP_NO_MATCH)) { /* If we are at the last key on the key page, allow writers to access the index. */ if (info->int_keypos >= info->int_maxpos && mi_yield_and_check_if_killed(info, inx)) { error= 1; break; } /* Skip rows that are either inserted by other threads since we got a lock or do not match pushed index conditions */ if ((error=_mi_search_next(info,info->s->keyinfo+inx, info->lastkey, info->lastkey_length, SEARCH_BIGGER, info->s->state.key_root[inx]))) break; } } if (info->s->concurrent_insert) mysql_rwlock_unlock(&info->s->key_root_lock[inx]); /* Don't clear if database-changed */ info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED); info->update|= update_mask; if (error || icp_res != ICP_MATCH) { fast_mi_writeinfo(info); if (my_errno == HA_ERR_KEY_NOT_FOUND) my_errno=HA_ERR_END_OF_FILE; } else if (!buf) { fast_mi_writeinfo(info); DBUG_RETURN(info->lastpos==HA_OFFSET_ERROR ? my_errno : 0); } else if (!(*info->read_record)(info,info->lastpos,buf)) { info->update|= HA_STATE_AKTIV; /* Record is read */ DBUG_RETURN(0); } DBUG_PRINT("error",("Got error: %d, errno: %d",error, my_errno)); DBUG_RETURN(my_errno); } /* mi_rnext */