zypper port starts. zypp2 to zypp
authorDuncan Mac-Vicar P <dmacvicar@suse.de>
Wed, 6 Jun 2007 14:44:54 +0000 (14:44 +0000)
committerDuncan Mac-Vicar P <dmacvicar@suse.de>
Wed, 6 Jun 2007 14:44:54 +0000 (14:44 +0000)
27 files changed:
zypp/CMakeLists.txt
zypp/cache/CacheException.cc [new file with mode: 0644]
zypp/cache/CacheException.h [new file with mode: 0644]
zypp/cache/CacheFSCK.cc [new file with mode: 0644]
zypp/cache/CacheFSCK.h [new file with mode: 0644]
zypp/cache/CacheInitializer.cpp [new file with mode: 0644]
zypp/cache/CacheInitializer.h [new file with mode: 0644]
zypp/cache/CacheStore.cpp [new file with mode: 0644]
zypp/cache/CacheStore.h [new file with mode: 0644]
zypp/cache/CacheTypes.cc [new file with mode: 0644]
zypp/cache/CacheTypes.h [new file with mode: 0644]
zypp/cache/DESIGN-WRITE-API.txt [new file with mode: 0644]
zypp/cache/ResolvableQuery.cc [new file with mode: 0644]
zypp/cache/ResolvableQuery.h [new file with mode: 0644]
zypp/cache/SQLITE3X-README.txt [new file with mode: 0644]
zypp/cache/Utils.cpp [new file with mode: 0644]
zypp/cache/Utils.h [new file with mode: 0644]
zypp/cache/schema/DESIGN-SCHEMA.txt [new file with mode: 0644]
zypp/cache/schema/mkarray.c [new file with mode: 0644]
zypp/cache/schema/schema.sql [new file with mode: 0644]
zypp/cache/sqlite3x/sqlite3x.hpp [new file with mode: 0644]
zypp/cache/sqlite3x/sqlite3x_command.cpp [new file with mode: 0644]
zypp/cache/sqlite3x/sqlite3x_connection.cpp [new file with mode: 0644]
zypp/cache/sqlite3x/sqlite3x_exception.cpp [new file with mode: 0644]
zypp/cache/sqlite3x/sqlite3x_reader.cpp [new file with mode: 0644]
zypp/cache/sqlite3x/sqlite3x_transaction.cpp [new file with mode: 0644]
zypp/cache/sqliteext/zlibext.c [new file with mode: 0644]

