diff --git a/fhem/CHANGED b/fhem/CHANGED
index 3d0f17cdc..dd9a2a7f8 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 PRAGMA leading an SQLIte SQL-Statement in sqlCmd
- bugfix/feature: 59_Weather/API's: fix weblink bug, add extended hourly
data format
- feature: 55_DWD_OpenData: - new readings SunRise, SunSet
diff --git a/fhem/FHEM/93_DbRep.pm b/fhem/FHEM/93_DbRep.pm
index 97a45f4fa..daf10412e 100644
--- a/fhem/FHEM/93_DbRep.pm
+++ b/fhem/FHEM/93_DbRep.pm
@@ -55,8 +55,9 @@ use IO::Uncompress::Gunzip qw(gunzip $GunzipError);
# no if $] >= 5.018000, warnings => 'experimental';
no if $] >= 5.017011, warnings => 'experimental::smartmatch';
-# Versions History intern
+# Version History intern
our %DbRep_vNotesIntern = (
+ "8.16.0" => "17.03.2019 include sortTopicNum from 99_Utils, allow PRAGMAS leading an SQLIte SQL-Statement in sqlCmd, switch to DbRep_setVersionInfo ",
"8.15.0" => "04.03.2019 readingsRename can rename readings of a given (optional) device ",
"8.14.1" => "04.03.2019 Bugfix in deldoublets with SQLite, Forum: https://forum.fhem.de/index.php/topic,53584.msg914489.html#msg914489 ",
"8.14.0" => "19.02.2019 delete Readings if !goodReadingName and featurelevel > 5.9 ",
@@ -138,8 +139,9 @@ our %DbRep_vNotesIntern = (
"1.0.0" => "19.05.2016 Initial"
);
-# Versions History extern:
+# Version History extern:
our %DbRep_vNotesExtern = (
+ "8.16.0" => "17.03.2019 allow SQLite PRAGMAS leading an SQLIte SQL-Statement in sqlCmd",
"8.15.0" => "04.03.2019 readingsRename can now rename readings of a given (optional) device instead of all found readings specified in command ",
"8.13.0" => "11.02.2019 executeBeforeProc / executeAfterProc is now available for sqlCmd,sumValue, maxValue, minValue, diffValue, averageValue ",
"8.11.0" => "24.01.2019 command exportToFile or attribute \"expimpfile\" accepts option \"MAXLINES=\" ",
@@ -364,8 +366,10 @@ sub DbRep_Initialize($) {
# $hash->{AttrRenameMap} = { "reading" => "readingFilter",
# "device" => "deviceFilter",
# };
-
-return undef;
+
+ # FHEM::Meta::InitMod( __FILE__, $hash ); # für Meta.pm (https://forum.fhem.de/index.php/topic,97589.0.html)
+
+return;
}
###################################################################################
@@ -393,12 +397,14 @@ sub DbRep_Define($@) {
$hash->{MODEL} = $hash->{ROLE};
$hash->{HELPER}{DBLOGDEVICE} = $a[2];
$hash->{HELPER}{IDRETRIES} = 3; # Anzahl wie oft versucht wird initiale Daten zu holen
- $hash->{VERSION} = (DbRep_sortVersion("desc",keys %DbRep_vNotesIntern))[0];
$hash->{NOTIFYDEV} = "global,".$name; # nur Events dieser Devices an DbRep_Notify weiterleiten
my $dbconn = $defs{$a[2]}{dbconn};
$hash->{DATABASE} = (split(/;|=/, $dbconn))[1];
$hash->{UTF8} = defined($defs{$a[2]}{UTF8})?$defs{$a[2]}{UTF8}:0;
+ # Versionsinformationen setzen
+ DbRep_setVersionInfo($hash);
+
my ($err,$hl) = DbRep_getCmdFile($name."_sqlCmdList");
if(!$err) {
$hash->{HELPER}{SQLHIST} = $hl;
@@ -964,7 +970,7 @@ sub DbRep_Get($@) {
}
}
$i = 0;
- foreach my $key (DbRep_sortVersion("desc",keys %hs)) {
+ foreach my $key (sortTopicNum("desc",keys %hs)) {
$val0 = $hs{$key};
$ret .= sprintf("
$key | $val0 | " );
$ret .= "";
@@ -989,7 +995,7 @@ sub DbRep_Get($@) {
$ret .= "";
$ret .= "";
$i = 0;
- foreach my $key (DbRep_sortVersion("desc",keys %DbRep_vNotesExtern)) {
+ foreach my $key (sortTopicNum("desc",keys %DbRep_vNotesExtern)) {
($val0,$val1) = split(/\s/,$DbRep_vNotesExtern{$key},2);
$ret .= sprintf("$key | $val0 | $val1 | " );
$ret .= "
";
@@ -5665,7 +5671,7 @@ sub sqlCmd_DoParse($) {
$set = $1;
$sql = $2;
}
-
+
if($set) {
Log3($name, 4, "DbRep $name - Set SQL session variables: $set");
eval {$dbh->do($set);}; # @\RB = Resetbit wenn neues Selektionsintervall beginnt
@@ -5677,6 +5683,27 @@ sub sqlCmd_DoParse($) {
return "$name|''|$opt|$set|''|''|$err";
}
+ # Abarbeitung aller Pragmas in einem SQLite Statement, SQL wird extrahiert
+ # Pragmas müssen im SQL vorangestellt sein
+ if($cmd =~ /^\s*PRAGMA.*;/i) {
+ my @pms = split(";",$cmd);
+ foreach my $pm (@pms) {
+ if($pm !~ /PRAGMA/i) {
+ $sql = $pm;
+ next;
+ }
+ $pm = ltrim($pm);
+ Log3($name, 4, "DbRep $name - Exec PRAGMA Statement: $pm");
+ eval {$dbh->do($pm);};
+ if ($@) {
+ $err = encode_base64($@,"");
+ Log3 ($name, 2, "DbRep $name - ERROR - $@");
+ $dbh->disconnect;
+ return "$name|''|$opt|$set|''|''|$err";
+ }
+ }
+ }
+
# Allow inplace replacement of keywords for timings (use time attribute syntax)
$sql =~ s/§timestamp_begin§/'$runtime_string_first'/g;
$sql =~ s/§timestamp_end§/'$runtime_string_next'/g;
@@ -10071,6 +10098,37 @@ sub DbRep_sortVersion (@){
return @sorted;
}
+################################################################
+# Versionierungen des Moduls setzen
+# Die Verwendung von Meta.pm und Packages wird berücksichtigt
+################################################################
+sub DbRep_setVersionInfo($) {
+ my ($hash) = @_;
+ my $name = $hash->{NAME};
+
+ my $type = $hash->{TYPE};
+ if($modules{$type}{META}{x_prereqs_src}) {
+ # META-Daten sind vorhanden
+ $modules{$type}{META}{version} = "v".(sortTopicNum("desc",keys %DbRep_vNotesIntern))[0]; # Version aus META.json überschreiben, Anzeige mit {Dumper $modules{SMAPortal}{META}}
+ if($modules{$type}{META}{x_version}) { # {x_version} ( nur gesetzt wenn $Id$ im Kopf komplett! vorhanden )
+ $modules{$type}{META}{x_version} =~ s/0.0.0/(sortTopicNum("desc",keys %DbRep_vNotesIntern))[0]/e;
+ } else {
+ $modules{$type}{META}{x_version} = (sortTopicNum("desc",keys %DbRep_vNotesIntern))[0];
+ }
+ return $@ unless (FHEM::Meta::SetInternals($hash)); # FVERSION wird gesetzt ( nur gesetzt wenn $Id$ im Kopf komplett! vorhanden )
+ if( __PACKAGE__ eq $type) {
+ # es wird mit Packages gearbeitet -> Perl übliche Modulversion setzen
+ # mit {->VERSION()} im FHEMWEB kann Modulversion abgefragt werden
+ use version 0.77; our $VERSION = FHEM::Meta::Get( $hash, 'version' );
+ }
+ } else {
+ # herkömmliche Modulstruktur
+ $hash->{VERSION} = (sortTopicNum("desc",keys %DbRep_vNotesIntern))[0];
+ }
+
+return;
+}
+
####################################################################################################
# blockierende DB-Abfrage
# liefert Ergebnis sofort zurück, setzt keine Readings
@@ -11487,8 +11545,8 @@ return;
"allowDeletion" has to be set for security reason.
The statement doesn't consider limitations by attributes "device", "reading", "time.*"
respectively "aggregation".
- This command also accept the setting of SQL session variables like "SET @open:=NULL,
- @closed:=NULL;".
+ This command also accept the setting of MySQL session variables like "SET @open:=NULL,
+ @closed:=NULL;" or the usage of SQLite PRAGMA before execution of the SQL-Statement.
If the attribute "timestamp_begin" respectively "timestamp_end"
is assumed in the statement, it is possible to use placeholder "§timestamp_begin§" respectively
"§timestamp_end§" on suitable place.
@@ -11514,8 +11572,8 @@ return;
- Here you can see an example of a more complex statement (MySQL) with setting SQL session
- variables:
+ Here you can see examples of a more complex statement (MySQL) with setting SQL session
+ variables and the SQLite PRAGMA usage:
- set <name> sqlCmd SET @open:=NULL, @closed:=NULL;
@@ -11530,6 +11588,8 @@ return;
READING = "state" AND
(VALUE = "open" OR VALUE = "closed")
ORDER BY TIMESTAMP;
+ - set <name> sqlCmd PRAGMA temp_store=MEMORY; PRAGMA synchronous=FULL; PRAGMA journal_mode=WAL; PRAGMA cache_size=4000; select count(*) from history;
+ - set <name> sqlCmd PRAGMA temp_store=FILE; PRAGMA temp_store_directory = '/opt/fhem/'; VACUUM;
@@ -13863,7 +13923,8 @@ sub bdump {
Bei der Ausführung dieses Kommandos werden keine Einschränkungen durch gesetzte Attribute
"device", "reading", "time.*" bzw. "aggregation" berücksichtigt.
Dieses Kommando akzeptiert ebenfalls das Setzen von SQL Session Variablen wie z.B.
- "SET @open:=NULL, @closed:=NULL;".
+ "SET @open:=NULL, @closed:=NULL;" oder die Verwendung von SQLite PRAGMA vor der
+ Ausführung des SQL-Statements.
Sollen die im Modul gesetzten Attribute "timestamp_begin" bzw.
"timestamp_end" im Statement berücksichtigt werden, können die Platzhalter
"§timestamp_begin§" bzw. "§timestamp_end§" dafür verwendet werden.
@@ -13889,8 +13950,8 @@ sub bdump {
- Nachfolgend noch ein Beispiel für ein komplexeres Statement (MySQL) unter Mitgabe von
- SQL Session Variablen:
+ Nachfolgend Beispiele für ein komplexeres Statement (MySQL) unter Mitgabe von
+ SQL Session Variablen und die SQLite PRAGMA-Verwendung:
- set <name> sqlCmd SET @open:=NULL, @closed:=NULL;
@@ -13905,6 +13966,8 @@ sub bdump {
READING = "state" AND
(VALUE = "open" OR VALUE = "closed")
ORDER BY TIMESTAMP;
+ - set <name> sqlCmd PRAGMA temp_store=MEMORY; PRAGMA synchronous=FULL; PRAGMA journal_mode=WAL; PRAGMA cache_size=4000; select count(*) from history;
+ - set <name> sqlCmd PRAGMA temp_store=FILE; PRAGMA temp_store_directory = '/opt/fhem/'; VACUUM;