~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
125
/*
126
  Delete all elements from the hash (the hash itself is to be reused).
127
128
  SYNOPSIS
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
129
  my_hash_reset()
130
  hash   the hash to delete elements of
1 by brian
clean slate
131
*/
132
133
void my_hash_reset(HASH *hash)
134
{
135
  hash_free_elements(hash);
136
  reset_dynamic(&hash->array);
137
  /* Set row pointers so that the hash can be reused at once */
138
  hash->blength= 1;
51.3.13 by Jay Pipes
Phase 1 removal of DBUG in mysys
139
  return;
1 by brian
clean slate
140
}
141
142
/* some helper functions */
143
144
/*
481 by Brian Aker
Remove all of uchar.
145
  This function is char* instead of unsigned char* as HPUX11 compiler can't
1 by brian
clean slate
146
  handle inline functions that are not defined as native types
147
*/
148
149
static inline char*
481 by Brian Aker
Remove all of uchar.
150
hash_key(const HASH *hash, const unsigned char *record, size_t *length,
146 by Brian Aker
my_bool cleanup.
151
         bool first)
1 by brian
clean slate
152
{
153
  if (hash->get_key)
154
    return (char*) (*hash->get_key)(record,length,first);
155
  *length=hash->key_length;
156
  return (char*) record+hash->key_offset;
157
}
158
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
159
/* Calculate pos according to keys */
1 by brian
clean slate
160
482 by Brian Aker
Remove uint.
161
static uint32_t hash_mask(uint32_t hashnr,uint32_t buffmax,uint32_t maxlength)
1 by brian
clean slate
162
{
163
  if ((hashnr & (buffmax-1)) < maxlength) return (hashnr & (buffmax-1));
164
  return (hashnr & ((buffmax >> 1) -1));
165
}
166
482 by Brian Aker
Remove uint.
167
static uint32_t hash_rec_mask(const HASH *hash, HASH_LINK *pos,
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
168
                              uint32_t buffmax, uint32_t maxlength)
1 by brian
clean slate
169
{
170
  size_t length;
481 by Brian Aker
Remove all of uchar.
171
  unsigned char *key= (unsigned char*) hash_key(hash,pos->data,&length,0);
1 by brian
clean slate
172
  return hash_mask(calc_hash(hash,key,length),buffmax,maxlength);
173
}
174
175
176
177
static
178
inline
481 by Brian Aker
Remove all of uchar.
179
unsigned int rec_hashnr(HASH *hash,const unsigned char *record)
1 by brian
clean slate
180
{
181
  size_t length;
481 by Brian Aker
Remove all of uchar.
182
  unsigned char *key= (unsigned char*) hash_key(hash,record,&length,0);
1 by brian
clean slate
183
  return calc_hash(hash,key,length);
184
}
185
186
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
187
unsigned char* hash_search(const HASH *hash, const unsigned char *key,
188
                           size_t length)
1 by brian
clean slate
189
{
190
  HASH_SEARCH_STATE state;
191
  return hash_first(hash, key, length, &state);
192
}
193
194
/*
195
  Search after a record based on a key
196
197
  NOTE
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
198
  Assigns the number of the found record to HASH_SEARCH_STATE state
1 by brian
clean slate
199
*/
200
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
201
unsigned char* hash_first(const HASH *hash, const unsigned char *key,
202
                          size_t length,
203
                          HASH_SEARCH_STATE *current_record)
1 by brian
clean slate
204
{
205
  HASH_LINK *pos;
482 by Brian Aker
Remove uint.
206
  uint32_t flag,idx;
1 by brian
clean slate
207
208
  flag=1;
209
  if (hash->records)
210
  {
211
    idx=hash_mask(calc_hash(hash,key,length ? length : hash->key_length),
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
212
                  hash->blength,hash->records);
1 by brian
clean slate
213
    do
214
    {
215
      pos= dynamic_element(&hash->array,idx,HASH_LINK*);
216
      if (!hashcmp(hash,pos,key,length))
217
      {
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
218
        *current_record= idx;
219
        return (pos->data);
1 by brian
clean slate
220
      }
221
      if (flag)
222
      {
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
223
        /* Reset flag */
224
        flag=0;
225
        if (hash_rec_mask(hash,pos,hash->blength,hash->records) != idx)
226
          /* Wrong link */
227
          break;
1 by brian
clean slate
228
      }
229
    }
230
    while ((idx=pos->next) != NO_RECORD);
231
  }
232
  *current_record= NO_RECORD;
51.3.13 by Jay Pipes
Phase 1 removal of DBUG in mysys
233
  return(0);
1 by brian
clean slate
234
}
235
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
236
/* Get next record with identical key */
237
/* Can only be called if previous calls was hash_search */
1 by brian
clean slate
238
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
239
unsigned char* hash_next(const HASH *hash, const unsigned char *key,
240
                         size_t length,
241
                         HASH_SEARCH_STATE *current_record)
