~drizzle-trunk/drizzle/development

520.7.1 by Monty Taylor
Moved hash.c to drizzled.
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 */
1 by brian
clean slate
21
/* One of key_length or key_length_offset must be given */
22
/* Key length of 0 isn't allowed */
23
612.2.4 by Monty Taylor
Moved some defines to config.h. Stopped including config.h directly anywhere.
24
#include <drizzled/global.h>
575.3.1 by Monty Taylor
Made mysys and mystrings c++. Fixed the resulting bugs the compiler found.
25
#include CSTDINT_H
520.8.3 by Monty Taylor
Moved hash back to mysys.
26
#include <mysys/hash.h>
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
27
28
const uint32_t NO_RECORD= UINT32_MAX;
29
30
const int LOWFIND= 1;
31
const int LOWUSED= 2;
32
const int HIGHFIND= 4;
33
const int HIGHUSED= 8;
1 by brian
clean slate
34
35
typedef struct st_hash_info {
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
36
  /* index to next key */
37
  uint32_t next;
38
  /* data for current entry */
39
  unsigned char *data;
1 by brian
clean slate
40
} HASH_LINK;
41
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
42
static uint32_t hash_mask(uint32_t hashnr, uint32_t buffmax,
43
                          uint32_t maxlength);
44
static void movelink(HASH_LINK *array, uint32_t pos,
45
                     uint32_t next_link, uint32_t newlink);
481 by Brian Aker
Remove all of uchar.
46
static int hashcmp(const HASH *hash, HASH_LINK *pos, const unsigned char *key,
1 by brian
clean slate
47
                   size_t length);
48
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
49
static uint32_t calc_hash(const HASH *hash, const unsigned char *key,
50
                          size_t length)
1 by brian
clean slate
51
{
290 by Brian Aker
Update for ulong change over.
52
  uint32_t nr1=1, nr2=4;
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
53
  hash->charset->coll->hash_sort(hash->charset, key,length, &nr1, &nr2);
1 by brian
clean slate
54
  return nr1;
55
}
56
146 by Brian Aker
my_bool cleanup.
57
bool
482 by Brian Aker
Remove uint.
58
_hash_init(HASH *hash,uint32_t growth_size, const CHARSET_INFO * const charset,
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
59
           uint32_t size, size_t key_offset, size_t key_length,
60
           hash_get_key get_key,
598.1.1 by Super-User
Fixed solaris build crap.
61
           hash_free_key free_element, uint32_t flags)
1 by brian
clean slate
62
{
63
  hash->records=0;
64
  if (my_init_dynamic_array_ci(&hash->array, sizeof(HASH_LINK), size,
65
                               growth_size))
66
  {
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
67
    /* Allow call to hash_free */
68
    hash->free=0;
202.3.7 by Monty Taylor
Gettext error compiles and passes test!
69
    return true;
1 by brian
clean slate
70
  }
71
  hash->key_offset=key_offset;
72
  hash->key_length=key_length;
73
  hash->blength=1;
74
  hash->get_key=get_key;
75
  hash->free=free_element;
76
  hash->flags=flags;
77
  hash->charset=charset;
202.3.7 by Monty Taylor
Gettext error compiles and passes test!
78
  return false;
1 by brian
clean slate
79
}
80
81
82
/*
83
  Call hash->free on all elements in hash.
84
85
  SYNOPSIS
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
86
  hash_free_elements()
87
  hash   hash table
1 by brian
clean slate
88
89
  NOTES:
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
90
  Sets records to 0
1 by brian
clean slate
91
*/
92
93
static inline void hash_free_elements(HASH *hash)
94
{
95
  if (hash->free)
96
  {
97
    HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
98
    HASH_LINK *end= data + hash->records;
99
    while (data < end)
100
      (*hash->free)((data++)->data);
101
  }
102
  hash->records=0;
103
}
104
105
106
/*
107
  Free memory used by hash.
108
109
  SYNOPSIS
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
110
  hash_free()
111
  hash   the hash to delete elements of
1 by brian
clean slate
112
113
  NOTES: Hash can't be reused without calling hash_init again.
114
*/
115
116
void hash_free(HASH *hash)
117
{
118
  hash_free_elements(hash);
119
  hash->free= 0;
120
  delete_dynamic(&hash->array);
51.3.13 by Jay Pipes
Phase 1 removal of DBUG in mysys
121
  return;
1 by brian
clean slate
122
}
123
124
/* some helper functions */
125
126
/*
481 by Brian Aker
Remove all of uchar.
127
  This function is char* instead of unsigned char* as HPUX11 compiler can't
1 by brian
clean slate
128
  handle inline functions that are not defined as native types
129
*/
130
131
static inline char*
481 by Brian Aker
Remove all of uchar.
132
hash_key(const HASH *hash, const unsigned char *record, size_t *length,
146 by Brian Aker
my_bool cleanup.
133
         bool first)
