~linuxjedi/drizzle/trunk-bug-667053

« back to all changes in this revision

Viewing changes to storage/myisam/mi_unique.c

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2000-2006 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
/* Functions to check if a row is unique */
 
17
 
 
18
#include "myisamdef.h"
 
19
#include <m_ctype.h>
 
20
 
 
21
my_bool mi_check_unique(MI_INFO *info, MI_UNIQUEDEF *def, uchar *record,
 
22
                        ha_checksum unique_hash, my_off_t disk_pos)
 
23
{
 
24
  my_off_t lastpos=info->lastpos;
 
25
  MI_KEYDEF *key= &info->s->keyinfo[def->key];
 
26
  uchar *key_buff=info->lastkey2;
 
27
  DBUG_ENTER("mi_check_unique");
 
28
 
 
29
  mi_unique_store(record+key->seg->start, unique_hash);
 
30
  _mi_make_key(info,def->key,key_buff,record,0);
 
31
 
 
32
  /* The above changed info->lastkey2. Inform mi_rnext_same(). */
 
33
  info->update&= ~HA_STATE_RNEXT_SAME;
 
34
 
 
35
  if (_mi_search(info,info->s->keyinfo+def->key,key_buff,MI_UNIQUE_HASH_LENGTH,
 
36
                 SEARCH_FIND,info->s->state.key_root[def->key]))
 
37
  {
 
38
    info->page_changed=1;                       /* Can't optimize read next */
 
39
    info->lastpos= lastpos;
 
40
    DBUG_RETURN(0);                             /* No matching rows */
 
41
  }
 
42
 
 
43
  for (;;)
 
44
  {
 
45
    if (info->lastpos != disk_pos &&
 
46
        !(*info->s->compare_unique)(info,def,record,info->lastpos))
 
47
    {
 
48
      my_errno=HA_ERR_FOUND_DUPP_UNIQUE;
 
49
      info->errkey= (int) def->key;
 
50
      info->dupp_key_pos= info->lastpos;
 
51
      info->page_changed=1;                     /* Can't optimize read next */
 
52
      info->lastpos=lastpos;
 
53
      DBUG_PRINT("info",("Found duplicate"));
 
54
      DBUG_RETURN(1);                           /* Found identical  */
 
55
    }
 
56
    if (_mi_search_next(info,info->s->keyinfo+def->key, info->lastkey,
 
57
                        MI_UNIQUE_HASH_LENGTH, SEARCH_BIGGER,
 
58
                        info->s->state.key_root[def->key]) ||
 
59
        bcmp((char*) info->lastkey, (char*) key_buff, MI_UNIQUE_HASH_LENGTH))
 
60
    {
 
61
      info->page_changed=1;                     /* Can't optimize read next */
 
62
      info->lastpos=lastpos;
 
63
      DBUG_RETURN(0);                           /* end of tree */
 
64
    }
 
65
  }
 
66
}
 
67
 
 
68
 
 
69
/*
 
70
  Calculate a hash for a row
 
71
 
 
72
  TODO
 
73
    Add support for bit fields
 
74
*/
 
75
 
 
76
ha_checksum mi_unique_hash(MI_UNIQUEDEF *def, const uchar *record)
 
77
{
 
78
  const uchar *pos, *end;
 
79
  ha_checksum crc= 0;
 
80
  ulong seed1=0, seed2= 4;
 
81
  HA_KEYSEG *keyseg;
 
82
 
 
83
  for (keyseg=def->seg ; keyseg < def->end ; keyseg++)
 
84
  {
 
85
    enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type;
 
86
    uint length=keyseg->length;
 
87
 
 
88
    if (keyseg->null_bit)
 
89
    {
 
90
      if (record[keyseg->null_pos] & keyseg->null_bit)
 
91
      {
 
92
        /*
 
93
          Change crc in a way different from an empty string or 0.
 
94
          (This is an optimisation;  The code will work even if this isn't
 
95
          done)
 
96
        */
 
97
        crc=((crc << 8) + 511+
 
98
             (crc >> (8*sizeof(ha_checksum)-8)));
 
99
        continue;
 
100
      }
 
101
    }
 
102
    pos= record+keyseg->start;
 
103
    if (keyseg->flag & HA_VAR_LENGTH_PART)
 
104
    {
 
105
      uint pack_length=  keyseg->bit_start;
 
106
      uint tmp_length= (pack_length == 1 ? (uint) *(uchar*) pos :
 
107
                        uint2korr(pos));
 
108
      pos+= pack_length;                        /* Skip VARCHAR length */
 
109
      set_if_smaller(length,tmp_length);
 
110
    }
 
111
    else if (keyseg->flag & HA_BLOB_PART)
 
112
    {
 
113
      uint tmp_length=_mi_calc_blob_length(keyseg->bit_start,pos);
 
114
      memcpy_fixed((uchar*) &pos,pos+keyseg->bit_start,sizeof(char*));
 
115
      if (!length || length > tmp_length)
 
116
        length=tmp_length;                      /* The whole blob */
 
117
    }
 
118
    end= pos+length;
 
119
    if (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_VARTEXT1 ||
 
120
        type == HA_KEYTYPE_VARTEXT2)
 
121
    {
 
122
      keyseg->charset->coll->hash_sort(keyseg->charset,
 
123
                                       (const uchar*) pos, length, &seed1,
 
124
                                       &seed2);
 
125
      crc^= seed1;
 
126
    }
 
127
    else
 
128
      while (pos != end)
 
129
        crc=((crc << 8) +
 
130
             (((uchar)  *(uchar*) pos++))) +
 
131
          (crc >> (8*sizeof(ha_checksum)-8));
 
132
  }
 
133
  return crc;
 
134
}
 
