2 # See the NOTICE file distributed with this work for additional information
3 # regarding copyright ownership.
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
9 # http://www.apache.org/licenses/LICENSE-2.0
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
25 use Getopt::Long qw/:config no_ignore_case auto_version bundling_override/;
30 my $opts = { port => 3306, verbose => 0 };
37 databases|database|db=s@
43 ) or pod2usage(-verbose => 1, -exitval => 1);
44 pod2usage(-verbose => 1, -exitval => 0) if $opts->{help};
45 pod2usage(-verbose => 2, -exitval => 0) if $opts->{man};
46 $self->{
opts} = $opts;
50 my $rcsid =
'$Revision$';
51 our ($VERSION) = $rcsid =~ /(\d+\.\d+)/;
55 my $self = bless({}, $class);
61 select($self->{oldfh});
69 my $o = $self->opts();
71 foreach my $required (qw/username databases host/) {
72 pod2usage(-msg => sprintf(
'No -%s specified', $required), -verbose => 2, -exitval => 1);
74 #Processing -opt 1 -opt 2,3 into opt => [1,2,3]
75 $self->_cmd_line_to_array(
'databases')
if $o->{databases};
77 $self->v(q{Working with %d database(s)}, scalar(@{$o->{databases}}));
84 my $o = $self->opts();
88 open my $fh,
'>', $file or die
"Cannot open log file '${file}' for writing: $!";
89 my $oldfh = select($fh);
90 $self->{oldfh} = $oldfh;
97 my $databases = $self->opts()->{databases};
98 foreach my $db (@{$databases}) {
99 $self->v(
'Working with database %s', $db);
101 $self->delete_tables();
102 my $ddl = sprintf(
'drop database %s', $db);
103 $self->v(qq{\tRunning:
'%s'}, $ddl);
104 $self->dbh()->do($ddl);
105 $self->clear_tables();
113 my @tables = keys %{ $self->tables() };
114 foreach my $table (@tables) {
115 $self->v(q{Processing
'%s'}, $table);
117 if($self->is_view($table)) {
118 $self->v(q{
'%s' is a view; just dropping}, $table);
119 push(@sql,
'drop view '.$table);
122 $self->v(q{
'%s' is being truncated and then dropped}, $table);
124 'truncate table '.$table,
125 'drop table '.$table,
129 foreach my $statement (@sql) {
130 $self->v(qq{\tRunning:
'%s'}, $statement);
131 $self->dbh()->do($statement);
138 my ($self, $msg, @args) = @_;
139 return unless $self->opts()->{verbose};
140 my $s_msg = sprintf($msg, @args);
141 my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) =
143 print sprintf(
"[%02d-%02d-%04d %02d:%02d:%02d] %s\n",
144 $mday, $mon, $year + 1900,
145 $hour, $min, $sec, $s_msg);
150 my ($self, $database) = @_;
151 if (!exists $self->{
'dbh'}) {
152 my $o = $self->opts();
153 my %args = (host => $o->{host}, port => $o->{port});
154 $args{database} = $database
if defined $database;
157 'DBI:mysql:' . join(q{;},
map { $_ .
'=' . $args{$_} } keys %args);
158 $self->v(
'DBI connection URI %s', $dsn);
160 DBI->connect($dsn, $o->{username}, $o->{password}, { RaiseError => 1 });
164 return $self->{
'dbh'};
169 if (exists $self->{dbh}) {
170 $self->{dbh}->disconnect();
177 my ($self, $table) = @_;
178 return ($self->tables()->{$table} eq
'VIEW') ? 1 : 0;
183 if (!exists $self->{tables}) {
185 $self->dbh()->selectcol_arrayref(
186 'select TABLE_NAME, TABLE_TYPE from information_schema.TABLES where TABLE_SCHEMA = DATABASE()',
187 { Columns => [ 1, 2 ] }
189 my %hits = @{$array};
190 $self->{tables} = \%hits;
192 return $self->{tables};
197 delete $self->{tables};
201 sub _cmd_line_to_array {
202 my ($self, $key) = @_;
203 my $array = $self->opts()->{$key};
204 $array = (ref($array) && ref($array) eq
'ARRAY') ? $array : [$array];
205 my $string = join(q{,}, @{$array});
206 my @new_array = split(/,/, $string);
207 $self->opts()->{$key} = \@new_array;
225 ./remove_mysqldb.pl -username USER -password PASS -host HOST [-port PORT] -database DB [-verbose] [-help | -man]
228 ./remove_mysqldb.pl -username USER -password PASS -host HOST -port PORT -database DB -database DBTWO -verbose
232 A script which is used to drop a database in the most lock friendly way.
233 If you issue a C<drop database DB> command to MySQL it first aquires
234 a C<LOCK_open> which is a global mutex always applied
for when you open
235 and close a file. Once the drop command has the lock no other process can
236 query the MySQL DB until the lock is relinquished once the DB has been dropped.
237 If your DB is very large or has a large number of tables
this can take a
long
238 time and has you performing a denile of service attack on your own DB server.
244 =item B<--username | --user | -u>
246 REQUIRED. Username of the connecting account. Must be able to perform
247 drop and truncate calls.
249 =item B<--password | -pass | -p>
251 Password of the connecting user.
253 =item B<--host | --hostname | -h>
255 REQUIRED. Host name of the database to connect to
259 Optional integer of the database port. Defaults to 3306
261 =item B<--databases | --database | --db>
263 Allows database name specification and can be used more than once. Comma
264 separated values are supported.
268 Makes the program give more information
about what is going on. Otherwise
269 the program is silent.
273 If given the script will write all logs to output. Switches on C<--verbose>