Merge branch '3.x' into dependabot/go_modules/go.mongodb.org/mongo-driver-1.17.2

This commit is contained in:
Sveta Smirnova
2025-01-14 19:32:13 +03:00
committed by GitHub
34 changed files with 479 additions and 45 deletions

View File

@@ -2993,7 +2993,10 @@ sub quote_val {
return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data
&& !$args{is_char}; # unless is_char is true
return $val if $args{is_float};
if ( $args{is_float} ) {
return sprintf("%.17g", $val) if $val - "$val" != 0;
return $val;
}
$val =~ s/(['\\])/\\$1/g;
return "'$val'";

View File

@@ -2088,7 +2088,10 @@ sub quote_val {
return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data
&& !$args{is_char}; # unless is_char is true
return $val if $args{is_float};
if ( $args{is_float} ) {
return sprintf("%.17g", $val) if $val - "$val" != 0;
return $val;
}
$val =~ s/(['\\])/\\$1/g;
return "'$val'";

View File

@@ -133,7 +133,10 @@ sub quote_val {
return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data
&& !$args{is_char}; # unless is_char is true
return $val if $args{is_float};
if ( $args{is_float} ) {
return sprintf("%.17g", $val) if $val - "$val" != 0;
return $val;
}
$val =~ s/(['\\])/\\$1/g;
return "'$val'";

View File

@@ -1690,7 +1690,10 @@ sub quote_val {
return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data
&& !$args{is_char}; # unless is_char is true
return $val if $args{is_float};
if ( $args{is_float} ) {
return sprintf("%.17g", $val) if $val - "$val" != 0;
return $val;
}
$val =~ s/(['\\])/\\$1/g;
return "'$val'";

View File

@@ -1242,7 +1242,10 @@ sub quote_val {
return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data
&& !$args{is_char}; # unless is_char is true
return $val if $args{is_float};
if ( $args{is_float} ) {
return sprintf("%.17g", $val) if $val - "$val" != 0;
return $val;
}
$val =~ s/(['\\])/\\$1/g;
return "'$val'";

View File

@@ -3564,7 +3564,10 @@ sub quote_val {
return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data
&& !$args{is_char}; # unless is_char is true
return $val if $args{is_float};
if ( $args{is_float} ) {
return sprintf("%.17g", $val) if $val - "$val" != 0;
return $val;
}
$val =~ s/(['\\])/\\$1/g;
return "'$val'";

View File

@@ -589,7 +589,10 @@ sub quote_val {
return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data
&& !$args{is_char}; # unless is_char is true
return $val if $args{is_float};
if ( $args{is_float} ) {
return sprintf("%.17g", $val) if $val - "$val" != 0;
return $val;
}
$val =~ s/(['\\])/\\$1/g;
return "'$val'";

View File

@@ -4905,7 +4905,10 @@ sub quote_val {
return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data
&& !$args{is_char}; # unless is_char is true
return $val if $args{is_float};
if ( $args{is_float} ) {
return sprintf("%.17g", $val) if $val - "$val" != 0;
return $val;
}
$val =~ s/(['\\])/\\$1/g;
return "'$val'";

View File

@@ -2866,7 +2866,10 @@ sub quote_val {
return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data
&& !$args{is_char}; # unless is_char is true
return $val if $args{is_float};
if ( $args{is_float} ) {
return sprintf("%.17g", $val) if $val - "$val" != 0;
return $val;
}
$val =~ s/(['\\])/\\$1/g;
return "'$val'";
@@ -5862,8 +5865,6 @@ sub _nibble_params {
);
PTDEBUG && _d('Ascend params:', Dumper($asc));
my $force_concat_enums;
my $from = "$tbl->{name} FORCE INDEX(`$index`)";
my $order_by = join(', ', map {$q->quote($_)} @{$index_cols});
@@ -9396,12 +9397,12 @@ sub main {
};
if ( $EVAL_ERROR ) {
chomp $EVAL_ERROR;
_die("Error checking --max-load or --critial-load: $EVAL_ERROR. "
_die("Error checking --max-load or --critical-load: $EVAL_ERROR. "
. "Check that the variables specified for --max-load and "
. "--critical-load are spelled correctly and exist in "
. "SHOW GLOBAL STATUS. Current values for these options are:\n"
. " --max-load " . (join(',', @{$o->get('max-load')})) . "\n"
. " --critial-load " . (join(',', @{$o->get('critical-load')}))
. " --critical-load " . (join(',', @{$o->get('critical-load')}))
, INVALID_PARAMETERS);
}

View File

@@ -1257,7 +1257,10 @@ sub quote_val {
return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data
&& !$args{is_char}; # unless is_char is true
return $val if $args{is_float};
if ( $args{is_float} ) {
return sprintf("%.17g", $val) if $val - "$val" != 0;
return $val;
}
$val =~ s/(['\\])/\\$1/g;
return "'$val'";

View File

@@ -135,7 +135,10 @@ sub quote_val {
return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data
&& !$args{is_char}; # unless is_char is true
return $val if $args{is_float};
if ( $args{is_float} ) {
return sprintf("%.17g", $val) if $val - "$val" != 0;
return $val;
}
$val =~ s/(['\\])/\\$1/g;
return "'$val'";

View File

@@ -4134,7 +4134,10 @@ sub quote_val {
return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data
&& !$args{is_char}; # unless is_char is true
return $val if $args{is_float};
if ( $args{is_float} ) {
return sprintf("%.17g", $val) if $val - "$val" != 0;
return $val;
}
$val =~ s/(['\\])/\\$1/g;
return "'$val'";
@@ -6683,8 +6686,6 @@ sub _nibble_params {
);
PTDEBUG && _d('Ascend params:', Dumper($asc));
my $force_concat_enums;
my $from = "$tbl->{name} FORCE INDEX(`$index`)";
my $order_by = join(', ', map {$q->quote($_)} @{$index_cols});
@@ -11074,7 +11075,7 @@ sub main {
. "(db, tbl, chunk, chunk_index,"
. " lower_boundary, upper_boundary, this_cnt, this_crc) "
. "SELECT"
. ($cluster->is_cluster_node($source_cxn) ? ' /*!99997*/' : '')
. ($cluster->is_cluster_node($source_cxn) ? ' /*!99997 */' : '')
. " ?, ?, ?, ?, ?, ?,";
my $past_cols = " COUNT(*), '0'";

View File

@@ -1909,7 +1909,10 @@ sub quote_val {
return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data
&& !$args{is_char}; # unless is_char is true
return $val if $args{is_float};
if ( $args{is_float} ) {
return sprintf("%.17g", $val) if $val - "$val" != 0;
return $val;
}
$val =~ s/(['\\])/\\$1/g;
return "'$val'";
@@ -3612,6 +3615,14 @@ sub make_UPDATE {
@cols = $self->sort_cols($row);
}
my $types = $self->{tbl_struct}->{type_for};
foreach my $col ( @cols ) {
my $is_json = ($types->{$col} || '') =~ m/json/i;
if ( $is_json && defined $row->{$col} ) {
utf8::decode($row->{$col});
}
}
return "UPDATE $self->{dst_db_tbl} SET "
. join(', ', map {
my $is_hex = ($types->{$_} || '') =~ m/^0x[0-9a-fA-F]+$/i;
@@ -3660,6 +3671,13 @@ sub make_row {
my $q = $self->{Quoter};
my $type_for = $self->{tbl_struct}->{type_for};
foreach my $col ( @cols ) {
my $is_json = ($type_for->{$col} || '') =~ m/json/i;
if ( $is_json && defined $row->{$col} ) {
utf8::decode($row->{$col});
}
}
return "$verb INTO $self->{dst_db_tbl}("
. join(', ', map { $q->quote($_) } @cols)
. ') VALUES ('

View File

@@ -6680,7 +6680,10 @@ sub quote_val {
return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data
&& !$args{is_char}; # unless is_char is true
return $val if $args{is_float};
if ( $args{is_float} ) {
return sprintf("%.17g", $val) if $val - "$val" != 0;
return $val;
}
$val =~ s/(['\\])/\\$1/g;
return "'$val'";

View File

@@ -1254,7 +1254,10 @@ sub quote_val {
return $val if $val =~ m/^0x[0-9a-fA-F]+$/ # quote hex data
&& !$args{is_char}; # unless is_char is true
return $val if $args{is_float};
if ( $args{is_float} ) {
return sprintf("%.17g", $val) if $val - "$val" != 0;
return $val;
}
$val =~ s/(['\\])/\\$1/g;
return "'$val'";

View File

@@ -529,7 +529,7 @@ list of supported platforms and versions.
In order to support IPv6 addresses to connect to MySQL, Perl DBD::MySQL driver v4.033_01 is
required. Also, as stated in RFC 3986 L<https://www.ietf.org/rfc/rfc3986.txt> section 3.2.2
brackes must be used to distinguish host and port.
brackets must be used to distinguish host and port.
Examples: L<https://metacpan.org/pod/DBD::mysql#port>
=head1 BUGS

8
go.mod
View File

@@ -7,7 +7,7 @@ require (
github.com/Ladicle/tabwriter v1.0.0
github.com/Masterminds/semver v1.5.0
github.com/alecthomas/kingpin v2.2.6+incompatible
github.com/alecthomas/kong v1.6.0
github.com/alecthomas/kong v1.6.1
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc
github.com/go-ini/ini v1.67.0
github.com/golang/mock v1.6.0
@@ -27,7 +27,7 @@ require (
github.com/stretchr/testify v1.10.0
github.com/xlab/treeprint v1.2.0
go.mongodb.org/mongo-driver v1.17.2
golang.org/x/crypto v0.31.0
golang.org/x/crypto v0.32.0
golang.org/x/exp v0.0.0-20230321023759-10a507213a29
gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22
gopkg.in/yaml.v2 v2.4.0
@@ -62,8 +62,8 @@ require (
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sync v0.10.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/term v0.27.0 // indirect
golang.org/x/sys v0.29.0 // indirect
golang.org/x/term v0.28.0 // indirect
golang.org/x/text v0.21.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect

16
go.sum
View File

@@ -8,8 +8,8 @@ github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8v
github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k=
github.com/alecthomas/kingpin v2.2.6+incompatible h1:5svnBTFgJjZvGKyYBtMB0+m5wvrbUHiqye8wRJMlnYI=
github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE=
github.com/alecthomas/kong v1.6.0 h1:mwOzbdMR7uv2vul9J0FU3GYxE7ls/iX1ieMg5WIM6gE=
github.com/alecthomas/kong v1.6.0/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU=
github.com/alecthomas/kong v1.6.1 h1:/7bVimARU3uxPD0hbryPE8qWrS3Oz3kPQoxA/H2NKG8=
github.com/alecthomas/kong v1.6.1/go.mod h1:p2vqieVMeTAnaC83txKtXe8FLke2X07aruPWXyMPQrU=
github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc=
github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
@@ -131,8 +131,8 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
golang.org/x/exp v0.0.0-20230321023759-10a507213a29 h1:ooxPy7fPvB4kwsA2h+iBNHkAbp/4JxTSwCmvdjEYmug=
golang.org/x/exp v0.0.0-20230321023759-10a507213a29/go.mod h1:CxIveKay+FTh1D0yPZemJVgC/95VzuuOLq5Qi4xnoYc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
@@ -170,12 +170,12 @@ golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=

View File

@@ -324,6 +324,16 @@ sub make_UPDATE {
@cols = $self->sort_cols($row);
}
my $types = $self->{tbl_struct}->{type_for};
# MySQL uses utf8mb4 for all strings in JSON, but
# DBD::mysql does not decode it accordingly
foreach my $col ( @cols ) {
my $is_json = ($types->{$col} || '') =~ m/json/i;
if ( $is_json && defined $row->{$col} ) {
utf8::decode($row->{$col});
}
}
return "UPDATE $self->{dst_db_tbl} SET "
. join(', ', map {
my $is_hex = ($types->{$_} || '') =~ m/^0x[0-9a-fA-F]+$/i;
@@ -403,6 +413,15 @@ sub make_row {
my $q = $self->{Quoter};
my $type_for = $self->{tbl_struct}->{type_for};
# MySQL uses utf8mb4 for all strings in JSON, but
# DBD::mysql does not decode it accordingly
foreach my $col ( @cols ) {
my $is_json = ($type_for->{$col} || '') =~ m/json/i;
if ( $is_json && defined $row->{$col} ) {
utf8::decode($row->{$col});
}
}
return "$verb INTO $self->{dst_db_tbl}("
. join(', ', map { $q->quote($_) } @cols)
. ') VALUES ('

View File

@@ -56,7 +56,7 @@ sub check_type_constraints {
. (defined $val ? Lmo::Dumper($val) : 'undef') )
}
# Nested (or parametized) constraints look like this: ArrayRef[CONSTRAINT] or
# Nested (or parameritized) constraints look like this: ArrayRef[CONSTRAINT] or
# Maybe[CONSTRAINT]. This function returns a coderef that implements one of
# these.
sub _nested_constraints {
@@ -64,7 +64,7 @@ sub _nested_constraints {
my $inner_types;
if ( $type =~ /\A(ArrayRef|Maybe)\[(.*)\]\z/ ) {
# If the inner constraint -- the part within brackets -- is also a parametized
# If the inner constraint -- the part within brackets -- is also a parametirized
# constraint, then call this function recursively.
$inner_types = _nested_constraints($1, $2);
}

View File

@@ -208,10 +208,6 @@ sub _nibble_params {
);
PTDEBUG && _d('Ascend params:', Dumper($asc));
# Check if enum fields items are sorted or not.
# If they are sorted we can skip adding CONCAT to improve the queries eficiency.
my $force_concat_enums;
# Make SQL statements, prepared on first call to next(). FROM and
# ORDER BY are the same for all statements. FORCE IDNEX and ORDER BY
# are needed to ensure deterministic nibbling.

View File

@@ -507,7 +507,7 @@ sub find {
}
my $reason = 'Exceeds busy time';
PTDEBUG && _d($reason);
# Saving the reasons for each query in the objct is a bit nasty,
# Saving the reasons for each query in the object is a bit nasty,
# but the alternatives are worse:
# - Saving internal data in the query
# - Instead of using the stringified hashref as a key, using

View File

@@ -78,7 +78,10 @@ sub quote_val {
&& !$args{is_char}; # unless is_char is true
# https://bugs.launchpad.net/percona-toolkit/+bug/1229861
return $val if $args{is_float};
if ( $args{is_float} ) {
return sprintf("%.17g", $val) if $val - "$val" != 0;
return $val;
}
# Quote and return non-numeric vals.
$val =~ s/(['\\])/\\$1/g;

View File

@@ -1140,7 +1140,7 @@ sub timestampdiff {
# Some column types can store invalid values, like most of the temporal
# types. When evaluated, invalid values return NULL. If the value is
# NULL to begin with, then it is not invalid because NULL is valid.
# For example, TO_DAYS('2009-00-00') evalues to NULL because that date
# For example, TO_DAYS('2009-00-00') evaluates to NULL because that date
# is invalid, even though it's storable.
sub get_valid_end_points {
my ( $self, %args ) = @_;

View File

@@ -7,6 +7,7 @@ BEGIN {
};
use strict;
use utf8;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More;
@@ -617,6 +618,52 @@ SKIP: {
);
}
# #############################################################################
# PT-2377: pt-table-sync must handle utf8 in JSON columns correctly
# #############################################################################
SKIP: {
skip 'Cannot connect to sandbox master', 1 unless $master_dbh;
$master_dbh->do('DROP TABLE IF EXISTS `test`.`pt-2377`');
$master_dbh->do('CREATE TABLE `test`.`pt-2377` (id INT, data JSON)');
$master_dbh->do(q/INSERT INTO `test`.`pt-2377` VALUES (1, '{"name": "Müller"}')/);
$master_dbh->do(q/INSERT INTO `test`.`pt-2377` VALUES (2, NULL)/);
@rows = ();
$tbl_struct = {
cols => [qw(id data)],
col_posn => {id=>0, data=>1},
type_for => {id=>'int', data=>'json'},
};
$ch = new ChangeHandler(
Quoter => $q,
left_db => 'test',
left_tbl => 'pt-2377',
right_db => 'test',
right_tbl => 'pt-2377',
actions => [ sub { push @rows, $_[0]; } ],
replace => 0,
queue => 0,
tbl_struct => $tbl_struct,
);
$ch->fetch_back($master_dbh);
$ch->change('UPDATE', {id=>1}, [qw(id)] );
$ch->change('INSERT', {id=>1}, [qw(id)] );
$ch->change('UPDATE', {id=>2}, [qw(id)] );
$ch->change('INSERT', {id=>2}, [qw(id)] );
is_deeply(
\@rows,
[
q/UPDATE `test`.`pt-2377` SET `data`='{"name": "Müller"}' WHERE `id`='1' LIMIT 1/,
q/INSERT INTO `test`.`pt-2377`(`id`, `data`) VALUES ('1', '{"name": "Müller"}')/,
q/UPDATE `test`.`pt-2377` SET `data`=NULL WHERE `id`='2' LIMIT 1/,
q/INSERT INTO `test`.`pt-2377`(`id`, `data`) VALUES ('2', NULL)/
],
"UPDATE and INSERT quote data regardless of how it looks if tbl_struct->quote_val is true"
);
}
# #############################################################################
# Done.
# #############################################################################

View File

@@ -71,6 +71,8 @@ is( $q->quote_val('0x89504E470', is_char => 0), '0x89504E470', 'hex string, with
is( $q->quote_val('0x89504E470', is_char => 1), "'0x89504E470'", 'hex string, with is_char => 1');
is( $q->quote_val('0x89504I470'), "'0x89504I470'", 'looks like hex string');
is( $q->quote_val('eastside0x3'), "'eastside0x3'", 'looks like hex str (issue 1110');
is( $q->quote_val(969.1 / 360, is_float => 1), "2.6919444444444447", 'float has full precision');
is( $q->quote_val(0.1, is_float => 1), "0.1", 'full precision for float only used when required');
# Splitting DB and tbl apart
is_deeply(

View File

@@ -0,0 +1,70 @@
#!/usr/bin/env perl
BEGIN {
die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
};
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More;
use Data::Dumper;
# Hostnames make testing less accurate. Tests need to see
# that such-and-such happened on specific replica hosts, but
# the sandbox servers are all on one host so all replicas have
# the same hostname.
$ENV{PERCONA_TOOLKIT_TEST_USE_DSN_NAMES} = 1;
use PerconaTest;
use Sandbox;
require "$trunk/bin/pt-table-checksum";
my $dp = new DSNParser(opts=>$dsn_opts);
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
my $node1 = $sb->get_dbh_for('node1');
my $sb_version = VersionParser->new($node1);
my $node2 = $sb->get_dbh_for('node2');
my $node3 = $sb->get_dbh_for('node3');
my %checks = (
'Cannot connect to cluster node1' => !$node1,
'Cannot connect to cluster node2' => !$node2,
'Cannot connect to cluster node3' => !$node3,
'PXC tests' => !$sb->is_cluster_mode,
);
for my $message (keys %checks) {
if ( $checks{$message} ) {
plan skip_all => $message;
}
}
my $node1_dsn = $sb->dsn_for('node1');
my @args = ($node1_dsn, qw(--databases pt-2400 --tables apple),
qw(--recursion-method none),
qw(--replicate percona.checksums --create-replicate-table --empty-replicate-table )
);
my $sample = "t/pt-table-checksum/samples/";
$sb->load_file('node1', "$sample/pt-2400.sql");
my ($output, $error) = full_output(
sub { pt_table_checksum::main(@args) },
stderr => 1,
);
unlike(
$output,
qr/Immediately starting the version comment after the version number is deprecated and may change behavior in a future release. Please insert a white-space character after the version number./,
"No typo in version comment"
);
# #############################################################################
# Done.
# #############################################################################
$sb->wipe_clean($node1);
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
done_testing;

View File

@@ -0,0 +1,13 @@
DROP DATABASE IF EXISTS `pt-2400`;
CREATE DATABASE `pt-2400`;
USE `pt-2400`;
CREATE TABLE `apple` (
`id` int NOT NULL,
`name` varchar(255) NOT NULL,
PRIMARY KEY (`id`,`name`)
) ENGINE=InnoDB;
INSERT INTO `apple` VALUES
(1, 'Granny Smith'),
(2, 'Red Delicious'),
(3, 'Golden Apple');

View File

@@ -63,6 +63,23 @@ is(
'--float-precision so no more diff (issue 410)'
);
# Although the SQL statement contains serialized values with more than necessary decimal digits
# we produce the expected value on execution
$output = `$trunk/bin/pt-table-sync --sync-to-source h=127.1,P=12346,u=msandbox,p=msandbox,D=test,t=fl --execute 2>&1`;
is(
$output,
'',
'REPLACE statement can be successfully applied'
);
$sb->wait_for_replicas();
my @rows = $replica_dbh->selectrow_array('SELECT `d` FROM `test`.`fl` WHERE `d` = 2.0000012');
is_deeply(
\@rows,
[2.0000012],
'Floating point values are set correctly in round trip'
);
# #############################################################################
# pt-table-sync quotes floats, prevents syncing
# https://bugs.launchpad.net/percona-toolkit/+bug/1229861
@@ -86,7 +103,6 @@ is_deeply(
[],
"Sync rows with float values (bug 1229861)"
) or diag(Dumper($rows), $output);
# #############################################################################
# Done.
# #############################################################################

83
t/pt-table-sync/pt-2377.t Normal file
View File

@@ -0,0 +1,83 @@
#!/usr/bin/env perl
BEGIN {
die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
};
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More;
use PerconaTest;
use Sandbox;
require "$trunk/bin/pt-table-sync";
my $dp = new DSNParser(opts=>$dsn_opts);
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
my $source_dbh = $sb->get_dbh_for('source');
my $replica1_dbh = $sb->get_dbh_for('replica1');
if ( !$source_dbh ) {
plan skip_all => 'Cannot connect to sandbox source';
}
elsif ( !$replica1_dbh ) {
plan skip_all => 'Cannot connect to sandbox replica1';
}
elsif ( $sandbox_version lt '8.0') {
plan skip_all => 'Requires MySQL >= 8.0';
}
else {
plan tests => 3;
}
my $output;
# #############################################################################
# Test generated REPLACE statements.
# #############################################################################
$sb->load_file('source', "t/pt-table-sync/samples/pt-2377.sql");
$sb->wait_for_replicas();
$replica1_dbh->do("delete from `test`.`test_table` where `id`=1");
$output = remove_traces(output(
sub { pt_table_sync::main('--sync-to-source',
'h=127.0.0.1,P=12346,u=msandbox,p=msandbox',
qw(-t test.test_table --print --execute))
},
));
chomp($output);
is(
$output,
q/REPLACE INTO `test`.`test_table`(`id`, `data`) VALUES ('1', '{"name": "Müller"}');/,
"UTF8 characters of JSON values are printed correctly in REPLACE statements"
);
# #############################################################################
# Test generated UPDATE statements.
# #############################################################################
$sb->load_file('source', "t/pt-table-sync/samples/pt-2377.sql");
$sb->wait_for_replicas();
$replica1_dbh->do(q/update `test`.`test_table` set `data`='{"reaction": "哈哈哈"}' where `id`=2/);
$output = remove_traces(output(
sub { pt_table_sync::main(qw(--print --execute),
"h=127.0.0.1,P=12346,u=msandbox,p=msandbox,D=test,t=test_table",
"h=127.0.0.1,P=12345,u=msandbox,p=msandbox,D=test,t=test_table");
}
));
chomp($output);
is(
$output,
q/UPDATE `test`.`test_table` SET `data`='{"reaction": "哈哈哈"}' WHERE `id`='2' LIMIT 1;/,
"UTF8 characters of JSON values are printed correctly in UPDATE statements"
);
# #############################################################################
# Done.
# #############################################################################
$sb->wipe_clean($source_dbh);
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
exit;

96
t/pt-table-sync/pt-2378.t Normal file
View File

@@ -0,0 +1,96 @@
#!/usr/bin/env perl
BEGIN {
die "The PERCONA_TOOLKIT_BRANCH environment variable is not set.\n"
unless $ENV{PERCONA_TOOLKIT_BRANCH} && -d $ENV{PERCONA_TOOLKIT_BRANCH};
unshift @INC, "$ENV{PERCONA_TOOLKIT_BRANCH}/lib";
};
use strict;
use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More;
use PerconaTest;
use Sandbox;
require "$trunk/bin/pt-table-sync";
my $dp = new DSNParser(opts=>$dsn_opts);
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
my $source_dbh = $sb->get_dbh_for('source');
my $replica1_dbh = $sb->get_dbh_for('replica1');
if ( !$source_dbh ) {
plan skip_all => 'Cannot connect to sandbox source';
}
elsif ( !$replica1_dbh ) {
plan skip_all => 'Cannot connect to sandbox replica1';
}
else {
plan tests => 5;
}
my ($output, @rows);
# #############################################################################
# Test generated REPLACE statements.
# #############################################################################
$sb->load_file('source', "t/pt-table-sync/samples/pt-2378.sql");
$sb->wait_for_replicas();
$replica1_dbh->do("update `test`.`test_table` set `some_string` = 'c' where `id` = 1");
$output = remove_traces(output(
sub { pt_table_sync::main('--sync-to-source',
'h=127.0.0.1,P=12346,u=msandbox,p=msandbox',
qw(-t test.test_table --print --execute))
},
));
chomp($output);
is(
$output,
"REPLACE INTO `test`.`test_table`(`id`, `value1`, `value2`, `some_string`) VALUES ('1', 315.25999999999942, 2.6919444444444447, 'a');",
"Floating point numbers are generated with sufficient precision in REPLACE statements"
);
$sb->wait_for_replicas();
my $query = 'SELECT * FROM `test`.`test_table` WHERE `value1` = 315.2599999999994 AND `value2` = 2.6919444444444447';
@rows = $replica1_dbh->selectrow_array($query);
is_deeply(
\@rows,
[1, 315.2599999999994, 2.6919444444444447, 'a'],
'Floating point values are set correctly in round trip'
);
# #############################################################################
# Test generated UPDATE statements.
# #############################################################################
$sb->load_file('source', "t/pt-table-sync/samples/pt-2378.sql");
$sb->wait_for_replicas();
$replica1_dbh->do("update `test`.`test_table` set `some_string` = 'c' where `id` = 1");
$output = remove_traces(output(
sub { pt_table_sync::main(qw(--print --execute),
"h=127.0.0.1,P=12346,u=msandbox,p=msandbox,D=test,t=test_table",
"h=127.0.0.1,P=12345,u=msandbox,p=msandbox,D=test,t=test_table");
}
));
chomp($output);
is(
$output,
"UPDATE `test`.`test_table` SET `value1`=315.25999999999942, `value2`=2.6919444444444447, `some_string`='c' WHERE `id`='1' LIMIT 1;",
"Floating point numbers are generated with sufficient precision in UPDATE statements"
);
@rows = $source_dbh->selectrow_array($query);
is_deeply(
\@rows,
[1, 315.2599999999994, 2.6919444444444447, 'c'],
'Floating point values are set correctly in round trip'
);
# #############################################################################
# Done.
# #############################################################################
$sb->wipe_clean($source_dbh);
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
exit;

View File

@@ -0,0 +1,14 @@
DROP DATABASE IF EXISTS test;
CREATE DATABASE test;
USE test;
CREATE TABLE `test_table` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`data` JSON NOT NULL
) ENGINE=InnoDB;
INSERT INTO
`test_table` (`data`)
VALUES
('{"name": "Müller"}'),
('{"reaction": "哈哈"}');

View File

@@ -0,0 +1,15 @@
DROP DATABASE IF EXISTS test;
CREATE DATABASE test;
USE test;
CREATE TABLE `test_table` (
`id` BIGINT AUTO_INCREMENT PRIMARY KEY,
`value1` DOUBLE NOT NULL,
`value2` DOUBLE NOT NULL,
`some_string` VARCHAR(32) NOT NULL
) ENGINE=InnoDB;
INSERT INTO `test_table`
(`value1`, `value2`, `some_string`)
VALUES
(315.2599999999994, 2.6919444444444447, 'a');

View File

@@ -137,6 +137,10 @@ if [ ! -f $tool_file ]; then
die "$tool_file does not exist"
fi
if [ -h $tool_file ]; then
die "$tool_file is a symbolic link"
fi
if [ -n "$(head -n 1 $tool_file | grep perl)" ]; then
tool_lang="perl"
else