1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2009 - 2010 Toru Maesaka
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.
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.
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
23
using namespace drizzled;
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;
33
int key_len, fetched_len;
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) {
38
KeyInfo *pk = &table->key_info[table->s->getPrimaryKey()];
39
KeyPartInfo *key_part = pk->key_part;
40
KeyPartInfo *key_part_end = key_part + pk->key_parts;
43
while (key_part != key_part_end) {
44
old_pos = old_row + key_part->offset;
45
new_pos = new_row + key_part->offset;
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);
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);
58
} else if (key_part->type == HA_KEYTYPE_BINARY) {
59
return HA_ERR_UNSUPPORTED;
61
key_changed = memcmp(old_pos, new_pos, key_part->length);
66
/* Key has changed. Look up the database to see if the new value
67
would violate the unique contraint. */
70
key_len = make_index_key(key, table->s->getPrimaryKey(), new_row);
71
fetched = share->dict.get_row(key, key_len, &fetched_len);
73
/* Key Exists. It's a violation. */
74
if (fetched != NULL) {
76
this->errkey_id = table->s->getPrimaryKey();
77
return HA_ERR_FOUND_DUPP_KEY;
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.
93
* INT (interpreted as LONG_INT)
94
* BIGINT (interpreted as LONGLONG)
95
* TIMESTAMP (interpreted as ULONG_INT)
96
* DATETIME (interpreted as ULONGLONG)
97
* DATE (interpreted as UINT_24)
98
* DOUBLE (interpreted as DOUBLE)
99
* VARCHAR (VARTEXT1 or VARTEXT2)
101
* BlitzDB Key Format:
102
* [DRIZZLE_KEY][UINT16_T][BLITZDB_UNIQUE_KEY]
109
int blitz_keycmp_cb(const char *a, int,
110
const char *b, int, void *opaque) {
111
BlitzTree *tree = (BlitzTree *)opaque;
112
int a_compared_len, b_compared_len, rv;
114
rv = packed_key_cmp(tree, a, b, &a_compared_len, &b_compared_len);
119
/* Getting here means that the Drizzle part of the keys are
120
identical. We now compare the BlitzDB part of the key. */
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)
130
char *a_pos = (char *)a + a_compared_len;
131
char *b_pos = (char *)b + b_compared_len;
133
uint16_t a_pk_len = uint2korr(a_pos);
134
uint16_t b_pk_len = uint2korr(b_pos);
136
a_pos += sizeof(a_pk_len);
137
b_pos += sizeof(b_pk_len);
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)
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) {
155
BlitzKeyPart *curr_part;
156
char *a_pos = (char *)a;
157
char *b_pos = (char *)b;
158
int a_next_offset = 0;
159
int b_next_offset = 0;
164
for (int i = 0; i < tree->nparts; i++) {
165
curr_part = &tree->parts[i];
167
if (curr_part->null_bitmask) {
168
*a_compared_len += 1;
169
*b_compared_len += 1;
171
if (*a_pos != *b_pos)
172
return ((int)*a_pos - (int)*b_pos);
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);
187
*a_compared_len += curr_part->length;
188
*b_compared_len += curr_part->length;
190
if (a_int_val < b_int_val)
192
else if (a_int_val > b_int_val)
195
a_next_offset = b_next_offset = curr_part->length;
198
case HA_KEYTYPE_ULONG_INT: {
199
uint32_t a_int_val = uint4korr(a_pos);
200
uint32_t b_int_val = uint4korr(b_pos);
202
*a_compared_len += curr_part->length;
203
*b_compared_len += curr_part->length;
205
if (a_int_val < b_int_val)
207
else if (a_int_val > b_int_val)
210
a_next_offset = b_next_offset = curr_part->length;
213
case HA_KEYTYPE_LONGLONG: {
214
int64_t a_int_val = sint8korr(a_pos);
215
int64_t b_int_val = sint8korr(b_pos);
217
*a_compared_len += curr_part->length;
218
*b_compared_len += curr_part->length;
220
if (a_int_val < b_int_val)
222
else if (a_int_val > b_int_val)
225
a_next_offset = b_next_offset = curr_part->length;
228
case HA_KEYTYPE_ULONGLONG: {
229
uint64_t a_int_val = uint8korr(a_pos);
230
uint64_t b_int_val = uint8korr(b_pos);
232
*a_compared_len += curr_part->length;
233
*b_compared_len += curr_part->length;
235
if (a_int_val < b_int_val)
237
else if (a_int_val > b_int_val)
240
a_next_offset = b_next_offset = curr_part->length;
243
case HA_KEYTYPE_UINT24: {
244
uint32_t a_int_val = uint3korr(a_pos);
245
uint32_t b_int_val = uint3korr(b_pos);
247
*a_compared_len += curr_part->length;
248
*b_compared_len += curr_part->length;
250
if (a_int_val < b_int_val)
252
else if (a_int_val > b_int_val)
255
a_next_offset = b_next_offset = curr_part->length;
258
case HA_KEYTYPE_DOUBLE: {
259
double a_double_val, b_double_val;
260
float8get(a_double_val, a_pos);
261
float8get(b_double_val, b_pos);
263
*a_compared_len += curr_part->length;
264
*b_compared_len += curr_part->length;
266
if (a_double_val < b_double_val)
268
else if (a_double_val > b_double_val)
271
a_next_offset = b_next_offset = curr_part->length;
274
case HA_KEYTYPE_VARTEXT1: {
275
uint8_t a_varchar_len = *(uint8_t *)a_pos;
276
uint8_t b_varchar_len = *(uint8_t *)b_pos;
282
*a_compared_len += a_varchar_len + sizeof(a_varchar_len);
283
*b_compared_len += b_varchar_len + sizeof(b_varchar_len);
285
/* Compare the texts by respecting collation. */
286
key_changed = my_strnncoll(&my_charset_utf8_general_ci,
287
(unsigned char *)a_pos, a_varchar_len,
288
(unsigned char *)b_pos, b_varchar_len);
291
else if (key_changed > 0)
294
a_next_offset = a_varchar_len;
295
b_next_offset = b_varchar_len;
298
case HA_KEYTYPE_VARTEXT2: {
299
uint16_t a_varchar_len = uint2korr(a_pos);
300
uint16_t b_varchar_len = uint2korr(b_pos);
303
a_pos += sizeof(a_varchar_len);
304
b_pos += sizeof(b_varchar_len);
306
*a_compared_len += a_varchar_len + sizeof(a_varchar_len);
307
*b_compared_len += b_varchar_len + sizeof(b_varchar_len);
309
/* Compare the texts by respecting collation. */
310
key_changed = my_strnncoll(&my_charset_utf8_general_ci,
311
(unsigned char *)a_pos, a_varchar_len,
312
(unsigned char *)b_pos, b_varchar_len);
315
else if (key_changed > 0)
318
a_next_offset = a_varchar_len;
319
b_next_offset = b_varchar_len;
326
a_pos += a_next_offset;
327
b_pos += b_next_offset;