1 by brian
clean slate
134
{
135
  if (hash->get_key)
136
    return (char*) (*hash->get_key)(record,length,first);
137
  *length=hash->key_length;
138
  return (char*) record+hash->key_offset;
139
}
140
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
141
/* Calculate pos according to keys */
1 by brian
clean slate
142
482 by Brian Aker
Remove uint.
143
static uint32_t hash_mask(uint32_t hashnr,uint32_t buffmax,uint32_t maxlength)
1 by brian
clean slate
144
{
145
  if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
146
  return (hashnr & ((buffmax >> 1) -1));
147
}
148
482 by Brian Aker
Remove uint.
149
static uint32_t hash_rec_mask(const HASH *hash, HASH_LINK *pos,
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
150
                              uint32_t buffmax, uint32_t maxlength)
1 by brian
clean slate
151
{
152
  size_t length;
481 by Brian Aker
Remove all of uchar.
153
  unsigned char *key= (unsigned char*) hash_key(hash,pos->data,&length,0);
1 by brian
clean slate
154
  return hash_mask(calc_hash(hash,key,length),buffmax,maxlength);
155
}
156
157
158
159
static
160
inline
481 by Brian Aker
Remove all of uchar.
161
unsigned int rec_hashnr(HASH *hash,const unsigned char *record)
1 by brian
clean slate
162
{
163
  size_t length;
481 by Brian Aker
Remove all of uchar.
164
  unsigned char *key= (unsigned char*) hash_key(hash,record,&length,0);
1 by brian
clean slate
165
  return calc_hash(hash,key,length);
166
}
167
168
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
169
unsigned char* hash_search(const HASH *hash, const unsigned char *key,
170
                           size_t length)
1 by brian
clean slate
171
{
172
  HASH_SEARCH_STATE state;
173
  return hash_first(hash, key, length, &state);
174
}
175
176
/*
177
  Search after a record based on a key
178
179
  NOTE
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
180
  Assigns the number of the found record to HASH_SEARCH_STATE state
1 by brian
clean slate
181
*/
182
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
183
unsigned char* hash_first(const HASH *hash, const unsigned char *key,
184
                          size_t length,
185
                          HASH_SEARCH_STATE *current_record)
1 by brian
clean slate
186
{
187
  HASH_LINK *pos;
482 by Brian Aker
Remove uint.
188
  uint32_t flag,idx;
1 by brian
clean slate
189
190
  flag=1;
191
  if (hash->records)
192
  {
193
    idx=hash_mask(calc_hash(hash,key,length ? length : hash->key_length),
1138 by Brian Aker
Merge of Joe Daly's work
194
                  hash->blength,hash->records);
1 by brian
clean slate
195
    do
196
    {
197
      pos= dynamic_element(&hash->array,idx,HASH_LINK*);
198
      if (!hashcmp(hash,pos,key,length))
199
      {
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
200
        *current_record= idx;
201
        return (pos->data);
1 by brian
clean slate
202
      }
203
      if (flag)
204
      {
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
205
        /* Reset flag */
206
        flag=0;
1138 by Brian Aker
Merge of Joe Daly's work
207
        if (hash_rec_mask(hash,pos,hash->blength,hash->records) != idx)
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
208
          /* Wrong link */
209
          break;
1 by brian
clean slate
210
      }
211
    }
212
    while ((idx=pos->next) != NO_RECORD);
213
  }
214
  *current_record= NO_RECORD;
51.3.13 by Jay Pipes
Phase 1 removal of DBUG in mysys
215
  return(0);
1 by brian
clean slate
216
}
217
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
218
/* Get next record with identical key */
219
/* Can only be called if previous calls was hash_search */
1 by brian
clean slate
220
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
221
unsigned char* hash_next(const HASH *hash, const unsigned char *key,
222
                         size_t length,
223
                         HASH_SEARCH_STATE *current_record)
