~drizzle-trunk/drizzle/development

1239.3.28 by Toru Maesaka
Added UNIQUE constraint check for UPDATE queries on VARCHAR key(s) and some tests for it.
1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3
 *
4
 *  Copyright (C) 2009 - 2010 Toru Maesaka
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
1800.3.1 by Vijay Samuel
Merge change of <config.h> to "config.h"
20
#include "config.h"
1239.3.28 by Toru Maesaka
Added UNIQUE constraint check for UPDATE queries on VARCHAR key(s) and some tests for it.
21
#include "ha_blitz.h"
22
1239.3.42 by Toru Maesaka
Merged Drizzle's Trunk.
23
using namespace drizzled;
24
1239.3.28 by Toru Maesaka
Added UNIQUE constraint check for UPDATE queries on VARCHAR key(s) and some tests for it.
25
/* Given two native rows, this function checks all unique fields to
26
   find whether the value has been updated. If a unique field value
27
   is updated, it checks if the new key exists in the database already.
28
   If it already exists, then it is a unique constraint violation. */
29
int ha_blitz::compare_rows_for_unique_violation(const unsigned char *old_row,
30
                                                const unsigned char *new_row) {
31
  const unsigned char *old_pos, *new_pos;
32
  char *key, *fetched;
33
  int key_len, fetched_len;
34
35
  /* For now, we are only interested in supporting a PRIMARY KEY. In the
36
     next phase of BlitzDB, this should loop through the key array. */
37
  if (share->primary_key_exists) {
1827.2.1 by Brian Aker
Encapsulate Table (remove its direct access of the share it contains)
38
    KeyInfo *pk = &table->key_info[table->getMutableShare()->getPrimaryKey()];
1239.3.112 by Toru Maesaka
Merged Drizzle's Trunk.
39
    KeyPartInfo *key_part = pk->key_part;
40
    KeyPartInfo *key_part_end = key_part + pk->key_parts;
1239.3.28 by Toru Maesaka
Added UNIQUE constraint check for UPDATE queries on VARCHAR key(s) and some tests for it.
41
    int key_changed = 0;
42
1239.3.29 by Toru Maesaka
Added UNIQUE constraint check on fixed length fields and more tests. Moved get_share() to ha_blitz class.
43
    while (key_part != key_part_end) {  
1239.3.28 by Toru Maesaka
Added UNIQUE constraint check for UPDATE queries on VARCHAR key(s) and some tests for it.
44
      old_pos = old_row + key_part->offset;
45
      new_pos = new_row + key_part->offset;
46
47
      /* In VARCHAR, first 2 bytes is reserved to represent the length
48
         of the key. Rip it out and move forward the row pointers. */
49
      if (key_part->type == HA_KEYTYPE_VARTEXT2) {
50
        uint16_t old_key_len = uint2korr(old_pos);
51
        uint16_t new_key_len = uint2korr(new_pos);
52
        old_pos += sizeof(old_key_len);
53
        new_pos += sizeof(new_key_len);
54
55
        /* Compare the actual data by repecting it's collation. */
56
        key_changed = my_strnncoll(&my_charset_utf8_general_ci, old_pos,
57
                                   old_key_len, new_pos, new_key_len);
1239.3.29 by Toru Maesaka
Added UNIQUE constraint check on fixed length fields and more tests. Moved get_share() to ha_blitz class.
58
      } else if (key_part->type == HA_KEYTYPE_BINARY) {
59
        return HA_ERR_UNSUPPORTED;
1239.3.28 by Toru Maesaka
Added UNIQUE constraint check for UPDATE queries on VARCHAR key(s) and some tests for it.
60
      } else {
1239.3.29 by Toru Maesaka
Added UNIQUE constraint check on fixed length fields and more tests. Moved get_share() to ha_blitz class.
61
        key_changed = memcmp(old_pos, new_pos, key_part->length);
1239.3.28 by Toru Maesaka
Added UNIQUE constraint check for UPDATE queries on VARCHAR key(s) and some tests for it.
62
      }
1239.3.29 by Toru Maesaka
Added UNIQUE constraint check on fixed length fields and more tests. Moved get_share() to ha_blitz class.
63
      key_part++;
1239.3.28 by Toru Maesaka
Added UNIQUE constraint check for UPDATE queries on VARCHAR key(s) and some tests for it.
64
    }
65
66
    /* Key has changed. Look up the database to see if the new value
1239.3.29 by Toru Maesaka
Added UNIQUE constraint check on fixed length fields and more tests. Moved get_share() to ha_blitz class.
67
       would violate the unique contraint. */
1239.3.28 by Toru Maesaka
Added UNIQUE constraint check for UPDATE queries on VARCHAR key(s) and some tests for it.
68
    if (key_changed) {
69
      key = key_buffer;
1827.2.1 by Brian Aker
Encapsulate Table (remove its direct access of the share it contains)
70
      key_len = make_index_key(key, table->getMutableShare()->getPrimaryKey(), new_row);
1239.3.28 by Toru Maesaka
Added UNIQUE constraint check for UPDATE queries on VARCHAR key(s) and some tests for it.
71
      fetched = share->dict.get_row(key, key_len, &fetched_len);
72
73
      /* Key Exists. It's a violation. */
74
      if (fetched != NULL) {
75
        free(fetched);
1827.2.1 by Brian Aker
Encapsulate Table (remove its direct access of the share it contains)
76
        this->errkey_id = table->getMutableShare()->getPrimaryKey();
1239.3.28 by Toru Maesaka
Added UNIQUE constraint check for UPDATE queries on VARCHAR key(s) and some tests for it.
77
        return HA_ERR_FOUND_DUPP_KEY;
78
      }
79
    }
80
  }
81
82
  return 0;
83
}
1239.3.41 by Toru Maesaka
Started hacking on the key comparator for B+Tree indexes. INT, BIGINT, DOUBLE and VARCHAR types are now supported. More to come.
84
85
/* 
86
 * Comparison Function for TC's B+Tree. This is the only function
87
 * in BlitzDB where you can feel free to write redundant code for
88
 * performance. Avoid function calls unless it is necessary. If
89
 * you reaaaally want to separate the code block for readability,
90
 * make sure to separate the code with C++ template for inlining.
91
 *                                               - Toru
1239.3.43 by Toru Maesaka
Further hack on the key comparator. Use HA_KEYTYPE instead of DRIZZLE_TYPE. Added support for TIMESTAMP and DATETIME.
92
 * Currently Handles:
93
 *   INT       (interpreted as LONG_INT)
94
 *   BIGINT    (interpreted as LONGLONG)
95
 *   TIMESTAMP (interpreted as ULONG_INT)
96
 *   DATETIME  (interpreted as ULONGLONG)
1239.3.65 by Toru Maesaka
Worked on the B+Tree comparison function to take the key suffix into account.
97
 *   DATE      (interpreted as UINT_24)
1239.3.43 by Toru Maesaka
Further hack on the key comparator. Use HA_KEYTYPE instead of DRIZZLE_TYPE. Added support for TIMESTAMP and DATETIME.
98
 *   DOUBLE    (interpreted as DOUBLE)
99
 *   VARCHAR   (VARTEXT1 or VARTEXT2)
1239.3.41 by Toru Maesaka
Started hacking on the key comparator for B+Tree indexes. INT, BIGINT, DOUBLE and VARCHAR types are now supported. More to come.
100
 *
1239.3.101 by Toru Maesaka
Fixed a bug for UNIQUE INDEX in BlitzDB's B+Tree key comparator.
101
 * BlitzDB Key Format:
102
 *   [DRIZZLE_KEY][UINT16_T][BLITZDB_UNIQUE_KEY]
103
 *
1239.3.43 by Toru Maesaka
Further hack on the key comparator. Use HA_KEYTYPE instead of DRIZZLE_TYPE. Added support for TIMESTAMP and DATETIME.
104
 * Returns:
105
 *   -1 = a < b
106
 *    0 = a == b
107
 *    1 = a > b
1239.3.41 by Toru Maesaka
Started hacking on the key comparator for B+Tree indexes. INT, BIGINT, DOUBLE and VARCHAR types are now supported. More to come.
108
 */
