PT-202 pt-online-schema-change fails with virtual columns

Modified TableParser to ignore GENERATED columns from the columns list
used to construct SELECTs/INSERTs
This commit is contained in:
Carlos Salguero
2017-10-05 15:19:57 -03:00
parent 6ff61612f4
commit b51d09d811
16 changed files with 761 additions and 323 deletions

View File

@@ -1965,8 +1965,8 @@ sub parse {
my %def_for;
@def_for{@cols} = @defs;
my (@nums, @null);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc);
my (@nums, @null, @non_generated);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc, %is_generated);
foreach my $col ( @cols ) {
my $def = $def_for{$col};
@@ -1983,6 +1983,11 @@ sub parse {
push @null, $col;
$is_nullable{$col} = 1;
}
if ( remove_quoted_text($def) =~ m/\WGENERATED\W/i ) {
$is_generated{$col} = 1;
} else {
push @non_generated, $col;
}
$is_autoinc{$col} = $def =~ m/AUTO_INCREMENT/i ? 1 : 0;
}
@@ -1991,24 +1996,34 @@ sub parse {
my ($charset) = $ddl =~ m/DEFAULT CHARSET=(\w+)/;
return {
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @cols },
null_cols => \@null,
is_nullable => \%is_nullable,
is_autoinc => \%is_autoinc,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @non_generated },
null_cols => \@null,
is_nullable => \%is_nullable,
non_generated_cols => \@non_generated,
is_autoinc => \%is_autoinc,
is_generated => \%is_generated,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
};
}
sub remove_quoted_text {
my ($string) = @_;
$string =~ s/[^\\]`[^`]*[^\\]`//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
return $string;
}
sub sort_indexes {
my ( $self, $tbl ) = @_;

View File

@@ -352,8 +352,8 @@ sub parse {
my %def_for;
@def_for{@cols} = @defs;
my (@nums, @null);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc);
my (@nums, @null, @non_generated);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc, %is_generated);
foreach my $col ( @cols ) {
my $def = $def_for{$col};
@@ -370,6 +370,11 @@ sub parse {
push @null, $col;
$is_nullable{$col} = 1;
}
if ( remove_quoted_text($def) =~ m/\WGENERATED\W/i ) {
$is_generated{$col} = 1;
} else {
push @non_generated, $col;
}
$is_autoinc{$col} = $def =~ m/AUTO_INCREMENT/i ? 1 : 0;
}
@@ -378,24 +383,34 @@ sub parse {
my ($charset) = $ddl =~ m/DEFAULT CHARSET=(\w+)/;
return {
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @cols },
null_cols => \@null,
is_nullable => \%is_nullable,
is_autoinc => \%is_autoinc,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @non_generated },
null_cols => \@null,
is_nullable => \%is_nullable,
non_generated_cols => \@non_generated,
is_autoinc => \%is_autoinc,
is_generated => \%is_generated,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
};
}
sub remove_quoted_text {
my ($string) = @_;
$string =~ s/[^\\]`[^`]*[^\\]`//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
return $string;
}
sub sort_indexes {
my ( $self, $tbl ) = @_;

View File

@@ -1880,8 +1880,8 @@ sub parse {
my %def_for;
@def_for{@cols} = @defs;
my (@nums, @null);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc);
my (@nums, @null, @non_generated);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc, %is_generated);
foreach my $col ( @cols ) {
my $def = $def_for{$col};
@@ -1898,6 +1898,11 @@ sub parse {
push @null, $col;
$is_nullable{$col} = 1;
}
if ( remove_quoted_text($def) =~ m/\WGENERATED\W/i ) {
$is_generated{$col} = 1;
} else {
push @non_generated, $col;
}
$is_autoinc{$col} = $def =~ m/AUTO_INCREMENT/i ? 1 : 0;
}
@@ -1906,24 +1911,34 @@ sub parse {
my ($charset) = $ddl =~ m/DEFAULT CHARSET=(\w+)/;
return {
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @cols },
null_cols => \@null,
is_nullable => \%is_nullable,
is_autoinc => \%is_autoinc,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @non_generated },
null_cols => \@null,
is_nullable => \%is_nullable,
non_generated_cols => \@non_generated,
is_autoinc => \%is_autoinc,
is_generated => \%is_generated,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
};
}
sub remove_quoted_text {
my ($string) = @_;
$string =~ s/[^\\]`[^`]*[^\\]`//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
return $string;
}
sub sort_indexes {
my ( $self, $tbl ) = @_;

View File

@@ -3499,8 +3499,8 @@ sub parse {
my %def_for;
@def_for{@cols} = @defs;
my (@nums, @null);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc);
my (@nums, @null, @non_generated);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc, %is_generated);
foreach my $col ( @cols ) {
my $def = $def_for{$col};
@@ -3517,6 +3517,11 @@ sub parse {
push @null, $col;
$is_nullable{$col} = 1;
}
if ( remove_quoted_text($def) =~ m/\WGENERATED\W/i ) {
$is_generated{$col} = 1;
} else {
push @non_generated, $col;
}
$is_autoinc{$col} = $def =~ m/AUTO_INCREMENT/i ? 1 : 0;
}
@@ -3525,24 +3530,34 @@ sub parse {
my ($charset) = $ddl =~ m/DEFAULT CHARSET=(\w+)/;
return {
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @cols },
null_cols => \@null,
is_nullable => \%is_nullable,
is_autoinc => \%is_autoinc,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @non_generated },
null_cols => \@null,
is_nullable => \%is_nullable,
non_generated_cols => \@non_generated,
is_autoinc => \%is_autoinc,
is_generated => \%is_generated,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
};
}
sub remove_quoted_text {
my ($string) = @_;
$string =~ s/[^\\]`[^`]*[^\\]`//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
return $string;
}
sub sort_indexes {
my ( $self, $tbl ) = @_;

View File

@@ -3119,8 +3119,8 @@ sub parse {
my %def_for;
@def_for{@cols} = @defs;
my (@nums, @null);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc);
my (@nums, @null, @non_generated);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc, %is_generated);
foreach my $col ( @cols ) {
my $def = $def_for{$col};
@@ -3137,6 +3137,11 @@ sub parse {
push @null, $col;
$is_nullable{$col} = 1;
}
if ( remove_quoted_text($def) =~ m/\WGENERATED\W/i ) {
$is_generated{$col} = 1;
} else {
push @non_generated, $col;
}
$is_autoinc{$col} = $def =~ m/AUTO_INCREMENT/i ? 1 : 0;
}
@@ -3145,24 +3150,34 @@ sub parse {
my ($charset) = $ddl =~ m/DEFAULT CHARSET=(\w+)/;
return {
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @cols },
null_cols => \@null,
is_nullable => \%is_nullable,
is_autoinc => \%is_autoinc,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @non_generated },
null_cols => \@null,
is_nullable => \%is_nullable,
non_generated_cols => \@non_generated,
is_autoinc => \%is_autoinc,
is_generated => \%is_generated,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
};
}
sub remove_quoted_text {
my ($string) = @_;
$string =~ s/[^\\]`[^`]*[^\\]`//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
return $string;
}
sub sort_indexes {
my ( $self, $tbl ) = @_;

View File

@@ -2945,8 +2945,8 @@ sub parse {
my %def_for;
@def_for{@cols} = @defs;
my (@nums, @null);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc);
my (@nums, @null, @non_generated);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc, %is_generated);
foreach my $col ( @cols ) {
my $def = $def_for{$col};
@@ -2963,6 +2963,11 @@ sub parse {
push @null, $col;
$is_nullable{$col} = 1;
}
if ( remove_quoted_text($def) =~ m/\WGENERATED\W/i ) {
$is_generated{$col} = 1;
} else {
push @non_generated, $col;
}
$is_autoinc{$col} = $def =~ m/AUTO_INCREMENT/i ? 1 : 0;
}
@@ -2971,24 +2976,34 @@ sub parse {
my ($charset) = $ddl =~ m/DEFAULT CHARSET=(\w+)/;
return {
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @cols },
null_cols => \@null,
is_nullable => \%is_nullable,
is_autoinc => \%is_autoinc,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @non_generated },
null_cols => \@null,
is_nullable => \%is_nullable,
non_generated_cols => \@non_generated,
is_autoinc => \%is_autoinc,
is_generated => \%is_generated,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
};
}
sub remove_quoted_text {
my ($string) = @_;
$string =~ s/[^\\]`[^`]*[^\\]`//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
return $string;
}
sub sort_indexes {
my ( $self, $tbl ) = @_;

View File

@@ -56,7 +56,7 @@ BEGIN {
{
package Percona::Toolkit;
our $VERSION = '3.0.4';
our $VERSION = '3.0.5';
use strict;
use warnings FATAL => 'all';
@@ -3309,8 +3309,8 @@ sub parse {
my %def_for;
@def_for{@cols} = @defs;
my (@nums, @null);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc);
my (@nums, @null, @non_generated);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc, %is_generated);
foreach my $col ( @cols ) {
my $def = $def_for{$col};
@@ -3327,6 +3327,11 @@ sub parse {
push @null, $col;
$is_nullable{$col} = 1;
}
if ( remove_quoted_text($def) =~ m/\WGENERATED\W/i ) {
$is_generated{$col} = 1;
} else {
push @non_generated, $col;
}
$is_autoinc{$col} = $def =~ m/AUTO_INCREMENT/i ? 1 : 0;
}
@@ -3335,24 +3340,34 @@ sub parse {
my ($charset) = $ddl =~ m/DEFAULT CHARSET=(\w+)/;
return {
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @cols },
null_cols => \@null,
is_nullable => \%is_nullable,
is_autoinc => \%is_autoinc,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @non_generated },
null_cols => \@null,
is_nullable => \%is_nullable,
non_generated_cols => \@non_generated,
is_autoinc => \%is_autoinc,
is_generated => \%is_generated,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
};
}
sub remove_quoted_text {
my ($string) = @_;
$string =~ s/[^\\]`[^`]*[^\\]`//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
return $string;
}
sub sort_indexes {
my ( $self, $tbl ) = @_;
@@ -11582,6 +11597,11 @@ The tool exits with an error if the host is a cluster node and the table
is MyISAM or is being converted to MyISAM (C<ENGINE=MyISAM>), or if
C<wsrep_OSU_method> is not C<TOI>. There is no way to disable these checks.
=head1 MySQL 5.7+ Generated columns
The tools ignores MySQL 5.7+ C<GENERATED> columns since the value for those columns
is generated according to the expresion used to compute column values.
=head1 OUTPUT
The tool prints information about its activities to STDOUT so that you can see

View File

@@ -8857,8 +8857,8 @@ sub parse {
my %def_for;
@def_for{@cols} = @defs;
my (@nums, @null);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc);
my (@nums, @null, @non_generated);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc, %is_generated);
foreach my $col ( @cols ) {
my $def = $def_for{$col};
@@ -8875,6 +8875,11 @@ sub parse {
push @null, $col;
$is_nullable{$col} = 1;
}
if ( remove_quoted_text($def) =~ m/\WGENERATED\W/i ) {
$is_generated{$col} = 1;
} else {
push @non_generated, $col;
}
$is_autoinc{$col} = $def =~ m/AUTO_INCREMENT/i ? 1 : 0;
}
@@ -8883,24 +8888,34 @@ sub parse {
my ($charset) = $ddl =~ m/DEFAULT CHARSET=(\w+)/;
return {
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @cols },
null_cols => \@null,
is_nullable => \%is_nullable,
is_autoinc => \%is_autoinc,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @non_generated },
null_cols => \@null,
is_nullable => \%is_nullable,
non_generated_cols => \@non_generated,
is_autoinc => \%is_autoinc,
is_generated => \%is_generated,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
};
}
sub remove_quoted_text {
my ($string) = @_;
$string =~ s/[^\\]`[^`]*[^\\]`//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
return $string;
}
sub sort_indexes {
my ( $self, $tbl ) = @_;

View File

@@ -4446,8 +4446,8 @@ sub parse {
my %def_for;
@def_for{@cols} = @defs;
my (@nums, @null);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc);
my (@nums, @null, @non_generated);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc, %is_generated);
foreach my $col ( @cols ) {
my $def = $def_for{$col};
@@ -4464,6 +4464,11 @@ sub parse {
push @null, $col;
$is_nullable{$col} = 1;
}
if ( remove_quoted_text($def) =~ m/\WGENERATED\W/i ) {
$is_generated{$col} = 1;
} else {
push @non_generated, $col;
}
$is_autoinc{$col} = $def =~ m/AUTO_INCREMENT/i ? 1 : 0;
}
@@ -4472,24 +4477,34 @@ sub parse {
my ($charset) = $ddl =~ m/DEFAULT CHARSET=(\w+)/;
return {
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @cols },
null_cols => \@null,
is_nullable => \%is_nullable,
is_autoinc => \%is_autoinc,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @non_generated },
null_cols => \@null,
is_nullable => \%is_nullable,
non_generated_cols => \@non_generated,
is_autoinc => \%is_autoinc,
is_generated => \%is_generated,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
};
}
sub remove_quoted_text {
my ($string) = @_;
$string =~ s/[^\\]`[^`]*[^\\]`//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
return $string;
}
sub sort_indexes {
my ( $self, $tbl ) = @_;

View File

@@ -2864,8 +2864,8 @@ sub parse {
my %def_for;
@def_for{@cols} = @defs;
my (@nums, @null);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc);
my (@nums, @null, @non_generated);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc, %is_generated);
foreach my $col ( @cols ) {
my $def = $def_for{$col};
@@ -2882,6 +2882,11 @@ sub parse {
push @null, $col;
$is_nullable{$col} = 1;
}
if ( remove_quoted_text($def) =~ m/\WGENERATED\W/i ) {
$is_generated{$col} = 1;
} else {
push @non_generated, $col;
}
$is_autoinc{$col} = $def =~ m/AUTO_INCREMENT/i ? 1 : 0;
}
@@ -2890,24 +2895,34 @@ sub parse {
my ($charset) = $ddl =~ m/DEFAULT CHARSET=(\w+)/;
return {
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @cols },
null_cols => \@null,
is_nullable => \%is_nullable,
is_autoinc => \%is_autoinc,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @non_generated },
null_cols => \@null,
is_nullable => \%is_nullable,
non_generated_cols => \@non_generated,
is_autoinc => \%is_autoinc,
is_generated => \%is_generated,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
};
}
sub remove_quoted_text {
my ($string) = @_;
$string =~ s/[^\\]`[^`]*[^\\]`//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
return $string;
}
sub sort_indexes {
my ( $self, $tbl ) = @_;

View File

@@ -6795,8 +6795,8 @@ sub parse {
my %def_for;
@def_for{@cols} = @defs;
my (@nums, @null);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc);
my (@nums, @null, @non_generated);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc, %is_generated);
foreach my $col ( @cols ) {
my $def = $def_for{$col};
@@ -6813,6 +6813,11 @@ sub parse {
push @null, $col;
$is_nullable{$col} = 1;
}
if ( remove_quoted_text($def) =~ m/\WGENERATED\W/i ) {
$is_generated{$col} = 1;
} else {
push @non_generated, $col;
}
$is_autoinc{$col} = $def =~ m/AUTO_INCREMENT/i ? 1 : 0;
}
@@ -6821,24 +6826,34 @@ sub parse {
my ($charset) = $ddl =~ m/DEFAULT CHARSET=(\w+)/;
return {
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @cols },
null_cols => \@null,
is_nullable => \%is_nullable,
is_autoinc => \%is_autoinc,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @non_generated },
null_cols => \@null,
is_nullable => \%is_nullable,
non_generated_cols => \@non_generated,
is_autoinc => \%is_autoinc,
is_generated => \%is_generated,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
};
}
sub remove_quoted_text {
my ($string) = @_;
$string =~ s/[^\\]`[^`]*[^\\]`//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
return $string;
}
sub sort_indexes {
my ( $self, $tbl ) = @_;

View File

@@ -159,8 +159,8 @@ sub parse {
# Find column types, whether numeric, whether nullable, whether
# auto-increment.
my (@nums, @null);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc);
my (@nums, @null, @non_generated);
my (%type_for, %is_nullable, %is_numeric, %is_autoinc, %is_generated);
foreach my $col ( @cols ) {
my $def = $def_for{$col};
@@ -180,6 +180,11 @@ sub parse {
push @null, $col;
$is_nullable{$col} = 1;
}
if ( remove_quoted_text($def) =~ m/\WGENERATED\W/i ) {
$is_generated{$col} = 1;
} else {
push @non_generated, $col;
}
$is_autoinc{$col} = $def =~ m/AUTO_INCREMENT/i ? 1 : 0;
}
@@ -191,24 +196,34 @@ sub parse {
my ($charset) = $ddl =~ m/DEFAULT CHARSET=(\w+)/;
return {
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @cols },
null_cols => \@null,
is_nullable => \%is_nullable,
is_autoinc => \%is_autoinc,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
name => $name,
cols => \@cols,
col_posn => { map { $cols[$_] => $_ } 0..$#cols },
is_col => { map { $_ => 1 } @non_generated },
null_cols => \@null,
is_nullable => \%is_nullable,
non_generated_cols => \@non_generated,
is_autoinc => \%is_autoinc,
is_generated => \%is_generated,
clustered_key => $clustered_key,
keys => $keys,
defs => \%def_for,
numeric_cols => \@nums,
is_numeric => \%is_numeric,
engine => $engine,
type_for => \%type_for,
charset => $charset,
};
}
sub remove_quoted_text {
my ($string) = @_;
$string =~ s/[^\\]`[^`]*[^\\]`//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
$string =~ s/[^\\]"[^"]*[^\\]"//g;
return $string;
}
# Sorts indexes in this order: PRIMARY, unique, non-nullable, any (shortest
# first, alphabetical). Only BTREE indexes are considered.
# TODO: consider length as # of bytes instead of # of columns.

