From deb7e364109d2367ac95b95d63edcb7830cfc810 Mon Sep 17 00:00:00 2001 From: nasseeder1 Date: Fri, 8 Mar 2024 14:36:14 +0000 Subject: [PATCH] 93_DbRep: attribute allowDeletion deleted, multiCmd: use of executeBeforeProc, executeAfterProc possible, prepare support of MariaDB git-svn-id: https://svn.fhem.de/fhem/trunk@28615 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 7 + fhem/FHEM/93_DbRep.pm | 663 +++++++++++++++++++----------------------- 2 files changed, 305 insertions(+), 365 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index 69f7f044f..413792c6e 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,12 @@ # Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # Do not insert empty lines here, update check depends on it. + - change: 93_DbRep: attribute allowDeletion deleted, multiCmd: use of + executeBeforeProc, executeAfterProc possible, + prepare support of MariaDB, + NOTE: if allowDeletion is set in your devices, messages + like '...The attribute 'allowDeletion' is obsolete and + will be deleted soon...'. This is _NOT_ an error. + Please save config when FHEM restart is finished. - feature: 76_SolarForecast: plantConfigCheck: check DWD Attr forecastRefresh, check weather/Rad1h data according MOSMIX variant - bugfix: 73_PRESENCE2: Fehlerbereinigungen Attribut intervalPresent diff --git a/fhem/FHEM/93_DbRep.pm b/fhem/FHEM/93_DbRep.pm index 71da438bc..cad72eb28 100644 --- a/fhem/FHEM/93_DbRep.pm +++ b/fhem/FHEM/93_DbRep.pm @@ -39,6 +39,7 @@ package main; use strict; use warnings; +use utf8; use POSIX qw(strftime SIGALRM); use Time::HiRes qw(gettimeofday tv_interval); use Scalar::Util qw(looks_like_number); @@ -59,6 +60,9 @@ no if $] >= 5.017011, warnings => 'experimental::smartmatch'; # Version History intern my %DbRep_vNotesIntern = ( + "8.53.3" => "06.03.2024 delete attribute allowDeletion, multiCmd: executeBeforeProc, executeAfterProc as attributes ". + "Set: all commands are executable even if \$dbloghash->{HELPER}{REOPEN_RUNS_UNTIL}is set ". + "prepare support of MariaDB ", "8.53.2" => "02.03.2024 delEntries, reduceLog: execute next DbRep_nextMultiCmd even if time check got failed ". "Forum:https://forum.fhem.de/index.php?msg=1305266 ", "8.53.1" => "16.02.2024 sqlCmd: executing ckey:latest possible ", @@ -93,31 +97,6 @@ my %DbRep_vNotesIntern = ( "8.51.0" => "02.01.2023 online formatting of sqlCmd, sqlCmdHistory, sqlSpecial, Commandref edited, get dbValue removed ". "sqlCmdBlocking customized like sqlCmd, bugfix avgTimeWeightMean ", "8.50.10" => "01.01.2023 Commandref edited ", - "8.50.9" => "28.12.2022 Commandref changed to a id-links ", - "8.50.8" => "21.12.2022 add call to DbRep_sqlCmd, DbRep_sqlCmdBlocking ", - "8.50.7" => "17.12.2022 Commandref edited ", - "8.50.6" => "14.12.2022 remove ularm from Time::HiRes, Forum: https://forum.fhem.de/index.php/topic,53584.msg1251313.html#msg1251313 ", - "8.50.5" => "05.12.2022 fix diffValue problem (DbRep_diffval) for newer MariaDB versions: https://forum.fhem.de/index.php/topic,130697.0.html ", - "8.50.4" => "04.11.2022 fix daylight saving bug in aggregation eq 'month' (_DbRep_collaggstr) ", - "8.50.3" => "19.09.2022 reduce memory allocation of function DbRep_reduceLog ", - "8.50.2" => "17.09.2022 release setter 'index' for device model 'Agent' ", - "8.50.1" => "05.09.2022 DbRep_setLastCmd, change changeValue syntax, minor fixes ", - "8.50.0" => "20.08.2022 rework of DbRep_reduceLog - add max, max=day, min, min=day, sum, sum=day ", - "8.49.1" => "03.08.2022 fix DbRep_deleteOtherFromDB, Forum: https://forum.fhem.de/index.php/topic,128605.0.html ". - "some code changes and bug fixes ", - "8.49.0" => "16.05.2022 allow optionally set device / reading in the insert command ", - "8.48.4" => "16.05.2022 fix perl warning of set ... insert, Forum: topic,53584.msg1221588.html#msg1221588 ", - "8.48.3" => "09.04.2022 minor code fix in DbRep_reduceLog ", - "8.48.2" => "22.02.2022 more code refacturing ", - "8.48.1" => "31.01.2022 minor fixes e.g. in file size determination, dump routines ", - "8.48.0" => "29.01.2022 new sqlCmdHistory params ___restore_sqlhistory___ , ___save_sqlhistory___ ". - "change _DbRep_mysqlOptimizeTables, revise insert command ", - "8.47.0" => "17.01.2022 new design of sqlCmdHistory, minor fixes ", - "8.46.13" => "12.01.2022 more code refacturing, minor fixes ", - "8.46.12" => "10.01.2022 more code refacturing, minor fixes, change usage of placeholder §device§, §reading§ in sqlCmd ", - "8.46.11" => "03.01.2022 more code refacturing, minor fixes ", - "8.46.10" => "02.01.2022 more code refacturing, minor fixes ", - "8.46.9" => "01.01.2022 some more code refacturing, minor fixes ", "1.0.0" => "19.05.2016 Initial" ); @@ -409,9 +388,9 @@ sub DbRep_Initialize { $hash->{FW_deviceOverview} = 1; $hash->{AttrList} = "aggregation:minute,hour,day,week,month,year,no ". + "allowDeletion:obsolete ". "disable:1,0 ". "reading ". - "allowDeletion:1,0 ". "autoForward:textField-long ". "averageCalcForm:avgArithmeticMean,avgDailyMeanGWS,avgDailyMeanGWSwithGTS,avgTimeWeightMean ". "countEntriesDetail:1,0 ". @@ -558,11 +537,11 @@ sub DbRep_Set { opendir(DIR,$dir); - if ($dbmodel =~ /MYSQL/) { + if ($dbmodel =~ /MYSQL|MARIADB/xs) { $dbname = $hash->{DATABASE}; $sd = $dbname."_.*?(csv|sql)"; } - elsif ($dbmodel =~ /SQLITE/) { + elsif ($dbmodel =~ /SQLITE/xs) { $dbname = $hash->{DATABASE}; $dbname = (split /[\/]/, $dbname)[-1]; $dbname = (split /\./, $dbname)[0]; @@ -578,7 +557,7 @@ sub DbRep_Set { my $cj = @bkps ? join(",",reverse(sort @bkps)) : " "; my (undef, $hl) = DbRep_listSQLcmdCache ($name); # Drop-Down Liste bisherige Befehle in "sqlCmd" erstellen - + if (AttrVal($name, "sqlCmdHistoryLength", 0)) { $hl .= "___purge_sqlhistory___"; $hl .= ",___list_sqlhistory___"; @@ -600,7 +579,7 @@ sub DbRep_Set { $specials .= ",allDevReadCount"; $specials .= ",50DevReadCount"; $specials .= ",recentReadingsOfDevice"; - $specials .= $dbmodel eq "MYSQL" ? ",readingsDifferenceByTimeDelta" : ""; + $specials .= $dbmodel =~ /MYSQL|MARIADB/xs ? ",readingsDifferenceByTimeDelta" : ""; my $indl = "list_all"; $indl .= ",recreate_Search_Idx"; @@ -634,27 +613,27 @@ sub DbRep_Set { ($hash->{ROLE} ne "Agent" ? "sumValue:display,writeToDB,writeToDBSingle,writeToDBInTime " : ""). ($hash->{ROLE} ne "Agent" ? "averageValue:display,writeToDB,writeToDBSingle,writeToDBSingleStart,writeToDBInTime " : ""). ($hash->{ROLE} ne "Agent" ? "delSeqDoublets:adviceRemain,adviceDelete,delete " : ""). - ($hash->{ROLE} ne "Agent" && $hl ? "sqlCmdHistory:".$hl." " : ""). - ($hash->{ROLE} ne "Agent" && $dbmodel =~ /MYSQL/ ? "adminCredentials " : ""). - ($hash->{ROLE} ne "Agent" && $dbmodel =~ /MYSQL/ ? "dumpMySQL:clientSide,serverSide " : ""). - ($hash->{ROLE} ne "Agent" && $dbmodel =~ /MYSQL/ ? "migrateCollation:".$collation." " : ""). - ($hash->{ROLE} ne "Agent" && $dbmodel =~ /SQLITE/ ? "dumpSQLite:noArg " : ""). - ($hash->{ROLE} ne "Agent" && $dbmodel =~ /SQLITE/ ? "repairSQLite " : ""). - ($hash->{ROLE} ne "Agent" && $dbmodel =~ /MYSQL/ ? "optimizeTables:showInfo,execute " : ""). - ($hash->{ROLE} ne "Agent" && $dbmodel =~ /SQLITE|POSTGRESQL/ ? "vacuum:noArg " : ""). - ($hash->{ROLE} ne "Agent" && $dbmodel =~ /MYSQL/ ? "restoreMySQL:".$cj." " : ""). - ($hash->{ROLE} ne "Agent" && $dbmodel =~ /SQLITE/ ? "restoreSQLite:".$cj." " : "") + ($hash->{ROLE} ne "Agent" && $hl ? "sqlCmdHistory:".$hl." " : ""). + ($hash->{ROLE} ne "Agent" && $dbmodel =~ /MYSQL|MARIADB/xs ? "adminCredentials " : ""). + ($hash->{ROLE} ne "Agent" && $dbmodel =~ /MYSQL|MARIADB/xs ? "dumpMySQL:clientSide,serverSide " : ""). + ($hash->{ROLE} ne "Agent" && $dbmodel =~ /MYSQL|MARIADB/xs ? "migrateCollation:".$collation." " : ""). + ($hash->{ROLE} ne "Agent" && $dbmodel =~ /SQLITE/xs ? "dumpSQLite:noArg " : ""). + ($hash->{ROLE} ne "Agent" && $dbmodel =~ /SQLITE/xs ? "repairSQLite " : ""). + ($hash->{ROLE} ne "Agent" && $dbmodel =~ /MYSQL|MARIADB/xs ? "optimizeTables:showInfo,execute " : ""). + ($hash->{ROLE} ne "Agent" && $dbmodel =~ /SQLITE|POSTGRESQL/xs ? "vacuum:noArg " : ""). + ($hash->{ROLE} ne "Agent" && $dbmodel =~ /MYSQL|MARIADB/xs ? "restoreMySQL:".$cj." " : ""). + ($hash->{ROLE} ne "Agent" && $dbmodel =~ /SQLITE/xs ? "restoreSQLite:".$cj." " : "") ; return if(IsDisabled($name)); if ($opt eq 'eraseReadings') { DbRep_setLastCmd (@a); - + no strict 'refs'; $dbrep_hmainf{$opt}{fn} ($hash); # Readings löschen die nicht in der Ausnahmeliste (Attr readingPreventFromDel) stehen use strict; - + return; } @@ -753,17 +732,12 @@ sub DbRep_Set { } DbRep_setLastCmd ($name, $opt, $prop); - - if ($prop =~ /delete/ && !AttrVal($hash->{NAME}, "allowDeletion", 0)) { - return " Set attribute 'allowDeletion' if you want to allow deletion of any database entries. Use it with care !"; - } - - DbRep_Main ($hash, $opt, $prop); + DbRep_Main ($hash, $opt, $prop); return; } - if ($opt =~ m/reduceLog/ && $hash->{ROLE} ne "Agent") { + if ($opt =~ m/reduceLog/ && $hash->{ROLE} ne "Agent") { if ($hash->{HELPER}{$dbrep_hmainf{reduceLog}{pk}} && $hash->{HELPER}{$dbrep_hmainf{reduceLog}{pk}}{pid} !~ m/DEAD/) { return "reduceLog already in progress. Please wait for the current process to finish."; } @@ -871,7 +845,7 @@ sub DbRep_Set { return; } - + if ($opt eq 'fetchrows' && $hash->{ROLE} ne "Agent") { my $table = $prop // "history"; @@ -884,24 +858,18 @@ sub DbRep_Set { ####################################################################################################### ## keine Aktionen außer die über diesem Eintrag solange Reopen xxxx im DbLog-Device läuft ####################################################################################################### - if ($dbloghash->{HELPER}{REOPEN_RUNS} && $opt !~ /\?/) { - my $ro = $dbloghash->{HELPER}{REOPEN_RUNS_UNTIL}; - - Log3 ($name, 3, "DbRep $name - connection $dblogdevice to db $dbname is closed until $ro - $opt postponed"); - - ReadingsSingleUpdateValue ($hash, "state", "connection $dblogdevice to $dbname is closed until $ro - $opt postponed", 1); - return; - } + #if ($dbloghash->{HELPER}{REOPEN_RUNS} && $opt !~ /\?/) { + # my $ro = $dbloghash->{HELPER}{REOPEN_RUNS_UNTIL}; + # Log3 ($name, 3, "DbRep $name - connection $dblogdevice to db $dbname is closed until $ro - $opt postponed"); + # ReadingsSingleUpdateValue ($hash, "state", "connection $dblogdevice to $dbname is closed until $ro - $opt postponed", 1); + # return; + #} if ($opt =~ m/(max|min|sum|average|diff)Value/ && $hash->{ROLE} ne "Agent") { if (!AttrVal($hash->{NAME}, "reading", "")) { return " The attribute reading to analyze is not set !"; } - if ($prop && $prop =~ /deleteOther/ && !AttrVal($hash->{NAME}, "allowDeletion", 0)) { - return " Set attribute 'allowDeletion' if you want to allow deletion of any database entries. Use it with care !"; - } - if ($prop && $prop =~ /writeToDB/) { if (!AttrVal($hash->{NAME}, "device", "") || AttrVal($hash->{NAME}, "device", "") =~ /[%*:=,]/ || AttrVal($hash->{NAME}, "reading", "") =~ /[,\s]/) { return "If you want write results back to database, attributes \"device\" and \"reading\" must be set.
@@ -914,10 +882,6 @@ sub DbRep_Set { DbRep_Main ($hash,$opt,$prop); } elsif ($opt =~ m/delEntries|tableCurrentPurge/ && $hash->{ROLE} ne "Agent") { - if (!AttrVal($hash->{NAME}, "allowDeletion", undef)) { - return " Set attribute 'allowDeletion' if you want to allow deletion of any database entries. Use it with care !"; - } - DbRep_setLastCmd (@a); shift @a; @@ -985,7 +949,7 @@ sub DbRep_Set { } # Attribute device & reading dürfen kein SQL-Wildcard % enthalten - if($i_device =~ m/%/ || $i_reading =~ m/%/ ) { + if ($i_device =~ m/%/ || $i_reading =~ m/%/ ) { return qq{One or both of "device", "reading" containing SQL wildcard "%". Wildcards are not allowed in manual function insert !} } @@ -1038,13 +1002,13 @@ sub DbRep_Set { my $sqlcmd; - if($opt eq "sqlSpecial") { + if ($opt eq "sqlSpecial") { my ($tq,$gcl); - if($prop eq "50mostFreqLogsLast2days") { - $sqlcmd = "select Device, reading, count(0) AS `countA` from history where TIMESTAMP > (NOW() - INTERVAL 2 DAY) group by DEVICE, READING order by countA desc, DEVICE limit 50;" if($dbmodel =~ /MYSQL/); - $sqlcmd = "select Device, reading, count(0) AS `countA` from history where TIMESTAMP > datetime('now' ,'-2 days') group by DEVICE, READING order by countA desc, DEVICE limit 50;" if($dbmodel =~ /SQLITE/); - $sqlcmd = "select Device, reading, count(0) AS countA from history where TIMESTAMP > (NOW() - INTERVAL '2' DAY) group by DEVICE, READING order by countA desc, DEVICE limit 50;" if($dbmodel =~ /POSTGRESQL/); + if ($prop eq "50mostFreqLogsLast2days") { + $sqlcmd = "select Device, reading, count(0) AS `countA` from history where TIMESTAMP > (NOW() - INTERVAL 2 DAY) group by DEVICE, READING order by countA desc, DEVICE limit 50;" if($dbmodel =~ /MYSQL|MARIADB/xs); + $sqlcmd = "select Device, reading, count(0) AS `countA` from history where TIMESTAMP > datetime('now' ,'-2 days') group by DEVICE, READING order by countA desc, DEVICE limit 50;" if($dbmodel =~ /SQLITE/xs); + $sqlcmd = "select Device, reading, count(0) AS countA from history where TIMESTAMP > (NOW() - INTERVAL '2' DAY) group by DEVICE, READING order by countA desc, DEVICE limit 50;" if($dbmodel =~ /POSTGRESQL/xs); } elsif ($prop eq "allDevReadCount") { $sqlcmd = "select device, reading, count(*) as count from history group by DEVICE, READING order by count desc;"; @@ -1056,9 +1020,9 @@ sub DbRep_Set { $sqlcmd = "select device, count(*) from history group by DEVICE;"; } elsif ($prop eq "recentReadingsOfDevice") { - if($dbmodel =~ /MYSQL/) {$tq = "NOW() - INTERVAL 1 DAY"; $gcl = "READING"}; - if($dbmodel =~ /SQLITE/) {$tq = "datetime('now','-1 day')"; $gcl = "READING"}; - if($dbmodel =~ /POSTGRESQL/) {$tq = "CURRENT_TIMESTAMP - INTERVAL '1 day'"; $gcl = "READING,DEVICE"}; + if ($dbmodel =~ /MYSQL|MARIADB/xs) {$tq = "NOW() - INTERVAL 1 DAY"; $gcl = "READING"}; + if ($dbmodel =~ /SQLITE/xs) {$tq = "datetime('now','-1 day')"; $gcl = "READING"}; + if ($dbmodel =~ /POSTGRESQL/xs) {$tq = "CURRENT_TIMESTAMP - INTERVAL '1 day'"; $gcl = "READING,DEVICE"}; $sqlcmd = "SELECT t1.TIMESTAMP,t1.DEVICE,t1.READING,t1.VALUE FROM history t1 @@ -1099,12 +1063,12 @@ sub DbRep_Set { if (!keys %{$data{DbRep}{$name}{sqlcache}{cmd}}) { return qq{No SQL statements are cached.}; } - + my $key = (split ":", $sqlcmd)[1]; - + if ($key eq 'latest') { my @xe = sort{$b<=>$a} keys %{$data{DbRep}{$name}{sqlcache}{cmd}}; - $key = shift @xe; + $key = shift @xe; } if (exists $data{DbRep}{$name}{sqlcache}{cmd}{$key}) { @@ -1118,7 +1082,7 @@ sub DbRep_Set { $sqlcmd .= ';' if ($sqlcmd !~ m/\;$/x); } - if($opt eq "sqlCmdHistory") { + if ($opt eq "sqlCmdHistory") { $sqlcmd = $prop; $sqlcmd =~ s/§/_ESC_ECS_/g; $sqlcmd =~ tr/ A-Za-z0-9!"#%&'()*+,-.\/:;<=>?@[\\]^_`{|}~äöüÄÖÜ߀/ /cs; @@ -1126,35 +1090,30 @@ sub DbRep_Set { $sqlcmd =~ s//,/g; # noch aus Kompatibilitätsgründen enthalten $sqlcmd =~ s/(\x20)*\xbc/,/g; # Forum: https://forum.fhem.de/index.php/topic,103908.0.html - if($sqlcmd eq "___purge_sqlhistory___") { + if ($sqlcmd eq "___purge_sqlhistory___") { DbRep_deleteSQLcmdCache ($name); return "SQL command historylist of $name deleted."; } - if($sqlcmd eq "___list_sqlhistory___") { + if ($sqlcmd eq "___list_sqlhistory___") { my ($cache) = DbRep_listSQLcmdCache ($name); return $cache; } - if($sqlcmd eq "___save_sqlhistory___") { + if ($sqlcmd eq "___save_sqlhistory___") { my $err = DbRep_writeSQLcmdCache ($hash); # SQL Cache File schreiben $err //= "SQL history entries of $name successfully saved"; return $err; } - if($sqlcmd eq "___restore_sqlhistory___") { + if ($sqlcmd eq "___restore_sqlhistory___") { my $count = DbRep_initSQLcmdCache ($name); return $count ? "SQL history entries of $name restored: $count" : undef; } } - if ($sqlcmd =~ m/^\s*delete/is && !AttrVal($name, 'allowDeletion', undef)) { - return "Attribute 'allowDeletion = 1' is needed for command '$sqlcmd'. Use it with care !"; - } - $sqlcmd = _DbRep_sqlFormOnline ($hash, $sqlcmd); # SQL Statement online formatieren - - $sqlcmd = DbRep_trim ($sqlcmd); + $sqlcmd = DbRep_trim ($sqlcmd); $data{DbRep}{$name}{sqlcache}{temp} = $sqlcmd; # SQL incl. Formatierung zwischenspeichern my @cmd = split /\s+/, $sqlcmd; @@ -1175,7 +1134,7 @@ sub DbRep_Set { my $complex = 0; - if($newval =~ m/^\s*\{"(.*)"\}\s*$/s) { + if ($newval =~ m/^\s*\{"(.*)"\}\s*$/s) { $newval = $1; $complex = 1; } @@ -1192,7 +1151,7 @@ sub DbRep_Set { return qq{A DbLog-device (standby) is needed to sync. Use "set $name syncStandby "}; } - if(!exists($defs{$prop}) || $defs{$prop}->{TYPE} ne "DbLog") { + if (!exists($defs{$prop}) || $defs{$prop}->{TYPE} ne "DbLog") { return qq{The device "$prop" doesn't exist or is not a DbLog-device.}; } @@ -1313,11 +1272,11 @@ sub DbRep_Get { "minTimestamp:noArg ". "initData:noArg ". "sqlCmdBlocking:textField-long ". - (($dbmodel =~ /MYSQL/) ? "storedCredentials:noArg " : ""). - (($dbmodel eq "MYSQL") ? "dbstatus:noArg " : ""). - (($dbmodel eq "MYSQL") ? "tableinfo:noArg " : ""). - (($dbmodel eq "MYSQL") ? "procinfo:noArg " : ""). - (($dbmodel eq "MYSQL") ? "dbvars:noArg " : ""). + (($dbmodel =~ /MYSQL|MARIADB/xs) ? "storedCredentials:noArg " : ""). + (($dbmodel =~ /MYSQL|MARIADB/xs) ? "dbstatus:noArg " : ""). + (($dbmodel =~ /MYSQL|MARIADB/xs) ? "tableinfo:noArg " : ""). + (($dbmodel =~ /MYSQL|MARIADB/xs) ? "procinfo:noArg " : ""). + (($dbmodel =~ /MYSQL|MARIADB/xs) ? "dbvars:noArg " : ""). "versionNotes " ; @@ -1335,7 +1294,7 @@ sub DbRep_Get { if ($opt =~ /dbvars|dbstatus|tableinfo|procinfo/) { return "Dump is running - try again later !" if($hash->{HELPER}{RUNNING_BACKUP_CLIENT}); - return "The operation \"$opt\" isn't available with database type $dbmodel" if($dbmodel ne 'MYSQL'); + return qq{The operation "$opt" isn't available with database type $dbmodel} if($dbmodel !~ /MYSQL|MARIADB/xs); DbRep_delread ($hash); # Readings löschen die nicht in der Ausnahmeliste (Attr readingPreventFromDel) stehen DbRep_setLastCmd (@a); @@ -1387,17 +1346,12 @@ sub DbRep_Get { $sqlcmd = join ' ', @cmd; DbRep_setLastCmd ($name, $opt, $sqlcmd); - - if ($sqlcmd =~ m/^\s*delete/is && !AttrVal($name, "allowDeletion", undef)) { - return "Attribute 'allowDeletion = 1' is needed for command '$sqlcmd'. Use it with care !"; - } - - DbRep_delread ($hash); # Readings löschen die nicht in der Ausnahmeliste (Attr readingPreventFromDel) stehen + DbRep_delread ($hash); # Readings löschen die nicht in der Ausnahmeliste (Attr readingPreventFromDel) stehen ReadingsSingleUpdateValue ($hash, "state", "running", 1); return DbRep_sqlCmdBlocking($name,$sqlcmd); } - elsif ($opt eq "storedCredentials") { # Credentials abrufen + elsif ($opt eq "storedCredentials") { # Credentials abrufen my $atxt; my $username = $defs{$defs{$name}->{HELPER}{DBLOGDEVICE}}->{dbuser}; my $dblogname = $defs{$defs{$name}->{HELPER}{DBLOGDEVICE}}->{NAME}; @@ -1527,13 +1481,24 @@ sub DbRep_Attr { my $dbmodel = $dbloghash->{MODEL}; my $do; + ### nicht mehr benötigte Daten verarbeiten - Bereich kann später wieder raus !! + ###################################################################################################################### + if ($cmd eq 'set' && $aName eq 'allowDeletion') { + if (!$init_done) { + return qq{Device "$name" -> The attribute '$aName' is obsolete and will be deleted soon. Please press "save config" when FHEM start is finished.}; + } + else { + return qq{The attribute '$aName' is obsolete and will be deleted soon.}; + } + } + ###################################################################################################################### + # $cmd can be "del" or "set" # $name is device name # aName and aVal are Attribute name and value # nicht erlaubte / nicht setzbare Attribute wenn role = Agent my @agentnoattr = qw(aggregation - allowDeletion autoForward dumpDirLocal reading @@ -2108,7 +2073,7 @@ sub DbRep_getInitData { my $bst = [gettimeofday]; # Background-Startzeit - my ($err,$dbh,$dbmodel) = DbRep_dbConnect($name, 0); + my ($err,$dbh,$dbmodel) = DbRep_dbConnect ($name, 0); return "$name|$err" if ($err); my $st = [gettimeofday]; # SQL-Startzeit @@ -2124,17 +2089,17 @@ sub DbRep_getInitData { my $encc = qq{}; my (@se,@sec); - if($dbmodel =~ /MYSQL/) { + if($dbmodel =~ /MYSQL|MARIADB/xs) { eval { @se = $dbh->selectrow_array("SELECT default_character_set_name FROM information_schema.SCHEMATA WHERE schema_name = '$database'") }; $enc = $se[0] // $enc; eval { @sec = $dbh->selectrow_array("SHOW VARIABLES LIKE 'character_set_connection'") }; $encc = $sec[1] // $encc; } - elsif($dbmodel =~ /SQLITE/) { + elsif($dbmodel =~ /SQLITE/xs) { eval { @se = $dbh->selectrow_array("PRAGMA encoding;") }; $enc = $se[0] // $enc; } - elsif($dbmodel =~ /POSTGRESQL/) { + elsif($dbmodel =~ /POSTGRESQL/xs) { eval { @se = $dbh->selectrow_array("SELECT pg_encoding_to_char(encoding) FROM pg_database WHERE datname = '$database'") }; $enc = $se[0] // $enc; eval { @sec = $dbh->selectrow_array("SHOW CLIENT_ENCODING") }; @@ -2150,13 +2115,13 @@ sub DbRep_getInitData { my ($ava,$sqlava); - if($dbmodel =~ /MYSQL/) { + if($dbmodel =~ /MYSQL|MARIADB/xs) { $sqlava = "SHOW INDEX FROM history where Key_name='$idx';"; } - elsif($dbmodel =~ /SQLITE/) { + elsif($dbmodel =~ /SQLITE/xs) { $sqlava = "SELECT name FROM sqlite_master WHERE type='index' AND name='$idx';"; } - elsif($dbmodel =~ /POSTGRESQL/) { + elsif($dbmodel =~ /POSTGRESQL/xs) { $sqlava = "SELECT indexname FROM pg_indexes WHERE tablename='history' and indexname ='$idx';"; } @@ -2248,8 +2213,7 @@ sub _DbRep_getInitData_grants { my ($sth,@uniq); - if($dbmodel eq 'MYSQL') { - + if($dbmodel =~ /MYSQL|MARIADB/xs) { eval {$sth = $dbh->prepare("SHOW GRANTS FOR CURRENT_USER();"); $sth->execute(); 1; @@ -2309,7 +2273,7 @@ sub DbRep_getInitDataDone { Log3 ($name, 5, qq{DbRep $name - getInitData finished PID "$hash->{HELPER}{RUNNING_PID}{pid}"}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { readingsBeginUpdate ($hash); @@ -2367,7 +2331,7 @@ sub DbRep_getInitDataAborted { Log3 ($name, 1, "DbRep $name -> BlockingCall $hash->{HELPER}{RUNNING_PID}{fn} pid:$hash->{HELPER}{RUNNING_PID}{pid} $cause"); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; readingsBeginUpdate ($hash); ReadingsBulkUpdateValue ($hash, "errortext", $cause); @@ -2420,7 +2384,7 @@ sub DbRep_Main { table => "history" }; - if ($dbmodel =~ /MYSQL/) { + if ($dbmodel =~ /MYSQL|MARIADB/xs) { if ($prop eq "serverSide") { $hash->{HELPER}{RUNNING_BCKPREST_SERVER} = BlockingCall("DbRep_mysql_DumpServerSide", $params, "DbRep_DumpDone", $to, "DbRep_DumpAborted", $hash); $hash->{HELPER}{RUNNING_BCKPREST_SERVER}{loglevel} = 5 if(exists $hash->{HELPER}{RUNNING_BCKPREST_SERVER}); @@ -2433,7 +2397,7 @@ sub DbRep_Main { } } - if ($dbmodel =~ /SQLITE/) { + if ($dbmodel =~ /SQLITE/xs) { $hash->{HELPER}{RUNNING_BACKUP_CLIENT} = BlockingCall("DbRep_sqlite_Dump", $params, "DbRep_DumpDone", $to, "DbRep_DumpAborted", $hash); $hash->{HELPER}{RUNNING_BACKUP_CLIENT}{loglevel} = 5 if(exists $hash->{HELPER}{RUNNING_BACKUP_CLIENT}); ReadingsSingleUpdateValue ($hash, 'state', 'SQLite Dump is running - be patient and see Logfile!', 1); @@ -2548,9 +2512,9 @@ sub DbRep_Main { ## eventuell bereits laufenden BlockingCall beenden ##################################################### if (exists($hash->{HELPER}{$dbrep_hmainf{$opt}{pk}}) && $hash->{ROLE} ne "Agent") { - + Log3 ($name, 3, "DbRep $name - WARNING - running process $hash->{HELPER}{$dbrep_hmainf{$opt}{pk}}{pid} will be killed now to start a new operation"); - + BlockingKill($hash->{HELPER}{$dbrep_hmainf{$opt}{pk}}); } @@ -2616,11 +2580,11 @@ sub DbRep_Main { if ($opt eq "delEntries" || $opt =~ /reduceLog/xi) { # Forum:#113202 my ($valid, $cause) = DbRep_checkValidTimeSequence ($hash, $runtime_string_first, $runtime_string_next); - + if (!$valid) { Log3 ($name, 2, "DbRep $name - ERROR - $cause"); - DbRep_delHashtags ($hash); - DbRep_nextMultiCmd ($name); # nächstes multiCmd ausführen falls gesetzt + DbRep_delHashtags ($hash); + DbRep_nextMultiCmd ($name); # nächstes multiCmd ausführen falls gesetzt return; } @@ -3356,7 +3320,7 @@ sub DbRep_averval { my ($gts, $gtsstr) = (0, q{}); # Variablen für Grünlandtemperatursumme GTS - my ($err,$dbh,$dbmodel) = DbRep_dbConnect($name, 0); + my ($err,$dbh,$dbmodel) = DbRep_dbConnect ($name, 0); return "$name|$err" if ($err); my ($IsTimeSet,$IsAggrSet) = DbRep_checktimeaggr($hash); # ist Zeiteingrenzung und/oder Aggregation gesetzt ? (wenn ja -> "?" in SQL sonst undef) @@ -3810,7 +3774,7 @@ sub DbRep_avervalDone { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -3915,7 +3879,7 @@ sub DbRep_count { my $bst = [gettimeofday]; # Background-Startzeit - my ($err,$dbh,$dbmodel) = DbRep_dbConnect($name, 0); + my ($err,$dbh,$dbmodel) = DbRep_dbConnect ($name, 0); return "$name|$err" if ($err); no warnings 'uninitialized'; @@ -4015,7 +3979,7 @@ sub DbRep_countDone { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -4090,7 +4054,7 @@ sub DbRep_maxval { my $bst = [gettimeofday]; # Background-Startzeit - my ($err,$dbh,$dbmodel) = DbRep_dbConnect($name, 0); + my ($err,$dbh,$dbmodel) = DbRep_dbConnect ($name, 0); return "$name|$err" if ($err); no warnings 'uninitialized'; @@ -4254,7 +4218,7 @@ sub DbRep_maxvalDone { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -4327,7 +4291,7 @@ sub DbRep_minval { my $bst = [gettimeofday]; # Background-Startzeit - my ($err,$dbh,$dbmodel) = DbRep_dbConnect($name, 0); + my ($err,$dbh,$dbmodel) = DbRep_dbConnect ($name, 0); return "$name|$err" if ($err); no warnings 'uninitialized'; @@ -4485,7 +4449,7 @@ sub DbRep_minvalDone { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -4545,6 +4509,7 @@ return; #################################################################################################### # nichtblockierende DB-Abfrage diffValue +# "OLDMYSQLVER" -> ursprünglich für MYSQL verwendete Statements -> obsolet #################################################################################################### sub DbRep_diffval { my $paref = shift; @@ -4561,7 +4526,7 @@ sub DbRep_diffval { my $bst = [gettimeofday]; # Background-Startzeit - my ($err,$dbh,$dbmodel) = DbRep_dbConnect($name, 0); + my ($err,$dbh,$dbmodel) = DbRep_dbConnect ($name, 0); return "$name|$err" if ($err); no warnings 'uninitialized'; @@ -4572,7 +4537,7 @@ sub DbRep_diffval { my @ts = split("\\|", $ts); # Timestampstring to Array Log3 ($name, 5, "DbRep $name - Timestamp-Array: \n@ts"); - if($dbmodel eq "OLDMYSQLVER") { # Forum: https://forum.fhem.de/index.php/topic,130697.0.html + if ($dbmodel eq "OLDMYSQLVER") { # Forum: https://forum.fhem.de/index.php/topic,130697.0.html $selspec = "TIMESTAMP,VALUE, if(VALUE-\@V < 0 OR \@RB = 1 , \@diff:= 0, \@diff:= VALUE-\@V ) as DIFF, \@V:= VALUE as VALUEBEFORE, \@RB:= '0' as RBIT "; } else { @@ -4594,7 +4559,7 @@ sub DbRep_diffval { my $runtime_string_next = $a[2]; $runtime_string = encode_base64($runtime_string,""); - if($dbmodel eq "OLDMYSQLVER") { # Forum: https://forum.fhem.de/index.php/topic,130697.0.html + if ($dbmodel eq "OLDMYSQLVER") { # Forum: https://forum.fhem.de/index.php/topic,130697.0.html ($err, undef) = DbRep_dbhDo ($name, $dbh, "set \@V:= 0, \@diff:= 0, \@diffTotal:= 0, \@RB:= 1;"); # @\RB = Resetbit wenn neues Selektionsintervall beginnt return "$name|$err" if ($err); } @@ -4609,7 +4574,7 @@ sub DbRep_diffval { ($err, $sth) = DbRep_prepareExecuteQuery ($name, $dbh, $sql); return "$name|$err" if ($err); - if($dbmodel eq "OLDMYSQLVER") { # Forum: https://forum.fhem.de/index.php/topic,130697.0.html + if ($dbmodel eq "OLDMYSQLVER") { # Forum: https://forum.fhem.de/index.php/topic,130697.0.html @array = map { $runtime_string." ".$_ -> [0]." ".$_ -> [1]." ".$_ -> [2]."\n" } @{ $sth->fetchall_arrayref() }; } else { @@ -4654,18 +4619,18 @@ sub DbRep_diffval { } } - if(!@array) { + if (!@array) { my $aval = AttrVal($name, "aggregation", ""); - if($aval eq "month") { + if ($aval eq "month") { my @rsf = split /[ -]/, $runtime_string_first; @array = ($runtime_string." ".$rsf[0]."_".$rsf[1]."\n"); } - elsif($aval eq "hour") { + elsif ($aval eq "hour") { my @rsf = split /[ :]/, $runtime_string_first; @array = ($runtime_string." ".$rsf[0]."_".$rsf[1]."\n"); } - elsif($aval eq "minute") { + elsif ($aval eq "minute") { my @rsf = split /[ :]/, $runtime_string_first; @array = ($runtime_string." ".$rsf[0]."_".$rsf[1]."-".$rsf[2]."\n"); } @@ -4705,16 +4670,15 @@ sub DbRep_diffval { my $runtime_string = decode_base64($a[0]); $lastruntimestring = $runtime_string if ($i == 1); - if(!$a[2]) { + if (!$a[2]) { $rh{$runtime_string} = $runtime_string."|-|".$runtime_string; next; } - my $timestamp = $a[1]."_".$a[2]; - my $value = $a[3] ? $a[3] : 0; - my $diff = $a[4] ? $a[4] : 0; - - $timestamp =~ s/\s+$//g; # Leerzeichen am Ende $timestamp entfernen + my $timestamp = $a[1]."_".$a[2]; + my $value = $a[3] ? $a[3] : 0; + my $diff = $a[4] ? $a[4] : 0; + $timestamp =~ s/\s+$//g; # Leerzeichen am Ende $timestamp entfernen if (!DbRep_IsNumeric ($value)) { # Test auf $value = "numeric" $a[3] =~ s/\s+$//g; @@ -4727,7 +4691,7 @@ sub DbRep_diffval { $diff_current = $timestamp." ".$diff; # String ignorierter Zeilen erzeugen - if(abs $diff > $dlim) { + if (abs $diff > $dlim) { $rejectstr .= $diff_before." -> ".$diff_current."\n"; } @@ -4735,7 +4699,7 @@ sub DbRep_diffval { if ($runtime_string eq $lastruntimestring) { # Ergebnishash erzeugen if ($i == 1) { - if(abs $diff <= $dlim) { + if (abs $diff <= $dlim) { $diff_total = $diff; } @@ -4746,7 +4710,7 @@ sub DbRep_diffval { } if ($diff) { - if(abs $diff <= $dlim) { + if (abs $diff <= $dlim) { $diff_total = $diff_total + $diff; } @@ -4768,7 +4732,7 @@ sub DbRep_diffval { $rslval = $runtime_string; - if(abs $diff <= $dlim) { + if (abs $diff <= $dlim) { $diff_total = $diff; } @@ -4790,7 +4754,7 @@ sub DbRep_diffval { my ($ncps,$ncpslist); - if(%$ncp) { + if (%$ncp) { Log3 ($name, 3, "DbRep $name - time/aggregation periods containing only one dataset -> no diffValue calc was possible in period:"); for my $key (sort(keys%{$ncp})) { @@ -4810,7 +4774,7 @@ sub DbRep_diffval { my ($wrt,$irowdone); # Ergebnisse in Datenbank schreiben - if($prop =~ /writeToDB/) { + if ($prop =~ /writeToDB/) { ($err,$wrt,$irowdone) = DbRep_OutputWriteToDB ($name,$device,$reading,$rows,"diff"); return "$name|$err" if($err); @@ -4851,7 +4815,7 @@ sub DbRep_diffvalDone { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -4877,7 +4841,7 @@ sub DbRep_diffvalDone { my %ncp = split("§", $ncpslist); my $ncpstr; - if(%ncp) { + if (%ncp) { for my $ncpkey (sort(keys(%ncp))) { $ncpstr .= $ncpkey." || "; } @@ -4903,6 +4867,7 @@ sub DbRep_diffvalDone { $rds = $reading."__" if ($reading); $reading_runtime_string = $rts.$ds.$rds."DIFF__".$k[0]; } + my $rv = $k[1]; ReadingsBulkUpdateValue ($hash, $reading_runtime_string, (!$valid ? "-" : defined $rv ? sprintf "%.${ndp}f", $rv : "-")); @@ -4939,7 +4904,7 @@ sub DbRep_sumval { my $bst = [gettimeofday]; # Background-Startzeit - my ($err,$dbh,$dbmodel) = DbRep_dbConnect($name, 0); + my ($err,$dbh,$dbmodel) = DbRep_dbConnect ($name, 0); return "$name|$err" if ($err); no warnings 'uninitialized'; # only for this block because of warnings if details of readings are not set @@ -4953,7 +4918,7 @@ sub DbRep_sumval { if ($dbmodel eq "POSTGRESQL") { #vorbereiten der DB-Abfrage, DB-Modell-abhaengig $selspec = "SUM(VALUE::numeric)"; } - elsif ($dbmodel eq "MYSQL") { + elsif ($dbmodel =~ /MYSQL|MARIADB/xs) { $selspec = "SUM(VALUE)"; } elsif ($dbmodel eq "SQLITE") { @@ -4986,7 +4951,7 @@ sub DbRep_sumval { Log3 ($name, 5, "DbRep $name - SQL result: $line[0]") if($line[0]); - if(AttrVal($name, "aggregation", "") eq "hour") { + if (AttrVal($name, "aggregation", "") eq "hour") { @rsf = split(/[ :]/,$runtime_string_first); @rsn = split(/[ :]/,$runtime_string_next); $arrstr .= $runtime_string."#".$line[0]."#".$rsf[0]."_".$rsf[1]."|"; @@ -5009,7 +4974,7 @@ sub DbRep_sumval { my ($wrt,$irowdone); # Ergebnisse in Datenbank schreiben - if($prop =~ /writeToDB/) { + if ($prop =~ /writeToDB/) { ($err,$wrt,$irowdone) = DbRep_OutputWriteToDB($name,$device,$reading,$wrstr,"sum"); return "$name|$err" if($err); @@ -5043,7 +5008,7 @@ sub DbRep_sumvalDone { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -5067,7 +5032,7 @@ sub DbRep_sumvalDone { readingsBeginUpdate ($hash); my @arr = split("\\|", $arrstr); - + for my $row (@arr) { my @a = split("#", $row); my $runtime_string = $a[0]; @@ -5114,7 +5079,7 @@ sub DbRep_del { my $bst = [gettimeofday]; # Background-Startzeit - my ($err,$dbh,$dbmodel) = DbRep_dbConnect($name, 0); + my ($err,$dbh,$dbmodel) = DbRep_dbConnect ($name, 0); return "$name|$err" if ($err); my ($IsTimeSet,$IsAggrSet) = DbRep_checktimeaggr($hash); # ist Zeiteingrenzung und/oder Aggregation gesetzt ? (wenn ja -> "?" in SQL sonst undef) @@ -5168,7 +5133,7 @@ sub DbRep_del_Done { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -5227,7 +5192,7 @@ sub DbRep_insert { my $bst = [gettimeofday]; # Background-Startzeit - my ($err,$dbh,$dbmodel) = DbRep_dbConnect($name, 0); + my ($err,$dbh,$dbmodel) = DbRep_dbConnect ($name, 0); return "$name|$err" if ($err); # check ob PK verwendet wird, @usepkx ? Anzahl der Felder im PK : 0 wenn kein PK, @@ -5252,7 +5217,7 @@ sub DbRep_insert { my ($sth,$sql,$irow); # insert into $table mit/ohne primary key - if ($usepkh && $dbmodel eq 'MYSQL') { + if ($usepkh && $dbmodel =~ /MYSQL|MARIADB/xs) { $sql = "INSERT IGNORE INTO $table (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"; } elsif ($usepkh && $dbmodel eq 'SQLITE') { @@ -5315,7 +5280,7 @@ sub DbRep_insertDone { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -5364,7 +5329,7 @@ sub DbRep_currentfillup { my $bst = [gettimeofday]; # Background-Startzeit - my ($err,$dbh,$dbmodel) = DbRep_dbConnect($name, 0); + my ($err,$dbh,$dbmodel) = DbRep_dbConnect ($name, 0); return "$name|$err" if ($err); my ($usepkh,$usepkc,$pkh,$pkc) = DbRep_checkUsePK($hash,$dbloghash,$dbh); # check ob PK verwendet wird, @usepkx?Anzahl der Felder im PK:0 wenn kein PK, $pkx?Namen der Felder:none wenn kein PK @@ -5374,7 +5339,7 @@ sub DbRep_currentfillup { my $st = [gettimeofday]; # SQL-Startzeit - if ($usepkc && $dbloghash->{MODEL} eq 'MYSQL') { + if ($usepkc && $dbloghash->{MODEL} =~ /MYSQL|MARIADB/xs) { $selspec = "INSERT IGNORE INTO $table (TIMESTAMP,DEVICE,READING) SELECT timestamp,device,reading FROM history where"; $addon = "group by timestamp,device,reading"; } @@ -5387,11 +5352,11 @@ sub DbRep_currentfillup { $addon = "group by device,reading ON CONFLICT ($pkc) DO NOTHING"; } else { - if($dbloghash->{MODEL} ne 'POSTGRESQL') { # MySQL und SQLite + if ($dbloghash->{MODEL} ne 'POSTGRESQL') { # MySQL und SQLite $selspec = "INSERT INTO $table (TIMESTAMP,DEVICE,READING) SELECT timestamp,device,reading FROM history where"; $addon = "group by device,reading"; } - else { # PostgreSQL + else { # PostgreSQL $selspec = "INSERT INTO $table (DEVICE,TIMESTAMP,READING) SELECT device, (array_agg(timestamp ORDER BY reading ASC))[1], reading FROM history where"; $addon = "group by device,reading"; } @@ -5454,7 +5419,7 @@ sub DbRep_currentfillupDone { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -5486,8 +5451,8 @@ sub DbRep_currentfillupDone { Log3 ($name, 3, "DbRep $name - Table '$hash->{DATABASE}'.'current' filled up with rows: $rowstr"); - DbRep_afterproc ($hash, $hash->{LASTCMD}); # Befehl nach Procedure ausführen incl. state - DbRep_nextMultiCmd ($name); # nächstes multiCmd ausführen falls gesetzt + DbRep_afterproc ($hash, $hash->{LASTCMD}); # Befehl nach Procedure ausführen incl. state + DbRep_nextMultiCmd ($name); # nächstes multiCmd ausführen falls gesetzt return; } @@ -5538,7 +5503,7 @@ sub DbRep_changeDevRead { $old =~ s/'/''/g; # escape ' with '' $new =~ s/'/''/g; # escape ' with '' - if($dev) { + if ($dev) { $sql = "UPDATE history SET TIMESTAMP=TIMESTAMP,READING='$new' WHERE DEVICE='$dev' AND READING='$old'; "; } else { @@ -5676,10 +5641,10 @@ sub DbRep_changeVal { my $addon = $old =~ /%/ ? "AND VALUE LIKE '$old'" : "AND VALUE='$old'"; for my $row (@tsa) { # DB-Abfrage zeilenweise für jeden Array-Eintrag - my @ra = split("#", $row); - my $runtime_string = $ra[0]; - my $runtime_string_first = $ra[1]; - my $runtime_string_next = $ra[2]; + my @ra = split("#", $row); + my $runtime_string = $ra[0]; + my $runtime_string_first = $ra[1]; + my $runtime_string_next = $ra[2]; if ($IsTimeSet || $IsAggrSet) { $sql = DbRep_createSelectSql($hash, $table, $selspec, $device, $reading, $runtime_string_first, $runtime_string_next, $addon); @@ -5774,7 +5739,7 @@ sub DbRep_changeDone { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -5919,7 +5884,7 @@ sub DbRep_fetchrowsDone { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -6121,10 +6086,10 @@ sub DbRep_deldoublets { for my $nr (map { $_->[1]."_ESC_".$_->[2]."_ESC_".($_->[0] =~ s/ /_ESC_/r)."_ESC_".$_->[3]."_|_".($_->[4]-1) } @{$sth->fetchall_arrayref()}) { # Reihenfolge geändert in: DEVICE,READING,DATE,TIME,VALUE,count(*) if($prop =~ /adviceDelete/x) { - push(@warp,$i."_".$nr) if($#todel+1 < $limit); # die zu löschenden Datensätze (nur zur Anzeige) + push(@warp,$i."_".$nr) if($#todel+1 < $limit); # die zu löschenden Datensätze (nur zur Anzeige) } else { - push(@warp,$i."_".$nr); # Array der zu löschenden Datensätze + push(@warp,$i."_".$nr); # Array der zu löschenden Datensätze } my $c = (split("|",$nr))[-1]; @@ -6133,17 +6098,17 @@ sub DbRep_deldoublets { $ntodel = $ntodel + $c; - if ($prop =~ /delete/x) { # delete Datensätze + if ($prop =~ /delete/x) { # delete Datensätze my ($dev,$read,$date,$time,$val,$limit) = split(/_ESC_|_\|_/, $nr); my $dt = $date." ".$time; chomp($val); - $dev =~ s/'/''/g; # escape ' with '' - $read =~ s/'/''/g; # escape ' with '' - $val =~ s/'/''/g; # escape ' with '' - $val =~ s/\\/\\\\/g if($dbmodel eq "MYSQL"); # escape \ with \\ für MySQL + $dev =~ s/'/''/g; # escape ' with '' + $read =~ s/'/''/g; # escape ' with '' + $val =~ s/'/''/g; # escape ' with '' + $val =~ s/\\/\\\\/g if($dbmodel =~ /MYSQL|MARIADB/xs); # escape \ with \\ für MySQL $st = [gettimeofday]; - if($dbmodel =~ /MYSQL/x) { + if($dbmodel =~ /MYSQL|MARIADB/xs) { $dsql = "delete FROM $table WHERE TIMESTAMP = '$dt' AND DEVICE = '$dev' AND READING = '$read' AND VALUE = '$val' limit $limit;"; } elsif ($dbmodel eq "SQLITE") { # Forum: https://forum.fhem.de/index.php/topic,122791.0.html @@ -6455,7 +6420,7 @@ sub DbRep_deldoubl_Done { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -6675,7 +6640,7 @@ sub DbRep_expfile_Done { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -6760,7 +6725,7 @@ sub DbRep_impfile { # insert history mit/ohne primary key my $sql; - if ($usepkh && $dbloghash->{MODEL} eq 'MYSQL') { + if ($usepkh && $dbloghash->{MODEL} =~ /MYSQL|MARIADB/xs) { $sql = "INSERT IGNORE INTO $table (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"; } elsif ($usepkh && $dbloghash->{MODEL} eq 'SQLITE') { @@ -6892,7 +6857,7 @@ sub DbRep_impfile_Done { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -7397,7 +7362,7 @@ sub DbRep_sqlCmdDone { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; my $tmpsql = $data{DbRep}{$name}{sqlcache}{temp}; # SQL incl. Formatierung aus Zwischenspeicher holen @@ -7536,7 +7501,7 @@ sub DbRep_dbmeta { my @row_array; # due to incompatible changes made in MyQL 5.7.5, see http://johnemb.blogspot.de/2014/09/adding-or-removing-individual-sql-modes.html - if($dbmodel eq "MYSQL") { + if($dbmodel =~ /MYSQL|MARIADB/xs) { ($err, undef) = DbRep_dbhDo ($name, $dbh, "SET sql_mode=(SELECT REPLACE(\@\@sql_mode,'ONLY_FULL_GROUP_BY',''));"); return "$name|$err" if ($err); } @@ -7707,7 +7672,7 @@ sub DbRep_dbmeta_Done { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -7779,7 +7744,7 @@ sub DbRep_Index { $paref->{database} = $database; my $grants = _DbRep_getInitData_grants ($paref); - if($cmdidx ne "list_all" && $dbmodel =~ /MYSQL/) { # Rechte Check MYSQL + if($cmdidx ne "list_all" && $dbmodel =~ /MYSQL|MARIADB/xs) { # Rechte Check MYSQL if($grants && $grants ne "ALL PRIVILEGES") { # Rechte INDEX und ALTER benötigt my $i = index($grants, "INDEX"); my $a = index($grants, "ALTER"); @@ -7806,7 +7771,7 @@ sub DbRep_Index { my $st = [gettimeofday]; # SQL-Startzeit - if($dbmodel =~ /MYSQL/) { + if($dbmodel =~ /MYSQL|MARIADB/xs) { $sqlallidx = "SELECT TABLE_NAME,INDEX_NAME,COLUMN_NAME FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = '$database';"; $sqlava = "SHOW INDEX FROM history where Key_name='$idx';"; @@ -7965,7 +7930,7 @@ sub DbRep_IndexDone { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_INDEX}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_INDEX}); + delete $hash->{HELPER}{RUNNING_INDEX}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -8014,7 +7979,7 @@ sub DbRep_IndexAborted { Log3 ($name, 2, "DbRep $name - Database index operation aborted due to \"$cause\" "); - delete($hash->{HELPER}{RUNNING_INDEX}); + delete $hash->{HELPER}{RUNNING_INDEX}; DbRep_nextMultiCmd ($name); # nächstes multiCmd ausführen falls gesetzt @@ -8043,7 +8008,7 @@ sub DbRep_optimizeTables { my $st = [gettimeofday]; # SQL-Startzeit - if ($dbmodel =~ /MYSQL/) { + if ($dbmodel =~ /MYSQL|MARIADB/xs) { $query = "SHOW TABLE STATUS FROM `$dbname`"; # Eigenschaften der vorhandenen Tabellen ermitteln (SHOW TABLE STATUS -> Rows sind nicht exakt !!) ($err, $sth) = DbRep_prepareExecuteQuery ($name, $dbh, $query, "Searching for tables inside database $dbname...."); @@ -8272,7 +8237,7 @@ sub DbRep_OptimizeDone { my $hash = $defs{$name}; - delete($hash->{HELPER}{RUNNING_OPTIMIZE}); + delete $hash->{HELPER}{RUNNING_OPTIMIZE}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -9045,8 +9010,8 @@ sub DbRep_DumpDone { my $hash = $defs{$name}; - delete($hash->{HELPER}{RUNNING_BACKUP_CLIENT}); - delete($hash->{HELPER}{RUNNING_BCKPREST_SERVER}); + delete $hash->{HELPER}{RUNNING_BACKUP_CLIENT}; + delete $hash->{HELPER}{RUNNING_BCKPREST_SERVER}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -9171,7 +9136,7 @@ sub DbRep_RepairDone { my $hash = $defs{$name}; my $dbloghash = $defs{$hash->{HELPER}{DBLOGDEVICE}}; - delete($hash->{HELPER}{RUNNING_REPAIR}); + delete $hash->{HELPER}{RUNNING_REPAIR}; CommandSet(undef,"$dbloghash->{NAME} reopen"); # Datenbankverbindung in DbLog wieder öffenen @@ -9532,7 +9497,7 @@ sub DbRep_restoreDone { my $hash = $defs{$name}; - delete($hash->{HELPER}{RUNNING_RESTORE}); + delete $hash->{HELPER}{RUNNING_RESTORE}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -9684,7 +9649,7 @@ sub DbRep_syncStandbyDone { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -10789,7 +10754,7 @@ sub DbRep_migCollation_Done { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; if ($err) { ReadingsSingleUpdateValue ($hash, "errortext", $err, 1); @@ -10831,7 +10796,7 @@ sub DbRep_ParseAborted { Log3 ($name, 5, qq{DbRep $name - BlockingCall PID "$hash->{HELPER}{RUNNING_PID}{pid}" finished}); Log3 ($name, 1, "DbRep $name -> BlockingCall $hash->{HELPER}{RUNNING_PID}{fn} pid:$hash->{HELPER}{RUNNING_PID}{pid} $cause"); - delete($hash->{HELPER}{RUNNING_PID}); + delete $hash->{HELPER}{RUNNING_PID}; ReadingsSingleUpdateValue ($hash, 'state', 'Abort', 0); @@ -10874,7 +10839,7 @@ sub DbRep_reduceLogAborted { Log3 ($name, 2, "DbRep $name - Database reduceLog aborted: \"$cause\" "); - delete($hash->{HELPER}{RUNNING_REDUCELOG}); + delete $hash->{HELPER}{RUNNING_REDUCELOG}; DbRep_nextMultiCmd ($name); # nächstes multiCmd ausführen falls gesetzt @@ -10905,7 +10870,7 @@ sub DbRep_restoreAborted { Log3 ($name, 2, "DbRep $name - Database restore aborted: \"$cause\" "); - delete($hash->{HELPER}{RUNNING_RESTORE}); + delete $hash->{HELPER}{RUNNING_RESTORE}; DbRep_nextMultiCmd ($name); # nächstes multiCmd ausführen falls gesetzt @@ -10937,8 +10902,8 @@ sub DbRep_DumpAborted { Log3 ($name, 2, "DbRep $name - Database dump aborted: \"$cause\" "); - delete($hash->{HELPER}{RUNNING_BACKUP_CLIENT}); - delete($hash->{HELPER}{RUNNING_BCKPREST_SERVER}); + delete $hash->{HELPER}{RUNNING_BACKUP_CLIENT}; + delete $hash->{HELPER}{RUNNING_BCKPREST_SERVER}; DbRep_nextMultiCmd ($name); # nächstes multiCmd ausführen falls gesetzt @@ -10969,7 +10934,7 @@ sub DbRep_OptimizeAborted { Log3 ($name, 2, "DbRep $name - Database optimize aborted: \"$cause\" "); - delete($hash->{HELPER}{RUNNING_OPTIMIZE}); + delete $hash->{HELPER}{RUNNING_OPTIMIZE}; DbRep_nextMultiCmd ($name); # nächstes multiCmd ausführen falls gesetzt @@ -11005,7 +10970,7 @@ sub DbRep_RepairAborted { Log3 ($name, 2, "DbRep $name - Database repair aborted: \"$cause\" "); - delete($hash->{HELPER}{RUNNING_REPAIR}); + delete $hash->{HELPER}{RUNNING_REPAIR}; DbRep_nextMultiCmd ($name); # nächstes multiCmd ausführen falls gesetzt @@ -11673,7 +11638,7 @@ sub DbRep_createInsertSQLscheme { my $sql; - if ($usepkh && $dbmodel eq 'MYSQL') { + if ($usepkh && $dbmodel =~ /MYSQL|MARIADB/xs) { $sql = "INSERT IGNORE INTO $table (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"; } elsif ($usepkh && $dbmodel eq 'SQLITE') { @@ -11723,7 +11688,7 @@ sub DbRep_dbConnect { my $dbh; my $err = q{}; - if($uac) { + if ($uac) { my ($success,$admusername,$admpassword) = DbRep_getcredentials ($hash, "adminCredentials"); if ($success) { @@ -11752,8 +11717,8 @@ sub DbRep_dbConnect { }; if ($utf8) { - if ($dbmodel eq "MYSQL") { - $dbh->{mysql_enable_utf8} = 1; + if ($dbmodel =~ /MYSQL|MARIADB/xs) { + $dbh->{mysql_enable_utf8} = 1 if($dbmodel =~ /MYSQL/xs); # MariaDB kenn kein mysql_enable_utf8 ($err, my @se) = DbRep_prepareExec2Array ($name, $dbh, "SHOW VARIABLES LIKE 'collation_database'"); return $err if ($err); @@ -12307,10 +12272,10 @@ sub DbRep_autoForward { my $name = shift; my $reading = shift; my $value = shift; - + my $hash = $defs{$name}; my $av = AttrVal ($name, 'autoForward', ''); - + return if(!$av); $av =~ m/^\{(.*)\}/s; @@ -12319,7 +12284,7 @@ sub DbRep_autoForward { my @a = split ",", $av; $av = "{ "; - + my $i = 0; for my $elm (@a) { $av .= qq("$i" => "$elm",); @@ -12329,9 +12294,9 @@ sub DbRep_autoForward { $av .= " }"; my ($sr,$af); - + $af = eval $av; - + if($@ || ref($af) ne "HASH") { Log3($name, 2, "$name - Values specified in attribute \"autoForward\" are not defined as HASH ... exiting !") if(ref($af) ne "HASH"); Log3($name, 2, "$name - Error while evaluate: ".$@) if($@); @@ -12342,7 +12307,7 @@ sub DbRep_autoForward { my ($srr, $ddev, $dr) = split("=>", $af->{$key}); $ddev = DbRep_trim ($ddev) if($ddev); next if(!$ddev); - + $srr = DbRep_trim ($srr) if($srr); $dr = DbRep_trim ($dr) if($dr); @@ -12359,7 +12324,7 @@ sub DbRep_autoForward { eval { $sr = $srr }; $dr = $dr ? $dr : ($sr !~ /\.\*/xs) ? $sr : $reading; # Destination Reading = Source Reading wenn Destination Reading nicht angegeben $dr = makeReadingName ($dr); # Destination Readingname validieren / entfernt aus dem übergebenen Readingname alle ungültigen Zeichen und ersetzt diese durch einen Unterstrich "_" - + Log3($name, 4, "$name - Forward reading \"$reading\" to \"$ddev:$dr\" "); CommandSetReading(undef, "$ddev $dr $value"); @@ -12849,7 +12814,7 @@ return; sub DbRep_delread { my $hash = shift; my $shutdown = shift; - + my $name = $hash->{NAME}; my @allrds = keys%{$defs{$name}{READINGS}}; my $featurelevel = AttrVal ('global', 'featurelevel', 99.99); @@ -13002,6 +12967,8 @@ sub DbRep_nextMultiCmd { my @mattr = qw(aggregation autoForward averageCalcForm + executeBeforeProc + executeAfterProc timestamp_begin timestamp_end timeDiffToNow @@ -13016,9 +12983,9 @@ sub DbRep_nextMultiCmd { for my $da (@mattr) { CommandDeleteAttr (undef, "-silent $name $da") if(defined AttrVal($name, $da, undef)); } - + pop (@mattr); # optimizeTablesBeforeDump aus Liste entfernen -> Attr darf nicht gesetzt werden! - + my $ok = 0; my $verb = 4; my $cmd = ''; @@ -13029,12 +12996,12 @@ sub DbRep_nextMultiCmd { for my $sa (@mattr) { next if(!defined $mcmd->{$sa}); - + CommandAttr (undef, "-silent $name $sa $mcmd->{$sa}"); } $cmd = (split " ", $mcmd->{cmd})[0]; - + if (defined $dbrep_hmainf{$cmd}) { $cmd = $mcmd->{cmd}; $la = 'start'; @@ -13044,19 +13011,19 @@ sub DbRep_nextMultiCmd { $verb = 1; $la = "don't contain a valid command -> skip '$cmd'"; } - + Log3 ($name, $verb, "DbRep $name - multiCmd index >$k< $la"); last; # immer nur den ersten verbliebenen Eintrag abarbeiten } - + if ($ok) { CommandSet (undef, "$name $cmd"); } else { DbRep_nextMultiCmd ($name); # nächsten Eintrag abarbeiten falls Kommando ungültig } - + return; } @@ -14119,7 +14086,7 @@ sub DbRep_WriteToDB { } if ($DbLogType =~ /history/xi) { # insert history mit/ohne primary key - if ($usepkh && $dbloghash->{MODEL} eq 'MYSQL') { + if ($usepkh && $dbloghash->{MODEL} =~ /MYSQL|MARIADB/xs) { $sql = "INSERT IGNORE INTO history (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"; } elsif ($usepkh && $dbloghash->{MODEL} eq 'SQLITE') { @@ -14143,7 +14110,7 @@ sub DbRep_WriteToDB { }; # update history mit/ohne primary key - if ($usepkh && $dbloghash->{MODEL} eq 'MYSQL') { + if ($usepkh && $dbloghash->{MODEL} =~ /MYSQL|MARIADB/xs) { $sql = "REPLACE INTO history (TYPE, EVENT, VALUE, UNIT, TIMESTAMP, DEVICE, READING) VALUES (?,?,?,?,?,?,?)"; } elsif ($usepkh && $dbloghash->{MODEL} eq 'SQLITE') { @@ -14163,7 +14130,7 @@ sub DbRep_WriteToDB { } if ($DbLogType =~ /current/xi ) { # insert current mit/ohne primary key - if ($usepkc && $dbloghash->{MODEL} eq 'MYSQL') { + if ($usepkc && $dbloghash->{MODEL} =~ /MYSQL|MARIADB/xs) { $sql = "INSERT IGNORE INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"; } elsif ($usepkc && $dbloghash->{MODEL} eq 'SQLITE') { @@ -14187,7 +14154,7 @@ sub DbRep_WriteToDB { }; # update current mit/ohne primary key - if ($usepkc && $dbloghash->{MODEL} eq 'MYSQL') { + if ($usepkc && $dbloghash->{MODEL} =~ /MYSQL|MARIADB/xs) { $sql = "REPLACE INTO current (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES (?,?,?,?,?,?,?)"; } elsif ($usepkc && $dbloghash->{MODEL} eq 'SQLITE') { @@ -14262,7 +14229,7 @@ return ($err,$irowdone,$wrt); ################################################################ # gesetzte Hashtags (Steuerbits) löschen ################################################################ -sub DbRep_delHashtags { +sub DbRep_delHashtags { my $hash = shift; my $rdltag = delete $hash->{HELPER}{REDUCELOG}; @@ -14564,7 +14531,7 @@ sub DbReadingsVal($$$$) { return qq{"device:reading" must be specified}; } - if($dbmodel eq "MYSQL") { + if ($dbmodel =~ /MYSQL|MARIADB/xs) { $sql = "select value from ( ( select *, TIMESTAMPDIFF(SECOND, '$ts', timestamp) as diff from history where device='$dev' and reading='$reading' and timestamp >= '$ts' order by timestamp asc limit 1 @@ -14575,7 +14542,8 @@ sub DbReadingsVal($$$$) { ) ) x order by diff limit 1;"; - } elsif ($dbmodel eq "SQLITE") { + } + elsif ($dbmodel eq "SQLITE") { $sql = "select value from ( select value, (julianday(timestamp) - julianday('$ts')) * 86400.0 as diff from history where device='$dev' and reading='$reading' and timestamp >= '$ts' @@ -14585,7 +14553,8 @@ sub DbReadingsVal($$$$) { ) x order by diff limit 1;"; - } elsif ($dbmodel eq "POSTGRESQL") { + } + elsif ($dbmodel eq "POSTGRESQL") { $sql = "select value from ( select value, EXTRACT(EPOCH FROM (timestamp - '$ts')) as diff from history where device='$dev' and reading='$reading' and timestamp >= '$ts' @@ -14595,7 +14564,8 @@ sub DbReadingsVal($$$$) { ) x order by diff limit 1;"; - } else { + } + else { return qq{DbReadingsVal is not implemented for $dbmodel}; } @@ -15053,8 +15023,6 @@ return;
- Due to security reasons the attribute allowDeletion needs - to be set for execute the "delete" option.
The amount of datasets to show by commands "delDoublets adviceDelete" is initially limited and can be adjusted by limit attribute. The adjustment of "limit" has no impact to the "delDoublets delete" function, but affects @@ -15083,7 +15051,6 @@ return;
    - @@ -15116,8 +15083,6 @@ return;
    - Due to security reasons the attribute allowDeletion needs to be set to unlock the - delete-function.
    Time limits (days) can be specified as an option. In this case, any time.*-attributes set are overmodulated. Records older than <no> days and (optionally) newer than @@ -15129,7 +15094,6 @@ return;
    allowDeletion : needs to be set to execute the delete option
    aggregation : choose the aggregation period
    limit : limits ONLY the count of datasets to display
    device : include or exclude <device> from selection
    - @@ -15164,8 +15128,6 @@ return;
    - Due to security reasons the attribute allowDeletion needs to be set for - execute the "delete" option.
    The amount of datasets to show by commands "delSeqDoublets adviceDelete", "delSeqDoublets adviceRemain" is initially limited (default: 1000) and can be adjusted by attribute limit. The adjustment of "limit" has no impact to the "delSeqDoublets delete" function, but affects ONLY the @@ -15215,7 +15177,6 @@ return;
    allowDeletion : unlock the delete function
    device : include or exclude <device> from selection
    reading : include or exclude <reading> from selection
    time.* : a number of attributes to limit selection by time
    - @@ -15904,33 +15865,35 @@ return;
               {
      -          1  => { timestamp_begin => '2023-12-17 00:00:00', 
      -                  timestamp_end   => '2023-12-17 01:00:00', 
      -                  device          => 'SMA_Energymeter', 
      -                  reading         => 'Einspeisung_Wirkleistung_Zaehler', 
      -                  cmd             => 'countEntries history'
      +          1  => { executeBeforeProc => 'set LogDB reopen 900',
      +                  timestamp_begin   => '2023-12-17 00:00:00',
      +                  timestamp_end     => '2023-12-17 01:00:00',
      +                  device            => 'SMA_Energymeter',
      +                  reading           => 'Einspeisung_Wirkleistung_Zaehler',
      +                  cmd               => 'countEntries history'
                       },
      -          2  => { timestamp_begin => '2023-12-15 11:00:00', 
      -                  timestamp_end   => 'previous_day_end', 
      -                  device          => 'SMA_Energymeter', 
      -                  reading         => 'Einspeisung_Wirkleistung_Zaehler', 
      -                  cmd             => 'countEntries' 
      +          2  => { timestamp_begin   => '2023-12-15 11:00:00',
      +                  timestamp_end     => 'previous_day_end',
      +                  device            => 'SMA_Energymeter',
      +                  reading           => 'Einspeisung_Wirkleistung_Zaehler',
      +                  cmd               => 'countEntries'
                       },
      -          3  => { timeDiffToNow   => 'd:2',
      -                  readingNameMap  => 'COUNT',
      -                  autoForward     => '{ ".*COUNT.*" => "Dum.Rep.All" }',
      -                  device          => 'SMA_%,MySTP.*',
      -                  reading         => 'etotal,etoday,Ein% EXCLUDE=%Wirkleistung', 
      -                  cmd             => 'countEntries history' 
      +          3  => { timeDiffToNow     => 'd:2',
      +                  readingNameMap    => 'COUNT',
      +                  autoForward       => '{ ".*COUNT.*" => "Dum.Rep.All" }',
      +                  device            => 'SMA_%,MySTP.*',
      +                  reading           => 'etotal,etoday,Ein% EXCLUDE=%Wirkleistung',
      +                  cmd               => 'countEntries history'
                       },
      -          4  => { timeDiffToNow   => 'd:2',
      -                  readingNameMap  => 'SUM',
      -                  autoForward     => '{ ".*SUM.*" => "Dum.Rep.All" }',
      -                  device          => 'SMA_%,MySTP.*',
      -                  reading         => 'etotal,etoday,Ein% EXCLUDE=%Wirkleistung', 
      -                  cmd             => 'sumValue' 
      +          4  => { timeDiffToNow     => 'd:2',
      +                  readingNameMap    => 'SUM',
      +                  autoForward       => '{ ".*SUM.*" => "Dum.Rep.All" }',
      +                  device            => 'SMA_%,MySTP.*',
      +                  reading           => 'etotal,etoday,Ein% EXCLUDE=%Wirkleistung',
      +                  cmd               => 'sumValue'
                       },
      -          5  => { cmd             => 'sqlCmd select count(*) from current'
      +          5  => { executeAfterProc  => 'set LogDB reopen',
      +                  cmd               => 'sqlCmd select count(*) from current'
                       },
               }
             
      @@ -16224,9 +16187,6 @@ return;
    • sqlCmd

      Executes any user-specific command.
      - If this command contains a delete operation, for safety reasons the attribute - allowDeletion has to be set.
      - sqlCmd also accepts the setting of SQL session variables such as. "SET @open:=NULL, @closed:=NULL;" or the use of SQLite PRAGMA prior to the execution of the SQL statement. @@ -16298,7 +16258,7 @@ return; set <name> sqlCmd ckey:<Index>      (e.g. ckey:4)

    - + The list index "ckey:latest" executes the last statement saved in the SQL history.

    Relevant attributes are:
    @@ -16306,7 +16266,6 @@ return;
    allowDeletion : needs to be set to execute the delete option
    aggregation : choose the aggregation period
    limit : limits ONLY the count of datasets to display
    device : include or exclude <device> from selection
    @@ -16810,14 +16767,7 @@ sub dbval {
    year - the functional results are summarized per calendar year
- -
- - -
  • allowDeletion

    - - Enables the delete function of the module. -
  • +
    @@ -16846,7 +16796,7 @@ sub dbval { # readings with "AVGAM" in the name are transferred to the "Dum.Rep" device in the reading "average" # readings with "SUM" in the name are transferred to the device "Dum.Rep.Sum" in the reading "summary" - +
    @@ -16880,10 +16830,10 @@ sub dbval {
  • countEntriesDetail

    - + If set, the function countEntries creates a detailed report of counted datasets of every reading. By default only the summary of counted datasets is reported. -
  • +
    @@ -17226,33 +17176,33 @@ sub bdump {
  • readingNameMap

    - - The part between the first and last double underscore ('__') of the created reading name is replaced with the - specified string. -
  • + + The part between the first and last double underscore ('__') of the created reading name is replaced with the + specified string. +
  • role

    - + The role of the DbRep-device. Standard role is "Client".
    The role "Agent" is described in section DbRep-Agent. -
  • +
  • readingPreventFromDel

    - + Comma separated list of readings which are should prevent from deletion when a new operation starts.
    The readings can be specified as a regular expression.
    (default: state)

    - +
      Example:
      attr <name> readingPreventFromDel .*Count.*,.*Summary1.*,.*Summary2.*
    -
  • +
    @@ -18165,8 +18115,6 @@ return;
    - Aus Sicherheitsgründen muss das Attribut allowDeletion für die "delete" Option - gesetzt sein.
    Die Anzahl der anzuzeigenden Datensätze des Kommandos "delDoublets adviceDelete" ist zunächst begrenzt (default 1000) und kann durch das Attribut limit angepasst werden. @@ -18196,7 +18144,6 @@ return;
      - @@ -18226,8 +18173,6 @@ return;
      - Aus Sicherheitsgründen muss das Attribut allowDeletion - gesetzt sein um die Löschfunktion freizuschalten.
      Zeitgrenzen (Tage) können als Option angegeben werden. In diesem Fall werden eventuell gesetzte Zeitattribute übersteuert. Es werden Datensätze berücksichtigt die älter sind als <no> Tage und (optional) neuer sind als @@ -18239,7 +18184,6 @@ return;
      allowDeletion : Freischaltung der Löschfunktion
      aggregation : Auswahl einer Aggregationsperiode
      device : einschließen oder ausschließen von Datensätzen die <device> enthalten
      limit : begrenzt NUR die Anzahl der anzuzeigenden Datensätze
      - @@ -18274,8 +18218,6 @@ return;
      - Aus Sicherheitsgründen muss das Attribut allowDeletion für die "delete" Option - gesetzt sein.
      Die Anzahl der anzuzeigenden Datensätze der Kommandos "delSeqDoublets adviceDelete", "delSeqDoublets adviceRemain" ist zunächst begrenzt (default 1000) und kann durch das Attribut limit angepasst werden. Die Einstellung von "limit" hat keinen Einfluss auf die "delSeqDoublets delete" Funktion, sondern beeinflusst NUR die @@ -18326,7 +18268,6 @@ return;
      allowDeletion : Freischaltung der Löschfunktion
      device : einschließen oder ausschließen von Datensätzen die <device> enthalten
      reading : einschließen oder ausschließen von Datensätzen die <reading> enthalten
      readingNameMap : die entstehenden Ergebnisreadings werden partiell umbenannt
      - @@ -19020,6 +18961,8 @@ return;
        autoForward, averageCalcForm, + executeBeforeProc, + executeAfterProc, timestamp_begin, timestamp_end, timeDiffToNow, @@ -19036,33 +18979,35 @@ return;
                   {
          -          1  => { timestamp_begin => '2023-12-17 00:00:00', 
          -                  timestamp_end   => '2023-12-17 01:00:00', 
          -                  device          => 'SMA_Energymeter', 
          -                  reading         => 'Einspeisung_Wirkleistung_Zaehler', 
          -                  cmd             => 'countEntries history'
          +          1  => { executeBeforeProc => 'set LogDB reopen 900',
          +                  timestamp_begin   => '2023-12-17 00:00:00',
          +                  timestamp_end     => '2023-12-17 01:00:00',
          +                  device            => 'SMA_Energymeter',
          +                  reading           => 'Einspeisung_Wirkleistung_Zaehler',
          +                  cmd               => 'countEntries history'
                           },
          -          2  => { timestamp_begin => '2023-12-15 11:00:00', 
          -                  timestamp_end   => 'previous_day_end', 
          -                  device          => 'SMA_Energymeter', 
          -                  reading         => 'Einspeisung_Wirkleistung_Zaehler', 
          -                  cmd             => 'countEntries' 
          +          2  => { timestamp_begin   => '2023-12-15 11:00:00',
          +                  timestamp_end     => 'previous_day_end',
          +                  device            => 'SMA_Energymeter',
          +                  reading           => 'Einspeisung_Wirkleistung_Zaehler',
          +                  cmd               => 'countEntries'
                           },
          -          3  => { timeDiffToNow   => 'd:2',
          -                  readingNameMap  => 'COUNT',
          -                  autoForward     => '{ ".*COUNT.*" => "Dum.Rep.All" }',
          -                  device          => 'SMA_%,MySTP.*',
          -                  reading         => 'etotal,etoday,Ein% EXCLUDE=%Wirkleistung', 
          -                  cmd             => 'countEntries history' 
          +          3  => { timeDiffToNow     => 'd:2',
          +                  readingNameMap    => 'COUNT',
          +                  autoForward       => '{ ".*COUNT.*" => "Dum.Rep.All" }',
          +                  device            => 'SMA_%,MySTP.*',
          +                  reading           => 'etotal,etoday,Ein% EXCLUDE=%Wirkleistung',
          +                  cmd               => 'countEntries history'
                           },
          -          4  => { timeDiffToNow   => 'd:2',
          -                  readingNameMap  => 'SUM',
          -                  autoForward     => '{ ".*SUM.*" => "Dum.Rep.All" }',
          -                  device          => 'SMA_%,MySTP.*',
          -                  reading         => 'etotal,etoday,Ein% EXCLUDE=%Wirkleistung', 
          -                  cmd             => 'sumValue' 
          +          4  => { timeDiffToNow     => 'd:2',
          +                  readingNameMap    => 'SUM',
          +                  autoForward       => '{ ".*SUM.*" => "Dum.Rep.All" }',
          +                  device            => 'SMA_%,MySTP.*',
          +                  reading           => 'etotal,etoday,Ein% EXCLUDE=%Wirkleistung',
          +                  cmd               => 'sumValue'
                           },
          -          5  => { cmd             => 'sqlCmd select count(*) from current'
          +          5  => { executeAfterProc  => 'set LogDB reopen',
          +                  cmd               => 'sqlCmd select count(*) from current'
                           },
                   }
                 
          @@ -19364,8 +19309,6 @@ return;
        • sqlCmd

          Führt ein beliebiges benutzerspezifisches Kommando aus.
          - Enthält dieses Kommando eine Delete-Operation, muss zur Sicherheit das Attribut - allowDeletion gesetzt sein.
          sqlCmd akzeptiert ebenfalls das Setzen von SQL Session Variablen wie z.B. "SET @open:=NULL, @closed:=NULL;" oder die Verwendung von SQLite PRAGMA vor der Ausführung des SQL-Statements. @@ -19439,15 +19382,14 @@ return; set <name> sqlCmd ckey:<Index>      (e.g. ckey:4)

        - + Der Listenindex "ckey:latest" führt das zuletzt in der SQL History gespeicherte Statement aus.

        - + Relevante Attribute sind:
      allowDeletion : needs to be set to execute the delete option
      aggregation : Auswahl einer Aggregationsperiode
      device : einschließen oder ausschließen von Datensätzen die <device> enthalten
      limit : begrenzt NUR die Anzahl der anzuzeigenden Datensätze
      @@ -19955,14 +19895,7 @@ sub dbval {
      year - die Funktionsergebnisse werden pro Kalenderjahr zusammengefasst
    - -
    - - -
  • allowDeletion

    - - Schaltet die Löschfunktion des Moduls frei. -
  • +
    @@ -19992,7 +19925,7 @@ sub dbval { # Readings mit "AVGAM" im Namen werden zum Device "Dum.Rep" in das Reading "average" übertragen # Readings mit "SUM" im Namen werden zum Device "Dum.Rep.Sum" in das Reading "summary" übertragen - +
    @@ -20027,11 +19960,11 @@ sub dbval {
  • countEntriesDetail

    - + Wenn gesetzt, erstellt die Funktion "countEntries" eine detallierte Ausgabe der Datensatzzahl pro Reading und Zeitintervall. Standardmäßig wird nur die Summe aller selektierten Datensätze ausgegeben. -
  • +
    @@ -20397,33 +20330,33 @@ sub bdump {
  • readingNameMap

    - - Der Teil zwischen dem ersten und letzten doppelten Unterstrich ('__') des erstellten Readingnamens wird mit dem - angegebenen String ersetzt. -
  • + + Der Teil zwischen dem ersten und letzten doppelten Unterstrich ('__') des erstellten Readingnamens wird mit dem + angegebenen String ersetzt. +
  • readingPreventFromDel

    - + Komma separierte Liste von Readings die vor einer neuen Operation nicht gelöscht werden sollen.
    Die Readings können als regulärer Ausdruck angegeben werden.
    (default: state)

    - +
      Beispiel:
      attr <name> readingPreventFromDel .*Count.*,.*Summary1.*,.*Summary2.*
    -
  • +
  • role

    - - Die Rolle des DbRep-Device. Standard ist "Client". + + Die Rolle des DbRep-Device. Standard ist "Client". Die Rolle "Agent" ist im Abschnitt DbRep-Agent beschrieben.
    -
  • +