wlcacheddb.cpp

00001 /***************************************************************************
00002  *   Copyright (C) 2004 by Michael Moritz                                  *
00003  *   mimo@restoel.net                                                      *
00004  *                                                                         *
00005  *   This program is free software; you can redistribute it and/or modify  *
00006  *   it under the terms of the GNU General Public License as published by  *
00007  *   the Free Software Foundation; either version 2 of the License, or     *
00008  *   (at your option) any later version.                                   *
00009  *                                                                         *
00010  *   This program is distributed in the hope that it will be useful,       *
00011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00013  *   GNU General Public License for more details.                          *
00014  *                                                                         *
00015  *   You should have received a copy of the GNU General Public License     *
00016  *   along with this program; if not, write to the                         *
00017  *   Free Software Foundation, Inc.,                                       *
00018  *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
00019  ***************************************************************************/
00020 #include <iostream>
00021 #include <syslog.h>
00022 #include <string.h>
00023 #include <algorithm>
00024 #include <cctype>
00025 #include "wlcacheddb.h"
00026 #include "dbdefs.h"
00027 #include "pmatcher.h"
00028 
00029 using namespace std;
00030 
00031 #define WLCACHEDDBDBG   false
00032 #define WLCACHEDMATCHDBG        false
00033 
00034 WlCachedDB::WlCachedDB(class DB& db,
00035                 bool initmode,
00036                 const WLStaticDef& staticDef) throw(std::exception)
00037         : _db(db),
00038           _staticDef(staticDef)
00039 {
00040         if(initmode) {
00041                         _db.createTable(_staticDef);
00042         } //else really
00043         dbi_result result = _db.executeSQL(_staticDef._testTable);
00044         if(!result) //table does not exist, error has been logged
00045                 return;
00046         // this is required in older versions of libdbi -- otherwise no fieldnames
00047         unsigned numrows = dbi_result_get_numrows(result);
00048         if(numrows == 0) {
00049                 dbi_result_free(result);
00050                 return;
00051         }
00052         dbi_result_next_row(result);
00053         unsigned numfields = dbi_result_get_numfields(result);
00054         if(WLCACHEDDBDBG)
00055                 cout << "numfields: " << numfields << endl;
00056         unsigned primaryIdx = numfields;
00057         for(unsigned i=0;i < numfields;i++) {
00058                 const char* colname = dbi_result_get_field_name(result,i+1);
00059                 if(WLCACHEDDBDBG)
00060                         cout << i << ": " << colname << endl;
00061                 if(strcmp(colname,_staticDef._primaryKey) == 0)
00062                         primaryIdx = i;
00063                 else
00064                         _heading.insert(Heading::value_type(colname,i));
00065         }
00066         if(primaryIdx >= numfields) {
00067                 dbi_result_free(result);
00068                 throw runtime_error(string("WlCachedDb no primary idx in table ")+_staticDef._tableName);
00069         }
00070         for(unsigned i=0;i < numrows;i++) {
00071                 string lowerKey( dbi_result_get_string_idx(result,primaryIdx+1) );
00072                 transform( lowerKey.begin(), lowerKey.end(), lowerKey.begin(), ToLower());
00073                 if(WLCACHEDDBDBG)
00074                         cout << "row: " << i << " key: " << lowerKey << endl;
00075                 Entry row;
00076                 for(Heading::const_iterator itr=_heading.begin();itr != _heading.end();++itr) {
00077                         string lowerVal; 
00078                         const char *val = dbi_result_get_string_idx(result,itr->second+1);
00079                         if(val)
00080                                 lowerVal = val;
00081                         else
00082                                 lowerVal = "";
00083                         transform( lowerVal.begin(), lowerVal.end(), lowerVal.begin(), ToLower());
00084                         if(WLCACHEDDBDBG)
00085                                 cout << "idx: " << itr->second << " val: " << val << endl;
00086                         row.insert(Entry::value_type(itr->second,lowerVal));
00087                 }
00088                 _data.insert(Data::value_type("'"+lowerKey+"'",row)); //quote the key, see patternMatch before changig
00089                 if(dbi_result_next_row(result) == 0)
00090                         break;
00091         }
00092         dbi_result_free(result);
00093 }
00094 bool WlCachedDB::check(const class Triplet& triplet) throw(std::exception) 
00095 {
00096         switch(_staticDef._compareMode) {
00097                 case WlModule::CM_exactMatch:
00098                         return exactMatch( "wl", triplet );
00099                 case WlModule::CM_patternMatch:
00100                         return patternMatch( "wl", triplet );
00101                 default:
00102                         return false;
00103         }
00104 }       
00105 bool WlCachedDB::exactMatch(const std::string logprefix,const class Triplet& triplet)
00106 {
00107         //TODO implement for more than one condition
00108         // we suppose that primary = first select where condition
00109         string searchfor = triplet.getMember(_staticDef._compares[0]._tripletMember);
00110         transform( searchfor.begin(), searchfor.end(), searchfor.begin(), ToLower());
00111         if(WLCACHEDMATCHDBG)
00112                 cout << "exactMatch: " << searchfor << endl;
00113         // if we'd use multimap for complex search this has to be changed
00114         Data::const_iterator itr = _data.find(searchfor);
00115         // now we should process other conditions if they contain OR
00116         if( itr == _data.end() ) {
00117                 return false;
00118                 /*
00119                 // check if the first condition is not the primary key
00120                 if(strcmp(_staticDef._compares[0]._compareWith, _staticDef._primaryKey) == 0)
00121                         return false;
00122                 //TODO search through complete table 
00123                 return false;
00124                 */
00125         }
00126         logMatch(logprefix,itr,triplet);
00127         return true;            
00128 }
00129 //TODO cache the complied regexes for subsequent calls
00130 bool WlCachedDB::patternMatch(const std::string logprefix,const class Triplet& triplet)
00131 {
00132         std::string pattern;
00133         try {
00134                 PatternMatcher pmatcher(triplet);
00135                 for(Data::const_iterator itr=_data.begin();itr != _data.end();++itr) {
00136                         //remove leading and trailing quote added in constructor...
00137                         pattern = itr->first.substr(1,itr->first.size()-2);
00138         //              cout << "rex: " << pattern << endl; //<< " 2nd:" << itr->second 
00139                                 if( pmatcher.match(pattern) ) {
00140         //                              cout << "match " << triplet << " ~ "<< pattern << endl;
00141                                         logMatch(logprefix,itr,triplet);
00142                                         return true;
00143                                 }
00144                 }
00145         } catch(exception &e) { //log only if something goes wrong with the regex
00146                 syslog(LOG_ERR,"pattern match failed: '%s' in pattern: %s",
00147                         e.what(),pattern.c_str());
00148         }
00149         return false;
00150 }
00151 void WlCachedDB::logMatch(const std::string& logprefix,Data::const_iterator& itr,const Triplet& triplet) const
00152 {
00153         string strComment = getRowComment(itr);
00154         syslog(LOG_INFO,"%s %s: %s -> %s, %s: %s",
00155                 logprefix.c_str(),_staticDef._tableName,triplet.getSender().c_str(),
00156                 triplet.getRecipient().c_str(),triplet.getClientAddress().c_str(),strComment.c_str());
00157 }
00158 
00159 string WlCachedDB::getRowComment(Data::const_iterator& itr) const
00160 {
00161         string strComment;
00162         Heading::const_iterator cmtitr=_heading.find(_staticDef._commentField);
00163         if( cmtitr == _heading.end() ) {
00164                 strComment = "(comment field not found in table definition, field: " 
00165                         + string(_staticDef._commentField) + ")";
00166         } else {
00167                 Entry::const_iterator eitr = itr->second.find(cmtitr->second);
00168                 if(eitr == itr->second.end())
00169                         strComment = "(comment not found in row)";
00170                 else
00171                         strComment = eitr->second;
00172         }
00173         return strComment;
00174 }
00175 WlCachedDB::~WlCachedDB()
00176 {
00177 }
00178 
00179 

Generated on Tue Jul 24 16:36:54 2007 for gps by  doxygen 1.5.1