diff --git a/fhem/contrib/DS_Starter/93_DbLog.pm b/fhem/contrib/DS_Starter/93_DbLog.pm
index 0d162816a..6f84cb307 100644
--- a/fhem/contrib/DS_Starter/93_DbLog.pm
+++ b/fhem/contrib/DS_Starter/93_DbLog.pm
@@ -1,5 +1,5 @@
############################################################################################################################################
-# $Id: 93_DbLog.pm 26923 2023-01-10 10:28:14Z DS_Starter $
+# $Id: 93_DbLog.pm 27082 2023-01-18 22:08:25Z DS_Starter $
#
# 93_DbLog.pm
# written by Dr. Boris Neubert 2007-12-30
@@ -8,7 +8,7 @@
# modified and maintained by Tobias Faust since 2012-06-26 until 2016
# e-mail: tobias dot faust at online dot de
#
-# redesigned and maintained 2016-2023 by DS_Starter with credits by: JoeAllb, DeeSpe
+# redesigned and maintained 2016-2023 by DS_Starter
# e-mail: heiko dot maaz at t-online dot de
#
# reduceLog() created by Claudiu Schuster (rapster) adapted by DS_Starter
@@ -38,14 +38,17 @@ no if $] >= 5.017011, warnings => 'experimental::smartmatch';
# Version History intern by DS_Starter:
my %DbLog_vNotesIntern = (
- "5.5.12" => "10.01.2023 changed routine _DbLog_SBP_onRun_LogBulk ",
+ "5.6.2" => "22.01.2023 check Syntax of DbLogValueFn attribute with Log output ",
+ "5.6.1" => "16.01.2023 rewrite sub _DbLog_SBP_connectDB, rewrite sub DbLog_ExecSQL, _DbLog_SBP_onRun_deleteOldDays ",
+ "5.6.0" => "11.01.2023 rename attribute 'bulkInsert' to 'insertMode' ",
+ "5.5.12" => "10.01.2023 changed routine _DbLog_SBP_onRun_LogSequential, edit CommandRef ",
"5.5.11" => "09.01.2023 more code rework / structured subroutines ",
- "5.5.10" => "07.01.2023 more code rework (_DbLog_SBP_checkDiscDelpars) and others, use dbh quote in _DbLog_SBP_onRun_LogBulk ".
+ "5.5.10" => "07.01.2023 more code rework (_DbLog_SBP_checkDiscDelpars) and others, use dbh quote in _DbLog_SBP_onRun_LogSequential ".
"configCheck changed to use only one db connect + measuring the connection time, universal DBHU ",
"5.5.9" => "28.12.2022 optimize \$hash->{HELPER}{TH}, \$hash->{HELPER}{TC}, mode in Define ".
"Forum: https://forum.fhem.de/index.php/topic,130588.msg1254073.html#msg1254073 ",
"5.5.8" => "27.12.2022 two-line output of long state messages, define LONGRUN_PID threshold ",
- "5.5.7" => "20.12.2022 cutted _DbLog_SBP_onRun_Log into _DbLog_SBP_onRun_LogArray and _DbLog_SBP_onRun_LogBulk ".
+ "5.5.7" => "20.12.2022 cutted _DbLog_SBP_onRun_Log into _DbLog_SBP_onRun_LogArray and _DbLog_SBP_onRun_LogSequential ".
"__DbLog_SBP_onRun_LogCurrent, __DbLog_SBP_fieldArrays, some bugfixes, add drivers to configCheck, edit comref ",
"5.5.6" => "12.12.2022 Serialize with Storable instead of JSON, more code rework ",
"5.5.5" => "11.12.2022 Array Log -> may be better error processing ",
@@ -147,7 +150,6 @@ sub DbLog_Initialize {
$hash->{ShutdownFn} = "DbLog_Shutdown";
$hash->{AttrList} = "addStateEvent:0,1 ".
"asyncMode:1,0 ".
- "bulkInsert:1,0 ".
"commitMode:basic_ta:on,basic_ta:off,ac:on_ta:on,ac:on_ta:off,ac:off_ta:on ".
"cacheEvents:2,1,0 ".
"cacheLimit ".
@@ -158,14 +160,13 @@ sub DbLog_Initialize {
"convertTimezone:UTC,none ".
"DbLogSelectionMode:Exclude,Include,Exclude/Include ".
"DbLogType:Current,History,Current/History,SampleFill/History ".
- "SQLiteJournalMode:WAL,off ".
- "SQLiteCacheSize ".
"dbSchema ".
"defaultMinInterval:textField-long ".
"disable:1,0 ".
"excludeDevs ".
"expimpdir ".
"exportCacheAppend:1,0 ".
+ "insertMode:1,0 ".
"noSupportPK:1,0 ".
"noNotifyDev:1,0 ".
"showproctime:1,0 ".
@@ -174,6 +175,8 @@ sub DbLog_Initialize {
"syncEvents:1,0 ".
"syncInterval ".
"showNotifyTime:1,0 ".
+ "SQLiteJournalMode:WAL,off ".
+ "SQLiteCacheSize ".
"traceFlag:SQL,CON,ENC,DBD,TXN,ALL ".
"traceLevel:0,1,2,3,4,5,6,7 ".
"timeout ".
@@ -190,6 +193,9 @@ sub DbLog_Initialize {
$hash->{SVG_sampleDataFn} = "DbLog_sampleDataFn";
$hash->{prioSave} = 1; # Prio-Flag für save Reihenfolge, Forum: https://forum.fhem.de/index.php/topic,130588.msg1249277.html#msg1249277
+ $hash->{AttrRenameMap} = { "bulkInsert" => "insertMode",
+ };
+
eval { FHEM::Meta::InitMod( __FILE__, $hash ) }; # für Meta.pm (https://forum.fhem.de/index.php/topic,97589.0.html)
return;
@@ -306,7 +312,7 @@ return;
sub DbLog_Undef {
my $hash = shift;
my $name = shift;
-
+
my $dbh = $hash->{DBHU};
__DbLog_SBP_disconnectOnly ($name, $dbh);
delete $hash->{DBHU};
@@ -404,22 +410,8 @@ sub DbLog_Attr {
return qq{"$aName" is not valid for database model "$hash->{MODEL}"};
}
- if( $aName eq 'valueFn' ) {
- my %specials= (
- "%TIMESTAMP" => $name,
- "%LASTTIMESTAMP" => $name,
- "%DEVICE" => $name,
- "%DEVICETYPE" => $name,
- "%EVENT" => $name,
- "%READING" => $name,
- "%VALUE" => $name,
- "%LASTVALUE" => $name,
- "%UNIT" => $name,
- "%IGNORE" => $name,
- "%CN" => $name
- );
-
- my $err = perlSyntaxCheck($aVal, %specials);
+ if($aName =~ /[Vv]alueFn/) {
+ my ($err, $func) = DbLog_checkSyntaxValueFn ($name, $aVal);
return $err if($err);
}
@@ -466,7 +458,7 @@ sub DbLog_Attr {
my $dbh = $hash->{DBHU};
__DbLog_SBP_disconnectOnly ($name, $dbh);
delete $hash->{DBHU};
-
+
if ($init_done == 1) {
DbLog_SBP_sendDbDisconnect ($hash, 1); # DB Verbindung und Verbindungsdaten im SubProzess löschen
@@ -752,11 +744,11 @@ sub _DbLog_setreopen { ## no critic "not used"
my $prop = $paref->{prop};
my $ret;
-
+
my $dbh = $hash->{DBHU};
__DbLog_SBP_disconnectOnly ($name, $dbh); # lokal
delete $hash->{DBHU};
-
+
DbLog_SBP_sendDbDisconnect ($hash); # an SBP
if (!$prop) {
@@ -805,11 +797,11 @@ sub _DbLog_setrereadcfg { ## no critic "not used"
my $ret = DbLog_readCfg($hash);
return $ret if $ret;
-
+
my $dbh = $hash->{DBHU};
__DbLog_SBP_disconnectOnly ($name, $dbh); # lokal
delete $hash->{DBHU};
-
+
DbLog_SBP_sendDbDisconnect ($hash, 1); # DB Verbindung und Verbindungsdaten im SubProzess löschen
my $rst = DbLog_SBP_sendConnectionData ($hash); # neue Verbindungsdaten an SubProzess senden
@@ -1224,33 +1216,25 @@ sub DbLog_Log {
my $memcount = 0;
my $re = $hash->{REGEXP};
- my $ts_0 = TimeNow(); # timestamp in SQL format YYYY-MM-DD hh:mm:ss
- my $now = gettimeofday(); # get timestamp in seconds since epoch
+ my $ts_0 = TimeNow(); # timestamp in SQL format YYYY-MM-DD hh:mm:ss
+ my $now = gettimeofday(); # get timestamp in seconds since epoch
my $DbLogExclude = AttrVal ($dev_name, 'DbLogExclude', undef);
my $DbLogInclude = AttrVal ($dev_name, 'DbLogInclude', undef);
my $DbLogValueFn = AttrVal ($dev_name, 'DbLogValueFn', '');
my $DbLogSelectionMode = AttrVal ($name, 'DbLogSelectionMode','Exclude');
my $value_fn = AttrVal ($name, 'valueFn', '');
- my $ctz = AttrVal ($name, 'convertTimezone', 'none'); # convert time zone
+ my $ctz = AttrVal ($name, 'convertTimezone', 'none'); # convert time zone
my $async = AttrVal ($name, 'asyncMode', 0);
my $clim = AttrVal ($name, 'cacheLimit', $dblog_cachedef);
my $ce = AttrVal ($name, 'cacheEvents', 0);
- if( $DbLogValueFn =~ m/^\s*(\{.*\})\s*$/s ) { # Funktion aus Device spezifischer DbLogValueFn validieren
- $DbLogValueFn = $1;
- }
- else {
- $DbLogValueFn = '';
- }
+ ($err, $DbLogValueFn) = DbLog_checkSyntaxValueFn ($name, $DbLogValueFn, $dev_name); # Funktion aus Device spezifischer DbLogValueFn validieren
+ $DbLogValueFn = '' if($err);
+
+ ($err, $value_fn) = DbLog_checkSyntaxValueFn ($name, $value_fn); # Funktion aus Attr valueFn validieren
+ $value_fn = '' if($err);
- if( $value_fn =~ m/^\s*(\{.*\})\s*$/s ) { # Funktion aus Attr valueFn validieren
- $value_fn = $1;
- }
- else {
- $value_fn = '';
- }
-
- eval { # one Transaction
+ eval { # one Transaction
for (my $i = 0; $i < $max; $i++) {
my $next = 0;
my $event = $events->[$i];
@@ -2114,13 +2098,13 @@ sub DbLog_SBP_onRun {
$attr{$name}{verbose} = $verbose if(defined $verbose); # verbose Level übergeben
my $bst = [gettimeofday]; # Background-Startzeit
# prüfen ob Datenbankverbindung beendet werden soll
- $doNext = _DbLog_SBP_checkDiscDelpars ({ subprocess => $subprocess,
+ $doNext = _DbLog_SBP_checkDiscDelpars ({ subprocess => $subprocess,
name => $name,
memc => $memc,
store => $store
}
);
-
+
if ($doNext) {
next;
}
@@ -2154,7 +2138,7 @@ sub DbLog_SBP_onRun {
};
__DbLog_SBP_sendToParent ($subprocess, $ret);
-
+
next;
}
@@ -2180,7 +2164,7 @@ sub DbLog_SBP_onRun {
};
__DbLog_SBP_sendToParent ($subprocess, $ret);
-
+
next;
}
@@ -2189,7 +2173,7 @@ sub DbLog_SBP_onRun {
## Verbindungsaufbau Datenbank
################################
- $doNext = _DbLog_SBP_manageDBconnect ({ subprocess => $subprocess,
+ $doNext = _DbLog_SBP_manageDBconnect ({ subprocess => $subprocess,
name => $name,
memc => $memc,
store => $store,
@@ -2197,7 +2181,7 @@ sub DbLog_SBP_onRun {
useac => $useac
}
);
-
+
if ($doNext) {
_DbLog_SBP_doWait (1000000);
next;
@@ -2206,18 +2190,18 @@ sub DbLog_SBP_onRun {
## Event Logging
#########################################################
if ($operation =~ /log_/xs) {
- my $bi = $memc->{bi}; # Bulk-Insert 0|1
+ my $im = $memc->{im}; # Insert-Mode 0|1
- if ($bi) {
- _DbLog_SBP_onRun_LogBulk ( { subprocess => $subprocess,
- name => $name,
- memc => $memc,
- store => $store,
- logstore => $logstore,
- useta => $useta,
- bst => $bst
- }
- );
+ if ($im) {
+ _DbLog_SBP_onRun_LogSequential ( { subprocess => $subprocess,
+ name => $name,
+ memc => $memc,
+ store => $store,
+ logstore => $logstore,
+ useta => $useta,
+ bst => $bst
+ }
+ );
}
else {
_DbLog_SBP_onRun_LogArray ( { subprocess => $subprocess,
@@ -2351,7 +2335,7 @@ return $doNext;
#################################################################
# Wartezeit blockierend
-# reduziert CPU Last im "Leerlauf"
+# reduziert CPU Last im "Leerlauf"
#################################################################
sub _DbLog_SBP_doWait {
my $wtus = shift // 300000; # Mikrosekunden
@@ -2373,12 +2357,12 @@ sub _DbLog_SBP_manageDBconnect {
my $store = $paref->{store}; # Datenspeicher
my $useac = $paref->{useac};
my $operation = $paref->{operation};
-
+
my $isNew = 0; # wurde Database Handle neu erstellt ?
my $doNext = 0;
-
+
my ($err, $dbh, $ret);
-
+
my $params = { name => $name,
dbconn => $store->{dbparams}{dbconn},
dbname => $store->{dbparams}{dbname},
@@ -2394,10 +2378,10 @@ sub _DbLog_SBP_manageDBconnect {
if (!defined $store->{dbh}) {
($err, $dbh) = _DbLog_SBP_connectDB ($params);
-
+
if ($err) {
Log3 ($name, 4, "DbLog $name - Database Connection impossible. Transferred data is returned to the cache.");
-
+
$ret = {
name => $name,
msg => $err,
@@ -2405,12 +2389,12 @@ sub _DbLog_SBP_manageDBconnect {
oper => $operation,
rowlback => $memc->{cdata} # Rückgabe aller übergebenen Log-Daten
};
-
+
$doNext = 1;
-
- $store->{dbparams}{cofaults}++;
+
+ $store->{dbparams}{cofaults}++;
__DbLog_SBP_sendToParent ($subprocess, $ret);
-
+
return $doNext;
}
@@ -2429,14 +2413,14 @@ sub _DbLog_SBP_manageDBconnect {
if (!$bool) { # DB Session dead
delete $store->{dbh};
-
+
Log3 ($name, 4, "DbLog $name - Database Connection dead. Try reconnect ...");
-
+
($err, $dbh) = _DbLog_SBP_connectDB ($params);
if ($err) {
Log3 ($name, 4, "DbLog $name - Database Reconnect impossible. Transferred data is returned to the cache.");
-
+
$ret = {
name => $name,
msg => $err,
@@ -2446,13 +2430,13 @@ sub _DbLog_SBP_manageDBconnect {
};
$doNext = 1;
-
- $store->{dbparams}{cofaults}++;
+
+ $store->{dbparams}{cofaults}++;
__DbLog_SBP_sendToParent ($subprocess, $ret);
-
+
return $doNext;
}
-
+
$store->{dbparams}{cofaults} = 0;
$store->{dbh} = $dbh;
}
@@ -2469,6 +2453,10 @@ return $doNext;
# PrintError - handle attribute tells DBI to call the Perl warn( ) function
# (which typically results in errors being printed to the screen
# when encountered)
+#
+# For maximum reliability and for robustness against database corruption,
+# SQLite should always be run with its default synchronous setting of FULL.
+# https://sqlite.org/howtocorrupt.html
###################################################################################
sub _DbLog_SBP_connectDB {
my $paref = shift;
@@ -2516,15 +2504,15 @@ sub _DbLog_SBP_connectDB {
1;
}
or do { $err = $@;
-
+
if ($cofaults <= 10) {
Log3 ($name, 2, "DbLog $name - ERROR: $err");
}
-
+
if ($cofaults == 10) {
Log3 ($name, 2, "DbLog $name - There seems to be a permanent connection error to the database. Further error messages are suppressed.");
}
-
+
return $err;
};
@@ -2533,70 +2521,125 @@ sub _DbLog_SBP_connectDB {
if($utf8) {
if($model eq "MYSQL") {
$dbh->{mysql_enable_utf8} = 1;
- $dbh->do('set names "UTF8"');
+ ($err, undef) = _DbLog_SBP_dbhDo ($name, $dbh, 'set names "UTF8"');
+ return ($err, q{}) if($err);
}
if($model eq "SQLITE") {
- $dbh->do('PRAGMA encoding="UTF-8"');
+ ($err, undef) = _DbLog_SBP_dbhDo ($name, $dbh, 'PRAGMA encoding="UTF-8"');
+ return ($err, q{}) if($err);
}
}
- if ($model eq 'SQLITE') {
- $dbh->do("PRAGMA temp_store=MEMORY");
- $dbh->do("PRAGMA synchronous=FULL"); # For maximum reliability and for robustness against database corruption,
- # SQLite should always be run with its default synchronous setting of FULL.
- # https://sqlite.org/howtocorrupt.html
-
- $dbh->do("PRAGMA journal_mode=$sltjm");
- $dbh->do("PRAGMA cache_size=$sltcs");
+ if ($model eq 'SQLITE') {
+ my @dos = ("PRAGMA temp_store=MEMORY",
+ "PRAGMA synchronous=FULL",
+ "PRAGMA journal_mode=$sltjm",
+ "PRAGMA cache_size=$sltcs"
+ );
+
+ for my $do (@dos) {
+ ($err, undef) = _DbLog_SBP_dbhDo ($name, $dbh, $do);
+ return ($err, q{}) if($err);
+ }
}
return ($err, $dbh);
}
+####################################################################################################
+# einfaches Sdbh->do, return ERROR-String wenn Fehler bzw. die Anzahl der betroffenen Zeilen
+####################################################################################################
+sub _DbLog_SBP_dbhDo {
+ my $name = shift;
+ my $dbh = shift;
+ my $sql = shift;
+ my $info = shift // "simple do statement: $sql";
+
+ my $err = q{};
+ my $rv = q{};
+
+ Log3 ($name, 4, "DbLog $name - $info");
+
+ eval{ $rv = $dbh->do($sql);
+ 1;
+ }
+ or do { $err = $@;
+ Log3 ($name, 2, "DbLog $name - ERROR - $@");
+ };
+
+return ($err, $rv);
+}
+
############################################################################
# Datenbank Ping
-# ohne alarm (timeout) bleibt ping hängen wenn DB nicht
+# ohne alarm (timeout) bleibt ping hängen wenn DB nicht
# errichbar ist
# https://perldoc.perl.org/functions/alarm
#
# andere: Variante (hat nicht funktioniert):
-# local $SIG{ALRM} = sub { die "Timeout\n" };
+# local $SIG{ALRM} = sub { die "Timeout\n" };
# -> https://blogs.perl.org/users/leon_timmermans/2012/01/what-you-should-know-about-signal-based-timeouts.html
############################################################################
sub _DbLog_SBP_pingDB {
my $name = shift;
my $dbh = shift;
my $to = shift // 10;
-
+
my $bool;
-
- eval {
+
+ eval {
POSIX::sigaction(SIGALRM, POSIX::SigAction->new(sub {die "Timeout"}));
-
+
alarm $to;
-
+
eval { $bool = $dbh->ping;
};
-
- alarm 0;
-
+
+ alarm 0;
+
if ($@ && $@ =~ /Timeout/xs) {
Log3 ($name, 2, "DbLog $name - Database Ping Timeout of >$to seconds< reached");
- }
-
+ }
+
};
-
- alarm 0; # Schutz vor Race Condition
-
+
+ alarm 0; # Schutz vor Race Condition
+
return $bool;
}
+############################################################################
+# DBH set
+# PrintError = 1, RaiseError = 0
+############################################################################
+sub _DbLog_SBP_dbhPrintError {
+ my $dbh = shift;
+
+ $dbh->{PrintError} = 1;
+ $dbh->{RaiseError} = 0;
+
+return;
+}
+
+############################################################################
+# DBH set
+# PrintError = 0, RaiseError = 1
+############################################################################
+sub _DbLog_SBP_dbhRaiseError {
+ my $dbh = shift;
+
+ $dbh->{PrintError} = 0;
+ $dbh->{RaiseError} = 1;
+
+return;
+}
+
#################################################################
# SubProcess - Log-Routine
# Bulk-Insert
#################################################################
-sub _DbLog_SBP_onRun_LogBulk {
+sub _DbLog_SBP_onRun_LogSequential {
my $paref = shift;
my $subprocess = $paref->{subprocess};
@@ -2668,18 +2711,18 @@ sub _DbLog_SBP_onRun_LogBulk {
my $faref = __DbLog_SBP_fieldArrays ($name, $cdata); # Feldarrays erstellen mit Logausgabe
my $ceti = scalar keys %{$cdata};
my $rv = 0;
-
+
my (@ins,$st,$sth_ih,$ins_hist);
if (lc($DbLogType) =~ m(history)) { # insert history mit/ohne primary key
for my $key (sort {$a<=>$b} keys %{$cdata}) {
- my $row = $cdata->{$key};
+ my $row = $cdata->{$key};
push @ins, $row;
- }
+ }
}
-
+
$st = [gettimeofday]; # SQL-Startzeit
-
+
if (lc($DbLogType) =~ m(history)) { # insert history mit/ohne primary key
($error, $sth_ih) = __DbLog_SBP_sthInsTable ( { table => $history,
dbh => $dbh,
@@ -2714,24 +2757,22 @@ sub _DbLog_SBP_onRun_LogBulk {
}
$error = __DbLog_SBP_beginTransaction ($name, $dbh, $useta);
-
- if(!$useta) { # generate errstr wenn keine TA
- $dbh->{PrintError} = 1;
- $dbh->{RaiseError} = 0;
+
+ if(!$useta) { # keine Transaktion: generate errstr, keine Ausnahme
+ _DbLog_SBP_dbhPrintError ($dbh);
}
-
+
eval { for my $ds (@ins) {
my @ao = split '\\|', $ds;
s/_ESC_/\|/gxs for @ao; # escaped Pipe back to "|"
-
+
unless ($rv = $sth_ih->execute ($ao[0], $ao[1], $ao[2], $ao[3], $ao[4], $ao[5], $ao[6])) {
Log3 ($name, 2, "DbLog $name - ERROR in >$operation< - ".$sth_ih->errstr);
}
else {
- #$rv = 0 if($rv eq "0E0");
$ins_hist += $rv;
}
- }
+ }
1;
}
or do { $error = $@;
@@ -2744,9 +2785,10 @@ sub _DbLog_SBP_onRun_LogBulk {
Log3 ($name, 4, "DbLog $name - Transaction is switched on. Transferred data is returned to the cache.");
}
else {
- Log3 ($name, 2, "DbLog $name - Transaction is switched off. Transferred data is lost.");
+ Log3 ($name, 2, "DbLog $name - Transaction is switched off. Transferred data is lost.");
}
+ _DbLog_SBP_dbhRaiseError ($dbh);
__DbLog_SBP_rollbackOnly ($name, $dbh, $history);
$ret = {
@@ -2758,15 +2800,12 @@ sub _DbLog_SBP_onRun_LogBulk {
};
__DbLog_SBP_sendToParent ($subprocess, $ret);
-
- $dbh->{PrintError} = 0;
- $dbh->{RaiseError} = 1;
-
+
return;
};
-
- $dbh->{PrintError} = 0;
- $dbh->{RaiseError} = 1;
+
+ _DbLog_SBP_dbhRaiseError ($dbh);
+ __DbLog_SBP_commitOnly ($name, $dbh, $history);
if($ins_hist == $ceti) {
Log3 ($name, 4, "DbLog $name - $ins_hist of $ceti events inserted into table $history".($usepkh ? " using PK on columns $pkh" : ""));
@@ -2779,8 +2818,6 @@ sub _DbLog_SBP_onRun_LogBulk {
Log3 ($name, 2, "DbLog $name - WARNING - only ".$ins_hist." of $ceti events inserted into table $history");
}
}
-
- __DbLog_SBP_commitOnly ($name, $dbh, $history);
}
if ($operation eq 'importCachefile') {
@@ -2879,7 +2916,7 @@ sub _DbLog_SBP_onRun_LogArray {
my $ln = scalar keys %{$logstore};
- if ($ln) { # temporär gespeicherte Daten hinzufügen
+ if ($ln) { # temporär gespeicherte Daten hinzufügen
for my $index (sort {$a<=>$b} keys %{$logstore}) {
Log3 ($name, 4, "DbLog $name - add stored data: $index -> ".$logstore->{$index});
@@ -2954,30 +2991,46 @@ sub _DbLog_SBP_onRun_LogArray {
$error = __DbLog_SBP_beginTransaction ($name, $dbh, $useta);
- eval {
- ($tuples, $rows) = $sth_ih->execute_array( { ArrayTupleStatus => \@tuple_status } );
- };
+ if(!$useta) { # keine Transaktion: generate errstr, keine Ausnahme
+ _DbLog_SBP_dbhPrintError ($dbh);
+ }
- if ($@) {
- $error = $@;
- $nins_hist = $ceti;
+ eval { ($tuples, $rows) = $sth_ih->execute_array( { ArrayTupleStatus => \@tuple_status } );
+ 1;
+ }
+ or do {
+ $error = $@;
+ $nins_hist = $ceti;
- Log3 ($name, 2, "DbLog $name - Error table $history - $error");
+ Log3 ($name, 2, "DbLog $name - Error table $history - $error");
- if($useta) {
- $rowlback = $cdata; # nicht gespeicherte Datensätze nur zurück geben wenn Transaktion ein
+ if($useta) {
+ $rowlback = $cdata; # nicht gespeicherte Datensätze nur zurück geben wenn Transaktion ein
+
+ Log3 ($name, 4, "DbLog $name - Transaction is switched on. Transferred data is returned to the cache.");
+ }
+ else {
+ Log3 ($name, 4, "DbLog $name - Transaction is switched off. Some or all of the transferred data will be lost. Note the following information.");
+ }
+
+ _DbLog_SBP_dbhRaiseError ($dbh);
__DbLog_SBP_rollbackOnly ($name, $dbh, $history);
- Log3 ($name, 4, "DbLog $name - Transaction is switched on. Transferred data is returned to the cache.");
- }
- else {
- __DbLog_SBP_commitOnly ($name, $dbh, $history);
- Log3 ($name, 4, "DbLog $name - Transaction is switched off. Some or all of the transferred data will be lost. Note the following information.");
- }
- }
- else {
- __DbLog_SBP_commitOnly ($name, $dbh, $history);
- }
+ $ret = {
+ name => $name,
+ msg => $error,
+ ot => 0,
+ oper => $operation,
+ rowlback => $rowlback
+ };
+
+ __DbLog_SBP_sendToParent ($subprocess, $ret);
+
+ return;
+ };
+
+ _DbLog_SBP_dbhRaiseError ($dbh);
+ __DbLog_SBP_commitOnly ($name, $dbh, $history);
no warnings 'uninitialized';
@@ -2987,7 +3040,7 @@ sub _DbLog_SBP_onRun_LogArray {
next if($status); # $status ist "1" wenn insert ok
- Log3 ($name, 4, "DbLog $name - Insert into $history rejected".($usepkh ? " (possible PK violation) " : " ")."- TS: $timestamp[$tuple], Device: $device[$tuple], Reading: $reading[$tuple]");
+ Log3 ($name, 4, "DbLog $name - Insert into $history rejected".($usepkh ? " (possible PK violation) " : " ")."->\nTS: $timestamp[$tuple], Device: $device[$tuple], Reading: $reading[$tuple]");
$event[$tuple] =~ s/\|/_ESC_/gxs; # escape Pipe "|"
$reading[$tuple] =~ s/\|/_ESC_/gxs;
@@ -3273,7 +3326,7 @@ sub __DbLog_SBP_logLogmodes {
my $name = $paref->{name};
my $useta = $paref->{useta};
my $dbh = $store->{dbh};
- my $bi = $memc->{bi}; # Bulk-Insert 0|1
+ my $im = $memc->{im}; # Insert-Mode 0|1
my $DbLogType = $memc->{DbLogType}; # Log-Ziele
my $operation = $memc->{operation} // 'unknown'; # aktuell angeforderte Operation (log, etc.)
@@ -3283,7 +3336,7 @@ sub __DbLog_SBP_logLogmodes {
Log3 ($name, 4, "DbLog $name - Operation: $operation");
Log3 ($name, 5, "DbLog $name - DbLogType: $DbLogType");
Log3 ($name, 4, "DbLog $name - AutoCommit: $ac, Transaction: $tm");
- Log3 ($name, 4, "DbLog $name - Insert mode: ".($bi ? "Bulk" : "Array"));
+ Log3 ($name, 4, "DbLog $name - Insert mode: ".($im ? "Sequential" : "Array"));
return;
}
@@ -3374,27 +3427,23 @@ sub _DbLog_SBP_onRun_deleteOldDays {
my $st = [gettimeofday]; # SQL-Startzeit
if(defined ($cmd)) {
- eval { $numdel = $dbh->do($cmd);
- 1;
- }
- or do { $error = $@;
+ (my $err, $numdel) = _DbLog_SBP_dbhDo ($name, $dbh, $cmd);
+
+ if ($err) {
+ $dbh->disconnect();
+ delete $store->{dbh};
- Log3 ($name, 2, "DbLog $name - Error table $history - $error");
-
- $dbh->disconnect();
- delete $store->{dbh};
-
- $ret = {
- name => $name,
- msg => $error,
- ot => 0,
- oper => $operation
- };
-
- __DbLog_SBP_sendToParent ($subprocess, $ret);
- return;
- };
+ $ret = {
+ name => $name,
+ msg => $err,
+ ot => 0,
+ oper => $operation
+ };
+ __DbLog_SBP_sendToParent ($subprocess, $ret);
+ return;
+ }
+
$numdel = 0 if($numdel == 0E0);
$error = __DbLog_SBP_commitOnly ($name, $dbh, $history);
@@ -3491,7 +3540,7 @@ return;
# $memc->{arguments} -> $infile
# $memc->{operation} -> 'importCachefile'
# $memc->{DbLogType} -> 'history'
-# $memc->{bi} -> 0
+# $memc->{im} -> 0
#
#################################################################
sub _DbLog_SBP_onRun_importCachefile {
@@ -3546,7 +3595,7 @@ sub _DbLog_SBP_onRun_importCachefile {
Log3 ($name, 3, "DbLog $name - $msg");
$memc->{DbLogType} = 'history'; # nur history-Insert !
- $memc->{bi} = 0; # Array-Insert !
+ $memc->{im} = 0; # Array-Insert !
($error, $nins_hist, $rowlback) = _DbLog_SBP_onRun_LogArray ( { subprocess => $subprocess,
name => $name,
@@ -4105,7 +4154,7 @@ sub __DbLog_SBP_beginTransaction {
eval{ if($useta && $dbh->{AutoCommit}) {
$dbh->begin_work();
Log3 ($name, 4, "DbLog $name - $info");
- };
+ };
1;
}
or do { $err = $@;
@@ -4186,32 +4235,6 @@ sub __DbLog_SBP_disconnectOnly {
return $err;
}
-#################################################################
-# erstellt SQL für Insert Daten in die HISTORY! Tabelle
-#################################################################
-sub __DbLog_SBP_sqlInsHistory {
- my $table = shift;
- my $model = shift;
- my $usepkh = shift;
-
- my $sql;
-
- if ($usepkh && $model eq 'MYSQL') {
- $sql = "INSERT IGNORE INTO $table (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES ";
- }
- elsif ($usepkh && $model eq 'SQLITE') {
- $sql = "INSERT OR IGNORE INTO $table (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES ";
- }
- elsif ($usepkh && $model eq 'POSTGRESQL') {
- $sql = "INSERT INTO $table (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES ";
- }
- else { # ohne PK
- $sql = "INSERT INTO $table (TIMESTAMP, DEVICE, TYPE, EVENT, READING, VALUE, UNIT) VALUES ";
- }
-
-return $sql;
-}
-
#################################################################
# erstellt Statement Handle für Insert Daten in die
# angegebene Tabelle
@@ -4453,7 +4476,7 @@ sub DbLog_SBP_sendLogData {
$memc->{nsupk} = AttrVal ($name, 'noSupportPK', 0);
$memc->{tl} = AttrVal ($name, 'traceLevel', 0);
$memc->{tf} = AttrVal ($name, 'traceFlag', 'SQL');
- $memc->{bi} = AttrVal ($name, 'bulkInsert', 0);
+ $memc->{im} = AttrVal ($name, 'insertMode', 0);
$memc->{verbose} = AttrVal ($name, 'verbose', 3);
$memc->{operation} = $oper;
@@ -4492,7 +4515,7 @@ sub DbLog_SBP_sendCommand {
$memc->{nsupk} = AttrVal ($name, 'noSupportPK', 0);
$memc->{tl} = AttrVal ($name, 'traceLevel', 0);
$memc->{tf} = AttrVal ($name, 'traceFlag', 'SQL');
- $memc->{bi} = AttrVal ($name, 'bulkInsert', 0);
+ $memc->{im} = AttrVal ($name, 'insertMode', 0);
$memc->{verbose} = AttrVal ($name, 'verbose', 3);
$memc->{operation} = $oper;
$memc->{arguments} = $arg;
@@ -4902,28 +4925,28 @@ return;
#################################################################
sub _DbLog_manageDBHU {
my $hash = shift;
-
+
my $name = $hash->{NAME};
my $dbh;
-
+
if (defined $hash->{DBHU}) {
$dbh = $hash->{DBHU};
my $bool = _DbLog_SBP_pingDB ($name, $dbh);
-
+
if (!$bool) {
delete $hash->{DBHU};
$dbh = _DbLog_getNewDBHandle ($hash) || return "Can't connect to database.";
$hash->{DBHU} = $dbh;
-
- Log3 ($name, 4, "DbLog $name - Created new DBHU for PID: $$");
+
+ Log3 ($name, 4, "DbLog $name - Created new DBHU for PID: $$");
}
}
- else {
+ else {
$dbh = _DbLog_getNewDBHandle ($hash) || return "Can't connect to database.";
$hash->{DBHU} = $dbh;
-
- Log3 ($name, 4, "DbLog $name - Created new DBHU for PID: $$");
+
+ Log3 ($name, 4, "DbLog $name - Created new DBHU for PID: $$");
}
return;
@@ -4982,13 +5005,13 @@ sub _DbLog_prepExecQueryOnly {
Log3 ($name, 2, "DbLog $name - ERROR - $err");
return $err;
};
-
+
@sr = $sth->fetchrow_array;
-
- no warnings 'uninitialized';
+
+ no warnings 'uninitialized';
Log3 ($name, 4, "DbLog $name - SQL result: ".join ' ', @sr);
use warnings;
-
+
return ($err, @sr);
}
@@ -4998,21 +5021,22 @@ return ($err, @sr);
#
# param1: DbLog-hash
# param2: SQL-Statement
-#
+#
##########################################################################
sub DbLog_ExecSQL {
my $hash = shift;
my $sql = shift;
-
+
my $err = _DbLog_manageDBHU ($hash);
return $err if($err);
-
+
my $dbh = $hash->{DBHU};
my $name = $hash->{NAME};
Log3 ($name, 4, "DbLog $name - Backdoor executing: $sql");
-
- my $sth = DbLog_ExecSQL1($hash, $dbh, $sql);
+
+ ($err, my $sth) = _DbLog_SBP_dbhDo ($name, $dbh, $sql);
+ $sth = 0 if($err);
__DbLog_SBP_commitOnly ($name, $dbh);
__DbLog_SBP_disconnectOnly ($name, $dbh);
@@ -5020,24 +5044,6 @@ sub DbLog_ExecSQL {
return $sth;
}
-sub DbLog_ExecSQL1 {
- my $hash = shift;
- my $dbh = shift;
- my $sql = shift;
-
- my $name = $hash->{NAME};
-
- my $sth;
-
- eval { $sth = $dbh->do($sql); };
- if($@) {
- Log3 ($name, 2, "DbLog $name - ERROR: $@");
- return 0;
- }
-
-return $sth;
-}
-
################################################################
#
# GET Funktion
@@ -5052,7 +5058,7 @@ sub DbLog_Get {
my $utf8 = defined($hash->{UTF8})?$hash->{UTF8}:0;
my $history = $hash->{HELPER}{TH};
my $current = $hash->{HELPER}{TC};
-
+
my ($dbh,$err);
if ($a[1] =~ m/^Readings/) {
@@ -5155,17 +5161,17 @@ sub DbLog_Get {
Log3($name, 4, "DbLog $name - main PID: $hash->{PID}, secondary PID: $$");
my $samePID = $hash->{PID} == $$ ? 1 : 0;
-
+
if ($samePID) {
$err = _DbLog_manageDBHU ($hash);
return $err if($err);
-
+
$dbh = $hash->{DBHU};
}
else {
$dbh = _DbLog_getNewDBHandle($hash) || return "Can't connect to database.";
-
- Log3 ($name, 4, "DbLog $name - Created new DBHU for PID: $$");
+
+ Log3 ($name, 4, "DbLog $name - Created new DBHU for PID: $$");
}
# vorbereiten der DB-Abfrage, DB-Modell-abhaengig
@@ -5734,9 +5740,9 @@ sub DbLog_configcheck {
my $current = $hash->{HELPER}{TC};
my ($check, $rec,%dbconfig);
-
+
Log3 ($name, 4, "DbLog $name - ### Start configCheck ###");
-
+
my $ok = FW_makeImage('10px-kreis-gruen.png', '');
my $nok = FW_makeImage('10px-kreis-rot.png', '');
my $warn = FW_makeImage('message_attention@orange', '');
@@ -5769,7 +5775,7 @@ sub DbLog_configcheck {
$dv = $_ if($_ =~ /mysql|mariadb/x);
}
}
-
+
my $dbd = ($dbmodel =~ /POSTGRESQL/xi) ? "Pg: ".$DBD::Pg::VERSION : # DBD Version
($dbmodel =~ /MYSQL/xi && $dv) ? "$dv: ".$DBD::mysql::VERSION :
($dbmodel =~ /SQLITE/xi) ? "SQLite: ".$DBD::SQLite::VERSION :
@@ -5839,7 +5845,7 @@ sub DbLog_configcheck {
$rec = $err;
}
$check .= "Connection $rec
";
- $check .= defined $dbconfig{connection} && defined $dbconfig{user} && defined $dbconfig{password} ?
+ $check .= defined $dbconfig{connection} && defined $dbconfig{user} && defined $dbconfig{password} ?
"Rating: ".$ok."
" :
"Rating: ".$nok."
";
$check .= "
";
@@ -5849,16 +5855,16 @@ sub DbLog_configcheck {
my $st = [gettimeofday]; # Startzeit
my $dbh = _DbLog_getNewDBHandle ($hash) || return "Can't connect to database.";
my $ct = sprintf("%.4f", tv_interval($st)); # Laufzeit ermitteln
-
+
Log3 ($name, 4, "DbLog $name - Time required to establish the database connection: ".$ct);
-
+
my (@ce,@se);
my ($chutf8mod,$chutf8dat);
if ($dbmodel =~ /MYSQL/) {
($err, @ce) = _DbLog_prepExecQueryOnly ($name, $dbh, "SHOW VARIABLES LIKE 'character_set_connection'");
$chutf8mod = @ce ? uc($ce[1]) : "no result";
-
+
($err, @se) = _DbLog_prepExecQueryOnly ($name, $dbh, "SHOW VARIABLES LIKE 'character_set_database'");
$chutf8dat = @se ? uc($se[1]) : "no result";
@@ -5877,11 +5883,11 @@ sub DbLog_configcheck {
}
}
-
+
if ($dbmodel =~ /POSTGRESQL/) {
($err, @ce) = _DbLog_prepExecQueryOnly ($name, $dbh, "SHOW CLIENT_ENCODING");
$chutf8mod = @ce ? uc($ce[0]) : "no result";
-
+
($err, @se) = _DbLog_prepExecQueryOnly ($name, $dbh, "select character_set_name from information_schema.character_sets");
$chutf8dat = @se ? uc($se[0]) : "no result";
@@ -5892,7 +5898,7 @@ sub DbLog_configcheck {
$rec = "This is only an information. PostgreSQL supports automatic character set conversion between server and client for certain character set combinations. The conversion information is stored in the pg_conversion system catalog. PostgreSQL comes with some predefined conversions.";
}
}
-
+
if ($dbmodel =~ /SQLITE/) {
($err, @ce) = _DbLog_prepExecQueryOnly ($name, $dbh, "PRAGMA encoding");
$chutf8dat = @ce ? uc($ce[0]) : "no result";
@@ -5904,9 +5910,9 @@ sub DbLog_configcheck {
$check .= "Result of connection check
";
if (!$err && @ce && @se) {
- $check .= "Connection to database $dbname successfully done.
";
+ $check .= "Connection to database $dbname successfully done.
";
$check .= "The time required to establish the connection was $ct seconds.
";
-
+
if ($ct > 5.0) {
$check .= "Rating: ".$nok."
";
$check .= "Recommendation: The time to establish a connection is much too long. There are connection problems that can massively affect the operation.
";
@@ -5922,7 +5928,7 @@ sub DbLog_configcheck {
else {
$check .= "Rating: ".$ok."
";
$check .= "Recommendation: settings o.k.
";
- }
+ }
}
if ($err || !@ce || !@se) {
@@ -5932,37 +5938,37 @@ sub DbLog_configcheck {
$check .= "