- create solv store
[platform/upstream/libzypp.git] / zypp / cache / ResolvableQuery.cc
1 #include <iterator>
2 #include <algorithm>
3 #include "zypp/base/PtrTypes.h"
4 #include "zypp/base/Logger.h"
5 #include "zypp/cache/CacheTypes.h"
6 #include "zypp/cache/ResolvableQuery.h"
7 #include "zypp/Package.h"
8 #include "zypp/cache/sqlite3x/sqlite3x.hpp"
9
10 using namespace sqlite3x;
11 using namespace std;
12 using namespace zypp;
13
14 typedef shared_ptr<sqlite3_command> sqlite3_command_ptr;
15
16 namespace zypp { namespace cache {
17
18 struct ResolvableQuery::Impl
19 {
20   Pathname _dbdir;
21   string _fields;
22   CacheTypes _type_cache;
23   sqlite3_connection _con;
24   sqlite3_command_ptr _cmd_attr_str;
25   sqlite3_command_ptr _cmd_attr_tstr;
26   sqlite3_command_ptr _cmd_attr_num;
27   sqlite3_command_ptr _cmd_disk_usage;
28   sqlite3_command_ptr _cmd_shared_id;
29
30   Impl( const Pathname &dbdir)
31   : _dbdir(dbdir)
32   , _type_cache(dbdir)
33   {
34     _con.open((dbdir + "zypp.db").asString().c_str());
35     _con.executenonquery("PRAGMA cache_size=8000;");
36
37     _cmd_shared_id.reset( new sqlite3_command( _con, "select shared_id from resolvables where id=:rid;") );
38
39     _cmd_attr_tstr.reset( new sqlite3_command( _con, "select a.text, l.name from text_attributes a,types l,types t where a.weak_resolvable_id=:rid and a.lang_id=l.id and a.attr_id=t.id and l.class=:lclass and t.class=:tclass and t.name=:tname;") );
40
41
42     _cmd_attr_str.reset( new sqlite3_command( _con, "select a.text from text_attributes a,types l,types t where a.weak_resolvable_id=:rid and a.lang_id=l.id and a.attr_id=t.id and l.class=:lclass and l.name=:lname and t.class=:tclass and t.name=:tname;"));
43
44     _cmd_attr_num.reset( new sqlite3_command( _con, "select a.value from numeric_attributes a,types t where a.weak_resolvable_id=:rid and a.attr_id=t.id and t.class=:tclass and t.name=:tname;"));
45
46     _cmd_disk_usage.reset( new sqlite3_command( _con, "select d.name,du.size,du.files from resolvable_disk_usage du,dir_names d where du.resolvable_id=:rid and du.dir_name_id=d.id;"));
47     
48     MIL << "Creating Resolvable query impl" << endl;
49     //         0   1     2        3        4      5     6     7               8             9             10          11            12
50     _fields = "id, name, version, release, epoch, arch, kind, installed_size, archive_size, install_only, build_time, install_time, repository_id";
51   }
52
53   ~Impl()
54   {
55       MIL << "Destroying Resolvable query impl" << endl;
56   }
57
58   //
59   // convert regex ? and * operators to sql _ and % respectively
60   //  example: regex2sql( "*foo?bar*" ) => "%foo_bar%"
61   // FIXME: take care of ".*" and "."
62   std::string regex2sql( const std::string & s)
63   {
64     std::string sql( s );
65     string::iterator it;
66     for (it = sql.begin(); it != sql.end(); ++it)
67     {
68       if (*it == '*') *it = '%';
69       else if (*it == '?') *it = '_';
70     }
71     return sql;
72   }
73
74   data::ResObject_Ptr fromRow( sqlite3_reader &reader )
75   {
76     data::ResObject_Ptr ptr (new data::ResObject);
77
78     // see _fields definition above for the getXXX() numbers
79
80     ptr->name = reader.getstring(1);
81     //ptr->edition = reader.getstring(2) reader.getstring(3), );
82     ptr->arch = _type_cache.archFor(reader.getint(5)).asString();
83     ptr->kind = _type_cache.kindFor( reader.getint(6) );
84     ptr->repository = reader.getint( 12 );
85
86     // TODO get the rest of the data
87
88     return ptr;
89   }
90
91   
92   void query( const data::RecordId &id,
93                   ProcessResolvable fnc )
94   {
95     sqlite3_command cmd( _con, "select " + _fields + " from resolvables where id=:id;");
96     cmd.bind(":id", id);
97     sqlite3_reader reader = cmd.executereader();
98     while(reader.read())
99     {
100       fnc( id, fromRow(reader) );
101     }
102   }
103
104
105   void query( const std::string &s,
106               ProcessResolvable fnc  )
107   {  
108     
109     sqlite3_command cmd( _con, "select " + _fields + " from resolvables where name like :name;");
110     cmd.bind( ":name", regex2sql( s ) );
111     sqlite3_reader reader = cmd.executereader();
112     while(reader.read())
113     {
114       fnc( reader.getint64(0), fromRow(reader) );
115     }
116   }
117
118
119   std::string queryStringAttribute( const data::RecordId &record_id,
120                                     const std::string &klass,
121                                     const std::string &name,
122                                     const std::string &default_value )
123   {
124     string value;
125     return queryStringAttributeTranslationInternal( _con, record_id, Locale(), klass, name, default_value);
126   }
127
128
129   std::string queryStringAttributeTranslation( const data::RecordId &record_id,
130                                                const Locale &locale,
131                                                const std::string &klass,
132                                                const std::string &name,
133                                                const std::string &default_value )
134   {
135     return queryStringAttributeTranslationInternal( _con, record_id, locale, klass, name, default_value );
136   }
137
138
139   TranslatedText queryTranslatedStringAttribute( const data::RecordId &record_id,
140                                                  const std::string &klass,
141                                                  const std::string &name,
142                                                  const TranslatedText &default_value )
143   {
144     return queryTranslatedStringAttributeInternal( _con, record_id, klass, name, default_value );
145   }
146
147
148   bool queryBooleanAttribute( const data::RecordId &record_id,
149                               const std::string &klass,
150                               const std::string &name,
151                               bool default_value )
152   {
153     return ( queryNumericAttributeInternal( _con, record_id, klass, name, default_value) > 0 );
154   }
155       
156   int queryNumericAttribute( const data::RecordId &record_id,
157                              const std::string &klass,
158                              const std::string &name,
159                              int default_value )
160   {
161     return queryNumericAttributeInternal( _con, record_id, klass, name, default_value);
162   }
163
164   void queryDiskUsage( const data::RecordId &record_id, DiskUsage &du )
165   {
166     _cmd_disk_usage->bind(":rid", record_id);
167     sqlite3_reader reader = _cmd_disk_usage->executereader();
168
169     while ( reader.read() )
170     {
171       DiskUsage::Entry entry(reader.getstring(0),
172                              reader.getint(1),
173                              reader.getint(2) );
174       du.add(entry);
175     }
176   }
177
178   std::string queryRepositoryAlias( const data::RecordId &repo_id )
179   {
180     std::string alias;
181     sqlite3_command cmd( _con, "select alias from repositories where id=:id;" );
182     cmd.bind( ":id", repo_id );
183     sqlite3_reader reader = cmd.executereader();
184     while( reader.read() )
185     {
186       alias = reader.getstring( 0 );
187       break;
188     }
189     return alias;
190   }
191   
192   data::RecordId queryRepositoryId( const std::string &repo_alias )
193   {
194     long long id = 0;
195     sqlite3_command cmd( _con, "select id from repositories where alias=:alias;" );
196     cmd.bind( ":alias", repo_alias );
197     sqlite3_reader reader = cmd.executereader();
198     while( reader.read() )
199     {
200       id = reader.getint64(0);
201       break;
202     }
203     return id;
204   }
205   
206   void iterateResolvablesByKindsAndStringsAndRepos( const std::vector<zypp::Resolvable::Kind> & kinds,
207                   const std::vector<std::string> &strings, int flags, const std::vector<std::string> repos, ProcessResolvable fnc )
208   {
209     std::string sqlcmd( "SELECT " + _fields + " FROM resolvables" );
210
211     std::vector<std::string>::const_iterator it_s;
212     for (it_s = strings.begin(); it_s != strings.end(); ++it_s)
213     {
214       std::string s( *it_s );
215
216       if (it_s == strings.begin())
217         sqlcmd += " WHERE (";
218       else
219         sqlcmd += " AND ";
220
221 //FIXME: Implement MATCH_RESSUMM and MATCH_RESDESC
222
223       sqlcmd += " name ";
224       if ((flags & MATCH_WILDCARDS) == 0)
225       {
226         sqlcmd += "=";
227       }
228       else
229       {
230         sqlcmd += "like";
231         s = regex2sql( s );
232       }
233       if (flags & MATCH_LEADING)
234         s += "%";
235       if (flags & MATCH_TRAILING)
236         s = string("%") + s;
237
238       sqlcmd += " '";
239       sqlcmd += s;
240       sqlcmd += "'";
241     }
242
243     if (it_s != strings.begin())
244     {
245       sqlcmd += ")";
246     }
247
248     std::vector<zypp::Resolvable::Kind>::const_iterator it_k;
249     if (!kinds.empty())
250     {
251       if (it_s == strings.begin())
252         sqlcmd += " WHERE";
253       else
254         sqlcmd += " AND";
255
256       for (it_k = kinds.begin(); it_k != kinds.end(); ++it_k)
257       {
258         if (it_k == kinds.begin())
259           sqlcmd += " kind IN (";
260         else
261           sqlcmd += ", ";
262
263         char idbuf[16];
264         snprintf( idbuf, 15, "%d", (int)(_type_cache.idForKind( *it_k )) );
265         sqlcmd += idbuf;
266       }
267
268       if (it_k != kinds.begin())
269       {
270         sqlcmd += ")";
271       }
272     }
273
274     std::vector<std::string>::const_iterator it_r;
275     if (!repos.empty())
276     {
277       if (it_s == strings.begin()
278           && it_k == kinds.begin())
279         sqlcmd += " WHERE";
280       else
281         sqlcmd += " AND";
282
283       for (it_r = repos.begin(); it_r != repos.end(); ++it_r)
284       {
285         if (it_r == repos.begin())
286           sqlcmd += " (";
287         else
288           sqlcmd += " OR ";
289
290         sqlcmd += "repository_id = ";
291         char idbuf[16];
292         snprintf( idbuf, 15, "%ld", (long)(queryRepositoryId( *it_r )) );
293         sqlcmd += idbuf;
294       }
295
296       if (it_r != repos.begin())
297       {
298         sqlcmd += ")";
299       }
300     }
301
302 MIL << "sqlcmd " << sqlcmd << endl;
303     sqlite3_command cmd( _con, sqlcmd );
304     sqlite3_reader reader = cmd.executereader();
305     while(reader.read())
306     {
307       fnc( reader.getint64(0), fromRow(reader) );
308     }
309   }
310
311 private:
312
313   int queryNumericAttributeInternal( sqlite3_connection &con,
314                                      const data::RecordId &record_id,
315                                      const std::string &klass,
316                                      const std::string &name,
317                                      int default_value )
318   {
319     //con.executenonquery("BEGIN;");
320     _cmd_attr_num->bind(":rid", record_id);
321
322     _cmd_attr_num->bind(":tclass", klass);
323     _cmd_attr_num->bind(":tname", name);
324
325     sqlite3_reader reader = _cmd_attr_num->executereader();
326     if ( reader.read() )
327       return reader.getint(0);
328     else
329     {
330       reader.close();
331       sqlite3_reader idreader = _cmd_shared_id->executereader();
332       if ( idreader.read() )
333       {
334         _cmd_shared_id->bind(":rid", record_id);
335         data::RecordId sid = idreader.getint(0);
336         idreader.close();
337         return queryNumericAttributeInternal(con, sid, klass, name, default_value);
338       }
339     }
340
341     return default_value;
342   }
343   
344   TranslatedText queryTranslatedStringAttributeInternal( sqlite3_connection &con,
345                                                          const data::RecordId &record_id,
346                                                          const std::string &klass,
347                                                          const std::string &name,
348                                                          const TranslatedText &default_value )
349   {
350     //con.executenonquery("PRAGMA cache_size=8000;");
351     //con.executenonquery("BEGIN;");
352
353     _cmd_attr_tstr->bind(":rid", record_id);
354     _cmd_attr_tstr->bind(":lclass", "lang");
355
356     _cmd_attr_tstr->bind(":tclass", klass);
357     _cmd_attr_tstr->bind(":tname", name);
358
359     TranslatedText result;
360     sqlite3_reader reader = _cmd_attr_tstr->executereader();
361     
362     int c = 0;
363     while(reader.read())
364     {
365       result.setText( reader.getstring(0), Locale( reader.getstring(1) ) );
366       c++;
367     }
368
369     if ( c>0 )
370       return result;
371     else
372     {
373       reader.close();
374       _cmd_shared_id->bind(":rid", record_id);
375       sqlite3_reader idreader = _cmd_shared_id->executereader();
376       if ( idreader.read() )
377       {
378         data::RecordId sid = idreader.getint(0);
379         idreader.close();
380         return queryTranslatedStringAttributeInternal(con, sid, klass, name, default_value);
381       }
382     }
383
384     return default_value;
385   }
386
387   std::string queryStringAttributeInternal( sqlite3_connection &con,
388                                             const data::RecordId &record_id,
389                                             const std::string &klass,
390                                             const std::string &name,
391                                             const std::string &default_value )
392   {
393     return queryStringAttributeTranslationInternal( con, record_id, Locale(), klass, name, default_value );
394   }
395
396   std::string queryStringAttributeTranslationInternal( sqlite3_connection &con,
397                                                        const data::RecordId &record_id,
398                                                        const Locale &locale,
399                                                        const std::string &klass,
400                                                        const std::string &name,
401                                                         const std::string &default_value )
402   {
403     //con.executenonquery("BEGIN;");
404     _cmd_attr_str->bind(":rid", record_id);
405     _cmd_attr_str->bind(":lclass", "lang");
406     if (locale == Locale() )
407       _cmd_attr_str->bind(":lname", "none");
408     else
409       _cmd_attr_str->bind(":lname", locale.code());
410
411     _cmd_attr_str->bind(":tclass", klass);
412     _cmd_attr_str->bind(":tname", name);
413
414     sqlite3_reader reader = _cmd_attr_str->executereader();
415     
416     if ( reader.read() )
417       return reader.getstring(0);
418     else
419     {
420       reader.close();
421       _cmd_shared_id->bind(":rid", record_id);
422       sqlite3_reader idreader = _cmd_shared_id->executereader();
423       if ( idreader.read() )
424       {
425         data::RecordId sid = idreader.getint(0);
426         idreader.close();
427         return queryStringAttributeTranslationInternal( con, sid, locale, klass, name, default_value );
428       }
429     }
430
431     return default_value;
432   }
433 };
434
435 //////////////////////////////////////////////////////////////////////////////
436 // FORWARD TO IMPLEMENTATION
437 //////////////////////////////////////////////////////////////////////////////
438
439 ResolvableQuery::ResolvableQuery( const Pathname &dbdir)
440   : _pimpl(new Impl(dbdir))
441 {
442   //MIL << "Creating Resolvable query" << endl;
443 }
444
445 ResolvableQuery::~ResolvableQuery()
446 {
447   //MIL << "Destroying Resolvable query" << endl;
448 }
449
450 //////////////////////////////////////////////////////////////////////////////
451
452 void ResolvableQuery::query( const data::RecordId &id, ProcessResolvable fnc  )
453 {
454   _pimpl->query(id, fnc);
455 }
456
457 //////////////////////////////////////////////////////////////////////////////
458
459 void ResolvableQuery::query( const std::string &s, ProcessResolvable fnc  )
460 {
461   _pimpl->query(s, fnc);
462 }
463
464 //////////////////////////////////////////////////////////////////////////////
465
466 int ResolvableQuery::queryNumericAttribute( const data::RecordId &record_id,
467                                             const std::string &klass,
468                                             const std::string &name,
469                                             int default_value )
470 {
471   return _pimpl->queryNumericAttribute(record_id, klass, name, default_value);
472 }
473
474 bool ResolvableQuery::queryBooleanAttribute( const data::RecordId &record_id,
475                                              const std::string &klass,
476                                              const std::string &name,
477                                              bool default_value )
478 {
479   return _pimpl->queryNumericAttribute(record_id, klass, name, default_value);
480 }
481
482
483 std::string ResolvableQuery::queryStringAttribute( const data::RecordId &record_id,
484                                                    const std::string &klass,
485                                                    const std::string &name,
486                                                    const std::string &default_value )
487 {
488   return _pimpl->queryStringAttribute(record_id, klass, name, default_value);
489 }
490
491 //////////////////////////////////////////////////////////////////////////////
492
493 std::string ResolvableQuery::queryStringAttributeTranslation( const data::RecordId &record_id,
494                                                               const Locale &locale,
495                                                               const std::string &klass,
496                                                               const std::string &name,
497                                                               const std::string &default_value )
498 {
499   return _pimpl->queryStringAttributeTranslation(record_id, locale, klass, name, default_value );
500 }
501
502 //////////////////////////////////////////////////////////////////////////////
503
504 TranslatedText ResolvableQuery::queryTranslatedStringAttribute( const data::RecordId &record_id,
505                                                                 const std::string &klass,
506                                                                 const std::string &name,
507                                                                 const TranslatedText &default_value )
508 {
509   return _pimpl->queryTranslatedStringAttribute(record_id, klass, name, default_value );
510 }
511
512 void ResolvableQuery::queryDiskUsage( const data::RecordId &record_id, DiskUsage &du )
513 {
514   _pimpl->queryDiskUsage(record_id, du);
515 }
516
517 std::string ResolvableQuery::queryRepositoryAlias( const data::RecordId &repo_id )
518 {
519   return _pimpl->queryRepositoryAlias( repo_id );
520 }
521
522 void ResolvableQuery::iterateResolvablesByKindsAndStringsAndRepos( const std::vector<zypp::Resolvable::Kind> & kinds,
523                   const std::vector<std::string> &strings, int flags, const std::vector<std::string> &repos, ProcessResolvable fnc )
524 {
525   _pimpl->iterateResolvablesByKindsAndStringsAndRepos( kinds, strings, flags, repos, fnc );
526 }
527 //////////////////////////////////////////////////////////////////////////////
528
529 } } // namespace zypp::cache