From a8829736ce5d327b0e72ce67762d67f566648e6c Mon Sep 17 00:00:00 2001 From: nasseeder1 <> Date: Fri, 14 Oct 2016 07:27:30 +0000 Subject: [PATCH] 93_DbRep: allow SQL-Wildcards (% _) in attr reading & attr device git-svn-id: https://svn.fhem.de/fhem/trunk@12336 2b470e98-0d58-463d-a4d8-8e2adae1ed80 --- fhem/CHANGED | 1 + fhem/FHEM/93_DbRep.pm | 413 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 339 insertions(+), 75 deletions(-) diff --git a/fhem/CHANGED b/fhem/CHANGED index dd945b9d0..593846c4e 100644 --- a/fhem/CHANGED +++ b/fhem/CHANGED @@ -1,5 +1,6 @@ # 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. + - feature: 93_DbRep: allow SQL-Wildcards (% _) in attr reading & attr device - bugfix: 49_SSCam: Experimental keys on scalar is now forbidden (Perl >= 5.23) Forum: #msg501709 - added: 37_dash_dhcp.pm: new module for amazon dash buttons diff --git a/fhem/FHEM/93_DbRep.pm b/fhem/FHEM/93_DbRep.pm index 104a58c61..5bf7a4cb7 100644 --- a/fhem/FHEM/93_DbRep.pm +++ b/fhem/FHEM/93_DbRep.pm @@ -36,6 +36,10 @@ # ########################################################################################################### # Versions History: +# +# 4.4 13.10.2016 get function prepared +# 4.3 11.10.2016 Preparation of get metadata +# 4.2 10.10.2016 allow SQL-Wildcards (% _) in attr reading & attr device # 4.1.3 09.10.2016 bugfix delEntries running on SQLite # 4.1.2 08.10.2016 old device in DEF of connected DbLog device will substitute by renamed device if # it is present in DEF @@ -157,6 +161,7 @@ sub DbRep_Initialize($) { $hash->{UndefFn} = "DbRep_Undef"; $hash->{NotifyFn} = "DbRep_Notify"; $hash->{SetFn} = "DbRep_Set"; +# $hash->{GetFn} = "DbRep_Get"; $hash->{AttrFn} = "DbRep_Attr"; $hash->{AttrList} = "disable:1,0 ". @@ -169,6 +174,8 @@ sub DbRep_Initialize($) { "aggregation:hour,day,week,month,no ". "role:Client,Agent ". "showproctime:1,0 ". + "showVariables ". + "showStatus ". "timestamp_begin ". "timestamp_end ". "timeDiffToNow ". @@ -240,7 +247,7 @@ sub DbRep_Set($@) { (($hash->{ROLE} ne "Agent")?"minValue:noArg ":""). (($hash->{ROLE} ne "Agent")?"fetchrows:noArg ":""). (($hash->{ROLE} ne "Agent")?"diffValue:noArg ":""). - (($hash->{ROLE} ne "Agent")?"insert ":""). + (($hash->{ROLE} ne "Agent")?"insert ":""). (($hash->{ROLE} ne "Agent")?"countEntries:noArg ":""); return if(IsDisabled($name)); @@ -273,9 +280,13 @@ sub DbRep_Set($@) { } elsif ($opt eq "insert" && $hash->{ROLE} ne "Agent") { if ($prop) { if (!AttrVal($hash->{NAME}, "device", "") || !AttrVal($hash->{NAME}, "reading", "") ) { - return " One or both of attributes \"device\", \"reading\" is not set. It's mandatory to set both to complete dataset for manual insert !"; + return "One or both of attributes \"device\", \"reading\" is not set. It's mandatory to set both to complete dataset for manual insert !"; } - + + # Attribute device & reading dürfen kein SQL-Wildcard % enthalten + return "One or both of attributes \"device\", \"reading\" containing SQL wildcard \"%\". Wildcards are not allowed in function manual insert !" + if(AttrVal($hash->{NAME},"device","") =~ m/%/ || AttrVal($hash->{NAME},"reading","") =~ m/%/ ); + my ($i_date, $i_time, $i_value, $i_unit) = split(",",$prop); if (!$i_date || !$i_time || !$i_value) {return "At least data for \"Date\", \"Time\" and \"Value\" is needed to insert. \"Unit\" is optional. Inputformat is 'YYYY-MM-DD,HH:MM:SS,,' ";} @@ -326,17 +337,17 @@ sub DbRep_Set($@) { } elsif ($opt eq "exportToFile" && $hash->{ROLE} ne "Agent") { if (!AttrVal($hash->{NAME}, "expimpfile", "")) { - return " The attribute \"expimpfile\" (path and filename) has to be set for export to file !"; + return "The attribute \"expimpfile\" (path and filename) has to be set for export to file !"; } sqlexec($hash,$opt); } elsif ($opt eq "importFromFile" && $hash->{ROLE} ne "Agent") { if (!AttrVal($hash->{NAME}, "expimpfile", "")) { - return " The attribute \"expimpfile\" (path and filename) has to be set for import from file !"; + return "The attribute \"expimpfile\" (path and filename) has to be set for import from file !"; } sqlexec($hash,$opt); - } + } else { return "$setlist"; @@ -345,6 +356,43 @@ $hash->{LASTCMD} = "$opt"; return undef; } +################################################################################### +# DbRep_Get +################################################################################### +sub DbRep_Get($@) { + my ($hash, @a) = @_; + return "\"get X\" needs at least an argument" if ( @a < 2 ); + my $name = $a[0]; + my $opt = $a[1]; + my $prop = $a[2]; + my $dbh = $hash->{DBH}; + my $dblogdevice = $hash->{HELPER}{DBLOGDEVICE}; + $hash->{dbloghash} = $defs{$dblogdevice}; + my $dbmodel = $hash->{dbloghash}{DBMODEL}; + my $to = AttrVal($name, "timeout", "60"); + + my $getlist = "Unknown argument $opt, choose one of ". + (($dbmodel eq "MYSQL")?"dbstatus:noArg ":""). + (($dbmodel eq "MYSQL")?"tableinfo:noArg ":""). + (($dbmodel eq "MYSQL")?"dbvars:noArg ":"") + ; + + return if(IsDisabled($name)); + + if ($opt eq "dbvars" || $opt eq "dbstatus" || $opt eq "tableinfo") { + return "The operation \"$opt\" isn't available with database type $dbmodel" if ($dbmodel ne 'MYSQL'); + delread($hash); # Readings löschen die nicht in der Ausnahmeliste (Attr readingPreventFromDel) stehen + $hash->{HELPER}{RUNNING_PID} = BlockingCall("dbmeta_DoParse", "$name|$opt", "dbmeta_ParseDone", $to, "ParseAborted", $hash); + } + else + { + return "$getlist"; + } + +$hash->{LASTCMD} = "$opt"; +return undef; +} + ################################################################################### # DbRep_Attr ################################################################################### @@ -588,8 +636,6 @@ sub DbRep_firstconnect($) { if ($init_done == 1) { - $hash->{ROLE} = AttrVal($name, "role", "Client"); # Rolle der DbRep-Instanz setzen - if ( !DbRep_Connect($hash) ) { Log3 ($name, 2, "DbRep $name - DB connect failed. Credentials of database $hash->{DATABASE} are valid and database reachable ?"); readingsSingleUpdate($hash, "state", "disconnected", 1); @@ -645,7 +691,7 @@ sub DbRep_Connect($) { } ################################################################################################################ -# Hauptroutine +# Hauptroutine "Set" ################################################################################################################ sub sqlexec($$) { @@ -657,40 +703,16 @@ sub sqlexec($$) { my $device = AttrVal($name, "device", undef); my $aggsec; - # Test-Aufbau DB-Connection - #if ( !DbRep_Connect($hash) ) { - # Log3 ($name, 2, "DbRep $name - DB connect failed. Database down ? "); - # readingsSingleUpdate($hash, "state", "disconnected", 1); - # return; - #} else { - # my $dbh = $hash->{DBH}; - # $dbh->disconnect; - #} + # Entkommentieren für Testroutine im Vordergrund + # testexit($hash); if (exists($hash->{HELPER}{RUNNING_PID}) && $hash->{ROLE} ne "Agent") { Log3 ($name, 3, "DbRep $name - WARNING - old process $hash->{HELPER}{RUNNING_PID}{pid} will be killed now to start a new BlockingCall"); BlockingKill($hash->{HELPER}{RUNNING_PID}); } - # alte Readings löschen die nicht in der Ausnahmeliste (Attr readingPreventFromDel) stehen - my @rdpfdel = split(",", $hash->{HELPER}{RDPFDEL}) if($hash->{HELPER}{RDPFDEL}); - if (@rdpfdel) { - my @allrds = keys($defs{$name}{READINGS}); - foreach my $key(@allrds) { - # Log3 ($name, 3, "DbRep $name - Reading Schlüssel: $key"); - my $dodel = 1; - foreach my $rdpfdel(@rdpfdel) { - if($key =~ /$rdpfdel/) { - $dodel = 0; - } - } - if($dodel) { - delete($defs{$name}{READINGS}{$key}); - } - } - } else { - delete $defs{$name}{READINGS}; - } + # Readings löschen die nicht in der Ausnahmeliste (Attr readingPreventFromDel) stehen + delread($hash); readingsSingleUpdate($hash, "state", "running", 1); @@ -877,6 +899,34 @@ $hash->{HELPER}{CV} = \%cv; return; } +#################################################################################################### +# delete Readings before new operation +#################################################################################################### +sub delread($) { + # Readings löschen die nicht in der Ausnahmeliste (Attr readingPreventFromDel) stehen + my ($hash) = @_; + my $name = $hash->{NAME}; + my @rdpfdel = split(",", $hash->{HELPER}{RDPFDEL}) if($hash->{HELPER}{RDPFDEL}); + if (@rdpfdel) { + my @allrds = keys($defs{$name}{READINGS}); + foreach my $key(@allrds) { + # Log3 ($name, 3, "DbRep $name - Reading Schlüssel: $key"); + my $dodel = 1; + foreach my $rdpfdel(@rdpfdel) { + if($key =~ /$rdpfdel/) { + $dodel = 0; + } + } + if($dodel) { + delete($defs{$name}{READINGS}{$key}); + } + } + } else { + delete $defs{$name}{READINGS}; + } +return undef; +} + #################################################################################################### # nichtblockierende DB-Abfrage averageValue #################################################################################################### @@ -927,14 +977,14 @@ sub averval_DoParse($) { # SQL zusammenstellen für DB-Abfrage my $sql = "SELECT AVG(VALUE) FROM `history` "; $sql .= "where " if($reading || $device || $runtime_string_first || AttrVal($hash->{NAME},"aggregation", "no") ne "no" || AttrVal($hash->{NAME},"timeDiffToNow",undef) || AttrVal($hash->{NAME}, "timeOlderThan",undef)); - $sql .= "DEVICE = '$device' " if($device); + $sql .= "DEVICE LIKE '$device' " if($device); $sql .= "AND " if($device && $reading); - $sql .= "READING = '$reading' " if($reading); + $sql .= "READING LIKE '$reading' " if($reading); $sql .= "AND " if((AttrVal($hash->{NAME}, "aggregation", "no") ne "no" || $runtime_string_first || AttrVal($hash->{NAME},"timestamp_end",undef) || AttrVal($hash->{NAME}, "timeDiffToNow",undef) || AttrVal($hash->{NAME},"timeOlderThan",undef)) && ($device || $reading)); $sql .= "TIMESTAMP >= '$runtime_string_first' AND TIMESTAMP < '$runtime_string_next' " if(AttrVal($hash->{NAME}, "aggregation", "no") ne "no" || $runtime_string_first || AttrVal($hash->{NAME},"timestamp_end",undef) || AttrVal($hash->{NAME},"timeDiffToNow",undef) || AttrVal($hash->{NAME},"timeOlderThan",undef)); $sql .= ";"; - Log3 ($name, 4, "DbRep $name - SQL to execute: $sql"); + Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); my $line; @@ -1090,14 +1140,14 @@ sub count_DoParse($) { # SQL zusammenstellen für DB-Abfrage my $sql = "SELECT COUNT(*) FROM `history` "; $sql .= "where " if($reading || $device || $runtime_string_first || AttrVal($hash->{NAME},"aggregation", "no") ne "no" || AttrVal($hash->{NAME},"timeDiffToNow",undef) || AttrVal($hash->{NAME}, "timeOlderThan",undef)); - $sql .= "DEVICE = '$device' " if($device); + $sql .= "DEVICE LIKE '$device' " if($device); $sql .= "AND " if($device && $reading); - $sql .= "READING = '$reading' " if($reading); + $sql .= "READING LIKE '$reading' " if($reading); $sql .= "AND " if((AttrVal($hash->{NAME}, "aggregation", "no") ne "no" || $runtime_string_first || AttrVal($hash->{NAME},"timestamp_end",undef) || AttrVal($hash->{NAME}, "timeDiffToNow",undef) || AttrVal($hash->{NAME},"timeOlderThan",undef)) && ($device || $reading)); $sql .= "TIMESTAMP >= '$runtime_string_first' AND TIMESTAMP < '$runtime_string_next' " if(AttrVal($hash->{NAME}, "aggregation", "no") ne "no" || $runtime_string_first || AttrVal($hash->{NAME},"timestamp_end",undef) || AttrVal($hash->{NAME},"timeDiffToNow",undef) || AttrVal($hash->{NAME},"timeOlderThan",undef)); $sql .= ";"; - Log3($name, 4, "DbRep $name - SQL to execute: $sql"); + Log3($name, 4, "DbRep $name - SQL execute: $sql"); my $line; # DB-Abfrage -> Ergebnis in $arrstr aufnehmen @@ -1253,17 +1303,17 @@ sub maxval_DoParse($) { # SQL zusammenstellen für DB-Operation my $sql = "SELECT VALUE,TIMESTAMP FROM `history` where "; - $sql .= "`DEVICE` = '$device' AND " if($device); - $sql .= "`READING` = '$reading' AND " if($reading); + $sql .= "`DEVICE` LIKE '$device' AND " if($device); + $sql .= "`READING` LIKE '$reading' AND " if($reading); $sql .= "TIMESTAMP >= ? AND TIMESTAMP < ? ORDER BY TIMESTAMP ;"; # SQL zusammenstellen für Logausgabe my $sql1 = "SELECT VALUE,TIMESTAMP FROM `history` where "; - $sql1 .= "`DEVICE` = '$device' AND " if($device); - $sql1 .= "`READING` = '$reading' AND " if($reading); + $sql1 .= "`DEVICE` LIKE '$device' AND " if($device); + $sql1 .= "`READING` LIKE '$reading' AND " if($reading); $sql1 .= "TIMESTAMP >= '$runtime_string_first' AND TIMESTAMP < '$runtime_string_next' ORDER BY TIMESTAMP;"; - Log3 ($name, 4, "DbRep $name - SQL to execute: $sql1"); + Log3 ($name, 4, "DbRep $name - SQL execute: $sql1"); $runtime_string = encode_base64($runtime_string,""); my $sth = $dbh->prepare($sql); @@ -1484,17 +1534,17 @@ sub minval_DoParse($) { # SQL zusammenstellen für DB-Operation my $sql = "SELECT VALUE,TIMESTAMP FROM `history` where "; - $sql .= "`DEVICE` = '$device' AND " if($device); - $sql .= "`READING` = '$reading' AND " if($reading); + $sql .= "`DEVICE` LIKE '$device' AND " if($device); + $sql .= "`READING` LIKE '$reading' AND " if($reading); $sql .= "TIMESTAMP >= ? AND TIMESTAMP < ? ORDER BY TIMESTAMP ;"; # SQL zusammenstellen für Logausgabe my $sql1 = "SELECT VALUE,TIMESTAMP FROM `history` where "; - $sql1 .= "`DEVICE` = '$device' AND " if($device); - $sql1 .= "`READING` = '$reading' AND " if($reading); + $sql1 .= "`DEVICE` LIKE '$device' AND " if($device); + $sql1 .= "`READING` LIKE '$reading' AND " if($reading); $sql1 .= "TIMESTAMP >= '$runtime_string_first' AND TIMESTAMP < '$runtime_string_next' ORDER BY TIMESTAMP;"; - Log3 ($name, 4, "DbRep $name - SQL to execute: $sql1"); + Log3 ($name, 4, "DbRep $name - SQL execute: $sql1"); $runtime_string = encode_base64($runtime_string,""); my $sth = $dbh->prepare($sql); @@ -1715,17 +1765,17 @@ sub diffval_DoParse($) { # SQL zusammenstellen für DB-Operation my $sql = "SELECT TIMESTAMP,VALUE FROM `history` where "; - $sql .= "`DEVICE` = '$device' AND " if($device); - $sql .= "`READING` = '$reading' AND " if($reading); + $sql .= "`DEVICE` LIKE '$device' AND " if($device); + $sql .= "`READING` LIKE '$reading' AND " if($reading); $sql .= "TIMESTAMP >= ? AND TIMESTAMP < ? ORDER BY TIMESTAMP ;"; # SQL zusammenstellen für Logausgabe my $sql1 = "SELECT TIMESTAMP,VALUE FROM `history` where "; - $sql1 .= "`DEVICE` = '$device' AND " if($device); - $sql1 .= "`READING` = '$reading' AND " if($reading); + $sql1 .= "`DEVICE` LIKE '$device' AND " if($device); + $sql1 .= "`READING` LIKE '$reading' AND " if($reading); $sql1 .= "TIMESTAMP >= '$runtime_string_first' AND TIMESTAMP < '$runtime_string_next' ORDER BY TIMESTAMP;"; - Log3 ($name, 4, "DbRep $name - SQL to execute: $sql1"); + Log3 ($name, 4, "DbRep $name - SQL execute: $sql1"); $runtime_string = encode_base64($runtime_string,""); my $sth = $dbh->prepare($sql); @@ -1962,14 +2012,14 @@ sub sumval_DoParse($) { # SQL zusammenstellen für DB-Abfrage my $sql = "SELECT SUM(VALUE) FROM `history` "; $sql .= "where " if($reading || $device || $runtime_string_first || AttrVal($hash->{NAME},"aggregation", "no") ne "no" || AttrVal($hash->{NAME},"timeDiffToNow",undef) || AttrVal($hash->{NAME}, "timeOlderThan",undef)); - $sql .= "DEVICE = '$device' " if($device); + $sql .= "DEVICE LIKE '$device' " if($device); $sql .= "AND " if($device && $reading); - $sql .= "READING = '$reading' " if($reading); + $sql .= "READING LIKE '$reading' " if($reading); $sql .= "AND " if((AttrVal($hash->{NAME}, "aggregation", "no") ne "no" || $runtime_string_first || AttrVal($hash->{NAME},"timestamp_end",undef) || AttrVal($hash->{NAME}, "timeDiffToNow",undef) || AttrVal($hash->{NAME},"timeOlderThan",undef)) && ($device || $reading)); $sql .= "TIMESTAMP >= '$runtime_string_first' AND TIMESTAMP < '$runtime_string_next' " if(AttrVal($hash->{NAME}, "aggregation", "no") ne "no" || $runtime_string_first || AttrVal($hash->{NAME},"timestamp_end",undef) || AttrVal($hash->{NAME},"timeDiffToNow",undef) || AttrVal($hash->{NAME},"timeOlderThan",undef)); $sql .= ";"; - Log3 ($name, 4, "DbRep $name - SQL to execute: $sql"); + Log3 ($name, 4, "DbRep $name - SQL execute: $sql"); my $line; # DB-Abfrage -> Ergebnis in $arrstr aufnehmen @@ -2115,7 +2165,7 @@ sub del_DoParse($) { $sql1 .= "READING = '$reading' AND " if($reading); $sql1 .= "TIMESTAMP >= '$runtime_string_first' AND TIMESTAMP < '$runtime_string_next';"; - Log3 ($name, 4, "DbRep $name - SQL to execute: $sql1"); + Log3 ($name, 4, "DbRep $name - SQL execute: $sql1"); # SQL-Startzeit my $st = [gettimeofday]; @@ -2485,17 +2535,17 @@ sub fetchrows_DoParse($) { # SQL zusammenstellen my $sql = "SELECT DEVICE,READING,TIMESTAMP,VALUE FROM history where "; - $sql .= "DEVICE = '$device' AND " if($device); - $sql .= "READING = '$reading' AND " if($reading); + $sql .= "DEVICE LIKE '$device' AND " if($device); + $sql .= "READING LIKE '$reading' AND " if($reading); $sql .= "TIMESTAMP >= ? AND TIMESTAMP < ? ORDER BY TIMESTAMP ;"; # SQL zusammenstellen für Logfileausgabe my $sql1 = "SELECT DEVICE,READING,TIMESTAMP,VALUE FROM history where "; - $sql1 .= "DEVICE = '$device' AND " if($device); - $sql1 .= "READING = '$reading' AND " if($reading); + $sql1 .= "DEVICE LIKE '$device' AND " if($device); + $sql1 .= "READING LIKE '$reading' AND " if($reading); $sql1 .= "TIMESTAMP >= '$runtime_string_first' AND TIMESTAMP < '$runtime_string_next' ORDER BY TIMESTAMP;"; - Log3 ($name, 4, "DbRep $name - SQL to execute: $sql1"); + Log3 ($name, 4, "DbRep $name - SQL execute: $sql1"); # SQL-Startzeit my $st = [gettimeofday]; @@ -2639,17 +2689,17 @@ sub expfile_DoParse($) { # SQL zusammenstellen my $sql = "SELECT TIMESTAMP,DEVICE,TYPE,EVENT,READING,VALUE,UNIT FROM history where "; - $sql .= "DEVICE = '$device' AND " if($device); - $sql .= "READING = '$reading' AND " if($reading); + $sql .= "DEVICE LIKE '$device' AND " if($device); + $sql .= "READING LIKE '$reading' AND " if($reading); $sql .= "TIMESTAMP >= ? AND TIMESTAMP < ? ORDER BY TIMESTAMP ;"; # SQL zusammenstellen für Logfileausgabe my $sql1 = "SELECT TIMESTAMP,DEVICE,TYPE,EVENT,READING,VALUE,UNIT FROM FROM history where "; - $sql1 .= "DEVICE = '$device' AND " if($device); - $sql1 .= "READING = '$reading' AND " if($reading); + $sql1 .= "DEVICE LIKE '$device' AND " if($device); + $sql1 .= "READING LIKE '$reading' AND " if($reading); $sql1 .= "TIMESTAMP >= '$runtime_string_first' AND TIMESTAMP < '$runtime_string_next' ORDER BY TIMESTAMP;"; - Log3 ($name, 4, "DbRep $name - SQL to execute: $sql1"); + Log3 ($name, 4, "DbRep $name - SQL execute: $sql1"); # SQL-Startzeit my $st = [gettimeofday]; @@ -2931,6 +2981,158 @@ sub impfile_PushDone($) { return; } +#################################################################################################### +# nichtblockierende DB-Abfrage get db Metadaten +#################################################################################################### + +sub dbmeta_DoParse($) { + my ($string) = @_; + my @a = split("\\|",$string); + my $name = $a[0]; + my $hash = $defs{$name}; + my $opt = $a[1]; + my $dbloghash = $hash->{dbloghash}; + my $dbconn = $dbloghash->{dbconn}; + my $dbuser = $dbloghash->{dbuser}; + my $dblogname = $dbloghash->{NAME}; + my $dbpassword = $attr{"sec$dblogname"}{secret}; + my $err; + + # Background-Startzeit + my $bst = [gettimeofday]; + + Log3 ($name, 4, "DbRep $name -> Start BlockingCall dbmeta_DoParse"); + + my $dbh; + eval {$dbh = DBI->connect("dbi:$dbconn", $dbuser, $dbpassword, { PrintError => 0, RaiseError => 1, AutoInactiveDestroy => 1 });}; + + if ($@) { + $err = encode_base64($@,""); + Log3 ($name, 2, "DbRep $name - $@"); + Log3 ($name, 4, "DbRep $name -> BlockingCall dbmeta_DoParse finished"); + return "$name|''|''|''|$err"; + } + + # Liste der anzuzeigenden Parameter erzeugen, sonst alle ("%"), abhängig von $opt + my $param = AttrVal($name, "showVariables", "%") if($opt eq "dbvars"); + $param = AttrVal($name, "showStatus", "%") if($opt eq "dbstatus"); + $param = "1" if($opt eq "tableinfo"); # Dummy-Eintrag für einen Schleifenabdruck + my @parlist = split(",",$param); + + # SQL-Startzeit + my $st = [gettimeofday]; + + my @row_array; + my $sth; + my $sql; + + foreach my $ple (@parlist) { + if ($opt eq "dbvars") { + $sql = "show global variables like '$ple';"; + } elsif ($opt eq "dbstatus") { + $sql = "show global status like '$ple';"; + } elsif ($opt eq "tableinfo") { + $sql = "select table_schema,round(sum(data_length+index_length)/1024/1024,4) from information_schema.tables group by table_schema;"; + } + + Log3($name, 4, "DbRep $name - SQL execute: $sql"); + + $sth = $dbh->prepare($sql); + eval {$sth->execute();}; + + if ($@) { + $err = encode_base64($@,""); + Log3 ($name, 2, "DbRep $name - $@"); + $dbh->disconnect; + Log3 ($name, 4, "DbRep $name -> BlockingCall dbmeta_DoParse finished"); + return "$name|''|''|''|$err"; + } else { + while (my @line = $sth->fetchrow_array()) { + Log3 ($name, 5, "DbRep $name - SQL result: $line[0] : $line[1]"); + push(@row_array, $line[0]." ".$line[1]); + } + } + } + + # SQL-Laufzeit ermitteln + my $rt = tv_interval($st); + + $sth->finish; + $dbh->disconnect; + + my $rowlist = join('§', @row_array); + Log3 ($name, 5, "DbRep $name -> row_array: \n@row_array"); + + # Daten müssen als Einzeiler zurückgegeben werden + $rowlist = encode_base64($rowlist,""); + + Log3 ($name, 4, "DbRep $name -> BlockingCall dbmeta_DoParse finished"); + + # Background-Laufzeit ermitteln + my $brt = tv_interval($bst); + + $rt = $rt.",".$brt; + + return "$name|$rowlist|$rt|$opt|0"; +} + +#################################################################################################### +# Auswertungsroutine der nichtblockierenden DB-Abfrage get db Metadaten +#################################################################################################### + +sub dbmeta_ParseDone($) { + my ($string) = @_; + my @a = split("\\|",$string); + my $hash = $defs{$a[0]}; + my $name = $hash->{NAME}; + my $rowlist = decode_base64($a[1]); + my $bt = $a[2]; + my $opt = $a[3]; + my ($rt,$brt) = split(",", $bt); + my $err = $a[4]?decode_base64($a[4]):undef; + + Log3 ($name, 4, "DbRep $name -> Start BlockingCall dbmeta_ParseDone"); + + if ($err) { + readingsSingleUpdate($hash, "errortext", $err, 1); + readingsSingleUpdate($hash, "state", "error", 1); + delete($hash->{HELPER}{RUNNING_PID}); + Log3 ($name, 4, "DbRep $name -> BlockingCall dbmeta_ParseDone finished"); + return; + } + + # only for this block because of warnings if details of readings are not set + no warnings 'uninitialized'; + + # Readingaufbereitung + readingsBeginUpdate($hash); + + my @row_array = split("§", $rowlist); + Log3 ($name, 5, "DbRep $name - SQL result decoded: \n@row_array") if(@row_array); + + my $pre = "VAR_" if($opt eq "dbvars"); + $pre = "STAT_" if($opt eq "dbstatus"); + $pre = "INFO_" if($opt eq "tableinfo"); + + foreach my $row (@row_array) { + my @a = split(" ", $row); + my $k = $a[0]; + $k = $a[0]."_MB" if($opt eq "tableinfo"); + my $v = $a[1]; + readingsBulkUpdate($hash, $pre.$k, $v); + } + + readingsBulkUpdate($hash, "background_processing_time", sprintf("%.4f",$brt)) if(AttrVal($name, "showproctime", undef)); + readingsBulkUpdate($hash, "sql_processing_time", sprintf("%.4f",$rt)) if(AttrVal($name, "showproctime", undef)); + readingsBulkUpdate($hash, "state", "done"); + readingsEndUpdate($hash, 1); + + delete($hash->{HELPER}{RUNNING_PID}); + Log3 ($name, 4, "DbRep $name -> BlockingCall dbmeta_ParseDone finished"); + +return; +} + #################################################################################################### # Abbruchroutine Timeout DB-Abfrage #################################################################################################### @@ -2957,9 +3159,9 @@ return; } -################################################################################################################ +#################################################################################################### # Zusammenstellung Aggregationszeiträume -################################################################################################################ +#################################################################################################### sub collaggstr($$$$) { my ($hash,$runtime,$i,$runtime_string_next) = @_; @@ -3127,6 +3329,49 @@ sub collaggstr($$$$) { return ($runtime,$runtime_string,$runtime_string_first,$runtime_string_next,$ll); } + +#################################################################################################### +# Test-Sub zu Testzwecken +#################################################################################################### +sub testexit ($) { +my ($hash) = @_; +my $name = $hash->{NAME}; + + if ( !DbRep_Connect($hash) ) { + Log3 ($name, 2, "DbRep $name - DB connect failed. Database down ? "); + readingsSingleUpdate($hash, "state", "disconnected", 1); + return; + } else { + my $dbh = $hash->{DBH}; + my $i = 1; + # $dbh->table_info( $catalog, $schema, $table) + # my $sth = $dbh->table_info('', '', ''); + # my $tables = $dbh->selectcol_arrayref($sth, {Columns => [3]}); + # my $table = join ', ', @$tables; + # Log3 ($name, 3, "DbRep $name - SQL_TABLES : $table"); + + Log3 ($name, 3, "DbRep $name - $i\--------------- COMMON SERVER INFO --------------"); + my %InfoTypes = ( SQL_DATA_SOURCE_NAME => 2 , + SQL_SERVER_NAME => 13 , + SQL_DBMS_NAME => 17 , + SQL_DBMS_VERSION => 18 , + SQL_TRANSACTION_CAPABLE => 46 , + ); + $i++; + while ((my $key, my $val) = each(%InfoTypes) ) { + my $d = $dbh->get_info( $val ); + Log3 ($name, 3, "DbRep $name - $i\_$key : $d"); + $i++; + } + + + # $sth->finish; + $dbh->disconnect; + } +return; +} + + 1; =pod @@ -3319,6 +3564,15 @@ return ($runtime,$runtime_string,$runtime_string_first,$runtime_string_next,$ll)