~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to mysys/hash.c

  • Committer: Brian Aker
  • Date: 2008-11-04 15:39:09 UTC
  • mfrom: (575.1.2 devel)
  • Revision ID: brian@tangent.org-20081104153909-c72hn65udxs1ccal
Merge of Monty's work

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000 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
 
/* The hash functions used for saveing keys */
 
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2008 Sun Microsystems
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; version 2 of the License.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
18
 */
 
19
 
 
20
/* The hash functions used for saving keys */
17
21
/* One of key_length or key_length_offset must be given */
18
22
/* Key length of 0 isn't allowed */
19
23
 
20
 
#include "mysys_priv.h"
21
 
#include <mystrings/m_string.h>
22
 
#include <mystrings/m_ctype.h>
23
 
#include "hash.h"
24
 
 
25
 
#define NO_RECORD       ((uint) -1)
26
 
#define LOWFIND 1
27
 
#define LOWUSED 2
28
 
#define HIGHFIND 4
29
 
#define HIGHUSED 8
 
24
#include <config.h>
 
25
#include <mysys/hash.h>
 
26
 
 
27
const uint32_t NO_RECORD= UINT32_MAX;
 
28
 
 
29
const int LOWFIND= 1;
 
30
const int LOWUSED= 2;
 
31
const int HIGHFIND= 4;
 
32
const int HIGHUSED= 8;
30
33
 
31
34
typedef struct st_hash_info {
32
 
  uint next;                                    /* index to next key */
33
 
  uchar *data;                                  /* data for current entry */
 
35
  /* index to next key */
 
36
  uint32_t next;
 
37
  /* data for current entry */
 
38
  unsigned char *data;
34
39
} HASH_LINK;
35
40
 
36
 
static uint hash_mask(uint hashnr,uint buffmax,uint maxlength);
37
 
static void movelink(HASH_LINK *array,uint pos,uint next_link,uint newlink);
38
 
static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key,
 
41
static uint32_t hash_mask(uint32_t hashnr, uint32_t buffmax,
 
42
                          uint32_t maxlength);
 
43
static void movelink(HASH_LINK *array, uint32_t pos,
 
44
                     uint32_t next_link, uint32_t newlink);
 
45
static int hashcmp(const HASH *hash, HASH_LINK *pos, const unsigned char *key,
39
46
                   size_t length);
40
47
 
41
 
static uint calc_hash(const HASH *hash, const uchar *key, size_t length)
 
48
static uint32_t calc_hash(const HASH *hash, const unsigned char *key,
 
49
                          size_t length)
42
50
{
43
51
  uint32_t nr1=1, nr2=4;
44
 
  hash->charset->coll->hash_sort(hash->charset,(const uchar*) key,length,&nr1,&nr2);
 
52
  hash->charset->coll->hash_sort(hash->charset, key,length, &nr1, &nr2);
45
53
  return nr1;
46
54
}
47
55
 
48
56
bool
49
 
_hash_init(HASH *hash,uint growth_size, const CHARSET_INFO * const charset,
50
 
           uint32_t size, size_t key_offset, size_t key_length,
51
 
           hash_get_key get_key,
52
 
           void (*free_element)(void*),uint flags CALLER_INFO_PROTO)
 
57
_hash_init(HASH *hash,uint32_t growth_size, const CHARSET_INFO * const charset,
 
58
           uint32_t size, size_t key_offset, size_t key_length,
 
59
           hash_get_key get_key,
 
60
           void (*free_element)(void*),uint32_t flags CALLER_INFO_PROTO)
