00001 #include <iterator>
00002 #include <algorithm>
00003 #include "zypp/base/PtrTypes.h"
00004 #include "zypp/base/Logger.h"
00005 #include "zypp/cache/CacheTypes.h"
00006 #include "zypp/cache/ResolvableQuery.h"
00007 #include "zypp/Package.h"
00008 #include "zypp/cache/sqlite3x/sqlite3x.hpp"
00009
00010 using namespace sqlite3x;
00011 using namespace std;
00012 using namespace zypp;
00013
00014 typedef shared_ptr<sqlite3_command> sqlite3_command_ptr;
00015
00016 namespace zypp { namespace cache {
00017
00018 struct ResolvableQuery::Impl
00019 {
00020 Pathname _dbdir;
00021 string _fields;
00022 CacheTypes _type_cache;
00023 sqlite3_connection _con;
00024 sqlite3_command_ptr _cmd_attr_str;
00025 sqlite3_command_ptr _cmd_attr_tstr;
00026 sqlite3_command_ptr _cmd_attr_num;
00027 sqlite3_command_ptr _cmd_disk_usage;
00028 sqlite3_command_ptr _cmd_shared_id;
00029
00030 Impl( const Pathname &dbdir)
00031 : _dbdir(dbdir)
00032 , _type_cache(dbdir)
00033 {
00034 _con.open((dbdir + "zypp.db").asString().c_str());
00035 _con.executenonquery("PRAGMA cache_size=8000;");
00036
00037 _cmd_shared_id.reset( new sqlite3_command( _con, "select shared_id from resolvables where id=:rid;") );
00038
00039 _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;") );
00040
00041
00042 _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;"));
00043
00044 _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;"));
00045
00046 _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;"));
00047
00048 MIL << "Creating Resolvable query impl" << endl;
00049
00050 _fields = "id, name, version, release, epoch, arch, kind, installed_size, archive_size, install_only, build_time, install_time, repository_id";
00051 }
00052
00053 ~Impl()
00054 {
00055 MIL << "Destroying Resolvable query impl" << endl;
00056 }
00057
00058
00059
00060
00061
00062 std::string regex2sql( const std::string & s)
00063 {
00064 std::string sql( s );
00065 string::iterator it;
00066 for (it = sql.begin(); it != sql.end(); ++it)
00067 {
00068 if (*it == '*') *it = '%';
00069 else if (*it == '?') *it = '_';
00070 }
00071 return sql;
00072 }
00073
00074 data::ResObject_Ptr fromRow( sqlite3_reader &reader )
00075 {
00076 data::ResObject_Ptr ptr (new data::ResObject);
00077
00078
00079
00080 ptr->name = reader.getstring(1);
00081 ptr->edition = Edition( reader.getstring(2), reader.getstring(3), reader.getint(4));
00082 ptr->arch = _type_cache.archFor(reader.getint(5));
00083 ptr->kind = _type_cache.kindFor( reader.getint(6) );
00084 ptr->repository = reader.getint( 12 );
00085
00086
00087
00088 return ptr;
00089 }
00090
00091
00092 void query( const data::RecordId &id,
00093 ProcessResolvable fnc )
00094 {
00095 sqlite3_command cmd( _con, "select " + _fields + " from resolvables where id=:id;");
00096 cmd.bind(":id", id);
00097 sqlite3_reader reader = cmd.executereader();
00098 while(reader.read())
00099 {
00100 fnc( id, fromRow(reader) );
00101 }
00102 }
00103
00104
00105 void query( const std::string &s,
00106 ProcessResolvable fnc )
00107 {
00108
00109 sqlite3_command cmd( _con, "select " + _fields + " from resolvables where name like :name;");
00110 cmd.bind( ":name", regex2sql( s ) );
00111 sqlite3_reader reader = cmd.executereader();
00112 while(reader.read())
00113 {
00114 fnc( reader.getint64(0), fromRow(reader) );
00115 }
00116 }
00117
00118
00119 std::string queryStringAttribute( const data::RecordId &record_id,
00120 const std::string &klass,
00121 const std::string &name,
00122 const std::string &default_value )
00123 {
00124 string value;
00125 return queryStringAttributeTranslationInternal( _con, record_id, Locale(), klass, name, default_value);
00126 }
00127
00128
00129 std::string queryStringAttributeTranslation( const data::RecordId &record_id,
00130 const Locale &locale,
00131 const std::string &klass,
00132 const std::string &name,
00133 const std::string &default_value )
00134 {
00135 return queryStringAttributeTranslationInternal( _con, record_id, locale, klass, name, default_value );
00136 }
00137
00138
00139 TranslatedText queryTranslatedStringAttribute( const data::RecordId &record_id,
00140 const std::string &klass,
00141 const std::string &name,
00142 const TranslatedText &default_value )
00143 {
00144 return queryTranslatedStringAttributeInternal( _con, record_id, klass, name, default_value );
00145 }
00146
00147
00148 bool queryBooleanAttribute( const data::RecordId &record_id,
00149 const std::string &klass,
00150 const std::string &name,
00151 bool default_value )
00152 {
00153 return ( queryNumericAttributeInternal( _con, record_id, klass, name, default_value) > 0 );
00154 }
00155
00156 int queryNumericAttribute( const data::RecordId &record_id,
00157 const std::string &klass,
00158 const std::string &name,
00159 int default_value )
00160 {
00161 return queryNumericAttributeInternal( _con, record_id, klass, name, default_value);
00162 }
00163
00164 void queryDiskUsage( const data::RecordId &record_id, DiskUsage &du )
00165 {
00166 _cmd_disk_usage->bind(":rid", record_id);
00167 sqlite3_reader reader = _cmd_disk_usage->executereader();
00168
00169 while ( reader.read() )
00170 {
00171 DiskUsage::Entry entry(reader.getstring(0),
00172 reader.getint(1),
00173 reader.getint(2) );
00174 du.add(entry);
00175 }
00176 }
00177
00178 std::string queryRepositoryAlias( const data::RecordId &repo_id )
00179 {
00180 std::string alias;
00181 sqlite3_command cmd( _con, "select alias from repositories where id=:id;" );
00182 cmd.bind( ":id", repo_id );
00183 sqlite3_reader reader = cmd.executereader();
00184 while( reader.read() )
00185 {
00186 alias = reader.getstring( 0 );
00187 break;
00188 }
00189 return alias;
00190 }
00191
00192 data::RecordId queryRepositoryId( const std::string &repo_alias )
00193 {
00194 long long id = 0;
00195 sqlite3_command cmd( _con, "select id from repositories where alias=:alias;" );
00196 cmd.bind( ":alias", repo_alias );
00197 sqlite3_reader reader = cmd.executereader();
00198 while( reader.read() )
00199 {
00200 id = reader.getint64(0);
00201 break;
00202 }
00203 return id;
00204 }
00205
00206 void iterateResolvablesByKindsAndStringsAndRepos( const std::vector<zypp::Resolvable::Kind> & kinds,
00207 const std::vector<std::string> &strings, int flags, const std::vector<std::string> repos, ProcessResolvable fnc )
00208 {
00209 std::string sqlcmd( "SELECT " + _fields + " FROM resolvables" );
00210
00211 std::vector<std::string>::const_iterator it_s;
00212 for (it_s = strings.begin(); it_s != strings.end(); ++it_s)
00213 {
00214 std::string s( *it_s );
00215
00216 if (it_s == strings.begin())
00217 sqlcmd += " WHERE (";
00218 else
00219 sqlcmd += " AND ";
00220
00221
00222
00223 sqlcmd += " name ";
00224 if (flags & MATCH_WILDCARDS == 0)
00225 {
00226 sqlcmd += "=";
00227 }
00228 else
00229 {
00230 sqlcmd += "like";
00231 s = regex2sql( s );
00232 }
00233 if (flags & MATCH_LEADING)
00234 s += "%";
00235 if (flags & MATCH_TRAILING)
00236 s = string("%") + s;
00237
00238 sqlcmd += " '";
00239 sqlcmd += s;
00240 sqlcmd += "'";
00241 }
00242
00243 if (it_s != strings.begin())
00244 {
00245 sqlcmd += ")";
00246 }
00247
00248 std::vector<zypp::Resolvable::Kind>::const_iterator it_k;
00249 if (!kinds.empty())
00250 {
00251 if (it_s == strings.begin())
00252 sqlcmd += " WHERE";
00253 else
00254 sqlcmd += " AND";
00255
00256 for (it_k = kinds.begin(); it_k != kinds.end(); ++it_k)
00257 {
00258 if (it_k == kinds.begin())
00259 sqlcmd += " kind IN (";
00260 else
00261 sqlcmd += ", ";
00262
00263 char idbuf[16];
00264 snprintf( idbuf, 15, "%d", (int)(_type_cache.idForKind( *it_k )) );
00265 sqlcmd += idbuf;
00266 }
00267
00268 if (it_k != kinds.begin())
00269 {
00270 sqlcmd += ")";
00271 }
00272 }
00273
00274 std::vector<std::string>::const_iterator it_r;
00275 if (!repos.empty())
00276 {
00277 if (it_s == strings.begin()
00278 && it_k == kinds.begin())
00279 sqlcmd += " WHERE";
00280 else
00281 sqlcmd += " AND";
00282
00283 for (it_r = repos.begin(); it_r != repos.end(); ++it_r)
00284 {
00285 if (it_r == repos.begin())
00286 sqlcmd += " (";
00287 else
00288 sqlcmd += " OR ";
00289
00290 sqlcmd += "repository_id = ";
00291 char idbuf[16];
00292 snprintf( idbuf, 15, "%ld", (long)(queryRepositoryId( *it_r )) );
00293 sqlcmd += idbuf;
00294 }
00295
00296 if (it_r != repos.begin())
00297 {
00298 sqlcmd += ")";
00299 }
00300 }
00301
00302 MIL << "sqlcmd " << sqlcmd << endl;
00303 sqlite3_command cmd( _con, sqlcmd );
00304 sqlite3_reader reader = cmd.executereader();
00305 while(reader.read())
00306 {
00307 fnc( reader.getint64(0), fromRow(reader) );
00308 }
00309 }
00310
00311 private:
00312
00313 int queryNumericAttributeInternal( sqlite3_connection &con,
00314 const data::RecordId &record_id,
00315 const std::string &klass,
00316 const std::string &name,
00317 int default_value )
00318 {
00319
00320 _cmd_attr_num->bind(":rid", record_id);
00321
00322 _cmd_attr_num->bind(":tclass", klass);
00323 _cmd_attr_num->bind(":tname", name);
00324
00325 sqlite3_reader reader = _cmd_attr_num->executereader();
00326 if ( reader.read() )
00327 return reader.getint(0);
00328 else
00329 {
00330 reader.close();
00331 sqlite3_reader idreader = _cmd_shared_id->executereader();
00332 if ( idreader.read() )
00333 {
00334 _cmd_shared_id->bind(":rid", record_id);
00335 data::RecordId sid = idreader.getint(0);
00336 idreader.close();
00337 return queryNumericAttributeInternal(con, sid, klass, name, default_value);
00338 }
00339 }
00340
00341 return default_value;
00342 }
00343
00344 TranslatedText queryTranslatedStringAttributeInternal( sqlite3_connection &con,
00345 const data::RecordId &record_id,
00346 const std::string &klass,
00347 const std::string &name,
00348 const TranslatedText &default_value )
00349 {
00350
00351
00352
00353 _cmd_attr_tstr->bind(":rid", record_id);
00354 _cmd_attr_tstr->bind(":lclass", "lang");
00355
00356 _cmd_attr_tstr->bind(":tclass", klass);
00357 _cmd_attr_tstr->bind(":tname", name);
00358
00359 TranslatedText result;
00360 sqlite3_reader reader = _cmd_attr_tstr->executereader();
00361
00362 int c = 0;
00363 while(reader.read())
00364 {
00365 result.setText( reader.getstring(0), Locale( reader.getstring(1) ) );
00366 c++;
00367 }
00368
00369 if ( c>0 )
00370 return result;
00371 else
00372 {
00373 reader.close();
00374 _cmd_shared_id->bind(":rid", record_id);
00375 sqlite3_reader idreader = _cmd_shared_id->executereader();
00376 if ( idreader.read() )
00377 {
00378 data::RecordId sid = idreader.getint(0);
00379 idreader.close();
00380 return queryTranslatedStringAttributeInternal(con, sid, klass, name, default_value);
00381 }
00382 }
00383
00384 return default_value;
00385 }
00386
00387 std::string queryStringAttributeInternal( sqlite3_connection &con,
00388 const data::RecordId &record_id,
00389 const std::string &klass,
00390 const std::string &name,
00391 const std::string &default_value )
00392 {
00393 return queryStringAttributeTranslationInternal( con, record_id, Locale(), klass, name, default_value );
00394 }
00395
00396 std::string queryStringAttributeTranslationInternal( sqlite3_connection &con,
00397 const data::RecordId &record_id,
00398 const Locale &locale,
00399 const std::string &klass,
00400 const std::string &name,
00401 const std::string &default_value )
00402 {
00403
00404 _cmd_attr_str->bind(":rid", record_id);
00405 _cmd_attr_str->bind(":lclass", "lang");
00406 if (locale == Locale() )
00407 _cmd_attr_str->bind(":lname", "none");
00408 else
00409 _cmd_attr_str->bind(":lname", locale.code());
00410
00411 _cmd_attr_str->bind(":tclass", klass);
00412 _cmd_attr_str->bind(":tname", name);
00413
00414 sqlite3_reader reader = _cmd_attr_str->executereader();
00415
00416 if ( reader.read() )
00417 return reader.getstring(0);
00418 else
00419 {
00420 reader.close();
00421 _cmd_shared_id->bind(":rid", record_id);
00422 sqlite3_reader idreader = _cmd_shared_id->executereader();
00423 if ( idreader.read() )
00424 {
00425 data::RecordId sid = idreader.getint(0);
00426 idreader.close();
00427 return queryStringAttributeTranslationInternal( con, sid, locale, klass, name, default_value );
00428 }
00429 }
00430
00431 return default_value;
00432 }
00433 };
00434
00436
00438
00439 ResolvableQuery::ResolvableQuery( const Pathname &dbdir)
00440 : _pimpl(new Impl(dbdir))
00441 {
00442
00443 }
00444
00445 ResolvableQuery::~ResolvableQuery()
00446 {
00447
00448 }
00449
00451
00452 void ResolvableQuery::query( const data::RecordId &id, ProcessResolvable fnc )
00453 {
00454 _pimpl->query(id, fnc);
00455 }
00456
00458
00459 void ResolvableQuery::query( const std::string &s, ProcessResolvable fnc )
00460 {
00461 _pimpl->query(s, fnc);
00462 }
00463
00465
00466 int ResolvableQuery::queryNumericAttribute( const data::RecordId &record_id,
00467 const std::string &klass,
00468 const std::string &name,
00469 int default_value )
00470 {
00471 return _pimpl->queryNumericAttribute(record_id, klass, name, default_value);
00472 }
00473
00474 bool ResolvableQuery::queryBooleanAttribute( const data::RecordId &record_id,
00475 const std::string &klass,
00476 const std::string &name,
00477 bool default_value )
00478 {
00479 return _pimpl->queryNumericAttribute(record_id, klass, name, default_value);
00480 }
00481
00482
00483 std::string ResolvableQuery::queryStringAttribute( const data::RecordId &record_id,
00484 const std::string &klass,
00485 const std::string &name,
00486 const std::string &default_value )
00487 {
00488 return _pimpl->queryStringAttribute(record_id, klass, name, default_value);
00489 }
00490
00492
00493 std::string ResolvableQuery::queryStringAttributeTranslation( const data::RecordId &record_id,
00494 const Locale &locale,
00495 const std::string &klass,
00496 const std::string &name,
00497 const std::string &default_value )
00498 {
00499 return _pimpl->queryStringAttributeTranslation(record_id, locale, klass, name, default_value );
00500 }
00501
00503
00504 TranslatedText ResolvableQuery::queryTranslatedStringAttribute( const data::RecordId &record_id,
00505 const std::string &klass,
00506 const std::string &name,
00507 const TranslatedText &default_value )
00508 {
00509 return _pimpl->queryTranslatedStringAttribute(record_id, klass, name, default_value );
00510 }
00511
00512 void ResolvableQuery::queryDiskUsage( const data::RecordId &record_id, DiskUsage &du )
00513 {
00514 _pimpl->queryDiskUsage(record_id, du);
00515 }
00516
00517 std::string ResolvableQuery::queryRepositoryAlias( const data::RecordId &repo_id )
00518 {
00519 return _pimpl->queryRepositoryAlias( repo_id );
00520 }
00521
00522 void ResolvableQuery::iterateResolvablesByKindsAndStringsAndRepos( const std::vector<zypp::Resolvable::Kind> & kinds,
00523 const std::vector<std::string> &strings, int flags, const std::vector<std::string> &repos, ProcessResolvable fnc )
00524 {
00525 _pimpl->iterateResolvablesByKindsAndStringsAndRepos( kinds, strings, flags, repos, fnc );
00526 }
00528
00529 } }