mi_rkey.c 5.85 KB
Newer Older
unknown's avatar
unknown committed
1
/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB
unknown's avatar
 
unknown committed
2

unknown's avatar
unknown committed
3 4 5 6
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.
unknown's avatar
 
unknown committed
7

unknown's avatar
unknown committed
8 9 10 11
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
unknown's avatar
 
unknown committed
12

unknown's avatar
unknown committed
13 14 15 16 17 18 19
   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

/* Read record based on a key */

#include "myisamdef.h"
20
#include "rt_index.h"
unknown's avatar
unknown committed
21 22 23 24

	/* Read a record using key */
	/* Ordinary search_flag is 0 ; Give error if no record with key */

unknown's avatar
unknown committed
25
int mi_rkey(MI_INFO *info, byte *buf, int inx, const byte *key, uint key_len,
26
	    enum ha_rkey_function search_flag)
unknown's avatar
unknown committed
27 28 29
{
  uchar *key_buff;
  MYISAM_SHARE *share=info->s;
30
  MI_KEYDEF *keyinfo;
unknown's avatar
unknown committed
31
  HA_KEYSEG *last_used_keyseg;
unknown's avatar
unknown committed
32
  uint pack_key_length, use_key_length, nextflag;
33
  DBUG_ENTER("mi_rkey");
unknown's avatar
unknown committed
34 35
  DBUG_PRINT("enter", ("base: %lx  buf: %lx  inx: %d  search_flag: %d",
                       (long) info, (long) buf, inx, search_flag));
unknown's avatar
unknown committed
36 37 38 39 40

  if ((inx = _mi_check_index(info,inx)) < 0)
    DBUG_RETURN(my_errno);

  info->update&= (HA_STATE_CHANGED | HA_STATE_ROW_CHANGED);
unknown's avatar
unknown committed
41
  info->last_key_func= search_flag;
42
  keyinfo= share->keyinfo + inx;
unknown's avatar
 
unknown committed
43

unknown's avatar
unknown committed
44 45
  if (info->once_flags & USE_PACKED_KEYS)
  {
unknown's avatar
unknown committed
46
    info->once_flags&= ~USE_PACKED_KEYS;	/* Reset flag */
47 48 49
    /*
      key is already packed!;  This happens when we are using a MERGE TABLE
    */
unknown's avatar
unknown committed
50
    key_buff=info->lastkey+info->s->base.max_key_length;
51
    pack_key_length= key_len;
unknown's avatar
unknown committed
52
    bmove(key_buff,key,key_len);
53
    last_used_keyseg= 0;
unknown's avatar
unknown committed
54 55
  }
  else
unknown's avatar
 
unknown committed
56
  {
57 58
    if (key_len == 0)
      key_len=USE_WHOLE_KEY;
59
    /* Save the packed key for later use in the second buffer of lastkey. */
60
    key_buff=info->lastkey+info->s->base.max_key_length;
unknown's avatar
unknown committed
61 62
    pack_key_length=_mi_pack_key(info,(uint) inx, key_buff, (uchar*) key,
				 key_len, &last_used_keyseg);
63 64
    /* Save packed_key_length for use by the MERGE engine. */
    info->pack_key_length= pack_key_length;
unknown's avatar
unknown committed
65 66
    DBUG_EXECUTE("key",_mi_print_key(DBUG_FILE, keyinfo->seg,
				     key_buff, pack_key_length););
unknown's avatar
 
unknown committed
67
  }
unknown's avatar
unknown committed
68

unknown's avatar
unknown committed
69
  if (fast_mi_readinfo(info))
unknown's avatar
unknown committed
70
    goto err;
71

unknown's avatar
unknown committed
72 73
  if (share->concurrent_insert)
    rw_rdlock(&share->key_root_lock[inx]);
unknown's avatar
unknown committed
74 75 76 77 78 79

  nextflag=myisam_read_vec[search_flag];
  use_key_length=pack_key_length;
  if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST)))
    use_key_length=USE_WHOLE_KEY;