53
61
{
54
62
  hash->records=0;
55
63
  if (my_init_dynamic_array_ci(&hash->array, sizeof(HASH_LINK), size,
56
64
                               growth_size))
57
65
  {
58
 
    hash->free=0;                               /* Allow call to hash_free */
 
66
    /* Allow call to hash_free */
 
67
    hash->free=0;
59
68
    return true;
60
69
  }
61
70
  hash->key_offset=key_offset;
73
82
  Call hash->free on all elements in hash.
74
83
 
75
84
  SYNOPSIS
76
 
    hash_free_elements()
77
 
    hash   hash table
 
85
  hash_free_elements()
 
86
  hash   hash table
78
87
 
79
88
  NOTES:
80
 
    Sets records to 0
 
89
  Sets records to 0
81
90
*/
82
91
 
83
92
static inline void hash_free_elements(HASH *hash)
97
106
  Free memory used by hash.
98
107
 
99
108
  SYNOPSIS
100
 
    hash_free()
101
 
    hash   the hash to delete elements of
 
109
  hash_free()
 
110
  hash   the hash to delete elements of
102
111
 
103
112
  NOTES: Hash can't be reused without calling hash_init again.
104
113
*/
116
125
  Delete all elements from the hash (the hash itself is to be reused).
117
126
 
118
127
  SYNOPSIS
119
 
    my_hash_reset()
120
 
    hash   the hash to delete elements of
 
128
  my_hash_reset()
 
129
  hash   the hash to delete elements of
121
130
*/
122
131
 
123
132
void my_hash_reset(HASH *hash)
132
141
/* some helper functions */
133
142
 
134
143
/*
135
 
  This function is char* instead of uchar* as HPUX11 compiler can't
 
144
  This function is char* instead of unsigned char* as HPUX11 compiler can't
136
145
  handle inline functions that are not defined as native types
137
146
*/
138
147
 
139
148
static inline char*
140
 
hash_key(const HASH *hash, const uchar *record, size_t *length,
 
149
hash_key(const HASH *hash, const unsigned char *record, size_t *length,
141
150
         bool first)
142
151
{
143
152
  if (hash->get_key)
146
155
  return (char*) record+hash->key_offset;
147
156
}
148
157
 
149
 
        /* Calculate pos according to keys */
 
158
/* Calculate pos according to keys */
150
159
 
151
 
static uint hash_mask(uint hashnr,uint buffmax,uint maxlength)
 
160
static uint32_t hash_mask(uint32_t hashnr,uint32_t buffmax,uint32_t maxlength)
152
161
{
153
162
  if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
154
163
  return (hashnr & ((buffmax >> 1) -1));
155
164
}
156
165
 
157
 
static uint hash_rec_mask(const HASH *hash, HASH_LINK *pos,
158
 
                          uint buffmax, uint maxlength)
 
166
static uint32_t hash_rec_mask(const HASH *hash, HASH_LINK *pos,
 
167
                              uint32_t buffmax, uint32_t maxlength)
159
168
{
160
169
  size_t length;
161
 
  uchar *key= (uchar*) hash_key(hash,pos->data,&length,0);
 
170
  unsigned char *key= (unsigned char*) hash_key(hash,pos->data,&length,0);
162
171
  return hash_mask(calc_hash(hash,key,length),buffmax,maxlength);
163
172
}
164
173
 
165
174
 
166
175
 
167
 
/* for compilers which can not handle inline */
168
176
static
169
 
#if !defined(__USLC__) && !defined(__sgi)
170
177
inline
171
 
#endif
172
 
unsigned int rec_hashnr(HASH *hash,const uchar *record)
 
178
unsigned int rec_hashnr(HASH *hash,const unsigned char *record)
173
179
{
174
180
  size_t length;
175
 
  uchar *key= (uchar*) hash_key(hash,record,&length,0);
 
181
  unsigned char *key= (unsigned char*) hash_key(hash,record,&length,0);
176
182
  return calc_hash(hash,key,length);
177
183
}
178
184
 
179
185
 
180
 
uchar* hash_search(const HASH *hash, const uchar *key, size_t length)
 
186
unsigned char* hash_search(const HASH *hash, const unsigned char *key,
 
187
                           size_t length)
181
188
{
182
189
  HASH_SEARCH_STATE state;
183
190
  return hash_first(hash, key, length, &state);
187
194
  Search after a record based on a key
188
195
 
189
196
  NOTE
190
 
   Assigns the number of the found record to HASH_SEARCH_STATE state
 
197
  Assigns the number of the found record to HASH_SEARCH_STATE state
191
198
*/
192
199
 
193
 
uchar* hash_first(const HASH *hash, const uchar *key, size_t length,
194
 
                HASH_SEARCH_STATE *current_record)
 
200
unsigned char* hash_first(const HASH *hash, const unsigned char *key,
 
201
                          size_t length,
 
202
                          HASH_SEARCH_STATE *current_record)
195
203
{
196
204
  HASH_LINK *pos;
197
 
  uint flag,idx;
 
205
  uint32_t flag,idx;
198
206
 
199
207
  flag=1;
200
208
  if (hash->records)
201
209
  {
202
210
    idx=hash_mask(calc_hash(hash,key,length ? length : hash->key_length),
203
 
                    hash->blength,hash->records);
 
211
                  hash->blength,hash->records);
204
212
    do
205
213
    {
206
214
      pos= dynamic_element(&hash->array,idx,HASH_LINK*);
207
215
      if (!hashcmp(hash,pos,key,length))
208
216
      {
209
 
        *current_record= idx;
210
 
        return (pos->data);
 
217
        *current_record= idx;
 
218
        return (pos->data);
211
219
      }
212
220
      if (flag)
213
221
      {
214
 
        flag=0;                                 /* Reset flag */
215
 
        if (hash_rec_mask(hash,pos,hash->blength,hash->records) != idx)
216
 
          break;                                /* Wrong link */
 
222
        /* Reset flag */
 
223
        flag=0;
 
224
        if (hash_rec_mask(hash,pos,hash->blength,hash->records) != idx)
 
225
          /* Wrong link */
 
226
          break;
217
227
      }
218
228
    }
219
229
    while ((idx=pos->next) != NO_RECORD);
222
232
  return(0);
223
233
}
224
234
 
225
 
        /* Get next record with identical key */
226
 
        /* Can only be called if previous calls was hash_search */
 
235
/* Get next record with identical key */
 
236
/* Can only be called if previous calls was hash_search */
227
237
 
228
 
uchar* hash_next(const HASH *hash, const uchar *key, size_t length,
229
 
               HASH_SEARCH_STATE *current_record)
 
238
unsigned char* hash_next(const HASH *hash, const unsigned char *key,
 
239
                         size_t length,
 
240
                         HASH_SEARCH_STATE *current_record)
230
241
{
231
242
  HASH_LINK *pos;
232
 
  uint idx;
 
243
  uint32_t idx;
233
244
 
234
245
  if (*current_record != NO_RECORD)
235
246
  {
239
250
      pos=data+idx;
240
251
      if (!hashcmp(hash,pos,key,length))
241
252
      {
242
 
        *current_record= idx;
243
 
        return pos->data;
 
253
        *current_record= idx;
 
254
        return pos->data;
244
255
      }
245
256
    }
246
257
    *current_record= NO_RECORD;
249
260
}
250
261
 
251
262
 
252
 
        /* Change link from pos to new_link */
 
263
/* Change link from pos to new_link */
253
264
 
254
 
static void movelink(HASH_LINK *array,uint find,uint next_link,uint newlink)
 
265
static void movelink(HASH_LINK *array, uint32_t find,
 
266
                     uint32_t next_link, uint32_t newlink)
255
267
{
256
268
  HASH_LINK *old_link;
257
269
  do
267
279
  Compare a key in a record to a whole key. Return 0 if identical
268
280
 
269
281
  SYNOPSIS
270
 
    hashcmp()
271
 
    hash   hash table
272
 
    pos    position of hash record to use in comparison
273
 
    key    key for comparison
274
 
    length length of key
 
282
  hashcmp()
 
283
  hash   hash table
 
284
  pos    position of hash record to use in comparison
 
285
  key    key for comparison
 
286
  length length of key
275
287
 
276
288
  NOTES:
277
 
    If length is 0, comparison is done using the length of the
278
 
    record being compared against.
 
289
  If length is 0, comparison is done using the length of the
 
290
  record being compared against.
279
291
 
280
292
  RETURN
281
 
    = 0  key of record == key
282
 
    != 0 key of record != key
283
 
 */
 
293
  = 0  key of record == key
 
294
  != 0 key of record != key
 
295
*/
284
296
 
285
 
static int hashcmp(const HASH *hash, HASH_LINK *pos, const uchar *key,
 
297
static int hashcmp(const HASH *hash, HASH_LINK *pos, const unsigned char *key,
286
298
                   size_t length)
287
299
{
288
300
  size_t rec_keylength;
289
 
  uchar *rec_key= (uchar*) hash_key(hash,pos->data,&rec_keylength,1);
 
301
  unsigned char *rec_key= (unsigned char*) hash_key(hash, pos->data,
 
302
                                                    &rec_keylength,1);
290
303
  return ((length && length != rec_keylength) ||
291
 
          my_strnncoll(hash->charset, (const uchar*) rec_key, rec_keylength,
292
 
                       (const uchar*) key, rec_keylength));
 
304
          my_strnncoll(hash->charset, rec_key, rec_keylength,
 
305
                       key, rec_keylength));
293
306
}
294
307
 
295
308
 
296
 
        /* Write a hash-key to the hash-index */
 
309
/* Write a hash-key to the hash-index */
297
310
 
298
 
bool my_hash_insert(HASH *info,const uchar *record)
 
311
bool my_hash_insert(HASH *info,const unsigned char *record)
299
312
{
300
313
  int flag;
301
314
  size_t idx;
302
 
  uint halfbuff,hash_nr,first_index;
303
 
  uchar *ptr_to_rec=NULL,*ptr_to_rec2=NULL;
 
315
  uint32_t halfbuff,hash_nr,first_index;
 
316
  unsigned char *ptr_to_rec=NULL,*ptr_to_rec2=NULL;
304
317
  HASH_LINK *data,*empty,*gpos=NULL,*gpos2=NULL,*pos;
305
318
 
306
319
  if (HASH_UNIQUE & info->flags)
307
320
  {
308
 
    uchar *key= (uchar*) hash_key(info, record, &idx, 1);
 
321
    unsigned char *key= (unsigned char*) hash_key(info, record, &idx, 1);
309
322
    if (hash_search(info, key, idx))
310
 
      return(true);                             /* Duplicate entry */
 
323
      /* Duplicate entry */
 
324
      return(true);
311
325
  }
312
326
 
313
327
  flag=0;
314
328
  if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array)))
315
 
    return(true);                               /* No more memory */
 
329
    /* No more memory */
 
330
    return(true);
316
331
 
317
332
  data=dynamic_element(&info->array,0,HASH_LINK*);
318
333
  halfbuff= info->blength >> 1;
319
334
 
320
335
  idx=first_index=info->records-halfbuff;
321
 
  if (idx != info->records)                             /* If some records */
 
336
  /* If some records */
 
337
  if (idx != info->records)
322
338
  {
323
339
    do
324
340
    {
325
341
      pos=data+idx;
326
342
      hash_nr=rec_hashnr(info,pos->data);
327
 
      if (flag == 0)                            /* First loop; Check if ok */
328
 
        if (hash_mask(hash_nr,info->blength,info->records) != first_index)
329
 
          break;
 
343
      /* First loop; Check if ok */
 
344
      if (flag == 0)
 
345
        if (hash_mask(hash_nr,info->blength,info->records) != first_index)
 
346
          break;
330
347
      if (!(hash_nr & halfbuff))
331
 
      {                                         /* Key will not move */
332
 
        if (!(flag & LOWFIND))
333
 
        {
334
 
          if (flag & HIGHFIND)
335
 
          {
336
 
            flag=LOWFIND | HIGHFIND;
337
 
            /* key shall be moved to the current empty position */
338
 
            gpos=empty;
339
 
            ptr_to_rec=pos->data;
340
 
            empty=pos;                          /* This place is now free */
341
 
          }
342
 
          else
343
 
          {
344
 
            flag=LOWFIND | LOWUSED;             /* key isn't changed */
345
 
            gpos=pos;
346
 
            ptr_to_rec=pos->data;
347
 
          }
348
 
        }
349
 
        else
350
 
        {
351
 
          if (!(flag & LOWUSED))
352
 
          {
353
 
            /* Change link of previous LOW-key */
354
 
            gpos->data=ptr_to_rec;
355
 
            gpos->next= (uint) (pos-data);
356
 
            flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
357
 
          }
358
 
          gpos=pos;
359
 
          ptr_to_rec=pos->data;
360
 
        }
 
348
      {
 
349
        /* Key will not move */
 
350
        if (!(flag & LOWFIND))
 
351
        {
 
352
          if (flag & HIGHFIND)
 
353
          {
 
354
            flag=LOWFIND | HIGHFIND;
 
355
            /* key shall be moved to the current empty position */
 
356
            gpos=empty;
 
357
            ptr_to_rec=pos->data;
 
358
            /* This place is now free */
 
359
            empty=pos;
 
360
          }
 
361
          else
 
362
          {
 
363
            /* key isn't changed */
 
364
            flag=LOWFIND | LOWUSED;
 
365
            gpos=pos;
 
366
            ptr_to_rec=pos->data;
 
367
          }
 
368
        }
 
369
        else
 
370
        {
 
371
          if (!(flag & LOWUSED))
 
372
          {
 
373
            /* Change link of previous LOW-key */
 
374
            gpos->data=ptr_to_rec;
 
375
            gpos->next= (uint) (pos-data);
 
376
            flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
 
377
          }
 
378
          gpos=pos;
 
379
          ptr_to_rec=pos->data;
 
380
        }
361
381
      }
362
382
      else
363
 
      {                                         /* key will be moved */
364
 
        if (!(flag & HIGHFIND))
365
 
        {
366
 
          flag= (flag & LOWFIND) | HIGHFIND;
367
 
          /* key shall be moved to the last (empty) position */
368
 
          gpos2 = empty; empty=pos;
369
 
          ptr_to_rec2=pos->data;
370
 
        }
371
 
        else
372
 
        {
373
 
          if (!(flag & HIGHUSED))
374
 
          {
375
 
            /* Change link of previous hash-key and save */
376
 
            gpos2->data=ptr_to_rec2;
377
 
            gpos2->next=(uint) (pos-data);
378
 
            flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
379
 
          }
380
 
          gpos2=pos;
381
 
          ptr_to_rec2=pos->data;
382
 
        }
 
383
      {
 
384
        /* key will be moved */
 
385
        if (!(flag & HIGHFIND))
 
386
        {
 
387
          flag= (flag & LOWFIND) | HIGHFIND;
 
388
          /* key shall be moved to the last (empty) position */
 
389
          gpos2 = empty; empty=pos;
 
390
          ptr_to_rec2=pos->data;
 
391
        }
 
392
        else
 
393
        {
 
394
          if (!(flag & HIGHUSED))
 
395
          {
 
396
            /* Change link of previous hash-key and save */
 
397
            gpos2->data=ptr_to_rec2;
 
398
            gpos2->next=(uint) (pos-data);
 
399
            flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
 
400
          }
 
401
          gpos2=pos;
 
402
          ptr_to_rec2=pos->data;
 
403
        }
383
404
      }
384
405
    }
385
406
    while ((idx=pos->next) != NO_RECORD);
401
422
  pos=data+idx;
402
423
  if (pos == empty)
403
424
  {
404
 
    pos->data=(uchar*) record;
 
425
    pos->data=(unsigned char*) record;
405
426
    pos->next=NO_RECORD;
406
427
  }
407
428
  else
411
432
    gpos=data+hash_rec_mask(info,pos,info->blength,info->records+1);
412
433
    if (pos == gpos)
413
434
    {
414
 
      pos->data=(uchar*) record;
 
435
      pos->data=(unsigned char*) record;
415
436
      pos->next=(uint) (empty - data);
416
437
    }
417
438
    else
418
439
    {
419
 
      pos->data=(uchar*) record;
 
440
      pos->data=(unsigned char*) record;
420
441
      pos->next=NO_RECORD;
421
442
      movelink(data,(uint) (pos-data),(uint) (gpos-data),(uint) (empty-data));
422
443
    }
428
449
 
429
450
 
430
451
/******************************************************************************
431
 
** Remove one record from hash-table. The record with the same record
432
 
** ptr is removed.
433
 
** if there is a free-function it's called for record if found
434
 
******************************************************************************/
 
452
 ** Remove one record from hash-table. The record with the same record
 
453
 ** ptr is removed.
 
454
 ** if there is a free-function it's called for record if found
 
455
 *****************************************************************************/
435
456
 
436
 
bool hash_delete(HASH *hash,uchar *record)
 
457
bool hash_delete(HASH *hash,unsigned char *record)
437
458
{
438
 
  uint blength,pos2,pos_hashnr,lastpos_hashnr,idx,empty_index;
 
459
  uint32_t blength,pos2,pos_hashnr,lastpos_hashnr,idx,empty_index;
439
460
  HASH_LINK *data,*lastpos,*gpos,*pos,*pos3,*empty;
440
461
  if (!hash->records)
441
462
    return(1);
450
471
  {
451
472
    gpos=pos;
452
473
    if (pos->next == NO_RECORD)
453
 
      return(1);                        /* Key not found */
 
474
      /* Key not found */
 
475
      return(1);
 
476
 
454
477
    pos=data+pos->next;
455
478
  }
456
479
 
460
483
  /* Remove link to record */
461
484
  empty=pos; empty_index=(uint) (empty-data);
462
485
  if (gpos)
463
 
    gpos->next=pos->next;               /* unlink current ptr */
 
486
    /* unlink current ptr */
 
487
    gpos->next=pos->next;
464
488
  else if (pos->next != NO_RECORD)
465
489
  {
466
490
    empty=data+(empty_index=pos->next);
468
492
    pos->next=empty->next;
469
493
  }
470
494
 
471
 
  if (empty == lastpos)                 /* last key at wrong pos or no next link */
 
495
  /* last key at wrong pos or no next link */
 
496
  if (empty == lastpos)
472
497
    goto exit;
473
498
 
474
499
  /* Move the last key (lastpos) */
475
500
  lastpos_hashnr=rec_hashnr(hash,lastpos->data);
476
501
  /* pos is where lastpos should be */
477
502
  pos=data+hash_mask(lastpos_hashnr,hash->blength,hash->records);
478
 
  if (pos == empty)                     /* Move to empty position. */
 
503
  /* Move to empty position. */
 
504
  if (pos == empty)
479
505
  {
480
506
    empty[0]=lastpos[0];
481
507
    goto exit;
508
534
  pos->next=empty_index;
509
535
 
510
536
exit:
511
 
  VOID(pop_dynamic(&hash->array));
 
537
  pop_dynamic(&hash->array);
512
538
  if (hash->free)
513
 
    (*hash->free)((uchar*) record);
 
539
    (*hash->free)((unsigned char*) record);
514
540
  return(0);
515
541
}
516
542
 
517
 
        /*
518
 
          Update keys when record has changed.
519
 
          This is much more efficent than using a delete & insert.
520
 
          */
 
543
/*
 
544
  Update keys when record has changed.
 
545
  This is much more efficent than using a delete & insert.
 
546
*/
521
547
 
522
 
bool hash_update(HASH *hash, uchar *record, uchar *old_key,
523
 
                    size_t old_key_length)
 
548
bool hash_update(HASH *hash, unsigned char *record, unsigned char *old_key,
 
549
                 size_t old_key_length)
524
550
{
525
 
  uint new_index,new_pos_index,blength,records,empty;
 
551
  uint32_t new_index,new_pos_index,blength,records,empty;
526
552
  size_t idx;
527
553
  HASH_LINK org_link,*data,*previous,*pos;
528
 
  
 
554
 
529
555
  if (HASH_UNIQUE & hash->flags)
530
556
  {
531
557
    HASH_SEARCH_STATE state;
532
 
    uchar *found, *new_key= (uchar*) hash_key(hash, record, &idx, 1);
 
558
    unsigned char *found,
 
559
      *new_key= (unsigned char*) hash_key(hash, record, &idx, 1);
 
560
 
533
561
    if ((found= hash_first(hash, new_key, idx, &state)))
534
562
    {
535
 
      do 
 
563
      do
536
564
      {
537
565
        if (found != record)
538
566
          return(1);            /* Duplicate entry */
539
 
      } 
 
567
      }
540
568
      while ((found= hash_next(hash, new_key, idx, &state)));
541
569
    }
542
570
  }
547
575
  /* Search after record with key */
548
576
 
549
577
  idx=hash_mask(calc_hash(hash, old_key,(old_key_length ?
550
 
                                              old_key_length :
551
 
                                              hash->key_length)),
552
 
                  blength,records);
 
578
                                         old_key_length :
 
579
                                         hash->key_length)),
 
580
                blength,records);
553
581
  new_index=hash_mask(rec_hashnr(hash,record),blength,records);
554
582
  if (idx == new_index)
555
583
    return(0);                  /* Nothing to do (No record check) */
618
646
}
619
647
 
620
648
 
621
 
uchar *hash_element(HASH *hash,uint32_t idx)
 
649
unsigned char *hash_element(HASH *hash,uint32_t idx)
622
650
{
623
651
  if (idx < hash->records)
624
652
    return dynamic_element(&hash->array,idx,HASH_LINK*)->data;
631
659
  isn't changed
632
660
*/
633
661
 
634
 
void hash_replace(HASH *hash, HASH_SEARCH_STATE *current_record, uchar *new_row)
 
662
void hash_replace(HASH *hash, HASH_SEARCH_STATE *current_record,
 
663
                  unsigned char *new_row)
635
664
{
636
665
  if (*current_record != NO_RECORD)            /* Safety */
637
666
    dynamic_element(&hash->array, *current_record, HASH_LINK*)->data= new_row;