1
/* Copyright (C) 2006 MySQL AB & MySQL Finland AB & TCX DataKonsult 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
/* Read record based on a key */
18
#include "maria_def.h"
19
#include "ma_rt_index.h"
22
Read a record using key
25
Ordinary search_flag is 0 ; Give error if no record with key
28
int maria_rkey(MARIA_HA *info, uchar *buf, int inx, const uchar *key_data,
29
key_part_map keypart_map, enum ha_rkey_function search_flag)
32
MARIA_SHARE *share= info->s;
33
MARIA_KEYDEF *keyinfo;
34
HA_KEYSEG *last_used_keyseg;
37
ICP_RESULT icp_res= ICP_MATCH;
38
DBUG_ENTER("maria_rkey");
39
DBUG_PRINT("enter", ("base: 0x%lx buf: 0x%lx inx: %d search_flag: %d",
40
(long) info, (long) buf, inx, search_flag));
42
if ((inx = _ma_check_index(info,inx)) < 0)
43
DBUG_RETURN(my_errno);
45
info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
46
info->last_key_func= search_flag;
47
keyinfo= info->last_key.keyinfo;
49
key_buff= info->lastkey_buff+info->s->base.max_key_length;
51
if (info->once_flags & USE_PACKED_KEYS)
53
info->once_flags&= ~USE_PACKED_KEYS; /* Reset flag */
55
key is already packed!; This happens when we are using a MERGE TABLE
56
In this key 'key_part_map' is the length of the key !
58
bmove(key_buff, key_data, keypart_map);
61
key.data_length= keypart_map;
65
last_used_keyseg= keyinfo->seg + info->last_used_keyseg;
69
DBUG_ASSERT(keypart_map);
70
/* Save the packed key for later use in the second buffer of lastkey. */
71
_ma_pack_key(info, &key, inx, key_buff, key_data,
72
keypart_map, &last_used_keyseg);
73
/* Save packed_key_length for use by the MERGE engine. */
74
info->pack_key_length= key.data_length;
75
info->last_used_keyseg= (uint16) (last_used_keyseg -
77
DBUG_EXECUTE("key", _ma_print_key(DBUG_FILE, &key););
80
if (fast_ma_readinfo(info))
82
if (share->lock_key_trees)
83
mysql_rwlock_rdlock(&keyinfo->root_lock);
85
nextflag= maria_read_vec[search_flag] | key.flag;
86
if (search_flag != HA_READ_KEY_EXACT)
88
/* Assume we will get a read next/previous call after this one */
89
nextflag|= SEARCH_SAVE_BUFF;
91
switch (keyinfo->key_alg) {
92
#ifdef HAVE_RTREE_KEYS
93
case HA_KEY_ALG_RTREE:
94
if (maria_rtree_find_first(info, &key, nextflag) < 0)
96
_ma_set_fatal_error(share, HA_ERR_CRASHED);
97
info->cur_row.lastpos= HA_OFFSET_ERROR;
101
case HA_KEY_ALG_BTREE:
103
if (!_ma_search(info, &key, nextflag, info->s->state.key_root[inx]))
107
Found a key, but it might not be usable. We cannot use rows that
108
are inserted by other threads after we got our table lock
109
("concurrent inserts"). The record may not even be present yet.
110
Keys are inserted into the index(es) before the record is
111
inserted into the data file.
113
If index condition is present, it must be either satisfied or
114
not satisfied with an out-of-range condition.
116
if ((*share->row_is_visible)(info) &&
117
((icp_res= ma_check_index_cond(info, inx, buf)) != ICP_NO_MATCH))
120
/* The key references a concurrently inserted record. */
121
if (search_flag == HA_READ_KEY_EXACT &&
122
last_used_keyseg == keyinfo->seg + keyinfo->keysegs)
124
/* Simply ignore the key if it matches exactly. (Bug #29838) */
125
my_errno= HA_ERR_KEY_NOT_FOUND;
126
info->cur_row.lastpos= HA_OFFSET_ERROR;
130
lastkey.keyinfo= keyinfo;
131
lastkey.data= info->lastkey_buff;
136
Skip rows that are inserted by other threads since we got
137
a lock. Note that this can only happen if we are not
138
searching after a full length exact key, because the keys
139
are sorted according to position.
141
lastkey.data_length= info->last_key.data_length;
142
lastkey.ref_length= info->last_key.ref_length;
143
lastkey.flag= info->last_key.flag;
144
if (_ma_search_next(info, &lastkey, maria_readnext_vec[search_flag],
145
info->s->state.key_root[inx]))
146
break; /* purecov: inspected */
149
If we are at the last key on the key page, allow writers to
152
if (info->int_keypos >= info->int_maxpos &&
153
ma_yield_and_check_if_killed(info, inx))
155
DBUG_ASSERT(info->cur_row.lastpos == HA_OFFSET_ERROR);
160
Check that the found key does still match the search.
161
_ma_search_next() delivers the next key regardless of its
164
if (!(nextflag & (SEARCH_BIGGER | SEARCH_SMALLER)) &&
165
ha_key_cmp(keyinfo->seg, info->last_key.data, key.data,
166
key.data_length, SEARCH_FIND, not_used))
168
/* purecov: begin inspected */
169
my_errno= HA_ERR_KEY_NOT_FOUND;
170
info->cur_row.lastpos= HA_OFFSET_ERROR;
175
} while (!(*share->row_is_visible)(info) ||
176
((icp_res= ma_check_index_cond(info, inx, buf)) == 0));
180
DBUG_ASSERT(info->cur_row.lastpos);
183
if (share->lock_key_trees)
184
mysql_rwlock_unlock(&keyinfo->root_lock);
186
if (info->cur_row.lastpos == HA_OFFSET_ERROR)
188
if (icp_res == ICP_OUT_OF_RANGE)
190
/* We don't want HA_ERR_END_OF_FILE in this particular case */
191
my_errno= HA_ERR_KEY_NOT_FOUND;
193
fast_ma_writeinfo(info);
197
/* Calculate length of the found key; Used by maria_rnext_same */
198
if ((keyinfo->flag & HA_VAR_LENGTH_KEY))
199
info->last_rkey_length= _ma_keylength_part(keyinfo, info->lastkey_buff,
202
info->last_rkey_length= key.data_length;
204
/* Check if we don't want to have record back, only error message */
207
fast_ma_writeinfo(info);
210
if (!(*info->read_record)(info, buf, info->cur_row.lastpos))
212
info->update|= HA_STATE_AKTIV; /* Record is read */
216
info->cur_row.lastpos= HA_OFFSET_ERROR; /* Didn't find row */
219
/* Store last used key as a base for read next */
220
memcpy(info->last_key.data, key_buff, key.data_length);
221
info->last_key.data_length= key.data_length;
222
info->last_key.ref_length= info->s->base.rec_reflength;
223
info->last_key.flag= 0;
224
/* Create key with rowid 0 */
225
bzero((char*) info->last_key.data + info->last_key.data_length,
226
info->s->base.rec_reflength);
228
if (search_flag == HA_READ_AFTER_KEY)
229
info->update|=HA_STATE_NEXT_FOUND; /* Previous gives last row */
230
DBUG_RETURN(my_errno);
235
Yield to possible other writers during a index scan.
236
Check also if we got killed by the user and if yes, return
237
HA_ERR_LOCK_WAIT_TIMEOUT
240
return 1 Query has been requested to be killed
243
my_bool ma_yield_and_check_if_killed(MARIA_HA *info, int inx)
248
/* purecov: begin tested */
249
/* Mark that we don't have an active row */
250
info->cur_row.lastpos= HA_OFFSET_ERROR;
251
/* Set error that we where aborted by kill from application */
252
my_errno= HA_ERR_ABORTED_BY_USER;
257
if ((share= info->s)->lock_key_trees)
259
/* Give writers a chance to access index */
260
mysql_rwlock_unlock(&share->keyinfo[inx].root_lock);
261
mysql_rwlock_rdlock(&share->keyinfo[inx].root_lock);