From d63594b5fa129969785d5493fe01cca75f0fb5e7 Mon Sep 17 00:00:00 2001 From: Isaac Connor Date: Mon, 22 Jan 2018 14:06:52 -0500 Subject: [PATCH] don't do updates in a transaction so we don't hold locks --- scripts/zmupdate.pl.in | 78 ++++++++++++++++++++++++++---------------- 1 file changed, 48 insertions(+), 30 deletions(-) diff --git a/scripts/zmupdate.pl.in b/scripts/zmupdate.pl.in index 9e8358e03..f428ea1f9 100644 --- a/scripts/zmupdate.pl.in +++ b/scripts/zmupdate.pl.in @@ -159,7 +159,7 @@ if ( $check && $Config{ZM_CHECK_FOR_UPDATES} ) { my $ua = LWP::UserAgent->new; $ua->agent( "ZoneMinder Update Agent/".ZM_VERSION ); if ( $Config{ZM_UPDATE_CHECK_PROXY} ) { - $ua->proxy( "http", $Config{ZM_UPDATE_CHECK_PROXY} ); + $ua->proxy( 'http', $Config{ZM_UPDATE_CHECK_PROXY} ); } my $req = HTTP::Request->new( GET=>'https://update.zoneminder.com/version.txt' ); my $res = $ua->request($req); @@ -224,7 +224,7 @@ if ( $zoneFix ) { } $sth->finish(); - $sql = "update Zones set MinAlarmPixels = ?, MaxAlarmPixels = ?, MinFilterPixels = ?, MaxFilterPixels = ?, MinBlobPixels = ?, MaxBlobPixels = ? where Id = ?"; + $sql = 'update Zones set MinAlarmPixels = ?, MaxAlarmPixels = ?, MinFilterPixels = ?, MaxFilterPixels = ?, MinBlobPixels = ?, MaxBlobPixels = ? where Id = ?'; $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); foreach my $zone ( @zones ) { my $zone_width = (($zone->{HiX}*$zone->{MonitorWidth})-($zone->{LoX}*$zone->{MonitorWidth}))/100; @@ -378,7 +378,7 @@ if ( $version ) { if ( $response =~ /^[yY]$/ ) { my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ); - my $command = "mysqldump"; + my $command = 'mysqldump'; if ( defined($portOrSocket) ) { if ( $portOrSocket =~ /^\// ) { $command .= " -S".$portOrSocket; @@ -503,7 +503,7 @@ if ( $version ) { my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() ); while( my $monitor = $sth->fetchrow_hashref() ) { - my $sql = "update Events set Width = ?, Height = ? where MonitorId = ?"; + my $sql = 'update Events set Width = ?, Height = ? where MonitorId = ?'; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute( $monitor->{Width}, $monitor->{Height}, $monitor->{Id} ) or die( "Can't execute: ".$sth->errstr() ); } @@ -518,7 +518,7 @@ if ( $version ) { my $res = $sth->execute() or die( "Can't execute: ".$sth->errstr() ); my $sequence = 1; while( my $monitor = $sth->fetchrow_hashref() ) { - my $sql = "update Monitors set Sequence = ? where Id = ?"; + my $sql = 'update Monitors set Sequence = ? where Id = ?'; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute( $sequence++, $monitor->{Id} ) or die( "Can't execute: ".$sth->errstr() ); } @@ -536,7 +536,7 @@ if ( $version ) { push( @filters, $filter ); } $sth->finish(); - $sql = "update Filters set Query = ? where Name = ?"; + $sql = 'update Filters set Query = ? where Name = ?'; $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); foreach my $filter ( @filters ) { if ( $filter->{Query} =~ /op\d=&/ ) { @@ -569,7 +569,7 @@ if ( $version ) { no strict 'refs'; foreach my $zone ( @zones ) { # Create the coordinate strings - if ( $zone->{Units} eq "Pixels" ) { + if ( $zone->{Units} eq 'Pixels' ) { my $sql = "update Zones set NumCoords = 4, Coords = concat( LoX,',',LoY,' ',HiX,',',LoY,' ',HiX,',',HiY,' ',LoX,',',HiY ), Area = round( ((HiX-LoX)+1)*((HiY-LoY)+1) ) where Id = ?"; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute( $zone->{Id} ) or die( "Can't execute: ".$sth->errstr() ); @@ -604,7 +604,7 @@ if ( $version ) { foreach my $defn ( split( /,/, $state->{Definition} ) ) { push( @new_defns, $defn.":1" ); } - my $sql = "update States set Definition = ? where Name = ?"; + my $sql = 'update States set Definition = ? where Name = ?'; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute( join( ',', @new_defns ), $state->{Name} ) or die( "Can't execute: ".$sth->errstr() ); } @@ -684,7 +684,7 @@ if ( $version ) { $db_monitor->{LabelFormat} =~ s/\%\%s/%N/; $db_monitor->{LabelFormat} =~ s/\%\%s/%Q/; - my $sql = "update Monitors set LabelFormat = ? where Id = ?"; + my $sql = 'update Monitors set LabelFormat = ? where Id = ?'; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute( $db_monitor->{LabelFormat}, $db_monitor->{Id} ) or die( "Can't execute: ".$sth->errstr() ); } @@ -743,7 +743,7 @@ if ( $version ) { $i++; } $newQuery .= '}'; - foreach my $field ( "sort_field", "sort_asc", "limit" ) { + foreach my $field ( 'sort_field', 'sort_asc', 'limit' ) { if ( defined($filter->{$field}) ) { $newQuery .= 's:'.length($field).':"'.$field.'";'; $newQuery .= 's:'.length($filter->{$field}).':"'.$filter->{$field}.'";'; @@ -751,7 +751,7 @@ if ( $version ) { } $newQuery .= '}'; - my $sql = "update Filters set Query = ? where Name = ?"; + my $sql = 'update Filters set Query = ? where Name = ?'; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute( $newQuery, $dbFilter->{Name} ) or die( "Can't execute: ".$sth->errstr() ); } @@ -829,7 +829,7 @@ if ( $version ) { my $phpQuery = $dbFilter->{Query}; my $query = PHP::Serialization::unserialize( $phpQuery ); my $jsonQuery = jsonEncode( $query ); - my $sql = "update Filters set Query = ? where Name = ?"; + my $sql = 'update Filters set Query = ? where Name = ?'; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); my $res = $sth->execute( $jsonQuery, $dbFilter->{Name} ) or die( "Can't execute: ".$sth->errstr() ); }; @@ -851,7 +851,7 @@ if ( $version ) { # Copy the FTP specific values to the new general config my $fetchSql = "select * from Config where Name like 'ZM_UPLOAD_FTP_%'"; my $fetchSth = $dbh->prepare_cached( $fetchSql ) or die( "Can't prepare '$fetchSql': ".$dbh->errstr() ); - my $updateSql = "update Config set Value = ? where Name = ?"; + my $updateSql = 'update Config set Value = ? where Name = ?'; my $updateSth = $dbh->prepare_cached( $updateSql ) or die( "Can't prepare '$updateSql': ".$dbh->errstr() ); my $fetchRes = $fetchSth->execute() or die( "Can't execute: ".$fetchSth->errstr() ); while( my $config = $fetchSth->fetchrow_hashref() ) { @@ -881,7 +881,7 @@ if ( $version ) { if ( $version ge '1.26.0' ) { my @files; - $updateDir = $Config{ZM_PATH_DATA}."/db" if ! $updateDir; + $updateDir = $Config{ZM_PATH_DATA}.'/db' if ! $updateDir; opendir( my $dh, $updateDir ) || die "Can't open updateDir $!"; #@files = sort grep { (!/^\./) && /^zm_update\-[\d\.]+\.sql$/ && -f "$updateDir/$_" } readdir($dh); #PP - use perl version sort @@ -895,29 +895,28 @@ if ( $version ) { die "Should have found upgrade scripts at $updateDir\n"; } # end if - $dbh->{'AutoCommit'} = 0; foreach my $patch ( @files ) { my ( $v ) = $patch =~ /^zm_update\-([\d\.]+)\.sql$/; #PP make sure we use version compare if ( version->parse('v' . $v) > version->parse('v' . $version) ) { print( "Upgrading DB to $v from $version\n" ); patchDB( $dbh, $v ); - if ( $dbh->errstr() ) { - $dbh->rollback(); - die "Error: " . $dbh->errstr(). ". Rolled back.\n"; - } # end if error - } # end if + my $sql = "update Config set Value = ? where Name = 'ZM_DYN_DB_VERSION'"; + my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $version ) or die( "Can't execute: ".$sth->errstr() ); + $sth->finish(); + #patchDB_using_do( $dbh, $version, $updateDir.'/'.$patch ); + } # end if newer version } # end foreach patchfile - $dbh->{'AutoCommit'} = 1; $cascade = !undef; } # end if if ( $cascade ) { my $installed_version = ZM_VERSION; - my $sql = "update Config set Value = ? where Name = ?"; + my $sql = 'update Config set Value = ? where Name = ?'; my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( "$installed_version", "ZM_DYN_DB_VERSION" ) or die( "Can't execute: ".$sth->errstr() ); - $res = $sth->execute( "$installed_version", "ZM_DYN_CURR_VERSION" ) or die( "Can't execute: ".$sth->errstr() ); + my $res = $sth->execute( "$installed_version", 'ZM_DYN_DB_VERSION' ) or die( "Can't execute: ".$sth->errstr() ); + $res = $sth->execute( "$installed_version", 'ZM_DYN_CURR_VERSION' ) or die( "Can't execute: ".$sth->errstr() ); $sth->finish(); } else { zmDbDisconnect(); @@ -928,11 +927,35 @@ if ( $version ) { zmDbDisconnect(); exit( 0 ); +sub patchDB_using_do { + my ( $dbh, $version, $file ) = @_; + + open( my $fh, '<', $file ) or die "Unable to open $file $!"; + $/ = undef; + my $sql = <$fh>; + close $fh; + if ( $sql ) { + $dbh->{'AutoCommit'} = 0; + $dbh->do($sql); + if ( $dbh->errstr() ) { + $dbh->rollback(); + die "Error: " . $dbh->errstr(). ". Rolled back.\n"; + } # end if error + + my $sql = "update Config set Value = ? where Name = 'ZM_DYN_DB_VERSION'"; + my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); + my $res = $sth->execute( $version ) or die( "Can't execute: ".$sth->errstr() ); + $sth->finish(); + + $dbh->{'AutoCommit'} = 1; + } else { + Warning("Empty db update file at $file"); + } +} sub patchDB { my $dbh = shift; my $version = shift; - zmDbDisconnect(); my ( $host, $portOrSocket ) = ( $Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ ); my $command = 'mysql'; @@ -969,11 +992,6 @@ sub patchDB { } print( "\nDatabase successfully upgraded to version $version.\n" ); - $dbh = zmDbConnect(); - my $sql = "update Config set Value = ? where Name = 'ZM_DYN_DB_VERSION'"; - my $sth = $dbh->prepare_cached( $sql ) or die( "Can't prepare '$sql': ".$dbh->errstr() ); - my $res = $sth->execute( $version ) or die( "Can't execute: ".$sth->errstr() ); - $sth->finish(); } sub migratePaths {