a5d55bc077f00512f32ee85bd870bab1b8eb7bbc
[platform/upstream/libzypp.git] / zypp / cache / CacheStore.cc
1 #include <sqlite3.h>
2 #include <map>
3 #include "zypp/cache/sqlite3x/sqlite3x.hpp"
4
5 #include "zypp/base/Logger.h"
6 #include "zypp/base/Measure.h"
7 #include "zypp/ZYppFactory.h"
8 #include "zypp/ZYpp.h"
9 #include "zypp/Package.h"
10 #include "zypp/cache/CacheInitializer.h"
11 #include "zypp/cache/CacheStore.h"
12 #include "zypp/cache/CacheException.h"
13
14 using namespace std;
15 using namespace zypp;
16 using namespace zypp::capability;
17 using namespace zypp::cache;
18 using zypp::data::RecordId;
19 using namespace sqlite3x;
20
21 using zypp::debug::Measure;
22
23 ///////////////////////////////////////////////////////////////////
24 namespace zypp
25 { /////////////////////////////////////////////////////////////////
26 ///////////////////////////////////////////////////////////////////
27 namespace cache
28 { /////////////////////////////////////////////////////////////////
29
30 typedef shared_ptr<sqlite3_command> sqlite3_command_ptr;
31
32 struct CacheStore::Impl
33 {
34   Impl( const Pathname &dbdir )
35   : name_cache_hits(0)
36   {
37     cache::CacheInitializer initializer(dbdir, "zypp.db");
38     if ( initializer.justInitialized() )
39     {
40       MIL << "database " << (dbdir + "zypp.db") << " was just created" << endl;
41     }
42
43     try
44     {
45       con.open( (dbdir + "zypp.db").asString().c_str());
46       //_insert_resolvable_cmd = new sqlite3_command( *_con, INSERT_RESOLVABLE_QUERY );
47       //_insert_package_cmd = new sqlite3_command( *_con, INSERT_PACKAGE_QUERY );
48     }
49     catch(exception &ex)
50     {
51       //ZYPP_CAUGHT(ex);
52       ZYPP_THROW(Exception(ex.what()));
53     }
54
55
56     // initialize all pre-compiled statements
57
58     insert_resolvable_in_repository_cmd.reset( new sqlite3_command( con, "insert into resolvables_repositories (resolvable_id, repository_id) values (:resolvable_id, :repository_id);" ));
59
60     update_repository_cmd.reset( new sqlite3_command( con, "update repositories set checksum=:checksum, timestamp=:timestamp where id=:repository_id;" ));
61
62     select_repository_cmd.reset( new sqlite3_command( con, "select id from repositories where alias=:alias;" ));
63     insert_repository_cmd.reset( new sqlite3_command( con, "insert into repositories (alias,timestamp) values (:alias, :timestamp);" ));
64
65     select_name_cmd.reset( new sqlite3_command( con, "select id from names where name=:name;" ));
66     insert_name_cmd.reset( new sqlite3_command( con, "insert into names (name) values (:name);" ));
67
68     select_dirname_cmd.reset( new sqlite3_command( con, "select id from dir_names where name=:name;" ));
69     insert_dirname_cmd.reset( new sqlite3_command( con, "insert into dir_names (name) values (:name);" ));
70
71     select_filename_cmd.reset( new sqlite3_command( con, "select id from file_names where name=:name;" ));
72     insert_filename_cmd.reset( new sqlite3_command( con, "insert into file_names (name) values (:name);" ));
73
74     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;" ));
75     insert_file_cmd.reset( new sqlite3_command( con, "insert into files (dir_name_id,file_name_id) values (:dir_name_id,:file_name_id);" ));
76
77     select_type_cmd.reset( new sqlite3_command( con, "select id from types where class=:class and name=:name;" ));
78     insert_type_cmd.reset( new sqlite3_command( con, "insert into types (class,name) values (:class,:name);" ));
79
80     set_shared_flag_cmd.reset( new sqlite3_command( con, "update resolvables set shared_id=:shared_id where id=:resolvable_id;" ));
81
82     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 );" ));
83     append_num_attribute_cmd.reset( new sqlite3_command( con, "insert into numeric_attributes ( weak_resolvable_id, attr_id, value ) values ( :rid, :attr_id, :value );" ));
84
85     //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 );" ));
86     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 );" ));
87     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 );" ));
88
89     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 );" ));
90
91     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 );" ));
92
93     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 );" ));
94
95     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 );" ));
96
97     count_shared_cmd.reset( new sqlite3_command( con, "select count(id) from resolvables where shared_id=:rid;" ));
98
99     insert_patchrpm_cmd.reset( new sqlite3_command (con,
100       "insert into patch_packages (repository_id, media_nr, location, checksum, download_size, build_time) "
101       "values (:repository_id, :media_nr, :location, :checksum, :download_size, :build_time);" ));
102     insert_deltarpm_cmd.reset( new sqlite3_command (con,
103       "insert into delta_packages (repository_id, media_nr, location, checksum, download_size, build_time, "
104         "baseversion_version, baseversion_release, baseversion_epoch, baseversion_checksum, "
105         "baseversion_build_time, baseversion_sequence_info) "
106       "values (:repository_id, :media_nr, :location, :checksum, :download_size, :build_time, "
107         ":baseversion_version, :baseversion_release, :baseversion_epoch, :baseversion_checksum, "
108         ":baseversion_build_time, :baseversion_sequence_info);" ));
109     append_patch_baseversion_cmd.reset( new sqlite3_command (con,
110       "insert into patch_packages_baseversions (patch_package_id, version, release, epoch) "
111       "values (:patch_package_id, :version, :release, :epoch)" ));
112
113
114     // disable autocommit
115     con.executenonquery("BEGIN;");
116   }
117
118   Impl()
119   {
120     Impl( getZYpp()->homePath() );
121   }
122
123   ~Impl()
124   {
125     MIL << "name cache hits: " << name_cache_hits << " | cache size: " << name_cache.size() << endl;
126   }
127
128  /**
129   * SQL statements
130   * (we precompile them
131   */
132   sqlite3_connection con;
133
134   sqlite3_command_ptr update_repository_cmd;
135   sqlite3_command_ptr insert_resolvable_in_repository_cmd;
136
137   sqlite3_command_ptr select_name_cmd;
138   sqlite3_command_ptr insert_name_cmd;
139
140   sqlite3_command_ptr select_dirname_cmd;
141   sqlite3_command_ptr insert_dirname_cmd;
142
143   sqlite3_command_ptr select_filename_cmd;
144   sqlite3_command_ptr insert_filename_cmd;
145
146   sqlite3_command_ptr select_repository_cmd;
147   sqlite3_command_ptr insert_repository_cmd;
148
149   sqlite3_command_ptr select_file_cmd;
150   sqlite3_command_ptr insert_file_cmd;
151
152   sqlite3_command_ptr select_type_cmd;
153   sqlite3_command_ptr insert_type_cmd;
154
155   //sqlite3_command_ptr insert_dependency_entry_cmd;
156
157   sqlite3_command_ptr append_file_dependency_cmd;
158   sqlite3_command_ptr append_named_dependency_cmd;
159   sqlite3_command_ptr append_modalias_dependency_cmd;
160   sqlite3_command_ptr append_hal_dependency_cmd;
161   sqlite3_command_ptr append_other_dependency_cmd;
162
163   sqlite3_command_ptr append_resolvable_cmd;
164
165   sqlite3_command_ptr append_text_attribute_cmd;
166   sqlite3_command_ptr append_num_attribute_cmd;
167
168   sqlite3_command_ptr set_shared_flag_cmd;
169
170   sqlite3_command_ptr count_shared_cmd;
171
172   sqlite3_command_ptr insert_patchrpm_cmd;
173   sqlite3_command_ptr insert_deltarpm_cmd;
174   sqlite3_command_ptr append_patch_baseversion_cmd;
175
176   map<string, RecordId> name_cache;
177   map< pair<string,string>, RecordId> type_cache;
178   int name_cache_hits;
179 };
180
181
182 CacheStore::CacheStore( const Pathname &dbdir )
183   : _pimpl( new Impl(dbdir) )
184 {
185
186 }
187
188 CacheStore::CacheStore()
189     : _pimpl( new Impl() )
190 {
191
192 }
193
194 CacheStore::~CacheStore()
195 {
196
197 }
198
199 void CacheStore::commit()
200 {
201   _pimpl->con.executenonquery("COMMIT;");
202 }
203
204 void CacheStore::appendResObjectAttributes( const data::RecordId &rid,
205                                             const data::ResObject_Ptr & res )
206 {
207   appendTranslatedStringAttribute( rid, "ResObject", "description", res->description );
208   appendTranslatedStringAttribute( rid, "ResObject", "summary", res->summary );
209   appendNumericAttribute( rid, "ResObject", "installedSize", res->installedSize );
210   appendNumericAttribute( rid, "ResObject", "buildTime", res->buildTime );
211   appendBooleanAttribute( rid, "ResObject", "installOnly", res->installOnly );
212   appendStringAttribute( rid, "ResObject", "vendor", res->vendor );
213   appendTranslatedStringAttribute( rid, "ResObject", "licenseToConfirm", res->licenseToConfirm );
214   appendTranslatedStringAttribute( rid, "ResObject", "insnotify", res->insnotify );
215   appendTranslatedStringAttribute( rid, "ResObject", "delnotify", res->delnotify );
216 }
217
218
219 void CacheStore::appendPackageBaseAttributes( const RecordId & pkgid,
220                                               const data::Packagebase_Ptr & package )
221 {
222   appendStringAttribute( pkgid, "Package", "checksum", package->repositoryLocation.fileChecksum.checksum() );
223   appendStringAttribute( pkgid, "Package", "checksumType", package->repositoryLocation.fileChecksum.type() );
224   appendStringAttribute( pkgid, "Package", "buildhost", package->buildhost );
225   appendStringAttribute( pkgid, "Package", "distribution", package->distribution );
226   appendStringAttribute( pkgid, "Package", "license", package->license );
227   appendStringAttribute( pkgid, "Package", "group", package->packager );
228   appendStringAttribute( pkgid, "Package", "url", package->url );
229   appendStringAttribute( pkgid, "Package", "operatingSystem", package->operatingSystem );
230   appendStringAttribute( pkgid, "Package", "prein", package->prein );
231   appendStringAttribute( pkgid, "Package", "postin", package->postin );
232   appendStringAttribute( pkgid, "Package", "preun", package->preun );
233   appendStringAttribute( pkgid, "Package", "postun", package->postun );
234   appendStringContainerAttribute( pkgid, "Package", "keywords", package->keywords.begin(), package->keywords.end() );
235   appendStringContainerAttribute( pkgid, "Package", "authors", package->authors.begin(), package->authors.end() );
236   appendStringAttribute( pkgid, "Package", "location", package->repositoryLocation.filePath.asString() );
237 }
238
239 RecordId CacheStore::consumePackage( const RecordId & repository_id,
240                                  const data::Package_Ptr & package )
241 {
242   RecordId id = appendResolvable( repository_id, ResTraits<Package>::kind,
243       NVRA( package->name, package->edition, package->arch ), package->deps );
244   appendResObjectAttributes( id, package );
245   appendPackageBaseAttributes( id, package );
246   return id;
247 }
248
249 RecordId CacheStore::consumeSourcePackage( const data::RecordId & repository_id,
250                                        const data::SrcPackage_Ptr & package )
251 {
252   RecordId id = appendResolvable( repository_id, ResTraits<SrcPackage>::kind,
253       NVRA( package->name, package->edition, package->arch ), package->deps );
254   appendResObjectAttributes( id, package );
255   appendPackageBaseAttributes( id, package );
256 #warning TBD WRONG IMPLEMENTATION
257   return id;
258 }
259
260 RecordId CacheStore::consumePatch( const data::RecordId & repository_id,
261                                const data::Patch_Ptr & patch)
262 {
263   RecordId id = appendResolvable(
264       repository_id, ResTraits<Patch>::kind,
265       NVRA( patch->name, patch->edition, patch->arch ), patch->deps );
266
267   appendResObjectAttributes( id, patch );
268
269   // patch attributes
270   appendNumericAttribute( id, "Patch", "timestamp",         patch->timestamp );
271   appendStringAttribute(  id, "Patch", "category",          patch->category );
272   appendBooleanAttribute( id, "Patch", "rebootNeeded",      patch->rebootNeeded );
273   appendBooleanAttribute( id, "Patch", "affectsPkgManager", patch->affectsPkgManager );
274
275
276   DBG << "got patch " << patch->name << ", atoms: ";
277   // cosume atoms
278   for (set<data::ResObject_Ptr>::const_iterator p = patch->atoms.begin();
279        p != patch->atoms.end(); ++p)
280   {
281     data::PackageAtom_Ptr atom = dynamic_pointer_cast<data::PackageAtom>(*p);
282     if (atom)
283     {
284       DBG << atom->name << "(atom) ";
285       consumePackageAtom(repository_id, atom);
286       continue;
287     }
288
289     data::Script_Ptr script = dynamic_pointer_cast<data::Script>(*p);
290     if (script)
291     {
292       DBG << script->name << "(script) ";
293       consumeScript(repository_id, script);
294       continue;
295     }
296
297     data::Message_Ptr message = dynamic_pointer_cast<data::Message>(*p);
298     if (message)
299     {
300       DBG << message->name << "(message) ";
301       consumeMessage(repository_id, message);
302       continue;
303     }
304
305     ERR << " ignoring !badatom! ";
306     if (*p) ERR << (*p)->name;
307     ERR << endl;
308   }
309
310   DBG << endl;
311   return id;
312 }
313
314 RecordId CacheStore::consumePackageAtom( const data::RecordId & repository_id,
315                                      const data::PackageAtom_Ptr & atom )
316 {
317   RecordId id = appendResolvable( repository_id, ResTraits<Atom>::kind,
318       NVRA( atom->name, atom->edition, atom->arch ), atom->deps );
319   appendResObjectAttributes( id, atom );
320   appendPackageBaseAttributes( id, atom );
321
322   for (set<data::PatchRpm_Ptr>::const_iterator p = atom->patchRpms.begin();
323        p != atom->patchRpms.end(); ++p)
324     appendPatchRpm(repository_id, *p);
325
326   for (set<data::DeltaRpm_Ptr>::const_iterator d = atom->deltaRpms.begin();
327        d != atom->deltaRpms.end(); ++d)
328     appendDeltaRpm(repository_id, *d);
329   return id;
330 }
331
332 RecordId CacheStore::consumeMessage( const data::RecordId & repository_id,
333                                  const data::Message_Ptr & message )
334 {
335   RecordId id = appendResolvable( repository_id, ResTraits<Message>::kind,
336       NVRA( message->name, message->edition, message->arch ), message->deps );
337   appendResObjectAttributes( id, message );
338
339   appendTranslatedStringAttribute( id, "Message", "text", message->text );
340   return id;
341 }
342
343 RecordId CacheStore::consumeScript( const data::RecordId & repository_id,
344                                 const data::Script_Ptr & script )
345 {
346   RecordId id = appendResolvable( repository_id, ResTraits<Script>::kind,
347       NVRA( script->name, script->edition, script->arch ), script->deps );
348   appendResObjectAttributes( id, script );
349
350   appendStringAttribute( id, "Script", "doScript", script->doScript );
351   appendStringAttribute( id, "Script", "doScriptLocation", script->doScriptLocation.filePath.asString() );
352   appendStringAttribute( id, "Script", "doScriptChecksum", script->doScriptLocation.fileChecksum.checksum() );
353   appendStringAttribute( id, "Script", "doScriptChecksumType", script->doScriptLocation.fileChecksum.type() );
354   appendStringAttribute( id, "Script", "undoScript", script->undoScript );
355   appendStringAttribute( id, "Script", "undoScriptLocation", script->undoScriptLocation.filePath.asString() );
356   appendStringAttribute( id, "Script", "undoScriptChecksum", script->undoScriptLocation.fileChecksum.checksum() );
357   appendStringAttribute( id, "Script", "undoScriptChecksumType", script->undoScriptLocation.fileChecksum.type() );
358   return id;
359 }
360
361 RecordId CacheStore::consumePattern( const data::RecordId & repository_id,
362                                  const data::Pattern_Ptr & pattern )
363 {
364   RecordId id = appendResolvable( repository_id, ResTraits<Pattern>::kind,
365       NVRA( pattern->name, pattern->edition, pattern->arch ), pattern->deps );
366   appendResObjectAttributes( id, pattern );
367
368   appendBooleanAttribute( id, "Pattern", "isDefault", pattern->isDefault );
369   appendBooleanAttribute( id, "Pattern", "userVisible", pattern->userVisible );
370   appendTranslatedStringAttribute( id, "Pattern", "category", pattern->category );
371   appendStringAttribute( id, "Pattern", "icon", pattern->icon );
372   appendStringAttribute( id, "Pattern", "order", pattern->order );
373   return id;
374 }
375
376 RecordId CacheStore::consumeProduct( const data::RecordId & repository_id,
377                                  const data::Product_Ptr & product )
378 {
379   RecordId id = appendResolvable( repository_id, ResTraits<Product>::kind,
380       NVRA( product->name, product->edition, product->arch ), product->deps );
381   appendResObjectAttributes( id, product );
382
383   appendTranslatedStringAttribute( id, "Product", "shortName", product->shortName );
384   appendTranslatedStringAttribute( id, "Product", "longName", product->longName );
385   appendStringContainerAttribute( id, "Product", "flags", product->flags.begin(), product->flags.end() );
386   appendStringAttribute( id, "Product", "releasenotesUrl", product->releasenotesUrl.asString() );
387   appendStringContainerAttribute( id, "Product", "updateUrls", product->updateUrls );
388   appendStringContainerAttribute( id, "Product", "extraUrls", product->extraUrls );
389   appendStringContainerAttribute( id, "Product", "optionalUrls", product->optionalUrls );
390   appendStringAttribute( id, "Product", "distributionName", product->distributionName );
391   appendStringAttribute( id, "Product", "distributionEdition", product->distributionEdition.asString() );
392   return id;
393 }
394
395 RecordId CacheStore::consumeChangelog( const data::RecordId & repository_id,
396                                    const data::Resolvable_Ptr & resolvable,
397                                    const Changelog & changelog )
398 {
399   //! \todo maybe appendChangelog(const data::RecordId & resolvable_id, Changelog changelog) will be needed
400   //! for inserting the changelog using in-memory record id of corresponding resolvable.
401   //! (first, we'll see how fast is the inserting without remembering those ids)
402 }
403
404 RecordId CacheStore::consumeFilelist( const data::RecordId & repository_id,
405                                   const data::Resolvable_Ptr & resolvable,
406                                   const data::Filenames & filenames )
407 {
408   //! \todo maybe consumeFilelist(const data::RecordId & resolvable_id, data::Filenames &) will be needed
409 }
410
411 RecordId CacheStore::appendResolvable( const RecordId &repository_id,
412                                        const Resolvable::Kind &kind,
413                                        const NVRA &nvra,
414                                        const data::Dependencies &deps )
415 {
416   _pimpl->append_resolvable_cmd->bind( ":name", nvra.name );
417   _pimpl->append_resolvable_cmd->bind( ":version", nvra.edition.version() );
418   _pimpl->append_resolvable_cmd->bind( ":release", nvra.edition.release() );
419   _pimpl->append_resolvable_cmd->bind( ":epoch", static_cast<int>( nvra.edition.epoch() ) );
420   _pimpl->append_resolvable_cmd->bind( ":arch", lookupOrAppendType("arch", nvra.arch.asString()) );
421   _pimpl->append_resolvable_cmd->bind( ":kind", lookupOrAppendType("kind", kind.asString()) );
422   _pimpl->append_resolvable_cmd->bind( ":repository_id", repository_id );
423
424   _pimpl->append_resolvable_cmd->executenonquery();
425
426   long long id = _pimpl->con.insertid();
427
428   appendDependencies( id, deps );
429   /*
430   _pimpl->insert_resolvable_in_repository_cmd->bind(":repository_id", repository_id);
431   _pimpl->insert_resolvable_in_repository_cmd->bind(":resolvable_id", id);
432   _pimpl->insert_resolvable_in_repository_cmd->executenonquery();*/
433
434   return static_cast<RecordId>(id);
435   return 1;
436 }
437
438 void CacheStore::appendDependencies( const RecordId &resolvable_id, const data::Dependencies &deps )
439 {
440   for ( data::Dependencies::const_iterator it = deps.begin(); it != deps.end(); ++it )
441   {
442     appendDependencyList( resolvable_id, it->first, it->second );
443   }
444 }
445
446 void CacheStore::appendDependencyList( const RecordId &resolvable_id, zypp::Dep deptype, const data::DependencyList &caps )
447 {
448   for ( data::DependencyList::const_iterator it = caps.begin(); it != caps.end(); ++it )
449   {
450     appendDependency( resolvable_id, deptype, *it );
451   }
452 }
453
454 void CacheStore::appendDependency( const RecordId &resolvable_id, zypp::Dep deptype, capability::CapabilityImpl::Ptr cap )
455 {
456   if ( cap == 0 )
457   {
458     DBG << "invalid capability" << endl;
459     return;
460   }
461
462   if ( capability::isKind<NamedCap>(cap) )
463   {
464       appendNamedDependency( resolvable_id, deptype, capability::asKind<NamedCap>(cap) );
465   }
466   else if ( capability::isKind<FileCap>(cap) )
467   {
468     appendFileDependency( resolvable_id, deptype, capability::asKind<FileCap>(cap) );
469     return;
470   }
471   else if ( capability::isKind<ModaliasCap>(cap) )
472   {
473       appendModaliasDependency( resolvable_id, deptype, capability::asKind<ModaliasCap>(cap) );
474   }
475   else if ( capability::isKind<HalCap>(cap) )
476   {
477       appendHalDependency( resolvable_id, deptype, capability::asKind<HalCap>(cap) );
478   }
479   else
480   {
481       appendUnknownDependency( resolvable_id, deptype, cap );
482   }
483 }
484
485 // RecordId CacheStore::lookupOrAppendNamedDependencyEntry( const RecordId name_id, const Edition &edition, const zypp::Rel &rel )
486 // {
487 //   _pimpl->select_named_dependency_cmd->bind( ":name_id", name_id);
488 //   _pimpl->select_named_dependency_cmd->bind( ":version", edition.version() );
489 //   _pimpl->select_named_dependency_cmd->bind( ":release", edition.release() );
490 //   _pimpl->select_named_dependency_cmd->bind( ":epoch", static_cast<int>( edition.epoch() ) );
491 //   _pimpl->select_named_dependency_cmd->bind( ":relation", zypp_rel2db_rel( rel ) );
492 //   long long id = 0;
493 //   try {
494 //     id = _pimpl->select_named_dependency_cmd->executeint64();
495 //   }
496 //   catch ( const sqlite3x::database_error &e )
497 //   {
498 //     // does not exist
499 //     _pimpl->append_named_dependency_entry_cmd->bind( ":name_id", name_id);
500 //     _pimpl->append_named_dependency_entry_cmd->bind( ":version", edition.version() );
501 //     _pimpl->append_named_dependency_entry_cmd->bind( ":release", edition.release() );
502 //     _pimpl->append_named_dependency_entry_cmd->bind( ":epoch", static_cast<int>( edition.epoch() ) );
503 //     _pimpl->append_named_dependency_entry_cmd->bind( ":relation", zypp_rel2db_rel( rel ) );
504 //     _pimpl->append_named_dependency_entry_cmd->executenonquery();
505 //     id = _pimpl->con.insertid();
506 //     return static_cast<RecordId>(id);
507 //   }
508 //   return static_cast<RecordId>(id);
509 // }
510
511 void CacheStore::appendNamedDependency( const RecordId &resolvable_id, zypp::Dep deptype, capability::NamedCap::Ptr cap )
512 {
513   if ( !cap )
514     ZYPP_THROW(Exception("bad versioned dep"));
515   //DBG << "versioned : " << cap << endl;
516
517   //RecordId capability_id = appendDependencyEntry( resolvable_id, deptype, cap->refers() );
518   RecordId name_id = lookupOrAppendName(cap->name());
519
520   _pimpl->append_named_dependency_cmd->bind( ":resolvable_id", resolvable_id );
521   _pimpl->append_named_dependency_cmd->bind( ":dependency_type", lookupOrAppendType("deptype", deptype.asString()) );
522   _pimpl->append_named_dependency_cmd->bind( ":refers_kind", lookupOrAppendType("kind", cap->refers().asString()) );
523
524   //_pimpl->append_named_dependency_cmd->bind( ":capability_id", capability_id);
525   _pimpl->append_named_dependency_cmd->bind( ":name_id", name_id);
526   _pimpl->append_named_dependency_cmd->bind( ":version", cap->edition().version() );
527   _pimpl->append_named_dependency_cmd->bind( ":release", cap->edition().release() );
528   _pimpl->append_named_dependency_cmd->bind( ":epoch", static_cast<int>( cap->edition().epoch() ) );
529   _pimpl->append_named_dependency_cmd->bind( ":relation", lookupOrAppendType("rel", cap->op().asString()) );
530   _pimpl->append_named_dependency_cmd->executenonquery();
531
532   //delete cmd;
533 }
534
535 void CacheStore::appendModaliasDependency( const RecordId &resolvable_id,
536                                                  zypp::Dep deptype,
537                                                  capability::ModaliasCap::Ptr cap )
538 {
539   if ( !cap )
540     ZYPP_THROW(Exception("Null modalias capability"));
541
542   _pimpl->append_modalias_dependency_cmd->bind( ":resolvable_id", resolvable_id );
543   _pimpl->append_modalias_dependency_cmd->bind( ":dependency_type", lookupOrAppendType("deptype", deptype.asString()) );
544   _pimpl->append_modalias_dependency_cmd->bind( ":refers_kind", lookupOrAppendType("kind", cap->refers().asString()) );
545
546   //_pimpl->append_modalias_dependency_cmd->bind( ":capability_id", capability_id);
547   _pimpl->append_modalias_dependency_cmd->bind( ":name", cap->name());
548   _pimpl->append_modalias_dependency_cmd->bind( ":value", cap->value());
549   _pimpl->append_modalias_dependency_cmd->bind( ":relation", lookupOrAppendType("rel", cap->op().asString()) );
550
551   _pimpl->append_modalias_dependency_cmd->executenonquery();
552   //delete cmd;
553 }
554
555 void CacheStore::appendHalDependency( const RecordId &resolvable_id,
556                                                  zypp::Dep deptype,
557                                                  capability::HalCap::Ptr cap )
558 {
559   if ( !cap )
560     ZYPP_THROW(Exception("Null HAL capability"));
561
562   _pimpl->append_hal_dependency_cmd->bind( ":resolvable_id", resolvable_id );
563   _pimpl->append_hal_dependency_cmd->bind( ":dependency_type", lookupOrAppendType("deptype", deptype.asString()) );
564   _pimpl->append_hal_dependency_cmd->bind( ":refers_kind", lookupOrAppendType("kind", cap->refers().asString()) );
565
566   //_pimpl->append_hal_dependency_cmd->bind( ":capability_id", capability_id);
567   _pimpl->append_hal_dependency_cmd->bind( ":name", cap->name());
568   _pimpl->append_hal_dependency_cmd->bind( ":value", cap->value());
569   _pimpl->append_hal_dependency_cmd->bind( ":relation", lookupOrAppendType("rel", cap->op().asString()) );
570
571   _pimpl->append_hal_dependency_cmd->executenonquery();
572   //delete cmd;
573 }
574
575 void CacheStore::appendFileDependency( const RecordId &resolvable_id, zypp::Dep deptype,
576                                        capability::FileCap::Ptr cap )
577 {
578   if ( !cap )
579     ZYPP_THROW(Exception("Null file capability"));
580
581   //RecordId capability_id = appendDependencyEntry( resolvable_id, deptype, cap->refers() );
582   RecordId file_id = lookupOrAppendFile(cap->filename());
583
584   _pimpl->append_file_dependency_cmd->bind( ":resolvable_id", resolvable_id );
585   _pimpl->append_file_dependency_cmd->bind( ":dependency_type", lookupOrAppendType("deptype", deptype.asString()) );
586   _pimpl->append_file_dependency_cmd->bind( ":refers_kind", lookupOrAppendType("kind", cap->refers().asString()) );
587
588   //_pimpl->append_file_dependency_cmd->bind( ":capability_id", capability_id);
589   _pimpl->append_file_dependency_cmd->bind( ":file_id", file_id);
590
591   _pimpl->append_file_dependency_cmd->executenonquery();
592   //delete cmd;
593 }
594
595 void CacheStore::appendUnknownDependency( const RecordId &resolvable_id,
596                                                zypp::Dep deptype,
597                                                capability::CapabilityImpl::Ptr cap )
598 {
599   if ( !cap )
600     ZYPP_THROW(Exception("Null unknown capability"));
601
602   _pimpl->append_other_dependency_cmd->bind( ":resolvable_id", resolvable_id );
603   _pimpl->append_other_dependency_cmd->bind( ":dependency_type", lookupOrAppendType("deptype", deptype.asString()) );
604   _pimpl->append_other_dependency_cmd->bind( ":refers_kind", lookupOrAppendType("kind", cap->refers().asString()) );
605   _pimpl->append_other_dependency_cmd->bind( ":value", cap->encode());
606
607   _pimpl->append_hal_dependency_cmd->executenonquery();
608   //delete cmd;
609 }
610
611
612 /** \todo lookupOrAppend ? */
613 RecordId CacheStore::appendPatchRpm(const zypp::data::RecordId &repository_id, const data::PatchRpm_Ptr & prpm)
614 {
615   RecordId id;
616
617   //! \todo what's this? _pimpl->insert_patchrpm_cmd->bind(":media_nr", ???);
618   _pimpl->insert_patchrpm_cmd->bind(":repository_id", repository_id);
619   _pimpl->insert_patchrpm_cmd->bind(":location", prpm->location.filePath.asString());
620   _pimpl->insert_patchrpm_cmd->bind(":checksum", prpm->location.fileChecksum.checksum());
621   //! \todo checksum type
622   _pimpl->insert_patchrpm_cmd->bind(":download_size", static_cast<ByteCount::SizeType>(prpm->location.fileSize));
623   _pimpl->insert_patchrpm_cmd->bind(":build_time", prpm->buildTime.asSeconds());
624   _pimpl->insert_patchrpm_cmd->executenonquery();
625
626   id = _pimpl->con.insertid();
627
628   for (set<data::BaseVersion_Ptr>::const_iterator bv = prpm->baseVersions.begin();
629        bv != prpm->baseVersions.end(); ++bv)
630   {
631     _pimpl->append_patch_baseversion_cmd->bind(":patch_package_id", id);
632     _pimpl->append_patch_baseversion_cmd->bind(":version", (*bv)->edition.version());
633     _pimpl->append_patch_baseversion_cmd->bind(":release", (*bv)->edition.release());
634     _pimpl->append_patch_baseversion_cmd->bind(":epoch", (int) (*bv)->edition.epoch());
635     _pimpl->append_patch_baseversion_cmd->executenonquery();
636   }
637
638   return id;
639 }
640
641
642 /** \todo lookupOrAppend ? */
643 RecordId CacheStore::appendDeltaRpm(const zypp::data::RecordId &repository_id, const data::DeltaRpm_Ptr & drpm)
644 {
645   RecordId id;
646
647   //! \todo what's this? _pimpl->insert_deltarpm_cmd->bind(":media_nr", ???);
648   _pimpl->insert_deltarpm_cmd->bind(":repository_id", repository_id);
649   _pimpl->insert_deltarpm_cmd->bind(":location", drpm->location.filePath.asString());
650   _pimpl->insert_deltarpm_cmd->bind(":checksum", drpm->location.fileChecksum.checksum());
651   //! \todo checksum type
652   _pimpl->insert_deltarpm_cmd->bind(":download_size", static_cast<ByteCount::SizeType>(drpm->location.fileSize));
653   _pimpl->insert_deltarpm_cmd->bind(":build_time", drpm->buildTime.asSeconds());
654
655   _pimpl->insert_deltarpm_cmd->bind(":baseversion_version", drpm->baseVersion.edition.version());
656   _pimpl->insert_deltarpm_cmd->bind(":baseversion_release", drpm->baseVersion.edition.release());
657   _pimpl->insert_deltarpm_cmd->bind(":baseversion_epoch", (int) drpm->baseVersion.edition.epoch());
658   _pimpl->insert_deltarpm_cmd->bind(":baseversion_build_time", drpm->baseVersion.buildTime.asSeconds());
659   _pimpl->insert_deltarpm_cmd->bind(":baseversion_checksum", drpm->baseVersion.checkSum.checksum());
660   _pimpl->insert_deltarpm_cmd->bind(":baseversion_sequence_info", drpm->baseVersion.sequenceInfo);
661
662   _pimpl->insert_deltarpm_cmd->executenonquery();
663   id = _pimpl->con.insertid();
664
665   return id;
666 }
667
668
669 // RecordId CacheStore::appendDependencyEntry( const RecordId &resolvable_id, zypp::Dep deptype, const Resolvable::Kind &refers )
670 // {
671 //   //DBG << "rid: " << resolvable_id << " deptype: " << deptype << " " << "refers: " << refers << endl;
672 //   _pimpl->insert_dependency_entry_cmd->bind( ":resolvable_id", resolvable_id );
673 //
674 //   db::DependencyType dt = zypp_deptype2db_deptype(deptype);
675 //   if ( dt == db::DEP_TYPE_UNKNOWN )
676 //   {
677 //     ZYPP_THROW(Exception("Unknown depenency type"));
678 //   }
679 //
680 //   _pimpl->insert_dependency_entry_cmd->bind( ":dependency_type", zypp_deptype2db_deptype(deptype) );
681 //   _pimpl->insert_dependency_entry_cmd->bind( ":refers_kind", zypp_kind2db_kind(refers) );
682 //
683 //   _pimpl->insert_dependency_entry_cmd->executenonquery();
684 //   //delete cmd;
685 //   long long id = _pimpl->con.insertid();
686 //   return static_cast<RecordId>(id);
687 // }
688
689 RecordId CacheStore::lookupOrAppendFile( const Pathname &path )
690 {
691   RecordId dir_name_id = lookupOrAppendDirName(path.dirname().asString());
692   RecordId file_name_id = lookupOrAppendFileName(path.basename());
693
694   _pimpl->select_file_cmd->bind(":dir_name_id", dir_name_id);
695   _pimpl->select_file_cmd->bind(":file_name_id", file_name_id);
696   long long id = 0;
697
698   try
699   {
700     sqlite3_reader reader= _pimpl->select_file_cmd->executereader();
701     if (!reader.read())
702     {
703       // does not exist
704       _pimpl->insert_file_cmd->bind(":dir_name_id", dir_name_id);
705       _pimpl->insert_file_cmd->bind(":file_name_id", file_name_id);
706       _pimpl->insert_file_cmd->executenonquery();
707       id = _pimpl->con.insertid();
708       return id;
709    }
710    return reader.getint64(0);
711   }
712   catch ( const sqlite3x::database_error &e )
713   {
714     ZYPP_RETHROW(e);
715   }
716   return id;
717 }
718
719 void CacheStore::updateRepository( const RecordId &id,
720                                    const string &checksum,
721                                    const Date &timestamp )
722 {
723   _pimpl->update_repository_cmd->bind(":repository_id", id);
724   _pimpl->update_repository_cmd->bind(":checksum", checksum);
725   _pimpl->update_repository_cmd->bind(":timestamp", static_cast<int>((Date::ValueType) timestamp) );
726   _pimpl->insert_repository_cmd->executenonquery();
727 }
728
729 RecordId CacheStore::lookupOrAppendRepository( const string &alias )
730 {
731   _pimpl->select_repository_cmd->bind(":alias", alias);
732   long long id = 0;
733   try
734   {
735     sqlite3_reader reader= _pimpl->select_repository_cmd->executereader();
736     if (!reader.read())
737     {
738       // does not exist
739       _pimpl->insert_repository_cmd->bind(":alias", alias);
740       _pimpl->insert_repository_cmd->bind(":timestamp", static_cast<int>((Date::ValueType) Date::now()) );
741       _pimpl->insert_repository_cmd->executenonquery();
742       id = _pimpl->con.insertid();
743       return id;
744    }
745    return reader.getint64(0);
746   }
747   catch ( const sqlite3x::database_error &e )
748   {
749     ZYPP_RETHROW(e);
750   }
751   return id;
752 }
753
754 void CacheStore::cleanRepository( const data::RecordId &id,
755                                   const ProgressData::ReceiverFnc & progressrcv )
756 {
757   sqlite3_command cmd( _pimpl->con, "delete from repositories where id=:id");
758   cmd.bind(":id", id);
759
760   try
761   {
762     cmd.executenonquery();
763   }
764   catch ( const sqlite3x::database_error &e )
765   {
766     ZYPP_THROW(CacheRecordNotFoundException());
767   }
768 }
769
770 void CacheStore::cleanRepository( const std::string &alias,
771                                   const ProgressData::ReceiverFnc & progressrcv )
772 {
773   cleanRepository(lookupRepository(alias), progressrcv);
774 }
775
776 RepoStatus CacheStore::repositoryStatus( const data::RecordId &id )
777 {
778   sqlite3_command cmd( _pimpl->con, "select id,alias,checksum,timestamp from repositories where id=:id");
779   cmd.bind(":id", id);
780
781   try
782   {
783     sqlite3_reader reader = cmd.executereader();
784     RepoStatus status;
785     if ( reader.read() )
786     {
787       status.setChecksum( reader.getstring(2) );
788       status.setTimestamp( reader.getstring(3) );
789     }
790     return status;
791   }
792   catch ( const sqlite3x::database_error &e )
793   {
794     ZYPP_THROW(CacheRecordNotFoundException());
795   }
796 }
797
798 RepoStatus CacheStore::repositoryStatus( const string &alias )
799 {
800   return repositoryStatus(lookupRepository(alias));
801 }
802
803 bool CacheStore::isCached( const string &alias )
804 {
805   sqlite3_command cmd(_pimpl->con, "select id from repositories where alias=:alias;");
806   cmd.bind(":alias", alias);
807   try
808   {
809     sqlite3_reader reader= cmd.executereader();
810     if (!reader.read())
811     {
812       return false;
813    }
814    return true;
815   }
816   catch ( const sqlite3x::database_error &e )
817   {
818     ZYPP_RETHROW(e);
819   }
820   return false;
821 }
822
823 RecordId CacheStore::lookupRepository( const string &alias )
824 {
825   long long id = 0;
826   sqlite3_command cmd(_pimpl->con, "select id from repositories where alias=:alias;");
827   cmd.bind(":alias", alias);
828   try
829   {
830     sqlite3_reader reader= cmd.executereader();
831     if (!reader.read())
832     {
833       // does not exist
834       ZYPP_THROW(CacheRecordNotFoundException());
835    }
836    return reader.getint64(0);
837   }
838   catch ( const sqlite3x::database_error &e )
839   {
840     ZYPP_RETHROW(e);
841   }
842   return id;
843 }
844
845 RecordId CacheStore::lookupOrAppendType( const string &klass, const string &name )
846 {
847   pair<string, string> thetype = make_pair(klass,name);
848   if ( _pimpl->type_cache.find(thetype) != _pimpl->type_cache.end() )
849   {
850     //_pimpl->name_cache_hits++;
851     return _pimpl->type_cache[thetype];
852   }
853
854   _pimpl->select_type_cmd->bind(":class", klass);
855   _pimpl->select_type_cmd->bind(":name", name);
856   long long id = 0;
857   try
858   {
859     sqlite3_reader reader= _pimpl->select_type_cmd->executereader();
860     if (!reader.read())
861     {
862       // does not exist
863       _pimpl->insert_type_cmd->bind(":class", klass);
864       _pimpl->insert_type_cmd->bind(":name", name);
865       _pimpl->insert_type_cmd->executenonquery();
866       id = _pimpl->con.insertid();
867       _pimpl->type_cache[thetype] = id;
868       return id;
869    }
870    return reader.getint64(0);
871   }
872   catch ( const sqlite3x::database_error &e )
873   {
874     ZYPP_RETHROW(e);
875   }
876   return id;
877 }
878
879 RecordId CacheStore::lookupOrAppendName( const string &name )
880 {
881   if ( _pimpl->name_cache.find(name) != _pimpl->name_cache.end() )
882   {
883     _pimpl->name_cache_hits++;
884     return _pimpl->name_cache[name];
885   }
886   long long id = 0;
887   try
888   {
889     _pimpl->select_name_cmd->bind(":name", name);
890     sqlite3_reader reader= _pimpl->select_name_cmd->executereader();
891     if (!reader.read())
892     {
893       // does not exist
894       _pimpl->insert_name_cmd->bind(":name", name);
895       _pimpl->insert_name_cmd->executenonquery();
896       id = _pimpl->con.insertid();
897       _pimpl->name_cache[name] = id;
898       return id;
899    }
900    return reader.getint64(0);
901   }
902   catch ( const sqlite3x::database_error &e )
903   {
904     ZYPP_RETHROW(e);
905   }
906   return id;
907 }
908
909 RecordId CacheStore::lookupOrAppendDirName( const string &name )
910 {
911   long long id = 0;
912   try
913   {
914     _pimpl->select_dirname_cmd->bind(":name", name);
915     sqlite3_reader reader= _pimpl->select_dirname_cmd->executereader();
916     if (!reader.read())
917     {
918       // does not exist
919       _pimpl->insert_dirname_cmd->bind(":name", name);
920       _pimpl->insert_dirname_cmd->executenonquery();
921       id = _pimpl->con.insertid();
922       return id;
923    }
924    return reader.getint64(0);
925   }
926   catch ( const sqlite3x::database_error &e )
927   {
928     ZYPP_RETHROW(e);
929   }
930   return id;
931 }
932
933 RecordId CacheStore::lookupOrAppendFileName( const string &name )
934 {
935   long long id = 0;
936   try
937   {
938     _pimpl->select_filename_cmd->bind(":name", name);
939     sqlite3_reader reader= _pimpl->select_filename_cmd->executereader();
940     if (!reader.read())
941     {
942       // does not exist
943       _pimpl->insert_filename_cmd->bind(":name", name);
944       _pimpl->insert_filename_cmd->executenonquery();
945       id = _pimpl->con.insertid();
946       return id;
947    }
948    return reader.getint64(0);
949   }
950   catch ( const sqlite3x::database_error &e )
951   {
952     ZYPP_RETHROW(e);
953   }
954   return id;
955 }
956
957 void CacheStore::setSharedData( const data::RecordId &resolvable_id,
958                                 const data::RecordId &shared_id )
959 {
960   _pimpl->set_shared_flag_cmd->bind(":resolvable_id", resolvable_id);
961
962   if ( shared_id == data::noRecordId )
963    _pimpl->set_shared_flag_cmd->bind(":shared_id");
964   else
965    _pimpl->set_shared_flag_cmd->bind(":shared_id", shared_id);
966
967   _pimpl->set_shared_flag_cmd->executenonquery();
968 }
969
970 void CacheStore::appendBooleanAttribute( const data::RecordId & resolvable_id,
971                                          const std::string & klass,
972                                          const std::string & name,
973                                          bool value)
974 {
975   RecordId type_id = lookupOrAppendType( klass, name );
976   appendNumericAttribute( resolvable_id, type_id, value ? 1 : 0 );
977 }
978
979 void CacheStore::appendNumericAttribute( const data::RecordId &resolvable_id,
980                                          const std::string &klass,
981                                          const std::string &name,
982                                          int value )
983 {
984   RecordId type_id = lookupOrAppendType( klass, name );
985   appendNumericAttribute( resolvable_id, type_id, value );
986 }
987
988 void CacheStore::appendNumericAttribute( const RecordId &resolvable_id,
989                                          const RecordId &type_id,
990                                          int value )
991 {
992   // weak resolvable_id
993   _pimpl->append_num_attribute_cmd->bind(":rid", resolvable_id );
994   _pimpl->append_num_attribute_cmd->bind(":attr_id", type_id );
995
996   _pimpl->append_num_attribute_cmd->bind(":value", value );
997
998   _pimpl->append_num_attribute_cmd->executenonquery();
999 }
1000
1001
1002 void CacheStore::appendTranslatedStringAttribute( const data::RecordId &resolvable_id,
1003                                                   const std::string &klass,
1004                                                   const std::string &name,
1005                                                   const TranslatedText &text )
1006 {
1007   set<Locale> locales = text.locales();
1008   for ( set<Locale>::const_iterator it = locales.begin(); it != locales.end(); ++it )
1009   {
1010     appendStringAttributeTranslation( resolvable_id, *it, klass, name, text.text(*it) );
1011   }
1012 }
1013
1014
1015 void CacheStore::appendStringAttributeTranslation( const data::RecordId &resolvable_id,
1016                                                    const Locale &locale,
1017                                                    const std::string &klass,
1018                                                    const std::string &name,
1019                                                    const std::string &text )
1020 {
1021   // don't bother with writing if the string is empty
1022   if (text.empty()) return;
1023
1024   RecordId lang_id = lookupOrAppendType("lang",
1025       locale.code().empty() ? "none" : locale.code() );
1026   RecordId type_id = lookupOrAppendType( klass, name );
1027   appendStringAttribute( resolvable_id, lang_id, type_id, text );
1028 }
1029
1030 void CacheStore::appendStringAttribute( const data::RecordId &resolvable_id,
1031                                         const std::string &klass,
1032                                         const std::string &name,
1033                                         const std::string &value )
1034 {
1035   // don't bother with writing if the string is empty
1036   if (value.empty()) return;
1037
1038   RecordId type_id = lookupOrAppendType(klass, name);
1039   appendStringAttribute( resolvable_id, type_id, value );
1040 }
1041
1042 void CacheStore::appendStringAttribute( const RecordId &resolvable_id,
1043                                         const RecordId &type_id,
1044                                         const std::string &value )
1045 {
1046   // don't bother with writing if the string is empty
1047   if (value.empty()) return;
1048
1049   RecordId lang_id = lookupOrAppendType("lang", "none");
1050   appendStringAttribute( resolvable_id, lang_id, type_id, value );
1051 }
1052
1053 void CacheStore::appendStringAttribute( const RecordId &resolvable_id,
1054                             const RecordId &lang_id,
1055                             const RecordId &type_id,
1056                             const string &value )
1057 {
1058   // don't bother with writing if the string is empty
1059   if (value.empty()) return;
1060
1061   // weak resolvable_id
1062   _pimpl->append_text_attribute_cmd->bind(":rid", resolvable_id );
1063   _pimpl->append_text_attribute_cmd->bind(":lang_id", lang_id );
1064   _pimpl->append_text_attribute_cmd->bind(":attr_id", type_id );
1065
1066   _pimpl->append_text_attribute_cmd->bind(":text", value );
1067
1068   _pimpl->append_text_attribute_cmd->executenonquery();
1069 }
1070
1071 }
1072 }
1073