1 by brian
clean slate
224
{
225
  HASH_LINK *pos;
482 by Brian Aker
Remove uint.
226
  uint32_t idx;
1 by brian
clean slate
227
228
  if (*current_record != NO_RECORD)
229
  {
230
    HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
231
    for (idx=data[*current_record].next; idx != NO_RECORD ; idx=pos->next)
232
    {
233
      pos=data+idx;
234
      if (!hashcmp(hash,pos,key,length))
235
      {
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
236
        *current_record= idx;
237
        return pos->data;
1 by brian
clean slate
238
      }
239
    }
240
    *current_record= NO_RECORD;
241
  }
242
  return 0;
243
}
244
245
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
246
/* Change link from pos to new_link */
1 by brian
clean slate
247
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
248
static void movelink(HASH_LINK *array, uint32_t find,
249
                     uint32_t next_link, uint32_t newlink)
1 by brian
clean slate
250
{
251
  HASH_LINK *old_link;
252
  do
253
  {
254
    old_link=array+next_link;
255
  }
256
  while ((next_link=old_link->next) != find);
257
  old_link->next= newlink;
258
  return;
259
}
260
261
/*
262
  Compare a key in a record to a whole key. Return 0 if identical
263
264
  SYNOPSIS
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
265
  hashcmp()
266
  hash   hash table
267
  pos    position of hash record to use in comparison
268
  key    key for comparison
269
  length length of key
1 by brian
clean slate
270
271
  NOTES:
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
272
  If length is 0, comparison is done using the length of the
273
  record being compared against.
1 by brian
clean slate
274
275
  RETURN
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
276
  = 0  key of record == key
277
  != 0 key of record != key
278
*/
1 by brian
clean slate
279
481 by Brian Aker
Remove all of uchar.
280
static int hashcmp(const HASH *hash, HASH_LINK *pos, const unsigned char *key,
1 by brian
clean slate
281
                   size_t length)
282
{
283
  size_t rec_keylength;
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
284
  unsigned char *rec_key= (unsigned char*) hash_key(hash, pos->data,
285
                                                    &rec_keylength,1);
1 by brian
clean slate
286
  return ((length && length != rec_keylength) ||
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
287
          my_strnncoll(hash->charset, rec_key, rec_keylength,
288
                       key, rec_keylength));
1 by brian
clean slate
289
}
290
291
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
292
/* Write a hash-key to the hash-index */
1 by brian
clean slate
293
481 by Brian Aker
Remove all of uchar.
294
bool my_hash_insert(HASH *info,const unsigned char *record)
1 by brian
clean slate
295
{
296
  int flag;
297
  size_t idx;
482 by Brian Aker
Remove uint.
298
  uint32_t halfbuff,hash_nr,first_index;
481 by Brian Aker
Remove all of uchar.
299
  unsigned char *ptr_to_rec=NULL,*ptr_to_rec2=NULL;
77.1.71 by Monty Taylor
Uninitialized use.
300
  HASH_LINK *data,*empty,*gpos=NULL,*gpos2=NULL,*pos;
1 by brian
clean slate
301
302
  if (HASH_UNIQUE & info->flags)
303
  {
481 by Brian Aker
Remove all of uchar.
304
    unsigned char *key= (unsigned char*) hash_key(info, record, &idx, 1);
1 by brian
clean slate
305
    if (hash_search(info, key, idx))
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
306
      /* Duplicate entry */
307
      return(true);
1 by brian
clean slate
308
  }
309
310
  flag=0;
311
  if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array)))
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
312
    /* No more memory */
313
    return(true);
1 by brian
clean slate
314
315
  data=dynamic_element(&info->array,0,HASH_LINK*);
1138 by Brian Aker
Merge of Joe Daly's work
316
  halfbuff= info->blength >> 1;
1 by brian
clean slate
317
1138 by Brian Aker
Merge of Joe Daly's work
318
  idx= first_index= info->records-halfbuff;
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
319
  /* If some records */
320
  if (idx != info->records)
