| 1 | /* Copyright (c) 2006, 2013, Oracle and/or its affiliates. |
| 2 | Copyright (c) 2011, 2013, Monty Program Ab |
| 3 | |
| 4 | This program is free software; you can redistribute it and/or modify |
| 5 | it under the terms of the GNU General Public License as published by |
| 6 | the Free Software Foundation; version 2 of the License. |
| 7 | |
| 8 | This program is distributed in the hope that it will be useful, |
| 9 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 11 | GNU General Public License for more details. |
| 12 | |
| 13 | You should have received a copy of the GNU General Public License |
| 14 | along with this program; if not, write to the Free Software |
| 15 | Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ |
| 16 | |
| 17 | #include "mariadb.h" |
| 18 | #include <my_bit.h> |
| 19 | #include "rpl_utility.h" |
| 20 | #include "log_event.h" |
| 21 | |
| 22 | #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) |
| 23 | #include "rpl_rli.h" |
| 24 | #include "sql_select.h" |
| 25 | |
| 26 | /** |
| 27 | Calculate display length for MySQL56 temporal data types from their metadata. |
| 28 | It contains fractional precision in the low 16-bit word. |
| 29 | */ |
| 30 | static uint32 |
| 31 | max_display_length_for_temporal2_field(uint32 int_display_length, |
| 32 | unsigned int metadata) |
| 33 | { |
| 34 | metadata&= 0x00ff; |
| 35 | return int_display_length + metadata + (metadata ? 1 : 0); |
| 36 | } |
| 37 | |
| 38 | |
| 39 | /** |
| 40 | Compute the maximum display length of a field. |
| 41 | |
| 42 | @param sql_type Type of the field |
| 43 | @param metadata The metadata from the master for the field. |
| 44 | @return Maximum length of the field in bytes. |
| 45 | |
| 46 | The precise values calculated by field->max_display_length() and |
| 47 | calculated by max_display_length_for_field() can differ (by +1 or -1) |
| 48 | for integer data types (TINYINT, SMALLINT, MEDIUMINT, INT, BIGINT). |
| 49 | This slight difference is not important here, because we call |
| 50 | this function only for two *different* integer data types. |
| 51 | */ |
| 52 | static uint32 |
| 53 | max_display_length_for_field(enum_field_types sql_type, unsigned int metadata) |
| 54 | { |
| 55 | DBUG_PRINT("debug" , ("sql_type: %d, metadata: 0x%x" , sql_type, metadata)); |
| 56 | DBUG_ASSERT(metadata >> 16 == 0); |
| 57 | |
| 58 | switch (sql_type) { |
| 59 | case MYSQL_TYPE_NEWDECIMAL: |
| 60 | return metadata >> 8; |
| 61 | |
| 62 | case MYSQL_TYPE_FLOAT: |
| 63 | return 12; |
| 64 | |
| 65 | case MYSQL_TYPE_DOUBLE: |
| 66 | return 22; |
| 67 | |
| 68 | case MYSQL_TYPE_SET: |
| 69 | case MYSQL_TYPE_ENUM: |
| 70 | return metadata & 0x00ff; |
| 71 | |
| 72 | case MYSQL_TYPE_STRING: |
| 73 | { |
| 74 | uchar type= metadata >> 8; |
| 75 | if (type == MYSQL_TYPE_SET || type == MYSQL_TYPE_ENUM) |
| 76 | return metadata & 0xff; |
| 77 | else |
| 78 | /* This is taken from Field_string::unpack. */ |
| 79 | return (((metadata >> 4) & 0x300) ^ 0x300) + (metadata & 0x00ff); |
| 80 | } |
| 81 | |
| 82 | case MYSQL_TYPE_YEAR: |
| 83 | case MYSQL_TYPE_TINY: |
| 84 | return 4; |
| 85 | |
| 86 | case MYSQL_TYPE_SHORT: |
| 87 | return 6; |
| 88 | |
| 89 | case MYSQL_TYPE_INT24: |
| 90 | return 9; |
| 91 | |
| 92 | case MYSQL_TYPE_LONG: |
| 93 | return 11; |
| 94 | |
| 95 | #ifdef HAVE_LONG_LONG |
| 96 | case MYSQL_TYPE_LONGLONG: |
| 97 | return 20; |
| 98 | |
| 99 | #endif |
| 100 | case MYSQL_TYPE_NULL: |
| 101 | return 0; |
| 102 | |
| 103 | case MYSQL_TYPE_NEWDATE: |
| 104 | return 3; |
| 105 | |
| 106 | case MYSQL_TYPE_DATE: |
| 107 | return 3; |
| 108 | |
| 109 | case MYSQL_TYPE_TIME: |
| 110 | return MIN_TIME_WIDTH; |
| 111 | |
| 112 | case MYSQL_TYPE_TIME2: |
| 113 | return max_display_length_for_temporal2_field(MIN_TIME_WIDTH, metadata); |
| 114 | |
| 115 | case MYSQL_TYPE_TIMESTAMP: |
| 116 | return MAX_DATETIME_WIDTH; |
| 117 | |
| 118 | case MYSQL_TYPE_TIMESTAMP2: |
| 119 | return max_display_length_for_temporal2_field(MAX_DATETIME_WIDTH, metadata); |
| 120 | |
| 121 | case MYSQL_TYPE_DATETIME: |
| 122 | return MAX_DATETIME_WIDTH; |
| 123 | |
| 124 | case MYSQL_TYPE_DATETIME2: |
| 125 | return max_display_length_for_temporal2_field(MAX_DATETIME_WIDTH, metadata); |
| 126 | |
| 127 | case MYSQL_TYPE_BIT: |
| 128 | /* |
| 129 | Decode the size of the bit field from the master. |
| 130 | */ |
| 131 | DBUG_ASSERT((metadata & 0xff) <= 7); |
| 132 | return 8 * (metadata >> 8U) + (metadata & 0x00ff); |
| 133 | |
| 134 | case MYSQL_TYPE_VAR_STRING: |
| 135 | case MYSQL_TYPE_VARCHAR: |
| 136 | return metadata; |
| 137 | case MYSQL_TYPE_VARCHAR_COMPRESSED: |
| 138 | return metadata - 1; |
| 139 | |
| 140 | /* |
| 141 | The actual length for these types does not really matter since |
| 142 | they are used to calc_pack_length, which ignores the given |
| 143 | length for these types. |
| 144 | |
| 145 | Since we want this to be accurate for other uses, we return the |
| 146 | maximum size in bytes of these BLOBs. |
| 147 | */ |
| 148 | |
| 149 | case MYSQL_TYPE_TINY_BLOB: |
| 150 | return (uint32)my_set_bits(1 * 8); |
| 151 | |
| 152 | case MYSQL_TYPE_MEDIUM_BLOB: |
| 153 | return (uint32)my_set_bits(3 * 8); |
| 154 | |
| 155 | case MYSQL_TYPE_BLOB: |
| 156 | case MYSQL_TYPE_BLOB_COMPRESSED: |
| 157 | /* |
| 158 | For the blob type, Field::real_type() lies and say that all |
| 159 | blobs are of type MYSQL_TYPE_BLOB. In that case, we have to look |
| 160 | at the length instead to decide what the max display size is. |
| 161 | */ |
| 162 | return (uint32)my_set_bits(metadata * 8); |
| 163 | |
| 164 | case MYSQL_TYPE_LONG_BLOB: |
| 165 | case MYSQL_TYPE_GEOMETRY: |
| 166 | return (uint32)my_set_bits(4 * 8); |
| 167 | |
| 168 | default: |
| 169 | return ~(uint32) 0; |
| 170 | } |
| 171 | } |
| 172 | |
| 173 | |
| 174 | /* |
| 175 | Compare the pack lengths of a source field (on the master) and a |
| 176 | target field (on the slave). |
| 177 | |
| 178 | @param field Target field. |
| 179 | @param type Source field type. |
| 180 | @param metadata Source field metadata. |
| 181 | |
| 182 | @retval -1 The length of the source field is smaller than the target field. |
| 183 | @retval 0 The length of the source and target fields are the same. |
| 184 | @retval 1 The length of the source field is greater than the target field. |
| 185 | */ |
| 186 | int compare_lengths(Field *field, enum_field_types source_type, uint16 metadata) |
| 187 | { |
| 188 | DBUG_ENTER("compare_lengths" ); |
| 189 | size_t const source_length= |
| 190 | max_display_length_for_field(source_type, metadata); |
| 191 | size_t const target_length= field->max_display_length(); |
| 192 | DBUG_PRINT("debug" , ("source_length: %lu, source_type: %u," |
| 193 | " target_length: %lu, target_type: %u" , |
| 194 | (unsigned long) source_length, source_type, |
| 195 | (unsigned long) target_length, field->real_type())); |
| 196 | int result= source_length < target_length ? -1 : source_length > target_length; |
| 197 | DBUG_PRINT("result" , ("%d" , result)); |
| 198 | DBUG_RETURN(result); |
| 199 | } |
| 200 | #endif //MYSQL_CLIENT |
| 201 | /********************************************************************* |
| 202 | * table_def member definitions * |
| 203 | *********************************************************************/ |
| 204 | |
| 205 | /* |
| 206 | This function returns the field size in raw bytes based on the type |
| 207 | and the encoded field data from the master's raw data. |
| 208 | */ |
| 209 | uint32 table_def::calc_field_size(uint col, uchar *master_data) const |
| 210 | { |
| 211 | uint32 length= 0; |
| 212 | |
| 213 | switch (type(col)) { |
| 214 | case MYSQL_TYPE_NEWDECIMAL: |
| 215 | length= my_decimal_get_binary_size(m_field_metadata[col] >> 8, |
| 216 | m_field_metadata[col] & 0xff); |
| 217 | break; |
| 218 | case MYSQL_TYPE_DECIMAL: |
| 219 | case MYSQL_TYPE_FLOAT: |
| 220 | case MYSQL_TYPE_DOUBLE: |
| 221 | length= m_field_metadata[col]; |
| 222 | break; |
| 223 | /* |
| 224 | The cases for SET and ENUM are include for completeness, however |
| 225 | both are mapped to type MYSQL_TYPE_STRING and their real types |
| 226 | are encoded in the field metadata. |
| 227 | */ |
| 228 | case MYSQL_TYPE_SET: |
| 229 | case MYSQL_TYPE_ENUM: |
| 230 | case MYSQL_TYPE_STRING: |
| 231 | { |
| 232 | uchar type= m_field_metadata[col] >> 8U; |
| 233 | if ((type == MYSQL_TYPE_SET) || (type == MYSQL_TYPE_ENUM)) |
| 234 | length= m_field_metadata[col] & 0x00ff; |
| 235 | else |
| 236 | { |
| 237 | /* |
| 238 | We are reading the actual size from the master_data record |
| 239 | because this field has the actual lengh stored in the first |
| 240 | byte. |
| 241 | */ |
| 242 | length= (uint) *master_data + 1; |
| 243 | DBUG_ASSERT(length != 0); |
| 244 | } |
| 245 | break; |
| 246 | } |
| 247 | case MYSQL_TYPE_YEAR: |
| 248 | case MYSQL_TYPE_TINY: |
| 249 | length= 1; |
| 250 | break; |
| 251 | case MYSQL_TYPE_SHORT: |
| 252 | length= 2; |
| 253 | break; |
| 254 | case MYSQL_TYPE_INT24: |
| 255 | length= 3; |
| 256 | break; |
| 257 | case MYSQL_TYPE_LONG: |
| 258 | length= 4; |
| 259 | break; |
| 260 | #ifdef HAVE_LONG_LONG |
| 261 | case MYSQL_TYPE_LONGLONG: |
| 262 | length= 8; |
| 263 | break; |
| 264 | #endif |
| 265 | case MYSQL_TYPE_NULL: |
| 266 | length= 0; |
| 267 | break; |
| 268 | case MYSQL_TYPE_NEWDATE: |
| 269 | length= 3; |
| 270 | break; |
| 271 | case MYSQL_TYPE_DATE: |
| 272 | case MYSQL_TYPE_TIME: |
| 273 | length= 3; |
| 274 | break; |
| 275 | case MYSQL_TYPE_TIME2: |
| 276 | length= my_time_binary_length(m_field_metadata[col]); |
| 277 | break; |
| 278 | case MYSQL_TYPE_TIMESTAMP: |
| 279 | length= 4; |
| 280 | break; |
| 281 | case MYSQL_TYPE_TIMESTAMP2: |
| 282 | length= my_timestamp_binary_length(m_field_metadata[col]); |
| 283 | break; |
| 284 | case MYSQL_TYPE_DATETIME: |
| 285 | length= 8; |
| 286 | break; |
| 287 | case MYSQL_TYPE_DATETIME2: |
| 288 | length= my_datetime_binary_length(m_field_metadata[col]); |
| 289 | break; |
| 290 | case MYSQL_TYPE_BIT: |
| 291 | { |
| 292 | /* |
| 293 | Decode the size of the bit field from the master. |
| 294 | from_len is the length in bytes from the master |
| 295 | from_bit_len is the number of extra bits stored in the master record |
| 296 | If from_bit_len is not 0, add 1 to the length to account for accurate |
| 297 | number of bytes needed. |
| 298 | */ |
| 299 | uint from_len= (m_field_metadata[col] >> 8U) & 0x00ff; |
| 300 | uint from_bit_len= m_field_metadata[col] & 0x00ff; |
| 301 | DBUG_ASSERT(from_bit_len <= 7); |
| 302 | length= from_len + ((from_bit_len > 0) ? 1 : 0); |
| 303 | break; |
| 304 | } |
| 305 | case MYSQL_TYPE_VARCHAR: |
| 306 | case MYSQL_TYPE_VARCHAR_COMPRESSED: |
| 307 | { |
| 308 | length= m_field_metadata[col] > 255 ? 2 : 1; // c&p of Field_varstring::data_length() |
| 309 | length+= length == 1 ? (uint32) *master_data : uint2korr(master_data); |
| 310 | break; |
| 311 | } |
| 312 | case MYSQL_TYPE_TINY_BLOB: |
| 313 | case MYSQL_TYPE_MEDIUM_BLOB: |
| 314 | case MYSQL_TYPE_LONG_BLOB: |
| 315 | case MYSQL_TYPE_BLOB: |
| 316 | case MYSQL_TYPE_BLOB_COMPRESSED: |
| 317 | case MYSQL_TYPE_GEOMETRY: |
| 318 | { |
| 319 | /* |
| 320 | Compute the length of the data. We cannot use get_length() here |
| 321 | since it is dependent on the specific table (and also checks the |
| 322 | packlength using the internal 'table' pointer) and replication |
| 323 | is using a fixed format for storing data in the binlog. |
| 324 | */ |
| 325 | switch (m_field_metadata[col]) { |
| 326 | case 1: |
| 327 | length= *master_data; |
| 328 | break; |
| 329 | case 2: |
| 330 | length= uint2korr(master_data); |
| 331 | break; |
| 332 | case 3: |
| 333 | length= uint3korr(master_data); |
| 334 | break; |
| 335 | case 4: |
| 336 | length= uint4korr(master_data); |
| 337 | break; |
| 338 | default: |
| 339 | DBUG_ASSERT(0); // Should not come here |
| 340 | break; |
| 341 | } |
| 342 | |
| 343 | length+= m_field_metadata[col]; |
| 344 | break; |
| 345 | } |
| 346 | default: |
| 347 | length= ~(uint32) 0; |
| 348 | } |
| 349 | return length; |
| 350 | } |
| 351 | |
| 352 | #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION) |
| 353 | /** |
| 354 | */ |
| 355 | void show_sql_type(enum_field_types type, uint16 metadata, String *str, CHARSET_INFO *field_cs) |
| 356 | { |
| 357 | DBUG_ENTER("show_sql_type" ); |
| 358 | DBUG_PRINT("enter" , ("type: %d, metadata: 0x%x" , type, metadata)); |
| 359 | |
| 360 | switch (type) |
| 361 | { |
| 362 | case MYSQL_TYPE_TINY: |
| 363 | str->set_ascii(STRING_WITH_LEN("tinyint" )); |
| 364 | break; |
| 365 | |
| 366 | case MYSQL_TYPE_SHORT: |
| 367 | str->set_ascii(STRING_WITH_LEN("smallint" )); |
| 368 | break; |
| 369 | |
| 370 | case MYSQL_TYPE_LONG: |
| 371 | str->set_ascii(STRING_WITH_LEN("int" )); |
| 372 | break; |
| 373 | |
| 374 | case MYSQL_TYPE_FLOAT: |
| 375 | str->set_ascii(STRING_WITH_LEN("float" )); |
| 376 | break; |
| 377 | |
| 378 | case MYSQL_TYPE_DOUBLE: |
| 379 | str->set_ascii(STRING_WITH_LEN("double" )); |
| 380 | break; |
| 381 | |
| 382 | case MYSQL_TYPE_NULL: |
| 383 | str->set_ascii(STRING_WITH_LEN("null" )); |
| 384 | break; |
| 385 | |
| 386 | case MYSQL_TYPE_TIMESTAMP: |
| 387 | case MYSQL_TYPE_TIMESTAMP2: |
| 388 | str->set_ascii(STRING_WITH_LEN("timestamp" )); |
| 389 | break; |
| 390 | |
| 391 | case MYSQL_TYPE_LONGLONG: |
| 392 | str->set_ascii(STRING_WITH_LEN("bigint" )); |
| 393 | break; |
| 394 | |
| 395 | case MYSQL_TYPE_INT24: |
| 396 | str->set_ascii(STRING_WITH_LEN("mediumint" )); |
| 397 | break; |
| 398 | |
| 399 | case MYSQL_TYPE_NEWDATE: |
| 400 | case MYSQL_TYPE_DATE: |
| 401 | str->set_ascii(STRING_WITH_LEN("date" )); |
| 402 | break; |
| 403 | |
| 404 | case MYSQL_TYPE_TIME: |
| 405 | case MYSQL_TYPE_TIME2: |
| 406 | str->set_ascii(STRING_WITH_LEN("time" )); |
| 407 | break; |
| 408 | |
| 409 | case MYSQL_TYPE_DATETIME: |
| 410 | case MYSQL_TYPE_DATETIME2: |
| 411 | str->set_ascii(STRING_WITH_LEN("datetime" )); |
| 412 | break; |
| 413 | |
| 414 | case MYSQL_TYPE_YEAR: |
| 415 | str->set_ascii(STRING_WITH_LEN("year" )); |
| 416 | break; |
| 417 | |
| 418 | case MYSQL_TYPE_VAR_STRING: |
| 419 | case MYSQL_TYPE_VARCHAR: |
| 420 | case MYSQL_TYPE_VARCHAR_COMPRESSED: |
| 421 | { |
| 422 | CHARSET_INFO *cs= str->charset(); |
| 423 | size_t length= |
| 424 | cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), |
| 425 | "varchar(%u)%s" , metadata, |
| 426 | type == MYSQL_TYPE_VARCHAR_COMPRESSED ? " compressed" |
| 427 | : "" ); |
| 428 | str->length(length); |
| 429 | } |
| 430 | break; |
| 431 | |
| 432 | case MYSQL_TYPE_BIT: |
| 433 | { |
| 434 | CHARSET_INFO *cs= str->charset(); |
| 435 | int bit_length= 8 * (metadata >> 8) + (metadata & 0xFF); |
| 436 | size_t length= |
| 437 | cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), |
| 438 | "bit(%d)" , bit_length); |
| 439 | str->length(length); |
| 440 | } |
| 441 | break; |
| 442 | |
| 443 | case MYSQL_TYPE_DECIMAL: |
| 444 | { |
| 445 | CHARSET_INFO *cs= str->charset(); |
| 446 | size_t length= |
| 447 | cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), |
| 448 | "decimal(%d,?)/*old*/" , metadata); |
| 449 | str->length(length); |
| 450 | } |
| 451 | break; |
| 452 | |
| 453 | case MYSQL_TYPE_NEWDECIMAL: |
| 454 | { |
| 455 | CHARSET_INFO *cs= str->charset(); |
| 456 | size_t length= |
| 457 | cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), |
| 458 | "decimal(%d,%d)" , metadata >> 8, metadata & 0xff); |
| 459 | str->length(length); |
| 460 | } |
| 461 | break; |
| 462 | |
| 463 | case MYSQL_TYPE_ENUM: |
| 464 | str->set_ascii(STRING_WITH_LEN("enum" )); |
| 465 | break; |
| 466 | |
| 467 | case MYSQL_TYPE_SET: |
| 468 | str->set_ascii(STRING_WITH_LEN("set" )); |
| 469 | break; |
| 470 | |
| 471 | case MYSQL_TYPE_BLOB: |
| 472 | case MYSQL_TYPE_BLOB_COMPRESSED: |
| 473 | /* |
| 474 | Field::real_type() lies regarding the actual type of a BLOB, so |
| 475 | it is necessary to check the pack length to figure out what kind |
| 476 | of blob it really is. |
| 477 | */ |
| 478 | switch (get_blob_type_from_length(metadata)) |
| 479 | { |
| 480 | case MYSQL_TYPE_TINY_BLOB: |
| 481 | str->set_ascii(STRING_WITH_LEN("tinyblob" )); |
| 482 | break; |
| 483 | |
| 484 | case MYSQL_TYPE_MEDIUM_BLOB: |
| 485 | str->set_ascii(STRING_WITH_LEN("mediumblob" )); |
| 486 | break; |
| 487 | |
| 488 | case MYSQL_TYPE_LONG_BLOB: |
| 489 | str->set_ascii(STRING_WITH_LEN("longblob" )); |
| 490 | break; |
| 491 | |
| 492 | case MYSQL_TYPE_BLOB: |
| 493 | str->set_ascii(STRING_WITH_LEN("blob" )); |
| 494 | break; |
| 495 | |
| 496 | default: |
| 497 | DBUG_ASSERT(0); |
| 498 | break; |
| 499 | } |
| 500 | |
| 501 | if (type == MYSQL_TYPE_BLOB_COMPRESSED) |
| 502 | str->append(STRING_WITH_LEN(" compressed" )); |
| 503 | break; |
| 504 | |
| 505 | case MYSQL_TYPE_STRING: |
| 506 | { |
| 507 | /* |
| 508 | This is taken from Field_string::unpack. |
| 509 | */ |
| 510 | CHARSET_INFO *cs= str->charset(); |
| 511 | uint bytes= (((metadata >> 4) & 0x300) ^ 0x300) + (metadata & 0x00ff); |
| 512 | size_t length= |
| 513 | cs->cset->snprintf(cs, (char*) str->ptr(), str->alloced_length(), |
| 514 | "char(%d)" , bytes / field_cs->mbmaxlen); |
| 515 | str->length(length); |
| 516 | } |
| 517 | break; |
| 518 | |
| 519 | case MYSQL_TYPE_GEOMETRY: |
| 520 | str->set_ascii(STRING_WITH_LEN("geometry" )); |
| 521 | break; |
| 522 | |
| 523 | default: |
| 524 | str->set_ascii(STRING_WITH_LEN("<unknown type>" )); |
| 525 | } |
| 526 | DBUG_VOID_RETURN; |
| 527 | } |
| 528 | |
| 529 | |
| 530 | /** |
| 531 | Check the order variable and print errors if the order is not |
| 532 | acceptable according to the current settings. |
| 533 | |
| 534 | @param order The computed order of the conversion needed. |
| 535 | @param rli The relay log info data structure: for error reporting. |
| 536 | */ |
| 537 | bool is_conversion_ok(int order, Relay_log_info *rli) |
| 538 | { |
| 539 | DBUG_ENTER("is_conversion_ok" ); |
| 540 | bool allow_non_lossy, allow_lossy; |
| 541 | |
| 542 | allow_non_lossy = slave_type_conversions_options & |
| 543 | (1ULL << SLAVE_TYPE_CONVERSIONS_ALL_NON_LOSSY); |
| 544 | allow_lossy= slave_type_conversions_options & |
| 545 | (1ULL << SLAVE_TYPE_CONVERSIONS_ALL_LOSSY); |
| 546 | |
| 547 | DBUG_PRINT("enter" , ("order: %d, flags:%s%s" , order, |
| 548 | allow_non_lossy ? " ALL_NON_LOSSY" : "" , |
| 549 | allow_lossy ? " ALL_LOSSY" : "" )); |
| 550 | if (order < 0 && !allow_non_lossy) |
| 551 | { |
| 552 | /* !!! Add error message saying that non-lossy conversions need to be allowed. */ |
| 553 | DBUG_RETURN(false); |
| 554 | } |
| 555 | |
| 556 | if (order > 0 && !allow_lossy) |
| 557 | { |
| 558 | /* !!! Add error message saying that lossy conversions need to be allowed. */ |
| 559 | DBUG_RETURN(false); |
| 560 | } |
| 561 | |
| 562 | DBUG_RETURN(true); |
| 563 | } |
| 564 | |
| 565 | |
| 566 | /** |
| 567 | Can a type potentially be converted to another type? |
| 568 | |
| 569 | This function check if the types are convertible and what |
| 570 | conversion is required. |
| 571 | |
| 572 | If conversion is not possible, and error is printed. |
| 573 | |
| 574 | If conversion is possible: |
| 575 | |
| 576 | - *order will be set to -1 if source type is smaller than target |
| 577 | type and a non-lossy conversion can be required. This includes |
| 578 | the case where the field types are different but types could |
| 579 | actually be converted in either direction. |
| 580 | |
| 581 | - *order will be set to 0 if no conversion is required. |
| 582 | |
| 583 | - *order will be set to 1 if the source type is strictly larger |
| 584 | than the target type and that conversion is potentially lossy. |
| 585 | |
| 586 | @param[in] field Target field |
| 587 | @param[in] type Source field type |
| 588 | @param[in] metadata Source field metadata |
| 589 | @param[in] rli Relay log info (for error reporting) |
| 590 | @param[in] mflags Flags from the table map event |
| 591 | @param[out] order Order between source field and target field |
| 592 | |
| 593 | @return @c true if conversion is possible according to the current |
| 594 | settings, @c false if conversion is not possible according to the |
| 595 | current setting. |
| 596 | */ |
| 597 | static bool |
| 598 | can_convert_field_to(Field *field, |
| 599 | enum_field_types source_type, uint16 metadata, |
| 600 | Relay_log_info *rli, uint16 mflags, |
| 601 | int *order_var) |
| 602 | { |
| 603 | DBUG_ENTER("can_convert_field_to" ); |
| 604 | bool same_type; |
| 605 | #ifndef DBUG_OFF |
| 606 | char field_type_buf[MAX_FIELD_WIDTH]; |
| 607 | String field_type(field_type_buf, sizeof(field_type_buf), &my_charset_latin1); |
| 608 | field->sql_type(field_type); |
| 609 | DBUG_PRINT("enter" , ("field_type: %s, target_type: %d, source_type: %d, source_metadata: 0x%x" , |
| 610 | field_type.c_ptr_safe(), field->real_type(), source_type, metadata)); |
| 611 | #endif |
| 612 | /** |
| 613 | @todo |
| 614 | Implement Field_varstring_cmopressed::real_type() and |
| 615 | Field_blob_compressed::real_type() properly. All occurencies |
| 616 | of Field::real_type() have to be inspected and adjusted if needed. |
| 617 | |
| 618 | Until it is not ready we have to compare source_type against |
| 619 | binlog_type() when replicating from or to compressed data types. |
| 620 | |
| 621 | @sa Comment for Field::binlog_type() |
| 622 | */ |
| 623 | if (source_type == MYSQL_TYPE_VARCHAR_COMPRESSED || |
| 624 | source_type == MYSQL_TYPE_BLOB_COMPRESSED || |
| 625 | field->binlog_type() == MYSQL_TYPE_VARCHAR_COMPRESSED || |
| 626 | field->binlog_type() == MYSQL_TYPE_BLOB_COMPRESSED) |
| 627 | same_type= field->binlog_type() == source_type; |
| 628 | else |
| 629 | same_type= field->real_type() == source_type; |
| 630 | |
| 631 | /* |
| 632 | If the real type is the same, we need to check the metadata to |
| 633 | decide if conversions are allowed. |
| 634 | */ |
| 635 | if (same_type) |
| 636 | { |
| 637 | if (metadata == 0) // Metadata can only be zero if no metadata was provided |
| 638 | { |
| 639 | /* |
| 640 | If there is no metadata, we either have an old event where no |
| 641 | metadata were supplied, or a type that does not require any |
| 642 | metadata. In either case, conversion can be done but no |
| 643 | conversion table is necessary. |
| 644 | */ |
| 645 | DBUG_PRINT("debug" , ("Base types are identical, but there is no metadata" )); |
| 646 | *order_var= 0; |
| 647 | DBUG_RETURN(true); |
| 648 | } |
| 649 | |
| 650 | DBUG_PRINT("debug" , ("Base types are identical, doing field size comparison" )); |
| 651 | if (field->compatible_field_size(metadata, rli, mflags, order_var)) |
| 652 | DBUG_RETURN(is_conversion_ok(*order_var, rli)); |
| 653 | else |
| 654 | DBUG_RETURN(false); |
| 655 | } |
| 656 | else if ( |
| 657 | /* |
| 658 | Conversion from MariaDB TIMESTAMP(0), TIME(0), DATETIME(0) |
| 659 | to the corresponding MySQL56 types is non-lossy. |
| 660 | */ |
| 661 | (metadata == 0 && |
| 662 | ((field->real_type() == MYSQL_TYPE_TIMESTAMP2 && |
| 663 | source_type == MYSQL_TYPE_TIMESTAMP) || |
| 664 | (field->real_type() == MYSQL_TYPE_TIME2 && |
| 665 | source_type == MYSQL_TYPE_TIME) || |
| 666 | (field->real_type() == MYSQL_TYPE_DATETIME2 && |
| 667 | source_type == MYSQL_TYPE_DATETIME))) || |
| 668 | /* |
| 669 | Conversion from MySQL56 TIMESTAMP(N), TIME(N), DATETIME(N) |
| 670 | to the corresponding MariaDB or MySQL55 types is non-lossy. |
| 671 | */ |
| 672 | (metadata == field->decimals() && |
| 673 | ((field->real_type() == MYSQL_TYPE_TIMESTAMP && |
| 674 | source_type == MYSQL_TYPE_TIMESTAMP2) || |
| 675 | (field->real_type() == MYSQL_TYPE_TIME && |
| 676 | source_type == MYSQL_TYPE_TIME2) || |
| 677 | (field->real_type() == MYSQL_TYPE_DATETIME && |
| 678 | source_type == MYSQL_TYPE_DATETIME2)))) |
| 679 | { |
| 680 | /* |
| 681 | TS-TODO: conversion from FSP1>FSP2. |
| 682 | */ |
| 683 | *order_var= -1; |
| 684 | DBUG_RETURN(true); |
| 685 | } |
| 686 | else if (!slave_type_conversions_options) |
| 687 | DBUG_RETURN(false); |
| 688 | |
| 689 | /* |
| 690 | Here, from and to will always be different. Since the types are |
| 691 | different, we cannot use the compatible_field_size() function, but |
| 692 | have to rely on hard-coded max-sizes for fields. |
| 693 | */ |
| 694 | |
| 695 | DBUG_PRINT("debug" , ("Base types are different, checking conversion" )); |
| 696 | switch (source_type) // Source type (on master) |
| 697 | { |
| 698 | case MYSQL_TYPE_DECIMAL: |
| 699 | case MYSQL_TYPE_NEWDECIMAL: |
| 700 | case MYSQL_TYPE_FLOAT: |
| 701 | case MYSQL_TYPE_DOUBLE: |
| 702 | switch (field->real_type()) |
| 703 | { |
| 704 | case MYSQL_TYPE_NEWDECIMAL: |
| 705 | /* |
| 706 | Then the other type is either FLOAT, DOUBLE, or old style |
| 707 | DECIMAL, so we require lossy conversion. |
| 708 | */ |
| 709 | *order_var= 1; |
| 710 | DBUG_RETURN(is_conversion_ok(*order_var, rli)); |
| 711 | |
| 712 | case MYSQL_TYPE_DECIMAL: |
| 713 | case MYSQL_TYPE_FLOAT: |
| 714 | case MYSQL_TYPE_DOUBLE: |
| 715 | { |
| 716 | if (source_type == MYSQL_TYPE_NEWDECIMAL || |
| 717 | source_type == MYSQL_TYPE_DECIMAL) |
| 718 | *order_var = 1; // Always require lossy conversions |
| 719 | else |
| 720 | *order_var= compare_lengths(field, source_type, metadata); |
| 721 | DBUG_ASSERT(*order_var != 0); |
| 722 | DBUG_RETURN(is_conversion_ok(*order_var, rli)); |
| 723 | } |
| 724 | |
| 725 | default: |
| 726 | DBUG_RETURN(false); |
| 727 | } |
| 728 | break; |
| 729 | |
| 730 | /* |
| 731 | The length comparison check will do the correct job of comparing |
| 732 | the field lengths (in bytes) of two integer types. |
| 733 | */ |
| 734 | case MYSQL_TYPE_TINY: |
| 735 | case MYSQL_TYPE_SHORT: |
| 736 | case MYSQL_TYPE_INT24: |
| 737 | case MYSQL_TYPE_LONG: |
| 738 | case MYSQL_TYPE_LONGLONG: |
| 739 | switch (field->real_type()) |
| 740 | { |
| 741 | case MYSQL_TYPE_TINY: |
| 742 | case MYSQL_TYPE_SHORT: |
| 743 | case MYSQL_TYPE_INT24: |
| 744 | case MYSQL_TYPE_LONG: |
| 745 | case MYSQL_TYPE_LONGLONG: |
| 746 | /* |
| 747 | max_display_length_for_field() is not fully precise for the integer |
| 748 | data types. So its result cannot be compared to the result of |
| 749 | field->max_dispay_length() when the table field and the binlog field |
| 750 | are of the same type. |
| 751 | This code should eventually be rewritten not to use |
| 752 | compare_lengths(), to detect subtype/supetype relations |
| 753 | just using the type codes. |
| 754 | */ |
| 755 | DBUG_ASSERT(source_type != field->real_type()); |
| 756 | *order_var= compare_lengths(field, source_type, metadata); |
| 757 | DBUG_ASSERT(*order_var != 0); |
| 758 | DBUG_RETURN(is_conversion_ok(*order_var, rli)); |
| 759 | |
| 760 | default: |
| 761 | DBUG_RETURN(false); |
| 762 | } |
| 763 | break; |
| 764 | |
| 765 | /* |
| 766 | Since source and target type is different, and it is not possible |
| 767 | to convert bit types to anything else, this will return false. |
| 768 | */ |
| 769 | case MYSQL_TYPE_BIT: |
| 770 | DBUG_RETURN(false); |
| 771 | |
| 772 | /* |
| 773 | If all conversions are disabled, it is not allowed to convert |
| 774 | between these types. Since the TEXT vs. BINARY is distinguished by |
| 775 | the charset, and the charset is not replicated, we cannot |
| 776 | currently distinguish between , e.g., TEXT and BLOB. |
| 777 | */ |
| 778 | case MYSQL_TYPE_TINY_BLOB: |
| 779 | case MYSQL_TYPE_MEDIUM_BLOB: |
| 780 | case MYSQL_TYPE_LONG_BLOB: |
| 781 | case MYSQL_TYPE_BLOB: |
| 782 | case MYSQL_TYPE_BLOB_COMPRESSED: |
| 783 | case MYSQL_TYPE_STRING: |
| 784 | case MYSQL_TYPE_VAR_STRING: |
| 785 | case MYSQL_TYPE_VARCHAR: |
| 786 | case MYSQL_TYPE_VARCHAR_COMPRESSED: |
| 787 | switch (field->real_type()) |
| 788 | { |
| 789 | case MYSQL_TYPE_TINY_BLOB: |
| 790 | case MYSQL_TYPE_MEDIUM_BLOB: |
| 791 | case MYSQL_TYPE_LONG_BLOB: |
| 792 | case MYSQL_TYPE_BLOB: |
| 793 | case MYSQL_TYPE_BLOB_COMPRESSED: |
| 794 | case MYSQL_TYPE_STRING: |
| 795 | case MYSQL_TYPE_VAR_STRING: |
| 796 | case MYSQL_TYPE_VARCHAR: |
| 797 | case MYSQL_TYPE_VARCHAR_COMPRESSED: |
| 798 | *order_var= compare_lengths(field, source_type, metadata); |
| 799 | /* |
| 800 | Here we know that the types are different, so if the order |
| 801 | gives that they do not require any conversion, we still need |
| 802 | to have non-lossy conversion enabled to allow conversion |
| 803 | between different (string) types of the same length. |
| 804 | */ |
| 805 | if (*order_var == 0) |
| 806 | *order_var= -1; |
| 807 | DBUG_RETURN(is_conversion_ok(*order_var, rli)); |
| 808 | |
| 809 | default: |
| 810 | DBUG_RETURN(false); |
| 811 | } |
| 812 | break; |
| 813 | |
| 814 | case MYSQL_TYPE_GEOMETRY: |
| 815 | case MYSQL_TYPE_TIMESTAMP: |
| 816 | case MYSQL_TYPE_DATE: |
| 817 | case MYSQL_TYPE_TIME: |
| 818 | case MYSQL_TYPE_DATETIME: |
| 819 | case MYSQL_TYPE_YEAR: |
| 820 | case MYSQL_TYPE_NEWDATE: |
| 821 | case MYSQL_TYPE_NULL: |
| 822 | case MYSQL_TYPE_ENUM: |
| 823 | case MYSQL_TYPE_SET: |
| 824 | case MYSQL_TYPE_TIMESTAMP2: |
| 825 | case MYSQL_TYPE_DATETIME2: |
| 826 | case MYSQL_TYPE_TIME2: |
| 827 | DBUG_RETURN(false); |
| 828 | } |
| 829 | DBUG_RETURN(false); // To keep GCC happy |
| 830 | } |
| 831 | |
| 832 | |
| 833 | /** |
| 834 | Is the definition compatible with a table? |
| 835 | |
| 836 | This function will compare the master table with an existing table |
| 837 | on the slave and see if they are compatible with respect to the |
| 838 | current settings of @c SLAVE_TYPE_CONVERSIONS. |
| 839 | |
| 840 | If the tables are compatible and conversions are required, @c |
| 841 | *tmp_table_var will be set to a virtual temporary table with field |
| 842 | pointers for the fields that require conversions. This allow simple |
| 843 | checking of whether a conversion are to be applied or not. |
| 844 | |
| 845 | If tables are compatible, but no conversions are necessary, @c |
| 846 | *tmp_table_var will be set to NULL. |
| 847 | |
| 848 | @param rli_arg[in] |
| 849 | Relay log info, for error reporting. |
| 850 | |
| 851 | @param table[in] |
| 852 | Table to compare with |
| 853 | |
| 854 | @param tmp_table_var[out] |
| 855 | Virtual temporary table for performing conversions, if necessary. |
| 856 | |
| 857 | @retval true Master table is compatible with slave table. |
| 858 | @retval false Master table is not compatible with slave table. |
| 859 | */ |
| 860 | bool |
| 861 | table_def::compatible_with(THD *thd, rpl_group_info *rgi, |
| 862 | TABLE *table, TABLE **conv_table_var) |
| 863 | const |
| 864 | { |
| 865 | /* |
| 866 | We only check the initial columns for the tables. |
| 867 | */ |
| 868 | uint const cols_to_check= MY_MIN(table->s->fields, size()); |
| 869 | Relay_log_info *rli= rgi->rli; |
| 870 | TABLE *tmp_table= NULL; |
| 871 | |
| 872 | for (uint col= 0 ; col < cols_to_check ; ++col) |
| 873 | { |
| 874 | Field *const field= table->field[col]; |
| 875 | int order; |
| 876 | if (can_convert_field_to(field, type(col), field_metadata(col), rli, m_flags, &order)) |
| 877 | { |
| 878 | DBUG_PRINT("debug" , ("Checking column %d -" |
| 879 | " field '%s' can be converted - order: %d" , |
| 880 | col, field->field_name.str, order)); |
| 881 | DBUG_ASSERT(order >= -1 && order <= 1); |
| 882 | |
| 883 | /* |
| 884 | If order is not 0, a conversion is required, so we need to set |
| 885 | up the conversion table. |
| 886 | */ |
| 887 | if (order != 0 && tmp_table == NULL) |
| 888 | { |
| 889 | /* |
| 890 | This will create the full table with all fields. This is |
| 891 | necessary to ge the correct field lengths for the record. |
| 892 | */ |
| 893 | tmp_table= create_conversion_table(thd, rgi, table); |
| 894 | if (tmp_table == NULL) |
| 895 | return false; |
| 896 | /* |
| 897 | Clear all fields up to, but not including, this column. |
| 898 | */ |
| 899 | for (unsigned int i= 0; i < col; ++i) |
| 900 | tmp_table->field[i]= NULL; |
| 901 | } |
| 902 | |
| 903 | if (order == 0 && tmp_table != NULL) |
| 904 | tmp_table->field[col]= NULL; |
| 905 | } |
| 906 | else |
| 907 | { |
| 908 | DBUG_PRINT("debug" , ("Checking column %d -" |
| 909 | " field '%s' can not be converted" , |
| 910 | col, field->field_name.str)); |
| 911 | DBUG_ASSERT(col < size() && col < table->s->fields); |
| 912 | DBUG_ASSERT(table->s->db.str && table->s->table_name.str); |
| 913 | DBUG_ASSERT(table->in_use); |
| 914 | const char *db_name= table->s->db.str; |
| 915 | const char *tbl_name= table->s->table_name.str; |
| 916 | char source_buf[MAX_FIELD_WIDTH]; |
| 917 | char target_buf[MAX_FIELD_WIDTH]; |
| 918 | String source_type(source_buf, sizeof(source_buf), &my_charset_latin1); |
| 919 | String target_type(target_buf, sizeof(target_buf), &my_charset_latin1); |
| 920 | THD *thd= table->in_use; |
| 921 | |
| 922 | show_sql_type(type(col), field_metadata(col), &source_type, field->charset()); |
| 923 | field->sql_type(target_type); |
| 924 | rli->report(ERROR_LEVEL, ER_SLAVE_CONVERSION_FAILED, rgi->gtid_info(), |
| 925 | ER_THD(thd, ER_SLAVE_CONVERSION_FAILED), |
| 926 | col, db_name, tbl_name, |
| 927 | source_type.c_ptr_safe(), target_type.c_ptr_safe()); |
| 928 | return false; |
| 929 | } |
| 930 | } |
| 931 | |
| 932 | #ifndef DBUG_OFF |
| 933 | if (tmp_table) |
| 934 | { |
| 935 | for (unsigned int col= 0; col < tmp_table->s->fields; ++col) |
| 936 | if (tmp_table->field[col]) |
| 937 | { |
| 938 | char source_buf[MAX_FIELD_WIDTH]; |
| 939 | char target_buf[MAX_FIELD_WIDTH]; |
| 940 | String source_type(source_buf, sizeof(source_buf), &my_charset_latin1); |
| 941 | String target_type(target_buf, sizeof(target_buf), &my_charset_latin1); |
| 942 | tmp_table->field[col]->sql_type(source_type); |
| 943 | table->field[col]->sql_type(target_type); |
| 944 | DBUG_PRINT("debug" , ("Field %s - conversion required." |
| 945 | " Source type: '%s', Target type: '%s'" , |
| 946 | tmp_table->field[col]->field_name.str, |
| 947 | source_type.c_ptr_safe(), target_type.c_ptr_safe())); |
| 948 | } |
| 949 | } |
| 950 | #endif |
| 951 | |
| 952 | *conv_table_var= tmp_table; |
| 953 | return true; |
| 954 | } |
| 955 | |
| 956 | |
| 957 | /** |
| 958 | A wrapper to Virtual_tmp_table, to get access to its constructor, |
| 959 | which is protected for safety purposes (against illegal use on stack). |
| 960 | */ |
| 961 | class Virtual_conversion_table: public Virtual_tmp_table |
| 962 | { |
| 963 | public: |
| 964 | Virtual_conversion_table(THD *thd) :Virtual_tmp_table(thd) { } |
| 965 | /** |
| 966 | Add a new field into the virtual table. |
| 967 | @param sql_type - The real_type of the field. |
| 968 | @param metadata - The RBR binary log metadata for this field. |
| 969 | @param target_field - The field from the target table, to get extra |
| 970 | attributes from (e.g. typelib in case of ENUM). |
| 971 | */ |
| 972 | bool add(enum_field_types sql_type, |
| 973 | uint16 metadata, const Field *target_field) |
| 974 | { |
| 975 | const Type_handler *handler= Type_handler::get_handler_by_real_type(sql_type); |
| 976 | if (!handler) |
| 977 | { |
| 978 | sql_print_error("In RBR mode, Slave received unknown field type field %d " |
| 979 | " for column Name: %s.%s.%s." , |
| 980 | (int) sql_type, |
| 981 | target_field->table->s->db.str, |
| 982 | target_field->table->s->table_name.str, |
| 983 | target_field->field_name.str); |
| 984 | return true; |
| 985 | } |
| 986 | Field *tmp= handler->make_conversion_table_field(this, metadata, |
| 987 | target_field); |
| 988 | if (!tmp) |
| 989 | return true; |
| 990 | Virtual_tmp_table::add(tmp); |
| 991 | DBUG_PRINT("debug" , ("sql_type: %d, target_field: '%s', max_length: %d, decimals: %d," |
| 992 | " maybe_null: %d, unsigned_flag: %d, pack_length: %u" , |
| 993 | sql_type, target_field->field_name.str, |
| 994 | tmp->field_length, tmp->decimals(), TRUE, |
| 995 | tmp->flags, tmp->pack_length())); |
| 996 | return false; |
| 997 | } |
| 998 | }; |
| 999 | |
| 1000 | |
| 1001 | /** |
| 1002 | Create a conversion table. |
| 1003 | |
| 1004 | If the function is unable to create the conversion table, an error |
| 1005 | will be printed and NULL will be returned. |
| 1006 | |
| 1007 | @return Pointer to conversion table, or NULL if unable to create |
| 1008 | conversion table. |
| 1009 | */ |
| 1010 | |
| 1011 | TABLE *table_def::create_conversion_table(THD *thd, rpl_group_info *rgi, |
| 1012 | TABLE *target_table) const |
| 1013 | { |
| 1014 | DBUG_ENTER("table_def::create_conversion_table" ); |
| 1015 | |
| 1016 | Virtual_conversion_table *conv_table; |
| 1017 | Relay_log_info *rli= rgi->rli; |
| 1018 | /* |
| 1019 | At slave, columns may differ. So we should create |
| 1020 | MY_MIN(columns@master, columns@slave) columns in the |
| 1021 | conversion table. |
| 1022 | */ |
| 1023 | uint const cols_to_create= MY_MIN(target_table->s->fields, size()); |
| 1024 | if (!(conv_table= new(thd) Virtual_conversion_table(thd)) || |
| 1025 | conv_table->init(cols_to_create)) |
| 1026 | goto err; |
| 1027 | for (uint col= 0 ; col < cols_to_create; ++col) |
| 1028 | { |
| 1029 | if (conv_table->add(type(col), field_metadata(col), |
| 1030 | target_table->field[col])) |
| 1031 | { |
| 1032 | DBUG_PRINT("debug" , ("binlog_type: %d, metadata: %04X, target_field: '%s'" |
| 1033 | " make_conversion_table_field() failed" , |
| 1034 | binlog_type(col), field_metadata(col), |
| 1035 | target_table->field[col]->field_name.str)); |
| 1036 | goto err; |
| 1037 | } |
| 1038 | } |
| 1039 | |
| 1040 | if (conv_table->open()) |
| 1041 | goto err; // Could not allocate record buffer? |
| 1042 | |
| 1043 | DBUG_RETURN(conv_table); |
| 1044 | |
| 1045 | err: |
| 1046 | if (conv_table) |
| 1047 | delete conv_table; |
| 1048 | rli->report(ERROR_LEVEL, ER_SLAVE_CANT_CREATE_CONVERSION, rgi->gtid_info(), |
| 1049 | ER_THD(thd, ER_SLAVE_CANT_CREATE_CONVERSION), |
| 1050 | target_table->s->db.str, |
| 1051 | target_table->s->table_name.str); |
| 1052 | DBUG_RETURN(NULL); |
| 1053 | } |
| 1054 | #endif /* MYSQL_CLIENT */ |
| 1055 | |
| 1056 | table_def::table_def(unsigned char *types, ulong size, |
| 1057 | uchar *field_metadata, int metadata_size, |
| 1058 | uchar *null_bitmap, uint16 flags) |
| 1059 | : m_size(size), m_type(0), m_field_metadata_size(metadata_size), |
| 1060 | m_field_metadata(0), m_null_bits(0), m_flags(flags), |
| 1061 | m_memory(NULL) |
| 1062 | { |
| 1063 | m_memory= (uchar *)my_multi_malloc(MYF(MY_WME), |
| 1064 | &m_type, size, |
| 1065 | &m_field_metadata, |
| 1066 | size * sizeof(uint16), |
| 1067 | &m_null_bits, (size + 7) / 8, |
| 1068 | NULL); |
| 1069 | |
| 1070 | bzero(m_field_metadata, size * sizeof(uint16)); |
| 1071 | |
| 1072 | if (m_type) |
| 1073 | memcpy(m_type, types, size); |
| 1074 | else |
| 1075 | m_size= 0; |
| 1076 | /* |
| 1077 | Extract the data from the table map into the field metadata array |
| 1078 | iff there is field metadata. The variable metadata_size will be |
| 1079 | 0 if we are replicating from an older version server since no field |
| 1080 | metadata was written to the table map. This can also happen if |
| 1081 | there were no fields in the master that needed extra metadata. |
| 1082 | */ |
| 1083 | if (m_size && metadata_size) |
| 1084 | { |
| 1085 | int index= 0; |
| 1086 | for (unsigned int i= 0; i < m_size; i++) |
| 1087 | { |
| 1088 | switch (binlog_type(i)) { |
| 1089 | case MYSQL_TYPE_TINY_BLOB: |
| 1090 | case MYSQL_TYPE_BLOB: |
| 1091 | case MYSQL_TYPE_BLOB_COMPRESSED: |
| 1092 | case MYSQL_TYPE_MEDIUM_BLOB: |
| 1093 | case MYSQL_TYPE_LONG_BLOB: |
| 1094 | case MYSQL_TYPE_DOUBLE: |
| 1095 | case MYSQL_TYPE_FLOAT: |
| 1096 | case MYSQL_TYPE_GEOMETRY: |
| 1097 | { |
| 1098 | /* |
| 1099 | These types store a single byte. |
| 1100 | */ |
| 1101 | m_field_metadata[i]= field_metadata[index]; |
| 1102 | index++; |
| 1103 | break; |
| 1104 | } |
| 1105 | case MYSQL_TYPE_SET: |
| 1106 | case MYSQL_TYPE_ENUM: |
| 1107 | case MYSQL_TYPE_STRING: |
| 1108 | { |
| 1109 | uint16 x= field_metadata[index++] << 8U; // real_type |
| 1110 | x+= field_metadata[index++]; // pack or field length |
| 1111 | m_field_metadata[i]= x; |
| 1112 | break; |
| 1113 | } |
| 1114 | case MYSQL_TYPE_BIT: |
| 1115 | { |
| 1116 | uint16 x= field_metadata[index++]; |
| 1117 | x = x + (field_metadata[index++] << 8U); |
| 1118 | m_field_metadata[i]= x; |
| 1119 | break; |
| 1120 | } |
| 1121 | case MYSQL_TYPE_VARCHAR: |
| 1122 | case MYSQL_TYPE_VARCHAR_COMPRESSED: |
| 1123 | { |
| 1124 | /* |
| 1125 | These types store two bytes. |
| 1126 | */ |
| 1127 | char *ptr= (char *)&field_metadata[index]; |
| 1128 | m_field_metadata[i]= uint2korr(ptr); |
| 1129 | index= index + 2; |
| 1130 | break; |
| 1131 | } |
| 1132 | case MYSQL_TYPE_NEWDECIMAL: |
| 1133 | { |
| 1134 | uint16 x= field_metadata[index++] << 8U; // precision |
| 1135 | x+= field_metadata[index++]; // decimals |
| 1136 | m_field_metadata[i]= x; |
| 1137 | break; |
| 1138 | } |
| 1139 | case MYSQL_TYPE_TIME2: |
| 1140 | case MYSQL_TYPE_DATETIME2: |
| 1141 | case MYSQL_TYPE_TIMESTAMP2: |
| 1142 | m_field_metadata[i]= field_metadata[index++]; |
| 1143 | break; |
| 1144 | default: |
| 1145 | m_field_metadata[i]= 0; |
| 1146 | break; |
| 1147 | } |
| 1148 | } |
| 1149 | } |
| 1150 | if (m_size && null_bitmap) |
| 1151 | memcpy(m_null_bits, null_bitmap, (m_size + 7) / 8); |
| 1152 | } |
| 1153 | |
| 1154 | |
| 1155 | table_def::~table_def() |
| 1156 | { |
| 1157 | my_free(m_memory); |
| 1158 | #ifndef DBUG_OFF |
| 1159 | m_type= 0; |
| 1160 | m_size= 0; |
| 1161 | #endif |
| 1162 | } |
| 1163 | |
| 1164 | |
| 1165 | /** |
| 1166 | @param even_buf point to the buffer containing serialized event |
| 1167 | @param event_len length of the event accounting possible checksum alg |
| 1168 | |
| 1169 | @return TRUE if test fails |
| 1170 | FALSE as success |
| 1171 | */ |
| 1172 | bool event_checksum_test(uchar *event_buf, ulong event_len, enum enum_binlog_checksum_alg alg) |
| 1173 | { |
| 1174 | bool res= FALSE; |
| 1175 | uint16 flags= 0; // to store in FD's buffer flags orig value |
| 1176 | |
| 1177 | if (alg != BINLOG_CHECKSUM_ALG_OFF && alg != BINLOG_CHECKSUM_ALG_UNDEF) |
| 1178 | { |
| 1179 | ha_checksum incoming; |
| 1180 | ha_checksum computed; |
| 1181 | |
| 1182 | if (event_buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT) |
| 1183 | { |
| 1184 | #ifdef DBUG_ASSERT_EXISTS |
| 1185 | int8 fd_alg= event_buf[event_len - BINLOG_CHECKSUM_LEN - |
| 1186 | BINLOG_CHECKSUM_ALG_DESC_LEN]; |
| 1187 | #endif |
| 1188 | /* |
| 1189 | FD event is checksummed and therefore verified w/o the binlog-in-use flag |
| 1190 | */ |
| 1191 | flags= uint2korr(event_buf + FLAGS_OFFSET); |
| 1192 | if (flags & LOG_EVENT_BINLOG_IN_USE_F) |
| 1193 | event_buf[FLAGS_OFFSET] &= ~LOG_EVENT_BINLOG_IN_USE_F; |
| 1194 | /* |
| 1195 | The only algorithm currently is CRC32. Zero indicates |
| 1196 | the binlog file is checksum-free *except* the FD-event. |
| 1197 | */ |
| 1198 | DBUG_ASSERT(fd_alg == BINLOG_CHECKSUM_ALG_CRC32 || fd_alg == 0); |
| 1199 | DBUG_ASSERT(alg == BINLOG_CHECKSUM_ALG_CRC32); |
| 1200 | /* |
| 1201 | Complile time guard to watch over the max number of alg |
| 1202 | */ |
| 1203 | compile_time_assert(BINLOG_CHECKSUM_ALG_ENUM_END <= 0x80); |
| 1204 | } |
| 1205 | incoming= uint4korr(event_buf + event_len - BINLOG_CHECKSUM_LEN); |
| 1206 | /* checksum the event content without the checksum part itself */ |
| 1207 | computed= my_checksum(0, event_buf, event_len - BINLOG_CHECKSUM_LEN); |
| 1208 | if (flags != 0) |
| 1209 | { |
| 1210 | /* restoring the orig value of flags of FD */ |
| 1211 | DBUG_ASSERT(event_buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT); |
| 1212 | event_buf[FLAGS_OFFSET]= (uchar) flags; |
| 1213 | } |
| 1214 | res= DBUG_EVALUATE_IF("simulate_checksum_test_failure" , TRUE, computed != incoming); |
| 1215 | } |
| 1216 | return res; |
| 1217 | } |
| 1218 | |
| 1219 | #if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION) |
| 1220 | |
| 1221 | Deferred_log_events::Deferred_log_events(Relay_log_info *rli) : last_added(NULL) |
| 1222 | { |
| 1223 | my_init_dynamic_array(&array, sizeof(Log_event *), 32, 16, MYF(0)); |
| 1224 | } |
| 1225 | |
| 1226 | Deferred_log_events::~Deferred_log_events() |
| 1227 | { |
| 1228 | delete_dynamic(&array); |
| 1229 | } |
| 1230 | |
| 1231 | int Deferred_log_events::add(Log_event *ev) |
| 1232 | { |
| 1233 | last_added= ev; |
| 1234 | insert_dynamic(&array, (uchar*) &ev); |
| 1235 | return 0; |
| 1236 | } |
| 1237 | |
| 1238 | bool Deferred_log_events::is_empty() |
| 1239 | { |
| 1240 | return array.elements == 0; |
| 1241 | } |
| 1242 | |
| 1243 | bool Deferred_log_events::execute(rpl_group_info *rgi) |
| 1244 | { |
| 1245 | bool res= false; |
| 1246 | DBUG_ENTER("Deferred_log_events::execute" ); |
| 1247 | DBUG_ASSERT(rgi->deferred_events_collecting); |
| 1248 | |
| 1249 | rgi->deferred_events_collecting= false; |
| 1250 | for (uint i= 0; !res && i < array.elements; i++) |
| 1251 | { |
| 1252 | Log_event *ev= (* (Log_event **) |
| 1253 | dynamic_array_ptr(&array, i)); |
| 1254 | res= ev->apply_event(rgi); |
| 1255 | } |
| 1256 | rgi->deferred_events_collecting= true; |
| 1257 | DBUG_RETURN(res); |
| 1258 | } |
| 1259 | |
| 1260 | void Deferred_log_events::rewind() |
| 1261 | { |
| 1262 | /* |
| 1263 | Reset preceding Query log event events which execution was |
| 1264 | deferred because of slave side filtering. |
| 1265 | */ |
| 1266 | if (!is_empty()) |
| 1267 | { |
| 1268 | for (uint i= 0; i < array.elements; i++) |
| 1269 | { |
| 1270 | Log_event *ev= *(Log_event **) dynamic_array_ptr(&array, i); |
| 1271 | delete ev; |
| 1272 | } |
| 1273 | last_added= NULL; |
| 1274 | if (array.elements > array.max_element) |
| 1275 | freeze_size(&array); |
| 1276 | reset_dynamic(&array); |
| 1277 | } |
| 1278 | last_added= NULL; |
| 1279 | } |
| 1280 | |
| 1281 | #endif |
| 1282 | |