1 by brian
clean slate
242
{
243
  HASH_LINK *pos;
482 by Brian Aker
Remove uint.
244
  uint32_t idx;
1 by brian
clean slate
245
246
  if (*current_record != NO_RECORD)
247
  {
248
    HASH_LINK *data=dynamic_element(&hash->array,0,HASH_LINK*);
249
    for (idx=data[*current_record].next; idx != NO_RECORD ; idx=pos->next)
250
    {
251
      pos=data+idx;
252
      if (!hashcmp(hash,pos,key,length))
253
      {
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
254
        *current_record= idx;
255
        return pos->data;
1 by brian
clean slate
256
      }
257
    }
258
    *current_record= NO_RECORD;
259
  }
260
  return 0;
261
}
262
263
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
264
/* Change link from pos to new_link */
1 by brian
clean slate
265
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
266
static void movelink(HASH_LINK *array, uint32_t find,
267
                     uint32_t next_link, uint32_t newlink)
1 by brian
clean slate
268
{
269
  HASH_LINK *old_link;
270
  do
271
  {
272
    old_link=array+next_link;
273
  }
274
  while ((next_link=old_link->next) != find);
275
  old_link->next= newlink;
276
  return;
277
}
278
279
/*
280
  Compare a key in a record to a whole key. Return 0 if identical
281
282
  SYNOPSIS
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
283
  hashcmp()
284
  hash   hash table
285
  pos    position of hash record to use in comparison
286
  key    key for comparison
287
  length length of key
1 by brian
clean slate
288
289
  NOTES:
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
290
  If length is 0, comparison is done using the length of the
291
  record being compared against.
1 by brian
clean slate
292
293
  RETURN
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
294
  = 0  key of record == key
295
  != 0 key of record != key
296
*/
1 by brian
clean slate
297
481 by Brian Aker
Remove all of uchar.
298
static int hashcmp(const HASH *hash, HASH_LINK *pos, const unsigned char *key,
1 by brian
clean slate
299
                   size_t length)