index 5b3270a..3500c3a 100644 (file)
@@ -3,6 +3,11 @@
 ####################################################################
 
 ADD_DEFINITIONS(-DLOCALEDIR=\\\"/usr/share/libzypp\\\" -DTEXTDOMAIN=\\\"zypp\\\" )
+ADD_EXECUTABLE(mkarray ${CMAKE_SOURCE_DIR}/zypp/cache/schema/mkarray.c )
+INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
+#FILE(WRITE filename "message to write"... )
+
+ADD_CUSTOM_COMMAND( OUTPUT ${CMAKE_BINARY_DIR}/zypp/sqlite-schema.h PRE_BUILD COMMAND "${CMAKE_BINARY_DIR}/zypp/mkarray" ARGS "${CMAKE_SOURCE_DIR}/zypp/cache/schema/schema.sql" "schemaData" "${CMAKE_BINARY_DIR}/zypp/sqlite-schema.h" DEPENDS mkarray DEPENDS ${CMAKE_SOURCE_DIR}/zypp/cache/schema/schema.sql )
 
 SET( zypp_SRCS
   ZConfig.cc
@@ -81,6 +86,11 @@ SET( zypp_SRCS
   OnMediaLocation.cc
   Fetcher.cc
   FileChecker.cc
+  Repository.cc
+  RepoInfo.cc
+  RepoStatus.cc
+  RepoManager.cc
+  RepositoryFactory.cc
 )
 
 SET( zypp_HEADERS
@@ -178,6 +188,11 @@ SET( zypp_HEADERS
   ZYppCommitResult.h
   ZYppFactory.h
   FileChecker.h
+  Repository.h
+  RepoInfo.h
+  RepoStatus.h
+  RepoManager.h
+  RepositoryFactory.h
 )
 
 INSTALL(  FILES ${zypp_HEADERS} DESTINATION "${CMAKE_INSTALL_PREFIX}/include/zypp" )
@@ -415,6 +430,7 @@ SET( zypp_parser_SRCS
   parser/LibXMLHelper.cc
   parser/SAXParser.cc
   parser/XMLNodeIterator.cc
+  parser/RepoFileReader.cc
 )
 
 SET( zypp_parser_HEADERS
@@ -427,6 +443,7 @@ SET( zypp_parser_HEADERS
   parser/SAXParser.h
   parser/XMLNodeIterator.h
   parser/xml_parser_assert.h
+  parser/RepoFileReader.h
 )
 
 INSTALL(  FILES
@@ -440,6 +457,7 @@ SET( zypp_parser_susetags_SRCS
   parser/susetags/PackagesFileReader.cc
   parser/susetags/PackagesLangFileReader.cc
   parser/susetags/PatternFileReader.cc
+  parser/susetags/RepoParser.cc
 )
 
 SET( zypp_parser_susetags_HEADERS
@@ -450,6 +468,7 @@ SET( zypp_parser_susetags_HEADERS
   parser/susetags/PackagesFileReader.h
   parser/susetags/PackagesLangFileReader.h
   parser/susetags/PatternFileReader.h
+  parser/susetags/RepoParser.h
 )
 
 INSTALL(  FILES
@@ -998,9 +1017,92 @@ INSTALL(  FILES
   DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/zypp_detail
 )
 
+SET( zypp_cache_SRCS
+  ${CMAKE_BINARY_DIR}/zypp/sqlite-schema.h
+  cache/CacheInitializer.cpp
+  cache/CacheException.cc
+  cache/CacheTypes.cc
+  cache/ResolvableQuery.cc
+  cache/CacheStore.cpp
+  cache/CacheFSCK.cc
+  cache/Utils.cpp
+)
+
+SET( zypp_cache_HEADERS
+  cache/CacheTypes.h
+  cache/CacheInitializer.h
+  cache/CacheException.h
+  cache/CacheStore.h
+  cache/CacheFSCK.h
+  cache/ResolvableQuery.h
+  cache/Utils.h
+)
+
+#INSTALL(  FILES
+#  ${zypp_cache_HEADERS}
+#  DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/cache
+#)
+
+SET( zypp_cache_sqlite3x_SRCS
+  cache/sqlite3x/sqlite3x_command.cpp
+  cache/sqlite3x/sqlite3x_connection.cpp
+  cache/sqlite3x/sqlite3x_exception.cpp
+  cache/sqlite3x/sqlite3x_reader.cpp
+  cache/sqlite3x/sqlite3x_transaction.cpp
+)
+
+SET( zypp_cache_sqlite3x_HEADERS
+  cache/sqlite3x/sqlite3x.hpp
+)
+
+#INSTALL(  FILES
+#  ${zypp_cache_sqlite3x_HEADERS}
+#  DESTINATION ${CMAKE_INSTALL_PREFIX}/include/zypp/cache/sqlite3x
+#)
+
+SET( zypp_repository_SRCS
+  repo/dummy.cc
+  repo/RepositoryImpl.cc
+  repo/RepoException.cc
+  repo/RepoType.cc
+)
+
+SET( zypp_repository_HEADERS
+  repo/dummy.h
+  repo/RepositoryImpl.h
+  repo/RepoException.h
+  repo/RepoType.h
+)
+
+SET( zypp_repository_cached_SRCS
+  repo/cached/RepoImpl.cc
+  repo/cached/PackageImpl.cc
+)
+
+SET( zypp_repository_cached_HEADERS
+  repo/cached/RepoImpl.h
+  repo/cached/PackageImpl.h
+)
+
+SET( zypp_repository_data_SRCS
+  repo/memory/PackageImpl.cc
+  repo/memory/PatternImpl.cc
+  repo/memory/ProductImpl.cc
+  repo/memory/SrcPackageImpl.cc
+)
+
+SET( zypp_repository_data_HEADERS
+  repo/memory/PackageImpl.h
+  repo/memory/PatternImpl.h
+  repo/memory/ProductImpl.h
+  repo/memory/SrcPackageImpl.h
+)
+
 SET( zypp_lib_SRCS
 ${zypp_detail_SRCS}
 ${zypp_capability_SRCS}
+${zypp_cache_SRCS}
+${zypp_cache_sqlite3x_SRCS}
 ${zypp_pool_SRCS}
 ${zypp_parser_tagfile_SRCS}
 ${zypp_parser_susetags_SRCS}
@@ -1017,6 +1119,9 @@ ${zypp_data_SRCS}
 ${zypp_media_proxyinfo_SRCS}
 ${zypp_media_SRCS}
 ${zypp_url_SRCS}
+${zypp_repository_SRCS}
+${zypp_repository_cached_SRCS}
+${zypp_repository_data_SRCS}
 ${zypp_target_store_xml_SRCS}
 ${zypp_target_store_SRCS}
 ${zypp_target_rpm_SRCS}
@@ -1039,6 +1144,8 @@ ${zypp_parser_susetags_HEADERS}
 ${zypp_target_rpm_HEADERS}
 ${zypp_parser_yum2_HEADERS}
 ${zypp_capability_HEADERS}
+${zypp_cache_HEADERS}
+${zypp_cache_sqlite3x_HEADERS}
 ${zypp_ui_HEADERS}
 ${zypp_parser_xmlstore_HEADERS}
 ${zypp_data_HEADERS}
@@ -1056,6 +1163,7 @@ ${zypp_parser_HEADERS}
 ${zypp_HEADERS}
 ${zypp_zypp_detail_HEADERS}
 ${zypp_thread_HEADERS}
+${zypp_repository_HEADERS}
 ${zypp_source_susetags_HEADERS}
 ${zypp_target_modalias_HEADERS}
 ${zypp_target_HEADERS}
@@ -1112,6 +1220,7 @@ SET_LOGGROUP( "tagfile" ${zypp_parser_tagfile_SRCS} )
 
 ADD_LIBRARY(zypp SHARED ${zypp_lib_SRCS})
 SET_TARGET_PROPERTIES( zypp PROPERTIES VERSION "${LIBZYPP_VERSION_INFO}" )
+ADD_DEPENDENCIES(zypp schema_header)
 # System libraries
 TARGET_LINK_LIBRARIES(zypp boost_filesystem boost_regex util )
 TARGET_LINK_LIBRARIES(zypp ${DBUS_LIBRARY} )
diff --git a/zypp/cache/CacheException.cc b/zypp/cache/CacheException.cc
new file mode 100644 (file)
index 0000000..bcc049e
--- /dev/null
@@ -0,0 +1,66 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/repo/CacheException.cc
+ *
+*/
+#include <iostream>
+//#include "zypp/base/Logger.h"
+#include "zypp/cache/CacheException.h"
+
+using std::endl;
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////
+  namespace cache
+  { /////////////////////////////////////////////////////////////////
+    ///////////////////////////////////////////////////////////////////
+    //
+    // METHOD NAME : CacheException::CacheException
+    // METHOD TYPE : Ctor
+    //
+    CacheException::CacheException()
+    : Exception( "Cache exception" )
+    {}
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // METHOD NAME : CacheException::CacheException
+    // METHOD TYPE : Ctor
+    //
+    CacheException::CacheException( const std::string & msg_r )
+    : Exception( msg_r )
+    {}
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // METHOD NAME : CacheException::~CacheException
+    // METHOD TYPE : Dtor
+    //
+    CacheException::~CacheException() throw()
+    {}
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // METHOD NAME : CacheException::dumpOn
+    // METHOD TYPE : std::ostream &
+    //
+    std::ostream & CacheException::dumpOn( std::ostream & str ) const
+    {
+      return Exception::dumpOn( str );
+    }
+
+    /////////////////////////////////////////////////////////////////
+  } // namespace repo
+  ///////////////////////////////////////////////////////////////////
+  /////////////////////////////////////////////////////////////////
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
diff --git a/zypp/cache/CacheException.h b/zypp/cache/CacheException.h
new file mode 100644 (file)
index 0000000..8a44183
--- /dev/null
@@ -0,0 +1,57 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+
+#ifndef ZYPP_REPO_REPOEXCEPTION_H
+#define ZYPP_REPO_REPOEXCEPTION_H
+
+#include <iosfwd>
+#include <string>
+
+#include "zypp/base/Exception.h"
+#include "zypp/base/UserRequestException.h"
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////
+  namespace cache
+  { /////////////////////////////////////////////////////////////////
+
+    /**
+     * \short Exception for cache errors
+     */
+    class CacheException : public Exception
+    {
+    public:
+      /** Default ctor */
+      CacheException();
+      /** Ctor */
+      CacheException( const std::string & msg_r );
+        /** Dtor */
+      virtual ~CacheException() throw();
+    protected:
+      virtual std::ostream & dumpOn( std::ostream & str ) const;
+    };
+    ///////////////////////////////////////////////////////////////////
+
+    /**
+     * The record you supplied can't be found
+     */
+    class CacheRecordNotFoundException : public CacheException
+    {
+    
+    };
+    
+    /////////////////////////////////////////////////////////////////
+  } // namespace cache
+  ///////////////////////////////////////////////////////////////////
+  /////////////////////////////////////////////////////////////////
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
+#endif // ZYPP_PARSER_TAGFILE_PARSEEXCEPTION_H
diff --git a/zypp/cache/CacheFSCK.cc b/zypp/cache/CacheFSCK.cc
new file mode 100644 (file)
index 0000000..8c71015
--- /dev/null
@@ -0,0 +1,125 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/cache/CacheFSCK.cc
+ *
+*/
+#include <iostream>
+#include "zypp/base/Logger.h"
+#include "zypp/base/Exception.h"
+#include "zypp/cache/CacheFSCK.h"
+#include "zypp/cache/sqlite3x/sqlite3x.hpp"
+
+using namespace zypp;
+using namespace zypp::cache;
+using namespace std;
+using namespace sqlite3x;
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////
+  namespace cache
+  { /////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // CLASS NAME : CacheFSCK::Impl
+    //
+    /** CacheFSCK implementation. */
+    struct CacheFSCK::Impl
+    {
+
+    public:
+      
+      Impl( const Pathname &dbdir )
+        : _dbdir(dbdir)
+      {
+  
+      }
+      
+      void start()
+      {
+        try
+        {
+          sqlite3_connection con((_dbdir + "zypp.db").asString().c_str());
+          //con.executenonquery("BEGIN;");
+
+          sqlite3_command cmd( con, "PRAGMA integrity_check;");
+          sqlite3_reader reader = cmd.executereader();
+          while(reader.read())
+          {
+            cout << reader.getstring(0) << endl;
+          }
+        }
+        catch( const std::exception &e )
+        {
+          ZYPP_RETHROW(Exception(e.what()));
+        }
+      }
+
+    private:
+      friend Impl * rwcowClone<Impl>( const Impl * rhs );
+      /** clone for RWCOW_pointer */
+      Impl * clone() const
+      { return new Impl( *this ); }
+      
+      Pathname _dbdir;
+    };
+    ///////////////////////////////////////////////////////////////////
+
+    /** \relates CacheFSCK::Impl Stream output */
+    inline std::ostream & operator<<( std::ostream & str, const CacheFSCK::Impl & obj )
+    {
+      return str << "CacheFSCK::Impl";
+    }
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // CLASS NAME : CacheFSCK
+    //
+    ///////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // METHOD NAME : CacheFSCK::CacheFSCK
+    // METHOD TYPE : Ctor
+    //
+    CacheFSCK::CacheFSCK( const Pathname &dbdir )
+    : _pimpl( new Impl(dbdir) )
+    {}
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // METHOD NAME : CacheFSCK::~CacheFSCK
+    // METHOD TYPE : Dtor
+    //
+    CacheFSCK::~CacheFSCK()
+    {}
+
+    void CacheFSCK::start()
+    {
+      _pimpl->start();
+    }
+    
+    /******************************************************************
+    **
+    ** FUNCTION NAME : operator<<
+    ** FUNCTION TYPE : std::ostream &
+    */
+    std::ostream & operator<<( std::ostream & str, const CacheFSCK & obj )
+    {
+      return str << *obj._pimpl;
+    }
+
+    /////////////////////////////////////////////////////////////////
+  } // namespace cache
+  ///////////////////////////////////////////////////////////////////
+  /////////////////////////////////////////////////////////////////
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
diff --git a/zypp/cache/CacheFSCK.h b/zypp/cache/CacheFSCK.h
new file mode 100644 (file)
index 0000000..3bf18e0
--- /dev/null
@@ -0,0 +1,71 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/cache/CacheFSCK.h
+ *
+*/
+#ifndef ZYPP2_CACHE_CACHEFSCK_H
+#define ZYPP2_CACHE_CACHEFSCK_H
+
+#include <iosfwd>
+
+#include "zypp/base/PtrTypes.h"
+#include "zypp/Pathname.h"
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////
+  namespace cache
+  { /////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // CLASS NAME : CacheFSCK
+    //
+    /** 
+     * Check for consistency of the cache
+     **/
+    class CacheFSCK
+    {
+      friend std::ostream & operator<<( std::ostream & str, const CacheFSCK & obj );
+
+    public:
+      /** Implementation  */
+      class Impl;
+
+    public:
+      /**
+       * Default ctor
+       *
+       * \param dbdir Cache directory
+       */
+      CacheFSCK( const Pathname &dbdir );
+      
+      void start();
+      /** Dtor */
+      ~CacheFSCK();
+
+    public:
+
+    private:
+      /** Pointer to implementation */
+      RWCOW_pointer<Impl> _pimpl;
+    };
+    ///////////////////////////////////////////////////////////////////
+
+    /** \relates CacheFSCK Stream output */
+    std::ostream & operator<<( std::ostream & str, const CacheFSCK & obj );
+
+    /////////////////////////////////////////////////////////////////
+  } // namespace cache
+  ///////////////////////////////////////////////////////////////////
+  /////////////////////////////////////////////////////////////////
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
+#endif // ZYPP2_CACHE_CACHEFSCK_H
diff --git a/zypp/cache/CacheInitializer.cpp b/zypp/cache/CacheInitializer.cpp
new file mode 100644 (file)
index 0000000..2ddb4f9
--- /dev/null
@@ -0,0 +1,115 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+
+#include <vector>
+#include <sstream>
+#include <fstream>
+
+#include "zypp/base/Logger.h"
+#include "zypp/base/String.h"
+#include "zypp/base/Measure.h"
+#include "zypp/cache/CacheInitializer.h"
+#include "zypp/target/store/PersistentStorage.h"
+#include "zypp/cache/Utils.h"
+
+#include "sqlite-schema.h"
+
+#define ZYPP_DB_FILE "/var/lib/zypp/zypp.db"
+
+using namespace sqlite3x;
+using namespace std;
+using zypp::debug::Measure;
+
+//////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+namespace cache
+{ /////////////////////////////////////////////////////////////////
+
+struct CacheInitializer::Impl
+{
+  Impl( const Pathname &root_r )
+  : root(root_r), just_initialized(false)
+  {
+  }
+  //typedef std::map<media::MediaNr, media::MediaAccessId> MediaMap
+  shared_ptr<sqlite3x::sqlite3_connection> con;
+  Pathname root;
+  bool just_initialized;
+};
+
+CacheInitializer::CacheInitializer( const Pathname &root_r, const Pathname &db_file )
+  : _pimpl( new Impl( root_r ) )
+{
+  try
+  {
+    _pimpl->con.reset( new sqlite3_connection( ( _pimpl->root + db_file).asString().c_str()) );
+
+    if( ! tablesCreated() )
+    {
+      createTables();
+      _pimpl->just_initialized = true;
+      _pimpl->con->close();
+      MIL << "Source cache initialized" << std::endl;
+    }
+    else
+    {
+      MIL << "Source cache already initialized" << std::endl;
+    }
+  }
+  catch( const exception &ex )
+  {
+    ZYPP_RETHROW(Exception(ex.what()));
+    //ERR << "Exception Occured: " << ex.what() << endl;
+  }
+
+}
+
+bool CacheInitializer::justInitialized() const
+{
+  return _pimpl->just_initialized;
+}
+
+CacheInitializer::~CacheInitializer()
+{
+
+}
+
+bool CacheInitializer::tablesCreated() const
+{
+  Measure timer("Check tables exist");
+  unsigned int count = _pimpl->con->executeint("select count(*) from sqlite_master where type='table';");
+  timer.elapsed();
+  return ( count > 0 );
+}
+
+void CacheInitializer::createTables()
+{
+  Measure timer("Create database tables");
+  MIL << "Initializing cache schema..." << endl;
+  sqlite3_transaction trans(*_pimpl->con);
+  {
+    string sql( schemaData, _schemaData_size);
+    //ERR << "Executing " << statements[i] << endl;
+    MIL << "Schema size: " << sql.size() << endl;
+    _pimpl->con->execute(sql.c_str());
+  }
+  trans.commit();
+  timer.elapsed();
+}
+
+std::ostream & CacheInitializer::dumpOn( std::ostream & str ) const
+{
+  return str;
+}
+
+}
+}
+
diff --git a/zypp/cache/CacheInitializer.h b/zypp/cache/CacheInitializer.h
new file mode 100644 (file)
index 0000000..8cc91cb
--- /dev/null
@@ -0,0 +1,74 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+
+#ifndef ZYPP_CacheInitializer_H
+#define ZYPP_CacheInitializer_H
+
+#include <iosfwd>
+#include <string>
+
+#include "zypp/base/PtrTypes.h"
+#include "zypp/base/ReferenceCounted.h"
+#include "zypp/base/NonCopyable.h"
+#include "zypp/Pathname.h"
+#include "zypp/cache/sqlite3x/sqlite3x.hpp"
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////
+  namespace cache
+  { /////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // CLASS NAME : CacheInitializer
+    //
+    class CacheInitializer
+    {
+      friend std::ostream & operator<<( std::ostream & str, const CacheInitializer & obj );
+
+    public:
+      /**
+       * Tries to initialize the source cache if it was not
+       * \throws Exception When cant initialize
+       */
+      CacheInitializer( const Pathname &root_r, const Pathname &db_file );
+      virtual ~CacheInitializer();
+
+      /**
+       * only true when cache was not initialized before
+       * and was just initialized with success
+       */
+      bool justInitialized() const;
+    protected:
+      bool tablesCreated() const;
+                       void createTables();
+      /** Overload to realize stream output. */
+      virtual std::ostream & dumpOn( std::ostream & str ) const;
+    private:
+       /** Implementation. */
+      class Impl;
+      /** Pointer to implementation. */
+      RW_pointer<Impl> _pimpl;
+    };
+    ///////////////////////////////////////////////////////////////////
+
+    /** \relates CacheInitializer Stream output */
+    inline std::ostream & operator<<( std::ostream & str, const CacheInitializer & obj )
+    { return obj.dumpOn( str ); }
+
+
+    /////////////////////////////////////////////////////////////////
+  } // namespace cache
+  ///////////////////////////////////////////////////////////////////
+  /////////////////////////////////////////////////////////////////
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
+#endif // ZYPP_SOURCE_CacheInitializer_H
diff --git a/zypp/cache/CacheStore.cpp b/zypp/cache/CacheStore.cpp
new file mode 100644 (file)
index 0000000..6a1d5ff
--- /dev/null
@@ -0,0 +1,1036 @@
+
+#include <sqlite3.h>
+#include <map>
+#include "zypp/cache/sqlite3x/sqlite3x.hpp"
+
+#include "zypp/base/Logger.h"
+#include "zypp/base/Measure.h"
+#include "zypp/ZYppFactory.h"
+#include "zypp/ZYpp.h"
+#include "zypp/ZConfig.h"
+
+#include "zypp/cache/CacheInitializer.h"
+#include "zypp/cache/CacheStore.h"
+#include "zypp/cache/CacheException.h"
+
+using namespace std;
+using namespace zypp;
+using namespace zypp::capability;
+using namespace zypp::cache;
+using zypp::data::RecordId;
+using namespace sqlite3x;
+
+using zypp::debug::Measure;
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+namespace cache
+{ /////////////////////////////////////////////////////////////////
+
+typedef shared_ptr<sqlite3_command> sqlite3_command_ptr;
+
+struct CacheStore::Impl
+{
+  Impl( const Pathname &dbdir )
+  : name_cache_hits(0)
+  {
+    cache::CacheInitializer initializer(dbdir, "zypp.db");
+    if ( initializer.justInitialized() )
+    {
+      MIL << "database " << (dbdir + "zypp.db") << " was just created" << endl;
+    }
+
+    try
+    {
+      con.open( (dbdir + "zypp.db").asString().c_str());
+      //_insert_resolvable_cmd = new sqlite3_command( *_con, INSERT_RESOLVABLE_QUERY );
+      //_insert_package_cmd = new sqlite3_command( *_con, INSERT_PACKAGE_QUERY );
+    }
+    catch(exception &ex)
+    {
+      //ZYPP_CAUGHT(ex);
+      ZYPP_THROW(Exception(ex.what()));
+    }
+
+
+    // initialize all pre-compiled statements
+
+    insert_resolvable_in_repository_cmd.reset( new sqlite3_command( con, "insert into resolvables_repositories (resolvable_id, repository_id) values (:resolvable_id, :repository_id);" ));
+
+    update_repository_cmd.reset( new sqlite3_command( con, "update repositories set checksum=:checksum, timestamp=:timestamp where id=:repository_id;" ));
+
+    select_repository_cmd.reset( new sqlite3_command( con, "select id from repositories where alias=:alias;" ));
+    insert_repository_cmd.reset( new sqlite3_command( con, "insert into repositories (alias,timestamp) values (:alias, :timestamp);" ));
+
+    select_name_cmd.reset( new sqlite3_command( con, "select id from names where name=:name;" ));
+    insert_name_cmd.reset( new sqlite3_command( con, "insert into names (name) values (:name);" ));
+
+    select_dirname_cmd.reset( new sqlite3_command( con, "select id from dir_names where name=:name;" ));
+    insert_dirname_cmd.reset( new sqlite3_command( con, "insert into dir_names (name) values (:name);" ));
+
+    select_filename_cmd.reset( new sqlite3_command( con, "select id from file_names where name=:name;" ));
+    insert_filename_cmd.reset( new sqlite3_command( con, "insert into file_names (name) values (:name);" ));
+
+    select_file_cmd.reset( new sqlite3_command( con, "select id from files where dir_name_id=:dir_name_id and file_name_id=:file_name_id;" ));
+    insert_file_cmd.reset( new sqlite3_command( con, "insert into files (dir_name_id,file_name_id) values (:dir_name_id,:file_name_id);" ));
+
+    select_type_cmd.reset( new sqlite3_command( con, "select id from types where class=:class and name=:name;" ));
+    insert_type_cmd.reset( new sqlite3_command( con, "insert into types (class,name) values (:class,:name);" ));
+
+    set_shared_flag_cmd.reset( new sqlite3_command( con, "update resolvables set shared_id=:shared_id where id=:resolvable_id;" ));
+
+    append_text_attribute_cmd.reset( new sqlite3_command( con, "insert into text_attributes ( weak_resolvable_id, lang_id, attr_id, text ) values ( :rid, :lang_id, :attr_id, :text );" ));
+    append_num_attribute_cmd.reset( new sqlite3_command( con, "insert into numeric_attributes ( weak_resolvable_id, attr_id, value ) values ( :rid, :attr_id, :value );" ));
+
+    //insert_dependency_entry_cmd.reset( new sqlite3_command( con, "insert into capabilities ( resolvable_id, dependency_type, refers_kind ) values ( :resolvable_id, :dependency_type, :refers_kind );" ));
+    append_file_dependency_cmd.reset( new sqlite3_command( con, "insert into file_capabilities ( resolvable_id, dependency_type, refers_kind, file_id ) values ( :resolvable_id, :dependency_type, :refers_kind, :file_id );" ));
+    append_named_dependency_cmd.reset( new sqlite3_command( con, "insert into named_capabilities ( resolvable_id, dependency_type, refers_kind, name_id, version, release, epoch, relation ) values ( :resolvable_id, :dependency_type, :refers_kind, :name_id, :version, :release, :epoch, :relation );" ));
+
+    append_modalias_dependency_cmd.reset( new sqlite3_command( con, "insert into modalias_capabilities ( resolvable_id, dependency_type, refers_kind, name, value, relation ) values ( :resolvable_id, :dependency_type, :refers_kind, :name, :value, :relation );" ));
+
+    append_hal_dependency_cmd.reset( new sqlite3_command( con, "insert into hal_capabilities ( resolvable_id, dependency_type, refers_kind, name, value, relation ) values ( :resolvable_id, :dependency_type, :refers_kind, :name, :value, :relation );" ));
+
+    append_other_dependency_cmd.reset( new sqlite3_command( con, "insert into other_capabilities ( resolvable_id, dependency_type, refers_kind, value ) values ( :resolvable_id, :dependency_type, :refers_kind, :value );" ));
+
+    append_resolvable_cmd.reset( new sqlite3_command( con, "insert into resolvables ( name, version, release, epoch, arch, kind, repository_id ) values ( :name, :version, :release, :epoch, :arch, :kind, :repository_id );" ));
+
+    count_shared_cmd.reset( new sqlite3_command( con, "select count(id) from resolvables where shared_id=:rid;" ));
+
+    insert_patchrpm_cmd.reset( new sqlite3_command (con,
+      "insert into patch_packages (media_nr, location, checksum, download_size, build_time) "
+      "values (:media_nr, :location, :checksum, :download_size, :build_time);" ));
+    insert_deltarpm_cmd.reset( new sqlite3_command (con,
+      "insert into delta_packages (media_nr, location, checksum, download_size, build_time, "
+        "baseversion_version, baseversion_release, baseversion_epoch, baseversion_checksum, "
+        "baseversion_build_time, baseversion_sequence_info) "
+      "values (:media_nr, :location, :checksum, :download_size, :build_time, "
+        ":baseversion_version, :baseversion_release, :baseversion_epoch, :baseversion_checksum, "
+        ":baseversion_build_time, :baseversion_sequence_info);" ));
+    append_patch_baseversion_cmd.reset( new sqlite3_command (con,
+      "insert into patch_packages_baseversions (patch_package_id, version, release, epoch) "
+      "values (:patch_package_id, :version, :release, :epoch)" ));
+
+
+    // disable autocommit
+    con.executenonquery("BEGIN;");
+  }
+
+  Impl()
+  {
+    Impl( getZYpp()->homePath() );
+  }
+
+  ~Impl()
+  {
+    MIL << "name cache hits: " << name_cache_hits << " | cache size: " << name_cache.size() << endl;
+  }
+
+ /**
+  * SQL statements
+  * (we precompile them
+  */
+  sqlite3_connection con;
+
+  sqlite3_command_ptr update_repository_cmd;
+  sqlite3_command_ptr insert_resolvable_in_repository_cmd;
+
+  sqlite3_command_ptr select_name_cmd;
+  sqlite3_command_ptr insert_name_cmd;
+
+  sqlite3_command_ptr select_dirname_cmd;
+  sqlite3_command_ptr insert_dirname_cmd;
+
+  sqlite3_command_ptr select_filename_cmd;
+  sqlite3_command_ptr insert_filename_cmd;
+
+  sqlite3_command_ptr select_repository_cmd;
+  sqlite3_command_ptr insert_repository_cmd;
+
+  sqlite3_command_ptr select_file_cmd;
+  sqlite3_command_ptr insert_file_cmd;
+
+  sqlite3_command_ptr select_type_cmd;
+  sqlite3_command_ptr insert_type_cmd;
+
+  //sqlite3_command_ptr insert_dependency_entry_cmd;
+
+  sqlite3_command_ptr append_file_dependency_cmd;
+  sqlite3_command_ptr append_named_dependency_cmd;
+  sqlite3_command_ptr append_modalias_dependency_cmd;
+  sqlite3_command_ptr append_hal_dependency_cmd;
+  sqlite3_command_ptr append_other_dependency_cmd;
+
+  sqlite3_command_ptr append_resolvable_cmd;
+
+  sqlite3_command_ptr append_text_attribute_cmd;
+  sqlite3_command_ptr append_num_attribute_cmd;
+
+  sqlite3_command_ptr set_shared_flag_cmd;
+
+  sqlite3_command_ptr count_shared_cmd;
+
+  sqlite3_command_ptr insert_patchrpm_cmd;
+  sqlite3_command_ptr insert_deltarpm_cmd;
+  sqlite3_command_ptr append_patch_baseversion_cmd;
+
+  map<string, RecordId> name_cache;
+  map< pair<string,string>, RecordId> type_cache;
+  int name_cache_hits;
+};
+
+
+CacheStore::CacheStore( const Pathname &dbdir )
+  : _pimpl( new Impl(dbdir) )
+{
+
+}
+
+CacheStore::CacheStore()
+    : _pimpl( new Impl() )
+{
+
+}
+
+CacheStore::~CacheStore()
+{
+
+}
+
+void CacheStore::commit()
+{
+  _pimpl->con.executenonquery("COMMIT;");
+}
+
+void CacheStore::appendResObjectAttributes( const data::RecordId &rid,
+                                            const data::ResObject_Ptr & res )
+{
+  appendTranslatedStringAttribute( rid, "ResObject", "description", res->description );
+  appendTranslatedStringAttribute( rid, "ResObject", "summary", res->summary );
+  appendNumericAttribute( rid, "ResObject", "installedSize", res->installedSize );
+  appendNumericAttribute( rid, "ResObject", "buildTime", res->buildTime );
+  appendBooleanAttribute( rid, "ResObject", "installOnly", res->installOnly );
+  appendStringAttribute( rid, "ResObject", "vendor", res->vendor );
+  appendTranslatedStringAttribute( rid, "ResObject", "licenseToConfirm", res->licenseToConfirm );
+  appendTranslatedStringAttribute( rid, "ResObject", "insnotify", res->insnotify );
+  appendTranslatedStringAttribute( rid, "ResObject", "delnotify", res->delnotify );
+}
+
+
+void CacheStore::appendPackageBaseAttributes( const RecordId & pkgid,
+                                              const data::Packagebase_Ptr & package )
+{
+  appendStringAttribute( pkgid, "Package", "checksum", package->repositoryLocation.fileChecksum.checksum() );
+  appendStringAttribute( pkgid, "Package", "checksumType", package->repositoryLocation.fileChecksum.type() );
+  appendStringAttribute( pkgid, "Package", "buildhost", package->buildhost );
+  appendStringAttribute( pkgid, "Package", "distribution", package->distribution );
+  appendStringAttribute( pkgid, "Package", "license", package->license );
+  appendStringAttribute( pkgid, "Package", "group", package->packager );
+  appendStringAttribute( pkgid, "Package", "url", package->url );
+  appendStringAttribute( pkgid, "Package", "operatingSystem", package->operatingSystem );
+  appendStringAttribute( pkgid, "Package", "prein", package->prein );
+  appendStringAttribute( pkgid, "Package", "postin", package->postin );
+  appendStringAttribute( pkgid, "Package", "preun", package->preun );
+  appendStringAttribute( pkgid, "Package", "postun", package->postun );
+  appendStringContainerAttribute( pkgid, "Package", "keywords", package->keywords );
+  appendStringContainerAttribute( pkgid, "Package", "authors", package->authors );
+  appendStringAttribute( pkgid, "Package", "location", package->repositoryLocation.filePath.asString() );
+}
+
+void CacheStore::consumePackage( const RecordId & repository_id,
+                                 const data::Package_Ptr & package )
+{
+  RecordId pkgid = appendResolvable( repository_id, ResTraits<Package>::kind,
+      NVRA( package->name, package->edition, package->arch ), package->deps );
+  appendResObjectAttributes( pkgid, package );
+  appendPackageBaseAttributes( pkgid, package );
+}
+
+void CacheStore::consumeSourcePackage( const data::RecordId & repository_id,
+                                       const data::SrcPackage_Ptr & package )
+{
+  RecordId pkgid = appendResolvable( repository_id, ResTraits<SrcPackage>::kind,
+      NVRA( package->name, package->edition, package->arch ), package->deps );
+  appendResObjectAttributes( pkgid, package );
+  appendPackageBaseAttributes( pkgid, package );
+#warning TBD
+}
+
+void CacheStore::consumePatch( const data::RecordId & repository_id,
+                               const data::Patch_Ptr & patch)
+{
+  RecordId id = appendResolvable(
+      repository_id, ResTraits<Patch>::kind,
+      NVRA( patch->name, patch->edition, patch->arch ), patch->deps );
+
+  appendResObjectAttributes( id, patch );
+
+  // patch attributes
+  appendNumericAttribute( id, "Patch", "timestamp",         patch->timestamp );
+  appendStringAttribute(  id, "Patch", "category",          patch->category );
+  appendBooleanAttribute( id, "Patch", "rebootNeeded",      patch->rebootNeeded );
+  appendBooleanAttribute( id, "Patch", "affectsPkgManager", patch->affectsPkgManager );
+
+
+  DBG << "got patch " << patch->name << ", atoms: ";
+  // cosume atoms
+  for (set<data::ResObject_Ptr>::const_iterator p = patch->atoms.begin();
+       p != patch->atoms.end(); ++p)
+  {
+    data::PackageAtom_Ptr atom = dynamic_pointer_cast<data::PackageAtom>(*p);
+    if (atom)
+    {
+      DBG << atom->name << "(atom) ";
+      consumePackageAtom(repository_id, atom);
+      continue;
+    }
+
+    data::Script_Ptr script = dynamic_pointer_cast<data::Script>(*p);
+    if (script)
+    {
+      DBG << script->name << "(script) ";
+      consumeScript(repository_id, script);
+      continue;
+    }
+
+    data::Message_Ptr message = dynamic_pointer_cast<data::Message>(*p);
+    if (message)
+    {
+      DBG << message->name << "(message) ";
+      consumeMessage(repository_id, message);
+      continue;
+    }
+
+    ERR << " ignoring !badatom! ";
+    if (*p) ERR << (*p)->name;
+    ERR << endl;
+  }
+
+  DBG << endl;
+}
+
+void CacheStore::consumePackageAtom( const data::RecordId & repository_id,
+                                     const data::PackageAtom_Ptr & atom )
+{
+  RecordId id = appendResolvable( repository_id, ResTraits<Atom>::kind,
+      NVRA( atom->name, atom->edition, atom->arch ), atom->deps );
+  appendResObjectAttributes( id, atom );
+  appendPackageBaseAttributes( id, atom );
+
+  for (set<data::PatchRpm_Ptr>::const_iterator p = atom->patchRpms.begin();
+       p != atom->patchRpms.end(); ++p)
+    appendPatchRpm(*p);
+
+  for (set<data::DeltaRpm_Ptr>::const_iterator d = atom->deltaRpms.begin();
+       d != atom->deltaRpms.end(); ++d)
+    appendDeltaRpm(*d);
+}
+
+void CacheStore::consumeMessage( const data::RecordId & repository_id,
+                                 const data::Message_Ptr & message )
+{
+  RecordId id = appendResolvable( repository_id, ResTraits<Message>::kind,
+      NVRA( message->name, message->edition, message->arch ), message->deps );
+  appendResObjectAttributes( id, message );
+
+  appendTranslatedStringAttribute( id, "Message", "text", message->text );
+}
+
+void CacheStore::consumeScript( const data::RecordId & repository_id,
+                                const data::Script_Ptr & script )
+{
+  RecordId id = appendResolvable( repository_id, ResTraits<Script>::kind,
+      NVRA( script->name, script->edition, script->arch ), script->deps );
+  appendResObjectAttributes( id, script );
+
+  appendStringAttribute( id, "Script", "doScript", script->doScript );
+  appendStringAttribute( id, "Script", "doScriptLocation", script->doScriptLocation.filePath.asString() );
+  appendStringAttribute( id, "Script", "doScriptChecksum", script->doScriptLocation.fileChecksum.checksum() );
+  appendStringAttribute( id, "Script", "doScriptChecksumType", script->doScriptLocation.fileChecksum.type() );
+  appendStringAttribute( id, "Script", "undoScript", script->undoScript );
+  appendStringAttribute( id, "Script", "undoScriptLocation", script->undoScriptLocation.filePath.asString() );
+  appendStringAttribute( id, "Script", "undoScriptChecksum", script->undoScriptLocation.fileChecksum.checksum() );
+  appendStringAttribute( id, "Script", "undoScriptChecksumType", script->undoScriptLocation.fileChecksum.type() );
+}
+
+void CacheStore::consumePattern( const data::RecordId & repository_id,
+                                 const data::Pattern_Ptr & pattern )
+{
+  RecordId id = appendResolvable( repository_id, ResTraits<Pattern>::kind,
+      NVRA( pattern->name, pattern->edition, pattern->arch ), pattern->deps );
+  appendResObjectAttributes( id, pattern );
+
+  appendBooleanAttribute( id, "Pattern", "isDefault", pattern->isDefault );
+  appendBooleanAttribute( id, "Pattern", "userVisible", pattern->userVisible );
+  appendTranslatedStringAttribute( id, "Pattern", "category", pattern->category );
+  appendStringAttribute( id, "Pattern", "icon", pattern->icon );
+  appendStringAttribute( id, "Pattern", "order", pattern->order );
+}
+
+void CacheStore::consumeProduct( const data::RecordId & repository_id,
+                                 const data::Product_Ptr & product )
+{
+  RecordId id = appendResolvable( repository_id, ResTraits<Product>::kind,
+      NVRA( product->name, product->edition, product->arch ), product->deps );
+  appendResObjectAttributes( id, product );
+
+  appendTranslatedStringAttribute( id, "Product", "shortName", product->shortName );
+  appendTranslatedStringAttribute( id, "Product", "longName", product->longName );
+  appendStringContainerAttribute( id, "Product", "flags", product->flags );
+  appendStringAttribute( id, "Pattern", "releasenotesUrl", product->releasenotesUrl.asString() );
+  //! \todo figure out how to store list of Urls. A separate method appendUrlContainerAttribute? Or change it to plain string in ResolvableData.h?
+//  appendStringContainerAttribute( id, "Product", "updateUrls", product->updateUrls );
+//  appendStringContainerAttribute( id, "Product", "extraUrls", product->extraUrls );
+//  appendStringContainerAttribute( id, "Product", "optionalUrls", product->optionalUrls );
+  appendStringAttribute( id, "Pattern", "distributionName", product->distributionName );
+  appendStringAttribute( id, "Pattern", "distributionEdition", product->distributionEdition.asString() );
+}
+
+void CacheStore::consumeChangelog( const data::RecordId & repository_id,
+                                   const data::Resolvable_Ptr & resolvable,
+                                   const Changelog & changelog )
+{
+  //! \todo maybe appendChangelog(const data::RecordId & resolvable_id, Changelog changelog) will be needed
+  //! for inserting the changelog using in-memory record id of corresponding resolvable.
+  //! (first, we'll see how fast is the inserting without remembering those ids)
+}
+
+void CacheStore::consumeFilelist( const data::RecordId & repository_id,
+                                  const data::Resolvable_Ptr & resolvable,
+                                  const data::Filenames & filenames )
+{
+  //! \todo maybe consumeFilelist(const data::RecordId & resolvable_id, data::Filenames &) will be needed
+}
+
+RecordId CacheStore::appendResolvable( const RecordId &repository_id,
+                                       const Resolvable::Kind &kind,
+                                       const NVRA &nvra,
+                                       const data::Dependencies &deps )
+{
+  _pimpl->append_resolvable_cmd->bind( ":name", nvra.name );
+  _pimpl->append_resolvable_cmd->bind( ":version", nvra.edition.version() );
+  _pimpl->append_resolvable_cmd->bind( ":release", nvra.edition.release() );
+  _pimpl->append_resolvable_cmd->bind( ":epoch", static_cast<int>( nvra.edition.epoch() ) );
+  _pimpl->append_resolvable_cmd->bind( ":arch", lookupOrAppendType("arch", nvra.arch.asString()) );
+  _pimpl->append_resolvable_cmd->bind( ":kind", lookupOrAppendType("kind", kind.asString()) );
+  _pimpl->append_resolvable_cmd->bind( ":repository_id", repository_id );
+
+  _pimpl->append_resolvable_cmd->executenonquery();
+
+  long long id = _pimpl->con.insertid();
+
+  appendDependencies( id, deps );
+  /*
+  _pimpl->insert_resolvable_in_repository_cmd->bind(":repository_id", repository_id);
+  _pimpl->insert_resolvable_in_repository_cmd->bind(":resolvable_id", id);
+  _pimpl->insert_resolvable_in_repository_cmd->executenonquery();*/
+
+  return static_cast<RecordId>(id);
+  return 1;
+}
+
+void CacheStore::appendDependencies( const RecordId &resolvable_id, const data::Dependencies &deps )
+{
+  for ( data::Dependencies::const_iterator it = deps.begin(); it != deps.end(); ++it )
+  {
+    appendDependencyList( resolvable_id, it->first, it->second );
+  }
+}
+
+void CacheStore::appendDependencyList( const RecordId &resolvable_id, zypp::Dep deptype, const data::DependencyList &caps )
+{
+  for ( data::DependencyList::const_iterator it = caps.begin(); it != caps.end(); ++it )
+  {
+    appendDependency( resolvable_id, deptype, *it );
+  }
+}
+
+void CacheStore::appendDependency( const RecordId &resolvable_id, zypp::Dep deptype, capability::CapabilityImpl::Ptr cap )
+{
+  if ( cap == 0 )
+  {
+    DBG << "invalid capability" << endl;
+    return;
+  }
+
+  if ( capability::isKind<NamedCap>(cap) )
+  {
+      appendNamedDependency( resolvable_id, deptype, capability::asKind<NamedCap>(cap) );
+  }
+  else if ( capability::isKind<FileCap>(cap) )
+  {
+    appendFileDependency( resolvable_id, deptype, capability::asKind<FileCap>(cap) );
+    return;
+  }
+  else if ( capability::isKind<ModaliasCap>(cap) )
+  {
+      appendModaliasDependency( resolvable_id, deptype, capability::asKind<ModaliasCap>(cap) );
+  }
+  else if ( capability::isKind<HalCap>(cap) )
+  {
+      appendHalDependency( resolvable_id, deptype, capability::asKind<HalCap>(cap) );
+  }
+  else
+  {
+      appendUnknownDependency( resolvable_id, deptype, cap );
+  }
+}
+
+// RecordId CacheStore::lookupOrAppendNamedDependencyEntry( const RecordId name_id, const Edition &edition, const zypp::Rel &rel )
+// {
+//   _pimpl->select_named_dependency_cmd->bind( ":name_id", name_id);
+//   _pimpl->select_named_dependency_cmd->bind( ":version", edition.version() );
+//   _pimpl->select_named_dependency_cmd->bind( ":release", edition.release() );
+//   _pimpl->select_named_dependency_cmd->bind( ":epoch", static_cast<int>( edition.epoch() ) );
+//   _pimpl->select_named_dependency_cmd->bind( ":relation", zypp_rel2db_rel( rel ) );
+//   long long id = 0;
+//   try {
+//     id = _pimpl->select_named_dependency_cmd->executeint64();
+//   }
+//   catch ( const sqlite3x::database_error &e )
+//   {
+//     // does not exist
+//     _pimpl->append_named_dependency_entry_cmd->bind( ":name_id", name_id);
+//     _pimpl->append_named_dependency_entry_cmd->bind( ":version", edition.version() );
+//     _pimpl->append_named_dependency_entry_cmd->bind( ":release", edition.release() );
+//     _pimpl->append_named_dependency_entry_cmd->bind( ":epoch", static_cast<int>( edition.epoch() ) );
+//     _pimpl->append_named_dependency_entry_cmd->bind( ":relation", zypp_rel2db_rel( rel ) );
+//     _pimpl->append_named_dependency_entry_cmd->executenonquery();
+//     id = _pimpl->con.insertid();
+//     return static_cast<RecordId>(id);
+//   }
+//   return static_cast<RecordId>(id);
+// }
+
+void CacheStore::appendNamedDependency( const RecordId &resolvable_id, zypp::Dep deptype, capability::NamedCap::Ptr cap )
+{
+  if ( !cap )
+    ZYPP_THROW(Exception("bad versioned dep"));
+  //DBG << "versioned : " << cap << endl;
+
+  //RecordId capability_id = appendDependencyEntry( resolvable_id, deptype, cap->refers() );
+  RecordId name_id = lookupOrAppendName(cap->name());
+
+  _pimpl->append_named_dependency_cmd->bind( ":resolvable_id", resolvable_id );
+  _pimpl->append_named_dependency_cmd->bind( ":dependency_type", lookupOrAppendType("deptype", deptype.asString()) );
+  _pimpl->append_named_dependency_cmd->bind( ":refers_kind", lookupOrAppendType("kind", cap->refers().asString()) );
+
+  //_pimpl->append_named_dependency_cmd->bind( ":capability_id", capability_id);
+  _pimpl->append_named_dependency_cmd->bind( ":name_id", name_id);
+  _pimpl->append_named_dependency_cmd->bind( ":version", cap->edition().version() );
+  _pimpl->append_named_dependency_cmd->bind( ":release", cap->edition().release() );
+  _pimpl->append_named_dependency_cmd->bind( ":epoch", static_cast<int>( cap->edition().epoch() ) );
+  _pimpl->append_named_dependency_cmd->bind( ":relation", lookupOrAppendType("rel", cap->op().asString()) );
+  _pimpl->append_named_dependency_cmd->executenonquery();
+
+  //delete cmd;
+}
+
+void CacheStore::appendModaliasDependency( const RecordId &resolvable_id,
+                                                 zypp::Dep deptype,
+                                                 capability::ModaliasCap::Ptr cap )
+{
+  if ( !cap )
+    ZYPP_THROW(Exception("Null modalias capability"));
+
+  _pimpl->append_modalias_dependency_cmd->bind( ":resolvable_id", resolvable_id );
+  _pimpl->append_modalias_dependency_cmd->bind( ":dependency_type", lookupOrAppendType("deptype", deptype.asString()) );
+  _pimpl->append_modalias_dependency_cmd->bind( ":refers_kind", lookupOrAppendType("kind", cap->refers().asString()) );
+
+  //_pimpl->append_modalias_dependency_cmd->bind( ":capability_id", capability_id);
+  _pimpl->append_modalias_dependency_cmd->bind( ":name", cap->name());
+  _pimpl->append_modalias_dependency_cmd->bind( ":value", cap->value());
+  _pimpl->append_modalias_dependency_cmd->bind( ":relation", lookupOrAppendType("rel", cap->op().asString()) );
+
+  _pimpl->append_modalias_dependency_cmd->executenonquery();
+  //delete cmd;
+}
+
+void CacheStore::appendHalDependency( const RecordId &resolvable_id,
+                                                 zypp::Dep deptype,
+                                                 capability::HalCap::Ptr cap )
+{
+  if ( !cap )
+    ZYPP_THROW(Exception("Null HAL capability"));
+
+  _pimpl->append_hal_dependency_cmd->bind( ":resolvable_id", resolvable_id );
+  _pimpl->append_hal_dependency_cmd->bind( ":dependency_type", lookupOrAppendType("deptype", deptype.asString()) );
+  _pimpl->append_hal_dependency_cmd->bind( ":refers_kind", lookupOrAppendType("kind", cap->refers().asString()) );
+
+  //_pimpl->append_hal_dependency_cmd->bind( ":capability_id", capability_id);
+  _pimpl->append_hal_dependency_cmd->bind( ":name", cap->name());
+  _pimpl->append_hal_dependency_cmd->bind( ":value", cap->value());
+  _pimpl->append_hal_dependency_cmd->bind( ":relation", lookupOrAppendType("rel", cap->op().asString()) );
+
+  _pimpl->append_hal_dependency_cmd->executenonquery();
+  //delete cmd;
+}
+
+void CacheStore::appendFileDependency( const RecordId &resolvable_id, zypp::Dep deptype,
+                                       capability::FileCap::Ptr cap )
+{
+  if ( !cap )
+    ZYPP_THROW(Exception("Null file capability"));
+
+  //RecordId capability_id = appendDependencyEntry( resolvable_id, deptype, cap->refers() );
+  RecordId file_id = lookupOrAppendFile(cap->filename());
+
+  _pimpl->append_file_dependency_cmd->bind( ":resolvable_id", resolvable_id );
+  _pimpl->append_file_dependency_cmd->bind( ":dependency_type", lookupOrAppendType("deptype", deptype.asString()) );
+  _pimpl->append_file_dependency_cmd->bind( ":refers_kind", lookupOrAppendType("kind", cap->refers().asString()) );
+
+  //_pimpl->append_file_dependency_cmd->bind( ":capability_id", capability_id);
+  _pimpl->append_file_dependency_cmd->bind( ":file_id", file_id);
+
+  _pimpl->append_file_dependency_cmd->executenonquery();
+  //delete cmd;
+}
+
+void CacheStore::appendUnknownDependency( const RecordId &resolvable_id,
+                                               zypp::Dep deptype,
+                                               capability::CapabilityImpl::Ptr cap )
+{
+  if ( !cap )
+    ZYPP_THROW(Exception("Null unknown capability"));
+
+  _pimpl->append_other_dependency_cmd->bind( ":resolvable_id", resolvable_id );
+  _pimpl->append_other_dependency_cmd->bind( ":dependency_type", lookupOrAppendType("deptype", deptype.asString()) );
+  _pimpl->append_other_dependency_cmd->bind( ":refers_kind", lookupOrAppendType("kind", cap->refers().asString()) );
+  _pimpl->append_other_dependency_cmd->bind( ":value", cap->encode());
+
+  _pimpl->append_hal_dependency_cmd->executenonquery();
+  //delete cmd;
+}
+
+
+/** \todo lookupOrAppend ? */
+RecordId CacheStore::appendPatchRpm(const data::PatchRpm_Ptr & prpm)
+{
+  RecordId id;
+
+  //! \todo what's this? _pimpl->insert_patchrpm_cmd->bind(":media_nr", ???);
+  _pimpl->insert_patchrpm_cmd->bind(":location", prpm->location.filePath.asString());
+  _pimpl->insert_patchrpm_cmd->bind(":checksum", prpm->location.fileChecksum.checksum());
+  //! \todo checksum type
+  _pimpl->insert_patchrpm_cmd->bind(":download_size", static_cast<ByteCount::SizeType>(prpm->location.fileSize));
+  _pimpl->insert_patchrpm_cmd->bind(":build_time", prpm->buildTime.asSeconds());
+  _pimpl->insert_patchrpm_cmd->executenonquery();
+
+  id = _pimpl->con.insertid();
+
+  for (set<data::BaseVersion_Ptr>::const_iterator bv = prpm->baseVersions.begin();
+       bv != prpm->baseVersions.end(); ++bv)
+  {
+    _pimpl->append_patch_baseversion_cmd->bind(":patch_package_id", id);
+    _pimpl->append_patch_baseversion_cmd->bind(":version", (*bv)->edition.version());
+    _pimpl->append_patch_baseversion_cmd->bind(":release", (*bv)->edition.release());
+    _pimpl->append_patch_baseversion_cmd->bind(":epoch", (int) (*bv)->edition.epoch());
+    _pimpl->append_patch_baseversion_cmd->executenonquery();
+  }
+  return id;
+}
+
+
+/** \todo lookupOrAppend ? */
+RecordId CacheStore::appendDeltaRpm(const data::DeltaRpm_Ptr & drpm)
+{
+  RecordId id;
+
+  //! \todo what's this? _pimpl->insert_deltarpm_cmd->bind(":media_nr", ???);
+  _pimpl->insert_deltarpm_cmd->bind(":location", drpm->location.filePath.asString());
+  _pimpl->insert_deltarpm_cmd->bind(":checksum", drpm->location.fileChecksum.checksum());
+  //! \todo checksum type
+  _pimpl->insert_deltarpm_cmd->bind(":download_size", static_cast<ByteCount::SizeType>(drpm->location.fileSize));
+  _pimpl->insert_deltarpm_cmd->bind(":build_time", drpm->buildTime.asSeconds());
+
+  _pimpl->insert_deltarpm_cmd->bind(":baseversion_version", drpm->baseVersion.edition.version());
+  _pimpl->insert_deltarpm_cmd->bind(":baseversion_release", drpm->baseVersion.edition.release());
+  _pimpl->insert_deltarpm_cmd->bind(":baseversion_epoch", (int) drpm->baseVersion.edition.epoch());
+  _pimpl->insert_deltarpm_cmd->bind(":baseversion_build_time", drpm->baseVersion.buildTime.asSeconds());
+  _pimpl->insert_deltarpm_cmd->bind(":baseversion_checksum", drpm->baseVersion.checkSum.checksum());
+  _pimpl->insert_deltarpm_cmd->bind(":baseversion_sequence_info", drpm->baseVersion.sequenceInfo);
+
+  _pimpl->insert_deltarpm_cmd->executenonquery();
+  id = _pimpl->con.insertid();
+
+  return id;
+}
+
+
+// RecordId CacheStore::appendDependencyEntry( const RecordId &resolvable_id, zypp::Dep deptype, const Resolvable::Kind &refers )
+// {
+//   //DBG << "rid: " << resolvable_id << " deptype: " << deptype << " " << "refers: " << refers << endl;
+//   _pimpl->insert_dependency_entry_cmd->bind( ":resolvable_id", resolvable_id );
+//
+//   db::DependencyType dt = zypp_deptype2db_deptype(deptype);
+//   if ( dt == db::DEP_TYPE_UNKNOWN )
+//   {
+//     ZYPP_THROW(Exception("Unknown depenency type"));
+//   }
+//
+//   _pimpl->insert_dependency_entry_cmd->bind( ":dependency_type", zypp_deptype2db_deptype(deptype) );
+//   _pimpl->insert_dependency_entry_cmd->bind( ":refers_kind", zypp_kind2db_kind(refers) );
+//
+//   _pimpl->insert_dependency_entry_cmd->executenonquery();
+//   //delete cmd;
+//   long long id = _pimpl->con.insertid();
+//   return static_cast<RecordId>(id);
+// }
+
+RecordId CacheStore::lookupOrAppendFile( const Pathname &path )
+{
+  RecordId dir_name_id = lookupOrAppendDirName(path.dirname().asString());
+  RecordId file_name_id = lookupOrAppendFileName(path.basename());
+
+  _pimpl->select_file_cmd->bind(":dir_name_id", dir_name_id);
+  _pimpl->select_file_cmd->bind(":file_name_id", file_name_id);
+  long long id = 0;
+  try {
+    id = _pimpl->select_file_cmd->executeint64();
+  }
+  catch ( const sqlite3x::database_error &e )
+  {
+    // does not exist
+    _pimpl->insert_file_cmd->bind(":dir_name_id", dir_name_id);
+    _pimpl->insert_file_cmd->bind(":file_name_id", file_name_id);
+    _pimpl->insert_file_cmd->executenonquery();
+    id = _pimpl->con.insertid();
+    return static_cast<RecordId>(id);
+
+  }
+  return static_cast<RecordId>(id);
+}
+
+void CacheStore::updateRepository( const RecordId &id,
+                    const string &checksum,
+                    const Date &timestamp )
+{
+  _pimpl->update_repository_cmd->bind(":repository_id", id);
+  _pimpl->update_repository_cmd->bind(":checksum", checksum);
+  _pimpl->update_repository_cmd->bind(":timestamp", static_cast<int>((Date::ValueType) timestamp) );
+  _pimpl->insert_repository_cmd->executenonquery();
+}
+
+RecordId CacheStore::lookupOrAppendRepository( const string &alias )
+{
+  _pimpl->select_repository_cmd->bind(":alias", alias);
+  
+  long long id = 0;
+  try {
+    id = _pimpl->select_repository_cmd->executeint64();
+  }
+  catch ( const sqlite3x::database_error &e )
+  {
+    // does not exist
+    _pimpl->insert_repository_cmd->bind(":alias", alias);
+    _pimpl->insert_repository_cmd->bind(":timestamp", static_cast<int>((Date::ValueType) Date::now()) );
+    _pimpl->insert_repository_cmd->executenonquery();
+    id = _pimpl->con.insertid();
+    return static_cast<RecordId>(id);
+
+  }
+  return static_cast<RecordId>(id);
+}
+
+void CacheStore::cleanRepository( const data::RecordId &id )
+{
+  sqlite3_command cmd( _pimpl->con, "delete from repositories where id=:id");
+  cmd.bind(":id", id);
+  
+  try
+  {
+    cmd.executenonquery();
+  }
+  catch ( const sqlite3x::database_error &e )
+  {
+    ZYPP_THROW(CacheRecordNotFoundException());
+  }
+}
+      
+void CacheStore::cleanRepository( const std::string &alias )
+{
+  cleanRepository(lookupRepository(alias));
+}
+
+RepoStatus CacheStore::repositoryStatus( const data::RecordId &id )
+{
+  sqlite3_command cmd( _pimpl->con, "select id,alias,checksum,timestamp from repositories where id=:id");
+  cmd.bind(":id", id);
+  
+  try
+  {
+    sqlite3_reader reader = cmd.executereader();
+    RepoStatus status;
+    while ( reader.read() )
+    {
+      status.setChecksum( reader.getstring(2) );
+      status.setTimestamp( reader.getstring(3) );
+    }
+    return status;
+  }
+  catch ( const sqlite3x::database_error &e )
+  {
+    ZYPP_THROW(CacheRecordNotFoundException());
+  }
+}
+
+RepoStatus CacheStore::repositoryStatus( const string &alias )
+{
+  return repositoryStatus(lookupRepository(alias));
+}
+
+bool CacheStore::isCached( const string &alias )
+{
+  try
+  {
+    lookupRepository(alias);
+  }
+  catch( const CacheRecordNotFoundException &e )
+  {
+    return false;
+  }
+  
+  return true;
+}
+
+RecordId CacheStore::lookupRepository( const string &alias )
+{
+  sqlite3_command cmd(_pimpl->con, "select id from repositories where alias=:alias;");
+  cmd.bind(":alias", alias);
+  
+  long long id = 0;
+  try {
+    id = cmd.executeint64();
+  }
+  catch ( const sqlite3x::database_error &e )
+  {
+    ZYPP_THROW(CacheRecordNotFoundException());
+  }
+  return id;
+}
+
+RecordId CacheStore::lookupOrAppendType( const string &klass, const string &name )
+{
+  pair<string, string> thetype = make_pair(klass,name);
+  if ( _pimpl->type_cache.find(thetype) != _pimpl->type_cache.end() )
+  {
+    //_pimpl->name_cache_hits++;
+    return _pimpl->type_cache[thetype];
+  }
+
+  _pimpl->select_type_cmd->bind(":class", klass);
+  _pimpl->select_type_cmd->bind(":name", name);
+  long long id = 0;
+  try {
+    id = _pimpl->select_type_cmd->executeint64();
+    _pimpl->type_cache[thetype] = id;
+  }
+  catch ( const sqlite3x::database_error &e )
+  {
+    // does not exist
+    _pimpl->insert_type_cmd->bind(":class", klass);
+    _pimpl->insert_type_cmd->bind(":name", name);
+    _pimpl->insert_type_cmd->executenonquery();
+    id = _pimpl->con.insertid();
+    return id;
+  }
+  return id;
+}
+
+RecordId CacheStore::lookupOrAppendName( const string &name )
+{
+  if ( _pimpl->name_cache.find(name) != _pimpl->name_cache.end() )
+  {
+    _pimpl->name_cache_hits++;
+    return _pimpl->name_cache[name];
+  }
+
+  _pimpl->select_name_cmd->bind(":name", name);
+  long long id = 0;
+  try {
+    id = _pimpl->select_name_cmd->executeint64();
+    _pimpl->name_cache[name] = id;
+  }
+  catch ( const sqlite3x::database_error &e )
+  {
+    // does not exist
+    _pimpl->insert_name_cmd->bind(":name", name);
+    _pimpl->insert_name_cmd->executenonquery();
+    id = _pimpl->con.insertid();
+    return static_cast<RecordId>(id);
+
+  }
+  return static_cast<RecordId>(id);
+}
+
+RecordId CacheStore::lookupOrAppendDirName( const string &name )
+{
+  _pimpl->select_dirname_cmd->bind(":name", name);
+  long long id = 0;
+  try {
+    id = _pimpl->select_dirname_cmd->executeint64();
+  }
+  catch ( const sqlite3x::database_error &e )
+  {
+    // does not exist
+    _pimpl->insert_dirname_cmd->bind(":name", name);
+    _pimpl->insert_dirname_cmd->executenonquery();
+    id = _pimpl->con.insertid();
+    return static_cast<RecordId>(id);
+
+  }
+  return static_cast<RecordId>(id);
+}
+
+RecordId CacheStore::lookupOrAppendFileName( const string &name )
+{
+  _pimpl->select_filename_cmd->bind(":name", name);
+  long long id = 0;
+  try {
+    id = _pimpl->select_filename_cmd->executeint64();
+  }
+  catch ( const sqlite3x::database_error &e )
+  {
+    // does not exist
+    _pimpl->insert_filename_cmd->bind(":name", name);
+    _pimpl->insert_filename_cmd->executenonquery();
+    id = _pimpl->con.insertid();
+    return static_cast<RecordId>(id);
+
+  }
+  return static_cast<RecordId>(id);
+}
+
+void CacheStore::setSharedData( const data::RecordId &resolvable_id,
+                                const data::RecordId &shared_id )
+{
+  _pimpl->set_shared_flag_cmd->bind(":resolvable_id", resolvable_id);
+
+  if ( shared_id == data::noRecordId )
+   _pimpl->set_shared_flag_cmd->bind(":shared_id");
+  else
+   _pimpl->set_shared_flag_cmd->bind(":shared_id", shared_id);
+
+  _pimpl->set_shared_flag_cmd->executenonquery();
+}
+
+void CacheStore::appendBooleanAttribute( const data::RecordId & resolvable_id,
+                                         const std::string & klass,
+                                         const std::string & name,
+                                         bool value)
+{
+  RecordId type_id = lookupOrAppendType( klass, name );
+  appendNumericAttribute( resolvable_id, type_id, value ? 1 : 0 );
+}
+
+void CacheStore::appendNumericAttribute( const data::RecordId &resolvable_id,
+                                         const std::string &klass,
+                                         const std::string &name,
+                                         int value )
+{
+  RecordId type_id = lookupOrAppendType( klass, name );
+  appendNumericAttribute( resolvable_id, type_id, value );
+}
+
+void CacheStore::appendNumericAttribute( const RecordId &resolvable_id,
+                                         const RecordId &type_id,
+                                         int value )
+{
+  // weak resolvable_id
+  _pimpl->append_num_attribute_cmd->bind(":rid", resolvable_id );
+  _pimpl->append_num_attribute_cmd->bind(":attr_id", type_id );
+
+  _pimpl->append_num_attribute_cmd->bind(":value", value );
+
+  _pimpl->append_num_attribute_cmd->executenonquery();
+}
+
+
+void CacheStore::appendTranslatedStringAttribute( const data::RecordId &resolvable_id,
+                                                  const std::string &klass,
+                                                  const std::string &name,
+                                                  const TranslatedText &text )
+{
+  set<Locale> locales = text.locales();
+  for ( set<Locale>::const_iterator it = locales.begin(); it != locales.end(); ++it )
+  {
+    appendStringAttributeTranslation( resolvable_id, *it, klass, name, text.text(*it) );
+  }
+}
+
+
+void CacheStore::appendStringAttributeTranslation( const data::RecordId &resolvable_id,
+                                                   const Locale &locale,
+                                                   const std::string &klass,
+                                                   const std::string &name,
+                                                   const std::string &text )
+{
+  // don't bother with writing if the string is empty
+  if (text.empty()) return;
+
+  RecordId lang_id = lookupOrAppendType("lang",
+      locale.code().empty() ? "none" : locale.code() );
+  RecordId type_id = lookupOrAppendType( klass, name );
+  appendStringAttribute( resolvable_id, lang_id, type_id, text );
+}
+
+void CacheStore::appendStringAttribute( const data::RecordId &resolvable_id,
+                                        const std::string &klass,
+                                        const std::string &name,
+                                        const std::string &value )
+{
+  // don't bother with writing if the string is empty
+  if (value.empty()) return;
+  
+  RecordId type_id = lookupOrAppendType(klass, name);
+  appendStringAttribute( resolvable_id, type_id, value );
+}
+
+void CacheStore::appendStringAttribute( const RecordId &resolvable_id,
+                                        const RecordId &type_id,
+                                        const std::string &value )
+{
+  // don't bother with writing if the string is empty
+  if (value.empty()) return;
+
+  RecordId lang_id = lookupOrAppendType("lang", "none");
+  appendStringAttribute( resolvable_id, lang_id, type_id, value );
+}
+
+void CacheStore::appendStringAttribute( const RecordId &resolvable_id,
+                            const RecordId &lang_id,
+                            const RecordId &type_id,
+                            const string &value )
+{
+  // don't bother with writing if the string is empty
+  if (value.empty()) return;
+
+  // weak resolvable_id
+  _pimpl->append_text_attribute_cmd->bind(":rid", resolvable_id );
+  _pimpl->append_text_attribute_cmd->bind(":lang_id", lang_id );
+  _pimpl->append_text_attribute_cmd->bind(":attr_id", type_id );
+
+  _pimpl->append_text_attribute_cmd->bind(":text", value );
+
+  _pimpl->append_text_attribute_cmd->executenonquery();
+}
+
+template <class _Container>
+void CacheStore::appendStringContainerAttribute( const data::RecordId &resolvable_id,
+                                                 const std::string &klass,
+                                                 const std::string &name,
+                                                 const _Container &cont )
+{
+  // don't bother with writing if the container is empty
+  if (cont.empty()) return;
+
+  string value = str::join(cont, ZConfig().cacheDBSplitJoinSeparator());
+
+  appendStringAttribute( resolvable_id, klass, name, value );
+}
+
+}
+}
+
diff --git a/zypp/cache/CacheStore.h b/zypp/cache/CacheStore.h
new file mode 100644 (file)
index 0000000..b392623
--- /dev/null
@@ -0,0 +1,675 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+
+#ifndef ZYPP_CacheStore_H
+#define ZYPP_CacheStore_H
+
+#include <iosfwd>
+#include <string>
+
+#include "zypp/base/ReferenceCounted.h"
+#include "zypp/base/NonCopyable.h"
+#include "zypp/base/PtrTypes.h"
+#include "zypp/Pathname.h"
+#include "zypp/NVRA.h"
+#include "zypp/capability/CapabilityImpl.h"
+#include "zypp/capability/Capabilities.h"
+
+#include "zypp/data/ResolvableDataConsumer.h"
+#include "zypp/data/RecordId.h"
+
+#include "zypp/base/PtrTypes.h"
+#include "zypp/RepoStatus.h"
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////
+  namespace cache
+  { /////////////////////////////////////////////////////////////////
+
+    /**
+     * The cache store caches resolvable data.
+     *
+     * \code
+     * CacheStore store("/path");
+     * RecordId repository_id =
+     *   store.lookupOrAppendRepository("some-alias");
+     * store.consumePackage( repository_id, package_ptr );
+     * store.commit();
+     * \endcode
+     *
+     * \note Data will not be commited until you explicitely commit.
+     */
+    class CacheStore : public data::ResolvableDataConsumer
+    {
+    public:
+
+      CacheStore();
+      virtual ~CacheStore();
+
+      /**
+       * Constructor for the CacheStore
+       *
+       * \note a transaction will be started from the moment the
+       * CacheStore is instanciated.
+       *
+       * The data will be saved in the directory specified in
+       * \a dbdir. \a dbdir must exist.
+       */
+      CacheStore( const Pathname &dbdir );
+
+      /**
+       * Commit the changes.
+       */
+      void commit();
+
+      /**
+       * Implementation of the \ref ResolvableConsumer interface
+       *
+       * Consume a package, inserting it in the cache, under
+       * \param repository_id ownership.
+       * \param package Package data
+      */
+      virtual void consumePackage(const data::RecordId &repository_id,
+                                  const data::Package_Ptr & package);
+
+      /**
+       * Implementation of the \ref ResolvableConsumer interface
+       *
+       * Consume a source package, inserting it in the cache, under
+       * \param catalog_id ownership.
+       * \param srcpackage Source package data
+      */
+      virtual void consumeSourcePackage(
+                                      const data::RecordId &catalog_id,
+                                      const data::SrcPackage_Ptr & srcpackage );
+
+      /**
+       * Implementation of the \ref ResolvableConsumer interface
+       *
+       * Consume a patch, inserting it in the cache, under
+       * \param repository_id ownership.
+       * \param patch Patch data
+      */
+      virtual void consumePatch( const data::RecordId &repository_id,
+                                 const data::Patch_Ptr & patch );
+
+      /**
+       * Implementation of the \ref ResolvableConsumer interface.
+       *
+       * Consume a package atom, inserting it in the cache, under
+       * \a repository_id ownership.
+       *
+       * \param repository_id record id of repository to which to append the resolvable.
+       * \param atom package atom data
+       *
+       * \note this is somewhat specific to current YUM patch metadata design
+       *       and may change (to consumeAtom(data::RecordId,data::Atom)).
+       */
+      virtual void consumePackageAtom( const data::RecordId &repository_id,
+                                       const data::PackageAtom_Ptr & atom );
+
+      /**
+       * Implementation of the \ref ResolvableConsumer interface
+       *
+       * Consume a message, inserting it in the cache, under
+       * \param repository_id ownership.
+       * \param message Message data
+      */
+      virtual void consumeMessage( const data::RecordId & repository_id,
+                                   const data::Message_Ptr & message);
+
+      /**
+       * Implementation of the \ref ResolvableConsumer interface
+       *
+       * Consume a script, inserting it in the cache, under
+       * \param repository_id ownership.
+       * \param script Script data
+      */
+      virtual void consumeScript( const data::RecordId & repository_id,
+                                  const data::Script_Ptr & script);
+
+      /**
+       * Implementation of the \ref ResolvableConsumer interface
+       *
+       * Consume a pattern, inserting it in the cache, under
+       * \param repository_id ownership.
+       * \param pattern Pattern data
+      */
+      virtual void consumePattern( const data::RecordId & repository_id,
+                                   const data::Pattern_Ptr & pattern );
+
+      /**
+       * Implementation of the \ref ResolvableConsumer interface
+       *
+       * Consume a product, inserting it in the cache, under
+       * \param repository_id ownership.
+       * \param pattern Pattern data
+      */
+      virtual void consumeProduct( const data::RecordId &repository_id,
+                                   const data::Product_Ptr & product );
+
+      /**
+       * Implementation of the \ref ResolvableConsumer interface
+       *
+       * Consume changelog of a resolvable, inserting it in the cache.
+       * \param repository_id ownership.
+       * \param resolvable resolvable for which the changelog data are to be saved
+       * \param changelog  the changelog
+       * \todo see implementation
+       */
+      virtual void consumeChangelog( const data::RecordId & repository_id,
+                                     const data::Resolvable_Ptr & resolvable,
+                                     const Changelog & changelog );
+
+      /**
+       * Implementation of the \ref ResolvableConsumer interface
+       *
+       * Consume filelist of a resolvable, inserting it in the cache.
+       * \param repository_id ownership.
+       * \param resolvable resolvable for which the filelist is to be saved
+       * \param filenames  list of filenames the resolvable contains
+       * \todo see implementation
+       */
+      virtual void consumeFilelist( const data::RecordId &repository_id,
+                                    const data::Resolvable_Ptr & resolvable,
+                                    const data::Filenames & filenames );
+
+      /**
+       * Appends a resolvable to the store.
+       *
+       * You have to specify with \a kind of resolvable are you inserting
+       * and its \c NVRA (name version release and architecture ).
+       * Optionaly you can pass a list of \c CapabilityImpl::Ptr
+       * as dependencies for the resolvable.
+       *
+       * You have to specify the RecordId for the repository owning
+       * this resolvable. Yuu can obtain it with
+       * \ref lookupOrAppendRepository
+       *
+       * You can create those \a deps using \ref capability::parse
+       * functions, or the build methods to create specific types
+       * of capabilities:
+       * \ref capability::buildVersioned for \c VersionedCap
+       * \ref capability::buildNamed for \c NamedCap
+       * etc.
+       *
+       * Once the resolvable is inserted, you will get back the id
+       * if it in the store. Which you can use for later adding
+       * other properties.
+       *
+       */
+      data::RecordId appendResolvable( const data::RecordId &repository_id,
+                                       const Resolvable::Kind &kind,
+                                       const NVRA &nvra,
+                                       const data::Dependencies &deps );
+
+      /**
+       * Adds dependencies to the store
+       *
+       * A map of dependency lists has to be specified. The map contains
+       * list of capablities for each dependency type \ref zypp::Dep
+       *
+       * \a resolvable_id is the resolvable Id in the CacheStore
+       * that will own those capabilities.
+       *
+       * FIXME should it \throw if the resolvable does not exist?
+       */
+      void appendDependencies( const data::RecordId &resolvable_id,
+                               const data::Dependencies &dependencies );
+
+      /**
+       * Adds dependencies to the store
+       *
+       * A lists of dependencies \a dlist to be specified. Among
+       * which type of dependencies \ref zypp::Dep it is as
+       * the \a deptype argument.
+       *
+       * \a resolvable_id is the resolvable Id in the CacheStore
+       * that will own those capabilities.
+       *
+       * FIXME should it \throw if the resolvable does not exist?
+       */
+      void appendDependencyList( const data::RecordId &resolvable_id,
+                                 zypp::Dep deptype,
+                                 const data::DependencyList &dlist );
+
+      /**
+       * Adds a dependency to the store.
+       *
+       * A \ref CapabilityImpl::Ptr argument \a cap has to be specified.
+       * Among which type of dependency \ref zypp::Dep it is as
+       * the \a deptype argument.
+       *
+       * \a resolvable_id is the resolvable Id in the CacheStore
+       * that will own the capability
+       *
+       * FIXME should it \throw if the resolvable does not exist?
+       */
+      void appendDependency( const data::RecordId &resolvable_id,
+                             zypp::Dep deptype,
+                             capability::CapabilityImpl::Ptr cap );
+
+      /**
+       * Adds a Named dependency to the store.
+       *
+       * A \ref NamedCap::Ptr \a dlist to be specified. Among
+       * which type of dependency \ref zypp::Dep it is as
+       * the \a deptype argument.
+       *
+       * \a resolvable_id is the resolvable Id in the CacheStore
+       * that will own the capability
+       *
+       * You can create the named capability using either
+       * \ref capability::parse or \ref capability::buildNamed
+       *
+       * FIXME should it \throw if the resolvable does not exist?
+       */
+      void appendNamedDependency( const data::RecordId &, zypp::Dep,
+                                  capability::NamedCap::Ptr);
+
+      /**
+       * Adds a file dependency to the store.
+       *
+       * A \ref FileCap::Ptr \a dlist to be specified. Among
+       * which type of dependency \ref zypp::Dep it is as
+       * the \a deptype argument.
+       *
+       * \a resolvable_id is the resolvable Id in the CacheStore
+       * that will own the capability
+       *
+       * You can create the file capability using either
+       * \ref capability::parse or \ref capability::buildFile
+       *
+       * FIXME should it \throw if the resolvable does not exist?
+       */
+      void appendFileDependency( const data::RecordId &, zypp::Dep,
+                                 capability::FileCap::Ptr);
+
+      /**
+       * Adds a Modalias dependency to the store.
+       *
+       * A \ref ModaliasCap::Ptr \a cap to be specified. Among
+       * which type of dependency \ref zypp::Dep it is as
+       * the \a deptype argument.
+       *
+       * \a resolvable_id is the resolvable Id in the CacheStore
+       * that will own the capability
+       *
+       * You can create the modalias capability using either
+       * \ref capability::parse or \ref capability::buildModalias
+       *
+       * FIXME should it \throw if the resolvable does not exist?
+       */
+      void appendModaliasDependency( const data::RecordId &resolvable_id,
+                                     zypp::Dep deptype,
+                                     capability::ModaliasCap::Ptr cap);
+
+      /**
+       * Adds a Hal dependency to the store.
+       *
+       * A \ref HalCap::Ptr \a cap to be specified. Among
+       * which type of dependency \ref zypp::Dep it is as
+       * the \a deptype argument.
+       *
+       * \a resolvable_id is the resolvable Id in the CacheStore
+       * that will own the capability
+       *
+       * You can create the modalias capability using either
+       * \ref capability::parse or \ref capability::buildHal
+       *
+       * FIXME should it \throw if the resolvable does not exist?
+       */
+      void appendHalDependency( const data::RecordId &resolvable_id,
+                                      zypp::Dep deptype,
+                                      capability::HalCap::Ptr cap );
+
+      /**
+       * Adds a unknown dependency to the store.
+       *
+       * A \ref Capability::Ptr \a cap to be specified. Among
+       * which type of dependency \ref zypp::Dep it is as
+       * the \a deptype argument.
+       *
+       * \a resolvable_id is the resolvable Id in the CacheStore
+       * that will own the capability
+       *
+       * You can create the capability using either
+       * \ref capability::parse
+       *
+       * FIXME should it \throw if the resolvable does not exist?
+       */
+      void appendUnknownDependency( const data::RecordId &resolvable_id,
+                                    zypp::Dep deptype,
+                                    capability::CapabilityImpl::Ptr cap );
+
+      /**
+       * Insert patch RPM data into <tt>patch_packages</tt> table.
+       *
+       * \param prpm The patch RPM object to insert.
+       * \return Record ID of the newly inserted record.
+       */
+      data::RecordId appendPatchRpm( const data::PatchRpm_Ptr & prpm);
+
+
+      /**
+       * Insert delta RPM data into <tt>delta_packages</tt> table.
+       *
+       * \param drpm The delta RPM object to insert.
+       * \return Record ID of the newly inserted record.
+       */
+      data::RecordId appendDeltaRpm( const data::DeltaRpm_Ptr & drpm);
+
+
+      /**
+       * Returns the record id of a type
+       *
+       * Types are mostly used internally. To give concepts
+       * a record id to associate with.
+       * Examples could be arch::i386, lang::en_US
+       * Packages::summary, rel:>, kind::Package
+       *
+       * \note If the type entry does not exist, it will
+       * be created and the new inserted entry's id will
+       * be returned.
+       */
+      data::RecordId lookupOrAppendType( const std::string &klass,
+                                         const std::string &name );
+
+      /**
+       * Returns the record id of a repository (Source)
+       *
+       * \param alias Unique alias for this repo
+       *
+       * \note If the repository entry does not exist, it will
+       * be created and the new inserted entry's id will
+       * be returned.
+       */
+      data::RecordId lookupOrAppendRepository( const std::string &alias );
+
+      /**
+       * Set the resolvable shared data flag pointing to
+       * another resolvable.
+       *
+       * This is a hint for cache readers. If any attribute
+       * of a resolvable is empty, is because it is shared
+       * with another resolvable.
+       *
+       * \param resolvable_id Id of the resolvable. Must exists
+       * \param shared_id The resolvable providing the data
+       * This one is a weak reference, the reader should just
+       * try to look the data there as a hint.
+       * use \ref data::noRecordId to reset the value.
+       *
+       */
+      void setSharedData( const data::RecordId &resolvable_id,
+                          const data::RecordId &shared_id );
+
+      /**
+       * Append a numeric attribute to a resolvable
+       * \param resolvable_id Resovable Id, owner of the attribute
+       * \param klass Type class i.e "Package" "lang" "kind"
+       * \param name Type name i.e : "size" "media_number"
+       * \param value numeric value
+       */
+      void appendNumericAttribute( const data::RecordId &resolvable_id,
+                                   const std::string &klass,
+                                   const std::string &name,
+                                   int value );
+
+      /**
+       * Append a translated string value to a resolvable
+       * \param resolvable_id Resovable Id, owner of the attribute
+       * \param klass Type class i.e "Package" "lang" "kind"
+       * \param name Type name i.e : "summary" "none" "Script"
+       * \param text Translated text
+       */
+      void appendTranslatedStringAttribute( const data::RecordId &resolvable_id,
+                                            const std::string &klass,
+                                            const std::string &name,
+                                            const TranslatedText &text );
+
+      /**
+       * Append a string value to a resolvable
+       * \param resolvable_id Resovable Id, owner of the attribute
+       * \param locale locale of the text language
+       * \param klass Type class i.e "Package" "lang" "kind"
+       * \param name Type name i.e : "summary" "none" "Script"
+       * \param text text
+       */
+      void appendStringAttributeTranslation( const data::RecordId &resolvable_id,
+                                             const Locale &locale,
+                                             const std::string &klass,
+                                             const std::string &name,
+                                             const std::string &text );
+
+      /**
+       * Append a string value to a resolvable
+       * \param resolvable_id Resovable Id, owner of the attribute
+       * \param klass Type class i.e "Package" "lang" "kind"
+       * \param name Type name i.e : "summary" "none" "Script"
+       * \param value string value
+       */
+      void appendStringAttribute( const data::RecordId &resolvable_id,
+                                  const std::string &klass,
+                                  const std::string &name,
+                                  const std::string &value );
+
+      /**
+       * Append a string value to a resolvable
+       * \param resolvable_id Resovable Id, owner of the attribute
+       * \param type_id Type id, \see lookupOrAppendType
+       * \param value string value
+       */
+      void appendStringAttribute( const data::RecordId &resolvable_id,
+                                  const data::RecordId &type_id,
+                                  const std::string &value );
+
+
+      /**
+       * Append strings from _Container to a resolvable.
+       * Uses \ref zypp::str::split(_Container, std::string) with
+       * \ref ZConfig::cacheDBSplitJoinSeparator() as the second argument
+       * (a separator string) of split().
+       * 
+       * \param resolvable_id Resovable Id, owner of the attribute
+       * \param klass Type class i.e "Package" "lang" "kind"
+       * \param name Type name i.e : "summary" "none" "Script"
+       * \param cont The string container.
+       */
+      template <class _Container>
+      void appendStringContainerAttribute( const data::RecordId &resolvable_id,
+                                           const std::string &klass,
+                                           const std::string &name,
+                                           const _Container &cont );
+
+       /**
+       * Update a known repository checksum and timestamp
+       *
+       * \note If you don't provide timestamp it defaults
+       * to now.
+       *
+       * It is responsability of the caller to operate with
+       * a valid record id. You can get one
+       * Using \ref lookupOrAppendRepository
+       *
+       * If the repository does not exists, nothing will happen
+       */
+      void updateRepository( const data::RecordId &id,
+                             const std::string &checksum,
+                             const Date &timestamp = Date::now() );
+      
+      /**
+       * \short Clean repository from cache
+       *
+       * \param id repository identifier in cache
+       *
+       * You can check existence using \ref isCached
+       *
+       * \throws CacheRecordNotFoundException if the repository
+       * id does not refer to a valid repository.
+       */
+      void cleanRepository( const data::RecordId &id );
+      
+      /**
+       * \short Clean repository from cache
+       *
+       * \param alias Repository unique alias
+       *
+       * You can check existence using \ref isCached
+       *
+       * \throws CacheRecordNotFoundException if the repository
+       * alias does not refer to a valid repository.
+       */
+      void cleanRepository( const std::string &alias );
+      
+      /**
+       * get the status of a cached repository
+       *
+       * It is responsability of the caller to operate with
+       * a valid record id. You can get one
+       * Using \ref lookupOrAppendRepository
+       *
+       * You can check existence using \ref isCached
+       *
+       * \throws CacheRecordNotFoundException if the repository
+       * id does not refer to a valid repository.
+       */
+      RepoStatus repositoryStatus( const data::RecordId &id );
+      
+      /**
+       * get the status of a cached repository
+       *
+       * It is responsability of the caller to operate with
+       * a valid alias. You can insert one
+       * Using \ref lookupOrAppendRepository
+       *
+       * You can check existence using \ref isCached
+       *
+       * \throws CacheRecordNotFoundException if the repository
+       * alias is unknown
+       */
+      RepoStatus repositoryStatus( const std::string &alias );
+
+      /**
+       * \short Does a repository exists in cache?
+       *
+       * True if the repository is cached
+       */
+      bool isCached( const std::string &alias );
+      
+      /**
+       * \short looks the id for a repository in cache
+       *
+       * \param alias Repository unique alias
+       *
+       * \throws CacheRecordNotFoundException if the repository
+       * alias is unknown
+       */
+      data::RecordId lookupRepository( const std::string &alias );
+      
+      
+      /**
+       * Returns the record id of a file entry \a path
+       *
+       * \note If the file entry does not exist, it will
+       * be created and the new inserted entry's id will
+       * be returned.
+       */
+      data::RecordId lookupOrAppendFile( const Pathname &path );
+
+      /**
+       * Returns the record id of a name entry \a name
+       *
+       * \note If the name entry does not exist, it will
+       * be created and the new inserted entry's id will
+       * be returned.
+       */
+      data::RecordId lookupOrAppendName( const std::string &name );
+
+      /**
+       * Returns the record id of a directory name  entry \a name
+       *
+       * \note If the directory name entry does not exist, it will
+       * be created and the new inserted entry's id will
+       * be returned.
+       */
+      data::RecordId lookupOrAppendDirName( const std::string &name );
+
+      /**
+       * Returns the record id of a file name entry \a name
+       *
+       * \note If the file name entry does not exist, it will
+       * be created and the new inserted entry's id will
+       * be returned.
+       */
+      data::RecordId lookupOrAppendFileName( const std::string &name );
+
+    protected:
+      /**
+       * Internally used function that appends a entry in
+       * the capabilities table for a specific capability
+       * entry.
+       */
+//       data::RecordId appendDependencyEntry( const data::RecordId &,
+//                                             zypp::Dep, const Resolvable::Kind & );
+
+      void appendStringAttribute( const data::RecordId &resolvable_id,
+                                  const data::RecordId &lang_id,
+                                  const data::RecordId &type_id,
+                                  const std::string &value );
+
+      /**
+       * Append a numeric attribute to a resolvable
+       * \param resolvable_id Resovable Id, owner of the attribute
+       * \param type_id attribute id
+       * \param value numeric value
+       */
+      void appendNumericAttribute( const data::RecordId &resolvable_id,
+                                   const data::RecordId &type_id,
+                                   int value );
+
+      /**
+       * Append a bool attribute to a resolvable. Will be stored as
+       * numeric 1 or 0.
+       * 
+       * \param resolvable_id Resovable Id, owner of the attribute
+       * \param type_id attribute id
+       * \param value bool value
+       */
+      void appendBooleanAttribute( const data::RecordId & resolvable_id,
+                                   const std::string & klass,
+                                   const std::string & name,
+                                   bool value);
+
+      /** \name Detail Attributes Inserters
+       * These functions are used by ResolvableConsumer interface functions
+       * to avoid some duplication across types.
+       */
+      //@{
+      void appendResObjectAttributes( const data::RecordId &rid,
+                                      const data::ResObject_Ptr & res );
+
+      void appendPackageBaseAttributes(const data::RecordId & pkgid,
+                                       const data::Packagebase_Ptr & package);
+      //@}
+
+
+    private:
+      /** Implementation. */
+      class Impl;
+      /** Pointer to implementation. */
+      RW_pointer<Impl> _pimpl;
+    };
+  }
+}
+
+#endif
+
diff --git a/zypp/cache/CacheTypes.cc b/zypp/cache/CacheTypes.cc
new file mode 100644 (file)
index 0000000..30be871
--- /dev/null
@@ -0,0 +1,158 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/cache/CacheTypes.cc
+ *
+*/
+#include <iostream>
+#include "zypp/base/Logger.h"
+#include "zypp/base/Exception.h"
+#include "zypp/cache/sqlite3x/sqlite3x.hpp"
+#include "zypp/CheckSum.h"
+#include "zypp/cache/CacheTypes.h"
+
+using namespace std;
+using namespace sqlite3x;
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////
+  namespace cache
+  { /////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // CLASS NAME : CacheTypes
+    //
+    ///////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // METHOD NAME : CacheTypes::CacheTypes
+    // METHOD TYPE : Ctor
+    //
+    CacheTypes::CacheTypes( const Pathname &dbdir )
+      : _dbdir(dbdir)
+    {
+      refreshCache();
+    }
+
+    void CacheTypes::refreshCache()
+    {
+      try
+      {
+        sqlite3_connection con((_dbdir + "zypp.db").asString().c_str());
+        con.executenonquery("PRAGMA cache_size=8000;");
+        con.executenonquery("BEGIN;");
+      
+        // get all types
+        sqlite3_command select_types_cmd( con, "select id,class,name from types;");
+        sqlite3_reader reader = select_types_cmd.executereader();
+      
+        while(reader.read())
+        {
+          data::RecordId id = reader.getint64(0);
+          string klass = reader.getstring(1);
+          string name = reader.getstring(2);
+          if ( klass == "arch" )
+            _arch_cache[id] = Arch(name);
+          if ( klass == "rel" )
+            _rel_cache[id] = Rel(name);
+          if ( klass == "kind" )
+            _kind_cache[id] = Resolvable::Kind(name);
+          if ( klass == "deptype" )
+            _deptype_cache[id] = name;
+        }
+        
+        MIL << "archs: " << _arch_cache.size() << endl;
+        MIL << "rel  : " << _rel_cache.size() << endl;
+        MIL << "kind : " << _kind_cache.size() << endl;
+        MIL << "deptype : " << _deptype_cache.size() << endl;
+      }
+      catch ( std::exception &e )
+      {
+        ZYPP_THROW(Exception("Error reading types"));
+      }
+    }
+    
+    Rel CacheTypes::relationFor( const data::RecordId &id )
+    {
+      Rel rel;
+      std::map<data::RecordId, Rel>::const_iterator it;
+      if ( (it = _rel_cache.find(id) ) != _rel_cache.end() )
+        rel = it->second;
+      else
+        ZYPP_THROW(Exception("Inconsistent Rel"));
+      
+      return rel;
+    
+    }
+    
+    Resolvable::Kind CacheTypes::kindFor( const data::RecordId &id )
+    {
+      Resolvable::Kind kind;
+      std::map<data::RecordId, Resolvable::Kind>::const_iterator it;
+      if ( (it = _kind_cache.find(id) ) != _kind_cache.end() )
+        kind = it->second;
+      else
+        ZYPP_THROW(Exception("Inconsistent Kind"));
+      
+      return kind;
+    }
+    
+    Dep CacheTypes::deptypeFor( const data::RecordId &id )
+    {
+      std::map<data::RecordId, string>::const_iterator it;
+      if ( (it = _deptype_cache.find(id) ) != _deptype_cache.end() )
+        return Dep(it->second);
+      else
+      {
+        ERR << "deptype: " << id << endl;
+        ZYPP_THROW(Exception("Inconsistent deptype"));
+      }
+    }
+    
+    Arch CacheTypes::archFor( const data::RecordId &id )
+    {
+      
+      Arch arch;
+      std::map<data::RecordId, Arch>::const_iterator it;
+      if ( (it = _arch_cache.find(id) ) != _arch_cache.end() )
+        arch = it->second;
+      else
+        ZYPP_THROW(Exception("Inconsistent Arch"));
+      
+      return arch;
+    }
+
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // METHOD NAME : CacheTypes::~CacheTypes
+    // METHOD TYPE : Dtor
+    //
+    CacheTypes::~CacheTypes()
+    {}
+    
+    /******************************************************************
+    **
+    ** FUNCTION NAME : operator<<
+    ** FUNCTION TYPE : std::ostream &
+    */
+    std::ostream & operator<<( std::ostream & str, const CacheTypes & obj )
+    {
+      return str;
+    }
+
+    /////////////////////////////////////////////////////////////////
+  } // namespace cache
+  ///////////////////////////////////////////////////////////////////
+  /////////////////////////////////////////////////////////////////
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
diff --git a/zypp/cache/CacheTypes.h b/zypp/cache/CacheTypes.h
new file mode 100644 (file)
index 0000000..36dc27d
--- /dev/null
@@ -0,0 +1,118 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+/** \file      zypp/cache/CacheTypes.h
+ *
+*/
+#ifndef ZYPP2_CACHE_CACHETYPES_H
+#define ZYPP2_CACHE_CACHETYPES_H
+
+#include <iosfwd>
+
+#include <map>
+#include <string>
+#include "zypp/Rel.h"
+#include "zypp/Arch.h"
+#include "zypp/ResTraits.h"
+#include "zypp/Dep.h"
+#include "zypp/Resolvable.h"
+#include "zypp/Pathname.h"
+#include "zypp/data/RecordId.h"
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////
+  namespace cache
+  { /////////////////////////////////////////////////////////////////
+
+    ///////////////////////////////////////////////////////////////////
+    //
+    // CLASS NAME : CacheTypes
+    //
+    /** 
+     * Cache types is a class that reads the dynamic types
+     * from the cache, and keeps them on memory.
+     * Then it can by asked for the type for an Id.
+     *
+     * \see CacheStore::lookupOrAppendType
+     */
+    class CacheTypes
+    {
+      friend std::ostream & operator<<( std::ostream & str, const CacheTypes & obj );
+    public:
+      /**
+       * Default ctor 
+       *
+       * \param dbdir Path where the cache is located.
+       *
+       */
+      CacheTypes( const Pathname &dbdir );
+      
+      /** Dtor */
+      ~CacheTypes();
+      /**
+       * Relation for a cache record id.
+       *
+       * \param id The id you got in a cache query
+       *
+       * \throws Exception if the id is not a valid type
+       */
+      Rel relationFor( const data::RecordId &id );
+      
+      /**
+       * Kind for a cache record id.
+       *
+       * \param id The id you got in a cache query
+       *
+       * \throws Exception if the id is not a valid type
+       */
+      Resolvable::Kind kindFor( const data::RecordId &id );
+      
+      /**
+       * Dependency type for a cache record id.
+       *
+       * \param id The id you got in a cache query
+       *
+       * \throws Exception if the id is not a valid type
+       */
+      Dep deptypeFor( const data::RecordId &id );
+      
+      /**
+       * Architecture for a cache record id.
+       *
+       * \param id The id you got in a cache query
+       *
+       * \throws Exception if the id is not a valid type
+       */
+      Arch archFor( const data::RecordId &id );
+      
+    public:
+
+    private:
+      void refreshCache();
+      
+      std::map<data::RecordId, Rel> _rel_cache;
+      std::map<data::RecordId, Resolvable::Kind> _kind_cache;
+      std::map<data::RecordId, std::string> _deptype_cache;
+      std::map<data::RecordId, Arch> _arch_cache;
+      Pathname _dbdir;
+    };
+    ///////////////////////////////////////////////////////////////////
+
+    /** \relates CacheTypes Stream output */
+    std::ostream & operator<<( std::ostream & str, const CacheTypes & obj );
+
+    /////////////////////////////////////////////////////////////////
+  } // namespace cache
+  ///////////////////////////////////////////////////////////////////
+  /////////////////////////////////////////////////////////////////
+} // namespace zypp
+///////////////////////////////////////////////////////////////////
+#endif // ZYPP2_CACHE_CACHETYPES_H
diff --git a/zypp/cache/DESIGN-WRITE-API.txt b/zypp/cache/DESIGN-WRITE-API.txt
new file mode 100644 (file)
index 0000000..9c9a32b
--- /dev/null
@@ -0,0 +1,147 @@
+
+CACHE WRITE API DESIGN
+dmacvicar@suse.de
+ma@suse.de
+
+Background and problems
+=======================
+
+The biggest problem when designing an API that will be used
+by metadata parsers to fill a database is the fact that all
+the formats read data in different order.
+
+YUM is flawed as it mixes descriptions and user data with
+basic solver data (NVRAD [1]). But it is easy to write to a
+store.
+
+SUSETags is on the other hand has different files for primary
+and user data.
+
+If we consideer a simple API where we have data objects to pass
+to the store:
+
+ .------------------.
+ |    package       |
+ +------------------+
+ | NVRAD            |
+ +------------------+
+ | summary          |
+ +------------------+
+ | other data       |
+ +------------------+
+ | description      |
+ '------------------'
+
+The SQL table behind the API, has a resolvables table which stores
+
+|-----------------| |-----------------|
+| resolvable      | | package_data    |
+|-----------------| |-----------------|
+| id  |   NVRAD   | | package_id      |
+|-----------------| |-----------------|
+                    | other data      |
+                    |-----------------|
+
+Inserting a package means, inserting a resolvable entry, getting a new id
+for it, and then insert a new package entry and fill package_id with it.
+
+YUM can insert this data at the same time while parsing as it is available
+at the same time. SUSETags can't, so it has to cache the NVRAD and the id, to
+insert the second block when it becomes available from the translations file.
+
+This causes the design of the data structures to be high dependant on how the metadata
+is read.
+
+Also
+
+We try to look for a solution that works well in the 99% of the cases, giving the flexibility
+in the rest 1%.
+
+Requirements
+============
+
+- Allow parsers to enter metadata as they get it.
+- Be reasonable fast
+
+The first requirement would make us unable to use fixed data transport
+objects to insert data.
+
+If we choose a data object with certains fields, we will be going in favour
+of the design of certain metadata format.
+
+Proposed Solution
+=================
+
+- a basic resolvable NVRAD data object
+- a dynamic fields object:
+
+ .------------------------.
+ |      package_data      |
+ +------------------+-----+
+ | summary          | [ ] |
+ | description      | [ ] |
+ | group            | [ ] |
+ | packager         | [ ] |
+ | license          | [ ] |
+ '------------------+-----'
+
+Everytime a package object is inserted in the cache, the resolvable
+entry will be inserted, but also the specific data for the resolvable
+kind will be created in a empty state. The id of the resolvable will be
+returned.
+
+The parser can then write the data passing a structure like the one
+described above, where the first column represents the field and the second
+the field to update. A SQL UPDATE statement will be generated from this
+data object, and adding the fields for first time will be no different as
+UPDATING the fields.
+
+This presents one problem. As the SQL is generated from the data object
+actve fields, we can't precompile those update statements. This is solved easily.
+We can assume if a metadata parser is inserting a combination of fields for
+lot of packages, that it will use the same combination for all packages in most
+of the cases. We can precompile the statements for a combination of fields and
+cache them in a precompiled statement pool. When we will insert another data
+block, we can lookup if a precompiled statement for the combination exists and
+use it. The only cases that will not benefit from it would be updating all the
+time in different orders (which will hit the cache when all field combinations are
+reached). So problem has a easy solution.
+
+Implementation
+==============
+
+The implementation of the data objects is not defined yet. Several alternatives
+come to mind:
+
+struct PackageData
+{
+  enum Fields {
+    FIELD_DESCRIPTION,
+    FIELD_SUMMARY,
+    FIELD_GROUP,
+  };
+  string description;
+  string summary;
+  int size;
+
+  int fields_mask;
+  // or set<Field> fields
+};
+
+struct PackageData
+{
+  pair<bool, string> description;
+  pair<bool, string> summary;
+  pair<bool, int> size;
+};
+
+In this case, we would need to know the types of the data
+before writing it.
+
+We are investigating the use of boost::any [2] in order to see if
+it is possible to make the api even easier.
+
+
+ [1]: Name Version Release Arch Deps
+ [2]: http://www.boost.org/doc/html/any.html
\ No newline at end of file
diff --git a/zypp/cache/ResolvableQuery.cc b/zypp/cache/ResolvableQuery.cc
new file mode 100644 (file)
index 0000000..53a8976
--- /dev/null
@@ -0,0 +1,257 @@
+
+#include "zypp/cache/CacheTypes.h"
+#include "zypp/cache/ResolvableQuery.h"
+#include "zypp/cache/sqlite3x/sqlite3x.hpp"
+
+using namespace sqlite3x;
+using namespace std;
+
+namespace zypp { namespace cache {
+
+
+struct ResolvableQuery::Impl
+{
+  Pathname _dbdir;
+  string _fields;
+  CacheTypes _type_cache;
+  
+  Impl( const Pathname &dbdir)
+  : _dbdir(dbdir)
+    , _type_cache(dbdir)
+  {
+    _fields = "id, name, version, release, epoch, arch, kind, installed_size, archive_size, install_only, build_time, install_time, repository_id";
+  }
+
+  ~Impl()
+  {
+  }
+
+
+  data::ResObject_Ptr fromRow( sqlite3_reader &reader )
+  {
+    data::ResObject_Ptr ptr (new data::ResObject);
+
+    ptr->name = reader.getstring(1);
+    ptr->edition = Edition( reader.getstring(2), reader.getstring(3), reader.getint(4));
+    ptr->arch = _type_cache.archFor(reader.getint(5));
+
+    // 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;");
+    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_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 )
+  {
+    sqlite3_connection con((_dbdir + "zypp.db").asString().c_str());
+    return queryStringAttributeTranslationInternal( con, record_id, Locale(), klass, name);
+  }
+
+
+  std::string queryStringAttributeTranslation( const data::RecordId &record_id,
+                                               const Locale &locale,
+                                               const std::string &klass,
+                                               const std::string &name )
+  {
+    sqlite3_connection con((_dbdir + "zypp.db").asString().c_str());
+    return queryStringAttributeTranslationInternal( con, record_id, locale, klass, name );
+  }
+
+
+  TranslatedText queryTranslatedStringAttribute( const data::RecordId &record_id,
+                                                 const std::string &klass,
+                                                 const std::string &name )
+  {
+    sqlite3_connection con((_dbdir + "zypp.db").asString().c_str());
+    return queryTranslatedStringAttributeInternal( con, record_id, klass, name );
+  }
+
+
+  int queryNumericAttribute( const data::RecordId &record_id,
+                                 const std::string &klass,
+                                 const std::string &name )
+  {
+    sqlite3_connection con((_dbdir + "zypp.db").asString().c_str());
+    return queryNumericAttributeInternal( con, record_id, klass, name);
+  }
+
+private:
+
+  int queryNumericAttributeInternal( sqlite3_connection &con,
+                                     const data::RecordId &record_id,
+                                     const std::string &klass,
+                                     const std::string &name )
+  {
+    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;");
+
+    cmd.bind(":rid", record_id);
+
+    cmd.bind(":tclass", klass);
+    cmd.bind(":tname", name);
+
+    return cmd.executeint();
+  }
+
+  TranslatedText queryTranslatedStringAttributeInternal( sqlite3_connection &con,
+                                                         const data::RecordId &record_id,
+                                                         const std::string &klass,
+                                                         const std::string &name )
+  {
+    //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;");
+
+    cmd.bind(":rid", record_id);
+    cmd.bind(":lclass", "lang");
+
+    cmd.bind(":tclass", klass);
+    cmd.bind(":tname", name);
+
+    TranslatedText result;
+    sqlite3_reader reader = cmd.executereader();
+    while(reader.read())
+    {
+      result.setText( reader.getstring(0), Locale( reader.getstring(1) ) );
+    }
+    return result;
+  }
+
+  std::string queryStringAttributeInternal( sqlite3_connection &con,
+                                            const data::RecordId &record_id,
+                                            const std::string &klass,
+                                            const std::string &name )
+  {
+    return queryStringAttributeTranslationInternal( con, record_id, Locale(), klass, name);
+  }
+
+  std::string queryStringAttributeTranslationInternal( sqlite3_connection &con,
+                                                       const data::RecordId &record_id,
+                                                       const Locale &locale,
+                                                       const std::string &klass,
+                                                       const std::string &name )
+  {
+    //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");
+    if (locale == Locale() )
+      cmd.bind(":lname", "none");
+    else
+      cmd.bind(":lname", locale.code());
+
+    cmd.bind(":tclass", klass);
+    cmd.bind(":tname", name);
+
+    return cmd.executestring();
+  }
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// FORWARD TO IMPLEMENTATION
+//////////////////////////////////////////////////////////////////////////////
+
+ResolvableQuery::ResolvableQuery( const Pathname &dbdir)
+  : _pimpl(new Impl(dbdir))
+{
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ResolvableQuery::query( const data::RecordId &id, ProcessResolvable fnc  )
+{
+  _pimpl->query(id, fnc);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+void ResolvableQuery::query( const std::string &s, ProcessResolvable fnc  )
+{
+  _pimpl->query(s, fnc);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+int ResolvableQuery::queryNumericAttribute( const data::RecordId &record_id,
+                                            const std::string &klass,
+                                            const std::string &name )
+{
+  return _pimpl->queryNumericAttribute(record_id, klass, name);
+}
+
+bool ResolvableQuery::queryBooleanAttribute( const data::RecordId &record_id,
+                                             const std::string &klass,
+                                             const std::string &name )
+{
+  return _pimpl->queryNumericAttribute(record_id, klass, name);
+}
+
+
+std::string ResolvableQuery::queryStringAttribute( const data::RecordId &record_id,
+                                                   const std::string &klass,
+                                                   const std::string &name )
+{
+  return _pimpl->queryStringAttribute(record_id, klass, name);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+std::string ResolvableQuery::queryStringAttributeTranslation( const data::RecordId &record_id,
+                                                              const Locale &locale,
+                                                              const std::string &klass,
+                                                              const std::string &name )
+{
+  return _pimpl->queryStringAttributeTranslation(record_id, locale, klass, name);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+TranslatedText ResolvableQuery::queryTranslatedStringAttribute( const data::RecordId &record_id,
+                                                                const std::string &klass,
+                                                                const std::string &name )
+{
+  return _pimpl->queryTranslatedStringAttribute(record_id, klass, name);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+} } // namespace zypp::cache
diff --git a/zypp/cache/ResolvableQuery.h b/zypp/cache/ResolvableQuery.h
new file mode 100644 (file)
index 0000000..5479bdc
--- /dev/null
@@ -0,0 +1,141 @@
+
+#ifndef ZYPP_CACHE_RESOLVABLE_QUERY_H
+#define ZYPP_CACHE_RESOLVABLE_QUERY_H
+
+#include "zypp/base/Function.h"
+#include "zypp/Pathname.h"
+#include "zypp/data/ResolvableData.h"
+#include "zypp/data/RecordId.h"
+
+///////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+  ///////////////////////////////////////////////////////////////////
+  namespace cache
+  { /////////////////////////////////////////////////////////////////
+   /**
+    * The resolvable query class allows you to query for resolvable
+    * data and properties from the cache.
+    */
+    struct ResolvableQuery
+    {
+    public:
+     /**
+      * Callback definition
+      * first parameter is the resolvable id.
+      * second parameter is a \ref data::ResObjectData object with the resource
+      */
+      typedef function<bool( const data::RecordId &, 
+                             data::ResObject_Ptr )> ProcessResolvable;
+      
+      /**
+       * Constructor
+       *
+       * \param dbdir Cache location path
+       */
+      ResolvableQuery( const Pathname &dbdir );
+      
+      /**
+      * Query by record id
+      * \param record_id Resolvable id to query
+      * \param fnc callback to send the data to. (Will be called once or none)
+      */
+      void query( const data::RecordId &record_id,
+                  ProcessResolvable fnc  );
+      
+      /**
+      * Query by matching text
+      * \param text text to match
+      * \param fnc callback to send the data to. (Will be called once per result)
+      */
+      void query( const std::string &text,
+                  ProcessResolvable fnc  );
+      
+      /**
+       * Queries a specifc attribute for a resolvable
+       *
+       * \param record_id Resolvable cache id
+       * \param klass Attribute Class
+       * \param name Attribute Name
+       *
+       * \return The attribute or 0 if
+       * no record is found.
+       */
+      int queryNumericAttribute( const data::RecordId &record_id,
+                                 const std::string &klass,
+                                 const std::string &name );
+
+
+      /**
+       * Queries a specifc attribute for a resolvable
+       *
+       * \param record_id Resolvable cache id
+       * \param klass Attribute Class
+       * \param name Attribute Name
+       *
+       * \return The bool value of the attribute or <tt>false</tt>
+       *         if no record is found.
+       */
+      bool queryBooleanAttribute( const data::RecordId &record_id,
+                                  const std::string &klass,
+                                  const std::string &name );
+
+
+      /**
+       * Queries a specifc attribute for a resolvable
+       *
+       * \param record_id Resolvable cache id
+       * \param klass Attribute Class
+       * \param name Attribute Name
+       *
+       * \return The attribute or a empty string if
+       * no record is found.
+       */
+      std::string queryStringAttribute( const data::RecordId &record_id,
+                                        const std::string &klass,
+                                        const std::string &name );
+      
+      /**
+       * Queries a specifc attribute translation
+       * for a resolvable.
+       *
+       * \param record_id Resolvable cache id
+       * \param locale Locale of the translation
+       * \param klass Attribute Class
+       * \param name Attribute Name
+       *
+       * \return The attribute or a empty string if
+       * no record is found.
+       */
+      std::string queryStringAttributeTranslation( const data::RecordId &record_id,
+                                                   const Locale &locale,
+                                                   const std::string &klass,
+                                                   const std::string &name );
+      
+      /**
+       * Queries all translations for a specific attribute
+       * in a resolvable.
+       *
+       * \param record_id Resolvable cache id
+       * \param klass Attribute Class
+       * \param name Attribute Name
+       *
+       * \return all attribute translations or a empty 
+       * \ref TranslatedString if no record is found.
+       */
+      TranslatedText queryTranslatedStringAttribute( const data::RecordId &record_id,
+                                                     const std::string &klass,
+                                                     const std::string &name );
+      
+    private:
+      /** Implementation. */
+      class Impl;
+      /** Pointer to implementation. */
+      RW_pointer<Impl> _pimpl;
+    };
+
+  } //NS cache
+} //NS zypp
+
+#endif
diff --git a/zypp/cache/SQLITE3X-README.txt b/zypp/cache/SQLITE3X-README.txt
new file mode 100644 (file)
index 0000000..b9ce04f
--- /dev/null
@@ -0,0 +1,2 @@
+
+http://s11n.net/sqlite/wrapper/overview-sqlite3x-sq3-2007.01.25.pdf
diff --git a/zypp/cache/Utils.cpp b/zypp/cache/Utils.cpp
new file mode 100644 (file)
index 0000000..53d5aeb
--- /dev/null
@@ -0,0 +1,62 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+
+#include <vector>
+
+#include "zypp/base/Logger.h"
+#include "zypp/base/String.h"
+
+#include "zypp/cache/Utils.h"
+
+using namespace std;
+
+//////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+namespace cache
+{ /////////////////////////////////////////////////////////////////
+
+int tribool_to_int( boost::tribool b )
+{
+  if (b)
+    return 1;
+  else if (!b)
+    return 0;
+  else
+    return 2;
+}  
+  
+boost::tribool int_to_tribool( int i )
+{
+  if (i==1)
+    return true;
+  else if (i==0)
+    return false;
+  else
+    return boost::indeterminate;
+}
+  
+std::string checksum_to_string( const CheckSum &checksum )
+{
+  return checksum.type() + ":" + checksum.checksum();
+}  
+  
+CheckSum string_to_checksum( const std::string &checksum )
+{
+  std::vector<std::string> words;
+  if ( str::split( checksum, std::back_inserter(words), ":" ) != 2 )
+    return CheckSum();
+  
+  return CheckSum( words[0], words[19]);
+}
+  
+}
+}
+
diff --git a/zypp/cache/Utils.h b/zypp/cache/Utils.h
new file mode 100644 (file)
index 0000000..50bfffe
--- /dev/null
@@ -0,0 +1,33 @@
+/*---------------------------------------------------------------------\
+|                          ____ _   __ __ ___                          |
+|                         |__  / \ / / . \ . \                         |
+|                           / / \ V /|  _/  _/                         |
+|                          / /__ | | | | | |                           |
+|                         /_____||_| |_| |_|                           |
+|                                                                      |
+\---------------------------------------------------------------------*/
+
+#ifndef ZYPP_DATA_UTILS_H
+#define ZYPP_DATA_UTILS_H
+
+#include "zypp/base/Logger.h"
+#include "zypp/base/String.h"
+#include "zypp/CheckSum.h"
+#include <boost/logic/tribool.hpp>
+
+//////////////////////////////////////////////////////////////////
+namespace zypp
+{ /////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////
+namespace cache
+{ /////////////////////////////////////////////////////////////////
+
+       int tribool_to_int( boost::tribool b );
+       boost::tribool int_to_tribool( int i );
+       std::string checksum_to_string( const CheckSum &checksum );
+       CheckSum string_to_checksum( const std::string &checksum );
+  
+}
+}
+
+#endif
diff --git a/zypp/cache/schema/DESIGN-SCHEMA.txt b/zypp/cache/schema/DESIGN-SCHEMA.txt
new file mode 100644 (file)
index 0000000..bfc4b4b
--- /dev/null
@@ -0,0 +1,3 @@
+
+See:
+http://en.opensuse.org/Libzypp/Refactoring/CacheSchema
\ No newline at end of file
diff --git a/zypp/cache/schema/mkarray.c b/zypp/cache/schema/mkarray.c
new file mode 100644 (file)
index 0000000..cea08f6
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ * mkarray - make a c array containing the input file.
+ *
+ * this file is part of the makeutil package:
+ *   http://sourceforge.net/projects/makeutil/
+ *   http://www.cybermesa.com/~aisa/makeutil/
+ *
+ * this file is hereby placed in the public domain.
+ * aisa0@users.sourceforge.net, aisa@cybermesa.com
+ */
+
+static char rcsid[]="$Id: mkarray.c,v 1.2 2004/12/11 18:21:51 aisa0 Exp $";
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static
+mkarray(filename, file, ofile, varname)
+  char *filename;
+  FILE *file;
+  FILE *ofile;
+  char *varname;
+{
+  char buf[BUFSIZ];
+  size_t i, rsize, tsize=0;
+  int done=0, line=8, status=EXIT_SUCCESS;
+
+  fprintf(ofile, "/*\n");
+  fprintf(ofile, " * this file is automatically generated\n");
+  fprintf(ofile, " */\n");
+  fprintf(ofile, "\n");
+  fprintf(ofile, "#include <string.h>\n");
+  fprintf(ofile, "\n");
+  fprintf(ofile, "static char rcsid[]=\"%s\";\n", rcsid);
+  fprintf(ofile, "\n");
+  fprintf(ofile, "char %s[]=\n{\n", varname);
+
+  while(!done) {
+    int i, ch;
+
+    rsize=fread(&buf[0], sizeof(char), sizeof buf/sizeof buf[0], file);
+    tsize+=rsize;
+
+    switch(rsize) {
+    case 0:
+      rsize=1;
+      buf[0]='\0';
+      done=1;
+
+      /* down seems more likely */
+
+    default:
+      for(i=0;i<rsize;++i) {
+        if(8==line) fputc('\t', ofile);
+
+        line+=(ch=fprintf(ofile, "0x%02x,", buf[i]&0xff));
+
+        if(line+ch>=78) {
+          line=8;
+          fputc('\n', ofile);
+        }
+      }
+    }
+  }
+  if(ferror(file)) {
+    perror("error: read");
+    status|=EXIT_FAILURE;
+  }
+
+  if(8!=line) fputc('\n', ofile);
+  fputs("};\n\n", ofile);
+
+  fprintf(ofile, "size_t _%s_size=%d;\n", varname, tsize);
+  fprintf(ofile, "size_t *%s_size=&_%s_size;\n", varname, varname);
+
+  if(ferror(ofile)) {
+    perror("error: write: -: ");
+    status|=EXIT_FAILURE;
+  }
+  if(EOF==fclose(ofile)) {
+    perror("error: close: -: ");
+    status|=EXIT_FAILURE;
+  }
+
+  return status;
+}
+
+main(argc, argv)
+  char *argv[];
+{
+  char *filename, *ofilename, *varname;
+  FILE *file;
+  int status=EXIT_SUCCESS;
+
+  --argc;
+  ++argv;
+
+  if(argc!=3) {
+      fputs("usage: mkarray <input-file> <var-name> <output-file>\n", stderr);
+      fprintf( stderr, "You gave %d args\n", argc);
+      exit(status|EXIT_FAILURE);
+  }
+
+  filename=argv[0];
+  ofilename=argv[2];
+  varname=argv[1];
+
+  if(0==strcmp("-", filename)) {
+    status|=mkarray(filename, stdin, varname);
+  } else {
+    FILE *file;
+    FILE *ofile;
+    if( ( NULL!=(file=fopen(filename, "rb")) ) && ( NULL!=(ofile=fopen(ofilename, "w")) ) )
+    {
+      status|=mkarray(filename, file, ofile, varname);
+      if(EOF==fclose(file)) {
+        perror("error: close");
+        status|=EXIT_FAILURE;
+      }
+    }
+    else
+    {
+      perror("error: open");
+      status|=EXIT_FAILURE;
+    }
+  }
+
+  exit(status);
+}
+
+/*                                                              ..__
+ *                                                              `' "
+ */
diff --git a/zypp/cache/schema/schema.sql b/zypp/cache/schema/schema.sql
new file mode 100644 (file)
index 0000000..07d3be4
--- /dev/null
@@ -0,0 +1,299 @@
+
+------------------------------------------------
+-- The cleanup can be generated as:
+-- cat schema.sql | grep "^CREATE" | awk '{print "DROP " $2 " IF EXISTS " $3 ";"}' | sort -r
+------------------------------------------------
+
+DROP TRIGGER IF EXISTS remove_resolvables;
+DROP TRIGGER IF EXISTS remove_patch_packages_baseversions;
+DROP TABLE IF EXISTS types;
+DROP TABLE IF EXISTS text_attributes;
+DROP TABLE IF EXISTS split_capabilities;
+DROP TABLE IF EXISTS resolvables_repositories;
+DROP TABLE IF EXISTS resolvables;
+DROP TABLE IF EXISTS patch_packages_baseversions;
+DROP TABLE IF EXISTS patch_packages;
+DROP TABLE IF EXISTS other_capabilities;
+DROP TABLE IF EXISTS numeric_attributes;
+DROP TABLE IF EXISTS names;
+DROP TABLE IF EXISTS named_capabilities;
+DROP TABLE IF EXISTS modalias_capabilities;
+DROP TABLE IF EXISTS locks;
+DROP TABLE IF EXISTS hal_capabilities;
+DROP TABLE IF EXISTS files;
+DROP TABLE IF EXISTS file_names;
+DROP TABLE IF EXISTS file_capabilities;
+DROP TABLE IF EXISTS dir_names;
+DROP TABLE IF EXISTS delta_packages;
+DROP TABLE IF EXISTS db_info;
+DROP TABLE IF EXISTS repositories;
+DROP INDEX IF EXISTS types_class_name_index;
+DROP INDEX IF EXISTS text_attributes_index;
+DROP INDEX IF EXISTS numeric_attributes_index;
+DROP INDEX IF EXISTS named_capabilities_name;
+
+------------------------------------------------
+-- version metadata, probably not needed, there
+-- is pragma user_version
+------------------------------------------------
+
+CREATE TABLE db_info (
+  version INTEGER
+);
+
+------------------------------------------------
+-- Basic types like archs, attributes, languages
+------------------------------------------------
+
+CREATE TABLE types (
+    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , class TEXT NOT NULL
+  , name TEXT NOT NULL
+);
+CREATE INDEX types_class_name_index ON types(class, name);
+
+------------------------------------------------
+-- Knew repositories. They existed some day.
+------------------------------------------------
+
+CREATE TABLE repositories (
+    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , alias TEXT NOT NULL UNIQUE
+  , checksum TEXT DEFAULT NULL
+  , timestamp INTEGER NOT NULL
+);
+CREATE INDEX repo_alias_index ON repositories(alias);
+
+------------------------------------------------
+-- Resolvable names
+------------------------------------------------
+
+CREATE TABLE names (
+    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , name TEXT UNIQUE
+);
+
+------------------------------------------------
+-- File names table and normalized sub tables
+------------------------------------------------
+
+CREATE TABLE file_names (
+   id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , name TEXT
+);
+
+CREATE TABLE dir_names (
+   id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , name TEXT
+);
+
+CREATE TABLE files (
+   id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , dir_name_id INTEGER NOT NULL
+  , file_name_id INTEGER NOT NULL
+  , UNIQUE ( dir_name_id, file_name_id )
+);
+
+------------------------------------------------
+-- Resolvables table
+------------------------------------------------
+
+-- Resolvables translated strings
+CREATE TABLE text_attributes (
+    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , weak_resolvable_id INTEGER NOT NULL
+  , lang_id INTEGER REFERENCES types(id)
+  , attr_id INTEGER REFERENCES types(id)
+  , text TEXT
+);
+CREATE INDEX text_attributes_index ON text_attributes(weak_resolvable_id, lang_id, attr_id);
+
+-- Resolvables numeric attributes
+CREATE TABLE numeric_attributes (
+    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , weak_resolvable_id INTEGER NOT NULL
+  , attr_id INTEGER REFERENCES types(id)
+  , value INTEGER NOT NULL
+);
+CREATE INDEX numeric_attributes_index ON numeric_attributes(weak_resolvable_id, attr_id);
+
+
+CREATE TABLE resolvables (
+    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , name TEXT
+  , version TEXT
+  , release TEXT
+  , epoch INTEGER
+  , arch INTEGER REFERENCES types(id)
+  , kind INTEGER REFERENCES types(id)
+  , repository_id INTEGER REFERENCES repositories(id)
+  , installed_size INTEGER
+  , archive_size INTEGER
+  , install_only INTEGER
+  , build_time INTEGER
+  , install_time INTEGER
+  , shared_id INTEGER DEFAULT NULL
+);
+CREATE INDEX resolvable_repository_id ON resolvables(repository_id);
+
+------------------------------------------------
+-- Do we need those here?
+------------------------------------------------
+
+CREATE TABLE locks (
+    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , name TEXT
+  , version TEXT
+  , release TEXT
+  , epoch INTEGER
+  , arch INTEGER
+  , relation INTEGER
+  , repository TEXT
+  , glob TEXT
+  , importance INTEGER
+  , importance_gteq INTEGER
+
+);
+
+CREATE TABLE delta_packages (
+    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , media_nr INTEGER
+  , location TEXT
+  , checksum TEXT
+  , download_size INTEGER
+  , build_time INTEGER
+  , baseversion_version TEXT
+  , baseversion_release TEXT
+  , baseversion_epoch INTEGER
+  , baseversion_checksum TEXT
+  , baseversion_build_time INTEGER
+  , baseversion_sequence_info TEXT
+
+);
+
+CREATE TABLE patch_packages (
+    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , media_nr INTEGER
+  , location TEXT
+  , checksum TEXT
+  , download_size INTEGER
+  , build_time INTEGER
+
+);
+
+CREATE TABLE patch_packages_baseversions (
+    id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , patch_package_id INTEGER REFERENCES patch_packages(id)
+  , version TEXT
+  , release TEXT
+  , epoch INTEGER
+
+);
+
+------------------------------------------------
+-- Capabilities
+------------------------------------------------
+
+CREATE TABLE named_capabilities (
+   id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , resolvable_id INTEGER REFERENCES resolvables(id)
+  , dependency_type INTEGER
+  , refers_kind INTEGER
+  , name_id INTEGER REFERENCES names(id)
+  , version TEXT
+  , release TEXT
+  , epoch INTEGER
+  , relation INTEGER
+);
+CREATE INDEX named_capabilities_name ON named_capabilities(name_id);
+CREATE INDEX named_capabilities_resolvable ON named_capabilities(resolvable_id);
+
+CREATE TABLE modalias_capabilities (
+   id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , resolvable_id INTEGER REFERENCES resolvables(id)
+  , dependency_type INTEGER
+  , refers_kind INTEGER
+  , name TEXT
+  , value TEXT
+  , relation INTEGER
+);
+CREATE INDEX modalias_capabilities_resolvable ON modalias_capabilities(resolvable_id);
+
+CREATE TABLE hal_capabilities (
+   id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , resolvable_id INTEGER REFERENCES resolvables(id)
+  , dependency_type INTEGER
+  , refers_kind INTEGER
+  , name TEXT
+  , value TEXT
+  , relation INTEGER
+);
+
+CREATE TABLE file_capabilities (
+   id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , resolvable_id INTEGER REFERENCES resolvables(id)
+  , dependency_type INTEGER
+  , refers_kind INTEGER
+  , file_id INTEGER REFERENCES files(id)
+);
+CREATE INDEX file_capabilities_resolvable ON file_capabilities(resolvable_id);
+
+CREATE TABLE other_capabilities (
+   id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , resolvable_id INTEGER REFERENCES resolvables(id)
+  , dependency_type INTEGER
+  , refers_kind INTEGER
+  , value TEXT
+);
+CREATE INDEX other_capabilities_resolvable ON other_capabilities(resolvable_id);
+
+CREATE TABLE split_capabilities (
+   id INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL
+  , resolvable_id INTEGER REFERENCES resolvables(id)
+  , dependency_type INTEGER
+  , refers_kind INTEGER
+  , name_id INTEGER REFERENCES names(id)
+  , file_id INTEGER REFERENCES files(id)
+);
+CREATE INDEX split_capabilities_resolvable ON split_capabilities(resolvable_id);
+
+-- Auto clean capabilities
+CREATE TRIGGER remove_resolvables
+  AFTER DELETE ON resolvables
+  BEGIN
+    DELETE FROM named_capabilities WHERE resolvable_id = old.id;
+    DELETE FROM modalias_capabilities WHERE resolvable_id = old.id;
+    DELETE FROM hal_capabilities WHERE resolvable_id = old.id;
+    DELETE FROM file_capabilities WHERE resolvable_id = old.id;
+    DELETE FROM split_capabilities WHERE resolvable_id = old.id;
+    DELETE FROM other_capabilities WHERE resolvable_id = old.id;
+  END;
+
+------------------------------------------------
+-- Associate resolvables and repositories
+------------------------------------------------
+
+-- FIXME do we want to allow same resolvable to
+-- be listed twice in same source but different
+-- medias? I think NOT.
+CREATE TABLE resolvables_repositories (
+    resolvable_id INTEGER REFERENCES resolvables (id)
+  , repository_id    INTEGER REFERENCES repositories    (id)
+  , repository_media_nr INTEGER
+  , PRIMARY KEY ( resolvable_id, repository_id )
+);
+
+-- Auto clean repositories
+CREATE TRIGGER remove_repositories
+  AFTER DELETE ON repositories
+  BEGIN
+    DELETE FROM resolvables WHERE repository_id = old.id;
+  END;
+
+CREATE TRIGGER remove_patch_packages_baseversions
+  AFTER DELETE ON patch_packages
+  BEGIN
+    DELETE FROM patch_packages_baseversions WHERE patch_package_id = old.id;
+  END;
+
+
diff --git a/zypp/cache/sqlite3x/sqlite3x.hpp b/zypp/cache/sqlite3x/sqlite3x.hpp
new file mode 100644 (file)
index 0000000..f45f464
--- /dev/null
@@ -0,0 +1,199 @@
+/*\r
+       Copyright (C) 2004-2005 Cory Nelson\r
+\r
+       This software is provided 'as-is', without any express or implied\r
+       warranty.  In no event will the authors be held liable for any damages\r
+       arising from the use of this software.\r
+\r
+       Permission is granted to anyone to use this software for any purpose,\r
+       including commercial applications, and to alter it and redistribute it\r
+       freely, subject to the following restrictions:\r
+\r
+       1. The origin of this software must not be misrepresented; you must not\r
+               claim that you wrote the original software. If you use this software\r
+               in a product, an acknowledgment in the product documentation would be\r
+               appreciated but is not required.\r
+       2. Altered source versions must be plainly marked as such, and must not be\r
+               misrepresented as being the original software.\r
+       3. This notice may not be removed or altered from any source distribution.\r
+\r
+       CVS Info :\r
+               $Author: phrostbyte $\r
+               $Date: 2005/06/16 20:46:40 $\r
+               $Revision: 1.1 $\r
+*/\r
+\r
+#ifndef __SQLITE3X_HPP__\r
+#define __SQLITE3X_HPP__\r
+\r
+#include <string>\r
+#include <exception>\r
+#include <stdexcept>\r
+#include <boost/utility.hpp>\r
+\r
+namespace sqlite3x\r
+{\r
+class sqlite3_connection : boost::noncopyable\r
+{\r
+private:\r
+  friend class sqlite3_command;\r
+  friend class database_error;\r
+\r
+  struct sqlite3 *db;\r
+\r
+public:\r
+  sqlite3_connection();\r
+  sqlite3_connection(const char *db);\r
+  sqlite3_connection(const wchar_t *db);\r
+  ~sqlite3_connection();\r
+\r
+  void open(const char *db);\r
+  void open(const wchar_t *db);\r
+  void close();\r
+\r
+  long long insertid();\r
+  void setbusytimeout(int ms);\r
+\r
+  void execute(const std::string &sql);\r
+  \r
+  void executenonquery(const char *sql);\r
+  void executenonquery(const wchar_t *sql);\r
+  void executenonquery(const std::string &sql);\r
+  void executenonquery(const std::wstring &sql);\r
+\r
+  int executeint(const char *sql);\r
+  int executeint(const wchar_t *sql);\r
+  int executeint(const std::string &sql);\r
+  int executeint(const std::wstring &sql);\r
+\r
+  long long executeint64(const char *sql);\r
+  long long executeint64(const wchar_t *sql);\r
+  long long executeint64(const std::string &sql);\r
+  long long executeint64(const std::wstring &sql);\r
+\r
+  double executedouble(const char *sql);\r
+  double executedouble(const wchar_t *sql);\r
+  double executedouble(const std::string &sql);\r
+  double executedouble(const std::wstring &sql);\r
+\r
+  std::string executestring(const char *sql);\r
+  std::string executestring(const wchar_t *sql);\r
+  std::string executestring(const std::string &sql);\r
+  std::string executestring(const std::wstring &sql);\r
+\r
+  std::wstring executestring16(const char *sql);\r
+  std::wstring executestring16(const wchar_t *sql);\r
+  std::wstring executestring16(const std::string &sql);\r
+  std::wstring executestring16(const std::wstring &sql);\r
+\r
+  std::string executeblob(const char *sql);\r
+  std::string executeblob(const wchar_t *sql);\r
+  std::string executeblob(const std::string &sql);\r
+  std::string executeblob(const std::wstring &sql);\r
+};\r
+\r
+class sqlite3_command;\r
+\r
+class database_error : public std::runtime_error\r
+{\r
+public:\r
+  database_error(const char *msg);\r
+  database_error(sqlite3_connection &con);\r
+};\r
+\r
+class sqlite3_transaction : boost::noncopyable\r
+{\r
+private:\r
+  sqlite3_connection &con;\r
+  bool intrans;\r
+\r
+public:\r
+  sqlite3_transaction(sqlite3_connection &con, bool start=true);\r
+  ~sqlite3_transaction();\r
+\r
+  void begin();\r
+  void commit();\r
+  void rollback();\r
+};\r
+\r
+class sqlite3_reader\r
+{\r
+private:\r
+  friend class sqlite3_command;\r
+\r
+  sqlite3_command *cmd;\r
+\r
+  sqlite3_reader(sqlite3_command *cmd);\r
+\r
+public:\r
+  sqlite3_reader();\r
+  sqlite3_reader(const sqlite3_reader &copy);\r
+  ~sqlite3_reader();\r
+\r
+  sqlite3_reader& operator=(const sqlite3_reader &copy);\r
+\r
+  bool read();\r
+  void reset();\r
+  void close();\r
+\r
+  int getint(int index);\r
+  long long getint64(int index);\r
+  double getdouble(int index);\r
+  std::string getstring(int index);\r
+  std::wstring getstring16(int index);\r
+  std::string getblob(int index);\r
+\r
+  std::string getcolname(int index);\r
+  std::wstring getcolname16(int index);\r
+};\r
+\r
+class sqlite3_command : boost::noncopyable\r
+{\r
+private:\r
+  friend class sqlite3_reader;\r
+\r
+  sqlite3_connection &con;\r
+  struct sqlite3_stmt *stmt;\r
+  unsigned int refs;\r
+  int argc;\r
+\r
+public:\r
+  sqlite3_command(sqlite3_connection &con, const char *sql);\r
+  sqlite3_command(sqlite3_connection &con, const wchar_t *sql);\r
+  sqlite3_command(sqlite3_connection &con, const std::string &sql);\r
+  sqlite3_command(sqlite3_connection &con, const std::wstring &sql);\r
+  ~sqlite3_command();\r
+\r
+  void bind(int index);\r
+  void bind(int index, int data);\r
+  void bind(int index, long long data);\r
+  void bind(int index, double data);\r
+  void bind(int index, const char *data, int datalen);\r
+  void bind(int index, const wchar_t *data, int datalen);\r
+  void bind(int index, const void *data, int datalen);\r
+  void bind(int index, const std::string &data);\r
+  void bind(int index, const std::wstring &data);\r
+  \r
+  void bind(const std::string &param);\r
+  void bind(const std::string &param, int data);\r
+  void bind(const std::string &param, long long data);\r
+  void bind(const std::string &param, double data);\r
+  void bind(const std::string &param, const char *data, int datalen);\r
+  void bind(const std::string &param, const wchar_t *data, int datalen);\r
+  void bind(const std::string &param, const void *data, int datalen);\r
+  void bind(const std::string &param, const std::string &data);\r
+  void bind(const std::string &param, const std::wstring &data);\r
+\r
+  sqlite3_reader executereader();\r
+  void executenonquery();\r
+  int executeint();\r
+  long long executeint64();\r
+  double executedouble();\r
+  std::string executestring();\r
+  std::wstring executestring16();\r
+  std::string executeblob();\r
+};\r
+\r
+}\r
+\r
+#endif\r
diff --git a/zypp/cache/sqlite3x/sqlite3x_command.cpp b/zypp/cache/sqlite3x/sqlite3x_command.cpp
new file mode 100644 (file)
index 0000000..2c077fa
--- /dev/null
@@ -0,0 +1,237 @@
+/*\r
+       Copyright (C) 2004-2005 Cory Nelson\r
+\r
+       This software is provided 'as-is', without any express or implied\r
+       warranty.  In no event will the authors be held liable for any damages\r
+       arising from the use of this software.\r
+\r
+       Permission is granted to anyone to use this software for any purpose,\r
+       including commercial applications, and to alter it and redistribute it\r
+       freely, subject to the following restrictions:\r
+\r
+       1. The origin of this software must not be misrepresented; you must not\r
+               claim that you wrote the original software. If you use this software\r
+               in a product, an acknowledgment in the product documentation would be\r
+               appreciated but is not required.\r
+       2. Altered source versions must be plainly marked as such, and must not be\r
+               misrepresented as being the original software.\r
+       3. This notice may not be removed or altered from any source distribution.\r
+\r
+       CVS Info :\r
+               $Author: phrostbyte $\r
+               $Date: 2005/06/16 20:46:40 $\r
+               $Revision: 1.1 $\r
+*/\r
+\r
+#include <sqlite3.h>\r
+#include "sqlite3x.hpp"\r
+\r
+namespace sqlite3x\r
+{\r
+\r
+sqlite3_command::sqlite3_command(sqlite3_connection &con, const char *sql) : con(con),refs(0)\r
+{\r
+  const char *tail=NULL;\r
+  if (sqlite3_prepare(con.db, sql, -1, &this->stmt, &tail)!=SQLITE_OK)\r
+    throw database_error(con);\r
+\r
+  this->argc=sqlite3_column_count(this->stmt);\r
+}\r
+\r
+sqlite3_command::sqlite3_command(sqlite3_connection &con, const wchar_t *sql) : con(con),refs(0)\r
+{\r
+  const wchar_t *tail=NULL;\r
+  if (sqlite3_prepare16(con.db, sql, -1, &this->stmt, (const void**)&tail)!=SQLITE_OK)\r
+    throw database_error(con);\r
+\r
+  this->argc=sqlite3_column_count(this->stmt);\r
+}\r
+\r
+sqlite3_command::sqlite3_command(sqlite3_connection &con, const std::string &sql) : con(con),refs(0)\r
+{\r
+  const char *tail=NULL;\r
+  if (sqlite3_prepare(con.db, sql.data(), (int)sql.length(), &this->stmt, &tail)!=SQLITE_OK)\r
+    throw database_error(con);\r
+\r
+  this->argc=sqlite3_column_count(this->stmt);\r
+}\r
+\r
+sqlite3_command::sqlite3_command(sqlite3_connection &con, const std::wstring &sql) : con(con),refs(0)\r
+{\r
+  const wchar_t *tail=NULL;\r
+  if (sqlite3_prepare16(con.db, sql.data(), (int)sql.length()*2, &this->stmt, (const void**)&tail)!=SQLITE_OK)\r
+    throw database_error(con);\r
+\r
+  this->argc=sqlite3_column_count(this->stmt);\r
+}\r
+\r
+sqlite3_command::~sqlite3_command()\r
+{\r
+  sqlite3_finalize(this->stmt);\r
+}\r
+\r
+void sqlite3_command::bind(int index)\r
+{\r
+  if (sqlite3_bind_null(this->stmt, index)!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+void sqlite3_command::bind(int index, int data)\r
+{\r
+  if (sqlite3_bind_int(this->stmt, index, data)!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+void sqlite3_command::bind(int index, long long data)\r
+{\r
+  if (sqlite3_bind_int64(this->stmt, index, data)!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+void sqlite3_command::bind(int index, double data)\r
+{\r
+  if (sqlite3_bind_double(this->stmt, index, data)!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+void sqlite3_command::bind(int index, const char *data, int datalen)\r
+{\r
+  if (sqlite3_bind_text(this->stmt, index, data, datalen, SQLITE_TRANSIENT)!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+void sqlite3_command::bind(int index, const wchar_t *data, int datalen)\r
+{\r
+  if (sqlite3_bind_text16(this->stmt, index, data, datalen, SQLITE_TRANSIENT)!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+void sqlite3_command::bind(int index, const void *data, int datalen)\r
+{\r
+  if (sqlite3_bind_blob(this->stmt, index, data, datalen, SQLITE_TRANSIENT)!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+void sqlite3_command::bind(int index, const std::string &data)\r
+{\r
+  if (sqlite3_bind_text(this->stmt, index, data.data(), (int)data.length(), SQLITE_TRANSIENT)!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+void sqlite3_command::bind(int index, const std::wstring &data)\r
+{\r
+  if (sqlite3_bind_text16(this->stmt, index, data.data(), (int)data.length()*2, SQLITE_TRANSIENT)!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+// named parameters bind\r
+\r
+void sqlite3_command::bind(const std::string &param)\r
+{\r
+  if (sqlite3_bind_null(this->stmt, sqlite3_bind_parameter_index( this->stmt, param.c_str() ) )!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+void sqlite3_command::bind(const std::string &param, int data)\r
+{\r
+  if (sqlite3_bind_int(this->stmt, sqlite3_bind_parameter_index( this->stmt, param.c_str() ) , data)!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+void sqlite3_command::bind(const std::string &param, long long data)\r
+{\r
+  if (sqlite3_bind_int64(this->stmt, sqlite3_bind_parameter_index( this->stmt, param.c_str() ) , data)!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+void sqlite3_command::bind(const std::string &param, double data)\r
+{\r
+  if (sqlite3_bind_double(this->stmt, sqlite3_bind_parameter_index( this->stmt, param.c_str() ) , data)!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+void sqlite3_command::bind(const std::string &param, const char *data, int datalen)\r
+{\r
+  if (sqlite3_bind_text(this->stmt, sqlite3_bind_parameter_index( this->stmt, param.c_str() ) , data, datalen, SQLITE_TRANSIENT)!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+void sqlite3_command::bind(const std::string &param, const wchar_t *data, int datalen)\r
+{\r
+  if (sqlite3_bind_text16(this->stmt, sqlite3_bind_parameter_index( this->stmt, param.c_str() ) , data, datalen, SQLITE_TRANSIENT)!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+void sqlite3_command::bind(const std::string &param, const void *data, int datalen)\r
+{\r
+  if (sqlite3_bind_blob(this->stmt, sqlite3_bind_parameter_index( this->stmt, param.c_str() ) , data, datalen, SQLITE_TRANSIENT)!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+void sqlite3_command::bind(const std::string &param, const std::string &data)\r
+{\r
+  if (sqlite3_bind_text(this->stmt, sqlite3_bind_parameter_index( this->stmt, param.c_str() ) , data.data(), (int)data.length(), SQLITE_TRANSIENT)!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+void sqlite3_command::bind(const std::string &param, const std::wstring &data)\r
+{\r
+  if (sqlite3_bind_text16(this->stmt, sqlite3_bind_parameter_index( this->stmt, param.c_str() ) , data.data(), (int)data.length()*2, SQLITE_TRANSIENT)!=SQLITE_OK)\r
+    throw database_error(this->con);\r
+}\r
+\r
+\r
+\r
+sqlite3_reader sqlite3_command::executereader()\r
+{\r
+  return sqlite3_reader(this);\r
+}\r
+\r
+void sqlite3_command::executenonquery()\r
+{\r
+  this->executereader().read();\r
+}\r
+\r
+int sqlite3_command::executeint()\r
+{\r
+  sqlite3_reader reader=this->executereader();\r
+  if (!reader.read()) throw database_error("nothing to read");\r
+  return reader.getint(0);\r
+}\r
+\r
+long long sqlite3_command::executeint64()\r
+{\r
+  sqlite3_reader reader=this->executereader();\r
+  if (!reader.read()) throw database_error("nothing to read");\r
+  return reader.getint64(0);\r
+}\r
+\r
+double sqlite3_command::executedouble()\r
+{\r
+  sqlite3_reader reader=this->executereader();\r
+  if (!reader.read()) throw database_error("nothing to read");\r
+  return reader.getdouble(0);\r
+}\r
+\r
+std::string sqlite3_command::executestring()\r
+{\r
+  sqlite3_reader reader=this->executereader();\r
+  if (!reader.read()) throw database_error("nothing to read");\r
+  return reader.getstring(0);\r
+}\r
+\r
+std::wstring sqlite3_command::executestring16()\r
+{\r
+  sqlite3_reader reader=this->executereader();\r
+  if (!reader.read()) throw database_error("nothing to read");\r
+  return reader.getstring16(0);\r
+}\r
+\r
+std::string sqlite3_command::executeblob()\r
+{\r
+  sqlite3_reader reader=this->executereader();\r
+  if (!reader.read()) throw database_error("nothing to read");\r
+  return reader.getblob(0);\r
+}\r
+\r
+}\r
diff --git a/zypp/cache/sqlite3x/sqlite3x_connection.cpp b/zypp/cache/sqlite3x/sqlite3x_connection.cpp
new file mode 100644 (file)
index 0000000..d6906ec
--- /dev/null
@@ -0,0 +1,278 @@
+/*\r
+       Copyright (C) 2004-2005 Cory Nelson\r
+\r
+       This software is provided 'as-is', without any express or implied\r
+       warranty.  In no event will the authors be held liable for any damages\r
+       arising from the use of this software.\r
+\r
+       Permission is granted to anyone to use this software for any purpose,\r
+       including commercial applications, and to alter it and redistribute it\r
+       freely, subject to the following restrictions:\r
+\r
+       1. The origin of this software must not be misrepresented; you must not\r
+               claim that you wrote the original software. If you use this software\r
+               in a product, an acknowledgment in the product documentation would be\r
+               appreciated but is not required.\r
+       2. Altered source versions must be plainly marked as such, and must not be\r
+               misrepresented as being the original software.\r
+       3. This notice may not be removed or altered from any source distribution.\r
+\r
+       CVS Info :\r
+               $Author: phrostbyte $\r
+               $Date: 2005/06/16 20:46:40 $\r
+               $Revision: 1.1 $\r
+*/\r
+\r
+/* \r
+  this source contains modifications by Novell Inc.\r
+  \r
+  Changes:\r
+  \r
+  * dmacvicar@novell.com\r
+    Wrap sqlite3_exec\r
+\r
+*/\r
+\r
+#include <sqlite3.h>\r
+#include "sqlite3x.hpp"\r
+\r
+namespace sqlite3x\r
+{\r
+\r
+sqlite3_connection::sqlite3_connection() : db(NULL)\r
+{}\r
+\r
+sqlite3_connection::sqlite3_connection(const char *db) : db(NULL)\r
+{\r
+  this->open(db);\r
+}\r
+\r
+sqlite3_connection::sqlite3_connection(const wchar_t *db) : db(NULL)\r
+{\r
+  this->open(db);\r
+}\r
+\r
+sqlite3_connection::~sqlite3_connection()\r
+{\r
+  if (this->db) sqlite3_close(this->db);\r
+}\r
+\r
+void sqlite3_connection::open(const char *db)\r
+{\r
+  if (sqlite3_open(db, &this->db)!=SQLITE_OK)\r
+    throw database_error("unable to open database");\r
+}\r
+\r
+void sqlite3_connection::open(const wchar_t *db)\r
+{\r
+  if (sqlite3_open16(db, &this->db)!=SQLITE_OK)\r
+    throw database_error("unable to open database");\r
+}\r
+\r
+void sqlite3_connection::close()\r
+{\r
+  if (this->db)\r
+  {\r
+    if (sqlite3_close(this->db)!=SQLITE_OK)\r
+      throw database_error(*this);\r
+    this->db=NULL;\r
+  }\r
+}\r
+\r
+long long sqlite3_connection::insertid()\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_last_insert_rowid(this->db);\r
+}\r
+\r
+void sqlite3_connection::setbusytimeout(int ms)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+\r
+  if (sqlite3_busy_timeout(this->db, ms)!=SQLITE_OK)\r
+    throw database_error(*this);\r
+}\r
+\r
+void sqlite3_connection::executenonquery(const char *sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  sqlite3_command(*this, sql).executenonquery();\r
+}\r
+\r
+void sqlite3_connection::executenonquery(const wchar_t *sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  sqlite3_command(*this, sql).executenonquery();\r
+}\r
+\r
+void sqlite3_connection::executenonquery(const std::string &sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  sqlite3_command(*this, sql).executenonquery();\r
+}\r
+\r
+void sqlite3_connection::executenonquery(const std::wstring &sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  sqlite3_command(*this, sql).executenonquery();\r
+}\r
+\r
+int sqlite3_connection::executeint(const char *sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executeint();\r
+}\r
+\r
+int sqlite3_connection::executeint(const wchar_t *sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executeint();\r
+}\r
+\r
+int sqlite3_connection::executeint(const std::string &sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executeint();\r
+}\r
+\r
+int sqlite3_connection::executeint(const std::wstring &sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executeint();\r
+}\r
+\r
+long long sqlite3_connection::executeint64(const char *sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executeint64();\r
+}\r
+\r
+long long sqlite3_connection::executeint64(const wchar_t *sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executeint64();\r
+}\r
+\r
+long long sqlite3_connection::executeint64(const std::string &sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executeint64();\r
+}\r
+\r
+long long sqlite3_connection::executeint64(const std::wstring &sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executeint64();\r
+}\r
+\r
+double sqlite3_connection::executedouble(const char *sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executedouble();\r
+}\r
+\r
+double sqlite3_connection::executedouble(const wchar_t *sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executedouble();\r
+}\r
+\r
+double sqlite3_connection::executedouble(const std::string &sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executedouble();\r
+}\r
+\r
+double sqlite3_connection::executedouble(const std::wstring &sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executedouble();\r
+}\r
+\r
+std::string sqlite3_connection::executestring(const char *sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executestring();\r
+}\r
+\r
+std::string sqlite3_connection::executestring(const wchar_t *sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executestring();\r
+}\r
+\r
+std::string sqlite3_connection::executestring(const std::string &sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executestring();\r
+}\r
+\r
+std::string sqlite3_connection::executestring(const std::wstring &sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executestring();\r
+}\r
+\r
+std::wstring sqlite3_connection::executestring16(const char *sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executestring16();\r
+}\r
+\r
+std::wstring sqlite3_connection::executestring16(const wchar_t *sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executestring16();\r
+}\r
+\r
+std::wstring sqlite3_connection::executestring16(const std::string &sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executestring16();\r
+}\r
+\r
+std::wstring sqlite3_connection::executestring16(const std::wstring &sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executestring16();\r
+}\r
+\r
+std::string sqlite3_connection::executeblob(const char *sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executeblob();\r
+}\r
+\r
+std::string sqlite3_connection::executeblob(const wchar_t *sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executeblob();\r
+}\r
+\r
+std::string sqlite3_connection::executeblob(const std::string &sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executeblob();\r
+}\r
+\r
+std::string sqlite3_connection::executeblob(const std::wstring &sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  return sqlite3_command(*this, sql).executeblob();\r
+}\r
+\r
+void sqlite3_connection::execute(const std::string &sql)\r
+{\r
+  if (!this->db) throw database_error("database is not open");\r
+  \r
+  char *err_msg;\r
+  \r
+  if ( sqlite3_exec( this->db, sql.c_str(), NULL, NULL, &err_msg ) != SQLITE_OK )\r
+  {\r
+    std::string err(err_msg);\r
+    sqlite3_free(err_msg);\r
+    throw database_error(err.c_str());\r
+  }\r
+}\r
+\r
+}\r
diff --git a/zypp/cache/sqlite3x/sqlite3x_exception.cpp b/zypp/cache/sqlite3x/sqlite3x_exception.cpp
new file mode 100644 (file)
index 0000000..eb56d3b
--- /dev/null
@@ -0,0 +1,37 @@
+/*\r
+       Copyright (C) 2004-2005 Cory Nelson\r
+\r
+       This software is provided 'as-is', without any express or implied\r
+       warranty.  In no event will the authors be held liable for any damages\r
+       arising from the use of this software.\r
+\r
+       Permission is granted to anyone to use this software for any purpose,\r
+       including commercial applications, and to alter it and redistribute it\r
+       freely, subject to the following restrictions:\r
+\r
+       1. The origin of this software must not be misrepresented; you must not\r
+               claim that you wrote the original software. If you use this software\r
+               in a product, an acknowledgment in the product documentation would be\r
+               appreciated but is not required.\r
+       2. Altered source versions must be plainly marked as such, and must not be\r
+               misrepresented as being the original software.\r
+       3. This notice may not be removed or altered from any source distribution.\r
+\r
+       CVS Info :\r
+               $Author: phrostbyte $\r
+               $Date: 2005/06/16 20:46:40 $\r
+               $Revision: 1.1 $\r
+*/\r
+\r
+#include <sqlite3.h>\r
+#include "sqlite3x.hpp"\r
+\r
+namespace sqlite3x\r
+{\r
+\r
+database_error::database_error(const char *msg) : runtime_error(msg)\r
+{}\r
+database_error::database_error(sqlite3_connection &con) : runtime_error(sqlite3_errmsg(con.db))\r
+{}\r
+\r
+}\r
diff --git a/zypp/cache/sqlite3x/sqlite3x_reader.cpp b/zypp/cache/sqlite3x/sqlite3x_reader.cpp
new file mode 100644 (file)
index 0000000..3e49836
--- /dev/null
@@ -0,0 +1,148 @@
+/*\r
+       Copyright (C) 2004-2005 Cory Nelson\r
+\r
+       This software is provided 'as-is', without any express or implied\r
+       warranty.  In no event will the authors be held liable for any damages\r
+       arising from the use of this software.\r
+\r
+       Permission is granted to anyone to use this software for any purpose,\r
+       including commercial applications, and to alter it and redistribute it\r
+       freely, subject to the following restrictions:\r
+\r
+       1. The origin of this software must not be misrepresented; you must not\r
+               claim that you wrote the original software. If you use this software\r
+               in a product, an acknowledgment in the product documentation would be\r
+               appreciated but is not required.\r
+       2. Altered source versions must be plainly marked as such, and must not be\r
+               misrepresented as being the original software.\r
+       3. This notice may not be removed or altered from any source distribution.\r
+\r
+       CVS Info :\r
+               $Author: phrostbyte $\r
+               $Date: 2005/06/16 20:46:40 $\r
+               $Revision: 1.1 $\r
+*/\r
+\r
+#include <sqlite3.h>\r
+#include "sqlite3x.hpp"\r
+\r
+namespace sqlite3x\r
+{\r
+\r
+sqlite3_reader::sqlite3_reader() : cmd(NULL)\r
+{}\r
+\r
+sqlite3_reader::sqlite3_reader(const sqlite3_reader &copy) : cmd(copy.cmd)\r
+{\r
+  if (this->cmd) ++this->cmd->refs;\r
+}\r
+\r
+sqlite3_reader::sqlite3_reader(sqlite3_command *cmd) : cmd(cmd)\r
+{\r
+  ++cmd->refs;\r
+}\r
+\r
+sqlite3_reader::~sqlite3_reader()\r
+{\r
+  this->close();\r
+}\r
+\r
+sqlite3_reader& sqlite3_reader::operator=(const sqlite3_reader &copy)\r
+{\r
+  this->close();\r
+\r
+  this->cmd=copy.cmd;\r
+  if (this->cmd) ++this->cmd->refs;\r
+\r
+  return *this;\r
+}\r
+\r
+bool sqlite3_reader::read()\r
+{\r
+  if (!this->cmd) throw database_error("reader is closed");\r
+\r
+  switch (sqlite3_step(this->cmd->stmt))\r
+  {\r
+  case SQLITE_ROW:\r
+    return true;\r
+  case SQLITE_DONE:\r
+    return false;\r
+  default:\r
+    throw database_error(this->cmd->con);\r
+  }\r
+}\r
+\r
+void sqlite3_reader::reset()\r
+{\r
+  if (!this->cmd) throw database_error("reader is closed");\r
+\r
+  if (sqlite3_reset(this->cmd->stmt)!=SQLITE_OK)\r
+    throw database_error(this->cmd->con);\r
+}\r
+\r
+void sqlite3_reader::close()\r
+{\r
+  if (this->cmd)\r
+  {\r
+    if (--this->cmd->refs==0) sqlite3_reset(this->cmd->stmt);\r
+    this->cmd=NULL;\r
+  }\r
+}\r
+\r
+int sqlite3_reader::getint(int index)\r
+{\r
+  if (!this->cmd) throw database_error("reader is closed");\r
+  if ((index)>(this->cmd->argc-1)) throw std::out_of_range("index out of range");\r
+  return sqlite3_column_int(this->cmd->stmt, index);\r
+}\r
+\r
+long long sqlite3_reader::getint64(int index)\r
+{\r
+  if (!this->cmd) throw database_error("reader is closed");\r
+  if ((index)>(this->cmd->argc-1)) throw std::out_of_range("index out of range");\r
+  return sqlite3_column_int64(this->cmd->stmt, index);\r
+}\r
+\r
+double sqlite3_reader::getdouble(int index)\r
+{\r
+  if (!this->cmd) throw database_error("reader is closed");\r
+  if ((index)>(this->cmd->argc-1)) throw std::out_of_range("index out of range");\r
+  return sqlite3_column_double(this->cmd->stmt, index);\r
+}\r
+\r
+std::string sqlite3_reader::getstring(int index)\r
+{\r
+  if (!this->cmd) throw database_error("reader is closed");\r
+  if ((index)>(this->cmd->argc-1)) throw std::out_of_range("index out of range");\r
+  return std::string((const char*)sqlite3_column_text(this->cmd->stmt, index), sqlite3_column_bytes(this->cmd->stmt, index));\r
+}\r
+\r
+std::wstring sqlite3_reader::getstring16(int index)\r
+{\r
+  if (!this->cmd) throw database_error("reader is closed");\r
+  if ((index)>(this->cmd->argc-1)) throw std::out_of_range("index out of range");\r
+  return std::wstring((const wchar_t*)sqlite3_column_text16(this->cmd->stmt, index), sqlite3_column_bytes16(this->cmd->stmt, index)/2);\r
+}\r
+\r
+std::string sqlite3_reader::getblob(int index)\r
+{\r
+  if (!this->cmd) throw database_error("reader is closed");\r
+  if ((index)>(this->cmd->argc-1)) throw std::out_of_range("index out of range");\r
+  return std::string((const char*)sqlite3_column_blob(this->cmd->stmt, index), sqlite3_column_bytes(this->cmd->stmt, index));\r
+}\r
+\r
+std::string sqlite3_reader::getcolname(int index)\r
+{\r
+  if (!this->cmd) throw database_error("reader is closed");\r
+  if ((index)>(this->cmd->argc-1)) throw std::out_of_range("index out of range");\r
+  return sqlite3_column_name(this->cmd->stmt, index);\r
+}\r
+\r
+std::wstring sqlite3_reader::getcolname16(int index)\r
+{\r
+  if (!this->cmd) throw database_error("reader is closed");\r
+  if ((index)>(this->cmd->argc-1)) throw std::out_of_range("index out of range");\r
+  return (const wchar_t*)sqlite3_column_name16(this->cmd->stmt, index);\r
+}\r
+\r
+}\r
diff --git a/zypp/cache/sqlite3x/sqlite3x_transaction.cpp b/zypp/cache/sqlite3x/sqlite3x_transaction.cpp
new file mode 100644 (file)
index 0000000..90bf5fb
--- /dev/null
@@ -0,0 +1,70 @@
+/*\r
+       Copyright (C) 2004-2005 Cory Nelson\r
+\r
+       This software is provided 'as-is', without any express or implied\r
+       warranty.  In no event will the authors be held liable for any damages\r
+       arising from the use of this software.\r
+\r
+       Permission is granted to anyone to use this software for any purpose,\r
+       including commercial applications, and to alter it and redistribute it\r
+       freely, subject to the following restrictions:\r
+\r
+       1. The origin of this software must not be misrepresented; you must not\r
+               claim that you wrote the original software. If you use this software\r
+               in a product, an acknowledgment in the product documentation would be\r
+               appreciated but is not required.\r
+       2. Altered source versions must be plainly marked as such, and must not be\r
+               misrepresented as being the original software.\r
+       3. This notice may not be removed or altered from any source distribution.\r
+\r
+       CVS Info :\r
+               $Author: phrostbyte $\r
+               $Date: 2005/06/16 20:46:40 $\r
+               $Revision: 1.1 $\r
+*/\r
+\r
+#include <sqlite3.h>\r
+#include "sqlite3x.hpp"\r
+\r
+namespace sqlite3x\r
+{\r
+\r
+sqlite3_transaction::sqlite3_transaction(sqlite3_connection &con, bool start) : con(con),intrans(false)\r
+{\r
+  if (start) begin();\r
+}\r
+\r
+sqlite3_transaction::~sqlite3_transaction()\r
+{\r
+  if (intrans)\r
+  {\r
+    try\r
+    {\r
+      rollback();\r
+    }\r
+    catch (...)\r
+    {\r
+      return;\r
+    }\r
+  }\r
+}\r
+\r
+void sqlite3_transaction::begin()\r
+{\r
+  con.executenonquery("begin;");\r
+  intrans=true;\r
+}\r
+\r
+void sqlite3_transaction::commit()\r
+{\r
+  con.executenonquery("commit;");\r
+  intrans=false;\r
+}\r
+\r
+void sqlite3_transaction::rollback()\r
+{\r
+  con.executenonquery("rollback;");\r
+  intrans=false;\r
+}\r
+\r
+}\r
diff --git a/zypp/cache/sqliteext/zlibext.c b/zypp/cache/sqliteext/zlibext.c
new file mode 100644 (file)
index 0000000..7ac96b2
--- /dev/null
@@ -0,0 +1,435 @@
+/*
+** Zlib for sqlite3
+**
+** Compile: gcc -o zlib.so -shared zlibext.c -lsqlite3 -lz
+**
+** based on sqaux code from    James P. Lyon
+** ported to sqlite3 by Duncan Mac-Vicar
+**
+** The authors disclaims copyright to this source code.  In place of
+** a legal notice, here is a blessing:
+**
+**    May you do good and not evil.
+**    May you find forgiveness for yourself and forgive others.
+**    May you share freely, never taking more than you give.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <string.h>
+#include <assert.h>
+
+#include <sqlite3ext.h>
+#include <zlib.h>
+
+#include <sqlite3ext.h>
+SQLITE_EXTENSION_INIT1
+
+/*
+** Compute the maximum size required by sqlite_encode_binary().
+** This doesn't include the NUL byte which terminates the string.
+*/
+int sqaux_encode_maxsize(int datasize)
+{
+       int nEncMax = (256*datasize + 1262)/253;
+       return nEncMax;
+}
+
+/*
+** Encode a binary buffer "in" of size n bytes so that it contains
+** no instances of characters '\'' or '\000'.  The output is 
+** null-terminated and can be used as a string value in an INSERT
+** or UPDATE statement.  Use sqlite_decode_binary() to convert the
+** string back into its original binary.
+**
+** The result is written into a preallocated output buffer "out".
+** "out" must be able to hold at least 2 +(257*n)/254 bytes.
+** In other words, the output will be expanded by as much as 3
+** bytes for every 254 bytes of input plus 2 bytes of fixed overhead.
+** (This is approximately 2 + 1.0118*n or about a 1.2% size increase.)
+**
+** The return value is the number of characters in the encoded
+** string, excluding the "\000" terminator.
+*/
+int sqlite3_encode_binary(const unsigned char *in, int n, unsigned char *out){
+  int i, j, e, m;
+  int cnt[256];
+  if( n<=0 ){
+    out[0] = 'x';
+    out[1] = 0;
+    return 1;
+  }
+  memset(cnt, 0, sizeof(cnt));
+  for(i=n-1; i>=0; i--){ cnt[in[i]]++; }
+  m = n;
+  for(i=1; i<256; i++){
+    int sum;
+    if( i=='\'' ) continue;
+    sum = cnt[i] + cnt[(i+1)&0xff] + cnt[(i+'\'')&0xff];
+    if( sum<m ){
+      m = sum;
+      e = i;
+      if( m==0 ) break;
+    }
+  }
+  out[0] = e;
+  j = 1;
+  for(i=0; i<n; i++){
+    int c = (in[i] - e)&0xff;
+    if( c==0 ){
+      out[j++] = 1;
+      out[j++] = 1;
+    }else if( c==1 ){
+      out[j++] = 1;
+      out[j++] = 2;
+    }else if( c=='\'' ){
+      out[j++] = 1;
+      out[j++] = 3;
+    }else{
+      out[j++] = c;
+    }
+  }
+  out[j] = 0;
+  return j;
+}
+
+/*
+** Decode the string "in" into binary data and write it into "out".
+** This routine reverses the encoding created by sqlite_encode_binary().
+** The output will always be a few bytes less than the input.  The number
+** of bytes of output is returned.  If the input is not a well-formed
+** encoding, -1 is returned.
+**
+** The "in" and "out" parameters may point to the same buffer in order
+** to decode a string in place.
+*/
+int sqlite3_decode_binary(const unsigned char *in, unsigned char *out){
+  int i, c, e;
+  e = *(in++);
+  i = 0;
+  while( (c = *(in++))!=0 ){
+    if( c==1 ){
+      c = *(in++);
+      if( c==1 ){
+        c = 0;
+      }else if( c==2 ){
+        c = 1;
+      }else if( c==3 ){
+        c = '\'';
+      }else{
+        return -1;
+      }
+    }
+    out[i++] = (c + e)&0xff;
+  }
+  return i;
+}
+
+
+/*
+** Compute the adler32 checksum of a string.
+** This function is exported from the zlib library.
+** Return the checksum as a hex string.
+** THIS IS AN SQLITE USER FUNCTION.
+**
+** argv[0] Data                ** encoded data to compute checksum of
+*/
+void FnAdler32(sqlite3_context *context, int argc, sqlite3_value **argv)
+{
+       unsigned long checksum;
+       char buf[8+1]; /* Buffer to hold 8 hex digits. */
+
+       /* Validate arguments. */
+       assert(argc == 1 && argv && argv[0]);
+
+       checksum = adler32(0L, Z_NULL, 0);
+
+       /* Compute the checksum */
+       if (argc == 1 && argv && argv[0])
+       {
+               int len = strlen(sqlite3_value_text(argv[0]));
+               checksum = adler32(checksum, (const unsigned char*)argv[0], len);
+       }
+
+       /* Convert checksum to (upper-case) hexadecimal string. */
+       sprintf(buf, "%08X", checksum);
+
+       /* 'Return' the string.
+       ** -1 means use entire string.
+       */
+       sqlite3_result_text(context, buf, -1, SQLITE_STATIC);
+}
+
+/*
+** Decode string data stored using ZipString().
+** This undoes sqlite binary encoding and zip compression.
+** <pData> is the NUL-terminated data string stored in the sqlite database.
+** <nSize> is the uncompressed size of the data.
+**   If -1 is passed for the size, it will be computed from strlen().
+** <pzErrMsg> points to a string pointer, to allow returning an error message.
+**   This argument can be NULL. It should not be freed by the caller.
+** Returns a pointer to dynamically allocated string.
+** Returns NULL on failure.
+*/
+char* UnzipString(const char* pData, long nSize, const char **pzErrMsg)
+{
+       long nEncSize, nZipSize;
+       long nXmlSize;
+       char *pZip, *pXml;
+       int zret;
+
+       assert(pData); if (!pData) return NULL;
+       assert(nSize >= 0); if (nSize < 0) return NULL;
+
+       /*
+       ** Set up a buffer to hold the unencoded zip data.
+       ** This data can contain NUL bytes.
+       ** This will always no larger in size than the encoded binary data.
+       */
+       nEncSize = strlen(pData);
+       pZip = (char*)malloc(nEncSize+1);
+       if (!pZip)
+       {
+               if (pzErrMsg)
+                       *pzErrMsg = "UnzipString: malloc() failure.";
+               return NULL;
+       }
+
+       /*
+       ** Decode the sqlite encoding of the zip data.
+       ** This returns the actual size of the unencoded [zip] data.
+       */
+       nZipSize = sqlite3_decode_binary((const unsigned char *)pData, (unsigned char *)pZip);
+       if (nZipSize < 0) /* error */
+       {
+               if (pzErrMsg)
+                       *pzErrMsg = "UnzipString: sqlite3_decode_binary() failure.";
+               free(pZip);
+               return NULL;
+       }
+
+       /*
+       ** Set up a buffer to hold the uncompressed data.
+       ** This data can contain NUL bytes.
+       ** We allocate extra size just to be safe.
+       ** NEED to find out how much extra we really need to pad.
+       ** This will be generally less than 10kB in size.
+       */
+       pXml = (char*)malloc(nSize+1);
+       if (!pXml)
+       {
+               if (pzErrMsg)
+                       *pzErrMsg = "UnzipString: malloc() failure.";
+               free(pZip);
+               return NULL;
+       }
+
+       /* Decompress the data into the XML string. */
+       nXmlSize = nSize;
+       zret = uncompress((unsigned char*)pXml, (unsigned long*)&nXmlSize, (const unsigned char*)pZip, nZipSize);
+       if (zret != Z_OK)
+       {
+               if (pzErrMsg)
+                       *pzErrMsg = "UnzipString: uncompress() failure.";
+               free(pZip);
+               free(pXml);
+               return NULL;
+       }
+       assert(nXmlSize == nSize);
+
+       /* Terminate the string. */
+       pXml[nXmlSize] = 0;
+
+       /* Free the zipped data. */
+       free(pZip);
+
+       return pXml;
+}
+
+/*
+** Compress and encode string data to be stored in an sqlite database.
+** This does zip compression and sqlite binary encoding on the string.
+** <pXml> is the NUL-terminated xml string to be stored in the sqlite Files.Data field.
+** <nSize> is the uncompressed size of the xml string. Can be -1 to cause to compute it.
+** <pzErrMsg> points to a string pointer, to allow returning an error message.
+**   This argument can be NULL. It should not be freed.
+** Return pointer to dynamically allocated encoded string.
+** Returns NULL on failure.
+*/
+char* ZipString(const char* pXml, long nXmlSize, const char **pzErrMsg)
+{
+       unsigned long nZipSize, nZipMax, nDataSize, nDataMax, i;
+       char *pZip, *pData;
+       int zret;
+
+       assert(pXml); if (!pXml) return NULL;
+
+       /* Compute the size if necessary. */
+       if (nXmlSize < 0)
+               nXmlSize = strlen(pXml);
+       assert((unsigned long)nXmlSize == strlen(pXml));
+
+       /*
+       ** Set up a buffer to hold the unencoded zip data.
+       ** This data can contain NUL bytes.
+       ** This can be larger than the XML data.
+       */
+       nZipMax = nXmlSize + nXmlSize/512 + 12;
+       pZip = (char*)malloc(nZipMax);
+       if (!pZip)
+       {
+               if (pzErrMsg)
+                       *pzErrMsg = "ZipString: malloc() failure.";
+               return NULL;
+       }
+
+       /*
+       ** Compress the xml data into the zip buffer.
+       ** This returns the actual size in <nZipSize>.
+       */
+       nZipSize = nZipMax;
+       zret = compress2((unsigned char*)pZip, &nZipSize, (const unsigned char*)pXml, nXmlSize, Z_BEST_COMPRESSION);
+       if (zret != Z_OK)
+       {
+               if (pzErrMsg)
+                       *pzErrMsg = "ZipString: compress2() failure.";
+               free (pZip);
+               return NULL;
+       }
+       assert(nZipSize <= nZipMax);
+
+       /*
+       ** Allocate the buffer to hold the encoded binary data.
+       ** This data will not contain NUL bytes.
+       ** This buffer will generally be larger than the unencoded data.
+       ** In general it will be smaller than the size allocated for the zipped data.
+       */
+       nDataMax = sqaux_encode_maxsize(nZipSize);
+       pData = (char*)malloc(nDataMax+1);
+       if (!pData)
+       {
+               if (pzErrMsg)
+                       *pzErrMsg = "ZipString: realloc() failure.";
+               free(pZip);
+               return NULL;
+       }
+
+       /*
+       ** Encode the binary data to convert to a form safe to store in sqlite.
+       ** This is done in place on the buffer holding the zipped data.
+       ** The actual size of the encoded data string will be returned.
+       */
+       nDataSize = sqlite3_encode_binary((const unsigned char*)pZip, nZipSize, (unsigned char*)pData);
+       assert(nDataSize <= nDataMax);
+
+       free(pZip);
+
+       /* Terminate the Data string. */
+       pData[nDataSize] = 0;
+
+       /* Return the data string. */
+       return pData;
+}
+
+/*
+** Compress and binary encode a data string for storing in an sqlite database.
+** Returns NULL if the argument is NULL.
+** THIS IS AN SQLITE USER FUNCTION.
+**
+** argv[0] = data string
+*/
+void FnZipString( sqlite3_context *context, int argc, sqlite3_value **argv)
+{
+       const char *pXml, *zErrMsg;
+       char *pEncXml;
+       long nSize;
+
+       /* TODO: validate arguments. */
+       assert(argc == 1 && argv);
+
+       pXml = sqlite3_value_text(argv[0]);
+
+       /* Handle NULL */
+       if (pXml == NULL)
+       {
+    sqlite3_result_null(context);
+               return;
+       }
+
+       nSize = strlen(pXml);
+
+       /*
+       ** If an error occurs, buffer[] will hold the error string.
+       ** This error message doesn't have to be freed.
+       */
+       zErrMsg = NULL;
+       pEncXml = ZipString(pXml, nSize, &zErrMsg);
+       if (pEncXml)
+    sqlite3_result_text(context,  pEncXml, -1, SQLITE_STATIC);
+       else
+               sqlite3_result_error(context, zErrMsg, -1);
+
+       free(pEncXml);
+}
+
+/*
+** Uncompress and binary decode a string compressed with [Fn]ZipString().
+** Returns NULL if the argument is NULL.
+** THIS IS AN SQLITE USER FUNCTION.
+**
+** argv[0] = compressed data string
+*/
+void FnUnzipString(sqlite3_context *context, int argc, sqlite3_value **argv)
+{
+       const char *pZip, *zErrMsg;
+       char *pData;
+       long nZipSize;
+
+       /* TODO: validate arguments. */
+       assert(argc == 1 && argv);
+
+       pZip = sqlite3_value_text(argv[0]);
+
+       /* Handle NULL */
+       if (pZip == NULL)
+       {
+               sqlite3_result_null(context);
+               return;
+       }
+
+       nZipSize = strlen(pZip);
+
+       /*
+       ** If an error occurs, buffer[] will hold the error string.
+       ** This error message doesn't have to be freed.
+       */
+       zErrMsg = NULL;
+       pData = UnzipString(pZip, nZipSize, &zErrMsg);
+       if (pData)
+               sqlite3_result_text(context, pData, -1, SQLITE_STATIC);
+       else
+               sqlite3_result_error(context, zErrMsg, -1);
+
+       free(pData);
+}
+
+
+/************************************************************************/
+
+    /* SQLite invokes this routine once when it loads the extension.
+    ** Create new functions, collating sequences, and virtual table
+    ** modules here.  This is usually the only exported symbol in
+    ** the shared library.
+    */
+    int sqlite3_extension_init(
+      sqlite3 *db,
+      char **pzErrMsg,
+      const sqlite3_api_routines *pApi
+    ){
+      SQLITE_EXTENSION_INIT2(pApi)
+      sqlite3_create_function(db, "unzip", 1, SQLITE_ANY, 0, FnUnzipString, 0, 0);
+      sqlite3_create_function(db, "zip", 1, SQLITE_ANY, 0, FnZipString, 0, 0);
+      return 0;
+    }
+