~drizzle-trunk/drizzle/development

1 by brian
clean slate
1
/* Copyright (C) 2000-2006 MySQL AB
2
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.
6
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.
11
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 */
15
16
/* Read record based on a key */
17
18
#include "myisamdef.h"
19
20
	/* Read a record using key */
21
	/* Ordinary search_flag is 0 ; Give error if no record with key */
22
23
int mi_rkey(MI_INFO *info, uchar *buf, int inx, const uchar *key,
24
            key_part_map keypart_map, enum ha_rkey_function search_flag)
25
{
26
  uchar *key_buff;
27
  MYISAM_SHARE *share=info->s;
28
  MI_KEYDEF *keyinfo;
29
  HA_KEYSEG *last_used_keyseg;
30
  uint pack_key_length, use_key_length, nextflag;
31
  uint myisam_search_flag;
32
  int res= 0;
33
34
  if ((inx = _mi_check_index(info,inx)) < 0)
51.1.109 by Jay Pipes
Removed/replaced DBUG
35
    return(my_errno);
1 by brian
clean slate
36
37
  info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
38
  info->last_key_func= search_flag;
39
  keyinfo= share->keyinfo + inx;
40
41
  if (info->once_flags & USE_PACKED_KEYS)
42
  {
43
    info->once_flags&= ~USE_PACKED_KEYS;	/* Reset flag */
44
    /*
45
      key is already packed!;  This happens when we are using a MERGE TABLE
46
      In this key 'key_part_map' is the length of the key !
47
    */
48
    key_buff=info->lastkey+info->s->base.max_key_length;
49
    pack_key_length= keypart_map;
212.6.3 by Mats Kindahl
Removing deprecated functions from code and replacing them with C99 equivalents:
50
    memcpy(key_buff, key, pack_key_length);
1 by brian
clean slate
51
    last_used_keyseg= info->s->keyinfo[inx].seg + info->last_used_keyseg;
52
  }
53
  else
54
  {
51.1.109 by Jay Pipes
Removed/replaced DBUG
55
    assert(keypart_map);
1 by brian
clean slate
56
    /* Save the packed key for later use in the second buffer of lastkey. */
57
    key_buff=info->lastkey+info->s->base.max_key_length;
58
    pack_key_length=_mi_pack_key(info,(uint) inx, key_buff, (uchar*) key,
59
				 keypart_map, &last_used_keyseg);
60
    /* Save packed_key_length for use by the MERGE engine. */
61
    info->pack_key_length= pack_key_length;
206 by Brian Aker
Removed final uint dead types.
62
    info->last_used_keyseg= (uint16_t) (last_used_keyseg -
1 by brian
clean slate
63
                                      info->s->keyinfo[inx].seg);
64
  }
65
66
  if (fast_mi_readinfo(info))
67
    goto err;
68
69
  if (share->concurrent_insert)
70
    rw_rdlock(&share->key_root_lock[inx]);
71
72
  nextflag=myisam_read_vec[search_flag];
73
  use_key_length=pack_key_length;
74
  if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST)))
75
    use_key_length=USE_WHOLE_KEY;