135
 
 
136
 
 
137
/*
 
138
  compare unique key for two rows
 
139
 
 
140
  TODO
 
141
    Add support for bit fields
 
142
 
 
143
  RETURN
 
144
    0   if both rows have equal unique value
 
145
    #   Rows are different
 
146
*/
 
147
 
 
148
int mi_unique_comp(MI_UNIQUEDEF *def, const uchar *a, const uchar *b,
 
149
                   my_bool null_are_equal)
 
150
{
 
151
  const uchar *pos_a, *pos_b, *end;
 
152
  HA_KEYSEG *keyseg;
 
153
 
 
154
  for (keyseg=def->seg ; keyseg < def->end ; keyseg++)
 
155
  {
 
156
    enum ha_base_keytype type=(enum ha_base_keytype) keyseg->type;
 
157
    uint a_length, b_length;
 
158
    a_length= b_length= keyseg->length;
 
159
 
 
160
    /* If part is NULL it's regarded as different */
 
161
    if (keyseg->null_bit)
 
162
    {
 
163
      uint tmp;
 
164
      if ((tmp=(a[keyseg->null_pos] & keyseg->null_bit)) !=
 
165
          (uint) (b[keyseg->null_pos] & keyseg->null_bit))
 
166
        return 1;
 
167
      if (tmp)
 
168
      {
 
169
        if (!null_are_equal)
 
170
          return 1;
 
171
        continue;
 
172
      }
 
173
    }
 
174
    pos_a= a+keyseg->start;
 
175
    pos_b= b+keyseg->start;
 
176
    if (keyseg->flag & HA_VAR_LENGTH_PART)
 
177
    {
 
178
      uint pack_length= keyseg->bit_start;
 
179
      if (pack_length == 1)
 
180
      {
 
181
        a_length= (uint) *(uchar*) pos_a++;
 
182
        b_length= (uint) *(uchar*) pos_b++;
 
183
      }
 
184
      else
 
185
      {
 
186
        a_length= uint2korr(pos_a);
 
187
        b_length= uint2korr(pos_b);
 
188
        pos_a+= 2;                              /* Skip VARCHAR length */
 
189
        pos_b+= 2;
 
190
      }
 
191
      set_if_smaller(a_length, keyseg->length); /* Safety */
 
192
      set_if_smaller(b_length, keyseg->length); /* safety */
 
193
    }
 
194
    else if (keyseg->flag & HA_BLOB_PART)
 
195
    {
 
196
      /* Only compare 'length' characters if length != 0 */
 
197
      a_length= _mi_calc_blob_length(keyseg->bit_start,pos_a);
 
198
      b_length= _mi_calc_blob_length(keyseg->bit_start,pos_b);
 
199
      /* Check that a and b are of equal length */
 
200
      if (keyseg->length)
 
201
      {
 
202
        /*
 
203
          This is used in some cases when we are not interested in comparing
 
204
          the whole length of the blob.
 
205
        */
 
206
        set_if_smaller(a_length, keyseg->length);
 
207
        set_if_smaller(b_length, keyseg->length);
 
208
      }
 
209
      memcpy_fixed((uchar*) &pos_a,pos_a+keyseg->bit_start,sizeof(char*));
 
210
      memcpy_fixed((uchar*) &pos_b,pos_b+keyseg->bit_start,sizeof(char*));
 
211
    }
 
212
    if (type == HA_KEYTYPE_TEXT || type == HA_KEYTYPE_VARTEXT1 ||
 
213
        type == HA_KEYTYPE_VARTEXT2)
 
214
    {
 
215
      if (ha_compare_text(keyseg->charset, (uchar *) pos_a, a_length,
 
216
                                           (uchar *) pos_b, b_length, 0, 1))
 
217
        return 1;
 
218
    }
 
219
    else
 
220
    {
 
221
      if (a_length != b_length)
 
222
        return 1;
 
223
      end= pos_a+a_length;
 
224
      while (pos_a != end)
 
225
      {
 
226
        if (*pos_a++ != *pos_b++)
 
227
          return 1;
 
228
      }
 
229
    }
 
230
  }
 
231
  return 0;
 
232
}