109
int blitz_keycmp_cb(const char *a, int,
110
                    const char *b, int, void *opaque) {
111
  BlitzTree *tree = (BlitzTree *)opaque;
1239.3.77 by Toru Maesaka
Isolated key comparison code. It's now a function that can be used anywhere in BlitzDB.
112
  int a_compared_len, b_compared_len, rv;
113
114
  rv = packed_key_cmp(tree, a, b, &a_compared_len, &b_compared_len);
115
116
  if (rv != 0)
117
    return rv;
118
1239.3.101 by Toru Maesaka
Fixed a bug for UNIQUE INDEX in BlitzDB's B+Tree key comparator.
119
  /* Getting here means that the Drizzle part of the keys are
120
     identical. We now compare the BlitzDB part of the key. */
121
  if (tree->unique) {
122
    /* This is a special exception that allows Drizzle's NULL
123
       key to be inserted duplicately into a UNIQUE tree. If
124
       the keys aren't NULL then it is safe to conclude that
125
       the keys are identical which this condition does. */
126
    if (*a != 0 && *b != 0)
127
      return 0;
128
  }
1239.3.77 by Toru Maesaka
Isolated key comparison code. It's now a function that can be used anywhere in BlitzDB.
129
130
  char *a_pos = (char *)a + a_compared_len;
131
  char *b_pos = (char *)b + b_compared_len;
132
133
  uint16_t a_pk_len = uint2korr(a_pos);
134
  uint16_t b_pk_len = uint2korr(b_pos);
135
136
  a_pos += sizeof(a_pk_len);
137
  b_pos += sizeof(b_pk_len);
138
139
  if (a_pk_len == b_pk_len)
140
    rv = memcmp(a_pos, b_pos, a_pk_len);
141
  else if (a_pk_len < b_pk_len)
142
    rv = -1;
143
  else
144
    rv = 1;
145
146
  return rv;
147
}
148
149
/* General purpose comparison function for BlitzDB. We cannot reuse
150
   blitz_keycmp_cb() for this purpose because the 'exact match' only
151
   applies to BlitzDB's unique B+Tree key format in blitz_keycmp_cb().
152
   Here we are comparing packed Drizzle keys. */
