mirror of
https://github.com/ZoneMinder/zoneminder.git
synced 2026-02-03 02:51:07 -05:00
331 lines
8.5 KiB
Perl
331 lines
8.5 KiB
Perl
# ==========================================================================
|
|
#
|
|
# ZoneMinder Database Module
|
|
# Copyright (C) 2001-2008 Philip Coombes
|
|
#
|
|
# This program is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU General Public License
|
|
# as published by the Free Software Foundation; either version 2
|
|
# of the License, or (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software
|
|
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
#
|
|
# ==========================================================================
|
|
#
|
|
# This module contains the common definitions and functions used by the rest
|
|
# of the ZoneMinder scripts
|
|
#
|
|
package ZoneMinder::Database;
|
|
|
|
use 5.006;
|
|
use strict;
|
|
use warnings;
|
|
use version;
|
|
|
|
require Exporter;
|
|
require ZoneMinder::Base;
|
|
|
|
our @ISA = qw(Exporter ZoneMinder::Base);
|
|
|
|
# Items to export into callers namespace by default. Note: do not export
|
|
# names by default without a very good reason. Use EXPORT_OK instead.
|
|
# Do not simply export all your public functions/methods/constants.
|
|
|
|
# This allows declaration use ZoneMinder ':all';
|
|
# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK
|
|
# will save memory.
|
|
our %EXPORT_TAGS = (
|
|
functions => [ qw(
|
|
zmDbConnect
|
|
zmDbDisconnect
|
|
zmDbGetMonitors
|
|
zmDbGetMonitor
|
|
zmDbGetMonitorAndControl
|
|
zmDbDo
|
|
zmDbExecute
|
|
zmSQLExecute
|
|
zmDbFetchOne
|
|
zmDbSupportsFeature
|
|
) ]
|
|
);
|
|
push( @{$EXPORT_TAGS{all}}, @{$EXPORT_TAGS{$_}} ) foreach keys %EXPORT_TAGS;
|
|
|
|
our @EXPORT_OK = ( @{ $EXPORT_TAGS{all} } );
|
|
|
|
our @EXPORT = qw();
|
|
|
|
our $VERSION = $ZoneMinder::Base::VERSION;
|
|
|
|
# ==========================================================================
|
|
#
|
|
# Database Access
|
|
#
|
|
# ==========================================================================
|
|
|
|
use ZoneMinder::Logger qw(:all);
|
|
|
|
require ZoneMinder::Config;
|
|
|
|
our $dbh = undef;
|
|
|
|
sub zmDbConnect {
|
|
my $force = shift;
|
|
if ( $force ) {
|
|
zmDbDisconnect();
|
|
}
|
|
my $options = shift;
|
|
|
|
if ( ( !defined($dbh) ) or ! $dbh->ping() ) {
|
|
my ( $host, $portOrSocket ) = ( $ZoneMinder::Config::Config{ZM_DB_HOST} =~ /^([^:]+)(?::(.+))?$/ );
|
|
my $socket;
|
|
|
|
if ( defined($portOrSocket) ) {
|
|
if ( $portOrSocket =~ /^\// ) {
|
|
$socket = ';mysql_socket='.$portOrSocket;
|
|
} else {
|
|
$socket = ';host='.$host.';port='.$portOrSocket;
|
|
}
|
|
} else {
|
|
$socket = ';host='.$ZoneMinder::Config::Config{ZM_DB_HOST};
|
|
}
|
|
|
|
my $sslOptions = '';
|
|
if ( $ZoneMinder::Config::Config{ZM_DB_SSL_CA_CERT} ) {
|
|
$sslOptions = join(';', '',
|
|
'mysql_ssl=1',
|
|
'mysql_ssl_ca_file='.$ZoneMinder::Config::Config{ZM_DB_SSL_CA_CERT},
|
|
'mysql_ssl_client_key='.$ZoneMinder::Config::Config{ZM_DB_SSL_CLIENT_KEY},
|
|
'mysql_ssl_client_cert='.$ZoneMinder::Config::Config{ZM_DB_SSL_CLIENT_CERT}
|
|
);
|
|
}
|
|
|
|
eval {
|
|
$dbh = DBI->connect(
|
|
'DBI:mysql:database='.$ZoneMinder::Config::Config{ZM_DB_NAME}
|
|
.$socket . $sslOptions . ($options?join(';', '', map { $_.'='.$$options{$_} } keys %{$options} ) : '')
|
|
, $ZoneMinder::Config::Config{ZM_DB_USER}
|
|
, $ZoneMinder::Config::Config{ZM_DB_PASS}
|
|
, { mysql_enable_utf8mb4 => 1, }
|
|
);
|
|
};
|
|
if ( !$dbh or $@ ) {
|
|
Error("Error reconnecting to db: errstr:$DBI::errstr error val:$@");
|
|
} else {
|
|
$dbh->{AutoCommit} = 1;
|
|
Error('Can\'t set AutoCommit on in database connection')
|
|
unless $dbh->{AutoCommit};
|
|
$dbh->trace( 0 );
|
|
} # end if success connecting
|
|
} # end if ! connected
|
|
return $dbh;
|
|
} # end sub zmDbConnect
|
|
|
|
sub zmDbDisconnect {
|
|
if ( defined($dbh) ) {
|
|
$dbh->disconnect() or Error('Error disconnecting db? ' . $dbh->errstr());
|
|
$dbh = undef;
|
|
}
|
|
}
|
|
|
|
use constant DB_MON_ALL => 0; # All monitors
|
|
use constant DB_MON_CAPT => 1; # All monitors that are capturing
|
|
use constant DB_MON_ACTIVE => 2; # All monitors that are active
|
|
use constant DB_MON_MOTION => 3; # All monitors that are doing motion detection
|
|
use constant DB_MON_RECORD => 4; # All monitors that are doing unconditional recording
|
|
use constant DB_MON_PASSIVE => 5; # All monitors that are in nodect state
|
|
|
|
sub zmDbGetMonitors {
|
|
zmDbConnect();
|
|
|
|
my $function = shift || DB_MON_ALL;
|
|
my $sql = 'SELECT * FROM Monitors';
|
|
|
|
if ( $function ) {
|
|
if ( $function == DB_MON_CAPT ) {
|
|
$sql .= " WHERE `Function` >= 'Monitor'";
|
|
} elsif ( $function == DB_MON_ACTIVE ) {
|
|
$sql .= " WHERE `Function` > 'Monitor'";
|
|
} elsif ( $function == DB_MON_MOTION ) {
|
|
$sql .= " WHERE `Function` = 'Modect' OR `Function` = 'Mocord'";
|
|
} elsif ( $function == DB_MON_RECORD ) {
|
|
$sql .= " WHERE `Function` = 'Record' OR `Function` = 'Mocord'";
|
|
} elsif ( $function == DB_MON_PASSIVE ) {
|
|
$sql .= " WHERE `Function` = 'Nodect'";
|
|
}
|
|
}
|
|
my $sth = $dbh->prepare_cached( $sql );
|
|
if ( ! $sth ) {
|
|
Error("Can't prepare '$sql': ".$dbh->errstr());
|
|
return undef;
|
|
}
|
|
my $res = $sth->execute();
|
|
if ( ! $res ) {
|
|
Error("Can't execute '$sql': ".$sth->errstr());
|
|
return undef;
|
|
}
|
|
|
|
my @monitors;
|
|
while( my $monitor = $sth->fetchrow_hashref() ) {
|
|
push( @monitors, $monitor );
|
|
}
|
|
$sth->finish();
|
|
return \@monitors;
|
|
}
|
|
|
|
sub zmSQLExecute {
|
|
Warning("zmSQLExecute is deprecated. Please update to use zmDbExecute");
|
|
return zmDbExecute(@_) ? 1 : undef;
|
|
}
|
|
|
|
sub zmDbExecute {
|
|
my $sql = shift;
|
|
|
|
my $sth = $dbh->prepare_cached($sql);
|
|
if (!$sth) {
|
|
Error("Can't prepare '$sql': ".$dbh->errstr());
|
|
return undef;
|
|
}
|
|
my $res = $sth->execute(@_);
|
|
if (!$res) {
|
|
my ( $caller, undef, $line ) = caller;
|
|
Error("Can't execute '$sql' from $caller:$line: ".$sth->errstr());
|
|
return undef;
|
|
}
|
|
return ($sth, $res) if wantarray();
|
|
return $res;
|
|
}
|
|
|
|
sub zmDbGetMonitor {
|
|
zmDbConnect();
|
|
|
|
my $id = shift;
|
|
|
|
if ( !defined($id) ) {
|
|
Error('Undefined id in zmDbgetMonitor');
|
|
return undef ;
|
|
}
|
|
|
|
return zmDbFetchOne('SELECT * FROM Monitors WHERE Id = ?', $id);
|
|
}
|
|
|
|
sub zmDbGetMonitorAndControl {
|
|
zmDbConnect();
|
|
|
|
my $id = shift;
|
|
return undef if !defined($id);
|
|
|
|
my $sql = 'SELECT C.*,M.*,C.Protocol
|
|
FROM Monitors as M
|
|
INNER JOIN Controls as C on (M.ControlId = C.Id)
|
|
WHERE M.Id = ?'
|
|
;
|
|
return zmDbFetchOne($sql);
|
|
}
|
|
|
|
sub start_transaction {
|
|
my $d = shift;
|
|
$d = $dbh if ! $d;
|
|
my $ac = $d->{AutoCommit};
|
|
$d->{AutoCommit} = 0;
|
|
return $ac;
|
|
} # end sub start_transaction
|
|
|
|
sub end_transaction {
|
|
my ( $d, $ac ) = @_;
|
|
if ( ! defined $ac ) {
|
|
Error("Undefined ac");
|
|
}
|
|
$d = $dbh if ! $d;
|
|
if ( $ac ) {
|
|
$d->commit();
|
|
} # end if
|
|
$d->{AutoCommit} = $ac;
|
|
} # end sub end_transaction
|
|
|
|
# Basic execution of $dbh->do but with some pretty logging of the sql on error.
|
|
sub zmDbDo {
|
|
my $sql = shift;
|
|
my $rows = $dbh->do($sql, undef, @_);
|
|
if ( ! defined $rows ) {
|
|
$sql =~ s/\?/'%s'/;
|
|
Error(sprintf("Failed $sql :", @_).$dbh->errstr());
|
|
} elsif ( ZoneMinder::Logger::logLevel() > INFO ) {
|
|
($rows) = $rows =~ /^(.*)$/; # de-taint
|
|
$sql =~ s/\?/'%s'/g;
|
|
Debug(sprintf("Succeeded $sql : $rows rows affected", @_));
|
|
}
|
|
return $rows;
|
|
}
|
|
|
|
sub zmDbFetchOne {
|
|
my $sql = shift;
|
|
|
|
Debug("$sql @_");
|
|
my $sth = $dbh->prepare_cached($sql);
|
|
if (!$sth) {
|
|
Error("Can't prepare '$sql': ".$dbh->errstr());
|
|
return undef;
|
|
}
|
|
my $res = $sth->execute(@_);
|
|
if (!$res) {
|
|
Error("Can't execute '$sql': ".$sth->errstr());
|
|
return undef;
|
|
}
|
|
my $row = $sth->fetchrow_hashref();
|
|
$sth->finish();
|
|
return $row;
|
|
}
|
|
|
|
sub zmDbSupportsFeature {
|
|
my $feature = shift;
|
|
my $row = zmDbFetchOne('SELECT VERSION()');
|
|
my ($version) = $$row{'VERSION()'} =~ /(^[0-9\.]+)/;
|
|
if ($feature eq 'skip_locked') {
|
|
if ($$row{'VERSION()'} =~ /MariaDB/) {
|
|
return version->parse($version) >= version->parse('10.6');
|
|
} else {
|
|
return version->parse($version) >= version->parse('8.0.1');
|
|
}
|
|
} else {
|
|
Warning("Unknown feature requested $feature");
|
|
}
|
|
}
|
|
|
|
1;
|
|
__END__
|
|
|
|
=head1 NAME
|
|
|
|
ZoneMinder::Database - Perl module containing database functions used in ZM
|
|
|
|
=head1 SYNOPSIS
|
|
|
|
use ZoneMinder::Database;
|
|
|
|
=head1 DESCRIPTION
|
|
|
|
|
|
=head2 EXPORT
|
|
|
|
zmDbConnect
|
|
zmDbDisconnect
|
|
zmDbGetMonitors
|
|
zmDbGetMonitor
|
|
zmDbGetMonitorAndControl
|
|
zmDbDo
|
|
zmSQLExecute
|
|
zmDbFetchOne
|
|
|
|
=head1 AUTHOR
|
|
|
|
Philip Coombes, E<lt>philip.coombes@zoneminder.comE<gt>
|
|
|
|
=cut
|