####################################################################
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
OnMediaLocation.cc
Fetcher.cc
FileChecker.cc
+ Repository.cc
+ RepoInfo.cc
+ RepoStatus.cc
+ RepoManager.cc
+ RepositoryFactory.cc
)
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" )
parser/LibXMLHelper.cc
parser/SAXParser.cc
parser/XMLNodeIterator.cc
+ parser/RepoFileReader.cc
)
SET( zypp_parser_HEADERS
parser/SAXParser.h
parser/XMLNodeIterator.h
parser/xml_parser_assert.h
+ parser/RepoFileReader.h
)
INSTALL( FILES
parser/susetags/PackagesFileReader.cc
parser/susetags/PackagesLangFileReader.cc
parser/susetags/PatternFileReader.cc
+ parser/susetags/RepoParser.cc
)
SET( zypp_parser_susetags_HEADERS
parser/susetags/PackagesFileReader.h
parser/susetags/PackagesLangFileReader.h
parser/susetags/PatternFileReader.h
+ parser/susetags/RepoParser.h
)
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}
${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}
${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}
${zypp_HEADERS}
${zypp_zypp_detail_HEADERS}
${zypp_thread_HEADERS}
+${zypp_repository_HEADERS}
${zypp_source_susetags_HEADERS}
${zypp_target_modalias_HEADERS}
${zypp_target_HEADERS}
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} )
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ 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
+///////////////////////////////////////////////////////////////////
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ 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
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ 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
+///////////////////////////////////////////////////////////////////
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ 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
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ 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;
+}
+
+}
+}
+
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ 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
--- /dev/null
+
+#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 ×tamp )
+{
+ _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 );
+}
+
+}
+}
+
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ 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 ×tamp = 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
+
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ 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
+///////////////////////////////////////////////////////////////////
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ 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
--- /dev/null
+
+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
--- /dev/null
+
+#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
--- /dev/null
+
+#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
--- /dev/null
+
+http://s11n.net/sqlite/wrapper/overview-sqlite3x-sq3-2007.01.25.pdf
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ 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]);
+}
+
+}
+}
+
--- /dev/null
+/*---------------------------------------------------------------------\
+| ____ _ __ __ ___ |
+| |__ / \ / / . \ . \ |
+| / / \ 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
--- /dev/null
+
+See:
+http://en.opensuse.org/Libzypp/Refactoring/CacheSchema
\ No newline at end of file
--- /dev/null
+/*
+ * 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);
+}
+
+/* ..__
+ * `' "
+ */
--- /dev/null
+
+------------------------------------------------
+-- 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;
+
+
--- /dev/null
+/*\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 ©);\r
+ ~sqlite3_reader();\r
+\r
+ sqlite3_reader& operator=(const sqlite3_reader ©);\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 ¶m);\r
+ void bind(const std::string ¶m, int data);\r
+ void bind(const std::string ¶m, long long data);\r
+ void bind(const std::string ¶m, double data);\r
+ void bind(const std::string ¶m, const char *data, int datalen);\r
+ void bind(const std::string ¶m, const wchar_t *data, int datalen);\r
+ void bind(const std::string ¶m, const void *data, int datalen);\r
+ void bind(const std::string ¶m, const std::string &data);\r
+ void bind(const std::string ¶m, 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
--- /dev/null
+/*\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 ¶m)\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 ¶m, 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 ¶m, 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 ¶m, 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 ¶m, 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 ¶m, 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 ¶m, 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 ¶m, 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 ¶m, 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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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 ©) : 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 ©)\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
--- /dev/null
+/*\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
--- /dev/null
+/*
+** 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;
+ }
+