first commit
This commit is contained in:
222
sqlbackup.pl
Normal file
222
sqlbackup.pl
Normal file
@@ -0,0 +1,222 @@
|
||||
#!/usr/bin/perl -w
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use DBI;
|
||||
use Data::Dumper;
|
||||
use JSON;
|
||||
use Getopt::Long;
|
||||
use File::Slurp qw(:std);
|
||||
use Archive::Zip qw( :ERROR_CODES :CONSTANTS );
|
||||
use POSIX qw(strftime);
|
||||
use IO::Handle;
|
||||
use File::Path qw(make_path);
|
||||
STDOUT->autoflush(1);
|
||||
|
||||
#https://www.easysoft.com/developer/languages/perl/dbd_odbc_tutorial_part_2.html
|
||||
|
||||
# use Term::ANSIColor;
|
||||
|
||||
my $db = ""; # Datenbank
|
||||
my $user = ""; # Datenbankuser
|
||||
my $pass = ""; # Datenbankpasswort
|
||||
my $server = ""; # Datenbankserver
|
||||
my $zip = "0"; #komprimieren und oder löschen
|
||||
my $maxlength = 0;
|
||||
my $list = "";
|
||||
my $dateien = "1";
|
||||
my $rem = "0";
|
||||
|
||||
my %h = ('db' => \$db, 'user' => \$user, 'pass' => \$pass, 'server' => \$server, 'zip' => \$zip, 'rem' => \$rem, 'max' => \$maxlength, 'list' => \$list, 'files' => \$dateien);
|
||||
GetOptions (\%h, 'db=s', 'user=s', 'pass=s', 'server=s', 'zip=s', 'rem=s', 'max=s', 'list=s', 'files=s');
|
||||
|
||||
if ( $db eq "" || $user eq "" || $user eq "" || $server eq "" ) {
|
||||
print "\nWillkommen zum Backup einer Mysqldatenbank\n";
|
||||
print "es fehlen noch folgende Parameter damit es losgehen kann.\n";
|
||||
print "\n";
|
||||
print "--server -s = Datenbankserver\n" if ($server eq "");
|
||||
print "--db -d = Datenbankname\n" if ($db eq "");
|
||||
print "--user -u = Datenbankuser\n" if ($user eq "");
|
||||
print "--pass -p = Datenbankpasswort\n" if ($pass eq "");
|
||||
print "--max -m = maximale Insertlänge in Bytes (optional)\n";
|
||||
print "--list -l = Liste der Tabellen mit ' ' getrennt (optional)\n";
|
||||
print "--files -f = 1 für jede Tabelle in eine Datei (optional)\n";
|
||||
print "--zip -z = 1 zum packen, 2 packen und Sql Dateien löschen (optional) \n";
|
||||
print "--rem -r = 0 vorhande Tabelle vorher löschen (optional) \n";
|
||||
|
||||
exit;
|
||||
}
|
||||
|
||||
my $tref; # dient zur analyse welcher Datentyp die Spalte hat
|
||||
my $text; # wird mit den Daten zum schreiben in die datei gefüllt
|
||||
my @files;
|
||||
my %tabellen;
|
||||
|
||||
my $dbh = DBI->connect("DBI:mysql:$db:$server", $user, $pass) or die "Couldn't connect to database: " . DBI->errstr;
|
||||
|
||||
print "Get tables from Database $db\n";
|
||||
my $s1 = $dbh->selectall_arrayref("SHOW FULL TABLES FROM $db;", { Slice => {} });
|
||||
|
||||
# Ordner erstellen wenn nicht bekannt
|
||||
if (!-d "$db") {
|
||||
make_path "$db";
|
||||
}
|
||||
|
||||
if ( $list ne "" ) {
|
||||
if ( $list !~ / / ) {
|
||||
$tabellen{$list} = 1;
|
||||
}
|
||||
}
|
||||
for my $l ( split( ' ', $list ) ) {
|
||||
$tabellen{$l} = 1;
|
||||
}
|
||||
|
||||
if ( $dateien eq '0' ) {
|
||||
push @files, "$server/$db/$db.sql";
|
||||
}
|
||||
|
||||
my $firsttableend = 0;
|
||||
|
||||
for my $tab ( @{$s1} ) {
|
||||
my $n = $tab->{"Tables_in_$db"};
|
||||
my $datei = "$db/$n.sql";
|
||||
if ( $dateien eq '0' ) {
|
||||
$datei = "$db/$db.sql";
|
||||
} else {
|
||||
write_file($datei, '' );
|
||||
}
|
||||
|
||||
if ( $list ne "" ) {
|
||||
next if ( !$tabellen{$n} );
|
||||
}
|
||||
|
||||
$text = "\n/*!40101 SET \@OLD_CHARACTER_SET_CLIENT=@\@CHARACTER_SET_CLIENT */;\n/*!40101 SET NAMES utf8 */;\n/*!50503 SET NAMES utf8mb4 */;\n/*!40014 SET \@OLD_FOREIGN_KEY_CHECKS=@\@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;\n/*!40101 SET \@OLD_SQL_MODE=@\@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;\n\n";
|
||||
|
||||
my $create = $dbh->selectrow_hashref("SHOW CREATE TABLE $db.$n" , { Slice => {} });
|
||||
|
||||
if ( $rem eq "1" ) {
|
||||
$text .= "DROP TABLE IF EXISTS `$n`;\n";
|
||||
}
|
||||
|
||||
# Createstatement beschaffen
|
||||
$text .= $create->{'Create Table'};
|
||||
$text =~ s/CREATE TABLE/CREATE TABLE IF NOT EXISTS/g;
|
||||
my $s2 = $dbh->selectall_arrayref("DESCRIBE $db.$n" , { Slice => {} });
|
||||
my @tabelle;
|
||||
|
||||
# hier wird sich der Datentyp einer Spalte gemerkt
|
||||
# und ein Array mit den Spaltenamen
|
||||
for my $s ( @{$s2} ) {
|
||||
my $f = $s->{Field};
|
||||
$tref->{ $n }->{$f} = $s->{Type};
|
||||
push @tabelle, $s->{Field};
|
||||
}
|
||||
$text .= ";\n\n/*!40000 ALTER TABLE `$n` DISABLE KEYS */;\n";
|
||||
|
||||
if ( $firsttableend == 1 ) {
|
||||
append_file($datei, $text );
|
||||
} else {
|
||||
write_file($datei, $text );
|
||||
}
|
||||
|
||||
# Insert Kopf erstellen
|
||||
my $inserttext .= "INSERT INTO $n (";
|
||||
for my $col( @tabelle ) {
|
||||
$inserttext .= "`".$col."`,"
|
||||
}
|
||||
$inserttext =~ s/,$/) VALUES/;
|
||||
|
||||
print "create Inserts for $n\n";
|
||||
|
||||
my $cnt = 0;
|
||||
my $len = 0; # Zähler für die maximale Länge in Bytes eines Insert
|
||||
|
||||
my $sth = $dbh->prepare("SELECT * from $db.$n"); # prepare the query
|
||||
# in der Schleife werden die einzelnen inserts direkt in die Datei geschrieben, geht schneller als wenn man die inserts sammelt und dann erst schreibt
|
||||
$sth->execute(); # execute the query with parameter
|
||||
my $max = $sth->rows;
|
||||
# Holen der Daten
|
||||
while (my $d = $sth->fetchrow_hashref) { # retrieve one row
|
||||
$cnt += 1;
|
||||
|
||||
if ( $len == 0 ) { # bei 0 wird ein neues Create statement erzeugt
|
||||
append_file($datei, $inserttext );
|
||||
}
|
||||
|
||||
$text = "\n("; # Klammer für insert erstellen
|
||||
|
||||
# hier wird entschieden wie die einzelnen Daten in abhängigkeit des Datentyps geschrieben werden
|
||||
# es kommen die gemerkten Spalten (@tabelle) und Datentypen ($tref) zum Einsatz
|
||||
# zb: mit Strings mit '' integer ohne '', umgang mit zeilenumbrüchen, blobs
|
||||
# bei einem unbekannten typ kommt der Dumper
|
||||
for my $col( @tabelle ) {
|
||||
if ( defined $d->{$col} ) {
|
||||
if ( $tref->{ $n }->{$col} =~ /int|year|double|decimal|float/ ) {
|
||||
$text .= $d->{$col}.","
|
||||
} elsif ($tref->{ $n }->{$col} =~ /char|date|time|enum|text/ ) {
|
||||
$d->{$col} =~ s/\\/\\\\/g;
|
||||
$d->{$col} =~ s/\n/\\n/g;
|
||||
$d->{$col} =~ s/\r/\\n/g;
|
||||
$d->{$col} =~ s/\r\n\\/\\n/g;
|
||||
$d->{$col} =~ s/\'/\\'/g;
|
||||
|
||||
$text .= "'".$d->{$col}."',"
|
||||
} elsif ($tref->{ $n }->{$col} =~ /blob/ ) {
|
||||
$text .= "_binary 0x". uc unpack("H*",$d->{$col}).",";
|
||||
} else {
|
||||
print Dumper($tref->{ $n }->{$col});
|
||||
}
|
||||
} else {
|
||||
$text .= "NULL,";
|
||||
}
|
||||
}
|
||||
|
||||
$len += length($text); # zählen der Länge der inserts es werden auch die , _binary
|
||||
$text =~ s/,$//; # letzes , insert entfernen
|
||||
$text .= "),"; # und Klammer wieder schließen
|
||||
|
||||
if ( $cnt == $max or ($len > $maxlength and $maxlength != 0 ) ) { # wenn maximale Länge eines insert oder Ende der Tabelle erreicht , gegen ; tauschen und Zähler auf 0
|
||||
$len = 0;
|
||||
$text =~ s/,$/;\n/;
|
||||
}
|
||||
append_file($datei, $text );
|
||||
|
||||
print "$cnt - $max\r";
|
||||
}
|
||||
print " ---> ready\n";
|
||||
|
||||
$text = "/*!40000 ALTER TABLE `$n` ENABLE KEYS */;\n\n/*!40101 SET SQL_MODE=IFNULL(\@OLD_SQL_MODE, '') */;\n/*!40014 SET FOREIGN_KEY_CHECKS=IF(\@OLD_FOREIGN_KEY_CHECKS IS NULL, 1, \@OLD_FOREIGN_KEY_CHECKS) */;\n/*!40101 SET CHARACTER_SET_CLIENT=\@OLD_CHARACTER_SET_CLIENT */;\n";
|
||||
append_file($datei, $text );
|
||||
|
||||
if ( $dateien == 1 ) {
|
||||
push @files, "$db/$n.sql";
|
||||
}
|
||||
$firsttableend = 1;
|
||||
}
|
||||
$dbh->disconnect;
|
||||
|
||||
if ( $zip > 0 ) {
|
||||
print "Compress $db into zip file ";
|
||||
my $now_string = strftime "%Y-%m-%d %H.%M", localtime;
|
||||
# Creating a new zip file
|
||||
my $zip = Archive::Zip->new();
|
||||
my $zipfile = "$db-$now_string.zip";
|
||||
# Trying to read the existing zip structure, when zip archive already exists
|
||||
$zip->read( $zipfile ) if -s $zipfile;
|
||||
|
||||
foreach my $file ( @files ) {
|
||||
# remove if the current file was already in the zip:
|
||||
$zip->removeMember( $file );
|
||||
# add a new file to zip object in memory, using best compressionLevel = 9
|
||||
$zip->addFile( $file, $file, 5 );
|
||||
}
|
||||
if ( $zip->numberOfMembers ) {
|
||||
# Save to a zip file $zipfile
|
||||
$zip->overwriteAs( $zipfile );
|
||||
}
|
||||
if ( $zip > 1 ) {
|
||||
unlink @files;
|
||||
}
|
||||
print "---> ready\n";
|
||||
}
|
||||
1;
|
||||
Reference in New Issue
Block a user