diff --git a/fhem/contrib/DS_Starter/93_DbRep.pm b/fhem/contrib/DS_Starter/93_DbRep.pm index 391ea8847..dcf327f94 100644 --- a/fhem/contrib/DS_Starter/93_DbRep.pm +++ b/fhem/contrib/DS_Starter/93_DbRep.pm @@ -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 ################################################################################### @@ -1199,7 +1200,7 @@ sub _DbRep_sqlFormOnline { my $name = $hash->{NAME}; my $fs = AttrVal ($name, 'sqlFormatService', 'none'); - + return $sqlcmd if($fs eq 'none'); if ($fs eq 'https://sqlformat.org') { @@ -1209,7 +1210,7 @@ sub _DbRep_sqlFormOnline { my @cmds = split ';', $sqlcmd; my $newcmd; - + for my $part (@cmds) { $part = urlEncode ($part); my ($err, $dat) = HttpUtils_BlockingGet ({ url => $fs, @@ -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 ". @@ -1327,9 +1328,9 @@ sub DbRep_Get { return qq{get "$opt" needs at least an argument} if ( @a < 3 ); my @cmd = @a; - shift @cmd; shift @cmd; - + shift @cmd; + my $sqlcmd = join ' ', @cmd; $sqlcmd =~ tr/ A-Za-z0-9!"#$§%&'()*+,-.\/:;<=>?@[\\]^_`{|}~äöüÄÖÜ߀/ /cs; $sqlcmd .= ';' if ($sqlcmd !~ m/\;$/xs); @@ -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}; @@ -6626,7 +6627,7 @@ sub DbRep_sqlCmd { if($pm !~ /PRAGMA|SET/i) { next; } - + $pm = ltrim($pm).';'; $pm =~ s/ESC_ESC_ESC/;/gx; # wiederherstellen von escapeten ";" -> umwandeln von ";;" in ";" @@ -6680,7 +6681,7 @@ sub DbRep_sqlCmd { if($sql =~ /^\s*PREPARE.*;/i) { @pms = split ';', $sql; $sql = q{}; - + for my $pm (@pms) { if($pm !~ /PREPARE/i) { $sql .= $pm.';'; @@ -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,68 +13845,61 @@ return;
  • cancelDump - stops a running database dump.

  • -
  • changeValue - changes the stored value of a reading. - If the selection is limited to certain device/reading combinations by the attributes - device or reading, they are taken into account - in the same way as set time limits (attributes time.*).
    - If these constraints are missing, the entire database is searched and the specified value is - is changed.

    + +
  • changeValue old="<old String>" new="<new String>"

    - + +
    +
    +
  • countEntries [history|current] - provides the number of table entries (default: history) between time period set by time.* -attributes if set. @@ -14978,113 +14972,113 @@ return; will are listed.


  • -
  • sqlCmd - executes any user-specific command.
    - If this command contains a delete operation, for safety reasons the attribute - allowDeletion has to be set.
    +
  • sqlCmd

    - 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. - If the session variable or PRAGMA has to be set every time before executing a SQL statement, the - attribute sqlCmdVars can be set.

    + Executes any user-specific command.
    + If this command contains a delete operation, for safety reasons the attribute + allowDeletion has to be set.
    - If the attributes device, reading, - timestamp_begin respectively - timestamp_end - set in the module are to be taken into account in the statement, - the placeholders §device§, §reading§, §timestamp_begin§ respectively - §timestamp_end§ can be used for this purpose.
    - It should be noted that the placeholders §device§ and §reading§ complex are resolved and - should be applied accordingly as in the example below. -

    + 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. + If the session variable or PRAGMA has to be set every time before executing a SQL statement, the + attribute sqlCmdVars can be set.

    - If you want update a dataset, you have to add "TIMESTAMP=TIMESTAMP" to the update-statement to avoid changing the - original timestamp.

    + If the attributes device, reading, + timestamp_begin respectively + timestamp_end + set in the module are to be taken into account in the statement, + the placeholders §device§, §reading§, §timestamp_begin§ respectively + §timestamp_end§ can be used for this purpose.
    + It should be noted that the placeholders §device§ and §reading§ complex are resolved and + should be applied accordingly as in the example below. +

    - + +
    +
    + + Note:
    + 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.
    + If you are unsure about the result of the statement, you should preventively add a limit to + the statement.

    +
  • +
  • sqlCmdHistory - If activated with the attribute sqlCmdHistoryLength, a stored SQL statement can be selected from a list and executed. @@ -15402,7 +15396,7 @@ return; If you create a little routine in 99_myUtils, for example:
    - +
     sub dbval {
       my $name = shift;
    @@ -15411,7 +15405,7 @@ sub dbval {
       return $ret;
     }
         
    - + it can be accessed with e.g. those calls:

    @@ -15982,7 +15976,7 @@ sub bdump {
  • showTableInfo

    - + Limits the result set of the command "get <name> tableinfo". SQL wildcard (%) can be used.

    @@ -16018,26 +16012,26 @@ sub bdump {

  • - +
  • sqlFormatService

    - + Automated formatting of SQL statements can be activated via an online service.
    - This option is especially useful for complex SQL statements of the setters sqlCmd, sqlCmdHistory, and sqlSpecial + This option is especially useful for complex SQL statements of the setters sqlCmd, sqlCmdHistory, and sqlSpecial to improve structuring and readability.
    - An Internet connection is required.
    + An internet connection is required and the global attribute dnsServer should be set.
    (default: none) - -
  • + +
  • sqlResultFieldSep

    - - Sets the used field separator in the result of the command "set ... sqlCmd".
    + + Sets the used field separator in the result of the command "set ... sqlCmd".
    (default: "|") - -
  • + +
    @@ -16706,74 +16700,61 @@ return;
  • cancelDump - bricht einen laufenden Datenbankdump ab.

  • + +
  • changeValue old="<alter String>" new="<neuer String>"

    -
  • changeValue - ändert den gespeicherten Wert eines Readings. - Ist die Selektion auf bestimmte Device/Reading-Kombinationen durch die Attribute - device bzw. reading beschränkt, werden sie genauso - berücksichtigt wie gesetzte Zeitgrenzen (Attribute time.*).
    - Fehlen diese Beschränkungen, wird die gesamte Datenbank durchsucht und der angegebene Wert - geändert.

    -
  • + Ändert den gespeicherten Wert eines Readings.
    + Ist die Selektion auf bestimmte Device/Reading-Kombinationen durch die Attribute + device bzw. reading beschränkt, werden sie genauso + berücksichtigt wie gesetzte Zeitgrenzen (time.* Attribute).
    + Fehlen diese Beschränkungen, wird die gesamte Datenbank durchsucht und der angegebene Wert + geändert.

    - -
    + set <name> changeValue old="%OL%" new="12 OL"
    + # enthält das Feld VALUE den Teilstring "OL", wird es in "12 OL" geändert.

    - + Zusammengefasst sind die zur Steuerung von changeValue relevanten Attribute:

    + +
    +
    +
  • countEntries [history | current] - liefert die Anzahl der Tabelleneinträge (default: history) in den gegebenen @@ -17871,111 +17852,112 @@ return; verbundenen Datenbank beginnt, aufgelistet .


  • -
  • 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. - Soll die Session Variable oder das PRAGMA vor jeder Ausführung eines SQL Statements - gesetzt werden, kann dafür das Attribut sqlCmdVars - verwendet werden.

    +
  • sqlCmd

    - Sollen die im Modul gesetzten Attribute device, reading, - timestamp_begin bzw. - timestamp_end im Statement berücksichtigt werden, können die Platzhalter - §device§, §reading§, §timestamp_begin§ bzw. - §timestamp_end§ eingesetzt werden.
    - Dabei ist zu beachten, dass die Platzhalter §device§ und §reading§ komplex aufgelöst werden - und dementsprechend wie im unten stehenden Beispiel anzuwenden sind. -

    + 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. + Soll die Session Variable oder das PRAGMA vor jeder Ausführung eines SQL Statements + gesetzt werden, kann dafür das Attribut sqlCmdVars + verwendet werden.

    - Soll ein Datensatz upgedated werden, ist dem Statement "TIMESTAMP=TIMESTAMP" hinzuzufügen um eine Änderung des - originalen Timestamps zu verhindern.

    + Sollen die im Modul gesetzten Attribute device, reading, + timestamp_begin bzw. + timestamp_end im Statement berücksichtigt werden, können die Platzhalter + §device§, §reading§, §timestamp_begin§ bzw. + §timestamp_end§ eingesetzt werden.
    + Dabei ist zu beachten, dass die Platzhalter §device§ und §reading§ komplex aufgelöst werden + und dementsprechend wie im unten stehenden Beispiel anzuwenden sind. +

    - + +
    + + Hinweis:
    + 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 + hinzufügen.

    +
  • +
  • sqlCmdHistory - Wenn mit dem Attribut sqlCmdHistoryLength aktiviert, kann ein gespeichertes SQL-Statement aus einer Liste ausgewählt und ausgeführt werden. @@ -18273,7 +18255,7 @@ return;
  • sqlCmdBlocking <SQL-Statement>

    - + Führt das angegebene SQL-Statement blockierend mit einem Standardtimeout von 10 Sekunden aus. Der Timeout kann mit dem Attribut timeout eingestellt werden.

    @@ -18300,7 +18282,7 @@ return; Erstellt man eine kleine Routine in 99_myUtils, wie z.B.:
    - +
     sub dbval {
       my $name = shift;
    @@ -18309,7 +18291,7 @@ sub dbval {
       return $ret;
     }
         
    - + kann sqlCmdBlocking vereinfacht verwendet werden mit Aufrufen wie:

    @@ -18893,7 +18875,7 @@ sub bdump {
  • showTableInfo

    - + Grenzt die Ergebnismenge des Befehls "get <name> tableinfo" ein. Es können SQL-Wildcard (%) verwendet werden.

    @@ -18929,26 +18911,26 @@ sub bdump {

  • - +
  • sqlFormatService

    - + Über einen Online-Dienst kann eine automatisierte Formatierung von SQL-Statements aktiviert werden.
    - Diese Möglichkeit ist insbesondere für komplexe SQL-Statements der Setter sqlCmd, sqlCmdHistory und sqlSpecial + Diese Möglichkeit ist insbesondere für komplexe SQL-Statements der Setter sqlCmd, sqlCmdHistory und sqlSpecial hilfreich um die Strukturierung und Lesbarkeit zu verbessern.
    - Eine Internetverbindung wird benötigt.
    + Eine Internetverbindung wird benötigt und es sollte das globale Attribut dnsServer gesetzt sein.
    (default: none) - -
  • + +
  • sqlResultFieldSep

    - - Legt den verwendeten Feldseparator im Ergebnis des Kommandos "set ... sqlCmd" fest.
    + + Legt den verwendeten Feldseparator im Ergebnis des Kommandos "set ... sqlCmd" fest.
    (default: "|") - -
  • + +
    @@ -18970,7 +18952,7 @@ sub bdump { des Datensatzes (Key) und dessen Wert zusammen.

    Die Weiterverarbeitung des Ergebnisses kann z.B. mit der folgenden userExitFn in 99_myUtils.pm erfolgen:
    - +
             sub resfromjson {
               my ($name,$reading,$value) = @_;