unknown's avatar
unknown committed
80
  switch (info->s->keyinfo[inx].key_alg) {
81
#ifdef HAVE_RTREE_KEYS
82
  case HA_KEY_ALG_RTREE:
unknown's avatar
unknown committed
83
    if (rtree_find_first(info,inx,key_buff,use_key_length,nextflag) < 0)
84
    {
unknown's avatar
unknown committed
85
      mi_print_error(info->s, HA_ERR_CRASHED);
86 87 88 89
      my_errno=HA_ERR_CRASHED;
      goto err;
    }
    break;
90
#endif
91 92
  case HA_KEY_ALG_BTREE:
  default:
unknown's avatar
unknown committed
93
    if (!_mi_search(info, keyinfo, key_buff, use_key_length,
94
                    myisam_read_vec[search_flag], info->s->state.key_root[inx]))
unknown's avatar
unknown committed
95 96
    {
      /*
97 98 99
        If we searching for a partial key (or using >, >=, < or <=) and
        the data is outside of the data file, we need to continue searching
        for the first key inside the data file
unknown's avatar
unknown committed
100
      */
101 102 103
      if (info->lastpos >= info->state->data_file_length &&
          (search_flag != HA_READ_KEY_EXACT ||
           last_used_keyseg != keyinfo->seg + keyinfo->keysegs))
104
      {
105
        do
106
        {
107
          uint not_used[2];
108 109 110 111 112 113 114 115 116 117 118
          /*
            Skip rows that are inserted by other threads since we got a lock
            Note that this can only happen if we are not searching after an
            full length exact key, because the keys are sorted
            according to position
          */
          if  (_mi_search_next(info, keyinfo, info->lastkey,
                               info->lastkey_length,
                               myisam_readnext_vec[search_flag],
                               info->s->state.key_root[inx]))
            break;
119 120 121 122 123 124 125
          /*
            Check that the found key does still match the search.
            _mi_search_next() delivers the next key regardless of its
            value.
          */
          if (search_flag == HA_READ_KEY_EXACT &&
              ha_key_cmp(keyinfo->seg, key_buff, info->lastkey, use_key_length,
126
                         SEARCH_FIND, not_used))
127 128 129 130 131 132
          {
            my_errno= HA_ERR_KEY_NOT_FOUND;
            info->lastpos= HA_OFFSET_ERROR;
            break;
          }
        } while (info->lastpos >= info->state->data_file_length);
133
      }
unknown's avatar
unknown committed
134 135
    }
  }
136

unknown's avatar
unknown committed
137 138 139
  if (share->concurrent_insert)
    rw_unlock(&share->key_root_lock[inx]);

140
  /* Calculate length of the found key;  Used by mi_rnext_same */
141 142
  if ((keyinfo->flag & HA_VAR_LENGTH_KEY) && last_used_keyseg &&
      info->lastpos != HA_OFFSET_ERROR)
143 144 145 146
    info->last_rkey_length= _mi_keylength_part(keyinfo, info->lastkey,
					       last_used_keyseg);
  else
    info->last_rkey_length= pack_key_length;
147 148

  /* Check if we don't want to have record back, only error message */
unknown's avatar
 
unknown committed
149
  if (!buf)
150
    DBUG_RETURN(info->lastpos == HA_OFFSET_ERROR ? my_errno : 0);
unknown's avatar
 
unknown committed
151

unknown's avatar
unknown committed
152 153 154 155 156 157 158 159
  if (!(*info->read_record)(info,info->lastpos,buf))
  {
    info->update|= HA_STATE_AKTIV;		/* Record is read */
    DBUG_RETURN(0);
  }

  info->lastpos = HA_OFFSET_ERROR;		/* Didn't find key */

160
  /* Store last used key as a base for read next */
unknown's avatar
unknown committed
161
  memcpy(info->lastkey,key_buff,pack_key_length);
162
  info->last_rkey_length= pack_key_length;
unknown's avatar
unknown committed
163 164 165 166 167 168 169
  bzero((char*) info->lastkey+pack_key_length,info->s->base.rec_reflength);
  info->lastkey_length=pack_key_length+info->s->base.rec_reflength;

  if (search_flag == HA_READ_AFTER_KEY)
    info->update|=HA_STATE_NEXT_FOUND;		/* Previous gives last row */
err:
  DBUG_RETURN(my_errno);
unknown's avatar
 
unknown committed
170
} /* _mi_rkey */