View File

@@ -11,6 +11,7 @@ use warnings FATAL => 'all';
use English qw(-no_match_vars);
use Test::More;
use Text::Diff;
use TableParser;
use Quoter;
use DSNParser;
@@ -71,21 +72,23 @@ like($EVAL_ERROR, qr/quoting/, 'No quoting');
$tbl = $tp->parse( load_file('t/lib/samples/t1.sql') );
is_deeply(
$tbl,
{ cols => [qw(a)],
col_posn => { a => 0 },
is_col => { a => 1 },
is_autoinc => { a => 0 },
null_cols => [qw(a)],
is_nullable => { a => 1 },
clustered_key => undef,
keys => {},
defs => { a => ' `a` int(11) default NULL' },
numeric_cols => [qw(a)],
is_numeric => { a => 1 },
engine => 'MyISAM',
type_for => { a => 'int' },
name => 't1',
charset => 'latin1',
{ cols => [qw(a)],
col_posn => { a => 0 },
is_col => { a => 1 },
is_autoinc => { a => 0 },
null_cols => [qw(a)],
is_generated => {},
non_generated_cols => [ 'a' ],
is_nullable => { a => 1 },
clustered_key => undef,
keys => {},
defs => { a => ' `a` int(11) default NULL' },
numeric_cols => [qw(a)],
is_numeric => { a => 1 },
engine => 'MyISAM',
type_for => { a => 'int' },
name => 't1',
charset => 'latin1',
},
'Basic table is OK',
);
@@ -94,11 +97,13 @@ $tbl = $tp->parse( load_file('t/lib/samples/TableParser-prefix_idx.sql') );
is_deeply(
$tbl,
{
name => 't1',
cols => [ 'a', 'b' ],
col_posn => { a => 0, b => 1 },
is_col => { a => 1, b => 1 },
is_autoinc => { 'a' => 0, 'b' => 0 },
name => 't1',
cols => [ 'a', 'b' ],
non_generated_cols => [ 'a', 'b' ],
col_posn => { a => 0, b => 1 },
is_col => { a => 1, b => 1 },
is_autoinc => { 'a' => 0, 'b' => 0 },
is_generated => {},
null_cols => [ 'a', 'b' ],
is_nullable => { 'a' => 1, 'b' => 1 },
clustered_key => undef,
@@ -169,6 +174,12 @@ is_deeply(
length replacement_cost rating special_features
last_update)
],
non_generated_cols => [
qw(film_id title description release_year language_id
original_language_id rental_duration rental_rate
length replacement_cost rating special_features
last_update)
],
col_posn => {
film_id => 0,
title => 1,
@@ -214,6 +225,7 @@ is_deeply(
special_features => 1,
last_update => 1,
},
is_generated => {},
null_cols => [qw(description release_year original_language_id length rating special_features )],
is_nullable => {
description => 1,
@@ -342,25 +354,109 @@ throws_ok (
$tbl = $tp->parse( load_file('t/lib/samples/temporary_table.sql') );
is_deeply(
$tbl,
{ cols => [qw(a)],
col_posn => { a => 0 },
is_col => { a => 1 },
is_autoinc => { a => 0 },
null_cols => [qw(a)],
is_nullable => { a => 1 },
clustered_key => undef,
keys => {},
defs => { a => ' `a` int(11) default NULL' },
numeric_cols => [qw(a)],
is_numeric => { a => 1 },
engine => 'MyISAM',
type_for => { a => 'int' },
name => 't',
charset => 'latin1',
{ cols => [qw(a)],
non_generated_cols => [qw(a)],
col_posn => { a => 0 },
is_col => { a => 1 },
is_autoinc => { a => 0 },
is_generated => {},
null_cols => [qw(a)],
is_nullable => { a => 1 },
clustered_key => undef,
keys => {},
defs => { a => ' `a` int(11) default NULL' },
numeric_cols => [qw(a)],
is_numeric => { a => 1 },
engine => 'MyISAM',
type_for => { a => 'int' },
name => 't',
charset => 'latin1',
},
'Temporary table',
);
my $want = { 'is_autoinc' => {
'sort_order' => 0,
'pfk-source_instrument_id' => 0,
'pfk-related_instrument_id' => 0
},
'null_cols' => [],
'numeric_cols' => [
'pfk-source_instrument_id', 'pfk-related_instrument_id',
'sort_order'
],
'cols' => [
'pfk-source_instrument_id', 'pfk-related_instrument_id',
'sort_order'
],
'non_generated_cols' => [
'pfk-source_instrument_id', 'pfk-related_instrument_id',
'sort_order'
],
is_autogenerated => {},
'col_posn' => {
'sort_order' => 2,
'pfk-source_instrument_id' => 0,
'pfk-related_instrument_id' => 1
},
clustered_key => 'PRIMARY',
'keys' => {
'sort_order' => {
'is_unique' => 0,
'is_col' => { 'sort_order' => 1 },
'name' => 'sort_order',
'type' => 'BTREE',
'col_prefixes' => [ undef ],
'is_nullable' => 0,
'colnames' => '`sort_order`',
'cols' => [ 'sort_order' ],
ddl => 'KEY `sort_order` (`sort_order`)',
},
'PRIMARY' => {
'is_unique' => 1,
'is_col' => {
'pfk-source_instrument_id' => 1,
'pfk-related_instrument_id' => 1
},
'name' => 'PRIMARY',
'type' => 'BTREE',
'col_prefixes' => [ undef, undef ],
'is_nullable' => 0,
'colnames' =>
'`pfk-source_instrument_id`,`pfk-related_instrument_id`',
'cols' =>
[ 'pfk-source_instrument_id', 'pfk-related_instrument_id' ],
ddl => 'PRIMARY KEY (`pfk-source_instrument_id`,`pfk-related_instrument_id`),',
}
},
'defs' => {
'sort_order' => ' `sort_order` int(11) NOT NULL',
'pfk-source_instrument_id' =>
' `pfk-source_instrument_id` int(10) unsigned NOT NULL',
'pfk-related_instrument_id' =>
' `pfk-related_instrument_id` int(10) unsigned NOT NULL'
},
'engine' => 'InnoDB',
'is_col' => {
'sort_order' => 1,
'pfk-source_instrument_id' => 1,
'pfk-related_instrument_id' => 1
},
'is_numeric' => {
'sort_order' => 1,
'pfk-source_instrument_id' => 1,
'pfk-related_instrument_id' => 1
},
'type_for' => {
'sort_order' => 'int',
'pfk-source_instrument_id' => 'int',
'pfk-related_instrument_id' => 'int'
},
'is_nullable' => {},
name => 'instrument_relation',
charset => 'latin1',
};
$tbl = $tp->parse( load_file('t/lib/samples/hyphentest.sql') );
is_deeply(
$tbl,
@@ -378,6 +474,11 @@ is_deeply(
'pfk-source_instrument_id', 'pfk-related_instrument_id',
'sort_order'
],
'non_generated_cols' => [
'pfk-source_instrument_id', 'pfk-related_instrument_id',
'sort_order'
],
is_generated => {},
'col_posn' => {
'sort_order' => 2,
'pfk-source_instrument_id' => 0,
@@ -446,13 +547,14 @@ is_deeply(
$tbl = $tp->parse( load_file('t/lib/samples/ndb_table.sql') );
is_deeply(
$tbl,
{ cols => [qw(id)],
col_posn => { id => 0 },
is_col => { id => 1 },
is_autoinc => { id => 1 },
null_cols => [],
is_nullable => {},
clustered_key => undef,
{ cols => [qw(id)],
non_generated_cols => [qw(id)],
col_posn => { id => 0 },
is_col => { id => 1 },
is_autoinc => { id => 1 },
null_cols => [],
is_nullable => {},
clustered_key => undef,
keys => {
PRIMARY => {
cols => [qw(id)],
@@ -473,6 +575,7 @@ is_deeply(
type_for => { id => 'bigint' },
name => 'pipo',
charset => 'latin1',
is_generated => {},
},
'NDB table',
);
@@ -481,9 +584,11 @@ $tbl = $tp->parse( load_file('t/lib/samples/mixed-case.sql') );
is_deeply(
$tbl,
{ cols => [qw(a b mixedcol)],
non_generated_cols => [qw(a b mixedcol)],
col_posn => { a => 0, b => 1, mixedcol => 2 },
is_col => { a => 1, b => 1, mixedcol => 1 },
is_autoinc => { a => 0, b => 0, mixedcol => 0 },
is_generated => {},
null_cols => [qw(a b mixedcol)],
is_nullable => { a => 1, b => 1, mixedcol => 1 },
clustered_key => undef,
@@ -518,14 +623,15 @@ is_deeply(
$tbl = $tp->parse( load_file('t/lib/samples/one_key.sql') );
is_deeply(
$tbl,
{ cols => [qw(a b)],
col_posn => { a => 0, b => 1 },
is_col => { a => 1, b => 1 },
is_autoinc => { a => 0, b => 0 },
null_cols => [qw(b)],
is_nullable => { b => 1 },
clustered_key => undef,
keys => {
{ cols => [qw(a b)],
non_generated_cols => [qw(a b)],
col_posn => { a => 0, b => 1 },
is_col => { a => 1, b => 1 },
is_autoinc => { a => 0, b => 0 },
null_cols => [qw(b)],
is_nullable => { b => 1 },
clustered_key => undef,
keys => {
PRIMARY => {
colnames => '`a`',
cols => [qw(a)],
@@ -538,16 +644,17 @@ is_deeply(
ddl => 'PRIMARY KEY (`a`)',
},
},
defs => {
defs => {
a => ' `a` int(11) NOT NULL',
b => ' `b` char(50) default NULL',
},
numeric_cols => [qw(a)],
is_numeric => { a => 1 },
engine => 'MyISAM',
type_for => { a => 'int', b => 'char' },
name => 't2',
charset => 'latin1',
numeric_cols => [qw(a)],
is_numeric => { a => 1 },
is_generated => {},
engine => 'MyISAM',
type_for => { a => 'int', b => 'char' },
name => 't2',
charset => 'latin1',
},
'No clustered key on MyISAM table'
);
@@ -751,21 +858,23 @@ cmp_ddls('v5.0 vs. v5.1', 't/lib/samples/issue_109-01-v50.sql', 't/lib/samples/i
$tbl = $tp->parse( load_file('t/lib/samples/issue_132.sql') );
is_deeply(
$tbl,
{ cols => [qw(country)],
col_posn => { country => 0 },
is_col => { country => 1 },
is_autoinc => { country => 0 },
null_cols => [qw(country)],
is_nullable => { country => 1 },
clustered_key => undef,
keys => {},
defs => { country => " `country` enum('','Cote D`ivoire') default NULL"},
numeric_cols => [],
is_numeric => {},
engine => 'MyISAM',
type_for => { country => 'enum' },
name => 'issue_132',
charset => 'latin1',
{ cols => [qw(country)],
non_generated_cols => [qw(country)],
col_posn => { country => 0 },
is_col => { country => 1 },
is_autoinc => { country => 0 },
is_generated => {},
null_cols => [qw(country)],
is_nullable => { country => 1 },
clustered_key => undef,
keys => {},
defs => { country => " `country` enum('','Cote D`ivoire') default NULL"},
numeric_cols => [],
is_numeric => {},
engine => 'MyISAM',
type_for => { country => 'enum' },
name => 'issue_132',
charset => 'latin1',
},
'ENUM col with backtick in value (issue 132)'
);
@@ -787,21 +896,23 @@ is(
$tbl = $tp->parse( load_file('t/lib/samples/issue_330_backtick_pair_in_col_comments.sql') );
is_deeply(
$tbl,
{ cols => [qw(a)],
col_posn => { a => 0 },
is_col => { a => 1 },
is_autoinc => { a => 0 },
null_cols => [qw(a)],
is_nullable => { a => 1 },
clustered_key => undef,
keys => {},
defs => { a => " `a` int(11) DEFAULT NULL COMMENT 'issue_330 `alex`'" },
numeric_cols => [qw(a)],
is_numeric => { a => 1 },
engine => 'MyISAM',
type_for => { a => 'int' },
name => 'issue_330',
charset => 'latin1',
{ cols => [qw(a)],
non_generated_cols => [qw(a)],
col_posn => { a => 0 },
is_col => { a => 1 },
is_generated => {},
is_autoinc => { a => 0 },
null_cols => [qw(a)],
is_nullable => { a => 1 },
clustered_key => undef,
keys => {},
defs => { a => " `a` int(11) DEFAULT NULL COMMENT 'issue_330 `alex`'" },
numeric_cols => [qw(a)],
is_numeric => { a => 1 },
engine => 'MyISAM',
type_for => { a => 'int' },
name => 'issue_330',
charset => 'latin1',
},
'issue with pairing backticks in column comments (issue 330)'
);
@@ -810,24 +921,26 @@ is_deeply(
$tbl = $tp->parse( load_file('t/lib/samples/issue_pt-193_backtick_in_col_comments.sql') );
is_deeply(
$tbl,
{ cols => [qw(id f22abcde f23abc)],
col_posn => { id => 0, f22abcde => 1, f23abc => 2 },
is_col => { id => 1, f22abcde => 1, f23abc => 1 },
is_autoinc => { id => 1, f22abcde => 0, f23abc => 0 },
null_cols => [qw(f22abcde)],
is_nullable => { f22abcde => 1},
clustered_key => undef,
keys => {},
defs => { id => " `id` int(11) NOT NULL AUTO_INCREMENT",
"f22abcde" => " `f22abcde` int(10) unsigned DEFAULT NULL COMMENT 'xxx`XXx'",
"f23abc" => " `f23abc` int(10) unsigned NOT NULL DEFAULT '255' COMMENT \"`yyy\""
},
numeric_cols => [qw(id f22abcde f23abc)],
is_numeric => { id => 1, f22abcde => 1, f23abc => 1 },
engine => 'InnoDB',
type_for => { id => 'int', f22abcde => 'int', f23abc => 'int' },
name => 't3',
charset => 'latin1',
{ cols => [qw(id f22abcde f23abc)],
non_generated_cols => [qw(id f22abcde f23abc)],
col_posn => { id => 0, f22abcde => 1, f23abc => 2 },
is_col => { id => 1, f22abcde => 1, f23abc => 1 },
is_autoinc => { id => 1, f22abcde => 0, f23abc => 0 },
is_generated => {},
null_cols => [qw(f22abcde)],
is_nullable => { f22abcde => 1},
clustered_key => undef,
keys => {},
defs => { id => " `id` int(11) NOT NULL AUTO_INCREMENT",
"f22abcde" => " `f22abcde` int(10) unsigned DEFAULT NULL COMMENT 'xxx`XXx'",
"f23abc" => " `f23abc` int(10) unsigned NOT NULL DEFAULT '255' COMMENT \"`yyy\""
},
numeric_cols => [qw(id f22abcde f23abc)],
is_numeric => { id => 1, f22abcde => 1, f23abc => 1 },
engine => 'InnoDB',
type_for => { id => 'int', f22abcde => 'int', f23abc => 'int' },
name => 't3',
charset => 'latin1',
},
'issue with pairing backticks in column comments (issue 330)'
);
@@ -874,12 +987,14 @@ is_deeply(
clustered_key => undef,
col_posn => { 'first, last' => 1, id => 0 },
cols => [ 'id', 'first, last' ],
non_generated_cols => [ 'id', 'first, last' ],
defs => {
'first, last' => ' `first, last` varchar(32) default NULL',
id => ' `id` int(11) NOT NULL auto_increment',
},
engine => 'MyISAM',
is_autoinc => { 'first, last' => 0, id => 1 },
is_generated => {},
is_col => { 'first, last' => 1, id => 1 },
is_nullable => { 'first, last' => 1 },
is_numeric => { id => 1 },
@@ -1000,22 +1115,24 @@ $tbl = $tp->parse(load_file('t/lib/samples/triple-quoted-col.sql'));
is_deeply(
$tbl,
{
clustered_key => undef,
col_posn => { 'foo' => 0, bar => 1 },
cols => [ 'foo', 'bar' ],
defs => {
clustered_key => undef,
col_posn => { 'foo' => 0, bar => 1 },
is_generated => {},
cols => [ 'foo', 'bar' ],
non_generated_cols => [ 'foo', 'bar' ],
defs => {
'foo' => ' `foo` int(11) DEFAULT NULL',
'bar' => ' ```bar``` int(11) DEFAULT NULL',
},
engine => 'InnoDB',
is_autoinc => { foo => 0, bar => 0 },
is_col => { foo => 1, bar => 1 },
is_nullable => { foo => 1, bar => 1 },
is_numeric => { foo => 1, bar => 1 },
name => 't',
null_cols => [ 'foo', 'bar' ],
numeric_cols => [ 'foo', 'bar' ],
type_for => {
engine => 'InnoDB',
is_autoinc => { foo => 0, bar => 0 },
is_col => { foo => 1, bar => 1 },
is_nullable => { foo => 1, bar => 1 },
is_numeric => { foo => 1, bar => 1 },
name => 't',
null_cols => [ 'foo', 'bar' ],
numeric_cols => [ 'foo', 'bar' ],
type_for => {
foo => 'int',
bar => 'int',
},
@@ -1025,6 +1142,51 @@ is_deeply(
'Literal backticks (bug 1462904)'
);
SKIP: {
skip "generated column tests require MySQL 5.7+", 1
if $sandbox_version lt '5.7';
$tbl = $tp->parse( load_file('t/lib/samples/generated_cols.sql') );
is_deeply(
$tbl,
{
charset => 'utf8mb4',
clustered_key => 'PRIMARY',
col_posn => { column2 => 1, column3 => 2, id => 0 },
cols => [ 'id', 'column2', 'column3' ],
non_generated_cols => [ 'id', 'column2' ],
defs => {
column2 => ' `column2` int(11) DEFAULT NULL',
column3 => ' `column3` int(11) GENERATED ALWAYS AS ((`column2` + 1)) STORED',
id => ' `id` int(11) NOT NULL'
},
engine => 'InnoDB',
is_autoinc => { column2 => 0, column3 => 0, id => 0 },
is_col => { column2 => 1, column3 => 1, id => 1 },
is_generated => { column3 => 1 },
is_nullable => { column2 => 1, column3 => 1 },
is_numeric => { column2 => 1, column3 => 1, id => 1 },
keys => {
PRIMARY => {
col_prefixes => [ undef ],
colnames => '`id`',
cols => [ 'id' ],
ddl => 'PRIMARY KEY (`id`)',
is_col => { id => 1 },
is_nullable => 0,
is_unique => 1,
name => 'PRIMARY',
type => 'BTREE'
}
},
name => 't1',
null_cols => [ 'column2', 'column3' ],
numeric_cols => [ 'id', 'column2', 'column3' ],
type_for => { column2 => 'int', column3 => 'int', id => 'int' }
},
'Generated columns is OK',
) or die Data::Dumper::Dumper($tbl);
}
# #############################################################################
# Done.
# #############################################################################

View File

@@ -0,0 +1,6 @@
CREATE TABLE `t1` (
`ID` int(11) NOT NULL,
`Column2` int(11) DEFAULT NULL,
`Column3` int(11) GENERATED ALWAYS AS ((`Column2` + 1)) STORED,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

View File

@@ -0,0 +1,76 @@
#!/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 threads;
use English qw(-no_match_vars);
use Test::More;
use Data::Dumper;
use PerconaTest;
use Sandbox;
use SqlModes;
use File::Temp qw/ tempdir /;
require "$trunk/bin/pt-online-schema-change";
my $dp = new DSNParser(opts=>$dsn_opts);
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
my $master_dbh = $sb->get_dbh_for('master');
my $master_dsn = 'h=127.1,P=12345,u=msandbox,p=msandbox';
if ( !$master_dbh ) {
plan skip_all => 'Cannot connect to sandbox master';
}
if ($sandbox_version lt '5.7') {
plan skip_all => "generated column tests require MySQL 5.7+";
}
plan tests => 3;
# The sandbox servers run with lock_wait_timeout=3 and it's not dynamic
# so we need to specify --set-vars innodb_lock_wait_timeout=3 else the
# tool will die.
my @args = (qw(--set-vars innodb_lock_wait_timeout=3));
my $output;
my $exit_status;
my $sample = "t/pt-online-schema-change/samples/";
$sb->load_file('master', "$sample/pt-202.sql");
($output, $exit_status) = full_output(
sub { pt_online_schema_change::main(@args, "$master_dsn,D=test,t=t1",
'--execute',
'--alter', "ADD COLUMN `Column4` VARCHAR(45) NULL AFTER `Column3`",
),
},
);
is(
$exit_status,
0,
"PT-202 Altering table having generated columns exit status 0",
);
like(
$output,
qr/Successfully altered `test`.`t1`/s,
"PT-202 Altering table having generated columns success",
);
$master_dbh->do("DROP DATABASE IF EXISTS test");
# #############################################################################
# Done.
# #############################################################################
$sb->wipe_clean($master_dbh);
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
done_testing;

View File

@@ -0,0 +1,9 @@
CREATE SCHEMA IF NOT EXISTS test;
USE test;
DROP TABLE IF EXISTS t1;
CREATE TABLE `test`.`t1` (
`ID` int(11) NOT NULL,
`Column2` int(11) DEFAULT NULL,
`Column3` int(11) GENERATED ALWAYS AS ((`Column2` + 1)) STORED,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;