1 | /* -*- mode: C++; c-basic-offset: 4; indent-tabs-mode: nil -*- */ |
2 | // vim: ft=cpp:expandtab:ts=8:sw=4:softtabstop=4: |
3 | #ident "$Id$" |
4 | /*====== |
5 | This file is part of TokuDB |
6 | |
7 | |
8 | Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved. |
9 | |
10 | TokuDBis is free software: you can redistribute it and/or modify |
11 | it under the terms of the GNU General Public License, version 2, |
12 | as published by the Free Software Foundation. |
13 | |
14 | TokuDB is distributed in the hope that it will be useful, |
15 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
17 | GNU General Public License for more details. |
18 | |
19 | You should have received a copy of the GNU General Public License |
20 | along with TokuDB. If not, see <http://www.gnu.org/licenses/>. |
21 | |
22 | ======= */ |
23 | |
24 | #ident "Copyright (c) 2006, 2015, Percona and/or its affiliates. All rights reserved." |
25 | |
26 | #if !defined(TOKUDB_ALTER_COMMON) |
27 | #define TOKUDB_ALTER_COMMON |
28 | |
29 | TOKUDB_UNUSED(static bool tables_have_same_keys( |
30 | TABLE* table, |
31 | TABLE* altered_table, |
32 | bool print_error, |
33 | bool check_field_index)); |
34 | |
35 | static bool tables_have_same_keys( |
36 | TABLE* table, |
37 | TABLE* altered_table, |
38 | bool print_error, |
39 | bool check_field_index) { |
40 | |
41 | bool retval; |
42 | if (table->s->keys != altered_table->s->keys) { |
43 | if (print_error) { |
44 | sql_print_error("tables have different number of keys" ); |
45 | } |
46 | retval = false; |
47 | goto cleanup; |
48 | } |
49 | if (table->s->primary_key != altered_table->s->primary_key) { |
50 | if (print_error) { |
51 | sql_print_error( |
52 | "Tables have different primary keys, %d %d" , |
53 | table->s->primary_key, |
54 | altered_table->s->primary_key); |
55 | } |
56 | retval = false; |
57 | goto cleanup; |
58 | } |
59 | for (uint32_t i=0; i < table->s->keys; i++) { |
60 | KEY* curr_orig_key = &table->key_info[i]; |
61 | KEY* curr_altered_key = &altered_table->key_info[i]; |
62 | if (strcmp(curr_orig_key->name.str, curr_altered_key->name.str)) { |
63 | if (print_error) { |
64 | sql_print_error( |
65 | "key %d has different name, %s %s" , |
66 | i, |
67 | curr_orig_key->name, |
68 | curr_altered_key->name); |
69 | } |
70 | retval = false; |
71 | goto cleanup; |
72 | } |
73 | if (key_is_clustering(curr_orig_key) != |
74 | key_is_clustering(curr_altered_key)) { |
75 | if (print_error) { |
76 | sql_print_error( |
77 | "keys disagree on if they are clustering, %d, %d" , |
78 | curr_orig_key->user_defined_key_parts, |
79 | curr_altered_key->user_defined_key_parts); |
80 | } |
81 | retval = false; |
82 | goto cleanup; |
83 | } |
84 | if (((curr_orig_key->flags & HA_NOSAME) == 0) != |
85 | ((curr_altered_key->flags & HA_NOSAME) == 0)) { |
86 | if (print_error) { |
87 | sql_print_error( |
88 | "keys disagree on if they are unique, %d, %d" , |
89 | curr_orig_key->user_defined_key_parts, |
90 | curr_altered_key->user_defined_key_parts); |
91 | } |
92 | retval = false; |
93 | goto cleanup; |
94 | } |
95 | if (curr_orig_key->user_defined_key_parts != |
96 | curr_altered_key->user_defined_key_parts) { |
97 | if (print_error) { |
98 | sql_print_error( |
99 | "keys have different number of parts, %d, %d" , |
100 | curr_orig_key->user_defined_key_parts, |
101 | curr_altered_key->user_defined_key_parts); |
102 | } |
103 | retval = false; |
104 | goto cleanup; |
105 | } |
106 | // |
107 | // now verify that each field in the key is the same |
108 | // |
109 | for (uint32_t j = 0; j < curr_orig_key->user_defined_key_parts; j++) { |
110 | KEY_PART_INFO* curr_orig_part = &curr_orig_key->key_part[j]; |
111 | KEY_PART_INFO* curr_altered_part = &curr_altered_key->key_part[j]; |
112 | Field* curr_orig_field = curr_orig_part->field; |
113 | Field* curr_altered_field = curr_altered_part->field; |
114 | if (curr_orig_part->length != curr_altered_part->length) { |
115 | if (print_error) { |
116 | sql_print_error( |
117 | "Key %s has different length at index %d" , |
118 | curr_orig_key->name, |
119 | j); |
120 | } |
121 | retval = false; |
122 | goto cleanup; |
123 | } |
124 | bool are_fields_same; |
125 | are_fields_same = (check_field_index) ? |
126 | (curr_orig_part->fieldnr == curr_altered_part->fieldnr && |
127 | fields_are_same_type(curr_orig_field, curr_altered_field)) : |
128 | (are_two_fields_same(curr_orig_field,curr_altered_field)); |
129 | |
130 | if (!are_fields_same) { |
131 | if (print_error) { |
132 | sql_print_error( |
133 | "Key %s has different field at index %d" , |
134 | curr_orig_key->name, |
135 | j); |
136 | } |
137 | retval = false; |
138 | goto cleanup; |
139 | } |
140 | } |
141 | } |
142 | |
143 | retval = true; |
144 | cleanup: |
145 | return retval; |
146 | } |
147 | |
148 | // MySQL sets the null_bit as a number that you can bit-wise AND a byte to |
149 | // to evaluate whether a field is NULL or not. This value is a power of 2, from |
150 | // 2^0 to 2^7. We return the position of the bit within the byte, which is |
151 | // lg null_bit |
152 | TOKUDB_UNUSED(static inline uint32_t get_null_bit_position( |
153 | uint32_t null_bit)); |
154 | static inline uint32_t get_null_bit_position(uint32_t null_bit) { |
155 | uint32_t retval = 0; |
156 | switch(null_bit) { |
157 | case (1): |
158 | retval = 0; |
159 | break; |
160 | case (2): |
161 | retval = 1; |
162 | break; |
163 | case (4): |
164 | retval = 2; |
165 | break; |
166 | case (8): |
167 | retval = 3; |
168 | break; |
169 | case (16): |
170 | retval = 4; |
171 | break; |
172 | case (32): |
173 | retval = 5; |
174 | break; |
175 | case (64): |
176 | retval = 6; |
177 | break; |
178 | case (128): |
179 | retval = 7; |
180 | break; |
181 | default: |
182 | assert_unreachable(); |
183 | } |
184 | return retval; |
185 | } |
186 | |
187 | // returns the index of the null bit of field. |
188 | TOKUDB_UNUSED(static inline uint32_t get_overall_null_bit_position( |
189 | TABLE* table, |
190 | Field* field)); |
191 | static inline uint32_t get_overall_null_bit_position( |
192 | TABLE* table, |
193 | Field* field) { |
194 | |
195 | uint32_t offset = get_null_offset(table, field); |
196 | uint32_t null_bit = field->null_bit; |
197 | return offset*8 + get_null_bit_position(null_bit); |
198 | } |
199 | |
200 | // not static since 51 uses this and 56 does not |
201 | TOKUDB_UNUSED(static bool are_null_bits_in_order(TABLE* table)); |
202 | static bool are_null_bits_in_order(TABLE* table) { |
203 | uint32_t curr_null_pos = 0; |
204 | bool first = true; |
205 | bool retval = true; |
206 | for (uint i = 0; i < table->s->fields; i++) { |
207 | Field* curr_field = table->field[i]; |
208 | bool nullable = (curr_field->null_bit != 0); |
209 | if (nullable) { |
210 | uint32_t pos = |
211 | get_overall_null_bit_position(table, curr_field); |
212 | if (!first && pos != curr_null_pos+1){ |
213 | retval = false; |
214 | break; |
215 | } |
216 | first = false; |
217 | curr_null_pos = pos; |
218 | } |
219 | } |
220 | return retval; |
221 | } |
222 | |
223 | TOKUDB_UNUSED(static uint32_t get_first_null_bit_pos(TABLE* table)); |
224 | static uint32_t get_first_null_bit_pos(TABLE* table) { |
225 | uint32_t table_pos = 0; |
226 | for (uint i = 0; i < table->s->fields; i++) { |
227 | Field* curr_field = table->field[i]; |
228 | bool nullable = (curr_field->null_bit != 0); |
229 | if (nullable) { |
230 | table_pos = |
231 | get_overall_null_bit_position(table, curr_field); |
232 | break; |
233 | } |
234 | } |
235 | return table_pos; |
236 | } |
237 | |
238 | TOKUDB_UNUSED(static bool is_column_default_null( |
239 | TABLE* src_table, |
240 | uint32_t field_index)); |
241 | static bool is_column_default_null( |
242 | TABLE* src_table, |
243 | uint32_t field_index) { |
244 | |
245 | Field* curr_field = src_table->field[field_index]; |
246 | bool is_null_default = false; |
247 | bool nullable = curr_field->null_bit != 0; |
248 | if (nullable) { |
249 | uint32_t null_bit_position = |
250 | get_overall_null_bit_position(src_table, curr_field); |
251 | is_null_default = |
252 | is_overall_null_position_set( |
253 | src_table->s->default_values, |
254 | null_bit_position); |
255 | } |
256 | return is_null_default; |
257 | } |
258 | |
259 | static uint32_t fill_static_row_mutator( |
260 | uchar* buf, |
261 | TABLE* orig_table, |
262 | TABLE* altered_table, |
263 | KEY_AND_COL_INFO* orig_kc_info, |
264 | KEY_AND_COL_INFO* altered_kc_info, |
265 | uint32_t keynr) { |
266 | |
267 | // |
268 | // start packing extra |
269 | // |
270 | uchar* pos = buf; |
271 | // says what the operation is |
272 | pos[0] = UP_COL_ADD_OR_DROP; |
273 | pos++; |
274 | |
275 | // |
276 | // null byte information |
277 | // |
278 | memcpy(pos, &orig_table->s->null_bytes, sizeof(orig_table->s->null_bytes)); |
279 | pos += sizeof(orig_table->s->null_bytes); |
280 | memcpy( |
281 | pos, |
282 | &altered_table->s->null_bytes, |
283 | sizeof(orig_table->s->null_bytes)); |
284 | pos += sizeof(altered_table->s->null_bytes); |
285 | |
286 | // |
287 | // num_offset_bytes |
288 | // |
289 | assert_always(orig_kc_info->num_offset_bytes <= 2); |
290 | pos[0] = orig_kc_info->num_offset_bytes; |
291 | pos++; |
292 | assert_always(altered_kc_info->num_offset_bytes <= 2); |
293 | pos[0] = altered_kc_info->num_offset_bytes; |
294 | pos++; |
295 | |
296 | // |
297 | // size of fixed fields |
298 | // |
299 | uint32_t fixed_field_size = orig_kc_info->mcp_info[keynr].fixed_field_size; |
300 | memcpy(pos, &fixed_field_size, sizeof(fixed_field_size)); |
301 | pos += sizeof(fixed_field_size); |
302 | fixed_field_size = altered_kc_info->mcp_info[keynr].fixed_field_size; |
303 | memcpy(pos, &fixed_field_size, sizeof(fixed_field_size)); |
304 | pos += sizeof(fixed_field_size); |
305 | |
306 | // |
307 | // length of offsets |
308 | // |
309 | uint32_t len_of_offsets = orig_kc_info->mcp_info[keynr].len_of_offsets; |
310 | memcpy(pos, &len_of_offsets, sizeof(len_of_offsets)); |
311 | pos += sizeof(len_of_offsets); |
312 | len_of_offsets = altered_kc_info->mcp_info[keynr].len_of_offsets; |
313 | memcpy(pos, &len_of_offsets, sizeof(len_of_offsets)); |
314 | pos += sizeof(len_of_offsets); |
315 | |
316 | uint32_t orig_start_null_pos = get_first_null_bit_pos(orig_table); |
317 | memcpy(pos, &orig_start_null_pos, sizeof(orig_start_null_pos)); |
318 | pos += sizeof(orig_start_null_pos); |
319 | uint32_t altered_start_null_pos = get_first_null_bit_pos(altered_table); |
320 | memcpy(pos, &altered_start_null_pos, sizeof(altered_start_null_pos)); |
321 | pos += sizeof(altered_start_null_pos); |
322 | |
323 | assert_always((pos-buf) == STATIC_ROW_MUTATOR_SIZE); |
324 | return pos - buf; |
325 | } |
326 | |
327 | static uint32_t fill_dynamic_row_mutator( |
328 | uchar* buf, |
329 | uint32_t* columns, |
330 | uint32_t num_columns, |
331 | TABLE* src_table, |
332 | KEY_AND_COL_INFO* src_kc_info, |
333 | uint32_t keynr, |
334 | bool is_add, |
335 | bool* out_has_blobs) { |
336 | |
337 | uchar* pos = buf; |
338 | bool has_blobs = false; |
339 | uint32_t cols = num_columns; |
340 | memcpy(pos, &cols, sizeof(cols)); |
341 | pos += sizeof(cols); |
342 | for (uint32_t i = 0; i < num_columns; i++) { |
343 | uint32_t curr_index = columns[i]; |
344 | Field* curr_field = src_table->field[curr_index]; |
345 | |
346 | pos[0] = is_add ? COL_ADD : COL_DROP; |
347 | pos++; |
348 | // |
349 | // NULL bit information |
350 | // |
351 | bool is_null_default = false; |
352 | bool nullable = curr_field->null_bit != 0; |
353 | if (!nullable) { |
354 | pos[0] = 0; |
355 | pos++; |
356 | } else { |
357 | pos[0] = 1; |
358 | pos++; |
359 | // write position of null byte that is to be removed |
360 | uint32_t null_bit_position = |
361 | get_overall_null_bit_position(src_table, curr_field); |
362 | memcpy(pos, &null_bit_position, sizeof(null_bit_position)); |
363 | pos += sizeof(null_bit_position); |
364 | // |
365 | // if adding a column, write the value of the default null_bit |
366 | // |
367 | if (is_add) { |
368 | is_null_default = |
369 | is_overall_null_position_set( |
370 | src_table->s->default_values, |
371 | null_bit_position); |
372 | pos[0] = is_null_default ? 1 : 0; |
373 | pos++; |
374 | } |
375 | } |
376 | if (is_fixed_field(src_kc_info, curr_index)) { |
377 | // we have a fixed field being dropped |
378 | // store the offset and the number of bytes |
379 | pos[0] = COL_FIXED; |
380 | pos++; |
381 | //store the offset |
382 | uint32_t fixed_field_offset = |
383 | src_kc_info->cp_info[keynr][curr_index].col_pack_val; |
384 | memcpy(pos, &fixed_field_offset, sizeof(fixed_field_offset)); |
385 | pos += sizeof(fixed_field_offset); |
386 | //store the number of bytes |
387 | uint32_t num_bytes = src_kc_info->field_lengths[curr_index]; |
388 | memcpy(pos, &num_bytes, sizeof(num_bytes)); |
389 | pos += sizeof(num_bytes); |
390 | if (is_add && !is_null_default) { |
391 | uint curr_field_offset = field_offset(curr_field, src_table); |
392 | memcpy( |
393 | pos, |
394 | src_table->s->default_values + curr_field_offset, |
395 | num_bytes); |
396 | pos += num_bytes; |
397 | } |
398 | } else if (is_variable_field(src_kc_info, curr_index)) { |
399 | pos[0] = COL_VAR; |
400 | pos++; |
401 | //store the index of the variable column |
402 | uint32_t var_field_index = |
403 | src_kc_info->cp_info[keynr][curr_index].col_pack_val; |
404 | memcpy(pos, &var_field_index, sizeof(var_field_index)); |
405 | pos += sizeof(var_field_index); |
406 | if (is_add && !is_null_default) { |
407 | uint curr_field_offset = field_offset(curr_field, src_table); |
408 | uint32_t len_bytes = src_kc_info->length_bytes[curr_index]; |
409 | uint32_t data_length = |
410 | get_var_data_length( |
411 | src_table->s->default_values + curr_field_offset, |
412 | len_bytes); |
413 | memcpy(pos, &data_length, sizeof(data_length)); |
414 | pos += sizeof(data_length); |
415 | memcpy( |
416 | pos, |
417 | src_table->s->default_values + curr_field_offset + len_bytes, |
418 | data_length); |
419 | pos += data_length; |
420 | } |
421 | } else { |
422 | pos[0] = COL_BLOB; |
423 | pos++; |
424 | has_blobs = true; |
425 | } |
426 | } |
427 | *out_has_blobs = has_blobs; |
428 | return pos-buf; |
429 | } |
430 | |
431 | static uint32_t fill_static_blob_row_mutator( |
432 | uchar* buf, |
433 | TABLE* src_table, |
434 | KEY_AND_COL_INFO* src_kc_info) { |
435 | |
436 | uchar* pos = buf; |
437 | // copy number of blobs |
438 | memcpy(pos, &src_kc_info->num_blobs, sizeof(src_kc_info->num_blobs)); |
439 | pos += sizeof(src_kc_info->num_blobs); |
440 | // copy length bytes for each blob |
441 | for (uint32_t i = 0; i < src_kc_info->num_blobs; i++) { |
442 | uint32_t curr_field_index = src_kc_info->blob_fields[i]; |
443 | Field* field = src_table->field[curr_field_index]; |
444 | uint32_t len_bytes = field->row_pack_length(); |
445 | assert_always(len_bytes <= 4); |
446 | pos[0] = len_bytes; |
447 | pos++; |
448 | } |
449 | |
450 | return pos-buf; |
451 | } |
452 | |
453 | static uint32_t fill_dynamic_blob_row_mutator( |
454 | uchar* buf, |
455 | uint32_t* columns, |
456 | uint32_t num_columns, |
457 | TABLE* src_table, |
458 | KEY_AND_COL_INFO* src_kc_info, |
459 | bool is_add) { |
460 | |
461 | uchar* pos = buf; |
462 | for (uint32_t i = 0; i < num_columns; i++) { |
463 | uint32_t curr_field_index = columns[i]; |
464 | Field* curr_field = src_table->field[curr_field_index]; |
465 | if (is_blob_field(src_kc_info, curr_field_index)) { |
466 | // find out which blob it is |
467 | uint32_t blob_index = src_kc_info->num_blobs; |
468 | for (uint32_t j = 0; j < src_kc_info->num_blobs; j++) { |
469 | if (curr_field_index == src_kc_info->blob_fields[j]) { |
470 | blob_index = j; |
471 | break; |
472 | } |
473 | } |
474 | // assert we found blob in list |
475 | assert_always(blob_index < src_kc_info->num_blobs); |
476 | pos[0] = is_add ? COL_ADD : COL_DROP; |
477 | pos++; |
478 | memcpy(pos, &blob_index, sizeof(blob_index)); |
479 | pos += sizeof(blob_index); |
480 | if (is_add) { |
481 | uint32_t len_bytes = curr_field->row_pack_length(); |
482 | assert_always(len_bytes <= 4); |
483 | pos[0] = len_bytes; |
484 | pos++; |
485 | |
486 | // create a zero length blob field that can be directly copied |
487 | // in for now, in MySQL, we can only have blob fields |
488 | // that have no default value |
489 | memset(pos, 0, len_bytes); |
490 | pos += len_bytes; |
491 | } |
492 | } |
493 | } |
494 | return pos-buf; |
495 | } |
496 | |
497 | // TODO: carefully review to make sure that the right information is used |
498 | // TODO: namely, when do we get stuff from share->kc_info and when we get |
499 | // TODO: it from altered_kc_info, and when is keynr associated with the right thing |
500 | uint32_t ha_tokudb::fill_row_mutator( |
501 | uchar* buf, |
502 | uint32_t* columns, |
503 | uint32_t num_columns, |
504 | TABLE* altered_table, |
505 | KEY_AND_COL_INFO* altered_kc_info, |
506 | uint32_t keynr, |
507 | bool is_add) { |
508 | |
509 | if (TOKUDB_UNLIKELY(TOKUDB_DEBUG_FLAGS(TOKUDB_DEBUG_ALTER_TABLE))) { |
510 | TOKUDB_HANDLER_TRACE("*****some info:*************" ); |
511 | TOKUDB_HANDLER_TRACE( |
512 | "old things: num_null_bytes %d, num_offset_bytes %d, " |
513 | "fixed_field_size %d, fixed_field_size %d" , |
514 | table->s->null_bytes, |
515 | share->kc_info.num_offset_bytes, |
516 | share->kc_info.mcp_info[keynr].fixed_field_size, |
517 | share->kc_info.mcp_info[keynr].len_of_offsets); |
518 | TOKUDB_HANDLER_TRACE( |
519 | "new things: num_null_bytes %d, num_offset_bytes %d, " |
520 | "fixed_field_size %d, fixed_field_size %d" , |
521 | altered_table->s->null_bytes, |
522 | altered_kc_info->num_offset_bytes, |
523 | altered_kc_info->mcp_info[keynr].fixed_field_size, |
524 | altered_kc_info->mcp_info[keynr].len_of_offsets); |
525 | TOKUDB_HANDLER_TRACE("****************************" ); |
526 | } |
527 | uchar* pos = buf; |
528 | bool has_blobs = false; |
529 | pos += |
530 | fill_static_row_mutator( |
531 | pos, |
532 | table, |
533 | altered_table, |
534 | &share->kc_info, |
535 | altered_kc_info, |
536 | keynr); |
537 | |
538 | if (is_add) { |
539 | pos += |
540 | fill_dynamic_row_mutator( |
541 | pos, |
542 | columns, |
543 | num_columns, |
544 | altered_table, |
545 | altered_kc_info, |
546 | keynr, |
547 | is_add, |
548 | &has_blobs); |
549 | } else { |
550 | pos += |
551 | fill_dynamic_row_mutator( |
552 | pos, |
553 | columns, |
554 | num_columns, |
555 | table, |
556 | &share->kc_info, |
557 | keynr, |
558 | is_add, |
559 | &has_blobs); |
560 | } |
561 | if (has_blobs) { |
562 | pos += fill_static_blob_row_mutator(pos, table, &share->kc_info); |
563 | if (is_add) { |
564 | pos += |
565 | fill_dynamic_blob_row_mutator( |
566 | pos, |
567 | columns, |
568 | num_columns, |
569 | altered_table, |
570 | altered_kc_info, |
571 | is_add); |
572 | } else { |
573 | pos += |
574 | fill_dynamic_blob_row_mutator( |
575 | pos, |
576 | columns, |
577 | num_columns, |
578 | table, |
579 | &share->kc_info, |
580 | is_add); |
581 | } |
582 | } |
583 | return pos-buf; |
584 | } |
585 | |
586 | static bool all_fields_are_same_type(TABLE *table_a, TABLE *table_b) { |
587 | if (table_a->s->fields != table_b->s->fields) |
588 | return false; |
589 | for (uint i = 0; i < table_a->s->fields; i++) { |
590 | Field* field_a = table_a->field[i]; |
591 | Field* field_b = table_b->field[i]; |
592 | if (!fields_are_same_type(field_a, field_b)) |
593 | return false; |
594 | } |
595 | return true; |
596 | } |
597 | |
598 | TOKUDB_UNUSED(static bool column_rename_supported( |
599 | TABLE* orig_table, |
600 | TABLE* new_table, |
601 | bool alter_column_order)); |
602 | static bool column_rename_supported( |
603 | TABLE* orig_table, |
604 | TABLE* new_table, |
605 | bool alter_column_order) { |
606 | |
607 | bool retval = false; |
608 | bool keys_same_for_cr; |
609 | uint num_fields_with_different_names = 0; |
610 | uint field_with_different_name = orig_table->s->fields; |
611 | if (orig_table->s->fields != new_table->s->fields) { |
612 | retval = false; |
613 | goto cleanup; |
614 | } |
615 | if (alter_column_order) { |
616 | retval = false; |
617 | goto cleanup; |
618 | } |
619 | if (!all_fields_are_same_type(orig_table, new_table)) { |
620 | retval = false; |
621 | goto cleanup; |
622 | } |
623 | for (uint i = 0; i < orig_table->s->fields; i++) { |
624 | Field* orig_field = orig_table->field[i]; |
625 | Field* new_field = new_table->field[i]; |
626 | if (!fields_have_same_name(orig_field, new_field)) { |
627 | num_fields_with_different_names++; |
628 | field_with_different_name = i; |
629 | } |
630 | } |
631 | // only allow one renamed field |
632 | if (num_fields_with_different_names != 1) { |
633 | retval = false; |
634 | goto cleanup; |
635 | } |
636 | assert_always(field_with_different_name < orig_table->s->fields); |
637 | // |
638 | // at this point, we have verified that the two tables have |
639 | // the same field types and with ONLY one field with a different name. |
640 | // We have also identified the field with the different name |
641 | // |
642 | // Now we need to check the indexes |
643 | // |
644 | keys_same_for_cr = |
645 | tables_have_same_keys( |
646 | orig_table, |
647 | new_table, |
648 | false, |
649 | true); |
650 | if (!keys_same_for_cr) { |
651 | retval = false; |
652 | goto cleanup; |
653 | } |
654 | retval = true; |
655 | cleanup: |
656 | return retval; |
657 | } |
658 | |
659 | TOKUDB_UNUSED(static int find_changed_columns( |
660 | uint32_t* changed_columns, |
661 | uint32_t* num_changed_columns, |
662 | TABLE* smaller_table, |
663 | TABLE* bigger_table)); |
664 | static int find_changed_columns( |
665 | uint32_t* changed_columns, |
666 | uint32_t* num_changed_columns, |
667 | TABLE* smaller_table, |
668 | TABLE* bigger_table) { |
669 | |
670 | int retval; |
671 | uint curr_new_col_index = 0; |
672 | uint32_t curr_num_changed_columns=0; |
673 | assert_always(bigger_table->s->fields > smaller_table->s->fields); |
674 | for (uint i = 0; i < smaller_table->s->fields; i++, curr_new_col_index++) { |
675 | if (curr_new_col_index >= bigger_table->s->fields) { |
676 | sql_print_error("error in determining changed columns" ); |
677 | retval = 1; |
678 | goto cleanup; |
679 | } |
680 | Field* curr_field_in_new = bigger_table->field[curr_new_col_index]; |
681 | Field* curr_field_in_orig = smaller_table->field[i]; |
682 | while (!fields_have_same_name(curr_field_in_orig, curr_field_in_new)) { |
683 | changed_columns[curr_num_changed_columns] = curr_new_col_index; |
684 | curr_num_changed_columns++; |
685 | curr_new_col_index++; |
686 | curr_field_in_new = bigger_table->field[curr_new_col_index]; |
687 | if (curr_new_col_index >= bigger_table->s->fields) { |
688 | sql_print_error("error in determining changed columns" ); |
689 | retval = 1; |
690 | goto cleanup; |
691 | } |
692 | } |
693 | // at this point, curr_field_in_orig and curr_field_in_new should be |
694 | // the same, let's verify make sure the two fields that have the same |
695 | // name are ok |
696 | if (!are_two_fields_same(curr_field_in_orig, curr_field_in_new)) { |
697 | sql_print_error( |
698 | "Two fields that were supposedly the same are not: %s in " |
699 | "original, %s in new" , |
700 | curr_field_in_orig->field_name.str, |
701 | curr_field_in_new->field_name.str); |
702 | retval = 1; |
703 | goto cleanup; |
704 | } |
705 | } |
706 | for (uint i = curr_new_col_index; i < bigger_table->s->fields; i++) { |
707 | changed_columns[curr_num_changed_columns] = i; |
708 | curr_num_changed_columns++; |
709 | } |
710 | *num_changed_columns = curr_num_changed_columns; |
711 | retval = 0; |
712 | cleanup: |
713 | return retval; |
714 | } |
715 | |
716 | TOKUDB_UNUSED(static bool tables_have_same_keys_and_columns( |
717 | TABLE* first_table, |
718 | TABLE* second_table, |
719 | bool print_error)); |
720 | static bool tables_have_same_keys_and_columns( |
721 | TABLE* first_table, |
722 | TABLE* second_table, |
723 | bool print_error) { |
724 | |
725 | bool retval; |
726 | if (first_table->s->null_bytes != second_table->s->null_bytes) { |
727 | retval = false; |
728 | if (print_error) { |
729 | sql_print_error( |
730 | "tables have different number of null bytes, %d, %d" , |
731 | first_table->s->null_bytes, |
732 | second_table->s->null_bytes); |
733 | } |
734 | goto exit; |
735 | } |
736 | if (first_table->s->fields != second_table->s->fields) { |
737 | retval = false; |
738 | if (print_error) { |
739 | sql_print_error( |
740 | "tables have different number of fields, %d, %d" , |
741 | first_table->s->fields, |
742 | second_table->s->fields); |
743 | } |
744 | goto exit; |
745 | } |
746 | for (uint i = 0; i < first_table->s->fields; i++) { |
747 | Field* a = first_table->field[i]; |
748 | Field* b = second_table->field[i]; |
749 | if (!are_two_fields_same(a,b)) { |
750 | retval = false; |
751 | sql_print_error( |
752 | "tables have different fields at position %d" , |
753 | i); |
754 | goto exit; |
755 | } |
756 | } |
757 | if (!tables_have_same_keys(first_table, second_table, print_error, true)) { |
758 | retval = false; |
759 | goto exit; |
760 | } |
761 | |
762 | retval = true; |
763 | exit: |
764 | return retval; |
765 | } |
766 | |
767 | #if TOKU_INCLUDE_WRITE_FRM_DATA |
768 | // write the new frm data to the status dictionary using the alter table |
769 | // transaction |
770 | int ha_tokudb::write_frm_data(const uchar* frm_data, size_t frm_len) { |
771 | TOKUDB_DBUG_ENTER("write_frm_data" ); |
772 | |
773 | int error = 0; |
774 | if (TOKU_PARTITION_WRITE_FRM_DATA || table->part_info == NULL) { |
775 | // write frmdata to status |
776 | THD* thd = ha_thd(); |
777 | tokudb_trx_data* trx = |
778 | (tokudb_trx_data*)thd_get_ha_data(thd, tokudb_hton); |
779 | assert_always(trx); |
780 | DB_TXN* txn = trx->stmt; // use alter table transaction |
781 | assert_always(txn); |
782 | error = |
783 | write_to_status( |
784 | share->status_block, |
785 | hatoku_frm_data, |
786 | (void*)frm_data, |
787 | (uint)frm_len, |
788 | txn); |
789 | } |
790 | |
791 | TOKUDB_DBUG_RETURN(error); |
792 | } |
793 | #endif |
794 | |
795 | #endif |
796 | |