- create resolvables (basically bring back old api so we
[platform/upstream/libzypp.git] / zypp / cache / ResolvableQuery.cc
index 0483f40..2aefa90 100644 (file)
@@ -1,4 +1,7 @@
-
+#include <iterator>
+#include <algorithm>
+#include "zypp/base/PtrTypes.h"
+#include "zypp/base/Logger.h"
 #include "zypp/cache/CacheTypes.h"
 #include "zypp/cache/ResolvableQuery.h"
 #include "zypp/Package.h"
 
 using namespace sqlite3x;
 using namespace std;
+using namespace zypp;
 
-namespace zypp { namespace cache {
+typedef shared_ptr<sqlite3_command> sqlite3_command_ptr;
 
+namespace zypp { namespace cache {
 
 struct ResolvableQuery::Impl
 {
   Pathname _dbdir;
   string _fields;
   CacheTypes _type_cache;
-  
+  sqlite3_connection _con;
+  sqlite3_command_ptr _cmd_attr_str;
+  sqlite3_command_ptr _cmd_attr_tstr;
+  sqlite3_command_ptr _cmd_attr_num;
+  sqlite3_command_ptr _cmd_disk_usage;
+  sqlite3_command_ptr _cmd_shared_id;
+
   Impl( const Pathname &dbdir)
   : _dbdir(dbdir)
-    , _type_cache(dbdir)
+  , _type_cache(dbdir)
   {
+    _con.open((dbdir + "zypp.db").asString().c_str());
+    _con.executenonquery("PRAGMA cache_size=8000;");
+
+    _cmd_shared_id.reset( new sqlite3_command( _con, "select shared_id from resolvables where id=:rid;") );
+
+    _cmd_attr_tstr.reset( new sqlite3_command( _con, "select a.text, l.name from text_attributes a,types l,types t where a.weak_resolvable_id=:rid and a.lang_id=l.id and a.attr_id=t.id and l.class=:lclass and t.class=:tclass and t.name=:tname;") );
+
+
+    _cmd_attr_str.reset( new sqlite3_command( _con, "select a.text from text_attributes a,types l,types t where a.weak_resolvable_id=:rid and a.lang_id=l.id and a.attr_id=t.id and l.class=:lclass and l.name=:lname and t.class=:tclass and t.name=:tname;"));
+
+    _cmd_attr_num.reset( new sqlite3_command( _con, "select a.value from numeric_attributes a,types t where a.weak_resolvable_id=:rid and a.attr_id=t.id and t.class=:tclass and t.name=:tname;"));
+
+    _cmd_disk_usage.reset( new sqlite3_command( _con, "select d.name,du.size,du.files from resolvable_disk_usage du,dir_names d where du.resolvable_id=:rid and du.dir_name_id=d.id;"));
+
+    MIL << "Creating Resolvable query impl" << endl;
+    //         0   1     2        3        4      5     6     7               8             9             10          11            12
     _fields = "id, name, version, release, epoch, arch, kind, installed_size, archive_size, install_only, build_time, install_time, repository_id";
   }
 
   ~Impl()
   {
+      MIL << "Destroying Resolvable query impl" << endl;
+  }
+
+  //
+  // convert regex ? and * operators to sql _ and % respectively
+  //  example: regex2sql( "*foo?bar*" ) => "%foo_bar%"
+  // FIXME: take care of ".*" and "."
+  std::string regex2sql( const std::string & s)
+  {
+    std::string sql( s );
+    string::iterator it;
+    for (it = sql.begin(); it != sql.end(); ++it)
+    {
+      if (*it == '*') *it = '%';
+      else if (*it == '?') *it = '_';
+    }
+    return sql;
   }
 
   data::ResObject_Ptr fromRow( sqlite3_reader &reader )
   {
     data::ResObject_Ptr ptr (new data::ResObject);
 
+    // see _fields definition above for the getXXX() numbers
+
     ptr->name = reader.getstring(1);
-    ptr->edition = Edition( reader.getstring(2), reader.getstring(3), reader.getint(4));
+    ptr->edition = Edition( reader.getstring(2), reader.getstring(3), reader.getint(4) );
     ptr->arch = _type_cache.archFor(reader.getint(5));
+    ptr->kind = _type_cache.kindFor( reader.getint(6) );
+    ptr->repository = reader.getint( 12 );
 
     // TODO get the rest of the data
 
     return ptr;
   }
 
-  
+
   void query( const data::RecordId &id,
                   ProcessResolvable fnc )
   {
-    sqlite3_connection con((_dbdir + "zypp.db").asString().c_str());
-    //con.executenonquery("PRAGMA cache_size=8000;");
-    con.executenonquery("BEGIN;");
-    sqlite3_command cmd( con, "select " + _fields + " from resolvables where id=:id;");
+    sqlite3_command cmd( _con, "select " + _fields + " from resolvables where id=:id;");
     cmd.bind(":id", id);
     sqlite3_reader reader = cmd.executereader();
     while(reader.read())
     {
       fnc( id, fromRow(reader) );
     }
-    con.executenonquery("COMMIT;");
   }
 
 
   void query( const std::string &s,
               ProcessResolvable fnc  )
-  {  
-    
-    sqlite3_connection con((_dbdir + "zypp.db").asString().c_str());
-    //con.executenonquery("PRAGMA cache_size=8000;");
-    con.executenonquery("BEGIN;");
-    sqlite3_command cmd( con, "select " + _fields + " from resolvables where name like '%:name%';");
-    cmd.bind(":name", s);
+  {
+
+    sqlite3_command cmd( _con, "select " + _fields + " from resolvables where name like :name;");
+    cmd.bind( ":name", regex2sql( s ) );
     sqlite3_reader reader = cmd.executereader();
     while(reader.read())
     {
       fnc( reader.getint64(0), fromRow(reader) );
     }
-    con.executenonquery("COMMIT;");
   }
 
 
   std::string queryStringAttribute( const data::RecordId &record_id,
                                     const std::string &klass,
-                                    const std::string &name )
+                                    const std::string &name,
+                                    const std::string &default_value )
   {
-    sqlite3_connection con((_dbdir + "zypp.db").asString().c_str());
-    return queryStringAttributeTranslationInternal( con, record_id, Locale(), klass, name);
+    string value;
+    return queryStringAttributeTranslationInternal( _con, record_id, Locale(), klass, name, default_value);
   }
 
 
   std::string queryStringAttributeTranslation( const data::RecordId &record_id,
                                                const Locale &locale,
                                                const std::string &klass,
-                                               const std::string &name )
+                                               const std::string &name,
+                                               const std::string &default_value )
   {
-    sqlite3_connection con((_dbdir + "zypp.db").asString().c_str());
-    return queryStringAttributeTranslationInternal( con, record_id, locale, klass, name );
+    return queryStringAttributeTranslationInternal( _con, record_id, locale, klass, name, default_value );
   }
 
 
   TranslatedText queryTranslatedStringAttribute( const data::RecordId &record_id,
                                                  const std::string &klass,
-                                                 const std::string &name )
+                                                 const std::string &name,
+                                                 const TranslatedText &default_value )
   {
-    sqlite3_connection con((_dbdir + "zypp.db").asString().c_str());
-    return queryTranslatedStringAttributeInternal( con, record_id, klass, name );
+    return queryTranslatedStringAttributeInternal( _con, record_id, klass, name, default_value );
   }
 
 
   bool queryBooleanAttribute( const data::RecordId &record_id,
-                                        const std::string &klass,
-                                        const std::string &name )
+                              const std::string &klass,
+                              const std::string &name,
+                              bool default_value )
+  {
+    return ( queryNumericAttributeInternal( _con, record_id, klass, name, default_value) > 0 );
+  }
+
+  int queryNumericAttribute( const data::RecordId &record_id,
+                             const std::string &klass,
+                             const std::string &name,
+                             int default_value )
   {
-    sqlite3_connection con((_dbdir + "zypp.db").asString().c_str());
-    return ( queryNumericAttributeInternal( con, record_id, klass, name) != 0 );
+    return queryNumericAttributeInternal( _con, record_id, klass, name, default_value);
   }
-      
-  template <class _Container> _Container 
-  queryStringContainerAttribute( const data::RecordId &record_id,
-                                 const std::string &klass,
-                                 const std::string &name )
+
+  void queryDiskUsage( const data::RecordId &record_id, DiskUsage &du )
   {
-    sqlite3_connection con((_dbdir + "zypp.db").asString().c_str());
-    string all = queryStringAttributeInternal( con, record_id, klass, name);
-    _Container words;
-    
-    //
-    //str::split( all, std::inserter(words) );
-    return words;
+    _cmd_disk_usage->bind(":rid", record_id);
+    sqlite3_reader reader = _cmd_disk_usage->executereader();
+
+    while ( reader.read() )
+    {
+      DiskUsage::Entry entry(reader.getstring(0),
+                             reader.getint(1),
+                             reader.getint(2) );
+      du.add(entry);
+    }
   }
-  
-  
-  int queryNumericAttribute( const data::RecordId &record_id,
-                                 const std::string &klass,
-                                 const std::string &name )
+
+  std::string queryRepositoryAlias( const data::RecordId &repo_id )
   {
-    sqlite3_connection con((_dbdir + "zypp.db").asString().c_str());
-    return queryNumericAttributeInternal( con, record_id, klass, name);
+    std::string alias;
+    sqlite3_command cmd( _con, "select alias from repositories where id=:id;" );
+    cmd.bind( ":id", repo_id );
+    sqlite3_reader reader = cmd.executereader();
+    while( reader.read() )
+    {
+      alias = reader.getstring( 0 );
+      break;
+    }
+    return alias;
+  }
+
+  data::RecordId queryRepositoryId( const std::string &repo_alias )
+  {
+    long long id = 0;
+    sqlite3_command cmd( _con, "select id from repositories where alias=:alias;" );
+    cmd.bind( ":alias", repo_alias );
+    sqlite3_reader reader = cmd.executereader();
+    while( reader.read() )
+    {
+      id = reader.getint64(0);
+      break;
+    }
+    return id;
+  }
+
+  void iterateResolvablesByKindsAndStringsAndRepos( const std::vector<zypp::Resolvable::Kind> & kinds,
+                  const std::vector<std::string> &strings, int flags, const std::vector<std::string> repos, ProcessResolvable fnc )
+  {
+    std::string sqlcmd( "SELECT " + _fields + " FROM resolvables" );
+
+    std::vector<std::string>::const_iterator it_s;
+    for (it_s = strings.begin(); it_s != strings.end(); ++it_s)
+    {
+      std::string s( *it_s );
+
+      if (it_s == strings.begin())
+        sqlcmd += " WHERE (";
+      else
+        sqlcmd += " AND ";
+
+//FIXME: Implement MATCH_RESSUMM and MATCH_RESDESC
+
+      sqlcmd += " name ";
+      if ((flags & MATCH_WILDCARDS) == 0)
+      {
+        sqlcmd += "=";
+      }
+      else
+      {
+        sqlcmd += "like";
+        s = regex2sql( s );
+      }
+      if (flags & MATCH_LEADING)
+        s += "%";
+      if (flags & MATCH_TRAILING)
+        s = string("%") + s;
+
+      sqlcmd += " '";
+      sqlcmd += s;
+      sqlcmd += "'";
+    }
+
+    if (it_s != strings.begin())
+    {
+      sqlcmd += ")";
+    }
+
+    std::vector<zypp::Resolvable::Kind>::const_iterator it_k;
+    if (!kinds.empty())
+    {
+      if (it_s == strings.begin())
+        sqlcmd += " WHERE";
+      else
+        sqlcmd += " AND";
+
+      for (it_k = kinds.begin(); it_k != kinds.end(); ++it_k)
+      {
+        if (it_k == kinds.begin())
+         sqlcmd += " kind IN (";
+       else
+          sqlcmd += ", ";
+
+        char idbuf[16];
+        snprintf( idbuf, 15, "%d", (int)(_type_cache.idForKind( *it_k )) );
+        sqlcmd += idbuf;
+      }
+
+      if (it_k != kinds.begin())
+      {
+        sqlcmd += ")";
+      }
+    }
+
+    std::vector<std::string>::const_iterator it_r;
+    if (!repos.empty())
+    {
+      if (it_s == strings.begin()
+         && it_k == kinds.begin())
+        sqlcmd += " WHERE";
+      else
+        sqlcmd += " AND";
+
+      for (it_r = repos.begin(); it_r != repos.end(); ++it_r)
+      {
+        if (it_r == repos.begin())
+         sqlcmd += " (";
+       else
+          sqlcmd += " OR ";
+
+        sqlcmd += "repository_id = ";
+        char idbuf[16];
+        snprintf( idbuf, 15, "%ld", (long)(queryRepositoryId( *it_r )) );
+        sqlcmd += idbuf;
+      }
+
+      if (it_r != repos.begin())
+      {
+        sqlcmd += ")";
+      }
+    }
+
+MIL << "sqlcmd " << sqlcmd << endl;
+    sqlite3_command cmd( _con, sqlcmd );
+    sqlite3_reader reader = cmd.executereader();
+    while(reader.read())
+    {
+      fnc( reader.getint64(0), fromRow(reader) );
+    }
   }
 
 private:
@@ -140,92 +313,138 @@ private:
   int queryNumericAttributeInternal( sqlite3_connection &con,
                                      const data::RecordId &record_id,
                                      const std::string &klass,
-                                     const std::string &name )
+                                     const std::string &name,
+                                     int default_value )
   {
-    con.executenonquery("BEGIN;");
-    sqlite3_command cmd( con, "select a.value from numeric_attributes a,types t where a.weak_resolvable_id=:rid and a.attr_id=t.id and t.class=:tclass and t.name=:tname;");
+    //con.executenonquery("BEGIN;");
+    _cmd_attr_num->bind(":rid", record_id);
 
-    cmd.bind(":rid", record_id);
+    _cmd_attr_num->bind(":tclass", klass);
+    _cmd_attr_num->bind(":tname", name);
 
-    cmd.bind(":tclass", klass);
-    cmd.bind(":tname", name);
+    sqlite3_reader reader = _cmd_attr_num->executereader();
+    if ( reader.read() )
+      return reader.getint(0);
+    else
+    {
+      reader.close();
+      sqlite3_reader idreader = _cmd_shared_id->executereader();
+      if ( idreader.read() )
+      {
+        _cmd_shared_id->bind(":rid", record_id);
+        data::RecordId sid = idreader.getint(0);
+        idreader.close();
+        return queryNumericAttributeInternal(con, sid, klass, name, default_value);
+      }
+    }
 
-    return cmd.executeint();
+    return default_value;
   }
-  
+
   TranslatedText queryTranslatedStringAttributeInternal( sqlite3_connection &con,
                                                          const data::RecordId &record_id,
                                                          const std::string &klass,
-                                                         const std::string &name )
+                                                         const std::string &name,
+                                                         const TranslatedText &default_value )
   {
     //con.executenonquery("PRAGMA cache_size=8000;");
-    con.executenonquery("BEGIN;");
-    sqlite3_command cmd( con, "select a.text, l.name from text_attributes a,types l,types t where a.weak_resolvable_id=:rid and a.lang_id=l.id and a.attr_id=t.id and l.class=:lclass and t.class=:tclass and t.name=:tname;");
+    //con.executenonquery("BEGIN;");
 
-    cmd.bind(":rid", record_id);
-    cmd.bind(":lclass", "lang");
+    _cmd_attr_tstr->bind(":rid", record_id);
+    _cmd_attr_tstr->bind(":lclass", "lang");
 
-    cmd.bind(":tclass", klass);
-    cmd.bind(":tname", name);
+    _cmd_attr_tstr->bind(":tclass", klass);
+    _cmd_attr_tstr->bind(":tname", name);
 
     TranslatedText result;
-    sqlite3_reader reader = cmd.executereader();
+    sqlite3_reader reader = _cmd_attr_tstr->executereader();
+
+    int c = 0;
     while(reader.read())
     {
       result.setText( reader.getstring(0), Locale( reader.getstring(1) ) );
+      c++;
     }
-    return result;
+
+    if ( c>0 )
+      return result;
+    else
+    {
+      reader.close();
+      _cmd_shared_id->bind(":rid", record_id);
+      sqlite3_reader idreader = _cmd_shared_id->executereader();
+      if ( idreader.read() )
+      {
+        data::RecordId sid = idreader.getint(0);
+        idreader.close();
+        return queryTranslatedStringAttributeInternal(con, sid, klass, name, default_value);
+      }
+    }
+
+    return default_value;
   }
 
   std::string queryStringAttributeInternal( sqlite3_connection &con,
                                             const data::RecordId &record_id,
                                             const std::string &klass,
-                                            const std::string &name )
+                                            const std::string &name,
+                                            const std::string &default_value )
   {
-    return queryStringAttributeTranslationInternal( con, record_id, Locale(), klass, name);
+    return queryStringAttributeTranslationInternal( con, record_id, Locale(), klass, name, default_value );
   }
 
   std::string queryStringAttributeTranslationInternal( sqlite3_connection &con,
                                                        const data::RecordId &record_id,
                                                        const Locale &locale,
                                                        const std::string &klass,
-                                                       const std::string &name )
+                                                       const std::string &name,
+                                                        const std::string &default_value )
   {
-    //con.executenonquery("PRAGMA cache_size=8000;");
-    con.executenonquery("BEGIN;");
-    sqlite3_command cmd( con, "select a.text from text_attributes a,types l,types t where a.weak_resolvable_id=:rid and a.lang_id=l.id and a.attr_id=t.id and l.class=:lclass and l.name=:lname and t.class=:tclass and t.name=:tname;");
-
-    cmd.bind(":rid", record_id);
-    cmd.bind(":lclass", "lang");
+    //con.executenonquery("BEGIN;");
+    _cmd_attr_str->bind(":rid", record_id);
+    _cmd_attr_str->bind(":lclass", "lang");
     if (locale == Locale() )
-      cmd.bind(":lname", "none");
+      _cmd_attr_str->bind(":lname", "none");
     else
-      cmd.bind(":lname", locale.code());
+      _cmd_attr_str->bind(":lname", locale.code());
 
-    cmd.bind(":tclass", klass);
-    cmd.bind(":tname", name);
+    _cmd_attr_str->bind(":tclass", klass);
+    _cmd_attr_str->bind(":tname", name);
 
-    return cmd.executestring();
-  }
-};
+    sqlite3_reader reader = _cmd_attr_str->executereader();
 