76
77
  switch (info->s->keyinfo[inx].key_alg) {
78
  case HA_KEY_ALG_BTREE:
79
  default:
80
    myisam_search_flag= myisam_read_vec[search_flag];
81
    if (!_mi_search(info, keyinfo, key_buff, use_key_length,
82
                    myisam_search_flag, info->s->state.key_root[inx]))
83
    {
84
      /*
85
        Found a key, but it might not be usable. We cannot use rows that
86
        are inserted by other threads after we got our table lock
87
        ("concurrent inserts"). The record may not even be present yet.
88
        Keys are inserted into the index(es) before the record is
89
        inserted into the data file. When we got our table lock, we
90
        saved the current data_file_length. Concurrent inserts always go
91
        to the end of the file. So we can test if the found key
92
        references a new record.
93
94
        If we are searching for a partial key (or using >, >=, < or <=) and
95
        the data is outside of the data file, we need to continue searching
96
        for the first key inside the data file.
97
98
        We do also continue searching if an index condition check function
99
        is available.
100
      */
101
      while ((info->lastpos >= info->state->data_file_length &&
102
              (search_flag != HA_READ_KEY_EXACT ||
103
              last_used_keyseg != keyinfo->seg + keyinfo->keysegs)) ||
104
             (info->index_cond_func && 
105
              !(res= mi_check_index_cond(info, inx, buf))))
106
      {
107
        uint not_used[2];
108
        /*
109
          Skip rows that are inserted by other threads since we got a lock
110
          Note that this can only happen if we are not searching after an
111
          full length exact key, because the keys are sorted
112
          according to position
113
        */
114
        if  (_mi_search_next(info, keyinfo, info->lastkey,
115
                             info->lastkey_length,
116
                             myisam_readnext_vec[search_flag],
117
                             info->s->state.key_root[inx]))
118
          break;
119
        /*
120
          Check that the found key does still match the search.
121
          _mi_search_next() delivers the next key regardless of its
122
          value.
123
        */
124
        if (search_flag == HA_READ_KEY_EXACT &&
125
            ha_key_cmp(keyinfo->seg, key_buff, info->lastkey, use_key_length,
126
                       SEARCH_FIND, not_used))
127
        {
128
          my_errno= HA_ERR_KEY_NOT_FOUND;
129
          info->lastpos= HA_OFFSET_ERROR;
130
          break;
131
        }
132
      }
133
      if (res == 2)
134
      {
135
        info->lastpos= HA_OFFSET_ERROR;
136
        if (share->concurrent_insert)
137
          rw_unlock(&share->key_root_lock[inx]);
51.1.109 by Jay Pipes
Removed/replaced DBUG
138
        return((my_errno= HA_ERR_KEY_NOT_FOUND));
1 by brian
clean slate
139
      }
140
      /*
141
        Error if no row found within the data file. (Bug #29838)
142
        Do not overwrite my_errno if already at HA_OFFSET_ERROR.
143
      */
144
      if (info->lastpos != HA_OFFSET_ERROR &&
145
          info->lastpos >= info->state->data_file_length)
146
      {
147
        info->lastpos= HA_OFFSET_ERROR;
148
        my_errno= HA_ERR_KEY_NOT_FOUND;
149
      }
150
    }
151
  }
152
  if (share->concurrent_insert)
153
    rw_unlock(&share->key_root_lock[inx]);
154
155
  /* Calculate length of the found key;  Used by mi_rnext_same */
156
  if ((keyinfo->flag & HA_VAR_LENGTH_KEY) && last_used_keyseg &&
157
      info->lastpos != HA_OFFSET_ERROR)
158
    info->last_rkey_length= _mi_keylength_part(keyinfo, info->lastkey,
159
					       last_used_keyseg);
160
  else
161
    info->last_rkey_length= pack_key_length;
162
163
  /* Check if we don't want to have record back, only error message */
164
  if (!buf)
51.1.109 by Jay Pipes
Removed/replaced DBUG
165
    return(info->lastpos == HA_OFFSET_ERROR ? my_errno : 0);
1 by brian
clean slate
166
167
  if (!(*info->read_record)(info,info->lastpos,buf))
168
  {
169
    info->update|= HA_STATE_AKTIV;		/* Record is read */
51.1.109 by Jay Pipes
Removed/replaced DBUG
170
    return(0);
1 by brian
clean slate
171
  }
172
173
  info->lastpos = HA_OFFSET_ERROR;		/* Didn't find key */
174
175
  /* Store last used key as a base for read next */
176
  memcpy(info->lastkey,key_buff,pack_key_length);
177
  info->last_rkey_length= pack_key_length;
212.6.12 by Mats Kindahl
Removing redundant use of casts in MyISAM storage for memcmp(), memcpy(), memset(), and memmove().
178
  memset(info->lastkey+pack_key_length, 0, info->s->base.rec_reflength);
1 by brian
clean slate
179
  info->lastkey_length=pack_key_length+info->s->base.rec_reflength;
180
181
  if (search_flag == HA_READ_AFTER_KEY)
182
    info->update|=HA_STATE_NEXT_FOUND;		/* Previous gives last row */
183
err:
51.1.109 by Jay Pipes
Removed/replaced DBUG
184
  return(my_errno);
1 by brian
clean slate
185
} /* _mi_rkey */