1
/* Copyright (C) 2000-2006 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
16
/* Read record based on a key */
18
#include "myisam_priv.h"
20
using namespace drizzled;
22
/* Read a record using key */
23
/* Ordinary search_flag is 0 ; Give error if no record with key */
25
int mi_rkey(MI_INFO *info, unsigned char *buf, int inx, const unsigned char *key,
26
key_part_map keypart_map, enum ha_rkey_function search_flag)
28
unsigned char *key_buff;
29
MYISAM_SHARE *share=info->s;
31
HA_KEYSEG *last_used_keyseg;
32
uint32_t pack_key_length, use_key_length, nextflag;
33
uint32_t myisam_search_flag;
36
if ((inx = _mi_check_index(info,inx)) < 0)
39
info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
40
info->last_key_func= search_flag;
41
keyinfo= share->keyinfo + inx;
43
if (info->once_flags & USE_PACKED_KEYS)
45
info->once_flags&= ~USE_PACKED_KEYS; /* Reset flag */
47
key is already packed!; This happens when we are using a MERGE TABLE
48
In this key 'key_part_map' is the length of the key !
50
key_buff=info->lastkey+info->s->base.max_key_length;
51
pack_key_length= keypart_map;
52
memmove(key_buff, key, pack_key_length);
53
last_used_keyseg= info->s->keyinfo[inx].seg + info->last_used_keyseg;
58
/* Save the packed key for later use in the second buffer of lastkey. */
59
key_buff=info->lastkey+info->s->base.max_key_length;
60
pack_key_length=_mi_pack_key(info,(uint) inx, key_buff, (unsigned char*) key,
61
keypart_map, &last_used_keyseg);
62
/* Save packed_key_length for use by the MERGE engine. */
63
info->pack_key_length= pack_key_length;
64
info->last_used_keyseg= (uint16_t) (last_used_keyseg -
65
info->s->keyinfo[inx].seg);
68
if (fast_mi_readinfo(info))
71
nextflag=myisam_read_vec[search_flag];
72
use_key_length=pack_key_length;
73
if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST)))
74
use_key_length=USE_WHOLE_KEY;
76
switch (info->s->keyinfo[inx].key_alg) {
77
case HA_KEY_ALG_BTREE:
79
myisam_search_flag= myisam_read_vec[search_flag];
80
if (!_mi_search(info, keyinfo, key_buff, use_key_length,
81
myisam_search_flag, info->s->state.key_root[inx]))
84
Found a key, but it might not be usable. We cannot use rows that
85
are inserted by other threads after we got our table lock
86
("concurrent inserts"). The record may not even be present yet.
87
Keys are inserted into the index(es) before the record is
88
inserted into the data file. When we got our table lock, we
89
saved the current data_file_length. Concurrent inserts always go
90
to the end of the file. So we can test if the found key
91
references a new record.
93
If we are searching for a partial key (or using >, >=, < or <=) and
94
the data is outside of the data file, we need to continue searching
95
for the first key inside the data file.
97
We do also continue searching if an index condition check function
100
while ((info->lastpos >= info->state->data_file_length &&
101
(search_flag != HA_READ_KEY_EXACT ||
102
last_used_keyseg != keyinfo->seg + keyinfo->keysegs)) ||
103
(info->index_cond_func &&
104
!(res= mi_check_index_cond(info, inx, buf))))
106
uint32_t not_used[2];
108
Skip rows that are inserted by other threads since we got a lock
109
Note that this can only happen if we are not searching after an
110
full length exact key, because the keys are sorted
111
according to position
113
if (_mi_search_next(info, keyinfo, info->lastkey,
114
info->lastkey_length,
115
myisam_readnext_vec[search_flag],
116
info->s->state.key_root[inx]))
119
Check that the found key does still match the search.
120
_mi_search_next() delivers the next key regardless of its
123
if (search_flag == HA_READ_KEY_EXACT &&
124
ha_key_cmp(keyinfo->seg, key_buff, info->lastkey, use_key_length,
125
SEARCH_FIND, not_used))
127
errno= HA_ERR_KEY_NOT_FOUND;
128
info->lastpos= HA_OFFSET_ERROR;
134
info->lastpos= HA_OFFSET_ERROR;
135
return((errno= HA_ERR_KEY_NOT_FOUND));
138
Error if no row found within the data file. (Bug #29838)
139
Do not overwrite errno if already at HA_OFFSET_ERROR.
141
if (info->lastpos != HA_OFFSET_ERROR &&
142
info->lastpos >= info->state->data_file_length)
144
info->lastpos= HA_OFFSET_ERROR;
145
errno= HA_ERR_KEY_NOT_FOUND;
150
/* Calculate length of the found key; Used by mi_rnext_same */
151
if ((keyinfo->flag & HA_VAR_LENGTH_KEY) && last_used_keyseg &&
152
info->lastpos != HA_OFFSET_ERROR)
153
info->last_rkey_length= _mi_keylength_part(keyinfo, info->lastkey,
156
info->last_rkey_length= pack_key_length;
158
/* Check if we don't want to have record back, only error message */
160
return(info->lastpos == HA_OFFSET_ERROR ? errno : 0);
162
if (!(*info->read_record)(info,info->lastpos,buf))
164
info->update|= HA_STATE_AKTIV; /* Record is read */
168
info->lastpos = HA_OFFSET_ERROR; /* Didn't find key */
170
/* Store last used key as a base for read next */
171
memcpy(info->lastkey,key_buff,pack_key_length);
172
info->last_rkey_length= pack_key_length;
173
memset(info->lastkey+pack_key_length, 0, info->s->base.rec_reflength);
174
info->lastkey_length=pack_key_length+info->s->base.rec_reflength;
176
if (search_flag == HA_READ_AFTER_KEY)
177
info->update|=HA_STATE_NEXT_FOUND; /* Previous gives last row */