~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to plugin/blitzdb/blitzcmp.cc

  • Committer: Brian Aker
  • Date: 2009-02-21 00:18:15 UTC
  • Revision ID: brian@tangent.org-20090221001815-x20e8h71e984lvs1
Completion (?) of uint conversion.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
 
20
 
#include "config.h"
21
 
#include "ha_blitz.h"
22
 
 
23
 
using namespace drizzled;
24
 
 
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) {
38
 
    KeyInfo *pk = &getTable()->key_info[getTable()->getShare()->getPrimaryKey()];
39
 
    KeyPartInfo *key_part = pk->key_part;
40
 
    KeyPartInfo *key_part_end = key_part + pk->key_parts;
41
 
    int key_changed = 0;
42
 
 
43
 
    while (key_part != key_part_end) {  
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);
58
 
      } else if (key_part->type == HA_KEYTYPE_BINARY) {
59
 
        return HA_ERR_UNSUPPORTED;
60
 
      } else {
61
 
        key_changed = memcmp(old_pos, new_pos, key_part->length);
62
 
      }
63
 
      key_part++;
64
 
    }
65
 
 
66
 
    /* Key has changed. Look up the database to see if the new value
67
 
       would violate the unique contraint. */
68
 
    if (key_changed) {
69
 
      key = key_buffer;
70
 
      key_len = make_index_key(key, getTable()->getMutableShare()->getPrimaryKey(), new_row);
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);
76
 
        this->errkey_id = getTable()->getShare()->getPrimaryKey();
77
 
        return HA_ERR_FOUND_DUPP_KEY;
78
 
      }
79
 
    }
80
 
  }
81
 
 
82
 
  return 0;
83
 
}
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
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)
97
 
 *   DATE      (interpreted as UINT_24)
98
 
 *   DOUBLE    (interpreted as DOUBLE)
99
 
 *   VARCHAR   (VARTEXT1 or VARTEXT2)
100
 
 *
101
 
 * BlitzDB Key Format:
102
 
 *   [DRIZZLE_KEY][UINT16_T][BLITZDB_UNIQUE_KEY]
103
 
 *
104
 
 * Returns:
105
 
 *   -1 = a < b
106
 
 *    0 = a == b
107
 
 *    1 = a > b
108
 
 */
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;
113
 
 
114
 
  rv = packed_key_cmp(tree, a, b, &a_compared_len, &b_compared_len);
115
 
 
116
 
  if (rv != 0)
117
 
    return rv;
118
 
 
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
 
  }
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) {
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;
160
 
 
161
 
  *a_compared_len = 0;
162
 
  *b_compared_len = 0;
163
 
 
164
 
  for (int i = 0; i < tree->nparts; i++) {
165
 
    curr_part = &tree->parts[i];
166
 
 
167
 
    if (curr_part->null_bitmask) {
168
 
      *a_compared_len += 1;
169
 
      *b_compared_len += 1;
170
 
 
171
 
      if (*a_pos != *b_pos)
172
 
        return ((int)*a_pos - (int)*b_pos);
173
 
 
174
 
      b_pos++;
175
 
 
176
 
      if (!*a_pos++) {
177
 
        curr_part++;
178
 
        continue;
179
 
      }
180
 
    }
181
 
 
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);
186
 
 
187
 
      *a_compared_len += curr_part->length;
188
 
      *b_compared_len += curr_part->length;
189
 
 
190
 
      if (a_int_val < b_int_val)
191
 
        return -1;
192
 
      else if (a_int_val > b_int_val)
193
 
        return 1;
194
 
 
195
 
      a_next_offset = b_next_offset = curr_part->length;
196
 
      break; 
197
 
    }
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
 
 
202
 
      *a_compared_len += curr_part->length;
203
 
      *b_compared_len += curr_part->length;
204
 
 
205
 
      if (a_int_val < b_int_val)
206
 
        return -1;
207
 
      else if (a_int_val > b_int_val)
208
 
        return 1;
209
 
 
210
 
      a_next_offset = b_next_offset = curr_part->length;
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
 
 
217
 
      *a_compared_len += curr_part->length;
218
 
      *b_compared_len += curr_part->length;
219
 
 
220
 
      if (a_int_val < b_int_val)
221
 
        return -1;
222
 
      else if (a_int_val > b_int_val)
223
 
        return 1;
224
 
 
225
 
      a_next_offset = b_next_offset = curr_part->length;
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
 
 
232
 
      *a_compared_len += curr_part->length;
233
 
      *b_compared_len += curr_part->length;
234
 
 
235
 
      if (a_int_val < b_int_val)
236
 
        return -1;
237
 
      else if (a_int_val > b_int_val)
238
 
        return 1;
239
 
 
240
 
      a_next_offset = b_next_offset = curr_part->length;
241
 
      break;
242
 
    }
243
 
    case HA_KEYTYPE_DOUBLE: {
244
 
      double a_double_val, b_double_val;
245
 
      float8get(a_double_val, a_pos);
246
 
      float8get(b_double_val, b_pos);
247
 
 
248
 
      *a_compared_len += curr_part->length;
249
 
      *b_compared_len += curr_part->length;
250
 
 
251
 
      if (a_double_val < b_double_val)
252
 
        return -1;
253
 
      else if (a_double_val > b_double_val)
254
 
        return 1;
255
 
 
256
 
      a_next_offset = b_next_offset = curr_part->length;
257
 
      break;
258
 
    }
259
 
    case HA_KEYTYPE_VARTEXT1:
260
 
    case HA_KEYTYPE_VARTEXT2: {
261
 
      uint16_t a_varchar_len = uint2korr(a_pos);
262
 
      uint16_t b_varchar_len = uint2korr(b_pos);
263
 
      int key_changed;
264
 
 
265
 
      a_pos += sizeof(a_varchar_len);
266
 
      b_pos += sizeof(b_varchar_len);
267
 
 
268
 
      *a_compared_len += a_varchar_len + sizeof(a_varchar_len);
269
 
      *b_compared_len += b_varchar_len + sizeof(b_varchar_len);
270
 
 
271
 
      /* Compare the texts by respecting collation. */
272
 
      key_changed = my_strnncoll(&my_charset_utf8_general_ci,
273
 
                                 (unsigned char *)a_pos, a_varchar_len,
274
 
                                 (unsigned char *)b_pos, b_varchar_len);
275
 
      if (key_changed < 0)
276
 
        return -1;
277
 
      else if (key_changed > 0)
278
 
        return 1;
279
 
 
280
 
      a_next_offset = a_varchar_len;
281
 
      b_next_offset = b_varchar_len;
282
 
      break; 
283
 
    }
284
 
    default:
285
 
      break;
286
 
    }
287
 
 
288
 
    a_pos += a_next_offset;
289
 
    b_pos += b_next_offset;
290
 
    curr_part++;
291
 
  }
292
 
 
293
 
  return 0;
294
 
}