2
0
mirror of https://github.com/fhem/fhem-mirror.git synced 2025-03-10 09:16:53 +00:00

93_DbRep: fix SQL statement if devspec can't be resolved

git-svn-id: https://svn.fhem.de/fhem/trunk@25170 2b470e98-0d58-463d-a4d8-8e2adae1ed80
This commit is contained in:
nasseeder1 2021-11-02 20:21:33 +00:00
parent ed14c6ac14
commit 7600ba8add
2 changed files with 99 additions and 72 deletions

View File

@ -1,5 +1,7 @@
# Add changes at the top of the list. Keep it in ASCII, and 80-char wide. # 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. # Do not insert empty lines here, update check depends on it.
- bugfix: 93_DbRep: fix SQL statement if devspec can't be resolved,
Forum:#/topic,53584.msg1184155.html#msg1184155
- bugfix: 10_KNX: rework de- en-code, removed examples from cmdref->WIKI - bugfix: 10_KNX: rework de- en-code, removed examples from cmdref->WIKI
- change: 47_OBIS: Added patch from alkazaa - change: 47_OBIS: Added patch from alkazaa
- change: 58_RPI_1Wire: Support for multiple Busmasters, enhancements, fixes - change: 58_RPI_1Wire: Support for multiple Busmasters, enhancements, fixes

View File