153
int packed_key_cmp(BlitzTree *tree, const char *a, const char *b,
154
                   int *a_compared_len, int *b_compared_len) {
1239.3.41 by Toru Maesaka
Started hacking on the key comparator for B+Tree indexes. INT, BIGINT, DOUBLE and VARCHAR types are now supported. More to come.
155
  BlitzKeyPart *curr_part;
1239.3.77 by Toru Maesaka
Isolated key comparison code. It's now a function that can be used anywhere in BlitzDB.
156
  char *a_pos = (char *)a;
157
  char *b_pos = (char *)b;
1239.3.65 by Toru Maesaka
Worked on the B+Tree comparison function to take the key suffix into account.
158
  int a_next_offset = 0;
159
  int b_next_offset = 0;
160
1239.3.78 by Toru Maesaka
ha_blitz::records_in_range() can now return the real number of keys if min and max keys are both provided.
161
  *a_compared_len = 0;
162
  *b_compared_len = 0;
163
1239.3.41 by Toru Maesaka
Started hacking on the key comparator for B+Tree indexes. INT, BIGINT, DOUBLE and VARCHAR types are now supported. More to come.
164
  for (int i = 0; i < tree->nparts; i++) {
165
    curr_part = &tree->parts[i];
166
1239.3.60 by Toru Maesaka
Fixed the B+Tree comparator to respect the NULL indication byte in a key for NULLable columns.
167
    if (curr_part->null_bitmask) {
1239.3.77 by Toru Maesaka
Isolated key comparison code. It's now a function that can be used anywhere in BlitzDB.
168
      *a_compared_len += 1;
169
      *b_compared_len += 1;
170
1239.3.60 by Toru Maesaka
Fixed the B+Tree comparator to respect the NULL indication byte in a key for NULLable columns.
171
      if (*a_pos != *b_pos)
172
        return ((int)*a_pos - (int)*b_pos);
173
174
      b_pos++;
175
1239.3.61 by Toru Maesaka
Worked on reducing the execution path of row insertion and supported NULL for key values. Added tests for NULL values in full index scan.
176
      if (!*a_pos++) {
1239.3.60 by Toru Maesaka
Fixed the B+Tree comparator to respect the NULL indication byte in a key for NULLable columns.
177
        curr_part++;
178
        continue;
179
      }
180
    }
181
1239.3.43 by Toru Maesaka
Further hack on the key comparator. Use HA_KEYTYPE instead of DRIZZLE_TYPE. Added support for TIMESTAMP and DATETIME.
182
    switch ((enum ha_base_keytype)curr_part->type) {
183
    case HA_KEYTYPE_LONG_INT: {
184
      int32_t a_int_val = sint4korr(a_pos);
185
      int32_t b_int_val = sint4korr(b_pos);
1239.3.41 by Toru Maesaka
Started hacking on the key comparator for B+Tree indexes. INT, BIGINT, DOUBLE and VARCHAR types are now supported. More to come.
186
1239.3.77 by Toru Maesaka
Isolated key comparison code. It's now a function that can be used anywhere in BlitzDB.
187
      *a_compared_len += curr_part->length;
188
      *b_compared_len += curr_part->length;
189
1239.3.43 by Toru Maesaka
Further hack on the key comparator. Use HA_KEYTYPE instead of DRIZZLE_TYPE. Added support for TIMESTAMP and DATETIME.
190
      if (a_int_val < b_int_val)
1239.3.41 by Toru Maesaka
Started hacking on the key comparator for B+Tree indexes. INT, BIGINT, DOUBLE and VARCHAR types are now supported. More to come.
191
        return -1;
1239.3.43 by Toru Maesaka
Further hack on the key comparator. Use HA_KEYTYPE instead of DRIZZLE_TYPE. Added support for TIMESTAMP and DATETIME.
192
      else if (a_int_val > b_int_val)
1239.3.41 by Toru Maesaka
Started hacking on the key comparator for B+Tree indexes. INT, BIGINT, DOUBLE and VARCHAR types are now supported. More to come.
193
        return 1;
194
1239.3.65 by Toru Maesaka
Worked on the B+Tree comparison function to take the key suffix into account.
195
      a_next_offset = b_next_offset = curr_part->length;
1239.3.41 by Toru Maesaka
Started hacking on the key comparator for B+Tree indexes. INT, BIGINT, DOUBLE and VARCHAR types are now supported. More to come.
196
      break; 
197
    }
1239.3.43 by Toru Maesaka
Further hack on the key comparator. Use HA_KEYTYPE instead of DRIZZLE_TYPE. Added support for TIMESTAMP and DATETIME.
198
    case HA_KEYTYPE_ULONG_INT: {
199
      uint32_t a_int_val = uint4korr(a_pos);
200
      uint32_t b_int_val = uint4korr(b_pos);
201
1239.3.77 by Toru Maesaka
Isolated key comparison code. It's now a function that can be used anywhere in BlitzDB.
202
      *a_compared_len += curr_part->length;
203
      *b_compared_len += curr_part->length;
204
1239.3.43 by Toru Maesaka
Further hack on the key comparator. Use HA_KEYTYPE instead of DRIZZLE_TYPE. Added support for TIMESTAMP and DATETIME.
205
      if (a_int_val < b_int_val)
206
        return -1;
207
      else if (a_int_val > b_int_val)
208
        return 1;
209
1239.3.65 by Toru Maesaka
Worked on the B+Tree comparison function to take the key suffix into account.
210
      a_next_offset = b_next_offset = curr_part->length;
1239.3.43 by Toru Maesaka
Further hack on the key comparator. Use HA_KEYTYPE instead of DRIZZLE_TYPE. Added support for TIMESTAMP and DATETIME.
211
      break;
212
    }
213
    case HA_KEYTYPE_LONGLONG: {
214
      int64_t a_int_val = sint8korr(a_pos);
215
      int64_t b_int_val = sint8korr(b_pos);
216
1239.3.77 by Toru Maesaka
Isolated key comparison code. It's now a function that can be used anywhere in BlitzDB.
217
      *a_compared_len += curr_part->length;
218
      *b_compared_len += curr_part->length;
219
1239.3.43 by Toru Maesaka
Further hack on the key comparator. Use HA_KEYTYPE instead of DRIZZLE_TYPE. Added support for TIMESTAMP and DATETIME.
220
      if (a_int_val < b_int_val)
221
        return -1;
222
      else if (a_int_val > b_int_val)
223
        return 1;
224
1239.3.65 by Toru Maesaka
Worked on the B+Tree comparison function to take the key suffix into account.
225
      a_next_offset = b_next_offset = curr_part->length;
1239.3.43 by Toru Maesaka
Further hack on the key comparator. Use HA_KEYTYPE instead of DRIZZLE_TYPE. Added support for TIMESTAMP and DATETIME.
226
      break;
227
    }
228
    case HA_KEYTYPE_ULONGLONG: {
229
      uint64_t a_int_val = uint8korr(a_pos);
230
      uint64_t b_int_val = uint8korr(b_pos);
231
1239.3.77 by Toru Maesaka
Isolated key comparison code. It's now a function that can be used anywhere in BlitzDB.
232
      *a_compared_len += curr_part->length;
233
      *b_compared_len += curr_part->length;
234
1239.3.43 by Toru Maesaka
Further hack on the key comparator. Use HA_KEYTYPE instead of DRIZZLE_TYPE. Added support for TIMESTAMP and DATETIME.
235
      if (a_int_val < b_int_val)
236
        return -1;
237
      else if (a_int_val > b_int_val)
238
        return 1;
239
1239.3.65 by Toru Maesaka
Worked on the B+Tree comparison function to take the key suffix into account.
240
      a_next_offset = b_next_offset = curr_part->length;
1239.3.43 by Toru Maesaka
Further hack on the key comparator. Use HA_KEYTYPE instead of DRIZZLE_TYPE. Added support for TIMESTAMP and DATETIME.
241
      break;
242
    }
243
    case HA_KEYTYPE_DOUBLE: {
1239.3.41 by Toru Maesaka
Started hacking on the key comparator for B+Tree indexes. INT, BIGINT, DOUBLE and VARCHAR types are now supported. More to come.
244
      double a_double_val, b_double_val;
245
      float8get(a_double_val, a_pos);
246
      float8get(b_double_val, b_pos);
247
1239.3.77 by Toru Maesaka
Isolated key comparison code. It's now a function that can be used anywhere in BlitzDB.
248
      *a_compared_len += curr_part->length;
249
      *b_compared_len += curr_part->length;
250
1239.3.41 by Toru Maesaka
Started hacking on the key comparator for B+Tree indexes. INT, BIGINT, DOUBLE and VARCHAR types are now supported. More to come.
251
      if (a_double_val < b_double_val)
252
        return -1;
253
      else if (a_double_val > b_double_val)
254
        return 1;
255
1239.3.65 by Toru Maesaka
Worked on the B+Tree comparison function to take the key suffix into account.
256
      a_next_offset = b_next_offset = curr_part->length;
1239.3.41 by Toru Maesaka
Started hacking on the key comparator for B+Tree indexes. INT, BIGINT, DOUBLE and VARCHAR types are now supported. More to come.
257
      break;
258
    }
1239.3.43 by Toru Maesaka
Further hack on the key comparator. Use HA_KEYTYPE instead of DRIZZLE_TYPE. Added support for TIMESTAMP and DATETIME.
259
    case HA_KEYTYPE_VARTEXT1: {
260
      uint8_t a_varchar_len = *(uint8_t *)a_pos;
261
      uint8_t b_varchar_len = *(uint8_t *)b_pos;
262
      int key_changed;
263
264
      a_pos++;
265
      b_pos++;
266
1239.3.77 by Toru Maesaka
Isolated key comparison code. It's now a function that can be used anywhere in BlitzDB.
267
      *a_compared_len += a_varchar_len + sizeof(a_varchar_len);
268
      *b_compared_len += b_varchar_len + sizeof(b_varchar_len);
269
1239.3.43 by Toru Maesaka
Further hack on the key comparator. Use HA_KEYTYPE instead of DRIZZLE_TYPE. Added support for TIMESTAMP and DATETIME.
270
      /* Compare the texts by respecting collation. */
271
      key_changed = my_strnncoll(&my_charset_utf8_general_ci,
272
                                 (unsigned char *)a_pos, a_varchar_len,
273
                                 (unsigned char *)b_pos, b_varchar_len);
274
      if (key_changed < 0)
275
        return -1;
276
      else if (key_changed > 0)
277
        return 1;
278
1239.3.65 by Toru Maesaka
Worked on the B+Tree comparison function to take the key suffix into account.
279
      a_next_offset = a_varchar_len;
280
      b_next_offset = b_varchar_len;
1239.3.43 by Toru Maesaka
Further hack on the key comparator. Use HA_KEYTYPE instead of DRIZZLE_TYPE. Added support for TIMESTAMP and DATETIME.
281
      break;
282
    }
283
    case HA_KEYTYPE_VARTEXT2: {
284
      uint16_t a_varchar_len = uint2korr(a_pos);
285
      uint16_t b_varchar_len = uint2korr(b_pos);
286
      int key_changed;
287
1239.3.41 by Toru Maesaka
Started hacking on the key comparator for B+Tree indexes. INT, BIGINT, DOUBLE and VARCHAR types are now supported. More to come.
288
      a_pos += sizeof(a_varchar_len);
289
      b_pos += sizeof(b_varchar_len);
290
1239.3.77 by Toru Maesaka
Isolated key comparison code. It's now a function that can be used anywhere in BlitzDB.
291
      *a_compared_len += a_varchar_len + sizeof(a_varchar_len);
292
      *b_compared_len += b_varchar_len + sizeof(b_varchar_len);
293
1239.3.41 by Toru Maesaka
Started hacking on the key comparator for B+Tree indexes. INT, BIGINT, DOUBLE and VARCHAR types are now supported. More to come.
294
      /* Compare the texts by respecting collation. */
295
      key_changed = my_strnncoll(&my_charset_utf8_general_ci,
296
                                 (unsigned char *)a_pos, a_varchar_len,
297
                                 (unsigned char *)b_pos, b_varchar_len);
298
      if (key_changed < 0)
299
        return -1;
300
      else if (key_changed > 0)
301
        return 1;
302
1239.3.65 by Toru Maesaka
Worked on the B+Tree comparison function to take the key suffix into account.
303
      a_next_offset = a_varchar_len;
304
      b_next_offset = b_varchar_len;
1239.3.41 by Toru Maesaka
Started hacking on the key comparator for B+Tree indexes. INT, BIGINT, DOUBLE and VARCHAR types are now supported. More to come.
305
      break; 
306
    }
307
    default:
308
      break;
309
    }
310
1239.3.65 by Toru Maesaka
Worked on the B+Tree comparison function to take the key suffix into account.
311
    a_pos += a_next_offset;
312
    b_pos += b_next_offset;
1239.3.41 by Toru Maesaka
Started hacking on the key comparator for B+Tree indexes. INT, BIGINT, DOUBLE and VARCHAR types are now supported. More to come.
313
    curr_part++;
314
  }
315
1239.3.76 by Toru Maesaka
Base work for implementing ha_blitz::records_in_range().
316
  return 0;
317
}