~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/myisam/mi_unique.cc

  • Committer: Stewart Smith
  • Date: 2009-06-16 06:55:11 UTC
  • mto: This revision was merged to the branch mainline in revision 1094.
  • Revision ID: stewart@flamingspork.com-20090616065511-ps3ewfxj7918lwy3
rollback.test for MyISAM temp only.
- rename to myisam_rollback to reflect what it's testing
- just use create temporary table

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