diff --git a/fhem/FHEM/98_configdb.pm b/fhem/FHEM/98_configdb.pm index f8e3221c5..71fd0013d 100644 --- a/fhem/FHEM/98_configdb.pm +++ b/fhem/FHEM/98_configdb.pm @@ -206,24 +206,6 @@ sub CommandConfigdb($$) { $ret = _cfgDB_Fileexport $filename; } -# when ('fileimport') { -# return "\n Syntax: configdb fileimport " if @a != 2; -# my $filename; -# if($param1 =~ m,^[./],) { -# $filename = $param1; -# } else { -# $filename = $attr{global}{modpath}; -# $filename .= "/$param1"; -# } -# if ( -r $filename ) { -# $ret = _cfgDB_Fileimport $filename; -# } elsif ( -e $filename) { -# $ret = "\n Read error on file $filename"; -# } else { -# $ret = "\n File $filename not found."; -# } -# } - when ('fileimport') { return "\n Syntax: configdb fileimport " if @a != 2; my $filename; @@ -286,7 +268,7 @@ sub CommandConfigdb($$) { $param1 = $param1 ? $param1 : '%'; $param2 = $param2 ? $param2 : 0; Log3('configdb', 4, "configdb: list requested for device: $param1 in version $param2."); - $ret = _cfgDB_List($param1,$param2); + $ret = _cfgDB_Search($param1,$param2,1); } when ('migrate') { diff --git a/fhem/configDB.pm b/fhem/configDB.pm index 67d9785c3..7a9031d9d 100644 --- a/fhem/configDB.pm +++ b/fhem/configDB.pm @@ -75,39 +75,62 @@ # # 2014-05-11 - removed binfileimport # changed store all files as binary -# added _cfgDB_move to move all files from text +# added _cfgDB_Move to move all files from text # to binary filesave on first load of configDB # +# 2014-05-12 - added sorted write & read for config data +# ############################################################################## # use DBI; -#use Data::Dumper; # for debugging only ################################################## # Forward declarations for functions in fhem.pl # sub AnalyzeCommandChain($$;$); -sub AttrVal($$$); -sub Debug($); sub Log3($$$); -sub GlobalAttr($$$$); ################################################## # Forward declarations inside this library # +sub cfgDB_AttrRead($); +sub cfgDB_Init(); +sub cfgDB_FileRead($); +sub cfgDB_FileUpdate($); +sub cfgDB_Fileversion($$); +sub cfgDB_FileWrite($@); +sub cfgDB_FW_fileList(@$); +sub cfgDB_Read99(); +sub cfgDB_ReadAll($); +sub cfgDB_SaveCfg(); +sub cfgDB_SaveState(); +sub cfgDB_svnId(); -sub _cfgDB_Connect; +sub _cfgDB_binFileimport($$;$); +sub _cfgDB_Connect(); +sub _cfgDB_Diff($$); +sub __cfgDB_Diff($$$); sub _cfgDB_InsertLine($$$$); sub _cfgDB_Execute($@); +sub _cfgDB_Filedelete($); +sub _cfgDB_Fileexport($); +sub _cfgDB_Filelist(;$); +sub _cfgDB_Info(); +sub _cfgDB_Migrate(); +sub _cfgDB_Move(); sub _cfgDB_ReadCfg(@); sub _cfgDB_ReadState(@); -sub _cfgDB_Rotate($); -sub _cfgDB_Uuid; -sub _cfgDB_Info; -sub _cfgDB_Filelist(;$); +sub _cfgDB_Recover($); sub _cfgDB_Reorg(;$$); -sub _cfgDB_move(); +sub _cfgDB_Rotate($); +sub _cfgDB_Search($$;$); +sub _cfgDB_Uuid(); + +# deprecated! +sub _cfgDB_Readfile($); +sub _cfgDB_Updatefile($); +sub _cfgDB_Writefile($$); ################################################## # Read configuration file for DB connection @@ -146,7 +169,7 @@ if($cfgDB_dbconn =~ m/pg:/i) { # # initialize database, create tables if necessary - sub cfgDB_Init { +sub cfgDB_Init() { ################################################## # Create non-existing database tables # Create default config entries if necessary @@ -207,13 +230,13 @@ if($cfgDB_dbconn =~ m/pg:/i) { $fhem_dbh->disconnect(); # move all files from text filesave to binary if not already done - _cfgDB_move if($needmove); + _cfgDB_Move if($needmove); return; } # read attributes - sub cfgDB_AttrRead($) { +sub cfgDB_AttrRead($) { my ($readSpec) = @_; my ($row, $sql, @line, @rets); my $fhem_dbh = _cfgDB_Connect; @@ -234,10 +257,8 @@ if($cfgDB_dbconn =~ m/pg:/i) { return @rets; } -# functions for filehandling to be called -# from fhem.pl and other fhem modules - - sub cfgDB_FileRead($) { +# generic file functions called from fhem.pl +sub cfgDB_FileRead($) { my ($filename) = @_; my ($err, @ret, $counter); my $fhem_dbh = _cfgDB_Connect; @@ -256,9 +277,9 @@ if($cfgDB_dbconn =~ m/pg:/i) { } return ($err, @ret); } - - sub cfgDB_FileWrite($@) { +sub cfgDB_FileWrite($@) { my ($filename,@content) = @_; + chomp(@content) if($filename =~ m/.gplot$/); my $fhem_dbh = _cfgDB_Connect; $fhem_dbh->do("delete from fhembinfilesave where filename = '$filename'"); my $sth = $fhem_dbh->prepare('INSERT INTO fhembinfilesave values (?, ?)'); @@ -268,8 +289,7 @@ if($cfgDB_dbconn =~ m/pg:/i) { $fhem_dbh->disconnect(); return; } - - sub cfgDB_FileUpdate($) { +sub cfgDB_FileUpdate($) { my ($filename) = @_; my $fhem_dbh = _cfgDB_Connect; my $id = $fhem_dbh->selectrow_array("SELECT filename from fhembinfilesave where filename = '$filename'"); @@ -282,10 +302,8 @@ if($cfgDB_dbconn =~ m/pg:/i) { return ""; } -# read and execute all commands from -# fhemconfig and fhemstate - - sub cfgDB_ReadAll($){ +# read and execute fhemconfig and fhemstate +sub cfgDB_ReadAll($) { my ($cl) = @_; my $ret; # add Config Rows to commandfile @@ -298,10 +316,8 @@ if($cfgDB_dbconn =~ m/pg:/i) { return undef; } -# rotate all older versions to versionnumber+1 # save running configuration to version 0 - - sub cfgDB_SaveCfg { +sub cfgDB_SaveCfg() { my (%devByNr, @rowList); map { $devByNr{$defs{$_}{NR}} = $_ } keys %defs; @@ -363,13 +379,14 @@ if($cfgDB_dbconn =~ m/pg:/i) { } $fhem_dbh->commit(); $fhem_dbh->disconnect(); - my $maxVersions = AttrVal('configdb','maxversions',0); + my $maxVersions = $attr{configdb}{maxversions}; + $maxVersions = ($maxVersions) ? $maxVersions : 0; _cfgDB_Reorg($maxVersions,1) if($maxVersions); return 'configDB saved.'; } # save statefile - sub cfgDB_SaveState { +sub cfgDB_SaveState() { my ($out,$val,$r,$rd,$t,@rowList); $t = localtime; @@ -423,12 +440,12 @@ if($cfgDB_dbconn =~ m/pg:/i) { } # return SVN Id, called by fhem's CommandVersion - sub cfgDB_svnId { +sub cfgDB_svnId() { return "# ".'$Id$' } # return filelist depending on directory and regexp - sub cfgDB_FW_fileList(@$) { +sub cfgDB_FW_fileList(@$) { my ($dir,$re,@ret) = @_; my @files = split(/\n/, _cfgDB_Filelist('notitle')); foreach my $f (@files) { @@ -441,7 +458,7 @@ if($cfgDB_dbconn =~ m/pg:/i) { } # read filelist containing 99_ files in database - sub cfgDB_Read99() { +sub cfgDB_Read99() { my $ret; my $fhem_dbh = _cfgDB_Connect; my $sth = $fhem_dbh->prepare( "SELECT filename FROM fhembinfilesave WHERE filename like '%/99_%.pm' group by filename" ); @@ -457,7 +474,7 @@ if($cfgDB_dbconn =~ m/pg:/i) { } # return SVN Id from file stored in database - sub cfgDB_Fileversion($$) { +sub cfgDB_Fileversion($$) { my ($file,$ret) = @_; my ($err,@in) = cfgDB_FileRead($file); foreach(@in){ $ret = $_ if($_ =~ m/# \$Id:/); } @@ -470,7 +487,7 @@ if($cfgDB_dbconn =~ m/pg:/i) { # # connect do database -sub _cfgDB_Connect { +sub _cfgDB_Connect() { my $fhem_dbh = DBI->connect( "dbi:$cfgDB_dbconn", $cfgDB_dbuser, @@ -550,7 +567,7 @@ sub _cfgDB_Rotate($) { } # return a UUID based on DB-model -sub _cfgDB_Uuid{ +sub _cfgDB_Uuid() { my $fhem_dbh = _cfgDB_Connect; my $uuid; $uuid = $fhem_dbh->selectrow_array('select lower(hex(randomblob(16)))') if($cfgDB_dbtype eq 'SQLITE'); @@ -565,8 +582,8 @@ sub _cfgDB_Uuid{ # not called from fhem.pl directly # -# migrate existing fhem config into database -sub _cfgDB_Migrate { +# migrate existing fhem config into database +sub _cfgDB_Migrate() { my $ret; $ret = "Starting migration...\n"; Log3('configDB',4,'Starting migration.'); @@ -586,8 +603,8 @@ sub _cfgDB_Migrate { } -# show database statistics -sub _cfgDB_Info { +# show database statistics +sub _cfgDB_Info() { my ($l, @r, @row_ary, $f); for my $i (1..65){ $l .= '-';} # $l .= "\n"; @@ -655,7 +672,7 @@ sub _cfgDB_Info { return join("\n", @r); } -# recover former config from database archive +# recover former config from database archive sub _cfgDB_Recover($) { my ($version) = @_; my ($cmd, $count, $ret); @@ -698,7 +715,7 @@ sub _cfgDB_Recover($) { return $ret; } -# delete old configurations +# delete old configurations sub _cfgDB_Reorg(;$$) { my ($lastversion,$quiet) = @_; $lastversion = ($lastversion > 0) ? $lastversion : 3; @@ -712,41 +729,21 @@ sub _cfgDB_Reorg(;$$) { return " Result after database reorg:\n"._cfgDB_Info; } -# list device(s) from given version -sub _cfgDB_List(;$$) { - my ($search,$searchversion) = @_; - $search = $search ? $search : "%"; - $searchversion = $searchversion ? $searchversion : 0; - my $fhem_dbh = _cfgDB_Connect; - my ($sql, $sth, @line, $row, @result, $ret); - $sql = "SELECT command, device, p1, p2 FROM fhemconfig as c join fhemversions as v ON v.versionuuid=c.versionuuid ". - "WHERE v.version = '$searchversion' AND command not like '#create%' AND device like '$search%' ORDER BY lower(device),command DESC"; - $sth = $fhem_dbh->prepare( $sql); - $sth->execute(); - push @result, "search result for device: $search in version: $searchversion"; - push @result, "--------------------------------------------------------------------------------"; - while (@line = $sth->fetchrow_array()) { - $row = "$line[0] $line[1] $line[2] $line[3]"; - push @result, "$row"; - } - $fhem_dbh->disconnect(); - $ret = join("\n", @result); - return $ret; -} - -sub _cfgDB_Search($;$) { - my ($search,$searchversion) = @_; +# search for device or fulltext in db +sub _cfgDB_Search($$;$) { + my ($search,$searchversion,$dsearch) = @_; return 'Syntax error.' if(!(defined($search))); - $searchversion = $searchversion ? $searchversion : 0; my $fhem_dbh = _cfgDB_Connect; - my ($sql, $sth, @line, $row, @result, $ret); - $sql = "SELECT command, device, p1, p2 FROM fhemconfig as c join fhemversions as v ON v.versionuuid=c.versionuuid ". - "WHERE v.version = '$searchversion' AND command not like '#create%' ". - "AND (device like '$search%' OR P1 like '$search%' OR P2 like '$search%') ". - "ORDER BY lower(device),command DESC"; + my ($sql, $sth, @line, $row, @result, $ret, $text); + $sql = "SELECT command, device, p1, p2 FROM fhemconfig as c join fhemversions as v ON v.versionuuid=c.versionuuid "; + $sql .= "WHERE v.version = '$searchversion' AND command not like '#create%' "; + $sql .= "AND device like '$search%' " if($dsearch); + $sql .= "AND (device like '$search%' OR P1 like '$search%' OR P2 like '$search%') " if(!$dsearch); + $sql .= "ORDER BY lower(device),command DESC"; $sth = $fhem_dbh->prepare( $sql); $sth->execute(); - push @result, "search result for: $search in version: $searchversion"; + $text = " device" if($dsearch); + push @result, "search result for$text: $search in version: $searchversion"; push @result, "--------------------------------------------------------------------------------"; while (@line = $sth->fetchrow_array()) { $row = "$line[0] $line[1] $line[2] $line[3]"; @@ -757,7 +754,7 @@ sub _cfgDB_Search($;$) { return $ret; } -# called from cfgDB_Diff +# called from cfgDB_Diff sub __cfgDB_Diff($$$) { my ($fhem_dbh,$search,$searchversion) = @_; my ($sql, $sth, @line, $ret); @@ -771,7 +768,7 @@ sub __cfgDB_Diff($$$) { return $ret; } -# compare device configurations from 2 versions +# compare device configurations from 2 versions sub _cfgDB_Diff($$) { my ($search,$searchversion) = @_; use Text::Diff; @@ -786,41 +783,14 @@ sub _cfgDB_Diff($$) { return $ret; } -sub _cfgDB_AttrTypeSet($$){ - my ($dName,$tName) = @_; - my @typeAttr = cfgDB_AttrRead($tName); - foreach my $ta (@typeAttr) { - my (undef,$n,$v) = split(/,/,$ta); - $attr{$dName}{$n} = $v; - } - return; -} - ################################################## # functions used for file handling +# called by 98_configdb.pm # -# find dbtable for file -sub _cfgDB_Filefind($) { - my ($filename) = @_; - my $fhem_dbh = _cfgDB_Connect; - my @dbtable = ('fhembinfilesave'); - my $retfile; - foreach (@dbtable) { - $retfile = $_; - my $ret = $fhem_dbh->selectrow_array("SELECT COUNT(*) from $retfile where filename = '$filename'"); - last if $ret; - $retfile = undef; - } - $fhem_dbh->disconnect(); - return $retfile; -} - -# delete file from database +# delete file from database sub _cfgDB_Filedelete($) { my ($filename) = @_; -# my $dbtable = _cfgDB_Filefind($filename); -# return "File $filename not found in database." if(!$dbtable); my $fhem_dbh = _cfgDB_Connect; my $ret = $fhem_dbh->do("delete from fhembinfilesave where filename = '$filename'"); $fhem_dbh->commit(); @@ -833,44 +803,27 @@ sub _cfgDB_Filedelete($) { return $ret; } -# export file from database to filesystem +# export file from database to filesystem sub _cfgDB_Fileexport($) { my ($filename) = @_; - my $dbtable = _cfgDB_Filefind($filename); - return "File $filename not found in database." if(!$dbtable); - my $counter = 0; - my $binfile = ($dbtable eq 'fhembinfilesave') ? 1 : 0; - my $sunit = ($binfile) ? 'bytes' : 'lines'; my $fhem_dbh = _cfgDB_Connect; - my $sth = $fhem_dbh->prepare( "SELECT * FROM $dbtable WHERE filename = '$filename'" ); + my $sth = $fhem_dbh->prepare( "SELECT content FROM fhembinfilesave WHERE filename = '$filename'" ); $sth->execute(); + my $blobContent = $sth->fetchrow_array(); + my $counter = length($blobContent); + return "No data found for file $filename" unless $counter; - if($binfile) { # write binfile + open( FILE,">$filename" ); + binmode(FILE); + print FILE $blobContent; + close( FILE ); - my $blobContent = $sth->fetchrow_array(); - $counter = length($blobContent); - open( FILE,">$filename" ); - binmode(FILE); - print FILE $blobContent; - close( FILE ); - - } else { # write textfile - - open( FILE, ">$filename" ); - while (my @line = $sth->fetchrow_array()) { - $counter++; - print FILE $line[1], "\n"; - } - close ( FILE ); - - } - $sth->finish(); $fhem_dbh->disconnect(); - return "$counter $sunit written from database into file $filename"; + return "$counter bytes written from database into file $filename"; } -# import file into database +# import file into database sub _cfgDB_binFileimport($$;$) { my ($filename,$filesize,$doDelete) = @_; $doDelete = (defined($doDelete)) ? 1 : 0; @@ -892,7 +845,7 @@ sub _cfgDB_binFileimport($$;$) { return "$readBytes bytes written from file $filename to database"; } -# show a list containing all file(names) in database +# list all files stored in database sub _cfgDB_Filelist(;$) { my ($notitle) = @_; my $ret = "Files found in database:\n". @@ -916,10 +869,11 @@ sub _cfgDB_Filelist(;$) { # # temporary inserted funktions # for data migration +# and database maintenance # ####################################### -sub _cfgDB_move() { +sub _cfgDB_Move() { my $fhem_dbh = _cfgDB_Connect; my $sth = $fhem_dbh->prepare( "select filename from fhemfilesave group by filename" ); $sth->execute(); @@ -983,7 +937,6 @@ sub _cfgDB_Updatefile($) { return ""; } - 1; =pod