Drizzled Public API Documentation

mi_unique.cc
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.h>
20 
21 using namespace drizzled;
22 
23 bool mi_check_unique(MI_INFO *info,
24  MI_UNIQUEDEF *def,
25  unsigned char *record,
26  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 ha_checksum mi_unique_hash(MI_UNIQUEDEF *def, const unsigned char *record)
80 {
81  const unsigned char *pos, *end;
82  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(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(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 }
TODO: Rename this file - func.h is stupid.