-template 
-list<string> ResolvableQuery::Impl::queryStringContainerAttribute( const data::RecordId &record_id,
-                                                                   const std::string &klass,
-                                                                   const std::string &name );
+    if ( reader.read() )
+      return reader.getstring(0);
+    else
+    {
+      reader.close();
+      _cmd_shared_id->bind(":rid", record_id);
+      sqlite3_reader idreader = _cmd_shared_id->executereader();
+      if ( idreader.read() )
+      {
+        data::RecordId sid = idreader.getint(0);
+        idreader.close();
+        return queryStringAttributeTranslationInternal( con, sid, locale, klass, name, default_value );
+      }
+    }
 
-template 
-set<string> ResolvableQuery::Impl::queryStringContainerAttribute( const data::RecordId &record_id,
-                                                                  const std::string &klass,
-                                                                  const std::string &name );
+    return default_value;
+  }
+};
 
 //////////////////////////////////////////////////////////////////////////////
 // FORWARD TO IMPLEMENTATION
 //////////////////////////////////////////////////////////////////////////////
 
 ResolvableQuery::ResolvableQuery( const Pathname &dbdir)
-  : _pimpl(new Impl(dbdir))
+  : _pimpl(/*new Impl(dbdir)*/)
+{
+  //MIL << "Creating Resolvable query" << endl;
+}
+
+ResolvableQuery::~ResolvableQuery()
 {
+  //MIL << "Destroying Resolvable query" << endl;
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -246,24 +465,27 @@ void ResolvableQuery::query( const std::string &s, ProcessResolvable fnc  )
 
 int ResolvableQuery::queryNumericAttribute( const data::RecordId &record_id,
                                             const std::string &klass,
-                                            const std::string &name )
+                                            const std::string &name,
+                                            int default_value )
 {
-  return _pimpl->queryNumericAttribute(record_id, klass, name);
+  return _pimpl->queryNumericAttribute(record_id, klass, name, default_value);
 }
 
 bool ResolvableQuery::queryBooleanAttribute( const data::RecordId &record_id,
                                              const std::string &klass,
-                                             const std::string &name )
+                                             const std::string &name,
+                                             bool default_value )
 {
-  return _pimpl->queryNumericAttribute(record_id, klass, name);
+  return _pimpl->queryNumericAttribute(record_id, klass, name, default_value);
 }
 
 
 std::string ResolvableQuery::queryStringAttribute( const data::RecordId &record_id,
                                                    const std::string &klass,
-                                                   const std::string &name )
+                                                   const std::string &name,
+                                                   const std::string &default_value )
 {
-  return _pimpl->queryStringAttribute(record_id, klass, name);
+  return _pimpl->queryStringAttribute(record_id, klass, name, default_value);
 }
 
 //////////////////////////////////////////////////////////////////////////////
