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/*======
5This file is part of TokuDB
6
7
8Copyright (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
29TOKUDB_UNUSED(static bool tables_have_same_keys(
30 TABLE* table,
31 TABLE* altered_table,
32 bool print_error,
33 bool check_field_index));
34
35static 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;
144cleanup:
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
152TOKUDB_UNUSED(static inline uint32_t get_null_bit_position(
153 uint32_t null_bit));
154static 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.
188TOKUDB_UNUSED(static inline uint32_t get_overall_null_bit_position(
189 TABLE* table,
190 Field* field));
191static 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
201TOKUDB_UNUSED(static bool are_null_bits_in_order(TABLE* table));
202static 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
223TOKUDB_UNUSED(static uint32_t get_first_null_bit_pos(TABLE* table));
224static 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
238TOKUDB_UNUSED(static bool is_column_default_null(
239 TABLE* src_table,
240 uint32_t field_index));
241static 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
259static 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
327static 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
431static 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
453static 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
500uint32_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
586static 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
598TOKUDB_UNUSED(static bool column_rename_supported(
599 TABLE* orig_table,
600 TABLE* new_table,
601 bool alter_column_order));
602static 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;
655cleanup:
656 return retval;
657}
658
659TOKUDB_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));
664static 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;
712cleanup:
713 return retval;
714}
715
716TOKUDB_UNUSED(static bool tables_have_same_keys_and_columns(
717 TABLE* first_table,
718 TABLE* second_table,
719 bool print_error));
720static 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;
763exit:
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
770int 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