1 by brian
clean slate
321
  {
322
    do
323
    {
324
      pos=data+idx;
325
      hash_nr=rec_hashnr(info,pos->data);
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
326
      /* First loop; Check if ok */
327
      if (flag == 0)
1138 by Brian Aker
Merge of Joe Daly's work
328
        if (hash_mask(hash_nr,info->blength,info->records) != first_index)
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
329
          break;
1 by brian
clean slate
330
      if (!(hash_nr & halfbuff))
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
331
      {
332
        /* Key will not move */
333
        if (!(flag & LOWFIND))
334
        {
335
          if (flag & HIGHFIND)
336
          {
337
            flag=LOWFIND | HIGHFIND;
338
            /* key shall be moved to the current empty position */
339
            gpos=empty;
340
            ptr_to_rec=pos->data;
341
            /* This place is now free */
342
            empty=pos;
343
          }
344
          else
345
          {
346
            /* key isn't changed */
347
            flag=LOWFIND | LOWUSED;
348
            gpos=pos;
349
            ptr_to_rec=pos->data;
350
          }
351
        }
352
        else
353
        {
354
          if (!(flag & LOWUSED))
355
          {
356
            /* Change link of previous LOW-key */
357
            gpos->data=ptr_to_rec;
895 by Brian Aker
Completion (?) of uint conversion.
358
            gpos->next= (uint32_t) (pos-data);
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
359
            flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
360
          }
361
          gpos=pos;
362
          ptr_to_rec=pos->data;
363
        }
1 by brian
clean slate
364
      }
365
      else
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
366
      {
367
        /* key will be moved */
368
        if (!(flag & HIGHFIND))
369
        {
370
          flag= (flag & LOWFIND) | HIGHFIND;
371
          /* key shall be moved to the last (empty) position */
372
          gpos2 = empty; empty=pos;
373
          ptr_to_rec2=pos->data;
374
        }
375
        else
376
        {
377
          if (!(flag & HIGHUSED))
378
          {
379
            /* Change link of previous hash-key and save */
380
            gpos2->data=ptr_to_rec2;
895 by Brian Aker
Completion (?) of uint conversion.
381
            gpos2->next=(uint32_t) (pos-data);
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
382
            flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
383
          }
384
          gpos2=pos;
385
          ptr_to_rec2=pos->data;
386
        }
1 by brian
clean slate
387
      }
388
    }
389
    while ((idx=pos->next) != NO_RECORD);
390
391
    if ((flag & (LOWFIND | LOWUSED)) == LOWFIND)
392
    {
393
      gpos->data=ptr_to_rec;
394
      gpos->next=NO_RECORD;
395
    }
396
    if ((flag & (HIGHFIND | HIGHUSED)) == HIGHFIND)
397
    {
398
      gpos2->data=ptr_to_rec2;
399
      gpos2->next=NO_RECORD;
400
    }
401
  }
402
  /* Check if we are at the empty position */
403
1138 by Brian Aker
Merge of Joe Daly's work
404
  idx=hash_mask(rec_hashnr(info,record),info->blength,info->records+1);
1 by brian
clean slate
405
  pos=data+idx;
406
  if (pos == empty)
407
  {
481 by Brian Aker
Remove all of uchar.
408
    pos->data=(unsigned char*) record;
1 by brian
clean slate
409
    pos->next=NO_RECORD;
410
  }
411
  else
412
  {
413
    /* Check if more records in same hash-nr family */
414
    empty[0]=pos[0];
1138 by Brian Aker
Merge of Joe Daly's work
415
    gpos=data+hash_rec_mask(info,pos,info->blength,info->records+1);
1 by brian
clean slate
416
    if (pos == gpos)
417
    {
481 by Brian Aker
Remove all of uchar.
418
      pos->data=(unsigned char*) record;
895 by Brian Aker
Completion (?) of uint conversion.
419
      pos->next=(uint32_t) (empty - data);
1 by brian
clean slate
420
    }
421
    else
422
    {
481 by Brian Aker
Remove all of uchar.
423
      pos->data=(unsigned char*) record;
1 by brian
clean slate
424
      pos->next=NO_RECORD;
895 by Brian Aker
Completion (?) of uint conversion.
425
      movelink(data,(uint32_t) (pos-data),(uint32_t) (gpos-data),(uint32_t) (empty-data));
1 by brian
clean slate
426
    }
427
  }
428
  if (++info->records == info->blength)
429
    info->blength+= info->blength;
430
  return(0);
431
}
432
433
434
/******************************************************************************
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
435
 ** Remove one record from hash-table. The record with the same record
436
 ** ptr is removed.
437
 ** if there is a free-function it's called for record if found
438
 *****************************************************************************/