@@ -271,43 +493,37 @@ std::string ResolvableQuery::queryStringAttribute( const data::RecordId &record_
 std::string ResolvableQuery::queryStringAttributeTranslation( const data::RecordId &record_id,
                                                               const Locale &locale,
                                                               const std::string &klass,
-                                                              const std::string &name )
+                                                              const std::string &name,
+                                                              const std::string &default_value )
 {
-  return _pimpl->queryStringAttributeTranslation(record_id, locale, klass, name);
+  return _pimpl->queryStringAttributeTranslation(record_id, locale, klass, name, default_value );
 }
 
 //////////////////////////////////////////////////////////////////////////////
 
 TranslatedText ResolvableQuery::queryTranslatedStringAttribute( const data::RecordId &record_id,
                                                                 const std::string &klass,
-                                                                const std::string &name )
+                                                                const std::string &name,
+                                                                const TranslatedText &default_value )
 {
-  return _pimpl->queryTranslatedStringAttribute(record_id, klass, name);
+  return _pimpl->queryTranslatedStringAttribute(record_id, klass, name, default_value );
 }
 
-template<class _Container>
-_Container ResolvableQuery::queryStringContainerAttribute( const data::RecordId &record_id,
-                                                           const std::string &klass,
-                                                           const std::string &name )
+void ResolvableQuery::queryDiskUsage( const data::RecordId &record_id, DiskUsage &du )
 {
-  return _pimpl->queryStringContainerAttribute<_Container>(record_id, klass, name);
+  _pimpl->queryDiskUsage(record_id, du);
 }
 
-template
-std::set<std::string> ResolvableQuery::queryStringContainerAttribute( const data::RecordId &record_id,
-                                                                      const std::string &klass,
-                                                                      const std::string &name );
-
-template
-std::list<std::string> ResolvableQuery::queryStringContainerAttribute( const data::RecordId &record_id,
-                                                                       const std::string &klass,
-                                                                       const std::string &name );
-
-template
-Package::Keywords ResolvableQuery::queryStringContainerAttribute( const data::RecordId &record_id,
-                                                                  const std::string &klass,
-                                                                  const std::string &name );
+std::string ResolvableQuery::queryRepositoryAlias( const data::RecordId &repo_id )
+{
+  return _pimpl->queryRepositoryAlias( repo_id );
+}
 
+void ResolvableQuery::iterateResolvablesByKindsAndStringsAndRepos( const std::vector<zypp::Resolvable::Kind> & kinds,
+                  const std::vector<std::string> &strings, int flags, const std::vector<std::string> &repos, ProcessResolvable fnc )
+{
+  _pimpl->iterateResolvablesByKindsAndStringsAndRepos( kinds, strings, flags, repos, fnc );
+}
 //////////////////////////////////////////////////////////////////////////////
 
 } } // namespace zypp::cache