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 
tables_have_same_keys(TABLE * table,TABLE * altered_table,bool print_error,bool check_field_index)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));
get_null_bit_position(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));
get_overall_null_bit_position(TABLE * table,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));
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));
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));
is_column_default_null(TABLE * src_table,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 
fill_static_row_mutator(uchar * buf,TABLE * orig_table,TABLE * altered_table,KEY_AND_COL_INFO * orig_kc_info,KEY_AND_COL_INFO * altered_kc_info,uint32_t keynr)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 
fill_dynamic_row_mutator(uchar * buf,uint32_t * columns,uint32_t num_columns,TABLE * src_table,KEY_AND_COL_INFO * src_kc_info,uint32_t keynr,bool is_add,bool * out_has_blobs)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 
fill_static_blob_row_mutator(uchar * buf,TABLE * src_table,KEY_AND_COL_INFO * src_kc_info)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 
fill_dynamic_blob_row_mutator(uchar * buf,uint32_t * columns,uint32_t num_columns,TABLE * src_table,KEY_AND_COL_INFO * src_kc_info,bool is_add)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
fill_row_mutator(uchar * buf,uint32_t * columns,uint32_t num_columns,TABLE * altered_table,KEY_AND_COL_INFO * altered_kc_info,uint32_t keynr,bool is_add)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 
all_fields_are_same_type(TABLE * table_a,TABLE * table_b)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));
column_rename_supported(TABLE * orig_table,TABLE * new_table,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));
find_changed_columns(uint32_t * changed_columns,uint32_t * num_changed_columns,TABLE * smaller_table,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));
tables_have_same_keys_and_columns(TABLE * first_table,TABLE * second_table,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 defined(TOKU_INCLUDE_WRITE_FRM_DATA) && TOKU_INCLUDE_WRITE_FRM_DATA
768 // write the new frm data to the status dictionary using the alter table
769 // transaction
write_frm_data(const uchar * frm_data,size_t frm_len)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 defined(WITH_PARTITION_STORAGE_ENGINE) && WITH_PARTITION_STORAGE_ENGINE
775     if (TOKU_PARTITION_WRITE_FRM_DATA || table->part_info == NULL) {
776         // write frmdata to status
777         THD* thd = ha_thd();
778         tokudb_trx_data* trx =
779             (tokudb_trx_data*)thd_get_ha_data(thd, tokudb_hton);
780         assert_always(trx);
781         DB_TXN* txn = trx->stmt; // use alter table transaction
782         assert_always(txn);
783         error =
784             write_to_status(
785                 share->status_block,
786                 hatoku_frm_data,
787                 (void*)frm_data,
788                 (uint)frm_len,
789                 txn);
790     }
791 #endif  // defined(WITH_PARTITION_STORAGE_ENGINE) && WITH_PARTITION_STORAGE_ENGINE
792 
793     TOKUDB_DBUG_RETURN(error);
794 }
795 #endif  // defined(TOKU_INCLUDE_WRITE_FRM_DATA) && TOKU_INCLUDE_WRITE_FRM_DATA
796 
797 #endif
798