300
{
301
  size_t rec_keylength;
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
302
  unsigned char *rec_key= (unsigned char*) hash_key(hash, pos->data,
303
                                                    &rec_keylength,1);
1 by brian
clean slate
304
  return ((length && length != rec_keylength) ||
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
305
          my_strnncoll(hash->charset, rec_key, rec_keylength,
306
                       key, rec_keylength));
1 by brian
clean slate
307
}
308
309
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
310
/* Write a hash-key to the hash-index */
1 by brian
clean slate
311
481 by Brian Aker
Remove all of uchar.
312
bool my_hash_insert(HASH *info,const unsigned char *record)
1 by brian
clean slate
313
{
314
  int flag;
315
  size_t idx;
482 by Brian Aker
Remove uint.
316
  uint32_t halfbuff,hash_nr,first_index;
481 by Brian Aker
Remove all of uchar.
317
  unsigned char *ptr_to_rec=NULL,*ptr_to_rec2=NULL;
77.1.71 by Monty Taylor
Uninitialized use.
318
  HASH_LINK *data,*empty,*gpos=NULL,*gpos2=NULL,*pos;
1 by brian
clean slate
319
320
  if (HASH_UNIQUE & info->flags)
321
  {
481 by Brian Aker
Remove all of uchar.
322
    unsigned char *key= (unsigned char*) hash_key(info, record, &idx, 1);
1 by brian
clean slate
323
    if (hash_search(info, key, idx))
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
324
      /* Duplicate entry */
325
      return(true);
1 by brian
clean slate
326
  }
327
328
  flag=0;
329
  if (!(empty=(HASH_LINK*) alloc_dynamic(&info->array)))
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
330
    /* No more memory */
331
    return(true);
1 by brian
clean slate
332
333
  data=dynamic_element(&info->array,0,HASH_LINK*);
334
  halfbuff= info->blength >> 1;
335
336
  idx=first_index=info->records-halfbuff;
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
337
  /* If some records */
338
  if (idx != info->records)
1 by brian
clean slate
339
  {
340
    do
341
    {
342
      pos=data+idx;
343
      hash_nr=rec_hashnr(info,pos->data);
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
344
      /* First loop; Check if ok */
345
      if (flag == 0)
346
        if (hash_mask(hash_nr,info->blength,info->records) != first_index)
347
          break;
1 by brian
clean slate
348
      if (!(hash_nr & halfbuff))
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
349
      {
350
        /* Key will not move */
351
        if (!(flag & LOWFIND))
352
        {
353
          if (flag & HIGHFIND)
354
          {
355
            flag=LOWFIND | HIGHFIND;
356
            /* key shall be moved to the current empty position */
357
            gpos=empty;
358
            ptr_to_rec=pos->data;
359
            /* This place is now free */
360
            empty=pos;
361
          }
362
          else
363
          {
364
            /* key isn't changed */
365
            flag=LOWFIND | LOWUSED;
366
            gpos=pos;
367
            ptr_to_rec=pos->data;
368
          }
369
        }
370
        else
371
        {
372
          if (!(flag & LOWUSED))
373
          {
374
            /* Change link of previous LOW-key */
375
            gpos->data=ptr_to_rec;
895 by Brian Aker
Completion (?) of uint conversion.
376
            gpos->next= (uint32_t) (pos-data);
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
377
            flag= (flag & HIGHFIND) | (LOWFIND | LOWUSED);
378
          }
379
          gpos=pos;
380
          ptr_to_rec=pos->data;
381
        }
1 by brian
clean slate
382
      }
383
      else
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
384
      {
385
        /* key will be moved */
386
        if (!(flag & HIGHFIND))
387
        {
388
          flag= (flag & LOWFIND) | HIGHFIND;
389
          /* key shall be moved to the last (empty) position */
390
          gpos2 = empty; empty=pos;
391
          ptr_to_rec2=pos->data;
392
        }
393
        else
394
        {
395
          if (!(flag & HIGHUSED))
396
          {
397
            /* Change link of previous hash-key and save */
398
            gpos2->data=ptr_to_rec2;
895 by Brian Aker
Completion (?) of uint conversion.
399
            gpos2->next=(uint32_t) (pos-data);
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
400
            flag= (flag & LOWFIND) | (HIGHFIND | HIGHUSED);
401
          }
402
          gpos2=pos;
403
          ptr_to_rec2=pos->data;
404
        }
1 by brian
clean slate
405
      }
406
    }
407
    while ((idx=pos->next) != NO_RECORD);
408
409
    if ((flag & (LOWFIND | LOWUSED)) == LOWFIND)
410
    {
411
      gpos->data=ptr_to_rec;
412
      gpos->next=NO_RECORD;
413
    }
414
    if ((flag & (HIGHFIND | HIGHUSED)) == HIGHFIND)
415
    {
416
      gpos2->data=ptr_to_rec2;
417
      gpos2->next=NO_RECORD;
418
    }
419
  }
420
  /* Check if we are at the empty position */
421
422
  idx=hash_mask(rec_hashnr(info,record),info->blength,info->records+1);
423
  pos=data+idx;
424
  if (pos == empty)
425
  {
481 by Brian Aker
Remove all of uchar.
426
    pos->data=(unsigned char*) record;
1 by brian
clean slate
427
    pos->next=NO_RECORD;
428
  }
429
  else
430
  {
431
    /* Check if more records in same hash-nr family */
432
    empty[0]=pos[0];
433
    gpos=data+hash_rec_mask(info,pos,info->blength,info->records+1);
434
    if (pos == gpos)
435
    {
481 by Brian Aker
Remove all of uchar.
436
      pos->data=(unsigned char*) record;
895 by Brian Aker
Completion (?) of uint conversion.
437
      pos->next=(uint32_t) (empty - data);
1 by brian
clean slate
438
    }
439
    else
440
    {
481 by Brian Aker
Remove all of uchar.
441
      pos->data=(unsigned char*) record;
1 by brian
clean slate
442
      pos->next=NO_RECORD;
895 by Brian Aker
Completion (?) of uint conversion.
443
      movelink(data,(uint32_t) (pos-data),(uint32_t) (gpos-data),(uint32_t) (empty-data));
1 by brian
clean slate
444
    }
445
  }
446
  if (++info->records == info->blength)
447
    info->blength+= info->blength;
448
  return(0);
449
}
450
451
452
/******************************************************************************
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
453
 ** Remove one record from hash-table. The record with the same record
454
 ** ptr is removed.
455
 ** if there is a free-function it's called for record if found
456
 *****************************************************************************/
