Merge pull request #974 from marek-knappe/PT-2457-pt-online-schema-change-add-drop-tablespace-Option

fix(pt-online-schema-change): correct --remove-data-dir default behav…
This commit is contained in:
Sveta Smirnova
2025-07-23 13:11:59 +03:00
committed by GitHub
28 changed files with 326 additions and 28 deletions

View File

@@ -319,7 +319,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -1048,7 +1048,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -1046,7 +1046,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -396,7 +396,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -392,7 +392,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -1451,7 +1451,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -320,7 +320,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -839,7 +839,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -321,7 +321,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -391,7 +391,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -1349,7 +1349,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -1005,7 +1005,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -401,7 +401,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -458,7 +458,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}
@@ -11413,6 +11415,10 @@ sub create_new_table {
$sql =~ s/DATA DIRECTORY\s*=\s*'.*?'//;
PTDEBUG && _d("removing data dir");
}
if ( $o->got('remove-tablespace') ) {
$sql =~ s/TABLESPACE\s+`[^`]+`\s*//;
PTDEBUG && _d("removing tablespace");
}
PTDEBUG && _d($sql);
eval {
$cxn->dbh()->do($sql);
@@ -12472,7 +12478,7 @@ sub exec_nibble {
#
# Required Arguments:
# * tbl - Standard tbl hashref
# * sth - Sth with EXLAIN <statement>
# * sth - Sth with EXPLAIN <statement>
# * vals - Values for sth, if any
#
# Returns:
@@ -13183,7 +13189,14 @@ than remove-data-dir.
default: no
If the original table was created using the DATA DIRECTORY feature, remove it and create
the new table in MySQL default directory without creating a new isl file.
the new table in MySQL directory without creating a new isl file.
=item --remove-tablespace
default: no
If the original table was created using the TABLESPACE feature, remove it and create
the new table without the TABLESPACE specification.
=item --defaults-file

View File

@@ -1673,7 +1673,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -329,7 +329,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -551,7 +551,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -322,7 +322,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -395,7 +395,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -2155,7 +2155,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -409,7 +409,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -1441,7 +1441,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -1670,7 +1670,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -398,7 +398,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -1008,7 +1008,9 @@ sub _parse_specs {
$opt->{spec} =~ s/=./=s/ if ( $type && $type =~ m/[HhAadzm]/ );
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -406,7 +406,9 @@ sub _parse_specs {
# These defaults from the POD may be overridden by later calls
# to set_defaults().
if ( (my ($def) = $opt->{desc} =~ m/default\b(?: ([^)]+))?/) ) {
$self->{defaults}->{$long} = defined $def ? $def : 1;
$def = defined $def ? $def : 1;
$def = $def eq 'yes' ? 1 : $def eq 'no' ? 0 : $def;
$self->{defaults}->{$long} = $def;
PTDEBUG && _d($long, 'default:', $def);
}

View File

@@ -0,0 +1,173 @@
#!/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;
use PerconaTest;
use Sandbox;
use SqlModes;
require "$trunk/bin/pt-online-schema-change";
my $dp = new DSNParser(opts=>$dsn_opts);
my $sb = new Sandbox(basedir => '/tmp', DSNParser => $dp);
if ($sandbox_version lt '5.7') {
plan skip_all => 'This test needs MySQL 5.7+ for general tablespace support';
} else {
plan tests => 10;
}
my $source_dbh = $sb->get_dbh_for('source');
my $replica_dbh = $sb->get_dbh_for('replica1');
if ( !$source_dbh ) {
plan skip_all => 'Cannot connect to sandbox source';
}
elsif ( !$replica_dbh ) {
plan skip_all => 'Cannot connect to sandbox replica';
}
# 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 $dsn = "h=127.1,P=12345,u=msandbox,p=msandbox";
my $sample = "t/pt-online-schema-change/samples";
# #############################################################################
# Test 1: Basic functionality - remove tablespace from table
# #############################################################################
$sb->load_file('source', "$sample/remove_tablespace.sql");
# Verify the table was created with tablespace
my $ddl = $source_dbh->selectrow_arrayref("SHOW CREATE TABLE test_ts.test_table");
like(
$ddl->[1],
qr/TABLESPACE `test_tablespace`/,
"Table created with tablespace"
);
# Get original row count
my $orig_rows = $source_dbh->selectall_arrayref(
"SELECT * FROM test_ts.test_table ORDER BY id"
);
($output, $exit_status) = full_output(
sub { pt_online_schema_change::main(@args, "$dsn,D=test_ts,t=test_table",
'--execute',
'--alter', "ADD COLUMN new_col INT DEFAULT 42",
'--remove-tablespace',
)},
stderr => 1,
);
is(
$exit_status,
0,
"Successfully altered table with --remove-tablespace"
);
like(
$output,
qr/Successfully altered/s,
"Got successfully altered message"
);
# Verify tablespace was removed from the table
$ddl = $source_dbh->selectrow_arrayref("SHOW CREATE TABLE test_ts.test_table");
unlike(
$ddl->[1],
qr/TABLESPACE `test_tablespace`/,
"Tablespace removed from table definition"
);
# Verify data integrity
my $new_rows = $source_dbh->selectall_arrayref(
"SELECT id, name, created_at FROM test_ts.test_table ORDER BY id"
);
is_deeply(
$new_rows,
$orig_rows,
"Data integrity maintained after removing tablespace"
);
# #############################################################################
# Test 3: Test with second table
# #############################################################################
($output, $exit_status) = full_output(
sub { pt_online_schema_change::main(@args, "$dsn,D=test_ts,t=test_table2",
'--execute',
'--alter', "ADD COLUMN second_col BOOLEAN DEFAULT FALSE",
'--remove-tablespace',
)},
stderr => 1,
);
is(
$exit_status,
0,
"Successfully altered second table with --remove-tablespace"
);
# Verify tablespace was removed from the second table
$ddl = $source_dbh->selectrow_arrayref("SHOW CREATE TABLE test_ts.test_table2");
unlike(
$ddl->[1],
qr/TABLESPACE `test_tablespace`/,
"Tablespace removed from second table definition"
);
# #############################################################################
# Test 4: Test without --remove-tablespace (control test)
# #############################################################################
$sb->load_file('source', "$sample/remove_tablespace.sql");
($output, $exit_status) = full_output(
sub { pt_online_schema_change::main(@args, "$dsn,D=test_ts,t=test_table",
'--execute',
'--alter', "ADD COLUMN control_col INT DEFAULT 0",
)},
stderr => 1,
);
is(
$exit_status,
0,
"Successfully altered table without --remove-tablespace"
);
# Verify tablespace is preserved when not using --remove-tablespace
$ddl = $source_dbh->selectrow_arrayref("SHOW CREATE TABLE test_ts.test_table");
like(
$ddl->[1],
qr/TABLESPACE `test_tablespace`/,
"Tablespace preserved when not using --remove-tablespace"
);
# #############################################################################
# Cleanup
# #############################################################################
$source_dbh->do("DROP DATABASE IF EXISTS test_ts");
$source_dbh->do("DROP TABLESPACE test_tablespace");
$sb->wipe_clean($source_dbh);
$sb->wipe_clean($replica_dbh);
ok($sb->ok(), "Sandbox servers") or BAIL_OUT(__FILE__ . " broke the sandbox");
done_testing;

View File

@@ -0,0 +1,62 @@
-- Sample table with tablespace for testing --remove-tablespace functionality
-- This requires MySQL 5.7+ for general tablespace support
-- Clean
-- Drop the database if it exists
DROP DATABASE IF EXISTS test_ts;
CREATE DATABASE IF NOT EXISTS test_ts;
USE test_ts;
DELIMITER $$
-- Procedure to delete tablespace as there is no IF EXIST for tablespace
CREATE PROCEDURE drop_tablespace_if_exists()
BEGIN
DECLARE ts_count INT;
SELECT COUNT(*) INTO ts_count
FROM information_schema.FILES
WHERE tablespace_name = 'test_tablespace';
IF ts_count > 0 THEN
SET @stmt := 'DROP TABLESPACE test_tablespace';
DROP TABLESPACE test_tablespace;
END IF;
END$$
DELIMITER ;
-- Call the procedure
CALL drop_tablespace_if_exists();
-- Create a general tablespace first (MySQL 5.7+)
CREATE TABLESPACE test_tablespace ADD DATAFILE 'test_tablespace.ibd';
-- Create table with tablespace
CREATE TABLE test_table (
id INT PRIMARY KEY,
name VARCHAR(50),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
) TABLESPACE test_tablespace;
-- Insert some test data
INSERT INTO test_table (id, name) VALUES
(1, 'Alice'),
(2, 'Bob'),
(3, 'Charlie'),
(4, 'David'),
(5, 'Eve');
-- Create another table with tablespace for testing multiple tables
CREATE TABLE test_table2 (
id INT PRIMARY KEY,
description TEXT,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP
) TABLESPACE test_tablespace;
INSERT INTO test_table2 (id, description) VALUES
(1, 'First record'),
(2, 'Second record'),
(3, 'Third record');