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