1 by brian
clean slate
457
481 by Brian Aker
Remove all of uchar.
458
bool hash_delete(HASH *hash,unsigned char *record)
1 by brian
clean slate
459
{
482 by Brian Aker
Remove uint.
460
  uint32_t blength,pos2,pos_hashnr,lastpos_hashnr,idx,empty_index;
1 by brian
clean slate
461
  HASH_LINK *data,*lastpos,*gpos,*pos,*pos3,*empty;
462
  if (!hash->records)
51.3.13 by Jay Pipes
Phase 1 removal of DBUG in mysys
463
    return(1);
1 by brian
clean slate
464
465
  blength=hash->blength;
466
  data=dynamic_element(&hash->array,0,HASH_LINK*);
467
  /* Search after record with key */
468
  pos=data+ hash_mask(rec_hashnr(hash,record),blength,hash->records);
469
  gpos = 0;
470
471
  while (pos->data != record)
472
  {
473
    gpos=pos;
474
    if (pos->next == NO_RECORD)
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
475
      /* Key not found */
476
      return(1);
477
1 by brian
clean slate
478
    pos=data+pos->next;
479
  }
480
481
  if ( --(hash->records) < hash->blength >> 1) hash->blength>>=1;
482
  lastpos=data+hash->records;
483
484
  /* Remove link to record */
895 by Brian Aker
Completion (?) of uint conversion.
485
  empty=pos; empty_index=(uint32_t) (empty-data);
1 by brian
clean slate
486
  if (gpos)
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
487
    /* unlink current ptr */
488
    gpos->next=pos->next;
1 by brian
clean slate
489
  else if (pos->next != NO_RECORD)
490
  {
491
    empty=data+(empty_index=pos->next);
492
    pos->data=empty->data;
493
    pos->next=empty->next;
494
  }
495
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
496
  /* last key at wrong pos or no next link */
497
  if (empty == lastpos)
1 by brian
clean slate
498
    goto exit;
499
500
  /* Move the last key (lastpos) */
501
  lastpos_hashnr=rec_hashnr(hash,lastpos->data);
502
  /* pos is where lastpos should be */
503
  pos=data+hash_mask(lastpos_hashnr,hash->blength,hash->records);
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
504
  /* Move to empty position. */
505
  if (pos == empty)
1 by brian
clean slate
506
  {
507
    empty[0]=lastpos[0];
508
    goto exit;
509
  }
510
  pos_hashnr=rec_hashnr(hash,pos->data);
511
  /* pos3 is where the pos should be */
512
  pos3= data+hash_mask(pos_hashnr,hash->blength,hash->records);
513
  if (pos != pos3)
514
  {					/* pos is on wrong posit */
515
    empty[0]=pos[0];			/* Save it here */
516
    pos[0]=lastpos[0];			/* This should be here */
895 by Brian Aker
Completion (?) of uint conversion.
517
    movelink(data,(uint32_t) (pos-data),(uint32_t) (pos3-data),empty_index);
1 by brian
clean slate
518
    goto exit;
519
  }
520
  pos2= hash_mask(lastpos_hashnr,blength,hash->records+1);
521
  if (pos2 == hash_mask(pos_hashnr,blength,hash->records+1))
522
  {					/* Identical key-positions */
523
    if (pos2 != hash->records)
524
    {
525
      empty[0]=lastpos[0];
895 by Brian Aker
Completion (?) of uint conversion.
526
      movelink(data,(uint32_t) (lastpos-data),(uint32_t) (pos-data),empty_index);
1 by brian
clean slate
527
      goto exit;
528
    }
895 by Brian Aker
Completion (?) of uint conversion.
529
    idx= (uint32_t) (pos-data);		/* Link pos->next after lastpos */
1 by brian
clean slate
530
  }
531
  else idx= NO_RECORD;		/* Different positions merge */
532
533
  empty[0]=lastpos[0];
534
  movelink(data,idx,empty_index,pos->next);
535
  pos->next=empty_index;
536
537
exit:
398.1.10 by Monty Taylor
Actually removed VOID() this time.
538
  pop_dynamic(&hash->array);
1 by brian
clean slate
539
  if (hash->free)
481 by Brian Aker
Remove all of uchar.
540
    (*hash->free)((unsigned char*) record);
51.3.13 by Jay Pipes
Phase 1 removal of DBUG in mysys
541
  return(0);
1 by brian
clean slate
542
}
543
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
544
/*
545
  Update keys when record has changed.
546
  This is much more efficent than using a delete & insert.
547
*/
1 by brian
clean slate
548
481 by Brian Aker
Remove all of uchar.
549
bool hash_update(HASH *hash, unsigned char *record, unsigned char *old_key,
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
550
                 size_t old_key_length)