1 by brian
clean slate
439
481 by Brian Aker
Remove all of uchar.
440
bool hash_delete(HASH *hash,unsigned char *record)
1 by brian
clean slate
441
{
482 by Brian Aker
Remove uint.
442
  uint32_t blength,pos2,pos_hashnr,lastpos_hashnr,idx,empty_index;
1 by brian
clean slate
443
  HASH_LINK *data,*lastpos,*gpos,*pos,*pos3,*empty;
444
  if (!hash->records)
51.3.13 by Jay Pipes
Phase 1 removal of DBUG in mysys
445
    return(1);
1 by brian
clean slate
446
1138 by Brian Aker
Merge of Joe Daly's work
447
  blength=hash->blength;
1 by brian
clean slate
448
  data=dynamic_element(&hash->array,0,HASH_LINK*);
449
  /* Search after record with key */
450
  pos=data+ hash_mask(rec_hashnr(hash,record),blength,hash->records);
451
  gpos = 0;
452
453
  while (pos->data != record)
454
  {
455
    gpos=pos;
456
    if (pos->next == NO_RECORD)
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
457
      /* Key not found */
458
      return(1);
459
1 by brian
clean slate
460
    pos=data+pos->next;
461
  }
462
463
  if ( --(hash->records) < hash->blength >> 1) hash->blength>>=1;
464
  lastpos=data+hash->records;
465
466
  /* Remove link to record */
895 by Brian Aker
Completion (?) of uint conversion.
467
  empty=pos; empty_index=(uint32_t) (empty-data);
1 by brian
clean slate
468
  if (gpos)
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
469
    /* unlink current ptr */
470
    gpos->next=pos->next;
1 by brian
clean slate
471
  else if (pos->next != NO_RECORD)
472
  {
473
    empty=data+(empty_index=pos->next);
474
    pos->data=empty->data;
475
    pos->next=empty->next;
476
  }
477
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
478
  /* last key at wrong pos or no next link */
479
  if (empty == lastpos)
1 by brian
clean slate
480
    goto exit;
481
482
  /* Move the last key (lastpos) */
483
  lastpos_hashnr=rec_hashnr(hash,lastpos->data);
484
  /* pos is where lastpos should be */
1138 by Brian Aker
Merge of Joe Daly's work
485
  pos=data+hash_mask(lastpos_hashnr,hash->blength,hash->records);
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
486
  /* Move to empty position. */
487
  if (pos == empty)
1 by brian
clean slate
488
  {
489
    empty[0]=lastpos[0];
490
    goto exit;
491
  }
492
  pos_hashnr=rec_hashnr(hash,pos->data);
493
  /* pos3 is where the pos should be */
1138 by Brian Aker
Merge of Joe Daly's work
494
  pos3= data+hash_mask(pos_hashnr,hash->blength,hash->records);
1 by brian
clean slate
495
  if (pos != pos3)
496
  {					/* pos is on wrong posit */
497
    empty[0]=pos[0];			/* Save it here */
498
    pos[0]=lastpos[0];			/* This should be here */
895 by Brian Aker
Completion (?) of uint conversion.
499
    movelink(data,(uint32_t) (pos-data),(uint32_t) (pos3-data),empty_index);
1 by brian
clean slate
500
    goto exit;
501
  }
502
  pos2= hash_mask(lastpos_hashnr,blength,hash->records+1);
503
  if (pos2 == hash_mask(pos_hashnr,blength,hash->records+1))
504
  {					/* Identical key-positions */
505
    if (pos2 != hash->records)
506
    {
507
      empty[0]=lastpos[0];
895 by Brian Aker
Completion (?) of uint conversion.
508
      movelink(data,(uint32_t) (lastpos-data),(uint32_t) (pos-data),empty_index);
1 by brian
clean slate
509
      goto exit;
510
    }
895 by Brian Aker
Completion (?) of uint conversion.
511
    idx= (uint32_t) (pos-data);		/* Link pos->next after lastpos */
1 by brian
clean slate
512
  }
513
  else idx= NO_RECORD;		/* Different positions merge */
514
515
  empty[0]=lastpos[0];
516
  movelink(data,idx,empty_index,pos->next);
517
  pos->next=empty_index;
518
519
exit:
398.1.10 by Monty Taylor
Actually removed VOID() this time.
520
  pop_dynamic(&hash->array);
1 by brian
clean slate
521
  if (hash->free)
481 by Brian Aker
Remove all of uchar.
522
    (*hash->free)((unsigned char*) record);
51.3.13 by Jay Pipes
Phase 1 removal of DBUG in mysys
523
  return(0);
1 by brian
clean slate
524
}
525
481 by Brian Aker
Remove all of uchar.
526
unsigned char *hash_element(HASH *hash,uint32_t idx)
1 by brian
clean slate
527
{
528
  if (idx < hash->records)
529
    return dynamic_element(&hash->array,idx,HASH_LINK*)->data;
530
  return 0;
531
}
532