- unify query API for kind and name, summary, description
[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
29   Impl( const Pathname &dbdir)
30   : _dbdir(dbdir)
31   , _type_cache(dbdir)
32   {
33     _con.open((dbdir + "zypp.db").asString().c_str());
34     _con.executenonquery("PRAGMA cache_size=8000;");
35
36     _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;") );
37
38
39     _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;"));
40
41     _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;"));
42
43     _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;"));
44     
45     MIL << "Creating Resolvable query impl" << endl;
46     //         0   1     2        3        4      5     6     7               8             9             10          11            12
47     _fields = "id, name, version, release, epoch, arch, kind, installed_size, archive_size, install_only, build_time, install_time, repository_id";
48   }
49
50   ~Impl()
51   {
52       MIL << "Destroying Resolvable query impl" << endl;
53   }
54
55   //
56   // convert regex ? and * operators to sql _ and % respectively
57   //  example: regex2sql( "*foo?bar*" ) => "%foo_bar%"
58   std::string regex2sql( const std::string & s)
59   {
60     std::string sql( s );
61     string::iterator it;
62     for (it = sql.begin(); it != sql.end(); ++it)
63     {
64       if (*it == '*') *it = '%';
65       else if (*it == '?') *it = '_';
66     }
67     return sql;
68   }
69
70   data::ResObject_Ptr fromRow( sqlite3_reader &reader )
71   {
72     data::ResObject_Ptr ptr (new data::ResObject);
73
74     // see _fields definition above for the getXXX() numbers
75
76     ptr->name = reader.getstring(1);
77     ptr->edition = Edition( reader.getstring(2), reader.getstring(3), reader.getint(4));
78     ptr->arch = _type_cache.archFor(reader.getint(5));
79     ptr->kind = _type_cache.kindFor( reader.getint(6) );
80     ptr->repository = reader.getint( 12 );
81
82     // TODO get the rest of the data
83
84     return ptr;
85   }
86
87   
88   void query( const data::RecordId &id,
89                   ProcessResolvable fnc )
90   {
91     sqlite3_command cmd( _con, "select " + _fields + " from resolvables where id=:id;");
92     cmd.bind(":id", id);
93     sqlite3_reader reader = cmd.executereader();
94     while(reader.read())
95     {
96       fnc( id, fromRow(reader) );
97     }
98   }
99
100
101   void query( const std::string &s,
102               ProcessResolvable fnc  )
103   {  
104     
105     sqlite3_command cmd( _con, "select " + _fields + " from resolvables where name like :name;");
106     cmd.bind( ":name", regex2sql( s ) );
107     sqlite3_reader reader = cmd.executereader();
108     while(reader.read())
109     {
110       fnc( reader.getint64(0), fromRow(reader) );
111     }
112   }
113
114
115   std::string queryStringAttribute( const data::RecordId &record_id,
116                                     const std::string &klass,
117                                     const std::string &name,
118                                     const std::string &default_value )
119   {
120     string value;
121     return queryStringAttributeTranslationInternal( _con, record_id, Locale(), klass, name, default_value);
122   }
123
124
125   std::string queryStringAttributeTranslation( const data::RecordId &record_id,
126                                                const Locale &locale,
127                                                const std::string &klass,
128                                                const std::string &name,
129                                                const std::string &default_value )
130   {
131     return queryStringAttributeTranslationInternal( _con, record_id, locale, klass, name, default_value );
132   }
133
134
135   TranslatedText queryTranslatedStringAttribute( const data::RecordId &record_id,
136                                                  const std::string &klass,
137                                                  const std::string &name,
138                                                  const TranslatedText &default_value )
139   {
140     return queryTranslatedStringAttributeInternal( _con, record_id, klass, name, default_value );
141   }
142
143
144   bool queryBooleanAttribute( const data::RecordId &record_id,
145                               const std::string &klass,
146                               const std::string &name,
147                               bool default_value )
148   {
149     return ( queryNumericAttributeInternal( _con, record_id, klass, name, default_value) > 0 );
150   }
151       
152   int queryNumericAttribute( const data::RecordId &record_id,
153                              const std::string &klass,
154                              const std::string &name,
155                              int default_value )
156   {
157     return queryNumericAttributeInternal( _con, record_id, klass, name, default_value);
158   }
159
160   void queryDiskUsage( const data::RecordId &record_id, DiskUsage &du )
161   {
162     _cmd_disk_usage->bind(":rid", record_id);
163     sqlite3_reader reader = _cmd_disk_usage->executereader();
164
165     while ( reader.read() )
166     {
167       DiskUsage::Entry entry(reader.getstring(0),
168                              reader.getint(1),
169                              reader.getint(2) );
170       du.add(entry);
171     }
172   }
173
174   std::string queryRepositoryAlias( const data::RecordId &repo_id )
175   {
176     std::string alias;
177     sqlite3_command cmd( _con, "select alias from repositories where id=:id;" );
178     cmd.bind( ":id", repo_id );
179     sqlite3_reader reader = cmd.executereader();
180     while( reader.read() )
181     {
182       alias = reader.getstring( 0 );
183       break;
184     }
185     return alias;
186   }
187   
188   void iterateResolvablesByKind( zypp::Resolvable::Kind kind, ProcessResolvable fnc )
189   {
190     sqlite3_command cmd( _con, "select " + _fields + " from resolvables where kind=:kind;");
191     data::RecordId kind_id = _type_cache.idForKind( kind );
192     cmd.bind(":kind", kind_id);
193     sqlite3_reader reader = cmd.executereader();
194     while(reader.read())
195     {
196       fnc( reader.getint64(0), fromRow(reader) );
197     }
198   }
199   
200   void iterateResolvablesByKindsAndStrings( const std::vector<zypp::Resolvable::Kind> & kinds,
201                   const std::vector<std::string> &strings, int flags, ProcessResolvable fnc )
202   {
203     std::string sqlcmd( "SELECT " + _fields + " FROM resolvables WHERE (" );
204     std::vector<std::string>::const_iterator it_s;
205     for (it_s = strings.begin(); it_s != strings.end(); ++it_s)
206     {
207       std::string s( *it_s );
208
209       if (it_s != strings.begin())
210         sqlcmd += "OR";
211
212 //FIXME: Implement MATCH_RESSUMM and MATCH_RESDESC
213
214       sqlcmd += " name ";
215       if (flags & MATCH_WILDCARDS == 0)
216       {
217         sqlcmd += "=";
218       }
219       else
220       {
221         sqlcmd += "like";
222         s = regex2sql( s );
223       }
224       if (flags & MATCH_LEADING)
225         s += "%";
226       if (flags & MATCH_TRAILING)
227         s = string("%") + s;
228
229       sqlcmd += " '";
230       sqlcmd += s;
231       sqlcmd += "'";
232     }
233     sqlcmd += ") AND kind IN (";
234
235     std::vector<zypp::Resolvable::Kind>::const_iterator it_k;
236     for (it_k = kinds.begin(); it_k != kinds.end(); ++it_k)
237     {
238       if (it_k != kinds.begin())
239         sqlcmd += ", ";
240       char idbuf[16];
241       snprintf( idbuf, 15, "%d", (int)(_type_cache.idForKind( *it_k )) );
242       sqlcmd += idbuf;
243     }
244     sqlite3_command cmd( _con, sqlcmd + ")");
245
246     sqlite3_reader reader = cmd.executereader();
247     while(reader.read())
248     {
249       fnc( reader.getint64(0), fromRow(reader) );
250     }
251   }
252
253 private:
254
255   int queryNumericAttributeInternal( sqlite3_connection &con,
256                                      const data::RecordId &record_id,
257                                      const std::string &klass,
258                                      const std::string &name,
259                                      int default_value )
260   {
261     //con.executenonquery("BEGIN;");
262     _cmd_attr_num->bind(":rid", record_id);
263
264     _cmd_attr_num->bind(":tclass", klass);
265     _cmd_attr_num->bind(":tname", name);
266
267     sqlite3_reader reader = _cmd_attr_num->executereader();
268     if ( reader.read() )
269       return reader.getint(0);
270
271     return default_value;
272   }
273   
274   TranslatedText queryTranslatedStringAttributeInternal( sqlite3_connection &con,
275                                                          const data::RecordId &record_id,
276                                                          const std::string &klass,
277                                                          const std::string &name,
278                                                          const TranslatedText &default_value )
279   {
280     //con.executenonquery("PRAGMA cache_size=8000;");
281     //con.executenonquery("BEGIN;");
282
283     _cmd_attr_tstr->bind(":rid", record_id);
284     _cmd_attr_tstr->bind(":lclass", "lang");
285
286     _cmd_attr_tstr->bind(":tclass", klass);
287     _cmd_attr_tstr->bind(":tname", name);
288
289     TranslatedText result;
290     sqlite3_reader reader = _cmd_attr_tstr->executereader();
291     
292     int c = 0;
293     while(reader.read())
294     {
295       result.setText( reader.getstring(0), Locale( reader.getstring(1) ) );
296       c++;
297     }
298
299     if ( c>0 )
300       return result;
301     
302     return default_value;
303   }
304
305   std::string queryStringAttributeInternal( sqlite3_connection &con,
306                                             const data::RecordId &record_id,
307                                             const std::string &klass,
308                                             const std::string &name,
309                                             const std::string &default_value )
310   {
311     return queryStringAttributeTranslationInternal( con, record_id, Locale(), klass, name, default_value );
312   }
313
314   std::string queryStringAttributeTranslationInternal( sqlite3_connection &con,
315                                                        const data::RecordId &record_id,
316                                                        const Locale &locale,
317                                                        const std::string &klass,
318                                                        const std::string &name,
319                                                         const std::string &default_value )
320   {
321     //con.executenonquery("BEGIN;");
322     _cmd_attr_str->bind(":rid", record_id);
323     _cmd_attr_str->bind(":lclass", "lang");
324     if (locale == Locale() )
325       _cmd_attr_str->bind(":lname", "none");
326     else
327       _cmd_attr_str->bind(":lname", locale.code());
328
329     _cmd_attr_str->bind(":tclass", klass);
330     _cmd_attr_str->bind(":tname", name);
331
332     sqlite3_reader reader = _cmd_attr_str->executereader();
333     
334     if ( reader.read() )
335       return reader.getstring(0);
336     
337     return default_value;
338   }
339 };
340
341 //////////////////////////////////////////////////////////////////////////////
342 // FORWARD TO IMPLEMENTATION
343 //////////////////////////////////////////////////////////////////////////////
344
345 ResolvableQuery::ResolvableQuery( const Pathname &dbdir)
346   : _pimpl(new Impl(dbdir))
347 {
348   //MIL << "Creating Resolvable query" << endl;
349 }
350
351 ResolvableQuery::~ResolvableQuery()
352 {
353   //MIL << "Destroying Resolvable query" << endl;
354 }
355
356 //////////////////////////////////////////////////////////////////////////////
357
358 void ResolvableQuery::query( const data::RecordId &id, ProcessResolvable fnc  )
359 {
360   _pimpl->query(id, fnc);
361 }
362
363 //////////////////////////////////////////////////////////////////////////////
364
365 void ResolvableQuery::query( const std::string &s, ProcessResolvable fnc  )
366 {
367   _pimpl->query(s, fnc);
368 }
369
370 //////////////////////////////////////////////////////////////////////////////
371
372 int ResolvableQuery::queryNumericAttribute( const data::RecordId &record_id,
373                                             const std::string &klass,
374                                             const std::string &name,
375                                             int default_value )
376 {
377   return _pimpl->queryNumericAttribute(record_id, klass, name, default_value);
378 }
379
380 bool ResolvableQuery::queryBooleanAttribute( const data::RecordId &record_id,
381                                              const std::string &klass,
382                                              const std::string &name,
383                                              bool default_value )
384 {
385   return _pimpl->queryNumericAttribute(record_id, klass, name, default_value);
386 }
387
388
389 std::string ResolvableQuery::queryStringAttribute( const data::RecordId &record_id,
390                                                    const std::string &klass,
391                                                    const std::string &name,
392                                                    const std::string &default_value )
393 {
394   return _pimpl->queryStringAttribute(record_id, klass, name, default_value);
395 }
396
397 //////////////////////////////////////////////////////////////////////////////
398
399 std::string ResolvableQuery::queryStringAttributeTranslation( const data::RecordId &record_id,
400                                                               const Locale &locale,
401                                                               const std::string &klass,
402                                                               const std::string &name,
403                                                               const std::string &default_value )
404 {
405   return _pimpl->queryStringAttributeTranslation(record_id, locale, klass, name, default_value );
406 }
407
408 //////////////////////////////////////////////////////////////////////////////
409
410 TranslatedText ResolvableQuery::queryTranslatedStringAttribute( const data::RecordId &record_id,
411                                                                 const std::string &klass,
412                                                                 const std::string &name,
413                                                                 const TranslatedText &default_value )
414 {
415   return _pimpl->queryTranslatedStringAttribute(record_id, klass, name, default_value );
416 }
417
418 void ResolvableQuery::queryDiskUsage( const data::RecordId &record_id, DiskUsage &du )
419 {
420   _pimpl->queryDiskUsage(record_id, du);
421 }
422
423 std::string ResolvableQuery::queryRepositoryAlias( const data::RecordId &repo_id )
424 {
425   return _pimpl->queryRepositoryAlias( repo_id );
426 }
427
428 void ResolvableQuery::iterateResolvablesByKind( zypp::Resolvable::Kind kind, ProcessResolvable fnc )
429 {
430   return _pimpl->iterateResolvablesByKind( kind, fnc );
431 }
432
433 void ResolvableQuery::iterateResolvablesByKindsAndStrings( const std::vector<zypp::Resolvable::Kind> & kinds,
434                   const std::vector<std::string> &strings, int flags, ProcessResolvable fnc )
435 {
436   _pimpl->iterateResolvablesByKindsAndStrings( kinds, strings, flags, fnc );
437 }
438 //////////////////////////////////////////////////////////////////////////////
439
440 } } // namespace zypp::cache