MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
mi_key.c
1 /* Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 /* Functions to handle keys */
17 
18 #include "myisamdef.h"
19 #include "m_ctype.h"
20 #include "sp_defs.h"
21 #ifdef HAVE_IEEEFP_H
22 #include <ieeefp.h>
23 #endif
24 
25 #define CHECK_KEYS /* Enable safety checks */
26 
27 #define FIX_LENGTH(cs, pos, length, char_length) \
28  do { \
29  if (length > char_length) \
30  char_length= my_charpos(cs, pos, pos+length, char_length); \
31  set_if_smaller(char_length,length); \
32  } while(0)
33 
34 static int _mi_put_key_in_record(MI_INFO *info, uint keynr,
35  my_bool unpack_blobs, uchar *record);
36 
37 /*
38  Make a intern key from a record
39 
40  SYNOPSIS
41  _mi_make_key()
42  info MyiSAM handler
43  keynr key number
44  key Store created key here
45  record Record
46  filepos Position to record in the data file
47 
48  RETURN
49  Length of key
50 */
51 
52 uint _mi_make_key(register MI_INFO *info, uint keynr, uchar *key,
53  const uchar *record, my_off_t filepos)
54 {
55  uchar *pos;
56  uchar *start;
57  reg1 HA_KEYSEG *keyseg;
58  my_bool is_ft= info->s->keyinfo[keynr].flag & HA_FULLTEXT;
59  DBUG_ENTER("_mi_make_key");
60 
61  if (info->s->keyinfo[keynr].flag & HA_SPATIAL)
62  {
63  /*
64  TODO: nulls processing
65  */
66 #ifdef HAVE_SPATIAL
67  DBUG_RETURN(sp_make_key(info,keynr,key,record,filepos));
68 #else
69  DBUG_ASSERT(0); /* mi_open should check that this never happens*/
70 #endif
71  }
72 
73  start=key;
74  for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
75  {
76  enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type;
77  uint length=keyseg->length;
78  uint char_length;
79  const CHARSET_INFO *cs= keyseg->charset;
80 
81  if (keyseg->null_bit)
82  {
83  if (record[keyseg->null_pos] & keyseg->null_bit)
84  {
85  *key++= 0; /* NULL in key */
86  continue;
87  }
88  *key++=1; /* Not NULL */
89  }
90 
91  char_length= ((!is_ft && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen :
92  length);
93 
94  pos= (uchar*) record+keyseg->start;
95  if (type == HA_KEYTYPE_BIT)
96  {
97  if (keyseg->bit_length)
98  {
99  uchar bits= get_rec_bits((uchar*) record + keyseg->bit_pos,
100  keyseg->bit_start, keyseg->bit_length);
101  *key++= bits;
102  length--;
103  }
104  memcpy((uchar*) key, pos, length);
105  key+= length;
106  continue;
107  }
108  if (keyseg->flag & HA_SPACE_PACK)
109  {
110  if (type != HA_KEYTYPE_NUM)
111  {
112  length= cs->cset->lengthsp(cs, (char*) pos, length);
113  }
114  else
115  {
116  uchar *end= pos + length;
117  while (pos < end && pos[0] == ' ')
118  pos++;
119  length=(uint) (end-pos);
120  }
121  FIX_LENGTH(cs, pos, length, char_length);
122  store_key_length_inc(key,char_length);
123  memcpy((uchar*) key,(uchar*) pos,(size_t) char_length);
124  key+=char_length;
125  continue;
126  }
127  if (keyseg->flag & HA_VAR_LENGTH_PART)
128  {
129  uint pack_length= (keyseg->bit_start == 1 ? 1 : 2);
130  uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos :
131  uint2korr(pos));
132  pos+= pack_length; /* Skip VARCHAR length */
133  set_if_smaller(length,tmp_length);
134  FIX_LENGTH(cs, pos, length, char_length);
135  store_key_length_inc(key,char_length);
136  memcpy((uchar*) key,(uchar*) pos,(size_t) char_length);
137  key+= char_length;
138  continue;
139  }
140  else if (keyseg->flag & HA_BLOB_PART)
141  {
142  uint tmp_length=_mi_calc_blob_length(keyseg->bit_start,pos);
143  memcpy(&pos,pos+keyseg->bit_start,sizeof(char*));
144  set_if_smaller(length,tmp_length);
145  FIX_LENGTH(cs, pos, length, char_length);
146  store_key_length_inc(key,char_length);
147  memcpy((uchar*) key,(uchar*) pos,(size_t) char_length);
148  key+= char_length;
149  continue;
150  }
151  else if (keyseg->flag & HA_SWAP_KEY)
152  { /* Numerical column */
153 #ifdef HAVE_ISNAN
154  if (type == HA_KEYTYPE_FLOAT)
155  {
156  float nr;
157  float4get(nr,pos);
158  if (isnan(nr))
159  {
160  /* Replace NAN with zero */
161  memset(key, 0, length);
162  key+=length;
163  continue;
164  }
165  }
166  else if (type == HA_KEYTYPE_DOUBLE)
167  {
168  double nr;
169  float8get(nr,pos);
170  if (isnan(nr))
171  {
172  memset(key, 0, length);
173  key+=length;
174  continue;
175  }
176  }
177 #endif
178  pos+=length;
179  while (length--)
180  {
181  *key++ = *--pos;
182  }
183  continue;
184  }
185  FIX_LENGTH(cs, pos, length, char_length);
186  memcpy((uchar*) key, pos, char_length);
187  if (length > char_length)
188  cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
189  key+= length;
190  }
191  _mi_dpointer(info,key,filepos);
192  DBUG_PRINT("exit",("keynr: %d",keynr));
193  DBUG_DUMP("key",(uchar*) start,(uint) (key-start)+keyseg->length);
194  DBUG_EXECUTE("key",
195  _mi_print_key(DBUG_FILE,info->s->keyinfo[keynr].seg,start,
196  (uint) (key-start)););
197  DBUG_RETURN((uint) (key-start)); /* Return keylength */
198 } /* _mi_make_key */
199 
200 
201 /*
202  Pack a key to intern format from given format (c_rkey)
203 
204  SYNOPSIS
205  _mi_pack_key()
206  info MyISAM handler
207  uint keynr key number
208  key Store packed key here
209  old Not packed key
210  keypart_map bitmap of used keyparts
211  last_used_keyseg out parameter. May be NULL
212 
213  RETURN
214  length of packed key
215 
216  last_use_keyseg Store pointer to the keyseg after the last used one
217 */
218 
219 uint _mi_pack_key(register MI_INFO *info, uint keynr, uchar *key, uchar *old,
220  key_part_map keypart_map, HA_KEYSEG **last_used_keyseg)
221 {
222  uchar *start_key=key;
223  HA_KEYSEG *keyseg;
224  my_bool is_ft= info->s->keyinfo[keynr].flag & HA_FULLTEXT;
225  DBUG_ENTER("_mi_pack_key");
226 
227  /* "one part" rtree key is 2*SPDIMS part key in MyISAM */
228  if (info->s->keyinfo[keynr].key_alg == HA_KEY_ALG_RTREE)
229  keypart_map= (((key_part_map)1) << (2*SPDIMS)) - 1;
230 
231  /* only key prefixes are supported */
232  DBUG_ASSERT(((keypart_map+1) & keypart_map) == 0);
233 
234  for (keyseg= info->s->keyinfo[keynr].seg ; keyseg->type && keypart_map;
235  old+= keyseg->length, keyseg++)
236  {
237  enum ha_base_keytype type= (enum ha_base_keytype) keyseg->type;
238  uint length= keyseg->length;
239  uint char_length;
240  uchar *pos;
241 
242  const CHARSET_INFO *cs= keyseg->charset;
243  keypart_map>>= 1;
244  if (keyseg->null_bit)
245  {
246  if (!(*key++= (char) 1-*old++)) /* Copy null marker */
247  {
248  if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
249  old+= 2;
250  continue; /* Found NULL */
251  }
252  }
253  char_length= (!is_ft && cs && cs->mbmaxlen > 1) ? length/cs->mbmaxlen : length;
254  pos=old;
255  if (keyseg->flag & HA_SPACE_PACK)
256  {
257  if (type == HA_KEYTYPE_NUM)
258  {
259  uchar *end= pos + length;
260  while (pos < end && pos[0] == ' ')
261  pos++;
262  length= (uint) (end - pos);
263  }
264  else if (type != HA_KEYTYPE_BINARY)
265  {
266  length= cs->cset->lengthsp(cs, (char*) pos, length);
267  }
268  FIX_LENGTH(cs, pos, length, char_length);
269  store_key_length_inc(key,char_length);
270  memcpy((uchar*) key,pos,(size_t) char_length);
271  key+= char_length;
272  continue;
273  }
274  else if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART))
275  {
276  /* Length of key-part used with mi_rkey() always 2 */
277  uint tmp_length=uint2korr(pos);
278  pos+=2;
279  set_if_smaller(length,tmp_length); /* Safety */
280  FIX_LENGTH(cs, pos, length, char_length);
281  store_key_length_inc(key,char_length);
282  old+=2; /* Skip length */
283  memcpy((uchar*) key, pos,(size_t) char_length);
284  key+= char_length;
285  continue;
286  }
287  else if (keyseg->flag & HA_SWAP_KEY)
288  { /* Numerical column */
289  pos+=length;
290  while (length--)
291  *key++ = *--pos;
292  continue;
293  }
294  FIX_LENGTH(cs, pos, length, char_length);
295  memcpy((uchar*) key, pos, char_length);
296  if (length > char_length)
297  cs->cset->fill(cs, (char*) key+char_length, length-char_length, ' ');
298  key+= length;
299  }
300  if (last_used_keyseg)
301  *last_used_keyseg= keyseg;
302 
303  DBUG_RETURN((uint) (key-start_key));
304 } /* _mi_pack_key */
305 
306 
307 
308 /*
309  Store found key in record
310 
311  SYNOPSIS
312  _mi_put_key_in_record()
313  info MyISAM handler
314  keynr Key number that was used
315  unpack_blobs TRUE <=> Unpack blob columns
316  FALSE <=> Skip them. This is used by index condition
317  pushdown check function
318  record Store key here
319 
320  Last read key is in info->lastkey
321 
322  NOTES
323  Used when only-keyread is wanted
324 
325  RETURN
326  0 ok
327  1 error
328 */
329 
330 static int _mi_put_key_in_record(register MI_INFO *info, uint keynr,
331  my_bool unpack_blobs, uchar *record)
332 {
333  reg2 uchar *key;
334  uchar *pos,*key_end;
335  reg1 HA_KEYSEG *keyseg;
336  uchar *blob_ptr;
337  DBUG_ENTER("_mi_put_key_in_record");
338 
339  blob_ptr= (uchar*) info->lastkey2; /* Place to put blob parts */
340  key=(uchar*) info->lastkey; /* KEy that was read */
341  key_end=key+info->lastkey_length;
342  for (keyseg=info->s->keyinfo[keynr].seg ; keyseg->type ;keyseg++)
343  {
344  if (keyseg->null_bit)
345  {
346  if (!*key++)
347  {
348  record[keyseg->null_pos]|= keyseg->null_bit;
349  continue;
350  }
351  record[keyseg->null_pos]&= ~keyseg->null_bit;
352  }
353  if (keyseg->type == HA_KEYTYPE_BIT)
354  {
355  uint length= keyseg->length;
356 
357  if (keyseg->bit_length)
358  {
359  uchar bits= *key++;
360  set_rec_bits(bits, record + keyseg->bit_pos, keyseg->bit_start,
361  keyseg->bit_length);
362  length--;
363  }
364  else
365  {
366  clr_rec_bits(record + keyseg->bit_pos, keyseg->bit_start,
367  keyseg->bit_length);
368  }
369  memcpy(record + keyseg->start, (uchar*) key, length);
370  key+= length;
371  continue;
372  }
373  if (keyseg->flag & HA_SPACE_PACK)
374  {
375  uint length;
376  get_key_length(length,key);
377 #ifdef CHECK_KEYS
378  if (length > keyseg->length || key+length > key_end)
379  goto err;
380 #endif
381  pos= record+keyseg->start;
382  if (keyseg->type != (int) HA_KEYTYPE_NUM)
383  {
384  memcpy(pos,key,(size_t) length);
385  keyseg->charset->cset->fill(keyseg->charset,
386  (char*) pos + length,
387  keyseg->length - length,
388  ' ');
389  }
390  else
391  {
392  memset(pos, ' ', keyseg->length-length);
393  memcpy(pos+keyseg->length-length,key,(size_t) length);
394  }
395  key+=length;
396  continue;
397  }
398 
399  if (keyseg->flag & HA_VAR_LENGTH_PART)
400  {
401  uint length;
402  get_key_length(length,key);
403 #ifdef CHECK_KEYS
404  if (length > keyseg->length || key+length > key_end)
405  goto err;
406 #endif
407  /* Store key length */
408  if (keyseg->bit_start == 1)
409  *(uchar*) (record+keyseg->start)= (uchar) length;
410  else
411  int2store(record+keyseg->start, length);
412  /* And key data */
413  memcpy(record+keyseg->start + keyseg->bit_start, (uchar*) key, length);
414  key+= length;
415  }
416  else if (keyseg->flag & HA_BLOB_PART)
417  {
418  uint length;
419  get_key_length(length,key);
420 #ifdef CHECK_KEYS
421  if (length > keyseg->length || key+length > key_end)
422  goto err;
423 #endif
424  if (unpack_blobs)
425  {
426  memcpy(record+keyseg->start+keyseg->bit_start,
427  &blob_ptr, sizeof(char*));
428  memcpy(blob_ptr,key,length);
429  blob_ptr+=length;
430  /* The above changed info->lastkey2. Inform mi_rnext_same(). */
431  info->update&= ~HA_STATE_RNEXT_SAME;
432  _mi_store_blob_length(record+keyseg->start,
433  (uint) keyseg->bit_start,length);
434  }
435  key+=length;
436  }
437  else if (keyseg->flag & HA_SWAP_KEY)
438  {
439  uchar *to= record+keyseg->start+keyseg->length;
440  uchar *end= key+keyseg->length;
441 #ifdef CHECK_KEYS
442  if (end > key_end)
443  goto err;
444 #endif
445  do
446  {
447  *--to= *key++;
448  } while (key != end);
449  continue;
450  }
451  else
452  {
453 #ifdef CHECK_KEYS
454  if (key+keyseg->length > key_end)
455  goto err;
456 #endif
457  memcpy(record+keyseg->start,(uchar*) key,
458  (size_t) keyseg->length);
459  key+= keyseg->length;
460  }
461  }
462  DBUG_RETURN(0);
463 
464 err:
465  DBUG_RETURN(1); /* Crashed row */
466 } /* _mi_put_key_in_record */
467 
468 
469  /* Here when key reads are used */
470 
471 int _mi_read_key_record(MI_INFO *info, my_off_t filepos, uchar *buf)
472 {
473  fast_mi_writeinfo(info);
474  if (filepos != HA_OFFSET_ERROR)
475  {
476  if (info->lastinx >= 0)
477  { /* Read only key */
478  if (_mi_put_key_in_record(info, (uint)info->lastinx, TRUE, buf))
479  {
480  mi_print_error(info->s, HA_ERR_CRASHED);
481  my_errno=HA_ERR_CRASHED;
482  return -1;
483  }
484  info->update|= HA_STATE_AKTIV; /* We should find a record */
485  return 0;
486  }
487  my_errno=HA_ERR_WRONG_INDEX;
488  }
489  return(-1); /* Wrong data to read */
490 }
491 
492 
493 /*
494  Save current key tuple to record and call index condition check function
495 
496  SYNOPSIS
497  mi_check_index_cond()
498  info MyISAM handler
499  keynr Index we're running a scan on
500  record Record buffer to use (it is assumed that index check function
501  will look for column values there)
502 
503  RETURN
504  -1 Error
505  0 Index condition is not satisfied, continue scanning
506  1 Index condition is satisfied
507  2 Index condition is not satisfied, end the scan.
508 */
509 
510 int mi_check_index_cond(register MI_INFO *info, uint keynr, uchar *record)
511 {
512  if (_mi_put_key_in_record(info, keynr, FALSE, record))
513  {
514  mi_print_error(info->s, HA_ERR_CRASHED);
515  my_errno=HA_ERR_CRASHED;
516  return -1;
517  }
518  return info->index_cond_func(info->index_cond_func_arg);
519 }
520 
521 
522 /*
523  Retrieve auto_increment info
524 
525  SYNOPSIS
526  retrieve_auto_increment()
527  info MyISAM handler
528  record Row to update
529 
530  IMPLEMENTATION
531  For signed columns we don't retrieve the auto increment value if it's
532  less than zero.
533 */
534 
535 ulonglong retrieve_auto_increment(MI_INFO *info,const uchar *record)
536 {
537  ulonglong value= 0; /* Store unsigned values here */
538  longlong s_value= 0; /* Store signed values here */
539  HA_KEYSEG *keyseg= info->s->keyinfo[info->s->base.auto_key-1].seg;
540  const uchar *key= (uchar*) record + keyseg->start;
541 
542  switch (keyseg->type) {
543  case HA_KEYTYPE_INT8:
544  s_value= (longlong) *(char*)key;
545  break;
546  case HA_KEYTYPE_BINARY:
547  value=(ulonglong) *(uchar*) key;
548  break;
549  case HA_KEYTYPE_SHORT_INT:
550  s_value= (longlong) sint2korr(key);
551  break;
552  case HA_KEYTYPE_USHORT_INT:
553  value=(ulonglong) uint2korr(key);
554  break;
555  case HA_KEYTYPE_LONG_INT:
556  s_value= (longlong) sint4korr(key);
557  break;
558  case HA_KEYTYPE_ULONG_INT:
559  value=(ulonglong) uint4korr(key);
560  break;
561  case HA_KEYTYPE_INT24:
562  s_value= (longlong) sint3korr(key);
563  break;
564  case HA_KEYTYPE_UINT24:
565  value=(ulonglong) uint3korr(key);
566  break;
567  case HA_KEYTYPE_FLOAT: /* This shouldn't be used */
568  {
569  float f_1;
570  float4get(f_1,key);
571  /* Ignore negative values */
572  value = (f_1 < (float) 0.0) ? 0 : (ulonglong) f_1;
573  break;
574  }
575  case HA_KEYTYPE_DOUBLE: /* This shouldn't be used */
576  {
577  double f_1;
578  float8get(f_1,key);
579  /* Ignore negative values */
580  value = (f_1 < 0.0) ? 0 : (ulonglong) f_1;
581  break;
582  }
583  case HA_KEYTYPE_LONGLONG:
584  s_value= sint8korr(key);
585  break;
586  case HA_KEYTYPE_ULONGLONG:
587  value= uint8korr(key);
588  break;
589  default:
590  DBUG_ASSERT(0);
591  value=0; /* Error */
592  break;
593  }
594 
595  /*
596  The following code works becasue if s_value < 0 then value is 0
597  and if s_value == 0 then value will contain either s_value or the
598  correct value.
599  */
600  return (s_value > 0) ? (ulonglong) s_value : value;
601 }