mirror of
https://github.com/fhem/fhem-mirror.git
synced 2025-04-19 12:46:03 +00:00
93_DbRep: contrib 8.51.0
git-svn-id: https://svn.fhem.de/fhem/trunk@26958 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
parent
61ee9415f1
commit
ad9cc9ff22
@ -406,7 +406,8 @@ my $dbrep_defdecplaces = 4;
|
||||
my $dbrep_dump_path_def = $attr{global}{modpath}."/log/"; # default Pfad für local Dumps
|
||||
my $dbrep_dump_remotepath_def = "./"; # default Pfad für remote Dumps
|
||||
my $dbrep_fName = $attr{global}{modpath}."/FHEM/FhemUtils/cacheDbRep"; # default Pfad/Name SQL Cache File
|
||||
|
||||
my $dbrep_deftonbl = 86400; # default Timeout non-blocking Operationen
|
||||
my $dbrep_deftobl = 10; # default Timeout blocking Operationen
|
||||
|
||||
|
||||
###################################################################################
|
||||
@ -1262,7 +1263,7 @@ sub DbRep_Get {
|
||||
my $dbloghash = $defs{$hash->{HELPER}{DBLOGDEVICE}};
|
||||
my $dbmodel = $dbloghash->{MODEL};
|
||||
my $dbname = $hash->{DATABASE};
|
||||
my $to = AttrVal($name, "timeout", "86400");
|
||||
my $to = AttrVal ($name, 'timeout', $dbrep_deftonbl);
|
||||
|
||||
my $getlist = "Unknown argument $opt, choose one of ".
|
||||
"svrinfo:noArg ".
|
||||
@ -1953,7 +1954,7 @@ sub DbRep_firstconnect {
|
||||
my $string = shift;
|
||||
my ($name,$opt,$prop,$fret) = split("\\|", $string);
|
||||
my $hash = $defs{$name};
|
||||
my $to = AttrVal($name, "timeout", "86400");
|
||||
my $to = AttrVal ($name, 'timeout', $dbrep_deftonbl);
|
||||
|
||||
RemoveInternalTimer ($hash, "DbRep_firstconnect");
|
||||
return if(IsDisabled($name));
|
||||
@ -2292,9 +2293,9 @@ sub DbRep_Main {
|
||||
my $opt = shift;
|
||||
my $prop = shift // q{};
|
||||
my $name = $hash->{NAME};
|
||||
my $to = AttrVal($name, "timeout", "86400");
|
||||
my $reading = AttrVal($name, "reading", "%");
|
||||
my $device = AttrVal($name, "device", "%");
|
||||
my $to = AttrVal ($name, 'timeout', $dbrep_deftonbl);
|
||||
my $reading = AttrVal ($name, 'reading', '%');
|
||||
my $device = AttrVal ($name, 'device', '%');
|
||||
my $dbloghash = $defs{$hash->{HELPER}{DBLOGDEVICE}};
|
||||
my $dbmodel = $dbloghash->{MODEL};
|
||||
|
||||
@ -6766,6 +6767,261 @@ sub DbRep_sqlCmd {
|
||||
return "$name|$err|$rowstring|$opt|$cmd|$nrows|$rt";
|
||||
}
|
||||
|
||||
####################################################################################################
|
||||
# blockierende DB-Abfrage
|
||||
# liefert Ergebnis sofort zurück, setzt keine Readings
|
||||
####################################################################################################
|
||||
sub DbRep_sqlCmdBlocking {
|
||||
my $name = shift;
|
||||
my $cmd = shift;
|
||||
|
||||
my $hash = $defs{$name};
|
||||
my $srs = AttrVal ($name, 'sqlResultFieldSep', '|');
|
||||
my $to = AttrVal ($name, 'timeout', $dbrep_deftobl);
|
||||
|
||||
my ($ret);
|
||||
|
||||
readingsDelete ($hash, "errortext");
|
||||
ReadingsSingleUpdateValue ($hash, "state", "running", 1);
|
||||
|
||||
my ($err,$dbh,$dbmodel) = DbRep_dbConnect($name);
|
||||
if ($err) {
|
||||
$err = decode_base64 ($err);
|
||||
|
||||
Log3 ($name, 2, "DbRep $name - ERROR - $err");
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
ReadingsBulkUpdateValue ($hash, 'errortext', $err);
|
||||
ReadingsBulkUpdateValue ($hash, 'state', 'error');
|
||||
readingsEndUpdate ($hash, 1);
|
||||
|
||||
return $err;
|
||||
}
|
||||
|
||||
$cmd =~ s/\;\;/ESC_ESC_ESC/gx; # ersetzen von escapeten ";" (;;)
|
||||
|
||||
$cmd .= ";" if ($cmd !~ m/\;$/x);
|
||||
my $sql = $cmd;
|
||||
|
||||
Log3 ($name, 4, "DbRep $name - -------- New selection --------- ");
|
||||
Log3 ($name, 4, "DbRep $name - sqlCmdBlocking Command:\n$sql");
|
||||
|
||||
my @pms;
|
||||
my $vars = AttrVal($name, "sqlCmdVars", ""); # Set Session Variablen "SET" oder PRAGMA aus Attribut "sqlCmdVars"
|
||||
|
||||
if ($vars) {
|
||||
@pms = split ';', $vars;
|
||||
|
||||
for my $pm (@pms) {
|
||||
if($pm !~ /PRAGMA|SET/i) {
|
||||
next;
|
||||
}
|
||||
|
||||
$pm = ltrim($pm).';';
|
||||
$pm =~ s/ESC_ESC_ESC/;/gx; # wiederherstellen von escapeten ";" -> umwandeln von ";;" in ";"
|
||||
|
||||
$err = DbRep_dbhDo ($name, $dbh, $pm, "Set VARIABLE or PRAGMA: $pm");
|
||||
if ($err) {
|
||||
$err = decode_base64 ($err);
|
||||
|
||||
Log3 ($name, 2, "DbRep $name - ERROR - $err");
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
ReadingsBulkUpdateValue ($hash, 'errortext', $err);
|
||||
ReadingsBulkUpdateValue ($hash, 'state', 'error');
|
||||
readingsEndUpdate ($hash, 1);
|
||||
|
||||
return $err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Abarbeitung von Session Variablen vor einem SQL-Statement
|
||||
# z.B. SET @open:=NULL, @closed:=NULL; Select ...
|
||||
if($cmd =~ /^\s*SET.*;/i) {
|
||||
@pms = split ';', $cmd;
|
||||
$sql = q{};
|
||||
|
||||
for my $pm (@pms) {
|
||||
if($pm !~ /SET/i) {
|
||||
$sql .= $pm.';';
|
||||
next;
|
||||
}
|
||||
|
||||
$pm = ltrim($pm).';';
|
||||
$pm =~ s/ESC_ESC_ESC/;/gx; # wiederherstellen von escapeten ";" -> umwandeln von ";;" in ";"
|
||||
|
||||
$err = DbRep_dbhDo ($name, $dbh, $pm, "Set SQL session variable: $pm");
|
||||
if ($err) {
|
||||
$err = decode_base64 ($err);
|
||||
|
||||
Log3 ($name, 2, "DbRep $name - ERROR - $err");
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
ReadingsBulkUpdateValue ($hash, 'errortext', $err);
|
||||
ReadingsBulkUpdateValue ($hash, 'state', 'error');
|
||||
readingsEndUpdate ($hash, 1);
|
||||
|
||||
return $err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Abarbeitung aller Pragmas vor einem SQLite Statement, SQL wird extrahiert
|
||||
# wenn Pragmas im SQL vorangestellt sind
|
||||
if($cmd =~ /^\s*PRAGMA.*;/i) {
|
||||
@pms = split ';', $cmd;
|
||||
$sql = q{};
|
||||
|
||||
for my $pm (@pms) {
|
||||
if($pm !~ /PRAGMA.*=/i) { # PRAGMA ohne "=" werden als SQL-Statement mit Abfrageergebnis behandelt
|
||||
$sql .= $pm.';';
|
||||
next;
|
||||
}
|
||||
|
||||
$pm = ltrim($pm).';';
|
||||
$pm =~ s/ESC_ESC_ESC/;/gx; # wiederherstellen von escapeten ";" -> umwandeln von ";;" in ";"
|
||||
|
||||
$err = DbRep_dbhDo ($name, $dbh, $pm, "Exec PRAGMA Statement: $pm");
|
||||
if ($err) {
|
||||
$err = decode_base64 ($err);
|
||||
|
||||
Log3 ($name, 2, "DbRep $name - ERROR - $err");
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
ReadingsBulkUpdateValue ($hash, 'errortext', $err);
|
||||
ReadingsBulkUpdateValue ($hash, 'state', 'error');
|
||||
readingsEndUpdate ($hash, 1);
|
||||
|
||||
return $err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Abarbeitung von PREPARE statement als Befehl als Bestandteil des SQL Forum: #114293 / https://forum.fhem.de/index.php?topic=114293.0
|
||||
# z.B. PREPARE statement FROM @CMD
|
||||
if($sql =~ /^\s*PREPARE.*;/i) {
|
||||
@pms = split ';', $sql;
|
||||
$sql = q{};
|
||||
|
||||
for my $pm (@pms) {
|
||||
if($pm !~ /PREPARE/i) {
|
||||
$sql .= $pm.';';
|
||||
next;
|
||||
}
|
||||
|
||||
$pm = ltrim($pm).';';
|
||||
$pm =~ s/ESC_ESC_ESC/;/gx; # wiederherstellen von escapeten ";" -> umwandeln von ";;" in ";"
|
||||
|
||||
$err = DbRep_dbhDo ($name, $dbh, $pm, "Exec PREPARE statement: $pm");
|
||||
if ($err) {
|
||||
$err = decode_base64 ($err);
|
||||
|
||||
Log3 ($name, 2, "DbRep $name - ERROR - $err");
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
ReadingsBulkUpdateValue ($hash, 'errortext', $err);
|
||||
ReadingsBulkUpdateValue ($hash, 'state', 'error');
|
||||
readingsEndUpdate ($hash, 1);
|
||||
|
||||
return $err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $st = [gettimeofday]; # SQL-Startzeit
|
||||
|
||||
my $totxt = qq{Timeout occured (limit: $to seconds). You may be able to adjust the "Timeout" attribute.};
|
||||
|
||||
my ($sth,$r,$failed);
|
||||
|
||||
eval { # outer eval fängt Alarm auf, der gerade vor diesem Alarm feuern könnte(0)
|
||||
POSIX::sigaction(SIGALRM, POSIX::SigAction->new(sub {die "Timeout\n"})); # \n ist nötig !
|
||||
|
||||
alarm($to);
|
||||
eval {
|
||||
$sth = $dbh->prepare($sql);
|
||||
$r = $sth->execute();
|
||||
1;
|
||||
};
|
||||
alarm(0); # Alarm aufheben (wenn der Code schnell lief)
|
||||
|
||||
if ($@) {
|
||||
if($@ eq "Timeout\n") { # timeout
|
||||
$failed = $totxt;
|
||||
|
||||
} else { # ein anderer Fehler
|
||||
$failed = $@;
|
||||
}
|
||||
}
|
||||
1;
|
||||
|
||||
} or $failed = $@;
|
||||
|
||||
alarm(0); # Schutz vor Race Condition
|
||||
|
||||
if ($failed) {
|
||||
$err = $failed eq "Timeout\n" ? $totxt : $failed;
|
||||
|
||||
Log3 ($name, 2, "DbRep $name - $err");
|
||||
|
||||
$sth->finish if($sth);
|
||||
$dbh->disconnect;
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
ReadingsBulkUpdateValue ($hash, 'errortext', $err);
|
||||
ReadingsBulkUpdateValue ($hash, 'state', 'error');
|
||||
readingsEndUpdate ($hash, 1);
|
||||
|
||||
return $err;
|
||||
}
|
||||
|
||||
my $nrows = 0;
|
||||
if($sql =~ m/^\s*(call|explain|select|pragma|show)/is) {
|
||||
while (my @line = $sth->fetchrow_array()) {
|
||||
Log3 ($name, 4, "DbRep $name - SQL result: @line");
|
||||
$ret .= "\n" if($nrows); # Forum: #103295
|
||||
$ret .= join("$srs", @line);
|
||||
$nrows++; # Anzahl der Datensätze
|
||||
}
|
||||
}
|
||||
else {
|
||||
$nrows = $sth->rows;
|
||||
|
||||
eval {$dbh->commit() if(!$dbh->{AutoCommit});};
|
||||
if ($@) {
|
||||
$err = $@;
|
||||
|
||||
Log3 ($name, 2, "DbRep $name - $err");
|
||||
|
||||
$dbh->disconnect;
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
ReadingsBulkUpdateValue ($hash, 'errortext', $err);
|
||||
ReadingsBulkUpdateValue ($hash, 'state', 'error');
|
||||
readingsEndUpdate ($hash, 1);
|
||||
|
||||
return $err;
|
||||
}
|
||||
|
||||
$ret = $nrows;
|
||||
}
|
||||
|
||||
$sth->finish;
|
||||
$dbh->disconnect;
|
||||
|
||||
my $rt = tv_interval($st); # SQL-Laufzeit ermitteln
|
||||
my $com = (split " ", $sql, 2)[0];
|
||||
|
||||
Log3 ($name, 4, "DbRep $name - Number of entries processed in db $hash->{DATABASE}: $nrows by $com");
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
ReadingsBulkUpdateTimeState ($hash, undef, $rt, 'done');
|
||||
readingsEndUpdate ($hash, 1);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
####################################################################################################
|
||||
# Ersetzung von Schlüsselwörtern für Time*, Devices und Readings
|
||||
# in SQL-Statements (unter Verwendung der Attributsyntax)
|
||||
@ -13177,261 +13433,6 @@ sub DbRep_setVersionInfo {
|
||||
return;
|
||||
}
|
||||
|
||||
####################################################################################################
|
||||
# blockierende DB-Abfrage
|
||||
# liefert Ergebnis sofort zurück, setzt keine Readings
|
||||
####################################################################################################
|
||||
sub DbRep_sqlCmdBlocking {
|
||||
my $name = shift;
|
||||
my $cmd = shift;
|
||||
my $hash = $defs{$name};
|
||||
|
||||
my $srs = AttrVal ($name, "sqlResultFieldSep", "|");
|
||||
my $to = AttrVal ($name, "timeout", 10 );
|
||||
|
||||
my ($ret);
|
||||
|
||||
readingsDelete ($hash, "errortext");
|
||||
ReadingsSingleUpdateValue ($hash, "state", "running", 1);
|
||||
|
||||
my ($err,$dbh,$dbmodel) = DbRep_dbConnect($name);
|
||||
if ($err) {
|
||||
$err = decode_base64 ($err);
|
||||
|
||||
Log3 ($name, 2, "DbRep $name - ERROR - $err");
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
ReadingsBulkUpdateValue ($hash, 'errortext', $err);
|
||||
ReadingsBulkUpdateValue ($hash, 'state', 'error');
|
||||
readingsEndUpdate ($hash, 1);
|
||||
|
||||
return $err;
|
||||
}
|
||||
|
||||
$cmd =~ s/\;\;/ESC_ESC_ESC/gx; # ersetzen von escapeten ";" (;;)
|
||||
|
||||
$cmd .= ";" if ($cmd !~ m/\;$/x);
|
||||
my $sql = $cmd;
|
||||
|
||||
Log3 ($name, 4, "DbRep $name - -------- New selection --------- ");
|
||||
Log3 ($name, 4, "DbRep $name - sqlCmdBlocking Command:\n$sql");
|
||||
|
||||
my @pms;
|
||||
my $vars = AttrVal($name, "sqlCmdVars", ""); # Set Session Variablen "SET" oder PRAGMA aus Attribut "sqlCmdVars"
|
||||
|
||||
if ($vars) {
|
||||
@pms = split ';', $vars;
|
||||
|
||||
for my $pm (@pms) {
|
||||
if($pm !~ /PRAGMA|SET/i) {
|
||||
next;
|
||||
}
|
||||
|
||||
$pm = ltrim($pm).';';
|
||||
$pm =~ s/ESC_ESC_ESC/;/gx; # wiederherstellen von escapeten ";" -> umwandeln von ";;" in ";"
|
||||
|
||||
$err = DbRep_dbhDo ($name, $dbh, $pm, "Set VARIABLE or PRAGMA: $pm");
|
||||
if ($err) {
|
||||
$err = decode_base64 ($err);
|
||||
|
||||
Log3 ($name, 2, "DbRep $name - ERROR - $err");
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
ReadingsBulkUpdateValue ($hash, 'errortext', $err);
|
||||
ReadingsBulkUpdateValue ($hash, 'state', 'error');
|
||||
readingsEndUpdate ($hash, 1);
|
||||
|
||||
return $err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Abarbeitung von Session Variablen vor einem SQL-Statement
|
||||
# z.B. SET @open:=NULL, @closed:=NULL; Select ...
|
||||
if($cmd =~ /^\s*SET.*;/i) {
|
||||
@pms = split ';', $cmd;
|
||||
$sql = q{};
|
||||
|
||||
for my $pm (@pms) {
|
||||
if($pm !~ /SET/i) {
|
||||
$sql .= $pm.';';
|
||||
next;
|
||||
}
|
||||
|
||||
$pm = ltrim($pm).';';
|
||||
$pm =~ s/ESC_ESC_ESC/;/gx; # wiederherstellen von escapeten ";" -> umwandeln von ";;" in ";"
|
||||
|
||||
$err = DbRep_dbhDo ($name, $dbh, $pm, "Set SQL session variable: $pm");
|
||||
if ($err) {
|
||||
$err = decode_base64 ($err);
|
||||
|
||||
Log3 ($name, 2, "DbRep $name - ERROR - $err");
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
ReadingsBulkUpdateValue ($hash, 'errortext', $err);
|
||||
ReadingsBulkUpdateValue ($hash, 'state', 'error');
|
||||
readingsEndUpdate ($hash, 1);
|
||||
|
||||
return $err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Abarbeitung aller Pragmas vor einem SQLite Statement, SQL wird extrahiert
|
||||
# wenn Pragmas im SQL vorangestellt sind
|
||||
if($cmd =~ /^\s*PRAGMA.*;/i) {
|
||||
@pms = split ';', $cmd;
|
||||
$sql = q{};
|
||||
|
||||
for my $pm (@pms) {
|
||||
if($pm !~ /PRAGMA.*=/i) { # PRAGMA ohne "=" werden als SQL-Statement mit Abfrageergebnis behandelt
|
||||
$sql .= $pm.';';
|
||||
next;
|
||||
}
|
||||
|
||||
$pm = ltrim($pm).';';
|
||||
$pm =~ s/ESC_ESC_ESC/;/gx; # wiederherstellen von escapeten ";" -> umwandeln von ";;" in ";"
|
||||
|
||||
$err = DbRep_dbhDo ($name, $dbh, $pm, "Exec PRAGMA Statement: $pm");
|
||||
if ($err) {
|
||||
$err = decode_base64 ($err);
|
||||
|
||||
Log3 ($name, 2, "DbRep $name - ERROR - $err");
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
ReadingsBulkUpdateValue ($hash, 'errortext', $err);
|
||||
ReadingsBulkUpdateValue ($hash, 'state', 'error');
|
||||
readingsEndUpdate ($hash, 1);
|
||||
|
||||
return $err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Abarbeitung von PREPARE statement als Befehl als Bestandteil des SQL Forum: #114293 / https://forum.fhem.de/index.php?topic=114293.0
|
||||
# z.B. PREPARE statement FROM @CMD
|
||||
if($sql =~ /^\s*PREPARE.*;/i) {
|
||||
@pms = split ';', $sql;
|
||||
$sql = q{};
|
||||
|
||||
for my $pm (@pms) {
|
||||
if($pm !~ /PREPARE/i) {
|
||||
$sql .= $pm.';';
|
||||
next;
|
||||
}
|
||||
|
||||
$pm = ltrim($pm).';';
|
||||
$pm =~ s/ESC_ESC_ESC/;/gx; # wiederherstellen von escapeten ";" -> umwandeln von ";;" in ";"
|
||||
|
||||
$err = DbRep_dbhDo ($name, $dbh, $pm, "Exec PREPARE statement: $pm");
|
||||
if ($err) {
|
||||
$err = decode_base64 ($err);
|
||||
|
||||
Log3 ($name, 2, "DbRep $name - ERROR - $err");
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
ReadingsBulkUpdateValue ($hash, 'errortext', $err);
|
||||
ReadingsBulkUpdateValue ($hash, 'state', 'error');
|
||||
readingsEndUpdate ($hash, 1);
|
||||
|
||||
return $err;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
my $st = [gettimeofday]; # SQL-Startzeit
|
||||
|
||||
my $totxt = qq{Timeout occured (limit: $to seconds). You may be able to adjust the "Timeout" attribute.};
|
||||
|
||||
my ($sth,$r,$failed);
|
||||
|
||||
eval { # outer eval fängt Alarm auf, der gerade vor diesem Alarm feuern könnte(0)
|
||||
POSIX::sigaction(SIGALRM, POSIX::SigAction->new(sub {die "Timeout\n"})); # \n ist nötig !
|
||||
|
||||
alarm($to);
|
||||
eval {
|
||||
$sth = $dbh->prepare($sql);
|
||||
$r = $sth->execute();
|
||||
1;
|
||||
};
|
||||
alarm(0); # Alarm aufheben (wenn der Code schnell lief)
|
||||
|
||||
if ($@) {
|
||||
if($@ eq "Timeout\n") { # timeout
|
||||
$failed = $totxt;
|
||||
|
||||
} else { # ein anderer Fehler
|
||||
$failed = $@;
|
||||
}
|
||||
}
|
||||
1;
|
||||
|
||||
} or $failed = $@;
|
||||
|
||||
alarm(0); # Schutz vor Race Condition
|
||||
|
||||
if ($failed) {
|
||||
$err = $failed eq "Timeout\n" ? $totxt : $failed;
|
||||
|
||||
Log3 ($name, 2, "DbRep $name - $err");
|
||||
|
||||
$sth->finish if($sth);
|
||||
$dbh->disconnect;
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
ReadingsBulkUpdateValue ($hash, 'errortext', $err);
|
||||
ReadingsBulkUpdateValue ($hash, 'state', 'error');
|
||||
readingsEndUpdate ($hash, 1);
|
||||
|
||||
return $err;
|
||||
}
|
||||
|
||||
my $nrows = 0;
|
||||
if($sql =~ m/^\s*(call|explain|select|pragma|show)/is) {
|
||||
while (my @line = $sth->fetchrow_array()) {
|
||||
Log3 ($name, 4, "DbRep $name - SQL result: @line");
|
||||
$ret .= "\n" if($nrows); # Forum: #103295
|
||||
$ret .= join("$srs", @line);
|
||||
$nrows++; # Anzahl der Datensätze
|
||||
}
|
||||
}
|
||||
else {
|
||||
$nrows = $sth->rows;
|
||||
|
||||
eval {$dbh->commit() if(!$dbh->{AutoCommit});};
|
||||
if ($@) {
|
||||
$err = $@;
|
||||
|
||||
Log3 ($name, 2, "DbRep $name - $err");
|
||||
|
||||
$dbh->disconnect;
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
ReadingsBulkUpdateValue ($hash, 'errortext', $err);
|
||||
ReadingsBulkUpdateValue ($hash, 'state', 'error');
|
||||
readingsEndUpdate ($hash, 1);
|
||||
|
||||
return $err;
|
||||
}
|
||||
|
||||
$ret = $nrows;
|
||||
}
|
||||
|
||||
$sth->finish;
|
||||
$dbh->disconnect;
|
||||
|
||||
my $rt = tv_interval($st); # SQL-Laufzeit ermitteln
|
||||
my $com = (split " ", $sql, 2)[0];
|
||||
|
||||
Log3 ($name, 4, "DbRep $name - Number of entries processed in db $hash->{DATABASE}: $nrows by $com");
|
||||
|
||||
readingsBeginUpdate ($hash);
|
||||
ReadingsBulkUpdateTimeState ($hash, undef, $rt, 'done');
|
||||
readingsEndUpdate ($hash, 1);
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
####################################################################################################
|
||||
# blockierende DB-Abfrage
|
||||
# liefert den Wert eines Device:Readings des nächstmöglichen Logeintrags zum
|
||||
@ -13844,19 +13845,17 @@ return;
|
||||
|
||||
<li><b> cancelDump </b> - stops a running database dump. </li> <br>
|
||||
|
||||
<li><b> changeValue </b> - changes the stored value of a reading.
|
||||
<a id="DbRep-set-changeValue"></a>
|
||||
<li><b> changeValue old="<old String>" new="<new String>" </b> <br><br>
|
||||
|
||||
Changes the stored value of a reading. <br>
|
||||
If the selection is limited to certain device/reading combinations by the attributes
|
||||
<a href="#DbRep-attr-device">device</a> or <a href="#DbRep-attr-reading">reading</a>, they are taken into account
|
||||
in the same way as set time limits (attributes time.*). <br>
|
||||
in the same way as set time limits (time.* attributes). <br>
|
||||
If these constraints are missing, the entire database is searched and the specified value is
|
||||
is changed. <br><br>
|
||||
|
||||
<ul>
|
||||
<b>Syntax: </b> <br>
|
||||
set <name> changeValue old="<old string>" new="<new string>" <br><br>
|
||||
|
||||
The "string" can be: <br>
|
||||
|
||||
<table>
|
||||
<colgroup> <col width=20%> <col width=80%> </colgroup>
|
||||
<tr><td><b><old String> :</b> </td><td><li>a simple string with/without spaces, e.g. "OL 12" </li> </td></tr>
|
||||
@ -13872,16 +13871,16 @@ return;
|
||||
<br>
|
||||
|
||||
<b>Examples: </b> <br>
|
||||
set <name> changeValue "OL","12 OL" <br>
|
||||
set <name> changeValue old="OL" new="12 OL" <br>
|
||||
# the old field value "OL" is changed to "12 OL". <br><br>
|
||||
|
||||
set <name> changeValue "%OL%","12 OL" <br>
|
||||
set <name> changeValue old="%OL%" new="12 OL" <br>
|
||||
# contains the field VALUE the substring "OL", it is changed to "12 OL". <br><br>
|
||||
|
||||
set <name> changeValue "12 kWh",{"($VALUE,$UNIT) = split(" ",$VALUE)"} <br>
|
||||
set <name> changeValue old="12 kWh" new={"($VALUE,$UNIT) = split(" ",$VALUE)"} <br>
|
||||
# the old field value "12 kWh" is splitted to VALUE=12 and UNIT=kWh and saved into the database fields <br><br>
|
||||
|
||||
set <name> changeValue "24%",{"$VALUE = (split(" ",$VALUE))[0]"} <br>
|
||||
set <name> changeValue old="24%" new={"$VALUE = (split(" ",$VALUE))[0]"} <br>
|
||||
# if the old field value begins with "24", it is splitted and VALUE=24 is saved (e.g. "24 kWh")
|
||||
<br><br>
|
||||
|
||||
@ -13900,12 +13899,7 @@ return;
|
||||
</ul>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<b>Note:</b> <br>
|
||||
Even though the function itself is designed non-blocking, make sure the assigned DbLog-device
|
||||
is operating in asynchronous mode to avoid FHEMWEB from blocking. <br><br>
|
||||
</li> <br>
|
||||
</ul>
|
||||
</li>
|
||||
|
||||
<li><b> countEntries [history|current] </b> - provides the number of table entries (default: history) between time period set
|
||||
by time.* -<a href="#DbRep-attr">attributes</a> if set.
|
||||
@ -14978,7 +14972,9 @@ return;
|
||||
will are listed. <br><br>
|
||||
</li><br>
|
||||
|
||||
<li><b> sqlCmd </b> - executes any user-specific command. <br>
|
||||
<li><b> sqlCmd </b> <br><br>
|
||||
|
||||
Executes any user-specific command. <br>
|
||||
If this command contains a delete operation, for safety reasons the attribute
|
||||
<a href="#DbRep-attr-allowDeletion">allowDeletion</a> has to be set. <br>
|
||||
|
||||
@ -15001,7 +14997,6 @@ return;
|
||||
If you want update a dataset, you have to add "TIMESTAMP=TIMESTAMP" to the update-statement to avoid changing the
|
||||
original timestamp. <br><br>
|
||||
|
||||
<ul>
|
||||
<b>Examples of SQL-statements: </b> <br><br>
|
||||
<ul>
|
||||
<li>set <name> sqlCmd select DEVICE, count(*) from history where TIMESTAMP >= "2017-01-06 00:00:00" group by DEVICE having count(*) > 800 </li>
|
||||
@ -15018,13 +15013,11 @@ return;
|
||||
<li>set <name> sqlCmd insert into history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES ('2017-05-09 17:00:14','Test','manuell','manuell','Tes§e','TestValue','°C') </li>
|
||||
<li>set <name> sqlCmd select DEVICE, count(*) from history where §device§ AND TIMESTAMP >= §timestamp_begin§ group by DEVICE </li>
|
||||
<li>set <name> sqlCmd select DEVICE, READING, count(*) from history where §device§ AND §reading§ AND TIMESTAMP >= §timestamp_begin§ group by DEVICE, READING </li>
|
||||
</ul>
|
||||
<br>
|
||||
|
||||
Here you can see examples of a more complex statement (MySQL) with setting SQL session
|
||||
variables and the SQLite PRAGMA usage: <br><br>
|
||||
|
||||
<ul>
|
||||
<li>set <name> sqlCmd SET @open:=NULL, @closed:=NULL;
|
||||
SELECT
|
||||
TIMESTAMP, VALUE,DEVICE,
|
||||
@ -15050,10 +15043,10 @@ return;
|
||||
To use this option, activate the attribute <a href="#DbRep-attr-sqlCmdHistoryLength">sqlCmdHistoryLength</a>
|
||||
with list lenght you want. <br>
|
||||
If the command history is enabled, an indexed list of stored SQL statements is available
|
||||
with <b>___list_sqlhistory___</b> within the sqlCmdHistory command.
|
||||
An SQL statement can be executed by specifying its index in <b>sqlCmd</b> in this form:
|
||||
<br><br>
|
||||
with <b>___list_sqlhistory___</b> within the sqlCmdHistory command. <br><br>
|
||||
|
||||
An SQL statement can be executed by specifying its index in this form:
|
||||
<br><br>
|
||||
<ul>
|
||||
set <name> sqlCmd ckey:<Index> (e.g. ckey:4)
|
||||
</ul>
|
||||
@ -15063,7 +15056,7 @@ return;
|
||||
|
||||
<ul>
|
||||
<table>
|
||||
<colgroup> <col width=5%> <col width=95%> </colgroup>
|
||||
<colgroup> <col width=25%> <col width=75%> </colgroup>
|
||||
<tr><td> <b>allowDeletion</b> </td><td>: activates capabilty to delete datasets </td></tr>
|
||||
<tr><td> <b>executeBeforeProc</b> </td><td>: execution of FHEM command (or Perl-routine) before operation </td></tr>
|
||||
<tr><td> <b>executeAfterProc</b> </td><td>: execution of FHEM command (or Perl-routine) after operation </td></tr>
|
||||
@ -15071,6 +15064,7 @@ return;
|
||||
<tr><td> <b>sqlResultFieldSep</b> </td><td>: choice of a useful field separator for result </td></tr>
|
||||
<tr><td> <b>sqlCmdHistoryLength</b> </td><td>: activates command history and length </td></tr>
|
||||
<tr><td> <b>sqlCmdVars</b> </td><td>: set SQL session variable or PRAGMA before execute the SQL statement </td></tr>
|
||||
<tr><td> <b>sqlFormatService</b> </td><td>: activates the formatting of the SQL statement via an online service </td></tr>
|
||||
<tr><td> <b>useAdminCredentials</b> </td><td>: use privileged user for the operation </td></tr>
|
||||
</table>
|
||||
</ul>
|
||||
@ -15080,11 +15074,11 @@ return;
|
||||
<b>Note:</b> <br>
|
||||
Even though the module works non-blocking regarding to database operations, a huge
|
||||
sample space (number of rows/readings) could block the browser session respectively
|
||||
FHEMWEB.
|
||||
FHEMWEB. <br>
|
||||
If you are unsure about the result of the statement, you should preventively add a limit to
|
||||
the statement. <br><br>
|
||||
</li><br>
|
||||
</ul>
|
||||
</li>
|
||||
<br>
|
||||
|
||||
<li><b> sqlCmdHistory </b> - If activated with the attribute <a href="#DbRep-attr-sqlCmdHistoryLength">sqlCmdHistoryLength</a>,
|
||||
a stored SQL statement can be selected from a list and executed.
|
||||
@ -16025,7 +16019,7 @@ sub bdump {
|
||||
Automated formatting of SQL statements can be activated via an online service. <br>
|
||||
This option is especially useful for complex SQL statements of the setters sqlCmd, sqlCmdHistory, and sqlSpecial
|
||||
to improve structuring and readability. <br>
|
||||
An Internet connection is required. <br>
|
||||
An internet connection is required and the global attribute <b>dnsServer</b> should be set. <br>
|
||||
(default: none)
|
||||
|
||||
</li>
|
||||
@ -16706,21 +16700,17 @@ return;
|
||||
|
||||
<li><b> cancelDump </b> - bricht einen laufenden Datenbankdump ab. </li> <br>
|
||||
|
||||
<a id="DbRep-set-changeValue"></a>
|
||||
<li><b> changeValue old="<alter String>" new="<neuer String>" </b> <br><br>
|
||||
|
||||
<li><b> changeValue </b> - ändert den gespeicherten Wert eines Readings.
|
||||
Ändert den gespeicherten Wert eines Readings. <br>
|
||||
Ist die Selektion auf bestimmte Device/Reading-Kombinationen durch die Attribute
|
||||
<a href="#DbRep-attr-device">device</a> bzw. <a href="#DbRep-attr-reading">reading</a> beschränkt, werden sie genauso
|
||||
berücksichtigt wie gesetzte Zeitgrenzen (Attribute time.*). <br>
|
||||
berücksichtigt wie gesetzte Zeitgrenzen (time.* Attribute). <br>
|
||||
Fehlen diese Beschränkungen, wird die gesamte Datenbank durchsucht und der angegebene Wert
|
||||
geändert. <br><br>
|
||||
</li>
|
||||
|
||||
<ul>
|
||||
<b>Syntax: </b> <br>
|
||||
set <name> changeValue old="<alter String>" new="<neuer String>" <br><br>
|
||||
|
||||
"String" kann sein: <br>
|
||||
|
||||
<table>
|
||||
<colgroup> <col width=20%> <col width=80%> </colgroup>
|
||||
<tr><td><b><alter String> :</b> </td><td><li>ein einfacher String mit/ohne Leerzeichen, z.B. "OL 12" </li> </td></tr>
|
||||
@ -16733,21 +16723,19 @@ return;
|
||||
<tr><td> </td><td>des Perl-Code geändert werden. Der zurückgebene Wert von $VALUE und $UNIT wird in dem Feld </td></tr>
|
||||
<tr><td> </td><td>VALUE bzw. UNIT des Datensatzes gespeichert. </li> </td></tr>
|
||||
</table>
|
||||
</ul>
|
||||
<br>
|
||||
|
||||
<ul>
|
||||
<b>Beispiele: </b> <br>
|
||||
set <name> changeValue "OL","12 OL" <br>
|
||||
set <name> changeValue old="OL" new="12 OL" <br>
|
||||
# der alte Feldwert "OL" wird in "12 OL" geändert. <br><br>
|
||||
|
||||
set <name> changeValue "%OL%","12 OL" <br>
|
||||
set <name> changeValue old="%OL%" new="12 OL" <br>
|
||||
# enthält das Feld VALUE den Teilstring "OL", wird es in "12 OL" geändert. <br><br>
|
||||
|
||||
set <name> changeValue "12 kWh",{"($VALUE,$UNIT) = split(" ",$VALUE)"} <br>
|
||||
set <name> changeValue old="12 kWh" new={"($VALUE,$UNIT) = split(" ",$VALUE)"} <br>
|
||||
# der alte Feldwert "12 kWh" wird in VALUE=12 und UNIT=kWh gesplittet und in den Datenbankfeldern gespeichert <br><br>
|
||||
|
||||
set <name> changeValue "24%",{"$VALUE = (split(" ",$VALUE))[0]"} <br>
|
||||
set <name> changeValue old="24%" new={"$VALUE = (split(" ",$VALUE))[0]"} <br>
|
||||
# beginnt der alte Feldwert mit "24", wird er gesplittet und VALUE=24 gespeichert (z.B. "24 kWh")
|
||||
<br><br>
|
||||
|
||||
@ -16757,7 +16745,6 @@ return;
|
||||
<table>
|
||||
<colgroup> <col width=5%> <col width=95%> </colgroup>
|
||||
<tr><td> <b>device</b> </td><td>: einschließen oder ausschließen von Datensätzen die <device> enthalten </td></tr>
|
||||
<tr><td> <b>aggregation</b> </td><td>: Auswahl einer Aggregationsperiode </td></tr>
|
||||
<tr><td> <b>reading</b> </td><td>: einschließen oder ausschließen von Datensätzen die <reading> enthalten </td></tr>
|
||||
<tr><td> <b>time.*</b> </td><td>: eine Reihe von Attributen zur Zeitabgrenzung </td></tr>
|
||||
<tr><td> <b>executeBeforeProc</b> </td><td>: ausführen FHEM Kommando (oder Perl-Routine) vor Start changeValue </td></tr>
|
||||
@ -16767,13 +16754,7 @@ return;
|
||||
</ul>
|
||||
<br>
|
||||
<br>
|
||||
|
||||
<b>Hinweis:</b> <br>
|
||||
Obwohl die Funktion selbst non-blocking ausgelegt ist, sollte das zugeordnete DbLog-Device
|
||||
im asynchronen Modus betrieben werden um ein Blockieren von FHEMWEB zu vermeiden (Tabellen-Lock). <br><br>
|
||||
<br>
|
||||
</ul>
|
||||
|
||||
</li>
|
||||
|
||||
<li><b> countEntries [history | current] </b>
|
||||
- liefert die Anzahl der Tabelleneinträge (default: history) in den gegebenen
|
||||
@ -17871,7 +17852,9 @@ return;
|
||||
verbundenen Datenbank beginnt, aufgelistet . <br><br>
|
||||
</li><br>
|
||||
|
||||
<li><b> sqlCmd </b> - führt ein beliebiges benutzerspezifisches Kommando aus. <br>
|
||||
<li><b> sqlCmd </b> <br><br>
|
||||
|
||||
Führt ein beliebiges benutzerspezifisches Kommando aus. <br>
|
||||
Enthält dieses Kommando eine Delete-Operation, muss zur Sicherheit das Attribut
|
||||
<a href="#DbRep-attr-allowDeletion">allowDeletion</a> gesetzt sein. <br>
|
||||
sqlCmd akzeptiert ebenfalls das Setzen von SQL Session Variablen wie z.B.
|
||||
@ -17893,7 +17876,6 @@ return;
|
||||
Soll ein Datensatz upgedated werden, ist dem Statement "TIMESTAMP=TIMESTAMP" hinzuzufügen um eine Änderung des
|
||||
originalen Timestamps zu verhindern. <br><br>
|
||||
|
||||
<ul>
|
||||
<b>Beispiele für Statements: </b> <br><br>
|
||||
<ul>
|
||||
<li>set <name> sqlCmd select DEVICE, count(*) from history where TIMESTAMP >= "2017-01-06 00:00:00" group by DEVICE having count(*) > 800 </li>
|
||||
@ -17910,13 +17892,11 @@ return;
|
||||
<li>set <name> sqlCmd insert into history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES ('2017-05-09 17:00:14','Test','manuell','manuell','Tes§e','TestValue','°C') </li>
|
||||
<li>set <name> sqlCmd select DEVICE, count(*) from history where §device§ AND TIMESTAMP >= §timestamp_begin§ group by DEVICE </li>
|
||||
<li>set <name> sqlCmd select DEVICE, READING, count(*) from history where §device§ AND §reading§ AND TIMESTAMP >= §timestamp_begin§ group by DEVICE, READING </li>
|
||||
</ul>
|
||||
<br>
|
||||
|
||||
Nachfolgend Beispiele für ein komplexeres Statement (MySQL) unter Mitgabe von
|
||||
SQL Session Variablen und die SQLite PRAGMA-Verwendung: <br><br>
|
||||
|
||||
<ul>
|
||||
<li>set <name> sqlCmd SET @open:=NULL, @closed:=NULL;
|
||||
SELECT
|
||||
TIMESTAMP, VALUE,DEVICE,
|
||||
@ -17943,10 +17923,10 @@ return;
|
||||
Um diese Option zu nutzen, ist das Attribut <a href="#DbRep-attr-sqlCmdHistoryLength">sqlCmdHistoryLength</a> mit der
|
||||
gewünschten Listenlänge zu aktivieren. <br>
|
||||
Ist die Kommando-Historie aktiviert, ist mit <b>___list_sqlhistory___</b> innerhalb des Kommandos
|
||||
sqlCmdHistory eine indizierte Liste der gespeicherten SQL-Statements verfügbar.
|
||||
Ein SQL-Statement kann durch Angabe seines Index im <b>sqlCmd</b> ausgeführt werden mit:
|
||||
<br><br>
|
||||
sqlCmdHistory eine indizierte Liste der gespeicherten SQL-Statements verfügbar. <br><br>
|
||||
|
||||
Ein SQL-Statement kann durch Angabe seines Index im ausgeführt werden mit:
|
||||
<br><br>
|
||||
<ul>
|
||||
set <name> sqlCmd ckey:<Index> (e.g. ckey:4)
|
||||
</ul>
|
||||
@ -17963,7 +17943,8 @@ return;
|
||||
<tr><td> <b>sqlResultFormat</b> </td><td>: legt die Darstellung des Kommandoergebnisses fest </td></tr>
|
||||
<tr><td> <b>sqlResultFieldSep</b> </td><td>: Auswahl Feldtrenner im Ergebnis </td></tr>
|
||||
<tr><td> <b>sqlCmdHistoryLength</b> </td><td>: Aktivierung Kommando-Historie und deren Umfang </td></tr>
|
||||
<tr><td> <b>sqlCmdVars</b> </td><td>: setzt SQL Session Variablen oder PRAGMA vor jeder Ausführung des SQL-Statements </td></tr>
|
||||
<tr><td> <b>sqlCmdVars</b> </td><td>: setzt SQL Session Variablen oder PRAGMA vor jeder Ausführung eines SQL-Statements </td></tr>
|
||||
<tr><td> <b>sqlFormatService</b> </td><td>: aktiviert die Formatierung des SQL Statements über einen Onlinedienst </td></tr>
|
||||
<tr><td> <b>useAdminCredentials</b> </td><td>: benutzt einen privilegierten User für die Operation </td></tr>
|
||||
</table>
|
||||
</ul>
|
||||
@ -17972,10 +17953,11 @@ return;
|
||||
<b>Hinweis:</b> <br>
|
||||
Auch wenn das Modul bezüglich der Datenbankabfrage nichtblockierend arbeitet, kann eine
|
||||
zu große Ergebnismenge (Anzahl Zeilen bzw. Readings) die Browsersesssion bzw. FHEMWEB
|
||||
blockieren. Wenn man sich unsicher ist, sollte man vorsorglich dem Statement ein Limit
|
||||
blockieren. <br>
|
||||
Wenn man sich unsicher ist, sollte man vorsorglich dem Statement ein Limit
|
||||
hinzufügen. <br><br>
|
||||
</li> <br>
|
||||
</ul>
|
||||
</li>
|
||||
<br>
|
||||
|
||||
<li><b> sqlCmdHistory </b> - Wenn mit dem Attribut <a href="#DbRep-attr-sqlCmdHistoryLength">sqlCmdHistoryLength</a> aktiviert, kann
|
||||
ein gespeichertes SQL-Statement aus einer Liste ausgewählt und ausgeführt werden.
|
||||
@ -18936,7 +18918,7 @@ sub bdump {
|
||||
Über einen Online-Dienst kann eine automatisierte Formatierung von SQL-Statements aktiviert werden. <br>
|
||||
Diese Möglichkeit ist insbesondere für komplexe SQL-Statements der Setter sqlCmd, sqlCmdHistory und sqlSpecial
|
||||
hilfreich um die Strukturierung und Lesbarkeit zu verbessern. <br>
|
||||
Eine Internetverbindung wird benötigt. <br>
|
||||
Eine Internetverbindung wird benötigt und es sollte das globale Attribut <b>dnsServer</b> gesetzt sein. <br>
|
||||
(default: none)
|
||||
|
||||
</li>
|
||||
|
Loading…
x
Reference in New Issue
Block a user