@ -57,6 +57,8 @@ no if $] >= 5.017011, warnings => 'experimental::smartmatch';
# Version History intern # Version History intern
my %DbRep_vNotesIntern = ( my %DbRep_vNotesIntern = (
"8.43.1" => "02.11.2021 fix SQL statement if devspec can't be resolved, Forum:https://forum.fhem.de/index.php/topic,53584.msg1184155.html#msg1184155 ",
"8.43.0" => "22.09.2021 consider attr device, reading in sqlCmd, remove length limit of attr device, reading ",
"8.42.9" => "05.09.2021 minor fixes, change SQL for SQLite in deldoublets_DoParse ", "8.42.9" => "05.09.2021 minor fixes, change SQL for SQLite in deldoublets_DoParse ",
"8.42.8" => "17.07.2021 more log data verbose 5, delete whitespaces in sub getInitData ", "8.42.8" => "17.07.2021 more log data verbose 5, delete whitespaces in sub getInitData ",
"8.42.7" => "27.02.2021 fix attribute sqlCmdVars is not working in sqlCmdBlocking Forum: /topic,53584.msg1135528.html#msg1135528", "8.42.7" => "27.02.2021 fix attribute sqlCmdVars is not working in sqlCmdBlocking Forum: /topic,53584.msg1135528.html#msg1135528",
@ -1443,14 +1445,6 @@ sub DbRep_Attr {
unless ($success) {return "The credentials of a database admin user couldn't be read. ". unless ($success) {return "The credentials of a database admin user couldn't be read. ".
"Make shure you have set them with command \"set $name adminCredentials <user> <password>\" before. ";} "Make shure you have set them with command \"set $name adminCredentials <user> <password>\" before. ";}
} }
if ($aName eq "reading" || $aName eq "device") {
if ($aVal !~ m/,/ && $dbmodel && $dbmodel ne 'SQLITE') {
my $attrname = uc($aName);
my $mlen = $hash->{HELPER}{DBREPCOL}{$attrname}?$hash->{HELPER}{DBREPCOL}{$attrname}:$dbrep_col{$attrname};
return "Length of \"$aName\" is too big. Maximum length for database type $dbmodel is $mlen" if(length($aVal) > $mlen);
}
}
} }
return; return;
@ -2155,6 +2149,7 @@ sub DbRep_Main {
$prop = join(" ", @cmd); $prop = join(" ", @cmd);
} }
} }
$hash->{HELPER}{RUNNING_PID} = BlockingCall("sqlCmd_DoParse", "$name|$opt|$runtime_string_first|$runtime_string_next|$prop", "sqlCmd_ParseDone", $to, "DbRep_ParseAborted", $hash); $hash->{HELPER}{RUNNING_PID} = BlockingCall("sqlCmd_DoParse", "$name|$opt|$runtime_string_first|$runtime_string_next|$prop", "sqlCmd_ParseDone", $to, "DbRep_ParseAborted", $hash);
} }
elsif ($opt =~ /syncStandby/ ) { elsif ($opt =~ /syncStandby/ ) {
@ -6381,6 +6376,8 @@ sub sqlCmd_DoParse {
my $dbpassword = $attr{"sec$dblogname"}{secret}; my $dbpassword = $attr{"sec$dblogname"}{secret};
my $utf8 = defined($hash->{UTF8})?$hash->{UTF8}:0; my $utf8 = defined($hash->{UTF8})?$hash->{UTF8}:0;
my $srs = AttrVal($name, "sqlResultFieldSep", "|"); my $srs = AttrVal($name, "sqlResultFieldSep", "|");
my $device = AttrVal($name, "device", undef);
my $reading = AttrVal($name, "reading", undef);
my ($err,$dbh,@pms); my ($err,$dbh,@pms);
# Background-Startzeit # Background-Startzeit
@ -6504,9 +6501,11 @@ sub sqlCmd_DoParse {
} }
} }
# Allow inplace replacement of keywords for timings (use time attribute syntax) # Allow inplace replacement of keywords for timings (use time attribute syntax), device, reading
$sql =~ s/§timestamp_begin§/'$runtime_string_first'/g; $sql =~ s/§timestamp_begin§/'$runtime_string_first'/g;
$sql =~ s/§timestamp_end§/'$runtime_string_next'/g; $sql =~ s/§timestamp_end§/'$runtime_string_next'/g;
$sql =~ s/§device§/'$device'/xg if ($device);
$sql =~ s/§reading§/'$reading'/xg if ($reading);
$sql =~ s/ESC_ESC_ESC/;/gx; # wiederherstellen von escapeten ";" -> umwandeln von ";;" in ";" $sql =~ s/ESC_ESC_ESC/;/gx; # wiederherstellen von escapeten ";" -> umwandeln von ";;" in ";"
@ -9836,8 +9835,11 @@ return $sql;
# Ableiten von Device, Reading-Spezifikationen # Ableiten von Device, Reading-Spezifikationen
#################################################################################################### ####################################################################################################
sub DbRep_specsForSql { sub DbRep_specsForSql {
my ($hash,$device,$reading) = @_; my $hash = shift;
my $device = shift;
my $reading = shift;
my $name = $hash->{NAME}; my $name = $hash->{NAME};
my (@idvspcs,@edvspcs,@idvs,@edvs,@idvswc,@edvswc,@residevs,@residevswc); my (@idvspcs,@edvspcs,@idvs,@edvs,@idvswc,@edvswc,@residevs,@residevswc);
my ($nl,$nlwc) = ("",""); my ($nl,$nlwc) = ("","");
@ -9845,45 +9847,26 @@ sub DbRep_specsForSql {
my ($idevice,$edevice) = ('',''); my ($idevice,$edevice) = ('','');
my ($idevs,$idevswc,$edevs,$edevswc) = ('','','',''); my ($idevs,$idevswc,$edevs,$edevswc) = ('','','','');
my ($idanz,$edanz) = (0,0); my ($idanz,$edanz) = (0,0);
if($device =~ /EXCLUDE=/i) { if($device =~ /EXCLUDE=/i) {
($idevice,$edevice) = split(/EXCLUDE=/i,$device); ($idevice,$edevice) = split(/EXCLUDE=/i,$device);
$idevice = $idevice ? DbRep_trim($idevice) : "%"; $idevice = $idevice ? DbRep_trim($idevice) : "%";
} else { }
else {
$idevice = $device; $idevice = $device;
} }
# Devices exkludiert # Devices exkludiert
if($edevice) { if($edevice) {
@edvs = split(",",$edevice); @edvs = split(",",$edevice);
foreach my $e (@edvs) { ($edevs,$edevswc) = DbRep_resolveDevspecs($name,$edevice,\@edvs);
$e =~ s/%/\.*/g if($e !~ /^%$/); # SQL Wildcard % auflösen
@edvspcs = devspec2array($e);
@edvspcs = map {s/\.\*/%/g; $_; } @edvspcs;
if((map {$_ =~ /%/;} @edvspcs) && $edevice !~ /^%$/) { # Devices mit Wildcard (%) erfassen, die nicht aufgelöst werden konnten
$edevswc .= "," if($edevswc);
$edevswc .= join(",",@edvspcs);
} else {
$edevs .= "," if($edevs);
$edevs .= join(",",@edvspcs);
}
}
} }
$edanz = split(",",$edevs); # Anzahl der exkludierten Elemente (Lauf1) $edanz = split(",",$edevs); # Anzahl der exkludierten Elemente (Lauf1)
# Devices inkludiert # Devices inkludiert
@idvs = split(",",$idevice); @idvs = split(",",$idevice);
foreach my $d (@idvs) { ($idevs,$idevswc) = DbRep_resolveDevspecs($name,$idevice,\@idvs);
$d =~ s/%/\.*/g if($d !~ /^%$/); # SQL Wildcard % auflösen
@idvspcs = devspec2array($d);
@idvspcs = map {s/\.\*/%/g; $_; } @idvspcs;
if((map {$_ =~ /%/;} @idvspcs) && $idevice !~ /^%$/) { # Devices mit Wildcard (%) erfassen, die nicht aufgelöst werden konnten
$idevswc .= "," if($idevswc);
$idevswc .= join(",",@idvspcs);
} else {
$idevs .= "," if($idevs);
$idevs .= join(",",@idvspcs);
}
}
$idanz = split(",",$idevs); # Anzahl der inkludierten Elemente (Lauf1) $idanz = split(",",$idevs); # Anzahl der inkludierten Elemente (Lauf1)
Log3 $name, 5, "DbRep $name - Devices for operation - \n" Log3 $name, 5, "DbRep $name - Devices for operation - \n"
@ -9895,14 +9878,17 @@ sub DbRep_specsForSql {
# exkludierte Devices aus inkludierten entfernen (aufgelöste) # exkludierte Devices aus inkludierten entfernen (aufgelöste)
@idvs = split(",",$idevs); @idvs = split(",",$idevs);
@edvs = split(",",$edevs); @edvs = split(",",$edevs);
foreach my $in (@idvs) {
for my $in (@idvs) {
my $inc = 1; my $inc = 1;
foreach(@edvs) {
next if($in ne $_); for my $v (@edvs) {
next if($in ne $v);
$inc = 0; $inc = 0;
$nl .= "|" if($nl); $nl .= "|" if($nl);
$nl .= $_; # Liste der entfernten devices füllen $nl .= $v; # Liste der entfernten devices füllen
} }
push(@residevs, $in) if($inc); push(@residevs, $in) if($inc);
} }
$edevs = join(",", map {($_ !~ /$nl/)?$_:();} @edvs) if($nl); $edevs = join(",", map {($_ !~ /$nl/)?$_:();} @edvs) if($nl);
@ -9910,18 +9896,20 @@ sub DbRep_specsForSql {
# exkludierte Devices aus inkludierten entfernen (wildcard konnte nicht aufgelöst werden) # exkludierte Devices aus inkludierten entfernen (wildcard konnte nicht aufgelöst werden)
@idvswc = split(",",$idevswc); @idvswc = split(",",$idevswc);
@edvswc = split(",",$edevswc); @edvswc = split(",",$edevswc);
foreach my $inwc (@idvswc) {
for my $inwc (@idvswc) {
my $inc = 1; my $inc = 1;
foreach(@edvswc) {
next if($inwc ne $_); for my $w (@edvswc) {
next if($inwc ne $w);
$inc = 0; $inc = 0;
$nlwc .= "|" if($nlwc); $nlwc .= "|" if($nlwc);
$nlwc .= $_; # Liste der entfernten devices füllen $nlwc .= $w; # Liste der entfernten devices füllen
} }
push(@residevswc, $inwc) if($inc); push(@residevswc, $inwc) if($inc);
} }
$edevswc = join(",", map {($_ !~ /$nlwc/)?$_:();} @edvswc) if($nlwc); $edevswc = join(",", map {($_ !~ /$nlwc/)?$_:();} @edvswc) if($nlwc);
# Log3($name, 1, "DbRep $name - nlwc: $nlwc, mwc: @mwc");
# Ergebnis zusammenfassen # Ergebnis zusammenfassen
$idevs = join(",",@residevs); $idevs = join(",",@residevs);
@ -9930,18 +9918,19 @@ sub DbRep_specsForSql {
$idevswc =~ s/'/''/g; # escape ' with '' $idevswc =~ s/'/''/g; # escape ' with ''
$idanz = split(",",$idevs); # Anzahl der inkludierten Elemente (Lauf2) $idanz = split(",",$idevs); # Anzahl der inkludierten Elemente (Lauf2)
if($idanz > 1) { if($idanz > 1) {
$idevs =~ s/,/','/g; $idevs =~ s/,/','/g;
$idevs = "'".$idevs."'"; $idevs = "'".$idevs."'";
} }
$edanz = split(",",$edevs); # Anzahl der exkludierten Elemente (Lauf2) $edanz = split(",",$edevs); # Anzahl der exkludierten Elemente (Lauf2)
if($edanz > 1) { if($edanz > 1) {
$edevs =~ s/,/','/g; $edevs =~ s/,/','/g;
$edevs = "'".$edevs."'"; $edevs = "'".$edevs."'";
} }
##### inkludierte / excludierte Readings und deren Anzahl ermitteln ##### ##### inkludierte / excludierte Readings und deren Anzahl ermitteln #####
my ($ireading,$ereading) = ('',''); my ($ireading,$ereading) = ('','');
my ($iranz,$eranz) = (0,0); my ($iranz,$eranz) = (0,0);
@ -9953,44 +9942,47 @@ sub DbRep_specsForSql {
if($reading =~ /EXCLUDE=/i) { if($reading =~ /EXCLUDE=/i) {
($ireading,$ereading) = split(/EXCLUDE=/i,$reading); ($ireading,$ereading) = split(/EXCLUDE=/i,$reading);
$ireading = $ireading ? DbRep_trim($ireading) : "%"; $ireading = $ireading ? DbRep_trim($ireading) : "%";
} else { }
else {
$ireading = $reading; $ireading = $reading;
} }
if($ereading) { if($ereading) {
@erds = split(",",$ereading); @erds = split(",",$ereading);
foreach my $e (@erds) {
for my $e (@erds) {
if($e =~ /%/ && $e !~ /^%$/) { # Readings mit Wildcard (%) erfassen if($e =~ /%/ && $e !~ /^%$/) { # Readings mit Wildcard (%) erfassen
$erdswc .= "," if($erdswc); $erdswc .= "," if($erdswc);
$erdswc .= $e; $erdswc .= $e;
} else { }
else {
$erdgs .= "," if($erdgs); $erdgs .= "," if($erdgs);
$erdgs .= $e; $erdgs .= $e;
} }
} }
} }
# Readings inkludiert @irds = split(",",$ireading); # Readings inkludiert
@irds = split(",",$ireading);
foreach my $i (@irds) { for my $i (@irds) {
if($i =~ /%/ && $i !~ /^%$/) { # Readings mit Wildcard (%) erfassen if($i =~ /%/ && $i !~ /^%$/) { # Readings mit Wildcard (%) erfassen
$irdswc .= "," if($irdswc); $irdswc .= "," if($irdswc);
$irdswc .= $i; $irdswc .= $i;
} else { }
else {
$irdgs .= "," if($irdgs); $irdgs .= "," if($irdgs);
$irdgs .= $i; $irdgs .= $i;
} }
} }
$iranz = split(",",$irdgs); $iranz = split(",",$irdgs);
if($iranz > 1) { if($iranz > 1) {
$irdgs =~ s/,/','/g; $irdgs =~ s/,/','/g;
$irdgs = "'".$irdgs."'"; $irdgs = "'".$irdgs."'";
} }
if($ereading) { if($ereading) { # Readings exkludiert
# Readings exkludiert
$eranz = split(",",$erdgs); $eranz = split(",",$erdgs);
if($eranz > 1) { if($eranz > 1) {
$erdgs =~ s/,/','/g; $erdgs =~ s/,/','/g;
@ -10007,6 +9999,35 @@ sub DbRep_specsForSql {
return ($idevs,$idevswc,$idanz,$irdgs,$iranz,$irdswc,$edevs,$edevswc,$edanz,$erdgs,$eranz,$erdswc); return ($idevs,$idevswc,$idanz,$irdgs,$iranz,$irdswc,$edevs,$edevswc,$edanz,$erdgs,$eranz,$erdswc);
} }
####################################################################################################
# devspecs für SQL auflösen
####################################################################################################
sub DbRep_resolveDevspecs {
my $name = shift;
my $dlist = shift; # Komma getrennte Deviceliste
my $devref = shift; # Referenz der Deviceliste
my ($devs,$devswc) = ('','');
for my $d (@$devref) {
$d =~ s/%/\.*/g if($d !~ /^%$/); # SQL Wildcard % auflösen
my @devspcs = devspec2array($d);
@devspcs = qw(^^) if(!@devspcs); # ein nie existierendes Device (^^) setzen wenn Liste leer
@devspcs = map {s/\.\*/%/g; $_; } @devspcs;
if((map {$_ =~ /%/;} @devspcs) && $dlist !~ /^%$/) { # Devices mit Wildcard (%) erfassen, die nicht aufgelöst werden konnten
$devswc .= "," if($devswc);
$devswc .= join(",",@devspcs);
}
else {
$devs .= "," if($devs);
$devs .= join(",",@devspcs);
}
}
return ($devs,$devswc);
}
#################################################################################################### ####################################################################################################
# Whitespace am Anfang / Ende eines Strings entfernen # Whitespace am Anfang / Ende eines Strings entfernen
#################################################################################################### ####################################################################################################
@ -13465,9 +13486,11 @@ return;
@closed:=NULL;" or the usage of SQLite PRAGMA before execution the SQL-Statement. @closed:=NULL;" or the usage of SQLite PRAGMA before execution the SQL-Statement.
If the session variable or PRAGMA has to be set every time before executing a SQL statement, the If the session variable or PRAGMA has to be set every time before executing a SQL statement, the
attribute <a href="#sqlCmdVars">'sqlCmdVars'</a> can be set. <br> attribute <a href="#sqlCmdVars">'sqlCmdVars'</a> can be set. <br>
If the attribute <a href="#timestamp_begin">'timestamp_begin'</a> respectively 'timestamp_end' If the attributes <a href="#device">device</a>, <a href="#reading">reading</a>,
is assumed in the statement, it is possible to use placeholder <b>§timestamp_begin§</b> respectively <a href="#timestamp_begin">'timestamp_begin'</a> respectively 'timestamp_end'
<b>§timestamp_end§</b> on suitable place. <br><br> set in the module are to be taken into account in the statement,
the placeholders <b>§device§</b>, <b>§reading§</b>, <b>§timestamp_begin§</b> respectively
<b>§timestamp_end§</b> can be used for this purpose. <br><br>
If you want update a dataset, you have to add "TIMESTAMP=TIMESTAMP" to the update-statement to avoid changing the If you want update a dataset, you have to add "TIMESTAMP=TIMESTAMP" to the update-statement to avoid changing the
original timestamp. <br><br> original timestamp. <br><br>
@ -16110,9 +16133,11 @@ sub bdump {
Soll die Session Variable oder das PRAGMA vor jeder Ausführung eines SQL Statements Soll die Session Variable oder das PRAGMA vor jeder Ausführung eines SQL Statements
gesetzt werden, kann dafür das Attribut <a href="#sqlCmdVars">sqlCmdVars</a> gesetzt werden, kann dafür das Attribut <a href="#sqlCmdVars">sqlCmdVars</a>
verwendet werden. <br> verwendet werden. <br>
Sollen die im Modul gesetzten Attribute <a href="#timestamp_begin">timestamp_begin</a> bzw. Sollen die im Modul gesetzten Attribute <a href="#device">device</a>, <a href="#reading">reading</a>,
<a href="#timestamp_begin">timestamp_begin</a> bzw.
<a href="#timestamp_end">timestamp_end</a> im Statement berücksichtigt werden, können die Platzhalter <a href="#timestamp_end">timestamp_end</a> im Statement berücksichtigt werden, können die Platzhalter
<b>§timestamp_begin§</b> bzw. <b>§timestamp_end§</b> dafür verwendet werden. <br><br> <b>§device§</b>, <b>§reading§</b>, <b>§timestamp_begin§</b> bzw.
<b>§timestamp_end§</b> dafür verwendet werden. <br><br>
Soll ein Datensatz upgedated werden, ist dem Statement "TIMESTAMP=TIMESTAMP" hinzuzufügen um eine Änderung des Soll ein Datensatz upgedated werden, ist dem Statement "TIMESTAMP=TIMESTAMP" hinzuzufügen um eine Änderung des
originalen Timestamps zu verhindern. <br><br> originalen Timestamps zu verhindern. <br><br>