mirror of
https://github.com/MariaDB/server.git
synced 2025-09-09 18:40:27 +03:00
MDEV-20477 Merge binlog extended metadata support from the upstream
Cherry-pick the commits the mysql and some changes. WL#4618 RBR: extended table metadata in the binary log This patch extends Table Map Event. It appends some new fields for more metadata. The new metadata includes: - Signedness of Numberic Columns - Character Set of Character Columns and Binary Columns - Column Name - String Value of SET Columns - String Value of ENUM Columns - Primary Key - Character Set of SET Columns and ENUM Columns - Geometry Type Some of them are optional, the patch introduces a GLOBAL system variable to control it. It is binlog_row_metadata. - Scope: GLOBAL - Dynamic: Yes - Type: ENUM - Values: {NO_LOG, MINIMAL, FULL} - Default: NO_LOG Only Signedness, character set and geometry type are logged if it is MINIMAL. Otherwise all of them are logged. Also add a binlog_type_info() to field, So that we can have extract relevant binlog info from field.
This commit is contained in:
@@ -102,6 +102,7 @@ enum options_client
|
||||
OPT_PRINT_ROW_COUNT, OPT_PRINT_ROW_EVENT_POSITIONS,
|
||||
OPT_SHUTDOWN_WAIT_FOR_SLAVES,
|
||||
OPT_COPY_S3_TABLES,
|
||||
OPT_PRINT_TABLE_METADATA,
|
||||
OPT_MAX_CLIENT_OPTION /* should be always the last */
|
||||
};
|
||||
|
||||
|
@@ -144,6 +144,7 @@ static const char* dirname_for_local_load= 0;
|
||||
static bool opt_skip_annotate_row_events= 0;
|
||||
|
||||
static my_bool opt_flashback;
|
||||
static bool opt_print_table_metadata;
|
||||
#ifdef WHEN_FLASHBACK_REVIEW_READY
|
||||
static my_bool opt_flashback_review;
|
||||
static char *flashback_review_dbname, *flashback_review_tablename;
|
||||
@@ -1095,6 +1096,7 @@ Exit_status process_event(PRINT_EVENT_INFO *print_event_info, Log_event *ev,
|
||||
print_event_info->hexdump_from= pos;
|
||||
|
||||
print_event_info->base64_output_mode= opt_base64_output_mode;
|
||||
print_event_info->print_table_metadata= opt_print_table_metadata;
|
||||
|
||||
DBUG_PRINT("debug", ("event_type: %s", ev->get_type_str()));
|
||||
|
||||
@@ -1788,6 +1790,10 @@ Example: rewrite-db='from->to'.",
|
||||
(uchar**) &opt_skip_annotate_row_events,
|
||||
(uchar**) &opt_skip_annotate_row_events,
|
||||
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"print-table-metadata", OPT_PRINT_TABLE_METADATA,
|
||||
"Print metadata stored in Table_map_log_event",
|
||||
&opt_print_table_metadata, &opt_print_table_metadata, 0,
|
||||
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
|
||||
};
|
||||
|
||||
|
@@ -9,6 +9,9 @@
|
||||
#
|
||||
# The environment variables SEARCH_FILE and SEARCH_PATTERN must be set
|
||||
# before sourcing this routine.
|
||||
# SEARCH_TYPE can also be set to either NULL(default) or _gm_
|
||||
# NULL is equivalent of using m/SEARCH_PATTERN/gs
|
||||
# _gm_ is equivalent of using m/SEARCH_RANGE/gm
|
||||
#
|
||||
# Optionally, SEARCH_RANGE can be set to the max number of bytes of the file
|
||||
# to search. If negative, it will search that many bytes at the end of the
|
||||
@@ -77,7 +80,15 @@ perl;
|
||||
close(FILE);
|
||||
$content.= $file_content;
|
||||
}
|
||||
my @matches=($content =~ m/$search_pattern/gs);
|
||||
my @matches;
|
||||
if (not defined($ENV{SEARCH_TYPE}))
|
||||
{
|
||||
@matches=($content =~ /$search_pattern/gs);
|
||||
}
|
||||
elsif($ENV{SEARCH_TYPE} == "_gm_")
|
||||
{
|
||||
@matches=($content =~ /$search_pattern/gm);
|
||||
}
|
||||
my $res=@matches ? "FOUND " . scalar(@matches) : "NOT FOUND";
|
||||
$ENV{SEARCH_FILE} =~ s{^.*?([^/\\]+)$}{$1};
|
||||
|
||||
|
@@ -114,6 +114,12 @@ The following specify which files/extra groups are read (specified before remain
|
||||
the table) is logged in the before image, and only
|
||||
changed columns are logged in the after image. (Default:
|
||||
FULL).
|
||||
--binlog-row-metadata=name
|
||||
Controls whether metadata is logged using FULL , MINIMAL
|
||||
format and NO_LOG.FULL causes all metadata to be logged;
|
||||
MINIMAL means that only metadata actually required by
|
||||
slave is logged; NO_LOG NO metadata will be
|
||||
logged.Default: NO_LOG.
|
||||
--binlog-stmt-cache-size=#
|
||||
The size of the statement cache for updates to
|
||||
non-transactional engines for the binary log. If you
|
||||
@@ -1433,6 +1439,7 @@ binlog-format MIXED
|
||||
binlog-optimize-thread-scheduling TRUE
|
||||
binlog-row-event-max-size 8192
|
||||
binlog-row-image FULL
|
||||
binlog-row-metadata NO_LOG
|
||||
binlog-stmt-cache-size 32768
|
||||
bulk-insert-buffer-size 8388608
|
||||
character-set-client-handshake TRUE
|
||||
|
34
mysql-test/suite/binlog/include/print_optional_metadata.inc
Normal file
34
mysql-test/suite/binlog/include/print_optional_metadata.inc
Normal file
@@ -0,0 +1,34 @@
|
||||
# Auxaliary file for printing optional metadata in table_map_log_event
|
||||
# Usage :
|
||||
# --let $binlog_file=
|
||||
# [--let $stop_position]
|
||||
# [--let $print_primary_key]
|
||||
# --source extra/binlog_tests/print_optional_metadata.inc
|
||||
|
||||
--let $output_file= $MYSQLTEST_VARDIR/tmp/mysqlbinlog.output
|
||||
|
||||
--let $_stop_position_opt=
|
||||
if ($stop_position)
|
||||
{
|
||||
--let $_stop_position_opt=--stop-position=$stop_position
|
||||
}
|
||||
|
||||
--exec $MYSQL_BINLOG -F --print-table-metadata $_stop_position_opt $binlog_file > $output_file
|
||||
|
||||
|
||||
--let SEARCH_PATTERN= # (?:Columns\(| {8}).*
|
||||
--let SEARCH_FILE= $output_file
|
||||
--let SEARCH_OUTPUT=matches
|
||||
--let SEARCH_TYPE="_gm_"
|
||||
--source include/search_pattern_in_file.inc
|
||||
|
||||
if ($print_primary_key)
|
||||
{
|
||||
--let SEARCH_PATTERN= # Primary Key
|
||||
--source include/search_pattern_in_file.inc
|
||||
}
|
||||
--remove_file $output_file
|
||||
--let $stop_position=
|
||||
--let $_stop_position_opt=
|
||||
|
||||
|
@@ -0,0 +1,312 @@
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
#
|
||||
# Temporal types can be printed correctly
|
||||
#
|
||||
CREATE TABLE t1(c_year YEAR, c_date DATE, c_time TIME, c_time_f TIME(3),
|
||||
c_datetime DATETIME, c_datetime_f DATETIME(3),
|
||||
c_timestamp TIMESTAMP, c_timestamp_f TIMESTAMP(3) DEFAULT "2017-1-1 10:10:10");
|
||||
INSERT INTO t1(c_year) VALUES(2017);
|
||||
# Columns(YEAR,
|
||||
# DATE,
|
||||
# TIME,
|
||||
# TIME(3),
|
||||
# DATETIME,
|
||||
# DATETIME(3),
|
||||
# TIMESTAMP NOT NULL,
|
||||
# TIMESTAMP(3) NOT NULL)
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
#
|
||||
# Geometry types can be printed correctly
|
||||
#
|
||||
CREATE TABLE t1 (c_geo GEOMETRY, c_point POINT, c_linestring LINESTRING,
|
||||
c_polygon POLYGON, c_multi_point MULTIPOINT,
|
||||
c_multi_linestring MULTILINESTRING, c_multi_polygon MULTIPOLYGON,
|
||||
c_geometrycollection GEOMETRYCOLLECTION, c_char CHAR(100));
|
||||
INSERT INTO t1(c_point) VALUES(ST_PointFromText('POINT(10 10)'));
|
||||
# Columns(GEOMETRY,
|
||||
# POINT,
|
||||
# LINESTRING,
|
||||
# POLYGON,
|
||||
# MULTIPOINT,
|
||||
# MULTILINESTRING,
|
||||
# MULTIPOLYGON,
|
||||
# GEOMETRYCOLLECTION,
|
||||
# CHAR(100) CHARSET latin1 COLLATE latin1_swedish_ci)
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1(c_point) VALUES(ST_PointFromText('POINT(10 10)'));
|
||||
# Columns(`c_geo` GEOMETRY,
|
||||
# `c_point` POINT,
|
||||
# `c_linestring` LINESTRING,
|
||||
# `c_polygon` POLYGON,
|
||||
# `c_multi_point` MULTIPOINT,
|
||||
# `c_multi_linestring` MULTILINESTRING,
|
||||
# `c_multi_polygon` MULTIPOLYGON,
|
||||
# `c_geometrycollection` GEOMETRYCOLLECTION,
|
||||
# `c_char` CHAR(100) CHARSET latin1 COLLATE latin1_swedish_ci)
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
#
|
||||
# Numeric types can be printed correctly
|
||||
#
|
||||
CREATE TABLE t1(c_bit BIT(10), c_bool BOOL, c_smallint SMALLINT,
|
||||
c_mediumint MEDIUMINT, c_int INT UNSIGNED, c_bigint BIGINT,
|
||||
c_float FLOAT UNSIGNED, c_double DOUBLE, c_decimal DECIMAL(10, 2));
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1(c_bool) VALUES(1);
|
||||
# UNSIGNED flag should be printed
|
||||
# Columns(BIT(10),
|
||||
# TINYINT,
|
||||
# SMALLINT,
|
||||
# MEDIUMINT,
|
||||
# INT UNSIGNED,
|
||||
# BIGINT,
|
||||
# FLOAT UNSIGNED,
|
||||
# DOUBLE,
|
||||
# DECIMAL(10,2))
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1(c_bool) VALUES(1);
|
||||
# Columns(`c_bit` BIT(10),
|
||||
# `c_bool` TINYINT,
|
||||
# `c_smallint` SMALLINT,
|
||||
# `c_mediumint` MEDIUMINT,
|
||||
# `c_int` INT UNSIGNED,
|
||||
# `c_bigint` BIGINT,
|
||||
# `c_float` FLOAT UNSIGNED,
|
||||
# `c_double` DOUBLE,
|
||||
# `c_decimal` DECIMAL(10,2))
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
#
|
||||
# Character types can be printed correctly
|
||||
#
|
||||
CREATE TABLE t1(c_char CHAR(10), c_varchar VARCHAR(500),
|
||||
c_tinytext TINYTEXT, c_text TEXT,
|
||||
c_mediumtext MEDIUMTEXT, c_longtext LONGTEXT CHARSET utf8);
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1(c_char) VALUES("1");
|
||||
# Columns(CHAR(10) CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# VARCHAR(500) CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# TINYTEXT CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# TEXT CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# MEDIUMTEXT CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# LONGTEXT CHARSET utf8 COLLATE utf8_general_ci)
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1(c_char) VALUES("1");
|
||||
# Columns(`c_char` CHAR(10) CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_varchar` VARCHAR(500) CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_tinytext` TINYTEXT CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_text` TEXT CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_mediumtext` MEDIUMTEXT CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_longtext` LONGTEXT CHARSET utf8 COLLATE utf8_general_ci)
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
#
|
||||
# Column names with non-ascii characters and escape characters can be printed correctly
|
||||
#
|
||||
set names utf8;
|
||||
CREATE TABLE t1(`åäö表\a'``"` INT);
|
||||
SHOW CREATE TABLE t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`åäö表\a'``"` int(11) DEFAULT NULL
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1
|
||||
INSERT INTO t1 VALUES(1);
|
||||
# Columns(`åäö表\\a\'`"` INT)
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
#
|
||||
# Charsets can be printed correctly
|
||||
#
|
||||
CREATE TABLE t1(c_char_utf8 CHAR(10) CHARSET utf8,
|
||||
c_varchar_utf8 VARCHAR(10) CHARSET utf8,
|
||||
c_text_utf8 TEXT CHARSET utf8);
|
||||
INSERT INTO t1 VALUES("1", "2", "3");
|
||||
# Columns(`c_char_utf8` CHAR(10) CHARSET utf8 COLLATE utf8_general_ci,
|
||||
# `c_varchar_utf8` VARCHAR(10) CHARSET utf8 COLLATE utf8_general_ci,
|
||||
# `c_text_utf8` TEXT CHARSET utf8 COLLATE utf8_general_ci)
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
CREATE TABLE t1(c_utf8mb4_520 CHAR(10) CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
c_utf8mb4_0900 VARCHAR(10) CHARSET utf8mb4 COLLATE utf8mb4_polish_ci,
|
||||
c_utf8mb4_def TEXT CHARSET utf8mb4);
|
||||
INSERT INTO t1 VALUES("1", "2", "3");
|
||||
# Columns(`c_utf8mb4_520` CHAR(10) CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
# `c_utf8mb4_0900` VARCHAR(10) CHARSET utf8mb4 COLLATE utf8mb4_polish_ci,
|
||||
# `c_utf8mb4_def` TEXT CHARSET utf8mb4 COLLATE utf8mb4_general_ci)
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
#
|
||||
# Blob and binary columns can be printed correctly
|
||||
#
|
||||
CREATE TABLE t1(c_binary BINARY(10), c_varbinary VARBINARY(10),
|
||||
c_tinyblob TINYBLOB, c_blob BLOB,
|
||||
c_mediumblob MEDIUMBLOB, c_longblob LONGBLOB);
|
||||
INSERT INTO t1 VALUES("1", "2", "3", "4", "5", "6");
|
||||
# Columns(`c_binary` BINARY(10),
|
||||
# `c_varbinary` VARBINARY(10),
|
||||
# `c_tinyblob` TINYBLOB,
|
||||
# `c_blob` BLOB,
|
||||
# `c_mediumblob` MEDIUMBLOB,
|
||||
# `c_longblob` LONGBLOB)
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
#
|
||||
# Verify that SET string values and character sets can be printed correctly
|
||||
#
|
||||
set names utf8;
|
||||
CREATE TABLE t1(
|
||||
c_set_1 SET("set1_v1_å", "set1_v2_ä", "set1_v3_ö"),
|
||||
c_set_2 SET("set2_v1_å", "set2_v2_ä", "set2_v3_ö") CHARACTER SET latin1,
|
||||
c_set_4 SET("set3_v1_å", "set3_v2_ä", "set3_v3_ö") CHARACTER SET swe7 COLLATE swe7_bin);
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v3_ö", "set3_v1_å");
|
||||
# Columns(SET,
|
||||
# SET,
|
||||
# SET)
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v3_ö", "set3_v1_å");
|
||||
# Columns(`c_set_1` SET('set1_v1_<31>','set1_v2_<32>','set1_v3_<33>') CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_set_2` SET('set2_v1_<31>','set2_v2_<32>','set2_v3_<33>') CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_set_4` SET('set3_v1_}','set3_v2_{','set3_v3_|') CHARSET swe7 COLLATE swe7_bin)
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
#
|
||||
# Verify that ENUM string values and character sets can be printed correctly
|
||||
#
|
||||
CREATE TABLE t1(
|
||||
c_enum_1 ENUM("enum1_v1_å", "enum1_v2_ä", "enum1_v3_ö"),
|
||||
c_enum_3 ENUM("enum2_v1_å", "enum2_v2_ä", "enum2_v3_ö") CHARACTER SET latin1,
|
||||
c_enum_4 ENUM("enum3_v1_å", "enum3_v2_ä", "enum3_v3_ö") CHARACTER SET swe7 COLLATE swe7_bin);
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v3_ö", "enum3_v1_å");
|
||||
# Columns(ENUM,
|
||||
# ENUM,
|
||||
# ENUM)
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v3_ö", "enum3_v1_å");
|
||||
# Columns(`c_enum_1` ENUM('enum1_v1_<31>','enum1_v2_<32>','enum1_v3_<33>') CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_enum_3` ENUM('enum2_v1_<31>','enum2_v2_<32>','enum2_v3_<33>') CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_enum_4` ENUM('enum3_v1_}','enum3_v2_{','enum3_v3_|') CHARSET swe7 COLLATE swe7_bin)
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
#
|
||||
# Verify that explicit NOT NULL can be printed correctly
|
||||
#
|
||||
CREATE TABLE t1(c_not_null1 INT NOT NULL, c_null1 INT, c_not_null2 INT NOT NULL,
|
||||
c_null2 INT);
|
||||
INSERT INTO t1 VALUES(1, 2, 3, 4);
|
||||
# Columns(`c_not_null1` INT NOT NULL,
|
||||
# `c_null1` INT,
|
||||
# `c_not_null2` INT NOT NULL,
|
||||
# `c_null2` INT)
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
#
|
||||
# Verify that primary key can be printed correctly
|
||||
#
|
||||
CREATE TABLE t1(c_key1 INT, c_key3 INT, c_not_key INT, c_key2 INT,
|
||||
PRIMARY KEY(c_key1, c_key2, c_key3));
|
||||
INSERT INTO t1 VALUES(1, 2, 3, 4);
|
||||
# Columns(`c_key1` INT NOT NULL,
|
||||
# `c_key3` INT NOT NULL,
|
||||
# `c_not_key` INT,
|
||||
# `c_key2` INT NOT NULL)
|
||||
# Primary Key
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
CREATE TABLE t1(c_key1 CHAR(100), c_key3 CHAR(100), c_not_key INT, c_key2 CHAR(10),
|
||||
PRIMARY KEY(c_key1(5), c_key2, c_key3(10)));
|
||||
INSERT INTO t1 VALUES("1", "2", 3, "4");
|
||||
# Columns(`c_key1` CHAR(100) NOT NULL CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_key3` CHAR(100) NOT NULL CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_not_key` INT,
|
||||
# `c_key2` CHAR(10) NOT NULL CHARSET latin1 COLLATE latin1_swedish_ci)
|
||||
# Primary Key
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1 VALUES("2", "2", 3, "4");
|
||||
# Columns(CHAR(100) NOT NULL CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# CHAR(100) NOT NULL CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# INT,
|
||||
# CHAR(10) NOT NULL CHARSET latin1 COLLATE latin1_swedish_ci)
|
||||
RESET MASTER;
|
||||
#
|
||||
# Coverage test: Print column index instead of column name if column name
|
||||
# is not binlogged.
|
||||
#
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
SET SESSION debug_dbug = 'd, dont_log_column_name';
|
||||
INSERT INTO t1 VALUES("3", "2", 3, "4");
|
||||
# Columns(`c_key1` CHAR(100) NOT NULL CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_key3` CHAR(100) NOT NULL CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_not_key` INT,
|
||||
# `c_key2` CHAR(10) NOT NULL CHARSET latin1 COLLATE latin1_swedish_ci)
|
||||
# Primary Key
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
#
|
||||
# Coverage test: Inject an invalid column type
|
||||
#
|
||||
CREATE TABLE t1(c1 int, c2 BLOB);
|
||||
SET SESSION debug_dbug = 'd,inject_invalid_column_type';
|
||||
INSERT INTO t1 VALUES(1, "a");
|
||||
# Columns(`c1` INT,
|
||||
# `c2` INVALID_TYPE(230))
|
||||
RESET MASTER;
|
||||
#
|
||||
# Coverage test: Inject an invalid BLOB metadata
|
||||
#
|
||||
SET SESSION debug_dbug = 'd,inject_invalid_blob_size';
|
||||
INSERT INTO t1 VALUES(2, "b");
|
||||
# Columns(`c1` INT,
|
||||
# `c2` INVALID_BLOB(5))
|
||||
#
|
||||
# Coverage test: Inject an invalid Geometry type
|
||||
#
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(c_geometry GEOMETRY, c_point POINT, c_multilinestring MULTILINESTRING);
|
||||
RESET MASTER;
|
||||
SET SESSION debug_dbug = 'd,inject_invalid_geometry_type';
|
||||
INSERT INTO t1(c_point) VALUES(ST_PointFromText('POINT(10 10)'));
|
||||
# Columns(`c_geometry` INVALID_GEOMETRY_TYPE(100),
|
||||
# `c_point` INVALID_GEOMETRY_TYPE(100),
|
||||
# `c_multilinestring` INVALID_GEOMETRY_TYPE(100))
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
#
|
||||
# Comptibility Test: Verify mysqlbinlog can print OLD table_map_log_event
|
||||
# without any optional metadata
|
||||
#
|
||||
CREATE TABLE t1(c_int INT, c_tiny_int_unsigned TINYINT UNSIGNED,
|
||||
c_binary BINARY(10), c_text TEXT, c_point POINT);
|
||||
SET session debug_dbug='d,simulate_no_optional_metadata';
|
||||
INSERT INTO t1(c_int) VALUES(1);
|
||||
# Columns(INT,
|
||||
# TINYINT,
|
||||
# BINARY(10),
|
||||
# BLOB,
|
||||
# GEOMETRY)
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
#
|
||||
# Simulate error on initializing charset and primary key metadata
|
||||
#
|
||||
CREATE TABLE t1(c1 char(10) PRIMARY KEY);
|
||||
SET session debug_dbug='d,simulate_init_charset_field_error';
|
||||
INSERT INTO t1 VALUES("a");
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
SET session debug_dbug='d,simulate_init_primary_key_field_error';
|
||||
INSERT INTO t1 VALUES("b");
|
||||
# Columns(BINARY(10) NOT NULL)
|
||||
# Columns(BINARY(10) NOT NULL)
|
||||
SET SESSION debug_dbug = '';
|
||||
SET GLOBAL binlog_row_metadata = NO_LOG;
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
@@ -0,0 +1,64 @@
|
||||
#
|
||||
# Verify that SET string values and character sets can be printed correctly
|
||||
#
|
||||
SET NAMES utf8;
|
||||
CREATE TABLE t1(
|
||||
c_set_1 SET("set1_v1_å", "set1_v2_ä", "set1_v3_ö"),
|
||||
c_set_2 SET("set2_v1_å", "set2_v2_ä", "set2_v3_ö") CHARACTER SET binary);
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v2_ä");
|
||||
# Columns(SET,
|
||||
# SET)
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v2_ä");
|
||||
# Columns(`c_set_1` SET('set1_v1_<31>','set1_v2_<32>','set1_v3_<33>') CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_set_2` SET('set2_v1_å','set2_v2_ä','set2_v3_ö') CHARSET binary COLLATE binary)
|
||||
INSERT INTO t1 VALUES("set1_v3_ö", "set2_v3_ö");
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v1_å");
|
||||
SELECT c_set_1, HEX(c_set_1) FROM t1;
|
||||
c_set_1 HEX(c_set_1)
|
||||
set1_v1_å 736574315F76315FE5
|
||||
set1_v1_å 736574315F76315FE5
|
||||
set1_v3_ö 736574315F76335FF6
|
||||
set1_v1_å 736574315F76315FE5
|
||||
SELECT c_set_2, HEX(c_set_2) FROM t1;
|
||||
c_set_2 HEX(c_set_2)
|
||||
set2_v2_ä 736574325F76325FC3A4
|
||||
set2_v2_ä 736574325F76325FC3A4
|
||||
set2_v3_ö 736574325F76335FC3B6
|
||||
set2_v1_å 736574325F76315FC3A5
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
#
|
||||
# Verify that ENUM string values and character sets can be printed correctly
|
||||
#
|
||||
CREATE TABLE t1(
|
||||
c_enum_1 ENUM("enum1_v1_å", "enum1_v2_ä", "enum1_v3_ö"),
|
||||
c_enum_2 ENUM("enum2_v1_å", "enum2_v2_ä", "enum2_v3_ö") CHARACTER SET binary);
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v2_ä");
|
||||
# Columns(ENUM,
|
||||
# ENUM)
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v2_ä");
|
||||
# Columns(`c_enum_1` ENUM('enum1_v1_<31>','enum1_v2_<32>','enum1_v3_<33>') CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_enum_2` ENUM('enum2_v1_å','enum2_v2_ä','enum2_v3_ö') CHARSET binary COLLATE binary)
|
||||
INSERT INTO t1 VALUES("enum1_v3_ö", "enum2_v3_ö");
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v1_å");
|
||||
SELECT c_enum_1, HEX(c_enum_1) FROM t1;
|
||||
c_enum_1 HEX(c_enum_1)
|
||||
enum1_v1_å 656E756D315F76315FE5
|
||||
enum1_v1_å 656E756D315F76315FE5
|
||||
enum1_v3_ö 656E756D315F76335FF6
|
||||
enum1_v1_å 656E756D315F76315FE5
|
||||
SELECT c_enum_2, HEX(c_enum_2) FROM t1;
|
||||
c_enum_2 HEX(c_enum_2)
|
||||
enum2_v2_ä 656E756D325F76325FC3A4
|
||||
enum2_v2_ä 656E756D325F76325FC3A4
|
||||
enum2_v3_ö 656E756D325F76335FC3B6
|
||||
enum2_v1_å 656E756D325F76315FC3A5
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = NO_LOG;
|
@@ -0,0 +1,64 @@
|
||||
#
|
||||
# Verify that SET string values and character sets can be printed correctly
|
||||
#
|
||||
SET NAMES utf8;
|
||||
CREATE TABLE t1(
|
||||
c_set_1 SET("set1_v1_å", "set1_v2_ä", "set1_v3_ö"),
|
||||
c_set_2 SET("set2_v1_å", "set2_v2_ä", "set2_v3_ö") CHARACTER SET ucs2);
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v2_ä");
|
||||
# Columns(SET,
|
||||
# SET)
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v2_ä");
|
||||
# Columns(`c_set_1` SET('set1_v1_<31>','set1_v2_<32>','set1_v3_<33>') CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_set_2` SET('\0s\0e\0t\02\0_\0v\01\0_\0<>','\0s\0e\0t\02\0_\0v\02\0_\0<>','\0s\0e\0t\02\0_\0v\03\0_\0<>') CHARSET ucs2 COLLATE ucs2_general_ci)
|
||||
INSERT INTO t1 VALUES("set1_v3_ö", "set2_v3_ö");
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v1_å");
|
||||
SELECT c_set_1, HEX(c_set_1) FROM t1;
|
||||
c_set_1 HEX(c_set_1)
|
||||
set1_v1_å 736574315F76315FE5
|
||||
set1_v1_å 736574315F76315FE5
|
||||
set1_v3_ö 736574315F76335FF6
|
||||
set1_v1_å 736574315F76315FE5
|
||||
SELECT c_set_2, HEX(c_set_2) FROM t1;
|
||||
c_set_2 HEX(c_set_2)
|
||||
set2_v2_ä 0073006500740032005F00760032005F00E4
|
||||
set2_v2_ä 0073006500740032005F00760032005F00E4
|
||||
set2_v3_ö 0073006500740032005F00760033005F00F6
|
||||
set2_v1_å 0073006500740032005F00760031005F00E5
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
#
|
||||
# Verify that ENUM string values and character sets can be printed correctly
|
||||
#
|
||||
CREATE TABLE t1(
|
||||
c_enum_1 ENUM("enum1_v1_å", "enum1_v2_ä", "enum1_v3_ö"),
|
||||
c_enum_2 ENUM("enum2_v1_å", "enum2_v2_ä", "enum2_v3_ö") CHARACTER SET ucs2);
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v2_ä");
|
||||
# Columns(ENUM,
|
||||
# ENUM)
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v2_ä");
|
||||
# Columns(`c_enum_1` ENUM('enum1_v1_<31>','enum1_v2_<32>','enum1_v3_<33>') CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_enum_2` ENUM('\0e\0n\0u\0m\02\0_\0v\01\0_\0<>','\0e\0n\0u\0m\02\0_\0v\02\0_\0<>','\0e\0n\0u\0m\02\0_\0v\03\0_\0<>') CHARSET ucs2 COLLATE ucs2_general_ci)
|
||||
INSERT INTO t1 VALUES("enum1_v3_ö", "enum2_v3_ö");
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v1_å");
|
||||
SELECT c_enum_1, HEX(c_enum_1) FROM t1;
|
||||
c_enum_1 HEX(c_enum_1)
|
||||
enum1_v1_å 656E756D315F76315FE5
|
||||
enum1_v1_å 656E756D315F76315FE5
|
||||
enum1_v3_ö 656E756D315F76335FF6
|
||||
enum1_v1_å 656E756D315F76315FE5
|
||||
SELECT c_enum_2, HEX(c_enum_2) FROM t1;
|
||||
c_enum_2 HEX(c_enum_2)
|
||||
enum2_v2_ä 0065006E0075006D0032005F00760032005F00E4
|
||||
enum2_v2_ä 0065006E0075006D0032005F00760032005F00E4
|
||||
enum2_v3_ö 0065006E0075006D0032005F00760033005F00F6
|
||||
enum2_v1_å 0065006E0075006D0032005F00760031005F00E5
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = NO_LOG;
|
@@ -0,0 +1,64 @@
|
||||
#
|
||||
# Verify that SET string values and character sets can be printed correctly
|
||||
#
|
||||
SET NAMES utf8;
|
||||
CREATE TABLE t1(
|
||||
c_set_1 SET("set1_v1_å", "set1_v2_ä", "set1_v3_ö"),
|
||||
c_set_2 SET("set2_v1_å", "set2_v2_ä", "set2_v3_ö") CHARACTER SET utf32);
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v2_ä");
|
||||
# Columns(SET,
|
||||
# SET)
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v2_ä");
|
||||
# Columns(`c_set_1` SET('set1_v1_<31>','set1_v2_<32>','set1_v3_<33>') CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_set_2` SET('\0\0\0s\0\0\0e\0\0\0t\0\0\02\0\0\0_\0\0\0v\0\0\01\0\0\0_\0\0\0<>','\0\0\0s\0\0\0e\0\0\0t\0\0\02\0\0\0_\0\0\0v\0\0\02\0\0\0_\0\0\0<>','\0\0\0s\0\0\0e\0\0\0t\0\0\02\0\0\0_\0\0\0v\0\0\03\0\0\0_\0\0\0<>') CHARSET utf32 COLLATE utf32_general_ci)
|
||||
INSERT INTO t1 VALUES("set1_v3_ö", "set2_v3_ö");
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v1_å");
|
||||
SELECT c_set_1, HEX(c_set_1) FROM t1;
|
||||
c_set_1 HEX(c_set_1)
|
||||
set1_v1_å 736574315F76315FE5
|
||||
set1_v1_å 736574315F76315FE5
|
||||
set1_v3_ö 736574315F76335FF6
|
||||
set1_v1_å 736574315F76315FE5
|
||||
SELECT c_set_2, HEX(c_set_2) FROM t1;
|
||||
c_set_2 HEX(c_set_2)
|
||||
set2_v2_ä 000000730000006500000074000000320000005F00000076000000320000005F000000E4
|
||||
set2_v2_ä 000000730000006500000074000000320000005F00000076000000320000005F000000E4
|
||||
set2_v3_ö 000000730000006500000074000000320000005F00000076000000330000005F000000F6
|
||||
set2_v1_å 000000730000006500000074000000320000005F00000076000000310000005F000000E5
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
#
|
||||
# Verify that ENUM string values and character sets can be printed correctly
|
||||
#
|
||||
CREATE TABLE t1(
|
||||
c_enum_1 ENUM("enum1_v1_å", "enum1_v2_ä", "enum1_v3_ö"),
|
||||
c_enum_2 ENUM("enum2_v1_å", "enum2_v2_ä", "enum2_v3_ö") CHARACTER SET utf32);
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v2_ä");
|
||||
# Columns(ENUM,
|
||||
# ENUM)
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v2_ä");
|
||||
# Columns(`c_enum_1` ENUM('enum1_v1_<31>','enum1_v2_<32>','enum1_v3_<33>') CHARSET latin1 COLLATE latin1_swedish_ci,
|
||||
# `c_enum_2` ENUM('\0\0\0e\0\0\0n\0\0\0u\0\0\0m\0\0\02\0\0\0_\0\0\0v\0\0\01\0\0\0_\0\0\0<>','\0\0\0e\0\0\0n\0\0\0u\0\0\0m\0\0\02\0\0\0_\0\0\0v\0\0\02\0\0\0_\0\0\0<>','\0\0\0e\0\0\0n\0\0\0u\0\0\0m\0\0\02\0\0\0_\0\0\0v\0\0\03\0\0\0_\0\0\0<>') CHARSET utf32 COLLATE utf32_general_ci)
|
||||
INSERT INTO t1 VALUES("enum1_v3_ö", "enum2_v3_ö");
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v1_å");
|
||||
SELECT c_enum_1, HEX(c_enum_1) FROM t1;
|
||||
c_enum_1 HEX(c_enum_1)
|
||||
enum1_v1_å 656E756D315F76315FE5
|
||||
enum1_v1_å 656E756D315F76315FE5
|
||||
enum1_v3_ö 656E756D315F76335FF6
|
||||
enum1_v1_å 656E756D315F76315FE5
|
||||
SELECT c_enum_2, HEX(c_enum_2) FROM t1;
|
||||
c_enum_2 HEX(c_enum_2)
|
||||
enum2_v2_ä 000000650000006E000000750000006D000000320000005F00000076000000320000005F000000E4
|
||||
enum2_v2_ä 000000650000006E000000750000006D000000320000005F00000076000000320000005F000000E4
|
||||
enum2_v3_ö 000000650000006E000000750000006D000000320000005F00000076000000330000005F000000F6
|
||||
enum2_v1_å 000000650000006E000000750000006D000000320000005F00000076000000310000005F000000E5
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = NO_LOG;
|
@@ -0,0 +1,334 @@
|
||||
################################################################################
|
||||
# WL#4618 RBR: extended table metadata in the binary log
|
||||
#
|
||||
# Below metadata is logged into Table_map_log_event
|
||||
# - signedness of numeric columns
|
||||
# - charsets of character columns
|
||||
# - column names
|
||||
# - set/enum character sets and string values
|
||||
# - primary key
|
||||
#
|
||||
# The first two are always logged. The others are controlled by system
|
||||
# variable --binlog-row-metadata
|
||||
#
|
||||
# The test will verify if the metadata can be logged and printed by mysqlbinlog
|
||||
# correctly.
|
||||
# mysqlbinlog --print-table-metadata will print the extra metadata
|
||||
################################################################################
|
||||
--source include/have_debug.inc
|
||||
--source include/have_binlog_format_row.inc
|
||||
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
|
||||
--let $MYSQLD_DATADIR= `select @@datadir`
|
||||
--let $binlog_file= $MYSQLD_DATADIR/master-bin.000001
|
||||
|
||||
--echo #
|
||||
--echo # Temporal types can be printed correctly
|
||||
--echo #
|
||||
CREATE TABLE t1(c_year YEAR, c_date DATE, c_time TIME, c_time_f TIME(3),
|
||||
c_datetime DATETIME, c_datetime_f DATETIME(3),
|
||||
c_timestamp TIMESTAMP, c_timestamp_f TIMESTAMP(3) DEFAULT "2017-1-1 10:10:10");
|
||||
|
||||
INSERT INTO t1(c_year) VALUES(2017);
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
--echo #
|
||||
--echo # Geometry types can be printed correctly
|
||||
--echo #
|
||||
CREATE TABLE t1 (c_geo GEOMETRY, c_point POINT, c_linestring LINESTRING,
|
||||
c_polygon POLYGON, c_multi_point MULTIPOINT,
|
||||
c_multi_linestring MULTILINESTRING, c_multi_polygon MULTIPOLYGON,
|
||||
c_geometrycollection GEOMETRYCOLLECTION, c_char CHAR(100));
|
||||
|
||||
INSERT INTO t1(c_point) VALUES(ST_PointFromText('POINT(10 10)'));
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
|
||||
# geometry type is binlogged, the real geometry types are printed
|
||||
INSERT INTO t1(c_point) VALUES(ST_PointFromText('POINT(10 10)'));
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
--echo #
|
||||
--echo # Numeric types can be printed correctly
|
||||
--echo #
|
||||
CREATE TABLE t1(c_bit BIT(10), c_bool BOOL, c_smallint SMALLINT,
|
||||
c_mediumint MEDIUMINT, c_int INT UNSIGNED, c_bigint BIGINT,
|
||||
c_float FLOAT UNSIGNED, c_double DOUBLE, c_decimal DECIMAL(10, 2));
|
||||
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1(c_bool) VALUES(1);
|
||||
|
||||
--echo # UNSIGNED flag should be printed
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1(c_bool) VALUES(1);
|
||||
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
--echo #
|
||||
--echo # Character types can be printed correctly
|
||||
--echo #
|
||||
CREATE TABLE t1(c_char CHAR(10), c_varchar VARCHAR(500),
|
||||
c_tinytext TINYTEXT, c_text TEXT,
|
||||
c_mediumtext MEDIUMTEXT, c_longtext LONGTEXT CHARSET utf8);
|
||||
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1(c_char) VALUES("1");
|
||||
|
||||
# Charset set is printed with default charset
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1(c_char) VALUES("1");
|
||||
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
--echo #
|
||||
--echo # Column names with non-ascii characters and escape characters can be printed correctly
|
||||
--echo #
|
||||
set names utf8;
|
||||
CREATE TABLE t1(`åäö表\a'``"` INT);
|
||||
|
||||
SHOW CREATE TABLE t1;
|
||||
|
||||
INSERT INTO t1 VALUES(1);
|
||||
--source include/print_optional_metadata.inc
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
--echo #
|
||||
--echo # Charsets can be printed correctly
|
||||
--echo #
|
||||
CREATE TABLE t1(c_char_utf8 CHAR(10) CHARSET utf8,
|
||||
c_varchar_utf8 VARCHAR(10) CHARSET utf8,
|
||||
c_text_utf8 TEXT CHARSET utf8);
|
||||
|
||||
INSERT INTO t1 VALUES("1", "2", "3");
|
||||
|
||||
# Charset set is printed with Default charset
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
# Test collation number less than 250 and collation number greater than 250
|
||||
CREATE TABLE t1(c_utf8mb4_520 CHAR(10) CHARSET utf8mb4 COLLATE utf8mb4_unicode_ci,
|
||||
c_utf8mb4_0900 VARCHAR(10) CHARSET utf8mb4 COLLATE utf8mb4_polish_ci,
|
||||
c_utf8mb4_def TEXT CHARSET utf8mb4);
|
||||
|
||||
INSERT INTO t1 VALUES("1", "2", "3");
|
||||
|
||||
# Charset set is printed without default charset
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
--echo #
|
||||
--echo # Blob and binary columns can be printed correctly
|
||||
--echo #
|
||||
CREATE TABLE t1(c_binary BINARY(10), c_varbinary VARBINARY(10),
|
||||
c_tinyblob TINYBLOB, c_blob BLOB,
|
||||
c_mediumblob MEDIUMBLOB, c_longblob LONGBLOB);
|
||||
|
||||
INSERT INTO t1 VALUES("1", "2", "3", "4", "5", "6");
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
--echo #
|
||||
--echo # Verify that SET string values and character sets can be printed correctly
|
||||
--echo #
|
||||
|
||||
set names utf8;
|
||||
CREATE TABLE t1(
|
||||
c_set_1 SET("set1_v1_å", "set1_v2_ä", "set1_v3_ö"),
|
||||
c_set_2 SET("set2_v1_å", "set2_v2_ä", "set2_v3_ö") CHARACTER SET latin1,
|
||||
c_set_4 SET("set3_v1_å", "set3_v2_ä", "set3_v3_ö") CHARACTER SET swe7 COLLATE swe7_bin);
|
||||
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v3_ö", "set3_v1_å");
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v3_ö", "set3_v1_å");
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
--echo #
|
||||
--echo # Verify that ENUM string values and character sets can be printed correctly
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1(
|
||||
c_enum_1 ENUM("enum1_v1_å", "enum1_v2_ä", "enum1_v3_ö"),
|
||||
c_enum_3 ENUM("enum2_v1_å", "enum2_v2_ä", "enum2_v3_ö") CHARACTER SET latin1,
|
||||
c_enum_4 ENUM("enum3_v1_å", "enum3_v2_ä", "enum3_v3_ö") CHARACTER SET swe7 COLLATE swe7_bin);
|
||||
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v3_ö", "enum3_v1_å");
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v3_ö", "enum3_v1_å");
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
--echo #
|
||||
--echo # Verify that explicit NOT NULL can be printed correctly
|
||||
--echo #
|
||||
CREATE TABLE t1(c_not_null1 INT NOT NULL, c_null1 INT, c_not_null2 INT NOT NULL,
|
||||
c_null2 INT);
|
||||
|
||||
INSERT INTO t1 VALUES(1, 2, 3, 4);
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
--echo #
|
||||
--echo # Verify that primary key can be printed correctly
|
||||
--echo #
|
||||
CREATE TABLE t1(c_key1 INT, c_key3 INT, c_not_key INT, c_key2 INT,
|
||||
PRIMARY KEY(c_key1, c_key2, c_key3));
|
||||
|
||||
INSERT INTO t1 VALUES(1, 2, 3, 4);
|
||||
--let $print_primary_key= 1
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
# Key has prefix
|
||||
CREATE TABLE t1(c_key1 CHAR(100), c_key3 CHAR(100), c_not_key INT, c_key2 CHAR(10),
|
||||
PRIMARY KEY(c_key1(5), c_key2, c_key3(10)));
|
||||
|
||||
INSERT INTO t1 VALUES("1", "2", 3, "4");
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
RESET MASTER;
|
||||
# Primary key should not be printed
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
|
||||
INSERT INTO t1 VALUES("2", "2", 3, "4");
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
RESET MASTER;
|
||||
--echo #
|
||||
--echo # Coverage test: Print column index instead of column name if column name
|
||||
--echo # is not binlogged.
|
||||
--echo #
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
|
||||
SET SESSION debug_dbug = 'd, dont_log_column_name';
|
||||
INSERT INTO t1 VALUES("3", "2", 3, "4");
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
--let $print_primary_key=
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
--echo #
|
||||
--echo # Coverage test: Inject an invalid column type
|
||||
--echo #
|
||||
CREATE TABLE t1(c1 int, c2 BLOB);
|
||||
|
||||
SET SESSION debug_dbug = 'd,inject_invalid_column_type';
|
||||
INSERT INTO t1 VALUES(1, "a");
|
||||
# It prints an error
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
RESET MASTER;
|
||||
|
||||
--echo #
|
||||
--echo # Coverage test: Inject an invalid BLOB metadata
|
||||
--echo #
|
||||
--let $start_pos= query_get_value(SHOW MASTER STATUS, Position, 1)
|
||||
|
||||
SET SESSION debug_dbug = 'd,inject_invalid_blob_size';
|
||||
INSERT INTO t1 VALUES(2, "b");
|
||||
|
||||
# The invalid metadata will case assertion failure on Write_rows_log_event
|
||||
# So we need to stop mysqlbinlog before reading Write_rows_log_event.
|
||||
--let $stop_position= query_get_value(SHOW BINLOG EVENTS FROM $start_pos LIMIT 3, End_log_pos, 3)
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
--echo #
|
||||
--echo # Coverage test: Inject an invalid Geometry type
|
||||
--echo #
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(c_geometry GEOMETRY, c_point POINT, c_multilinestring MULTILINESTRING);
|
||||
RESET MASTER;
|
||||
--let $start_pos= query_get_value(SHOW MASTER STATUS, Position, 1)
|
||||
|
||||
SET SESSION debug_dbug = 'd,inject_invalid_geometry_type';
|
||||
INSERT INTO t1(c_point) VALUES(ST_PointFromText('POINT(10 10)'));
|
||||
|
||||
# The invalid metadata will case assertion failure on Write_rows_log_event
|
||||
# So we need to stop mysqlbinlog before reading Write_rows_log_event.
|
||||
--let $stop_position= query_get_value(SHOW BINLOG EVENTS FROM $start_pos LIMIT 3, End_log_pos, 3)
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
--echo #
|
||||
--echo # Comptibility Test: Verify mysqlbinlog can print OLD table_map_log_event
|
||||
--echo # without any optional metadata
|
||||
--echo #
|
||||
CREATE TABLE t1(c_int INT, c_tiny_int_unsigned TINYINT UNSIGNED,
|
||||
c_binary BINARY(10), c_text TEXT, c_point POINT);
|
||||
|
||||
SET session debug_dbug='d,simulate_no_optional_metadata';
|
||||
INSERT INTO t1(c_int) VALUES(1);
|
||||
# TINYINT will be printed without UNSIGNED flag,
|
||||
# CHAR will be printed as BINARY(10)
|
||||
# POINT will be printed as GEOMETRY
|
||||
--let $stop_position=
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
--echo #
|
||||
--echo # Simulate error on initializing charset and primary key metadata
|
||||
--echo #
|
||||
CREATE TABLE t1(c1 char(10) PRIMARY KEY);
|
||||
|
||||
SET session debug_dbug='d,simulate_init_charset_field_error';
|
||||
INSERT INTO t1 VALUES("a");
|
||||
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
SET session debug_dbug='d,simulate_init_primary_key_field_error';
|
||||
INSERT INTO t1 VALUES("b");
|
||||
|
||||
--let $print_primary_key= 1
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
SET SESSION debug_dbug = '';
|
||||
SET GLOBAL binlog_row_metadata = NO_LOG;
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
@@ -0,0 +1,73 @@
|
||||
################################################################################
|
||||
# WL#4618 RBR: extended table metadata in the binary log
|
||||
#
|
||||
# Below metadata is logged into Table_map_log_event
|
||||
# - signedness of numeric columns
|
||||
# - charsets of character columns
|
||||
# - column names
|
||||
# - set/enum character sets and string values
|
||||
# - primary key
|
||||
#
|
||||
# The first two are always logged. The others are controlled by system
|
||||
# variable --binlog-row-metadata
|
||||
#
|
||||
# The test will verify if the metadata can be logged and printed by mysqlbinlog
|
||||
# correctly.
|
||||
# mysqlbinlog --print-table-metadata will print the extra metadata
|
||||
################################################################################
|
||||
--source include/have_debug.inc
|
||||
--source include/have_binlog_format_row.inc
|
||||
--let $MYSQLD_DATADIR= `select @@datadir`
|
||||
--let $binlog_file= $MYSQLD_DATADIR/master-bin.000001
|
||||
|
||||
--echo #
|
||||
--echo # Verify that SET string values and character sets can be printed correctly
|
||||
--echo #
|
||||
|
||||
SET NAMES utf8;
|
||||
CREATE TABLE t1(
|
||||
c_set_1 SET("set1_v1_å", "set1_v2_ä", "set1_v3_ö"),
|
||||
c_set_2 SET("set2_v1_å", "set2_v2_ä", "set2_v3_ö") CHARACTER SET binary);
|
||||
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v2_ä");
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v2_ä");
|
||||
--source include/print_optional_metadata.inc
|
||||
INSERT INTO t1 VALUES("set1_v3_ö", "set2_v3_ö");
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v1_å");
|
||||
SELECT c_set_1, HEX(c_set_1) FROM t1;
|
||||
SELECT c_set_2, HEX(c_set_2) FROM t1;
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
--echo #
|
||||
--echo # Verify that ENUM string values and character sets can be printed correctly
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1(
|
||||
c_enum_1 ENUM("enum1_v1_å", "enum1_v2_ä", "enum1_v3_ö"),
|
||||
c_enum_2 ENUM("enum2_v1_å", "enum2_v2_ä", "enum2_v3_ö") CHARACTER SET binary);
|
||||
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v2_ä");
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v2_ä");
|
||||
--source include/print_optional_metadata.inc
|
||||
INSERT INTO t1 VALUES("enum1_v3_ö", "enum2_v3_ö");
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v1_å");
|
||||
SELECT c_enum_1, HEX(c_enum_1) FROM t1;
|
||||
SELECT c_enum_2, HEX(c_enum_2) FROM t1;
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
SET GLOBAL binlog_row_metadata = NO_LOG;
|
@@ -0,0 +1,74 @@
|
||||
################################################################################
|
||||
# WL#4618 RBR: extended table metadata in the binary log
|
||||
#
|
||||
# Below metadata is logged into Table_map_log_event
|
||||
# - signedness of numeric columns
|
||||
# - charsets of character columns
|
||||
# - column names
|
||||
# - set/enum character sets and string values
|
||||
# - primary key
|
||||
#
|
||||
# The first two are always logged. The others are controlled by system
|
||||
# variable --binlog-row-metadata
|
||||
#
|
||||
# The test will verify if the metadata can be logged and printed by mysqlbinlog
|
||||
# correctly.
|
||||
# mysqlbinlog --print-table-metadata will print the extra metadata
|
||||
################################################################################
|
||||
--source include/have_debug.inc
|
||||
--source include/have_binlog_format_row.inc
|
||||
--source include/have_ucs2.inc
|
||||
--let $MYSQLD_DATADIR= `select @@datadir`
|
||||
--let $binlog_file= $MYSQLD_DATADIR/master-bin.000001
|
||||
|
||||
--echo #
|
||||
--echo # Verify that SET string values and character sets can be printed correctly
|
||||
--echo #
|
||||
|
||||
SET NAMES utf8;
|
||||
CREATE TABLE t1(
|
||||
c_set_1 SET("set1_v1_å", "set1_v2_ä", "set1_v3_ö"),
|
||||
c_set_2 SET("set2_v1_å", "set2_v2_ä", "set2_v3_ö") CHARACTER SET ucs2);
|
||||
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v2_ä");
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v2_ä");
|
||||
--source include/print_optional_metadata.inc
|
||||
INSERT INTO t1 VALUES("set1_v3_ö", "set2_v3_ö");
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v1_å");
|
||||
SELECT c_set_1, HEX(c_set_1) FROM t1;
|
||||
SELECT c_set_2, HEX(c_set_2) FROM t1;
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
--echo #
|
||||
--echo # Verify that ENUM string values and character sets can be printed correctly
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1(
|
||||
c_enum_1 ENUM("enum1_v1_å", "enum1_v2_ä", "enum1_v3_ö"),
|
||||
c_enum_2 ENUM("enum2_v1_å", "enum2_v2_ä", "enum2_v3_ö") CHARACTER SET ucs2);
|
||||
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v2_ä");
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v2_ä");
|
||||
--source include/print_optional_metadata.inc
|
||||
INSERT INTO t1 VALUES("enum1_v3_ö", "enum2_v3_ö");
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v1_å");
|
||||
SELECT c_enum_1, HEX(c_enum_1) FROM t1;
|
||||
SELECT c_enum_2, HEX(c_enum_2) FROM t1;
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
SET GLOBAL binlog_row_metadata = NO_LOG;
|
@@ -0,0 +1,74 @@
|
||||
################################################################################
|
||||
# WL#4618 RBR: extended table metadata in the binary log
|
||||
#
|
||||
# Below metadata is logged into Table_map_log_event
|
||||
# - signedness of numeric columns
|
||||
# - charsets of character columns
|
||||
# - column names
|
||||
# - set/enum character sets and string values
|
||||
# - primary key
|
||||
#
|
||||
# The first two are always logged. The others are controlled by system
|
||||
# variable --binlog-row-metadata
|
||||
#
|
||||
# The test will verify if the metadata can be logged and printed by mysqlbinlog
|
||||
# correctly.
|
||||
# mysqlbinlog --print-table-metadata will print the extra metadata
|
||||
################################################################################
|
||||
--source include/have_debug.inc
|
||||
--source include/have_binlog_format_row.inc
|
||||
--source include/have_utf32.inc
|
||||
--let $MYSQLD_DATADIR= `select @@datadir`
|
||||
--let $binlog_file= $MYSQLD_DATADIR/master-bin.000001
|
||||
|
||||
--echo #
|
||||
--echo # Verify that SET string values and character sets can be printed correctly
|
||||
--echo #
|
||||
|
||||
SET NAMES utf8;
|
||||
CREATE TABLE t1(
|
||||
c_set_1 SET("set1_v1_å", "set1_v2_ä", "set1_v3_ö"),
|
||||
c_set_2 SET("set2_v1_å", "set2_v2_ä", "set2_v3_ö") CHARACTER SET utf32);
|
||||
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v2_ä");
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v2_ä");
|
||||
--source include/print_optional_metadata.inc
|
||||
INSERT INTO t1 VALUES("set1_v3_ö", "set2_v3_ö");
|
||||
INSERT INTO t1 VALUES("set1_v1_å", "set2_v1_å");
|
||||
SELECT c_set_1, HEX(c_set_1) FROM t1;
|
||||
SELECT c_set_2, HEX(c_set_2) FROM t1;
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
--echo #
|
||||
--echo # Verify that ENUM string values and character sets can be printed correctly
|
||||
--echo #
|
||||
|
||||
CREATE TABLE t1(
|
||||
c_enum_1 ENUM("enum1_v1_å", "enum1_v2_ä", "enum1_v3_ö"),
|
||||
c_enum_2 ENUM("enum2_v1_å", "enum2_v2_ä", "enum2_v3_ö") CHARACTER SET utf32);
|
||||
|
||||
SET GLOBAL binlog_row_metadata = MINIMAL;
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v2_ä");
|
||||
--source include/print_optional_metadata.inc
|
||||
|
||||
|
||||
RESET MASTER;
|
||||
SET GLOBAL binlog_row_metadata = FULL;
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v2_ä");
|
||||
--source include/print_optional_metadata.inc
|
||||
INSERT INTO t1 VALUES("enum1_v3_ö", "enum2_v3_ö");
|
||||
INSERT INTO t1 VALUES("enum1_v1_å", "enum2_v1_å");
|
||||
SELECT c_enum_1, HEX(c_enum_1) FROM t1;
|
||||
SELECT c_enum_2, HEX(c_enum_2) FROM t1;
|
||||
|
||||
DROP TABLE t1;
|
||||
RESET MASTER;
|
||||
|
||||
SET GLOBAL binlog_row_metadata = NO_LOG;
|
90
mysql-test/suite/sys_vars/r/binlog_row_metadata_basic.result
Normal file
90
mysql-test/suite/sys_vars/r/binlog_row_metadata_basic.result
Normal file
@@ -0,0 +1,90 @@
|
||||
NO_LOG Expected
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
@@GLOBAL.binlog_row_metadata
|
||||
NO_LOG
|
||||
SELECT @@SESSION.binlog_row_metadata;
|
||||
ERROR HY000: Variable 'binlog_row_metadata' is a GLOBAL variable
|
||||
'#---------------------BS_STVARS_002_01----------------------#'
|
||||
SET @start_value= @@global.binlog_row_metadata;
|
||||
SELECT COUNT(@@GLOBAL.binlog_row_metadata);
|
||||
COUNT(@@GLOBAL.binlog_row_metadata)
|
||||
1
|
||||
1 Expected
|
||||
'#---------------------BS_STVARS_002_02----------------------#'
|
||||
SET @@GLOBAL.binlog_row_metadata=0;
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
@@GLOBAL.binlog_row_metadata
|
||||
NO_LOG
|
||||
NO_LOG Expected
|
||||
SET @@GLOBAL.binlog_row_metadata=1;
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
@@GLOBAL.binlog_row_metadata
|
||||
MINIMAL
|
||||
MINIMAL Expected
|
||||
SET @@GLOBAL.binlog_row_metadata=2;
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
@@GLOBAL.binlog_row_metadata
|
||||
FULL
|
||||
FULL Expected
|
||||
SET @@GLOBAL.binlog_row_metadata=NO_LOG;
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
@@GLOBAL.binlog_row_metadata
|
||||
NO_LOG
|
||||
NO_LOG Expected
|
||||
SET @@GLOBAL.binlog_row_metadata=MINIMAL;
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
@@GLOBAL.binlog_row_metadata
|
||||
MINIMAL
|
||||
MINIMAL Expected
|
||||
SET @@GLOBAL.binlog_row_metadata=FULL;
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
@@GLOBAL.binlog_row_metadata
|
||||
FULL
|
||||
FULL Expected
|
||||
SET @@GLOBAL.binlog_row_metadata='NO_LOG';
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
@@GLOBAL.binlog_row_metadata
|
||||
NO_LOG
|
||||
NO_LOG Expected
|
||||
SET @@GLOBAL.binlog_row_metadata='MINIMAL';
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
@@GLOBAL.binlog_row_metadata
|
||||
MINIMAL
|
||||
MINIMAL Expected
|
||||
SET @@GLOBAL.binlog_row_metadata='FULL';
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
@@GLOBAL.binlog_row_metadata
|
||||
FULL
|
||||
FULL Expected
|
||||
'#---------------------BS_STVARS_002_03----------------------#'
|
||||
SET @@GLOBAL.binlog_row_metadata='MINIMAl';
|
||||
SELECT *
|
||||
FROM information_schema.global_variables
|
||||
WHERE VARIABLE_NAME='binlog_row_metadata';
|
||||
VARIABLE_NAME VARIABLE_VALUE
|
||||
BINLOG_ROW_METADATA MINIMAL
|
||||
'#---------------------BS_STVARS_002_04----------------------#'
|
||||
SELECT *
|
||||
FROM information_schema.session_variables
|
||||
WHERE VARIABLE_NAME LIKE 'binlog_row_metadata';
|
||||
VARIABLE_NAME VARIABLE_VALUE
|
||||
BINLOG_ROW_METADATA MINIMAL
|
||||
'#---------------------BS_STVARS_002_05----------------------#'
|
||||
SELECT COUNT(@@binlog_row_metadata);
|
||||
COUNT(@@binlog_row_metadata)
|
||||
1
|
||||
1 Expected
|
||||
SELECT COUNT(@@GLOBAL.binlog_row_metadata);
|
||||
COUNT(@@GLOBAL.binlog_row_metadata)
|
||||
1
|
||||
1 Expected
|
||||
'#---------------------BS_STVARS_002_06----------------------#'
|
||||
SET GLOBAL binlog_row_metadata = full1;
|
||||
ERROR 42000: Variable 'binlog_row_metadata' can't be set to the value of 'full1'
|
||||
SET GLOBAL binlog_row_metadata = "full1";
|
||||
ERROR 42000: Variable 'binlog_row_metadata' can't be set to the value of 'full1'
|
||||
SET GLOBAL binlog_row_metadata = 3;
|
||||
ERROR 42000: Variable 'binlog_row_metadata' can't be set to the value of '3'
|
||||
SET GLOBAL binlog_row_metadata = -1;
|
||||
ERROR 42000: Variable 'binlog_row_metadata' can't be set to the value of '-1'
|
||||
SET @@global.binlog_row_metadata= @start_value;
|
@@ -423,6 +423,20 @@ NUMERIC_BLOCK_SIZE NULL
|
||||
ENUM_VALUE_LIST MINIMAL,NOBLOB,FULL
|
||||
READ_ONLY NO
|
||||
COMMAND_LINE_ARGUMENT REQUIRED
|
||||
VARIABLE_NAME BINLOG_ROW_METADATA
|
||||
SESSION_VALUE NULL
|
||||
GLOBAL_VALUE NO_LOG
|
||||
GLOBAL_VALUE_ORIGIN COMPILE-TIME
|
||||
DEFAULT_VALUE NO_LOG
|
||||
VARIABLE_SCOPE GLOBAL
|
||||
VARIABLE_TYPE ENUM
|
||||
VARIABLE_COMMENT Controls whether metadata is logged using FULL , MINIMAL format and NO_LOG.FULL causes all metadata to be logged; MINIMAL means that only metadata actually required by slave is logged; NO_LOG NO metadata will be logged.Default: NO_LOG.
|
||||
NUMERIC_MIN_VALUE NULL
|
||||
NUMERIC_MAX_VALUE NULL
|
||||
NUMERIC_BLOCK_SIZE NULL
|
||||
ENUM_VALUE_LIST NO_LOG,MINIMAL,FULL
|
||||
READ_ONLY NO
|
||||
COMMAND_LINE_ARGUMENT REQUIRED
|
||||
VARIABLE_NAME BINLOG_STMT_CACHE_SIZE
|
||||
VARIABLE_SCOPE GLOBAL
|
||||
VARIABLE_TYPE BIGINT UNSIGNED
|
||||
|
121
mysql-test/suite/sys_vars/t/binlog_row_metadata_basic.test
Normal file
121
mysql-test/suite/sys_vars/t/binlog_row_metadata_basic.test
Normal file
@@ -0,0 +1,121 @@
|
||||
################## mysql-test\t\binlog_row_metadata_basic.test ################
|
||||
# #
|
||||
# Variable Name: binlog_row_metadata #
|
||||
# Scope: Global #
|
||||
# Data Type: enumeration #
|
||||
# #
|
||||
# Creation Date: 2017-01-23 #
|
||||
# Author : Libing Song #
|
||||
# #
|
||||
# #
|
||||
# Description:Test Cases of Dynamic System Variable binlog_row_metadata #
|
||||
# that checks the behavior of this variable in the following ways #
|
||||
# * Value Check #
|
||||
# * Scope Check #
|
||||
# #
|
||||
# Reference: #
|
||||
# http://dev.mysql.com/doc/refman/8.X/en/server-system-variables.html #
|
||||
# #
|
||||
###############################################################################
|
||||
|
||||
|
||||
--echo NO_LOG Expected
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
|
||||
SELECT @@SESSION.binlog_row_metadata;
|
||||
|
||||
--echo '#---------------------BS_STVARS_002_01----------------------#'
|
||||
####################################################################
|
||||
# Displaying default value #
|
||||
####################################################################
|
||||
SET @start_value= @@global.binlog_row_metadata;
|
||||
|
||||
SELECT COUNT(@@GLOBAL.binlog_row_metadata);
|
||||
--echo 1 Expected
|
||||
|
||||
--echo '#---------------------BS_STVARS_002_02----------------------#'
|
||||
####################################################################
|
||||
# Check if Value can set #
|
||||
####################################################################
|
||||
SET @@GLOBAL.binlog_row_metadata=0;
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
--echo NO_LOG Expected
|
||||
|
||||
SET @@GLOBAL.binlog_row_metadata=1;
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
--echo MINIMAL Expected
|
||||
|
||||
SET @@GLOBAL.binlog_row_metadata=2;
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
--echo FULL Expected
|
||||
|
||||
SET @@GLOBAL.binlog_row_metadata=NO_LOG;
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
--echo NO_LOG Expected
|
||||
|
||||
SET @@GLOBAL.binlog_row_metadata=MINIMAL;
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
--echo MINIMAL Expected
|
||||
|
||||
SET @@GLOBAL.binlog_row_metadata=FULL;
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
--echo FULL Expected
|
||||
|
||||
SET @@GLOBAL.binlog_row_metadata='NO_LOG';
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
--echo NO_LOG Expected
|
||||
|
||||
SET @@GLOBAL.binlog_row_metadata='MINIMAL';
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
--echo MINIMAL Expected
|
||||
|
||||
SET @@GLOBAL.binlog_row_metadata='FULL';
|
||||
SELECT @@GLOBAL.binlog_row_metadata;
|
||||
--echo FULL Expected
|
||||
|
||||
--echo '#---------------------BS_STVARS_002_03----------------------#'
|
||||
#################################################################
|
||||
# Check if the value in GLOBAL Table matches value in variable #
|
||||
#################################################################
|
||||
|
||||
SET @@GLOBAL.binlog_row_metadata='MINIMAl';
|
||||
SELECT *
|
||||
FROM information_schema.global_variables
|
||||
WHERE VARIABLE_NAME='binlog_row_metadata';
|
||||
|
||||
--echo '#---------------------BS_STVARS_002_04----------------------#'
|
||||
#################################################################
|
||||
# Check if the value in SESSION Table matches value in variable #
|
||||
#################################################################
|
||||
|
||||
SELECT *
|
||||
FROM information_schema.session_variables
|
||||
WHERE VARIABLE_NAME LIKE 'binlog_row_metadata';
|
||||
|
||||
--echo '#---------------------BS_STVARS_002_05----------------------#'
|
||||
################################################################################
|
||||
# Check if binlog_row_metadata can be accessed with and without @@ sign #
|
||||
################################################################################
|
||||
|
||||
SELECT COUNT(@@binlog_row_metadata);
|
||||
--echo 1 Expected
|
||||
SELECT COUNT(@@GLOBAL.binlog_row_metadata);
|
||||
--echo 1 Expected
|
||||
|
||||
--echo '#---------------------BS_STVARS_002_06----------------------#'
|
||||
################################################################################
|
||||
# Check if binlog_row_metadata can handle invalid values correctly #
|
||||
################################################################################
|
||||
--error ER_WRONG_VALUE_FOR_VAR
|
||||
SET GLOBAL binlog_row_metadata = full1;
|
||||
|
||||
--error ER_WRONG_VALUE_FOR_VAR
|
||||
SET GLOBAL binlog_row_metadata = "full1";
|
||||
|
||||
--error ER_WRONG_VALUE_FOR_VAR
|
||||
SET GLOBAL binlog_row_metadata = 3;
|
||||
|
||||
--error ER_WRONG_VALUE_FOR_VAR
|
||||
SET GLOBAL binlog_row_metadata = -1;
|
||||
|
||||
SET @@global.binlog_row_metadata= @start_value;
|
115
sql/field.cc
115
sql/field.cc
@@ -3493,11 +3493,12 @@ void Field_new_decimal::sql_type(String &str) const
|
||||
|
||||
@returns number of bytes written to metadata_ptr
|
||||
*/
|
||||
int Field_new_decimal::save_field_metadata(uchar *metadata_ptr)
|
||||
|
||||
Binlog_type_info Field_new_decimal::binlog_type_info() const
|
||||
{
|
||||
*metadata_ptr= precision;
|
||||
*(metadata_ptr + 1)= decimals();
|
||||
return 2;
|
||||
DBUG_ASSERT(Field_new_decimal::type() == binlog_type());
|
||||
return Binlog_type_info(Field_new_decimal::type(), precision +
|
||||
(decimals() << 8), 2, binlog_signess());
|
||||
}
|
||||
|
||||
|
||||
@@ -4665,10 +4666,11 @@ bool Field_float::send_binary(Protocol *protocol)
|
||||
|
||||
@returns number of bytes written to metadata_ptr
|
||||
*/
|
||||
int Field_float::save_field_metadata(uchar *metadata_ptr)
|
||||
Binlog_type_info Field_float::binlog_type_info() const
|
||||
{
|
||||
*metadata_ptr= pack_length();
|
||||
return 1;
|
||||
DBUG_ASSERT(Field_float::type() == binlog_type());
|
||||
return Binlog_type_info(Field_float::type(), pack_length(), 1,
|
||||
binlog_signess());
|
||||
}
|
||||
|
||||
|
||||
@@ -4976,10 +4978,11 @@ void Field_double::sort_string(uchar *to,uint length __attribute__((unused)))
|
||||
|
||||
@returns number of bytes written to metadata_ptr
|
||||
*/
|
||||
int Field_double::save_field_metadata(uchar *metadata_ptr)
|
||||
Binlog_type_info Field_double::binlog_type_info() const
|
||||
{
|
||||
*metadata_ptr= pack_length();
|
||||
return 1;
|
||||
DBUG_ASSERT(Field_double::type() == binlog_type());
|
||||
return Binlog_type_info(Field_double::type(), pack_length(), 1,
|
||||
binlog_signess());
|
||||
}
|
||||
|
||||
|
||||
@@ -5627,6 +5630,11 @@ bool Field_timestampf::val_native(Native *to)
|
||||
return Field::val_native(to);
|
||||
}
|
||||
|
||||
Binlog_type_info Field_timestampf::binlog_type_info() const
|
||||
{
|
||||
return Binlog_type_info(Field_timestampf::binlog_type(), decimals(), 1);
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************/
|
||||
sql_mode_t Field_temporal::can_handle_sql_mode_dependency_on_store() const
|
||||
@@ -6244,6 +6252,10 @@ bool Field_timef::get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
|
||||
TIME_from_longlong_time_packed(ltime, tmp);
|
||||
return false;
|
||||
}
|
||||
Binlog_type_info Field_timef::binlog_type_info() const
|
||||
{
|
||||
return Binlog_type_info(Field_timef::binlog_type(), decimals(), 1);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
** year type
|
||||
@@ -6955,6 +6967,10 @@ bool Field_datetimef::get_TIME(MYSQL_TIME *ltime, const uchar *pos,
|
||||
TIME_from_longlong_datetime_packed(ltime, tmp);
|
||||
return validate_MMDD(tmp, ltime->month, ltime->day, fuzzydate);
|
||||
}
|
||||
Binlog_type_info Field_datetimef::binlog_type_info() const
|
||||
{
|
||||
return Binlog_type_info(Field_datetimef::binlog_type(), decimals(), 1);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
** string type
|
||||
@@ -7536,15 +7552,16 @@ Field_string::unpack(uchar *to, const uchar *from, const uchar *from_end,
|
||||
|
||||
@returns number of bytes written to metadata_ptr
|
||||
*/
|
||||
int Field_string::save_field_metadata(uchar *metadata_ptr)
|
||||
Binlog_type_info Field_string::binlog_type_info() const
|
||||
{
|
||||
uint16 a;
|
||||
DBUG_ASSERT(field_length < 1024);
|
||||
DBUG_ASSERT((real_type() & 0xF0) == 0xF0);
|
||||
DBUG_PRINT("debug", ("field_length: %u, real_type: %u",
|
||||
field_length, real_type()));
|
||||
*metadata_ptr= (real_type() ^ ((field_length & 0x300) >> 4));
|
||||
*(metadata_ptr + 1)= field_length & 0xFF;
|
||||
return 2;
|
||||
field_length, real_type()));
|
||||
a= (real_type() ^ ((field_length & 0x300) >> 4)) + (((uint)(field_length & 0xFF)) << 8);
|
||||
DBUG_ASSERT(Field_string::type() == binlog_type());
|
||||
return Binlog_type_info(Field_string::type(), a, 2, charset());
|
||||
}
|
||||
|
||||
|
||||
@@ -7633,11 +7650,10 @@ const uint Field_varstring::MAX_SIZE= UINT_MAX16;
|
||||
|
||||
@returns number of bytes written to metadata_ptr
|
||||
*/
|
||||
int Field_varstring::save_field_metadata(uchar *metadata_ptr)
|
||||
Binlog_type_info Field_varstring::binlog_type_info() const
|
||||
{
|
||||
DBUG_ASSERT(field_length <= 65535);
|
||||
int2store((char*)metadata_ptr, field_length);
|
||||
return 2;
|
||||
DBUG_ASSERT(Field_varstring::type() == binlog_type());
|
||||
return Binlog_type_info(Field_varstring::type(), field_length, 2, charset());
|
||||
}
|
||||
|
||||
|
||||
@@ -8270,6 +8286,11 @@ int Field_varstring_compressed::cmp_max(const uchar *a_ptr, const uchar *b_ptr,
|
||||
|
||||
return sortcmp(&a, &b, field_charset());
|
||||
}
|
||||
Binlog_type_info Field_varstring_compressed::binlog_type_info() const
|
||||
{
|
||||
return Binlog_type_info(Field_varstring_compressed::binlog_type(),
|
||||
field_length, 2, charset());
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
@@ -8614,12 +8635,11 @@ Field *Field_blob::new_key_field(MEM_ROOT *root, TABLE *new_table,
|
||||
|
||||
@returns number of bytes written to metadata_ptr
|
||||
*/
|
||||
int Field_blob::save_field_metadata(uchar *metadata_ptr)
|
||||
Binlog_type_info Field_blob::binlog_type_info() const
|
||||
{
|
||||
DBUG_ENTER("Field_blob::save_field_metadata");
|
||||
*metadata_ptr= pack_length_no_ptr();
|
||||
DBUG_PRINT("debug", ("metadata: %u (pack_length_no_ptr)", *metadata_ptr));
|
||||
DBUG_RETURN(1);
|
||||
DBUG_ASSERT(Field_blob::type() == binlog_type());
|
||||
return Binlog_type_info(Field_blob::type(), pack_length_no_ptr(), 1,
|
||||
charset());
|
||||
}
|
||||
|
||||
|
||||
@@ -8874,6 +8894,11 @@ longlong Field_blob_compressed::val_int(void)
|
||||
buf.ptr(), buf.length()).result();
|
||||
}
|
||||
|
||||
Binlog_type_info Field_blob_compressed::binlog_type_info() const
|
||||
{
|
||||
return Binlog_type_info(Field_blob_compressed::binlog_type(),
|
||||
pack_length_no_ptr(), 1, charset());
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
** enum type.
|
||||
@@ -9008,11 +9033,11 @@ longlong Field_enum::val_int(const uchar *real_ptr) const
|
||||
|
||||
@returns number of bytes written to metadata_ptr
|
||||
*/
|
||||
int Field_enum::save_field_metadata(uchar *metadata_ptr)
|
||||
Binlog_type_info Field_enum::binlog_type_info() const
|
||||
{
|
||||
*metadata_ptr= real_type();
|
||||
*(metadata_ptr + 1)= pack_length();
|
||||
return 2;
|
||||
DBUG_ASSERT(Field_enum::type() == binlog_type());
|
||||
return Binlog_type_info(Field_enum::type(), real_type() + (pack_length() << 8),
|
||||
2, charset(), (TYPELIB *)get_typelib(), NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -9215,6 +9240,13 @@ void Field_set::sql_type(String &res) const
|
||||
res.append(')');
|
||||
}
|
||||
|
||||
Binlog_type_info Field_set::binlog_type_info() const
|
||||
{
|
||||
DBUG_ASSERT(Field_set::type() == binlog_type());
|
||||
return Binlog_type_info(Field_set::type(), real_type()
|
||||
+ (pack_length() << 8), 2, charset(), NULL, (TYPELIB *)get_typelib());
|
||||
}
|
||||
|
||||
/**
|
||||
@retval
|
||||
1 if the fields are equally defined
|
||||
@@ -9742,33 +9774,6 @@ uint Field_bit::get_key_image(uchar *buff, uint length, imagetype type_arg)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Save the field metadata for bit fields.
|
||||
|
||||
Saves the bit length in the first byte and bytes in record in the
|
||||
second byte of the field metadata array at index of *metadata_ptr and
|
||||
*(metadata_ptr + 1).
|
||||
|
||||
@param metadata_ptr First byte of field metadata
|
||||
|
||||
@returns number of bytes written to metadata_ptr
|
||||
*/
|
||||
int Field_bit::save_field_metadata(uchar *metadata_ptr)
|
||||
{
|
||||
DBUG_ENTER("Field_bit::save_field_metadata");
|
||||
DBUG_PRINT("debug", ("bit_len: %d, bytes_in_rec: %d",
|
||||
bit_len, bytes_in_rec));
|
||||
/*
|
||||
Since this class and Field_bit_as_char have different ideas of
|
||||
what should be stored here, we compute the values of the metadata
|
||||
explicitly using the field_length.
|
||||
*/
|
||||
metadata_ptr[0]= field_length % 8;
|
||||
metadata_ptr[1]= field_length / 8;
|
||||
DBUG_RETURN(2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Returns the number of bytes field uses in row-based replication
|
||||
row packed size.
|
||||
|
185
sql/field.h
185
sql/field.h
@@ -634,6 +634,91 @@ public:
|
||||
inline void print(String*);
|
||||
};
|
||||
|
||||
class Binlog_type_info
|
||||
{
|
||||
public:
|
||||
enum binlog_signess_t
|
||||
{
|
||||
SIGNED,
|
||||
UNSIGNED,
|
||||
SIGNESS_NOT_RELEVANT // for non-numeric types
|
||||
};
|
||||
uchar m_type_code; // according to Field::binlog_type()
|
||||
/**
|
||||
Retrieve the field metadata for fields.
|
||||
*/
|
||||
uint16 m_metadata;
|
||||
uint8 m_metadata_size;
|
||||
binlog_signess_t m_signess;
|
||||
CHARSET_INFO *m_cs; // NULL if not relevant
|
||||
TYPELIB *m_enum_typelib; // NULL if not relevant
|
||||
TYPELIB *m_set_typelib; // NULL if not relevant
|
||||
uchar m_geom_type; // Non-geometry fields can return 0
|
||||
Binlog_type_info(uchar type_code,
|
||||
uint16 metadata,
|
||||
uint8 metadata_size)
|
||||
:m_type_code(type_code),
|
||||
m_metadata(metadata),
|
||||
m_metadata_size(metadata_size),
|
||||
m_signess(SIGNESS_NOT_RELEVANT),
|
||||
m_cs(NULL),
|
||||
m_enum_typelib(NULL),
|
||||
m_set_typelib(NULL),
|
||||
m_geom_type(0)
|
||||
{};
|
||||
Binlog_type_info(uchar type_code, uint16 metadata,
|
||||
uint8 metadata_size,
|
||||
binlog_signess_t signess)
|
||||
:m_type_code(type_code),
|
||||
m_metadata(metadata),
|
||||
m_metadata_size(metadata_size),
|
||||
m_signess(signess),
|
||||
m_cs(NULL),
|
||||
m_enum_typelib(NULL),
|
||||
m_set_typelib(NULL),
|
||||
m_geom_type(0)
|
||||
{};
|
||||
Binlog_type_info(uchar type_code, uint16 metadata,
|
||||
uint8 metadata_size,
|
||||
CHARSET_INFO *cs)
|
||||
:m_type_code(type_code),
|
||||
m_metadata(metadata),
|
||||
m_metadata_size(metadata_size),
|
||||
m_signess(SIGNESS_NOT_RELEVANT),
|
||||
m_cs(cs),
|
||||
m_enum_typelib(NULL),
|
||||
m_set_typelib(NULL),
|
||||
m_geom_type(0)
|
||||
{};
|
||||
Binlog_type_info(uchar type_code, uint16 metadata,
|
||||
uint8 metadata_size,
|
||||
CHARSET_INFO *cs,
|
||||
TYPELIB *t_enum, TYPELIB *t_set)
|
||||
:m_type_code(type_code),
|
||||
m_metadata(metadata),
|
||||
m_metadata_size(metadata_size),
|
||||
m_signess(SIGNESS_NOT_RELEVANT),
|
||||
m_cs(cs),
|
||||
m_enum_typelib(t_enum),
|
||||
m_set_typelib(t_set),
|
||||
m_geom_type(0)
|
||||
{};
|
||||
Binlog_type_info(uchar type_code, uint16 metadata,
|
||||
uint8 metadata_size, CHARSET_INFO *cs,
|
||||
uchar geom_type)
|
||||
:m_type_code(type_code),
|
||||
m_metadata(metadata),
|
||||
m_metadata_size(metadata_size),
|
||||
m_signess(SIGNESS_NOT_RELEVANT),
|
||||
m_cs(cs),
|
||||
m_enum_typelib(NULL),
|
||||
m_set_typelib(NULL),
|
||||
m_geom_type(geom_type)
|
||||
{};
|
||||
static void *operator new(size_t size, MEM_ROOT *mem_root) throw ()
|
||||
{ return alloc_root(mem_root, size); }
|
||||
};
|
||||
|
||||
class Field: public Value_source
|
||||
{
|
||||
Field(const Item &); /* Prevent use of these */
|
||||
@@ -953,21 +1038,6 @@ public:
|
||||
}
|
||||
virtual uint row_pack_length() const { return 0; }
|
||||
|
||||
|
||||
/**
|
||||
Retrieve the field metadata for fields.
|
||||
|
||||
This default implementation returns 0 and saves 0 in the first_byte value.
|
||||
|
||||
@param first_byte First byte of field metadata
|
||||
|
||||
@returns 0 no bytes written.
|
||||
*/
|
||||
|
||||
virtual int save_field_metadata(uchar *first_byte)
|
||||
{ return 0; }
|
||||
|
||||
|
||||
/*
|
||||
data_length() return the "real size" of the data in memory.
|
||||
*/
|
||||
@@ -1110,6 +1180,11 @@ public:
|
||||
*/
|
||||
return type();
|
||||
}
|
||||
virtual Binlog_type_info binlog_type_info() const
|
||||
{
|
||||
DBUG_ASSERT(Field::type() == binlog_type());
|
||||
return Binlog_type_info(Field::type(), 0, 0);
|
||||
}
|
||||
virtual en_fieldtype tmp_engine_column_type(bool use_packed_rows) const
|
||||
{
|
||||
return FIELD_NORMAL;
|
||||
@@ -1820,6 +1895,11 @@ protected:
|
||||
void prepend_zeros(String *value) const;
|
||||
Item *get_equal_zerofill_const_item(THD *thd, const Context &ctx,
|
||||
Item *const_item);
|
||||
Binlog_type_info::binlog_signess_t binlog_signess() const
|
||||
{
|
||||
return (flags & UNSIGNED_FLAG) ? Binlog_type_info::UNSIGNED :
|
||||
Binlog_type_info::SIGNED;
|
||||
}
|
||||
public:
|
||||
const uint8 dec;
|
||||
bool zerofill,unsigned_flag; // Purify cannot handle bit fields
|
||||
@@ -1874,6 +1954,11 @@ public:
|
||||
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
|
||||
const Item_bool_func *cond,
|
||||
scalar_comparison_op op, Item *value);
|
||||
Binlog_type_info binlog_type_info() const
|
||||
{
|
||||
DBUG_ASSERT(Field_num::type() == binlog_type());
|
||||
return Binlog_type_info(Field_num::type(), 0, 0, binlog_signess());
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1938,6 +2023,11 @@ public:
|
||||
SEL_ARG *get_mm_leaf(RANGE_OPT_PARAM *param, KEY_PART *key_part,
|
||||
const Item_bool_func *cond,
|
||||
scalar_comparison_op op, Item *value);
|
||||
Binlog_type_info binlog_type_info() const
|
||||
{
|
||||
DBUG_ASSERT(Field_str::type() == binlog_type());
|
||||
return Binlog_type_info(Field_str::type(), 0, 0, charset());
|
||||
}
|
||||
};
|
||||
|
||||
/* base class for Field_string, Field_varstring and Field_blob */
|
||||
@@ -2114,8 +2204,6 @@ public:
|
||||
|
||||
/* New decimal/numeric field which use fixed point arithmetic */
|
||||
class Field_new_decimal :public Field_num {
|
||||
private:
|
||||
int save_field_metadata(uchar *first_byte);
|
||||
public:
|
||||
/* The maximum number of decimal digits can be stored */
|
||||
uint precision;
|
||||
@@ -2212,6 +2300,7 @@ public:
|
||||
bool is_equal(const Column_definition &new_field) const;
|
||||
virtual const uchar *unpack(uchar* to, const uchar *from, const uchar *from_end, uint param_data);
|
||||
Item *get_equal_const_item(THD *thd, const Context &ctx, Item *const_item);
|
||||
Binlog_type_info binlog_type_info() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -2638,8 +2727,7 @@ public:
|
||||
*/
|
||||
return 0x1000000ULL;
|
||||
}
|
||||
private:
|
||||
int save_field_metadata(uchar *first_byte);
|
||||
Binlog_type_info binlog_type_info() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -2703,8 +2791,7 @@ public:
|
||||
*/
|
||||
return 0x20000000000000ULL;
|
||||
}
|
||||
private:
|
||||
int save_field_metadata(uchar *first_byte);
|
||||
Binlog_type_info binlog_type_info() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -3048,11 +3135,6 @@ public:
|
||||
TIMESTAMP(0..6) - MySQL56 version
|
||||
*/
|
||||
class Field_timestampf :public Field_timestamp_with_dec {
|
||||
int save_field_metadata(uchar *metadata_ptr)
|
||||
{
|
||||
*metadata_ptr= (uchar) decimals();
|
||||
return 1;
|
||||
}
|
||||
void store_TIMEVAL(const timeval &tv);
|
||||
public:
|
||||
Field_timestampf(uchar *ptr_arg,
|
||||
@@ -3092,6 +3174,7 @@ public:
|
||||
}
|
||||
bool val_native(Native *to);
|
||||
uint size_of() const { return sizeof(*this); }
|
||||
Binlog_type_info binlog_type_info() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -3376,11 +3459,6 @@ public:
|
||||
*/
|
||||
class Field_timef :public Field_time_with_dec {
|
||||
void store_TIME(const MYSQL_TIME *ltime);
|
||||
int save_field_metadata(uchar *metadata_ptr)
|
||||
{
|
||||
*metadata_ptr= (uchar) decimals();
|
||||
return 1;
|
||||
}
|
||||
public:
|
||||
Field_timef(uchar *ptr_arg, uchar *null_ptr_arg, uchar null_bit_arg,
|
||||
enum utype unireg_check_arg, const LEX_CSTRING *field_name_arg,
|
||||
@@ -3419,6 +3497,7 @@ public:
|
||||
int reset();
|
||||
bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate);
|
||||
uint size_of() const { return sizeof(*this); }
|
||||
Binlog_type_info binlog_type_info() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -3545,11 +3624,6 @@ public:
|
||||
class Field_datetimef :public Field_datetime_with_dec {
|
||||
void store_TIME(const MYSQL_TIME *ltime);
|
||||
bool get_TIME(MYSQL_TIME *ltime, const uchar *pos, date_mode_t fuzzydate) const;
|
||||
int save_field_metadata(uchar *metadata_ptr)
|
||||
{
|
||||
*metadata_ptr= (uchar) decimals();
|
||||
return 1;
|
||||
}
|
||||
public:
|
||||
Field_datetimef(uchar *ptr_arg, uchar *null_ptr_arg,
|
||||
uchar null_bit_arg, enum utype unireg_check_arg,
|
||||
@@ -3581,6 +3655,7 @@ public:
|
||||
bool get_date(MYSQL_TIME *ltime, date_mode_t fuzzydate)
|
||||
{ return Field_datetimef::get_TIME(ltime, ptr, fuzzydate); }
|
||||
uint size_of() const { return sizeof(*this); }
|
||||
Binlog_type_info binlog_type_info() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -3726,8 +3801,7 @@ public:
|
||||
sql_mode_t value_depends_on_sql_mode() const;
|
||||
sql_mode_t can_handle_sql_mode_dependency_on_store() const;
|
||||
void print_key_value(String *out, uint32 length);
|
||||
private:
|
||||
int save_field_metadata(uchar *first_byte);
|
||||
Binlog_type_info binlog_type_info() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -3843,8 +3917,7 @@ public:
|
||||
void hash(ulong *nr, ulong *nr2);
|
||||
uint length_size() const { return length_bytes; }
|
||||
void print_key_value(String *out, uint32 length);
|
||||
private:
|
||||
int save_field_metadata(uchar *first_byte);
|
||||
Binlog_type_info binlog_type_info() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -3893,6 +3966,7 @@ private:
|
||||
int key_cmp(const uchar *str, uint length) const
|
||||
{ DBUG_ASSERT(0); return 0; }
|
||||
using Field_varstring::key_cmp;
|
||||
Binlog_type_info binlog_type_info() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -4200,12 +4274,10 @@ public:
|
||||
return table->file->can_convert_blob(this, new_type);
|
||||
}
|
||||
void print_key_value(String *out, uint32 length);
|
||||
Binlog_type_info binlog_type_info() const;
|
||||
|
||||
friend void TABLE::remember_blob_values(String *blob_storage);
|
||||
friend void TABLE::restore_blob_values(String *blob_storage);
|
||||
|
||||
private:
|
||||
int save_field_metadata(uchar *first_byte);
|
||||
};
|
||||
|
||||
|
||||
@@ -4253,6 +4325,7 @@ private:
|
||||
uchar *new_ptr, uint32 length,
|
||||
uchar *new_null_ptr, uint new_null_bit)
|
||||
{ DBUG_ASSERT(0); return 0; }
|
||||
Binlog_type_info binlog_type_info() const;
|
||||
};
|
||||
|
||||
|
||||
@@ -4364,8 +4437,8 @@ public:
|
||||
bool can_optimize_range(const Item_bool_func *cond,
|
||||
const Item *item,
|
||||
bool is_eq_func) const;
|
||||
Binlog_type_info binlog_type_info() const;
|
||||
private:
|
||||
int save_field_metadata(uchar *first_byte);
|
||||
bool is_equal(const Column_definition &new_field) const;
|
||||
};
|
||||
|
||||
@@ -4401,6 +4474,7 @@ public:
|
||||
uint size_of() const { return sizeof(*this); }
|
||||
const Type_handler *type_handler() const { return &type_handler_set; }
|
||||
bool has_charset(void) const { return TRUE; }
|
||||
Binlog_type_info binlog_type_info() const;
|
||||
private:
|
||||
const String empty_set_string;
|
||||
};
|
||||
@@ -4573,10 +4647,31 @@ public:
|
||||
{
|
||||
val_int_as_str(out, 1);
|
||||
}
|
||||
/**
|
||||
Save the field metadata for bit fields.
|
||||
Saves the bit length in the first byte and bytes in record in the
|
||||
second byte of the field metadata array at index of *metadata_ptr and
|
||||
*(metadata_ptr + 1).
|
||||
|
||||
@param metadata_ptr First byte of field metadata
|
||||
|
||||
@returns number of bytes written to metadata_ptr
|
||||
*/
|
||||
Binlog_type_info binlog_type_info() const
|
||||
{
|
||||
DBUG_PRINT("debug", ("bit_len: %d, bytes_in_rec: %d",
|
||||
bit_len, bytes_in_rec));
|
||||
/*
|
||||
Since this class and Field_bit_as_char have different ideas of
|
||||
what should be stored here, we compute the values of the metadata
|
||||
explicitly using the field_length.
|
||||
*/
|
||||
return Binlog_type_info(type(),
|
||||
field_length % 8 + ((field_length / 8) << 8), 2);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual size_t do_last_null_byte() const;
|
||||
int save_field_metadata(uchar *first_byte);
|
||||
};
|
||||
|
||||
|
||||
|
254
sql/log_event.cc
254
sql/log_event.cc
@@ -3428,7 +3428,8 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
|
||||
m_colcnt(0), m_coltype(0),
|
||||
m_memory(NULL), m_table_id(ULONGLONG_MAX), m_flags(0),
|
||||
m_data_size(0), m_field_metadata(0), m_field_metadata_size(0),
|
||||
m_null_bits(0), m_meta_memory(NULL)
|
||||
m_null_bits(0), m_meta_memory(NULL),
|
||||
m_optional_metadata_len(0), m_optional_metadata(NULL)
|
||||
{
|
||||
unsigned int bytes_read= 0;
|
||||
DBUG_ENTER("Table_map_log_event::Table_map_log_event(const char*,uint,...)");
|
||||
@@ -3517,8 +3518,28 @@ Table_map_log_event::Table_map_log_event(const char *buf, uint event_len,
|
||||
memcpy(m_field_metadata, ptr_after_colcnt, m_field_metadata_size);
|
||||
ptr_after_colcnt= (uchar*)ptr_after_colcnt + m_field_metadata_size;
|
||||
memcpy(m_null_bits, ptr_after_colcnt, num_null_bytes);
|
||||
ptr_after_colcnt= (unsigned char*)ptr_after_colcnt + num_null_bytes;
|
||||
}
|
||||
|
||||
bytes_read= (uint) (ptr_after_colcnt - (uchar *)buf);
|
||||
|
||||
/* After null_bits field, there are some new fields for extra metadata. */
|
||||
if (bytes_read < event_len)
|
||||
{
|
||||
m_optional_metadata_len= event_len - bytes_read;
|
||||
m_optional_metadata=
|
||||
static_cast<unsigned char*>(my_malloc(m_optional_metadata_len, MYF(MY_WME)));
|
||||
memcpy(m_optional_metadata, ptr_after_colcnt, m_optional_metadata_len);
|
||||
}
|
||||
}
|
||||
#ifdef MYSQL_SERVER
|
||||
if (!m_table)
|
||||
DBUG_VOID_RETURN;
|
||||
binlog_type_info_array= (Binlog_type_info *)thd->alloc(m_table->s->fields *
|
||||
sizeof(Binlog_type_info));
|
||||
for (uint i= 0; i < m_table->s->fields; i++)
|
||||
binlog_type_info_array[i]= m_table->field[i]->binlog_type_info();
|
||||
#endif
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@@ -3528,6 +3549,237 @@ Table_map_log_event::~Table_map_log_event()
|
||||
{
|
||||
my_free(m_meta_memory);
|
||||
my_free(m_memory);
|
||||
my_free(m_optional_metadata);
|
||||
m_optional_metadata= NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
Parses SIGNEDNESS field.
|
||||
|
||||
@param[out] vec stores the signedness flags extracted from field.
|
||||
@param[in] field SIGNEDNESS field in table_map_event.
|
||||
@param[in] length length of the field
|
||||
*/
|
||||
static void parse_signedness(std::vector<bool> &vec,
|
||||
unsigned char *field, unsigned int length)
|
||||
{
|
||||
for (unsigned int i= 0; i < length; i++)
|
||||
{
|
||||
for (unsigned char c= 0x80; c != 0; c>>= 1)
|
||||
vec.push_back(field[i] & c);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Parses DEFAULT_CHARSET field.
|
||||
|
||||
@param[out] default_charset stores collation numbers extracted from field.
|
||||
@param[in] field DEFAULT_CHARSET field in table_map_event.
|
||||
@param[in] length length of the field
|
||||
*/
|
||||
static void parse_default_charset(Table_map_log_event::Optional_metadata_fields::
|
||||
Default_charset &default_charset,
|
||||
unsigned char *field, unsigned int length)
|
||||
{
|
||||
unsigned char* p= field;
|
||||
|
||||
default_charset.default_charset= net_field_length(&p);
|
||||
while (p < field + length)
|
||||
{
|
||||
unsigned int col_index= net_field_length(&p);
|
||||
unsigned int col_charset= net_field_length(&p);
|
||||
|
||||
default_charset.charset_pairs.push_back(std::make_pair(col_index,
|
||||
col_charset));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Parses COLUMN_CHARSET field.
|
||||
|
||||
@param[out] vec stores collation numbers extracted from field.
|
||||
@param[in] field COLUMN_CHARSET field in table_map_event.
|
||||
@param[in] length length of the field
|
||||
*/
|
||||
static void parse_column_charset(std::vector<unsigned int> &vec,
|
||||
unsigned char *field, unsigned int length)
|
||||
{
|
||||
unsigned char* p= field;
|
||||
|
||||
while (p < field + length)
|
||||
vec.push_back(net_field_length(&p));
|
||||
}
|
||||
|
||||
/**
|
||||
Parses COLUMN_NAME field.
|
||||
|
||||
@param[out] vec stores column names extracted from field.
|
||||
@param[in] field COLUMN_NAME field in table_map_event.
|
||||
@param[in] length length of the field
|
||||
*/
|
||||
static void parse_column_name(std::vector<std::string> &vec,
|
||||
unsigned char *field, unsigned int length)
|
||||
{
|
||||
unsigned char* p= field;
|
||||
|
||||
while (p < field + length)
|
||||
{
|
||||
unsigned len= net_field_length(&p);
|
||||
vec.push_back(std::string(reinterpret_cast<char *>(p), len));
|
||||
p+= len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Parses SET_STR_VALUE/ENUM_STR_VALUE field.
|
||||
|
||||
@param[out] vec stores SET/ENUM column's string values extracted from
|
||||
field. Each SET/ENUM column's string values are stored
|
||||
into a string separate vector. All of them are stored
|
||||
in 'vec'.
|
||||
@param[in] field COLUMN_NAME field in table_map_event.
|
||||
@param[in] length length of the field
|
||||
*/
|
||||
static void parse_set_str_value(std::vector<Table_map_log_event::
|
||||
Optional_metadata_fields::str_vector> &vec,
|
||||
unsigned char *field, unsigned int length)
|
||||
{
|
||||
unsigned char* p= field;
|
||||
|
||||
while (p < field + length)
|
||||
{
|
||||
unsigned int count= net_field_length(&p);
|
||||
|
||||
vec.push_back(std::vector<std::string>());
|
||||
for (unsigned int i= 0; i < count; i++)
|
||||
{
|
||||
unsigned len1= net_field_length(&p);
|
||||
vec.back().push_back(std::string(reinterpret_cast<char *>(p), len1));
|
||||
p+= len1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Parses GEOMETRY_TYPE field.
|
||||
|
||||
@param[out] vec stores geometry column's types extracted from field.
|
||||
@param[in] field GEOMETRY_TYPE field in table_map_event.
|
||||
@param[in] length length of the field
|
||||
*/
|
||||
static void parse_geometry_type(std::vector<unsigned int> &vec,
|
||||
unsigned char *field, unsigned int length)
|
||||
{
|
||||
unsigned char* p= field;
|
||||
|
||||
while (p < field + length)
|
||||
vec.push_back(net_field_length(&p));
|
||||
}
|
||||
|
||||
/**
|
||||
Parses SIMPLE_PRIMARY_KEY field.
|
||||
|
||||
@param[out] vec stores primary key's column information extracted from
|
||||
field. Each column has an index and a prefix which are
|
||||
stored as a unit_pair. prefix is always 0 for
|
||||
SIMPLE_PRIMARY_KEY field.
|
||||
@param[in] field SIMPLE_PRIMARY_KEY field in table_map_event.
|
||||
@param[in] length length of the field
|
||||
*/
|
||||
static void parse_simple_pk(std::vector<Table_map_log_event::
|
||||
Optional_metadata_fields::uint_pair> &vec,
|
||||
unsigned char *field, unsigned int length)
|
||||
{
|
||||
unsigned char* p= field;
|
||||
|
||||
while (p < field + length)
|
||||
vec.push_back(std::make_pair(net_field_length(&p), 0));
|
||||
}
|
||||
|
||||
/**
|
||||
Parses PRIMARY_KEY_WITH_PREFIX field.
|
||||
|
||||
@param[out] vec stores primary key's column information extracted from
|
||||
field. Each column has an index and a prefix which are
|
||||
stored as a unit_pair.
|
||||
@param[in] field PRIMARY_KEY_WITH_PREFIX field in table_map_event.
|
||||
@param[in] length length of the field
|
||||
*/
|
||||
|
||||
static void parse_pk_with_prefix(std::vector<Table_map_log_event::
|
||||
Optional_metadata_fields::uint_pair> &vec,
|
||||
unsigned char *field, unsigned int length)
|
||||
{
|
||||
unsigned char* p= field;
|
||||
|
||||
while (p < field + length)
|
||||
{
|
||||
unsigned int col_index= net_field_length(&p);
|
||||
unsigned int col_prefix= net_field_length(&p);
|
||||
vec.push_back(std::make_pair(col_index, col_prefix));
|
||||
}
|
||||
}
|
||||
|
||||
Table_map_log_event::Optional_metadata_fields::
|
||||
Optional_metadata_fields(unsigned char* optional_metadata,
|
||||
unsigned int optional_metadata_len)
|
||||
{
|
||||
unsigned char* field= optional_metadata;
|
||||
|
||||
if (optional_metadata == NULL)
|
||||
return;
|
||||
|
||||
while (field < optional_metadata + optional_metadata_len)
|
||||
{
|
||||
unsigned int len;
|
||||
Optional_metadata_field_type type=
|
||||
static_cast<Optional_metadata_field_type>(field[0]);
|
||||
|
||||
// Get length and move field to the value.
|
||||
field++;
|
||||
len= net_field_length(&field);
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case SIGNEDNESS:
|
||||
parse_signedness(m_signedness, field, len);
|
||||
break;
|
||||
case DEFAULT_CHARSET:
|
||||
parse_default_charset(m_default_charset, field, len);
|
||||
break;
|
||||
case COLUMN_CHARSET:
|
||||
parse_column_charset(m_column_charset, field, len);
|
||||
break;
|
||||
case COLUMN_NAME:
|
||||
parse_column_name(m_column_name, field, len);
|
||||
break;
|
||||
case SET_STR_VALUE:
|
||||
parse_set_str_value(m_set_str_value, field, len);
|
||||
break;
|
||||
case ENUM_STR_VALUE:
|
||||
parse_set_str_value(m_enum_str_value, field, len);
|
||||
break;
|
||||
case GEOMETRY_TYPE:
|
||||
parse_geometry_type(m_geometry_type, field, len);
|
||||
break;
|
||||
case SIMPLE_PRIMARY_KEY:
|
||||
parse_simple_pk(m_primary_key, field, len);
|
||||
break;
|
||||
case PRIMARY_KEY_WITH_PREFIX:
|
||||
parse_pk_with_prefix(m_primary_key, field, len);
|
||||
break;
|
||||
case ENUM_AND_SET_DEFAULT_CHARSET:
|
||||
parse_default_charset(m_enum_and_set_default_charset, field, len);
|
||||
break;
|
||||
case ENUM_AND_SET_COLUMN_CHARSET:
|
||||
parse_column_charset(m_enum_and_set_column_charset, field, len);
|
||||
break;
|
||||
default:
|
||||
DBUG_ASSERT(0);
|
||||
}
|
||||
// next field
|
||||
field+= len;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
302
sql/log_event.h
302
sql/log_event.h
@@ -35,6 +35,11 @@
|
||||
|
||||
#include <my_bitmap.h>
|
||||
#include "rpl_constants.h"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <map>
|
||||
|
||||
#ifdef MYSQL_CLIENT
|
||||
#include "sql_const.h"
|
||||
@@ -791,7 +796,6 @@ enum Int_event_type
|
||||
INVALID_INT_EVENT = 0, LAST_INSERT_ID_EVENT = 1, INSERT_ID_EVENT = 2
|
||||
};
|
||||
|
||||
|
||||
#ifdef MYSQL_SERVER
|
||||
class String;
|
||||
class MYSQL_BIN_LOG;
|
||||
@@ -881,6 +885,7 @@ typedef struct st_print_event_info
|
||||
statement for it.
|
||||
*/
|
||||
bool skip_replication;
|
||||
bool print_table_metadata;
|
||||
|
||||
/*
|
||||
These two caches are used by the row-based replication events to
|
||||
@@ -4063,6 +4068,18 @@ private:
|
||||
ninth is in the least significant bit of the second byte, and so
|
||||
on. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>optional metadata fields</td>
|
||||
<td>optional metadata fields are stored in Type, Length, Value(TLV) format.
|
||||
Type takes 1 byte. Length is a packed integer value. Values takes
|
||||
Length bytes.
|
||||
</td>
|
||||
<td>There are some optional metadata defined. They are listed in the table
|
||||
@ref Table_table_map_event_optional_metadata. Optional metadata fields
|
||||
follow null_bits. Whether binlogging an optional metadata is decided by the
|
||||
server. The order is not defined, so they can be binlogged in any order.
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
@@ -4268,6 +4285,123 @@ private:
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
The table below lists all optional metadata types, along with the numerical
|
||||
identifier for it and the size and interpretation of meta-data used
|
||||
to describe the type.
|
||||
|
||||
@anchor Table_table_map_event_optional_metadata
|
||||
<table>
|
||||
<caption>Table_map_event optional metadata types: numerical identifier and
|
||||
metadata. Optional metadata fields are stored in TLV fields.
|
||||
Format of values are described in this table. </caption>
|
||||
<tr>
|
||||
<th>Type</th>
|
||||
<th>Description</th>
|
||||
<th>Format</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SIGNEDNESS</td>
|
||||
<td>signedness of numeric colums. This is included for all values of
|
||||
binlog_row_metadata.</td>
|
||||
<td>For each numeric column, a bit indicates whether the numeric
|
||||
colunm has unsigned flag. 1 means it is unsigned. The number of
|
||||
bytes needed for this is int((column_count + 7) / 8). The order is
|
||||
the same as the order of column_type field.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>DEFAULT_CHARSET</td>
|
||||
<td>Charsets of character columns. It has a default charset for
|
||||
the case that most of character columns have same charset and the
|
||||
most used charset is binlogged as default charset.Collation
|
||||
numbers are binlogged for identifying charsets. They are stored in
|
||||
packed length format. Either DEFAULT_CHARSET or COLUMN_CHARSET is
|
||||
included for all values of binlog_row_metadata.</td>
|
||||
<td>Default charset's collation is logged first. The charsets which are not
|
||||
same to default charset are logged following default charset. They are
|
||||
logged as column index and charset collation number pair sequence. The
|
||||
column index is counted only in all character columns. The order is same to
|
||||
the order of column_type
|
||||
field. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>COLUMN_CHARSET</td>
|
||||
<td>Charsets of character columns. For the case that most of columns have
|
||||
different charsets, this field is logged. It is never logged with
|
||||
DEFAULT_CHARSET together. Either DEFAULT_CHARSET or COLUMN_CHARSET is
|
||||
included for all values of binlog_row_metadata.</td>
|
||||
<td>It is a collation number sequence for all character columns.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>COLUMN_NAME</td>
|
||||
<td>Names of columns. This is only included if
|
||||
binlog_row_metadata=FULL.</td>
|
||||
<td>A sequence of column names. For each column name, 1 byte for
|
||||
the string length in bytes is followed by a string without null
|
||||
terminator.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SET_STR_VALUE</td>
|
||||
<td>The string values of SET columns. This is only included if
|
||||
binlog_row_metadata=FULL.</td>
|
||||
<td>For each SET column, a pack_length representing the value
|
||||
count is followed by a sequence of length and string pairs. length
|
||||
is the byte count in pack_length format. The string has no null
|
||||
terminator.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ENUM_STR_VALUE</td>
|
||||
<td>The string values is ENUM columns. This is only included
|
||||
if binlog_row_metadata=FULL.</td>
|
||||
<td>The format is the same as SET_STR_VALUE.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>GEOMETRY_TYPE</td>
|
||||
<td>The real type of geometry columns. This is only included
|
||||
if binlog_row_metadata=FULL.</td>
|
||||
<td>A sequence of real type of geometry columns are stored in pack_length
|
||||
format. </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SIMPLE_PRIMARY_KEY</td>
|
||||
<td>The primary key without any prefix. This is only included
|
||||
if binlog_row_metadata=FULL and there is a primary key where every
|
||||
key part covers an entire column.</td>
|
||||
<td>A sequence of column indexes. The indexes are stored in pack_length
|
||||
format.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>PRIMARY_KEY_WITH_PREFIX</td>
|
||||
<td>The primary key with some prefix. It doesn't appear together with
|
||||
SIMPLE_PRIMARY_KEY. This is only included if
|
||||
binlog_row_metadata=FULL and there is a primary key where some key
|
||||
part covers a prefix of the column.</td>
|
||||
<td>A sequence of column index and prefix length pairs. Both
|
||||
column index and prefix length are in pack_length format. Prefix length
|
||||
0 means that the whole column value is used.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ENUM_AND_SET_DEFAULT_CHARSET</td>
|
||||
<td>Charsets of ENUM and SET columns. It has the same layout as
|
||||
DEFAULT_CHARSET. If there are SET or ENUM columns and
|
||||
binlog_row_metadata=FULL, exactly one of
|
||||
ENUM_AND_SET_DEFAULT_CHARSET and ENUM_AND_SET_COLUMN_CHARSET
|
||||
appears (the encoder chooses the representation that uses the
|
||||
least amount of space). Otherwise, none of them appears.</td>
|
||||
<td>The same format as for DEFAULT_CHARSET, except it counts ENUM
|
||||
and SET columns rather than character columns.</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ENUM_AND_SET_COLUMN_CHARSET</td>
|
||||
<td>Charsets of ENUM and SET columns. It has the same layout as
|
||||
COLUMN_CHARSET. If there are SET or ENUM columns and
|
||||
binlog_row_metadata=FULL, exactly one of
|
||||
ENUM_AND_SET_DEFAULT_CHARSET and ENUM_AND_SET_COLUMN_CHARSET
|
||||
appears (the encoder chooses the representation that uses the
|
||||
least amount of space). Otherwise, none of them appears.</td>
|
||||
<td>The same format as for COLUMN_CHARSET, except it counts ENUM
|
||||
and SET columns rather than character columns.</td>
|
||||
</tr>
|
||||
</table>
|
||||
*/
|
||||
class Table_map_log_event : public Log_event
|
||||
{
|
||||
@@ -4303,6 +4437,124 @@ public:
|
||||
};
|
||||
|
||||
typedef uint16 flag_set;
|
||||
/**
|
||||
DEFAULT_CHARSET and COLUMN_CHARSET don't appear together, and
|
||||
ENUM_AND_SET_DEFAULT_CHARSET and ENUM_AND_SET_COLUMN_CHARSET don't
|
||||
appear together. They are just alternative ways to pack character
|
||||
set information. When binlogging, it logs character sets in the
|
||||
way that occupies least storage.
|
||||
|
||||
SIMPLE_PRIMARY_KEY and PRIMARY_KEY_WITH_PREFIX don't appear together.
|
||||
SIMPLE_PRIMARY_KEY is for the primary keys which only use whole values of
|
||||
pk columns. PRIMARY_KEY_WITH_PREFIX is
|
||||
for the primary keys which just use part value of pk columns.
|
||||
*/
|
||||
enum Optional_metadata_field_type
|
||||
{
|
||||
SIGNEDNESS = 1, // UNSIGNED flag of numeric columns
|
||||
DEFAULT_CHARSET, /* Character set of string columns, optimized to
|
||||
minimize space when many columns have the
|
||||
same charset. */
|
||||
COLUMN_CHARSET, /* Character set of string columns, optimized to
|
||||
minimize space when columns have many
|
||||
different charsets. */
|
||||
COLUMN_NAME,
|
||||
SET_STR_VALUE, // String value of SET columns
|
||||
ENUM_STR_VALUE, // String value of ENUM columns
|
||||
GEOMETRY_TYPE, // Real type of geometry columns
|
||||
SIMPLE_PRIMARY_KEY, // Primary key without prefix
|
||||
PRIMARY_KEY_WITH_PREFIX, // Primary key with prefix
|
||||
ENUM_AND_SET_DEFAULT_CHARSET, /* Character set of enum and set
|
||||
columns, optimized to minimize
|
||||
space when many columns have the
|
||||
same charset. */
|
||||
ENUM_AND_SET_COLUMN_CHARSET, /* Character set of enum and set
|
||||
columns, optimized to minimize
|
||||
space when many columns have the
|
||||
same charset. */
|
||||
};
|
||||
/**
|
||||
Metadata_fields organizes m_optional_metadata into a structured format which
|
||||
is easy to access.
|
||||
*/
|
||||
// Values for binlog_row_metadata sysvar
|
||||
enum enum_binlog_row_metadata
|
||||
{
|
||||
BINLOG_ROW_METADATA_NO_LOG= 0,
|
||||
BINLOG_ROW_METADATA_MINIMAL= 1,
|
||||
BINLOG_ROW_METADATA_FULL= 2
|
||||
};
|
||||
struct Optional_metadata_fields
|
||||
{
|
||||
typedef std::pair<unsigned int, unsigned int> uint_pair;
|
||||
typedef std::vector<std::string> str_vector;
|
||||
|
||||
struct Default_charset
|
||||
{
|
||||
Default_charset() : default_charset(0) {}
|
||||
bool empty() const { return default_charset == 0; }
|
||||
|
||||
// Default charset for the columns which are not in charset_pairs.
|
||||
unsigned int default_charset;
|
||||
|
||||
/* The uint_pair means <column index, column charset number>. */
|
||||
std::vector<uint_pair> charset_pairs;
|
||||
};
|
||||
|
||||
// Contents of DEFAULT_CHARSET field is converted into Default_charset.
|
||||
Default_charset m_default_charset;
|
||||
// Contents of ENUM_AND_SET_DEFAULT_CHARSET are converted into
|
||||
// Default_charset.
|
||||
Default_charset m_enum_and_set_default_charset;
|
||||
std::vector<bool> m_signedness;
|
||||
// Character set number of every string column
|
||||
std::vector<unsigned int> m_column_charset;
|
||||
// Character set number of every ENUM or SET column.
|
||||
std::vector<unsigned int> m_enum_and_set_column_charset;
|
||||
std::vector<std::string> m_column_name;
|
||||
// each str_vector stores values of one enum/set column
|
||||
std::vector<str_vector> m_enum_str_value;
|
||||
std::vector<str_vector> m_set_str_value;
|
||||
std::vector<unsigned int> m_geometry_type;
|
||||
/*
|
||||
The uint_pair means <column index, prefix length>. Prefix length is 0 if
|
||||
whole column value is used.
|
||||
*/
|
||||
std::vector<uint_pair> m_primary_key;
|
||||
|
||||
/*
|
||||
It parses m_optional_metadata and populates into above variables.
|
||||
|
||||
@param[in] optional_metadata points to the begin of optional metadata
|
||||
fields in table_map_event.
|
||||
@param[in] optional_metadata_len length of optional_metadata field.
|
||||
*/
|
||||
Optional_metadata_fields(unsigned char* optional_metadata,
|
||||
unsigned int optional_metadata_len);
|
||||
};
|
||||
|
||||
/**
|
||||
Print column metadata. Its format looks like:
|
||||
# Columns(colume_name type, colume_name type, ...)
|
||||
if colume_name field is not logged into table_map_log_event, then
|
||||
only type is printed.
|
||||
|
||||
@@param[out] file the place where colume metadata is printed
|
||||
@@param[in] The metadata extracted from optional metadata fields
|
||||
*/
|
||||
void print_columns(IO_CACHE *file,
|
||||
const Optional_metadata_fields &fields);
|
||||
/**
|
||||
Print primary information. Its format looks like:
|
||||
# Primary Key(colume_name, column_name(prifix), ...)
|
||||
if colume_name field is not logged into table_map_log_event, then
|
||||
colume index is printed.
|
||||
|
||||
@@param[out] file the place where primary key is printed
|
||||
@@param[in] The metadata extracted from optional metadata fields
|
||||
*/
|
||||
void print_primary_key(IO_CACHE *file,
|
||||
const Optional_metadata_fields &fields);
|
||||
|
||||
/* Special constants representing sets of flags */
|
||||
enum
|
||||
@@ -4369,6 +4621,51 @@ private:
|
||||
|
||||
#ifdef MYSQL_SERVER
|
||||
TABLE *m_table;
|
||||
Binlog_type_info *binlog_type_info_array;
|
||||
|
||||
|
||||
// Metadata fields buffer
|
||||
StringBuffer<1024> m_metadata_buf;
|
||||
|
||||
/**
|
||||
Capture the optional metadata fields which should be logged into
|
||||
table_map_log_event and serialize them into m_metadata_buf.
|
||||
*/
|
||||
void init_metadata_fields();
|
||||
bool init_signedness_field();
|
||||
/**
|
||||
Capture and serialize character sets. Character sets for
|
||||
character columns (TEXT etc) and character sets for ENUM and SET
|
||||
columns are stored in different metadata fields. The reason is
|
||||
that TEXT character sets are included even when
|
||||
binlog_row_metadata=MINIMAL, whereas ENUM and SET character sets
|
||||
are included only when binlog_row_metadata=FULL.
|
||||
|
||||
@param include_type Predicate to determine if a given Field object
|
||||
is to be included in the metadata field.
|
||||
|
||||
@param default_charset_type Type code when storing in "default
|
||||
charset" format. (See comment above Table_maps_log_event in
|
||||
libbinlogevents/include/rows_event.h)
|
||||
|
||||
@param column_charset_type Type code when storing in "column
|
||||
charset" format. (See comment above Table_maps_log_event in
|
||||
libbinlogevents/include/rows_event.h)
|
||||
*/
|
||||
bool init_charset_field(bool(* include_type)(Binlog_type_info *, Field *),
|
||||
Optional_metadata_field_type default_charset_type,
|
||||
Optional_metadata_field_type column_charset_type);
|
||||
bool init_column_name_field();
|
||||
bool init_set_str_value_field();
|
||||
bool init_enum_str_value_field();
|
||||
bool init_geometry_type_field();
|
||||
bool init_primary_key_field();
|
||||
#endif
|
||||
|
||||
#ifdef MYSQL_CLIENT
|
||||
class Charset_iterator;
|
||||
class Default_charset_iterator;
|
||||
class Column_charset_iterator;
|
||||
#endif
|
||||
char const *m_dbnam;
|
||||
size_t m_dblen;
|
||||
@@ -4390,6 +4687,8 @@ private:
|
||||
ulong m_field_metadata_size;
|
||||
uchar *m_null_bits;
|
||||
uchar *m_meta_memory;
|
||||
unsigned int m_optional_metadata_len;
|
||||
unsigned char *m_optional_metadata;
|
||||
};
|
||||
|
||||
|
||||
@@ -5261,5 +5560,4 @@ int row_log_event_uncompress(const Format_description_log_event *description_eve
|
||||
const char *src, ulong src_len, char* buf, ulong buf_size, bool* is_malloc,
|
||||
char **dst, ulong *newlen);
|
||||
|
||||
|
||||
#endif /* _log_event_h */
|
||||
|
@@ -26,10 +26,11 @@
|
||||
#endif
|
||||
|
||||
|
||||
static bool pretty_print_str(IO_CACHE* cache, const char* str, int len)
|
||||
static bool pretty_print_str(IO_CACHE* cache, const char* str,
|
||||
size_t len, bool identifier)
|
||||
{
|
||||
const char* end = str + len;
|
||||
if (my_b_write_byte(cache, '\''))
|
||||
if (my_b_write_byte(cache, identifier ? '`' : '\''))
|
||||
goto err;
|
||||
|
||||
while (str < end)
|
||||
@@ -52,12 +53,39 @@ static bool pretty_print_str(IO_CACHE* cache, const char* str, int len)
|
||||
if (unlikely(error))
|
||||
goto err;
|
||||
}
|
||||
return my_b_write_byte(cache, '\'');
|
||||
return my_b_write_byte(cache, identifier ? '`' : '\'');
|
||||
|
||||
err:
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
Print src as an string enclosed with "'"
|
||||
|
||||
@param[out] cache IO_CACHE where the string will be printed.
|
||||
@param[in] str the string will be printed.
|
||||
@param[in] len length of the string.
|
||||
*/
|
||||
static inline bool pretty_print_str(IO_CACHE* cache, const char* str,
|
||||
size_t len)
|
||||
{
|
||||
return pretty_print_str(cache, str, len, false);
|
||||
}
|
||||
|
||||
/**
|
||||
Print src as an identifier enclosed with "`"
|
||||
|
||||
@param[out] cache IO_CACHE where the identifier will be printed.
|
||||
@param[in] str the string will be printed.
|
||||
@param[in] len length of the string.
|
||||
*/
|
||||
static inline bool pretty_print_identifier(IO_CACHE* cache, const char* str,
|
||||
size_t len)
|
||||
{
|
||||
return pretty_print_str(cache, str, len, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Prints a "session_var=value" string. Used by mysqlbinlog to print some SET
|
||||
@@ -257,6 +285,46 @@ err:
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline bool is_numeric_type(uint type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MYSQL_TYPE_TINY:
|
||||
case MYSQL_TYPE_SHORT:
|
||||
case MYSQL_TYPE_INT24:
|
||||
case MYSQL_TYPE_LONG:
|
||||
case MYSQL_TYPE_LONGLONG:
|
||||
case MYSQL_TYPE_NEWDECIMAL:
|
||||
case MYSQL_TYPE_FLOAT:
|
||||
case MYSQL_TYPE_DOUBLE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static inline bool is_character_type(uint type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MYSQL_TYPE_STRING:
|
||||
case MYSQL_TYPE_VAR_STRING:
|
||||
case MYSQL_TYPE_VARCHAR:
|
||||
case MYSQL_TYPE_BLOB:
|
||||
// Base class is blob for geom type
|
||||
case MYSQL_TYPE_GEOMETRY:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool is_enum_or_set_type(uint type) {
|
||||
return type == MYSQL_TYPE_ENUM || type == MYSQL_TYPE_SET;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Log_event::print_header()
|
||||
*/
|
||||
@@ -3110,6 +3178,15 @@ bool Table_map_log_event::print(FILE *file, PRINT_EVENT_INFO *print_event_info)
|
||||
}
|
||||
if (!print_event_info->short_form || print_event_info->print_row_count)
|
||||
{
|
||||
|
||||
if (print_event_info->print_table_metadata)
|
||||
{
|
||||
Optional_metadata_fields fields(m_optional_metadata,
|
||||
m_optional_metadata_len);
|
||||
|
||||
print_columns(&print_event_info->head_cache, fields);
|
||||
print_primary_key(&print_event_info->head_cache, fields);
|
||||
}
|
||||
bool do_print_encoded=
|
||||
print_event_info->base64_output_mode != BASE64_OUTPUT_NEVER &&
|
||||
print_event_info->base64_output_mode != BASE64_OUTPUT_DECODE_ROWS &&
|
||||
@@ -3127,6 +3204,396 @@ err:
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
Interface for iterator over charset columns.
|
||||
*/
|
||||
class Table_map_log_event::Charset_iterator
|
||||
{
|
||||
public:
|
||||
typedef Table_map_log_event::Optional_metadata_fields::Default_charset
|
||||
Default_charset;
|
||||
virtual const CHARSET_INFO *next()= 0;
|
||||
virtual ~Charset_iterator(){};
|
||||
/**
|
||||
Factory method to create an instance of the appropriate subclass.
|
||||
*/
|
||||
static std::unique_ptr<Charset_iterator> create_charset_iterator(
|
||||
const Default_charset &default_charset,
|
||||
const std::vector<uint> &column_charset);
|
||||
};
|
||||
|
||||
/**
|
||||
Implementation of charset iterator for the DEFAULT_CHARSET type.
|
||||
*/
|
||||
class Table_map_log_event::Default_charset_iterator : public Charset_iterator
|
||||
{
|
||||
public:
|
||||
Default_charset_iterator(const Default_charset &default_charset)
|
||||
: m_iterator(default_charset.charset_pairs.begin()),
|
||||
m_end(default_charset.charset_pairs.end()),
|
||||
m_column_index(0),
|
||||
m_default_charset_info(
|
||||
get_charset(default_charset.default_charset, 0)) {}
|
||||
|
||||
const CHARSET_INFO *next() override {
|
||||
const CHARSET_INFO *ret;
|
||||
if (m_iterator != m_end && m_iterator->first == m_column_index) {
|
||||
ret = get_charset(m_iterator->second, 0);
|
||||
m_iterator++;
|
||||
} else
|
||||
ret = m_default_charset_info;
|
||||
m_column_index++;
|
||||
return ret;
|
||||
}
|
||||
~Default_charset_iterator(){};
|
||||
|
||||
private:
|
||||
std::vector<Optional_metadata_fields::uint_pair>::const_iterator m_iterator,
|
||||
m_end;
|
||||
uint m_column_index;
|
||||
const CHARSET_INFO *m_default_charset_info;
|
||||
};
|
||||
//Table_map_log_event::Default_charset_iterator::~Default_charset_iterator(){int a=8;a++; a--;};
|
||||
/**
|
||||
Implementation of charset iterator for the COLUMNT_CHARSET type.
|
||||
*/
|
||||
class Table_map_log_event::Column_charset_iterator : public Charset_iterator
|
||||
{
|
||||
public:
|
||||
Column_charset_iterator(const std::vector<uint> &column_charset)
|
||||
: m_iterator(column_charset.begin()), m_end(column_charset.end()) {}
|
||||
|
||||
const CHARSET_INFO *next() override {
|
||||
const CHARSET_INFO *ret = nullptr;
|
||||
if (m_iterator != m_end) {
|
||||
ret = get_charset(*m_iterator, 0);
|
||||
m_iterator++;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
~Column_charset_iterator(){};
|
||||
private:
|
||||
std::vector<uint>::const_iterator m_iterator;
|
||||
std::vector<uint>::const_iterator m_end;
|
||||
};
|
||||
//Table_map_log_event::Column_charset_iterator::~Column_charset_iterator(){int a=8;a++; a--;};
|
||||
|
||||
std::unique_ptr<Table_map_log_event::Charset_iterator>
|
||||
Table_map_log_event::Charset_iterator::create_charset_iterator(
|
||||
const Default_charset &default_charset,
|
||||
const std::vector<uint> &column_charset)
|
||||
{
|
||||
if (!default_charset.empty())
|
||||
return std::unique_ptr<Charset_iterator>(
|
||||
new Default_charset_iterator(default_charset));
|
||||
else
|
||||
return std::unique_ptr<Charset_iterator>(
|
||||
new Column_charset_iterator(column_charset));
|
||||
}
|
||||
/**
|
||||
return the string name of a type.
|
||||
|
||||
@param[in] type type of a column
|
||||
@param[in|out] meta_ptr the meta_ptr of the column. If the type doesn't have
|
||||
metadata, it will not change meta_ptr, otherwise
|
||||
meta_ptr will be moved to the end of the column's
|
||||
metadat.
|
||||
@param[in] cs charset of the column if it is a character column.
|
||||
@param[out] typestr buffer to storing the string name of the type
|
||||
@param[in] typestr_length length of typestr
|
||||
@param[in] geometry_type internal geometry_type
|
||||
*/
|
||||
static void get_type_name(uint type, unsigned char** meta_ptr,
|
||||
const CHARSET_INFO *cs, char *typestr,
|
||||
uint typestr_length, unsigned int geometry_type)
|
||||
{
|
||||
switch (type) {
|
||||
case MYSQL_TYPE_LONG:
|
||||
my_snprintf(typestr, typestr_length, "%s", "INT");
|
||||
break;
|
||||
case MYSQL_TYPE_TINY:
|
||||
my_snprintf(typestr, typestr_length, "TINYINT");
|
||||
break;
|
||||
case MYSQL_TYPE_SHORT:
|
||||
my_snprintf(typestr, typestr_length, "SMALLINT");
|
||||
break;
|
||||
case MYSQL_TYPE_INT24:
|
||||
my_snprintf(typestr, typestr_length, "MEDIUMINT");
|
||||
break;
|
||||
case MYSQL_TYPE_LONGLONG:
|
||||
my_snprintf(typestr, typestr_length, "BIGINT");
|
||||
break;
|
||||
case MYSQL_TYPE_NEWDECIMAL:
|
||||
my_snprintf(typestr, typestr_length, "DECIMAL(%d,%d)",
|
||||
(*meta_ptr)[0], (*meta_ptr)[1]);
|
||||
(*meta_ptr)+= 2;
|
||||
break;
|
||||
case MYSQL_TYPE_FLOAT:
|
||||
my_snprintf(typestr, typestr_length, "FLOAT");
|
||||
(*meta_ptr)++;
|
||||
break;
|
||||
case MYSQL_TYPE_DOUBLE:
|
||||
my_snprintf(typestr, typestr_length, "DOUBLE");
|
||||
(*meta_ptr)++;
|
||||
break;
|
||||
case MYSQL_TYPE_BIT:
|
||||
my_snprintf(typestr, typestr_length, "BIT(%d)",
|
||||
(((*meta_ptr)[0])) + (*meta_ptr)[1]*8);
|
||||
(*meta_ptr)+= 2;
|
||||
break;
|
||||
case MYSQL_TYPE_TIMESTAMP2:
|
||||
if (**meta_ptr != 0)
|
||||
my_snprintf(typestr, typestr_length, "TIMESTAMP(%d)", **meta_ptr);
|
||||
else
|
||||
my_snprintf(typestr, typestr_length, "TIMESTAMP");
|
||||
(*meta_ptr)++;
|
||||
break;
|
||||
case MYSQL_TYPE_DATETIME2:
|
||||
if (**meta_ptr != 0)
|
||||
my_snprintf(typestr, typestr_length, "DATETIME(%d)", **meta_ptr);
|
||||
else
|
||||
my_snprintf(typestr, typestr_length, "DATETIME");
|
||||
(*meta_ptr)++;
|
||||
break;
|
||||
case MYSQL_TYPE_TIME2:
|
||||
if (**meta_ptr != 0)
|
||||
my_snprintf(typestr, typestr_length, "TIME(%d)", **meta_ptr);
|
||||
else
|
||||
my_snprintf(typestr, typestr_length, "TIME");
|
||||
(*meta_ptr)++;
|
||||
break;
|
||||
case MYSQL_TYPE_NEWDATE:
|
||||
case MYSQL_TYPE_DATE:
|
||||
my_snprintf(typestr, typestr_length, "DATE");
|
||||
break;
|
||||
case MYSQL_TYPE_YEAR:
|
||||
my_snprintf(typestr, typestr_length, "YEAR");
|
||||
break;
|
||||
case MYSQL_TYPE_ENUM:
|
||||
my_snprintf(typestr, typestr_length, "ENUM");
|
||||
(*meta_ptr)+= 2;
|
||||
break;
|
||||
case MYSQL_TYPE_SET:
|
||||
my_snprintf(typestr, typestr_length, "SET");
|
||||
(*meta_ptr)+= 2;
|
||||
break;
|
||||
case MYSQL_TYPE_BLOB:
|
||||
{
|
||||
bool is_text= (cs && cs->number != my_charset_bin.number);
|
||||
const char *names[5][2] = {
|
||||
{"INVALID_BLOB(%d)", "INVALID_TEXT(%d)"},
|
||||
{"TINYBLOB", "TINYTEXT"},
|
||||
{"BLOB", "TEXT"},
|
||||
{"MEDIUMBLOB", "MEDIUMTEXT"},
|
||||
{"LONGBLOB", "LONGTEXT"}
|
||||
};
|
||||
unsigned char size= **meta_ptr;
|
||||
|
||||
if (size == 0 || size > 4)
|
||||
my_snprintf(typestr, typestr_length, names[0][is_text], size);
|
||||
else
|
||||
my_snprintf(typestr, typestr_length, names[**meta_ptr][is_text]);
|
||||
|
||||
(*meta_ptr)++;
|
||||
}
|
||||
break;
|
||||
case MYSQL_TYPE_VARCHAR:
|
||||
case MYSQL_TYPE_VAR_STRING:
|
||||
if (cs && cs->number != my_charset_bin.number)
|
||||
my_snprintf(typestr, typestr_length, "VARCHAR(%d)",
|
||||
uint2korr(*meta_ptr)/cs->mbmaxlen);
|
||||
else
|
||||
my_snprintf(typestr, typestr_length, "VARBINARY(%d)",
|
||||
uint2korr(*meta_ptr));
|
||||
|
||||
(*meta_ptr)+= 2;
|
||||
break;
|
||||
case MYSQL_TYPE_STRING:
|
||||
{
|
||||
uint byte0= (*meta_ptr)[0];
|
||||
uint byte1= (*meta_ptr)[1];
|
||||
uint len= (((byte0 & 0x30) ^ 0x30) << 4) | byte1;
|
||||
|
||||
if (cs && cs->number != my_charset_bin.number)
|
||||
my_snprintf(typestr, typestr_length, "CHAR(%d)", len/cs->mbmaxlen);
|
||||
else
|
||||
my_snprintf(typestr, typestr_length, "BINARY(%d)", len);
|
||||
|
||||
(*meta_ptr)+= 2;
|
||||
}
|
||||
break;
|
||||
case MYSQL_TYPE_GEOMETRY:
|
||||
{
|
||||
const char* names[8] = {
|
||||
"GEOMETRY", "POINT", "LINESTRING", "POLYGON", "MULTIPOINT",
|
||||
"MULTILINESTRING", "MULTIPOLYGON", "GEOMETRYCOLLECTION"
|
||||
};
|
||||
if (geometry_type < 8)
|
||||
my_snprintf(typestr, typestr_length, names[geometry_type]);
|
||||
else
|
||||
my_snprintf(typestr, typestr_length, "INVALID_GEOMETRY_TYPE(%u)",
|
||||
geometry_type);
|
||||
(*meta_ptr)++;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
*typestr= 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void Table_map_log_event::print_columns(IO_CACHE *file,
|
||||
const Optional_metadata_fields &fields)
|
||||
{
|
||||
unsigned char* field_metadata_ptr= m_field_metadata;
|
||||
std::vector<bool>::const_iterator signedness_it= fields.m_signedness.begin();
|
||||
|
||||
std::unique_ptr<Charset_iterator> charset_it =
|
||||
Charset_iterator::create_charset_iterator(fields.m_default_charset,
|
||||
fields.m_column_charset);
|
||||
std::unique_ptr<Charset_iterator> enum_and_set_charset_it =
|
||||
Charset_iterator::create_charset_iterator(
|
||||
fields.m_enum_and_set_default_charset,
|
||||
fields.m_enum_and_set_column_charset);
|
||||
std::vector<std::string>::const_iterator col_names_it=
|
||||
fields.m_column_name.begin();
|
||||
std::vector<Optional_metadata_fields::str_vector>::const_iterator
|
||||
set_str_values_it= fields.m_set_str_value.begin();
|
||||
std::vector<Optional_metadata_fields::str_vector>::const_iterator
|
||||
enum_str_values_it= fields.m_enum_str_value.begin();
|
||||
std::vector<unsigned int>::const_iterator geometry_type_it=
|
||||
fields.m_geometry_type.begin();
|
||||
|
||||
uint geometry_type= 0;
|
||||
|
||||
my_b_printf(file, "# Columns(");
|
||||
|
||||
for (unsigned long i= 0; i < m_colcnt; i++)
|
||||
{
|
||||
uint real_type = m_coltype[i];
|
||||
if (real_type == MYSQL_TYPE_STRING &&
|
||||
(*field_metadata_ptr == MYSQL_TYPE_ENUM ||
|
||||
*field_metadata_ptr == MYSQL_TYPE_SET))
|
||||
real_type= *field_metadata_ptr;
|
||||
|
||||
// Get current column's collation id if it is a character, enum,
|
||||
// or set column
|
||||
const CHARSET_INFO *cs = NULL;
|
||||
if (is_character_type(real_type))
|
||||
cs = charset_it->next();
|
||||
else if (is_enum_or_set_type(real_type))
|
||||
cs = enum_and_set_charset_it->next();
|
||||
|
||||
// Print column name
|
||||
if (col_names_it != fields.m_column_name.end())
|
||||
{
|
||||
pretty_print_identifier(file, col_names_it->c_str(), col_names_it->size());
|
||||
my_b_printf(file, " ");
|
||||
col_names_it++;
|
||||
}
|
||||
|
||||
|
||||
// update geometry_type for geometry columns
|
||||
if (real_type == MYSQL_TYPE_GEOMETRY)
|
||||
{
|
||||
geometry_type= (geometry_type_it != fields.m_geometry_type.end()) ?
|
||||
*geometry_type_it++ : 0;
|
||||
}
|
||||
|
||||
// print column type
|
||||
const uint TYPE_NAME_LEN = 100;
|
||||
char type_name[TYPE_NAME_LEN];
|
||||
get_type_name(real_type, &field_metadata_ptr, cs, type_name,
|
||||
TYPE_NAME_LEN, geometry_type);
|
||||
|
||||
if (type_name[0] == '\0')
|
||||
{
|
||||
my_b_printf(file, "INVALID_TYPE(%d)", real_type);
|
||||
continue;
|
||||
}
|
||||
my_b_printf(file, "%s", type_name);
|
||||
|
||||
// Print UNSIGNED for numeric column
|
||||
if (is_numeric_type(real_type) &&
|
||||
signedness_it != fields.m_signedness.end())
|
||||
{
|
||||
if (*signedness_it == true)
|
||||
my_b_printf(file, " UNSIGNED");
|
||||
signedness_it++;
|
||||
}
|
||||
|
||||
// if the column is not marked as 'null', print 'not null'
|
||||
if (!(m_null_bits[(i / 8)] & (1 << (i % 8))))
|
||||
my_b_printf(file, " NOT NULL");
|
||||
|
||||
// Print string values of SET and ENUM column
|
||||
const Optional_metadata_fields::str_vector *str_values= NULL;
|
||||
if (real_type == MYSQL_TYPE_ENUM &&
|
||||
enum_str_values_it != fields.m_enum_str_value.end())
|
||||
{
|
||||
str_values= &(*enum_str_values_it);
|
||||
enum_str_values_it++;
|
||||
}
|
||||
else if (real_type == MYSQL_TYPE_SET &&
|
||||
set_str_values_it != fields.m_set_str_value.end())
|
||||
{
|
||||
str_values= &(*set_str_values_it);
|
||||
set_str_values_it++;
|
||||
}
|
||||
|
||||
if (str_values != NULL)
|
||||
{
|
||||
const char *separator= "(";
|
||||
for (Optional_metadata_fields::str_vector::const_iterator it=
|
||||
str_values->begin(); it != str_values->end(); it++)
|
||||
{
|
||||
my_b_printf(file, "%s", separator);
|
||||
pretty_print_str(file, it->c_str(), it->size());
|
||||
separator= ",";
|
||||
}
|
||||
my_b_printf(file, ")");
|
||||
}
|
||||
// Print column character set, except in text columns with binary collation
|
||||
if (cs != NULL &&
|
||||
(is_enum_or_set_type(real_type) || cs->number != my_charset_bin.number))
|
||||
my_b_printf(file, " CHARSET %s COLLATE %s", cs->csname, cs->name);
|
||||
if (i != m_colcnt - 1) my_b_printf(file, ",\n# ");
|
||||
}
|
||||
my_b_printf(file, ")");
|
||||
my_b_printf(file, "\n");
|
||||
}
|
||||
|
||||
void Table_map_log_event::print_primary_key
|
||||
(IO_CACHE *file,const Optional_metadata_fields &fields)
|
||||
{
|
||||
if (!fields.m_primary_key.empty())
|
||||
{
|
||||
my_b_printf(file, "# Primary Key(");
|
||||
|
||||
std::vector<Optional_metadata_fields::uint_pair>::const_iterator it=
|
||||
fields.m_primary_key.begin();
|
||||
|
||||
for (; it != fields.m_primary_key.end(); it++)
|
||||
{
|
||||
if (it != fields.m_primary_key.begin())
|
||||
my_b_printf(file, ", ");
|
||||
|
||||
// Print column name or column index
|
||||
if (it->first >= fields.m_column_name.size())
|
||||
my_b_printf(file, "%u", it->first);
|
||||
else
|
||||
my_b_printf(file, "%s", fields.m_column_name[it->first].c_str());
|
||||
|
||||
// Print prefix length
|
||||
if (it->second != 0)
|
||||
my_b_printf(file, "(%u)", it->second);
|
||||
}
|
||||
|
||||
my_b_printf(file, ")\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool Write_rows_log_event::print(FILE *file, PRINT_EVENT_INFO* print_event_info)
|
||||
{
|
||||
|
@@ -5914,10 +5914,19 @@ int Table_map_log_event::save_field_metadata()
|
||||
{
|
||||
DBUG_ENTER("Table_map_log_event::save_field_metadata");
|
||||
int index= 0;
|
||||
Binlog_type_info *info;
|
||||
for (unsigned int i= 0 ; i < m_table->s->fields ; i++)
|
||||
{
|
||||
DBUG_PRINT("debug", ("field_type: %d", m_coltype[i]));
|
||||
index+= m_table->s->field[i]->save_field_metadata(&m_field_metadata[index]);
|
||||
//index+= m_table->s->field[i]->save_field_metadata(&m_field_metadata[index]);
|
||||
info= binlog_type_info_array + i;
|
||||
memcpy(&m_field_metadata[index], (uchar *)&info->m_metadata, info->m_metadata_size);
|
||||
index+= info->m_metadata_size;
|
||||
DBUG_EXECUTE_IF("inject_invalid_blob_size",
|
||||
{
|
||||
if (m_coltype[i] == MYSQL_TYPE_BLOB)
|
||||
m_field_metadata[index-1] = 5;
|
||||
});
|
||||
}
|
||||
DBUG_RETURN(index);
|
||||
}
|
||||
@@ -5944,7 +5953,9 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid,
|
||||
m_field_metadata(0),
|
||||
m_field_metadata_size(0),
|
||||
m_null_bits(0),
|
||||
m_meta_memory(NULL)
|
||||
m_meta_memory(NULL),
|
||||
m_optional_metadata_len(0),
|
||||
m_optional_metadata(NULL)
|
||||
{
|
||||
uchar cbuf[MAX_INT_WIDTH];
|
||||
uchar *cbuf_end;
|
||||
@@ -5960,6 +5971,13 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid,
|
||||
(tbl->s->db.str[tbl->s->db.length] == 0));
|
||||
DBUG_ASSERT(tbl->s->table_name.str[tbl->s->table_name.length] == 0);
|
||||
|
||||
#ifdef MYSQL_SERVER
|
||||
binlog_type_info_array= (Binlog_type_info *)thd->alloc(m_table->s->fields *
|
||||
sizeof(Binlog_type_info));
|
||||
for (uint i= 0; i < m_table->s->fields; i++)
|
||||
binlog_type_info_array[i]= m_table->field[i]->binlog_type_info();
|
||||
#endif
|
||||
|
||||
|
||||
m_data_size= TABLE_MAP_HEADER_LEN;
|
||||
DBUG_EXECUTE_IF("old_row_based_repl_4_byte_map_id_master", m_data_size= 6;);
|
||||
@@ -5977,7 +5995,8 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid,
|
||||
{
|
||||
m_coltype= reinterpret_cast<uchar*>(m_memory);
|
||||
for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
|
||||
m_coltype[i]= m_table->field[i]->binlog_type();
|
||||
m_coltype[i]= binlog_type_info_array[i].m_type_code;
|
||||
DBUG_EXECUTE_IF("inject_invalid_column_type", m_coltype[1]= 230;);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -6016,6 +6035,9 @@ Table_map_log_event::Table_map_log_event(THD *thd, TABLE *tbl, ulong tid,
|
||||
if (m_table->field[i]->maybe_null())
|
||||
m_null_bits[(i / 8)]+= 1 << (i % 8);
|
||||
|
||||
init_metadata_fields();
|
||||
m_data_size+= m_metadata_buf.length();
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@@ -6310,9 +6332,393 @@ bool Table_map_log_event::write_data_body()
|
||||
write_data(m_coltype, m_colcnt) ||
|
||||
write_data(mbuf, (size_t) (mbuf_end - mbuf)) ||
|
||||
write_data(m_field_metadata, m_field_metadata_size),
|
||||
write_data(m_null_bits, (m_colcnt + 7) / 8);
|
||||
write_data(m_null_bits, (m_colcnt + 7) / 8) ||
|
||||
write_data((const uchar*) m_metadata_buf.ptr(),
|
||||
m_metadata_buf.length());
|
||||
}
|
||||
|
||||
/**
|
||||
stores an integer into packed format.
|
||||
|
||||
@param[out] str_buf a buffer where the packed integer will be stored.
|
||||
@param[in] length the integer will be packed.
|
||||
*/
|
||||
static inline
|
||||
void store_compressed_length(String &str_buf, ulonglong length)
|
||||
{
|
||||
// Store Type and packed length
|
||||
uchar buf[4];
|
||||
uchar *buf_ptr = net_store_length(buf, length);
|
||||
|
||||
str_buf.append(reinterpret_cast<char *>(buf), buf_ptr-buf);
|
||||
}
|
||||
|
||||
/**
|
||||
Write data into str_buf with Type|Length|Value(TLV) format.
|
||||
|
||||
@param[out] str_buf a buffer where the field is stored.
|
||||
@param[in] type type of the field
|
||||
@param[in] length length of the field value
|
||||
@param[in] value value of the field
|
||||
*/
|
||||
static inline
|
||||
bool write_tlv_field(String &str_buf,
|
||||
enum Table_map_log_event::Optional_metadata_field_type
|
||||
type, uint length, const uchar *value)
|
||||
{
|
||||
/* type is stored in one byte, so it should never bigger than 255. */
|
||||
DBUG_ASSERT(static_cast<int>(type) <= 255);
|
||||
str_buf.append((char) type);
|
||||
store_compressed_length(str_buf, length);
|
||||
return str_buf.append(reinterpret_cast<const char *>(value), length);
|
||||
}
|
||||
|
||||
/**
|
||||
Write data into str_buf with Type|Length|Value(TLV) format.
|
||||
|
||||
@param[out] str_buf a buffer where the field is stored.
|
||||
@param[in] type type of the field
|
||||
@param[in] value value of the field
|
||||
*/
|
||||
static inline
|
||||
bool write_tlv_field(String &str_buf,
|
||||
enum Table_map_log_event::Optional_metadata_field_type
|
||||
type, const String &value)
|
||||
{
|
||||
return write_tlv_field(str_buf, type, value.length(),
|
||||
reinterpret_cast<const uchar *>(value.ptr()));
|
||||
}
|
||||
|
||||
static inline bool is_character_field(Binlog_type_info *info_array, Field *field)
|
||||
{
|
||||
Binlog_type_info *info= info_array + field->field_index;
|
||||
if (!info->m_cs)
|
||||
return 0;
|
||||
if (info->m_set_typelib || info->m_enum_typelib)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline bool is_enum_or_set_field(Binlog_type_info *info_array, Field *field) {
|
||||
Binlog_type_info *info= info_array + field->field_index;
|
||||
if (info->m_set_typelib || info->m_enum_typelib)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void Table_map_log_event::init_metadata_fields()
|
||||
{
|
||||
DBUG_ENTER("init_metadata_fields");
|
||||
DBUG_EXECUTE_IF("simulate_no_optional_metadata", DBUG_VOID_RETURN;);
|
||||
|
||||
if (binlog_row_metadata == BINLOG_ROW_METADATA_NO_LOG)
|
||||
DBUG_VOID_RETURN;
|
||||
if (init_signedness_field() ||
|
||||
init_charset_field(&is_character_field, DEFAULT_CHARSET,
|
||||
COLUMN_CHARSET) ||
|
||||
init_geometry_type_field())
|
||||
{
|
||||
m_metadata_buf.length(0);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
if (binlog_row_metadata == BINLOG_ROW_METADATA_FULL)
|
||||
{
|
||||
if (DBUG_EVALUATE_IF("dont_log_column_name", 0, init_column_name_field()) ||
|
||||
init_charset_field(&is_enum_or_set_field, ENUM_AND_SET_DEFAULT_CHARSET,
|
||||
ENUM_AND_SET_COLUMN_CHARSET) ||
|
||||
init_set_str_value_field() ||
|
||||
init_enum_str_value_field() ||
|
||||
init_primary_key_field())
|
||||
m_metadata_buf.length(0);
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
bool Table_map_log_event::init_signedness_field()
|
||||
{
|
||||
/* use it to store signed flags, each numeric column take a bit. */
|
||||
StringBuffer<128> buf;
|
||||
unsigned char flag= 0;
|
||||
unsigned char mask= 0x80;
|
||||
Binlog_type_info *info;
|
||||
|
||||
for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
|
||||
{
|
||||
info= binlog_type_info_array + i;
|
||||
if (info->m_signess != Binlog_type_info::SIGNESS_NOT_RELEVANT)
|
||||
{
|
||||
if (info->m_signess == Binlog_type_info::UNSIGNED)
|
||||
flag|= mask;
|
||||
mask >>= 1;
|
||||
|
||||
// 8 fields are tested, store the result and clear the flag.
|
||||
if (mask == 0)
|
||||
{
|
||||
buf.append(flag);
|
||||
flag= 0;
|
||||
mask= 0x80;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Stores the signedness flags of last few columns
|
||||
if (mask != 0x80)
|
||||
buf.append(flag);
|
||||
|
||||
// The table has no numeric column, so don't log SIGNEDNESS field
|
||||
if (buf.is_empty())
|
||||
return false;
|
||||
|
||||
return write_tlv_field(m_metadata_buf, SIGNEDNESS, buf);
|
||||
}
|
||||
|
||||
bool Table_map_log_event::init_charset_field(
|
||||
bool (* include_type)(Binlog_type_info *, Field *),
|
||||
Optional_metadata_field_type default_charset_type,
|
||||
Optional_metadata_field_type column_charset_type)
|
||||
{
|
||||
DBUG_EXECUTE_IF("simulate_init_charset_field_error", return true;);
|
||||
|
||||
std::map<uint, uint> collation_map;
|
||||
// For counting characters columns
|
||||
uint char_col_cnt= 0;
|
||||
|
||||
/* Find the collation number used by most fields */
|
||||
for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
|
||||
{
|
||||
if ((*include_type)(binlog_type_info_array, m_table->field[i]))
|
||||
{
|
||||
collation_map[binlog_type_info_array[i].m_cs->number]++;
|
||||
char_col_cnt++;
|
||||
}
|
||||
}
|
||||
|
||||
if (char_col_cnt == 0)
|
||||
return false;
|
||||
|
||||
/* Find the most used collation */
|
||||
uint most_used_collation= 0;
|
||||
uint most_used_count= 0;
|
||||
for (std::map<uint, uint>::iterator it= collation_map.begin();
|
||||
it != collation_map.end(); it++)
|
||||
{
|
||||
if (it->second > most_used_count)
|
||||
{
|
||||
most_used_count= it->second;
|
||||
most_used_collation= it->first;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Comparing length of COLUMN_CHARSET field and COLUMN_CHARSET_WITH_DEFAULT
|
||||
field to decide which field should be logged.
|
||||
|
||||
Length of COLUMN_CHARSET = character column count * collation id size.
|
||||
Length of COLUMN_CHARSET_WITH_DEFAULT =
|
||||
default collation_id size + count of columns not use default charset *
|
||||
(column index size + collation id size)
|
||||
|
||||
Assume column index just uses 1 byte and collation number also uses 1 byte.
|
||||
*/
|
||||
if (char_col_cnt * 1 < (1 + (char_col_cnt - most_used_count) * 2))
|
||||
{
|
||||
StringBuffer<512> buf;
|
||||
|
||||
/*
|
||||
Stores character set information into COLUMN_CHARSET format,
|
||||
character sets of all columns are stored one by one.
|
||||
-----------------------------------------
|
||||
| Charset number | .... |Charset number |
|
||||
-----------------------------------------
|
||||
*/
|
||||
for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
|
||||
{
|
||||
if (include_type(binlog_type_info_array, m_table->field[i]))
|
||||
store_compressed_length(buf, binlog_type_info_array[i].m_cs->number);
|
||||
}
|
||||
return write_tlv_field(m_metadata_buf, column_charset_type, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
StringBuffer<512> buf;
|
||||
uint char_column_index= 0;
|
||||
uint default_collation= most_used_collation;
|
||||
|
||||
/*
|
||||
Stores character set information into DEFAULT_CHARSET format,
|
||||
First stores the default character set, and then stores the character
|
||||
sets different to default character with their column index one by one.
|
||||
--------------------------------------------------------
|
||||
| Default Charset | Col Index | Charset number | ... |
|
||||
--------------------------------------------------------
|
||||
*/
|
||||
|
||||
// Store the default collation number
|
||||
store_compressed_length(buf, default_collation);
|
||||
|
||||
for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
|
||||
{
|
||||
if (include_type(binlog_type_info_array, m_table->field[i]))
|
||||
{
|
||||
Field_str *field= dynamic_cast<Field_str *>(m_table->field[i]);
|
||||
|
||||
if (field->charset()->number != default_collation)
|
||||
{
|
||||
store_compressed_length(buf, char_column_index);
|
||||
store_compressed_length(buf, field->charset()->number);
|
||||
}
|
||||
char_column_index++;
|
||||
}
|
||||
}
|
||||
return write_tlv_field(m_metadata_buf, default_charset_type, buf);
|
||||
}
|
||||
}
|
||||
|
||||
bool Table_map_log_event::init_column_name_field()
|
||||
{
|
||||
StringBuffer<2048> buf;
|
||||
|
||||
for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
|
||||
{
|
||||
size_t len= m_table->field[i]->field_name.length;
|
||||
|
||||
store_compressed_length(buf, len);
|
||||
buf.append(m_table->field[i]->field_name.str, len);
|
||||
}
|
||||
return write_tlv_field(m_metadata_buf, COLUMN_NAME, buf);
|
||||
}
|
||||
|
||||
bool Table_map_log_event::init_set_str_value_field()
|
||||
{
|
||||
StringBuffer<1024> buf;
|
||||
TYPELIB *typelib;
|
||||
|
||||
/*
|
||||
SET string values are stored in the same format:
|
||||
----------------------------------------------
|
||||
| Value number | value1 len | value 1| .... | // first SET column
|
||||
----------------------------------------------
|
||||
| Value number | value1 len | value 1| .... | // second SET column
|
||||
----------------------------------------------
|
||||
*/
|
||||
for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
|
||||
{
|
||||
if ((typelib= binlog_type_info_array[i].m_set_typelib))
|
||||
{
|
||||
store_compressed_length(buf, typelib->count);
|
||||
for (unsigned int i= 0; i < typelib->count; i++)
|
||||
{
|
||||
store_compressed_length(buf, typelib->type_lengths[i]);
|
||||
buf.append(typelib->type_names[i], typelib->type_lengths[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (buf.length() > 0)
|
||||
return write_tlv_field(m_metadata_buf, SET_STR_VALUE, buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Table_map_log_event::init_enum_str_value_field()
|
||||
{
|
||||
StringBuffer<1024> buf;
|
||||
TYPELIB *typelib;
|
||||
|
||||
/* ENUM is same to SET columns, see comment in init_set_str_value_field */
|
||||
for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
|
||||
{
|
||||
if ((typelib= binlog_type_info_array[i].m_enum_typelib))
|
||||
{
|
||||
store_compressed_length(buf, typelib->count);
|
||||
for (unsigned int i= 0; i < typelib->count; i++)
|
||||
{
|
||||
store_compressed_length(buf, typelib->type_lengths[i]);
|
||||
buf.append(typelib->type_names[i], typelib->type_lengths[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (buf.length() > 0)
|
||||
return write_tlv_field(m_metadata_buf, ENUM_STR_VALUE, buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Table_map_log_event::init_geometry_type_field()
|
||||
{
|
||||
StringBuffer<256> buf;
|
||||
uint geom_type;
|
||||
|
||||
/* Geometry type of geometry columns is stored one by one as packed length */
|
||||
for (unsigned int i= 0 ; i < m_table->s->fields ; ++i)
|
||||
{
|
||||
if (binlog_type_info_array[i].m_type_code == MYSQL_TYPE_GEOMETRY)
|
||||
{
|
||||
geom_type= binlog_type_info_array[i].m_geom_type;
|
||||
DBUG_EXECUTE_IF("inject_invalid_geometry_type", geom_type= 100;);
|
||||
store_compressed_length(buf, geom_type);
|
||||
}
|
||||
}
|
||||
|
||||
if (buf.length() > 0)
|
||||
return write_tlv_field(m_metadata_buf, GEOMETRY_TYPE, buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Table_map_log_event::init_primary_key_field()
|
||||
{
|
||||
DBUG_EXECUTE_IF("simulate_init_primary_key_field_error", return true;);
|
||||
|
||||
if (unlikely(m_table->s->primary_key == MAX_KEY))
|
||||
return false;
|
||||
|
||||
// If any key column uses prefix like KEY(c1(10)) */
|
||||
bool has_prefix= false;
|
||||
KEY *pk= m_table->key_info + m_table->s->primary_key;
|
||||
|
||||
DBUG_ASSERT(pk->user_defined_key_parts > 0);
|
||||
|
||||
/* Check if any key column uses prefix */
|
||||
for (uint i= 0; i < pk->user_defined_key_parts; i++)
|
||||
{
|
||||
KEY_PART_INFO *key_part= pk->key_part+i;
|
||||
if (key_part->length != m_table->field[key_part->fieldnr-1]->key_length())
|
||||
{
|
||||
has_prefix= true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
StringBuffer<128> buf;
|
||||
|
||||
if (!has_prefix)
|
||||
{
|
||||
/* Index of PK columns are stored one by one. */
|
||||
for (uint i= 0; i < pk->user_defined_key_parts; i++)
|
||||
{
|
||||
KEY_PART_INFO *key_part= pk->key_part+i;
|
||||
store_compressed_length(buf, key_part->fieldnr-1);
|
||||
}
|
||||
return write_tlv_field(m_metadata_buf, SIMPLE_PRIMARY_KEY, buf);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Index of PK columns are stored with a prefix length one by one. */
|
||||
for (uint i= 0; i < pk->user_defined_key_parts; i++)
|
||||
{
|
||||
KEY_PART_INFO *key_part= pk->key_part+i;
|
||||
size_t prefix= 0;
|
||||
|
||||
store_compressed_length(buf, key_part->fieldnr-1);
|
||||
|
||||
// Store character length but not octet length
|
||||
if (key_part->length != m_table->field[key_part->fieldnr-1]->key_length())
|
||||
prefix= key_part->length / key_part->field->charset()->mbmaxlen;
|
||||
store_compressed_length(buf, prefix);
|
||||
}
|
||||
return write_tlv_field(m_metadata_buf, PRIMARY_KEY_WITH_PREFIX, buf);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_REPLICATION)
|
||||
/*
|
||||
|
@@ -450,6 +450,7 @@ my_bool opt_noacl;
|
||||
my_bool sp_automatic_privileges= 1;
|
||||
|
||||
ulong opt_binlog_rows_event_max_size;
|
||||
ulong binlog_row_metadata;
|
||||
my_bool opt_master_verify_checksum= 0;
|
||||
my_bool opt_slave_sql_verify_checksum= 1;
|
||||
const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS};
|
||||
|
@@ -245,6 +245,7 @@ extern ulonglong max_binlog_cache_size, max_binlog_stmt_cache_size;
|
||||
extern ulong max_binlog_size;
|
||||
extern ulong slave_max_allowed_packet;
|
||||
extern ulong opt_binlog_rows_event_max_size;
|
||||
extern ulong binlog_row_metadata;
|
||||
extern ulong thread_cache_size;
|
||||
extern ulong stored_program_cache_size;
|
||||
extern ulong opt_slave_parallel_threads;
|
||||
|
@@ -912,4 +912,11 @@ uint Field_geom::get_key_image(uchar *buff,uint length, imagetype type_arg)
|
||||
return Field_blob::get_key_image_itRAW(buff, length);
|
||||
}
|
||||
|
||||
Binlog_type_info Field_geom::binlog_type_info() const
|
||||
{
|
||||
DBUG_ASSERT(Field_geom::type() == binlog_type());
|
||||
return Binlog_type_info(Field_geom::type(), pack_length_no_ptr(), 1,
|
||||
field_charset(), type_handler_geom()->geometry_type());
|
||||
}
|
||||
|
||||
#endif // HAVE_SPATIAL
|
||||
|
@@ -435,6 +435,7 @@ public:
|
||||
{
|
||||
out->append(STRING_WITH_LEN("unprintable_geometry_value"));
|
||||
}
|
||||
Binlog_type_info binlog_type_info() const;
|
||||
};
|
||||
|
||||
#endif // HAVE_SPATIAL
|
||||
|
@@ -6209,6 +6209,19 @@ static Sys_var_enum Sys_binlog_row_image(
|
||||
SESSION_VAR(binlog_row_image), CMD_LINE(REQUIRED_ARG),
|
||||
binlog_row_image_names, DEFAULT(BINLOG_ROW_IMAGE_FULL));
|
||||
|
||||
static const char *binlog_row_metadata_names[]= {"NO_LOG", "MINIMAL", "FULL", NullS};
|
||||
static Sys_var_enum Sys_binlog_row_metadata(
|
||||
"binlog_row_metadata",
|
||||
"Controls whether metadata is logged using FULL , MINIMAL format and NO_LOG."
|
||||
"FULL causes all metadata to be logged; MINIMAL means that only "
|
||||
"metadata actually required by slave is logged; NO_LOG NO metadata will be logged."
|
||||
"Default: NO_LOG.",
|
||||
GLOBAL_VAR(binlog_row_metadata), CMD_LINE(REQUIRED_ARG),
|
||||
binlog_row_metadata_names, DEFAULT(Table_map_log_event::BINLOG_ROW_METADATA_NO_LOG),
|
||||
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(NULL),
|
||||
ON_UPDATE(NULL));
|
||||
|
||||
|
||||
static bool check_pseudo_slave_mode(sys_var *self, THD *thd, set_var *var)
|
||||
{
|
||||
longlong previous_val= thd->variables.pseudo_slave_mode;
|
||||
|
Reference in New Issue
Block a user