~linuxjedi/drizzle/trunk-bug-667053

« back to all changes in this revision

Viewing changes to storage/myisam/mi_rkey.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

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