1 by brian
clean slate
551
{
482 by Brian Aker
Remove uint.
552
  uint32_t new_index,new_pos_index,blength,records,empty;
1 by brian
clean slate
553
  size_t idx;
554
  HASH_LINK org_link,*data,*previous,*pos;
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
555
1 by brian
clean slate
556
  if (HASH_UNIQUE & hash->flags)
557
  {
558
    HASH_SEARCH_STATE state;
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
559
    unsigned char *found,
560
      *new_key= (unsigned char*) hash_key(hash, record, &idx, 1);
561
1 by brian
clean slate
562
    if ((found= hash_first(hash, new_key, idx, &state)))
563
    {
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
564
      do
1 by brian
clean slate
565
      {
566
        if (found != record)
51.3.13 by Jay Pipes
Phase 1 removal of DBUG in mysys
567
          return(1);		/* Duplicate entry */
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
568
      }
1 by brian
clean slate
569
      while ((found= hash_next(hash, new_key, idx, &state)));
570
    }
571
  }
572
573
  data=dynamic_element(&hash->array,0,HASH_LINK*);
574
  blength=hash->blength; records=hash->records;
575
576
  /* Search after record with key */
577
578
  idx=hash_mask(calc_hash(hash, old_key,(old_key_length ?
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
579
                                         old_key_length :
580
                                         hash->key_length)),
581
                blength,records);
1 by brian
clean slate
582
  new_index=hash_mask(rec_hashnr(hash,record),blength,records);
583
  if (idx == new_index)
51.3.13 by Jay Pipes
Phase 1 removal of DBUG in mysys
584
    return(0);			/* Nothing to do (No record check) */
1 by brian
clean slate
585
  previous=0;
586
  for (;;)
587
  {
588
589
    if ((pos= data+idx)->data == record)
590
      break;
591
    previous=pos;
592
    if ((idx=pos->next) == NO_RECORD)
51.3.13 by Jay Pipes
Phase 1 removal of DBUG in mysys
593
      return(1);			/* Not found in links */
1 by brian
clean slate
594
  }
595
  org_link= *pos;
596
  empty=idx;
597
598
  /* Relink record from current chain */
599
600
  if (!previous)
601
  {
602
    if (pos->next != NO_RECORD)
603
    {
604
      empty=pos->next;
605
      *pos= data[pos->next];
606
    }
607
  }
608
  else
609
    previous->next=pos->next;		/* unlink pos */
610
611
  /* Move data to correct position */
612
  if (new_index == empty)
613
  {
614
    /*
615
      At this point record is unlinked from the old chain, thus it holds
616
      random position. By the chance this position is equal to position
617
      for the first element in the new chain. That means updated record
618
      is the only record in the new chain.
619
    */
620
    if (empty != idx)
621
    {
622
      /*
623
        Record was moved while unlinking it from the old chain.
624
        Copy data to a new position.
625
      */
626
      data[empty]= org_link;
627
    }
628
    data[empty].next= NO_RECORD;
51.3.13 by Jay Pipes
Phase 1 removal of DBUG in mysys
629
    return(0);
1 by brian
clean slate
630
  }
631
  pos=data+new_index;
632
  new_pos_index=hash_rec_mask(hash,pos,blength,records);
633
  if (new_index != new_pos_index)
634
  {					/* Other record in wrong position */
635
    data[empty] = *pos;
636
    movelink(data,new_index,new_pos_index,empty);
637
    org_link.next=NO_RECORD;
638
    data[new_index]= org_link;
639
  }
640
  else
641
  {					/* Link in chain at right position */
642
    org_link.next=data[new_index].next;
643
    data[empty]=org_link;
644
    data[new_index].next=empty;
645
  }
51.3.13 by Jay Pipes
Phase 1 removal of DBUG in mysys
646
  return(0);
1 by brian
clean slate
647
}
648
649
481 by Brian Aker
Remove all of uchar.
650
unsigned char *hash_element(HASH *hash,uint32_t idx)
1 by brian
clean slate
651
{
652
  if (idx < hash->records)
653
    return dynamic_element(&hash->array,idx,HASH_LINK*)->data;
654
  return 0;
655
}
656
657
658
/*
659
  Replace old row with new row.  This should only be used when key
660
  isn't changed
661
*/
662
520.7.1 by Monty Taylor
Moved hash.c to drizzled.
663
void hash_replace(HASH *hash, HASH_SEARCH_STATE *current_record,
664
                  unsigned char *new_row)
1 by brian
clean slate
665
{
666
  if (*current_record != NO_RECORD)            /* Safety */
667
    dynamic_element(&hash->array, *current_record, HASH_LINK*)->data= new_row;
668
}