2 * Copyright (C) 2005-2013 Team XBMC
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
21 #include "AddonDatabase.h"
22 #include "addons/AddonManager.h"
23 #include "utils/log.h"
24 #include "utils/Variant.h"
25 #include "utils/StringUtils.h"
26 #include "XBDateTime.h"
27 #include "addons/Service.h"
28 #include "dbwrappers/dataset.h"
29 #include "pvr/PVRManager.h"
31 using namespace ADDON;
34 CAddonDatabase::CAddonDatabase()
38 CAddonDatabase::~CAddonDatabase()
42 bool CAddonDatabase::Open()
44 return CDatabase::Open();
47 bool CAddonDatabase::CreateTables()
51 CDatabase::CreateTables();
53 CLog::Log(LOGINFO, "create addon table");
54 m_pDS->exec("CREATE TABLE addon (id integer primary key, type text,"
55 "name text, summary text, description text, stars integer,"
56 "path text, addonID text, icon text, version text, "
57 "changelog text, fanart text, author text, disclaimer text,"
58 "minversion text)\n");
60 CLog::Log(LOGINFO, "create addon index");
61 m_pDS->exec("CREATE INDEX idxAddon ON addon(addonID)");
63 CLog::Log(LOGINFO, "create addonextra table");
64 m_pDS->exec("CREATE TABLE addonextra (id integer, key text, value text)\n");
66 CLog::Log(LOGINFO, "create addonextra index");
67 m_pDS->exec("CREATE INDEX idxAddonExtra ON addonextra(id)");
69 CLog::Log(LOGINFO, "create dependencies table");
70 m_pDS->exec("CREATE TABLE dependencies (id integer, addon text, version text, optional boolean)\n");
71 m_pDS->exec("CREATE INDEX idxDependencies ON dependencies(id)");
73 CLog::Log(LOGINFO, "create repo table");
74 m_pDS->exec("CREATE TABLE repo (id integer primary key, addonID text,"
75 "checksum text, lastcheck text)\n");
77 CLog::Log(LOGINFO, "create addonlinkrepo table");
78 m_pDS->exec("CREATE TABLE addonlinkrepo (idRepo integer, idAddon integer)\n");
79 m_pDS->exec("CREATE UNIQUE INDEX ix_addonlinkrepo_1 ON addonlinkrepo ( idAddon, idRepo )\n");
80 m_pDS->exec("CREATE UNIQUE INDEX ix_addonlinkrepo_2 ON addonlinkrepo ( idRepo, idAddon )\n");
82 CLog::Log(LOGINFO, "create disabled table");
83 m_pDS->exec("CREATE TABLE disabled (id integer primary key, addonID text)\n");
84 m_pDS->exec("CREATE UNIQUE INDEX idxDisabled ON disabled(addonID)");
86 CLog::Log(LOGINFO, "create broken table");
87 m_pDS->exec("CREATE TABLE broken (id integer primary key, addonID text, reason text)\n");
88 m_pDS->exec("CREATE UNIQUE INDEX idxBroken ON broken(addonID)");
90 CLog::Log(LOGINFO, "create blacklist table");
91 m_pDS->exec("CREATE TABLE blacklist (id integer primary key, addonID text, version text)\n");
92 m_pDS->exec("CREATE UNIQUE INDEX idxBlack ON blacklist(addonID)");
94 CLog::Log(LOGINFO, "create package table");
95 m_pDS->exec("CREATE TABLE package (id integer primary key, addonID text, filename text, hash text)\n");
96 m_pDS->exec("CREATE UNIQUE INDEX idxPackage ON package(filename)");
100 CLog::Log(LOGERROR, "%s unable to create tables", __FUNCTION__);
107 bool CAddonDatabase::UpdateOldVersion(int version)
111 m_pDS->exec("CREATE TABLE dependencies (id integer, addon text, version text, optional boolean)\n");
112 m_pDS->exec("CREATE INDEX idxDependencies ON dependencies(id)");
116 m_pDS->exec("ALTER TABLE addon add minversion text");
120 m_pDS->exec("CREATE TABLE blacklist (id integer primary key, addonID text, version text)\n");
121 m_pDS->exec("CREATE UNIQUE INDEX idxBlack ON blacklist(addonID)");
125 m_pDS->exec("CREATE TABLE package (id integer primary key, addonID text, filename text, hash text)\n");
126 m_pDS->exec("CREATE UNIQUE INDEX idxPackage ON package(filename)");
131 int CAddonDatabase::AddAddon(const AddonPtr& addon,
136 if (NULL == m_pDB.get()) return -1;
137 if (NULL == m_pDS.get()) return -1;
139 bool bDisablePVRAddon = addon->Type() == ADDON_PVRDLL && !HasAddon(addon->ID());
141 CStdString sql = PrepareSQL("insert into addon (id, type, name, summary,"
142 "description, stars, path, icon, changelog, "
143 "fanart, addonID, version, author, disclaimer, minversion)"
144 " values(NULL, '%s', '%s', '%s', '%s', %i,"
145 "'%s', '%s', '%s', '%s', '%s','%s','%s','%s','%s')",
146 TranslateType(addon->Type(),false).c_str(),
147 addon->Name().c_str(), addon->Summary().c_str(),
148 addon->Description().c_str(),addon->Stars(),
149 addon->Path().c_str(), addon->Props().icon.c_str(),
150 addon->ChangeLog().c_str(),addon->FanArt().c_str(),
151 addon->ID().c_str(), addon->Version().c_str(),
152 addon->Author().c_str(),addon->Disclaimer().c_str(),
153 addon->MinVersion().c_str());
154 m_pDS->exec(sql.c_str());
155 int idAddon = (int)m_pDS->lastinsertid();
157 sql = PrepareSQL("insert into addonlinkrepo (idRepo, idAddon) values (%i,%i)",idRepo,idAddon);
158 m_pDS->exec(sql.c_str());
160 const InfoMap &info = addon->ExtraInfo();
161 for (InfoMap::const_iterator i = info.begin(); i != info.end(); ++i)
163 sql = PrepareSQL("insert into addonextra(id, key, value) values (%i, '%s', '%s')", idAddon, i->first.c_str(), i->second.c_str());
164 m_pDS->exec(sql.c_str());
166 const ADDONDEPS &deps = addon->GetDeps();
167 for (ADDONDEPS::const_iterator i = deps.begin(); i != deps.end(); ++i)
169 sql = PrepareSQL("insert into dependencies(id, addon, version, optional) values (%i, '%s', '%s', %i)", idAddon, i->first.c_str(), i->second.first.c_str(), i->second.second ? 1 : 0);
170 m_pDS->exec(sql.c_str());
172 // these need to be configured
173 if (bDisablePVRAddon)
174 DisableAddon(addon->ID(), true);
179 CLog::Log(LOGERROR, "%s failed on addon '%s'", __FUNCTION__, addon->Name().c_str());
184 bool CAddonDatabase::GetAddon(const CStdString& id, AddonPtr& addon)
188 if (NULL == m_pDB.get()) return false;
189 if (NULL == m_pDS2.get()) return false;
191 // there may be multiple addons with this id (eg from different repositories) in the database,
192 // so we want to retrieve the latest version. Order by version won't work as the database
193 // won't know that 1.10 > 1.2, so grab them all and order outside
194 CStdString sql = PrepareSQL("select id,version from addon where addonID='%s'",id.c_str());
195 m_pDS2->query(sql.c_str());
200 AddonVersion maxversion("0.0.0");
202 while (!m_pDS2->eof())
204 AddonVersion version(m_pDS2->fv(1).get_asString());
205 if (version > maxversion)
207 maxid = m_pDS2->fv(0).get_asInt();
208 maxversion = version;
212 return GetAddon(maxid,addon);
216 CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, id.c_str());
222 bool CAddonDatabase::GetRepoForAddon(const CStdString& addonID, CStdString& repo)
226 if (NULL == m_pDB.get()) return false;
227 if (NULL == m_pDS2.get()) return false;
229 CStdString sql = PrepareSQL("select repo.addonID from repo join addonlinkrepo on repo.id=addonlinkrepo.idRepo join addon on addonlinkrepo.idAddon=addon.id where addon.addonID like '%s'", addonID.c_str());
230 m_pDS2->query(sql.c_str());
233 repo = m_pDS2->fv(0).get_asString();
240 CLog::Log(LOGERROR, "%s failed for addon %s", __FUNCTION__, addonID.c_str());
245 bool CAddonDatabase::GetAddon(int id, AddonPtr &addon)
249 if (NULL == m_pDB.get()) return false;
250 if (NULL == m_pDS2.get()) return false;
252 std::string sql = "SELECT addon.*,"
254 " addonextra.key, addonextra.value,"
255 " dependencies.addon, dependencies.version, dependencies.optional"
258 " ON broken.addonID = addon.addonID"
259 " LEFT JOIN addonextra"
260 " ON addonextra.id = addon.id"
261 " LEFT JOIN dependencies"
262 " ON dependencies.id = addon.id";
264 sql += PrepareSQL(" WHERE addon.id=%i", id);
266 m_pDS2->query(sql.c_str());
269 const dbiplus::query_data &data = m_pDS2->get_result_set().records;
270 const dbiplus::sql_record* const record = data[0];
271 AddonProps props(record->at(addon_addonID).get_asString(),
272 TranslateType(record->at(addon_type).get_asString()),
273 record->at(addon_version).get_asString(),
274 record->at(addon_minversion).get_asString());
275 props.name = record->at(addon_name).get_asString();
276 props.summary = record->at(addon_summary).get_asString();
277 props.description = record->at(addon_description).get_asString();
278 props.changelog = record->at(addon_changelog).get_asString();
279 props.path = record->at(addon_path).get_asString();
280 props.icon = record->at(addon_icon).get_asString();
281 props.fanart = record->at(addon_fanart).get_asString();
282 props.author = record->at(addon_author).get_asString();
283 props.disclaimer = record->at(addon_disclaimer).get_asString();
284 props.broken = record->at(broken_reason).get_asString();
286 /* while this is a cartesion join and we'll typically get multiple rows, we rely on the fact that
287 extrainfo and dependencies are maps, so insert() will insert the first instance only */
288 for (dbiplus::query_data::const_iterator i = data.begin(); i != data.end(); ++i)
290 const dbiplus::sql_record* const record = *i;
291 if (!record->at(addonextra_key).get_asString().empty())
292 props.extrainfo.insert(make_pair(record->at(addonextra_key).get_asString(), record->at(addonextra_value).get_asString()));
293 if (!m_pDS2->fv(dependencies_addon).get_asString().empty())
294 props.dependencies.insert(make_pair(record->at(dependencies_addon).get_asString(), make_pair(AddonVersion(record->at(dependencies_version).get_asString()), record->at(dependencies_optional).get_asBool())));
297 addon = CAddonMgr::AddonFromProps(props);
298 return NULL != addon.get();
303 CLog::Log(LOGERROR, "%s failed on addon %i", __FUNCTION__, id);
309 bool CAddonDatabase::GetAddons(VECADDONS& addons)
313 if (NULL == m_pDB.get()) return false;
314 if (NULL == m_pDS2.get()) return false;
316 CStdString sql = PrepareSQL("select distinct addonID from addon");
317 m_pDS->query(sql.c_str());
318 while (!m_pDS->eof())
321 if (GetAddon(m_pDS->fv(0).get_asString(),addon))
322 addons.push_back(addon);
330 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
335 void CAddonDatabase::DeleteRepository(const CStdString& id)
339 if (NULL == m_pDB.get()) return;
340 if (NULL == m_pDS.get()) return;
342 CStdString sql = PrepareSQL("select id from repo where addonID='%s'",id.c_str());
343 m_pDS->query(sql.c_str());
345 DeleteRepository(m_pDS->fv(0).get_asInt());
349 CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
353 void CAddonDatabase::DeleteRepository(int idRepo)
357 if (NULL == m_pDB.get()) return;
358 if (NULL == m_pDS.get()) return;
360 CStdString sql = PrepareSQL("delete from repo where id=%i",idRepo);
361 m_pDS->exec(sql.c_str());
362 sql = PrepareSQL("delete from addon where id in (select idAddon from addonlinkrepo where idRepo=%i)",idRepo);
363 m_pDS->exec(sql.c_str());
364 sql = PrepareSQL("delete from addonextra where id in (select idAddon from addonlinkrepo where idRepo=%i)",idRepo);
365 m_pDS->exec(sql.c_str());
366 sql = PrepareSQL("delete from dependencies where id in (select idAddon from addonlinkrepo where idRepo=%i)",idRepo);
367 m_pDS->exec(sql.c_str());
368 sql = PrepareSQL("delete from addonlinkrepo where idRepo=%i",idRepo);
369 m_pDS->exec(sql.c_str());
374 CLog::Log(LOGERROR, "%s failed on repo %i", __FUNCTION__, idRepo);
378 int CAddonDatabase::AddRepository(const CStdString& id, const VECADDONS& addons, const CStdString& checksum)
382 if (NULL == m_pDB.get()) return -1;
383 if (NULL == m_pDS.get()) return -1;
386 int idRepo = GetRepoChecksum(id,sql);
388 DeleteRepository(idRepo);
392 CDateTime time = CDateTime::GetCurrentDateTime();
393 sql = PrepareSQL("insert into repo (id,addonID,checksum,lastcheck) values (NULL,'%s','%s','%s')",id.c_str(),checksum.c_str(),time.GetAsDBDateTime().c_str());
394 m_pDS->exec(sql.c_str());
395 idRepo = (int)m_pDS->lastinsertid();
396 for (unsigned int i=0;i<addons.size();++i)
397 AddAddon(addons[i],idRepo);
404 CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
405 RollbackTransaction();
410 int CAddonDatabase::GetRepoChecksum(const std::string& id, std::string& checksum)
414 if (NULL == m_pDB.get()) return -1;
415 if (NULL == m_pDS.get()) return -1;
417 std::string strSQL = PrepareSQL("select * from repo where addonID='%s'",id.c_str());
418 m_pDS->query(strSQL.c_str());
421 checksum = m_pDS->fv("checksum").get_asString();
422 return m_pDS->fv("id").get_asInt();
427 CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
433 CDateTime CAddonDatabase::GetRepoTimestamp(const CStdString& id)
438 if (NULL == m_pDB.get()) return date;
439 if (NULL == m_pDS.get()) return date;
441 CStdString strSQL = PrepareSQL("select * from repo where addonID='%s'",id.c_str());
442 m_pDS->query(strSQL.c_str());
445 date.SetFromDBDateTime(m_pDS->fv("lastcheck").get_asString());
451 CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
456 bool CAddonDatabase::SetRepoTimestamp(const CStdString& id, const CStdString& time)
460 if (NULL == m_pDB.get()) return false;
461 if (NULL == m_pDS.get()) return false;
463 CStdString sql = PrepareSQL("update repo set lastcheck='%s' where addonID='%s'",time.c_str(),id.c_str());
464 m_pDS->exec(sql.c_str());
470 CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
475 bool CAddonDatabase::GetRepository(int id, VECADDONS& addons)
479 if (NULL == m_pDB.get()) return false;
480 if (NULL == m_pDS.get()) return false;
482 CStdString strSQL = PrepareSQL("select * from addonlinkrepo where idRepo=%i",id);
483 m_pDS->query(strSQL.c_str());
484 while (!m_pDS->eof())
487 if (GetAddon(m_pDS->fv("idAddon").get_asInt(),addon))
488 addons.push_back(addon);
495 CLog::Log(LOGERROR, "%s failed on repo %i", __FUNCTION__, id);
500 bool CAddonDatabase::GetRepository(const CStdString& id, VECADDONS& addons)
504 if (NULL == m_pDB.get()) return false;
505 if (NULL == m_pDS.get()) return false;
507 CStdString strSQL = PrepareSQL("select id from repo where addonID='%s'",id.c_str());
508 m_pDS->query(strSQL.c_str());
510 return GetRepository(m_pDS->fv(0).get_asInt(),addons);
514 CLog::Log(LOGERROR, "%s failed on repo %s", __FUNCTION__, id.c_str());
519 bool CAddonDatabase::Search(const CStdString& search, VECADDONS& addons)
523 if (NULL == m_pDB.get()) return false;
524 if (NULL == m_pDS.get()) return false;
527 strSQL=PrepareSQL("SELECT addonID FROM addon WHERE name LIKE '%%%s%%' OR summary LIKE '%%%s%%' OR description LIKE '%%%s%%'", search.c_str(), search.c_str(), search.c_str());
528 CLog::Log(LOGDEBUG, "%s query: %s", __FUNCTION__, strSQL.c_str());
530 if (!m_pDS->query(strSQL.c_str())) return false;
531 if (m_pDS->num_rows() == 0) return false;
533 while (!m_pDS->eof())
536 GetAddon(m_pDS->fv(0).get_asString(),addon);
537 if (addon->Type() >= ADDON_UNKNOWN+1 && addon->Type() < ADDON_SCRAPER_LIBRARY)
538 addons.push_back(addon);
546 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
551 void CAddonDatabase::SetPropertiesFromAddon(const AddonPtr& addon,
554 pItem->SetProperty("Addon.ID", addon->ID());
555 pItem->SetProperty("Addon.Type", TranslateType(addon->Type(),true));
556 pItem->SetProperty("Addon.intType", TranslateType(addon->Type()));
557 pItem->SetProperty("Addon.Name", addon->Name());
558 pItem->SetProperty("Addon.Version", addon->Version().c_str());
559 pItem->SetProperty("Addon.Summary", addon->Summary());
560 pItem->SetProperty("Addon.Description", addon->Description());
561 pItem->SetProperty("Addon.Creator", addon->Author());
562 pItem->SetProperty("Addon.Disclaimer", addon->Disclaimer());
563 pItem->SetProperty("Addon.Rating", addon->Stars());
564 CStdString starrating = StringUtils::Format("rating%d.png", addon->Stars());
565 pItem->SetProperty("Addon.StarRating",starrating);
566 pItem->SetProperty("Addon.Path", addon->Path());
567 if (addon->Props().broken == "DEPSNOTMET")
568 pItem->SetProperty("Addon.Broken", g_localizeStrings.Get(24044));
570 pItem->SetProperty("Addon.Broken", addon->Props().broken);
571 std::map<CStdString,CStdString>::iterator it =
572 addon->Props().extrainfo.find("language");
573 if (it != addon->Props().extrainfo.end())
574 pItem->SetProperty("Addon.Language", it->second);
577 bool CAddonDatabase::DisableAddon(const CStdString &addonID, bool disable /* = true */)
581 if (NULL == m_pDB.get()) return false;
582 if (NULL == m_pDS.get()) return false;
586 if (!IsAddonDisabled(addonID)) // Enabled
588 CStdString sql = PrepareSQL("insert into disabled(id, addonID) values(NULL, '%s')", addonID.c_str());
592 // If the addon is a service, stop it
593 if (CAddonMgr::Get().GetAddon(addonID, addon, ADDON_SERVICE, false) && addon)
595 boost::shared_ptr<CService> service = boost::dynamic_pointer_cast<CService>(addon);
599 // restart the pvr manager when disabling a pvr add-on with the pvr manager enabled
600 else if (CAddonMgr::Get().GetAddon(addonID, addon, ADDON_PVRDLL, false) && addon &&
601 PVR::CPVRManager::Get().IsStarted())
602 PVR::CPVRManager::Get().Start(true);
606 return false; // already disabled or failed query
610 bool disabled = IsAddonDisabled(addonID); //we need to know if service addon is running
611 CStdString sql = PrepareSQL("delete from disabled where addonID='%s'", addonID.c_str());
615 // If the addon is a service, start it
616 if (CAddonMgr::Get().GetAddon(addonID, addon, ADDON_SERVICE, false) && addon && disabled)
618 boost::shared_ptr<CService> service = boost::dynamic_pointer_cast<CService>(addon);
622 // (re)start the pvr manager when enabling a pvr add-on
623 else if (CAddonMgr::Get().GetAddon(addonID, addon, ADDON_PVRDLL, false) && addon)
624 PVR::CPVRManager::Get().Start(true);
630 CLog::Log(LOGERROR, "%s failed on addon '%s'", __FUNCTION__, addonID.c_str());
635 bool CAddonDatabase::BreakAddon(const CStdString &addonID, const CStdString& reason)
638 return ExecuteQuery(PrepareSQL("DELETE FROM broken WHERE addonID='%s'", addonID.c_str()));
640 return ExecuteQuery(PrepareSQL("REPLACE INTO broken(addonID, reason) VALUES('%s', '%s')",
641 addonID.c_str(), reason.c_str()));
644 bool CAddonDatabase::HasAddon(const CStdString &addonID)
646 CStdString strWhereClause = PrepareSQL("addonID = '%s'", addonID.c_str());
647 CStdString strHasAddon = GetSingleValue("addon", "id", strWhereClause);
649 return !strHasAddon.empty();
652 bool CAddonDatabase::IsAddonDisabled(const CStdString &addonID)
656 if (NULL == m_pDB.get()) return false;
657 if (NULL == m_pDS.get()) return false;
659 CStdString sql = PrepareSQL("select id from disabled where addonID='%s'", addonID.c_str());
660 m_pDS->query(sql.c_str());
661 bool ret = !m_pDS->eof(); // in the disabled table -> disabled
667 CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, addonID.c_str());
672 bool CAddonDatabase::IsSystemPVRAddonEnabled(const CStdString &addonID)
674 CStdString strWhereClause = PrepareSQL("addonID = '%s'", addonID.c_str());
675 CStdString strEnabled = GetSingleValue("pvrenabled", "id", strWhereClause);
677 return !strEnabled.empty();
680 CStdString CAddonDatabase::IsAddonBroken(const CStdString &addonID)
682 return GetSingleValue(PrepareSQL("SELECT reason FROM broken WHERE addonID='%s'", addonID.c_str()));
685 bool CAddonDatabase::HasDisabledAddons()
689 if (NULL == m_pDB.get()) return false;
690 if (NULL == m_pDS.get()) return false;
692 m_pDS->query("select count(id) from disabled");
693 bool ret = !m_pDS->eof() && m_pDS->fv(0).get_asInt() > 0; // have rows -> have disabled addons
699 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
704 bool CAddonDatabase::BlacklistAddon(const CStdString& addonID,
705 const CStdString& version)
709 if (NULL == m_pDB.get()) return false;
710 if (NULL == m_pDS.get()) return false;
712 CStdString sql = PrepareSQL("insert into blacklist(id, addonID, version) values(NULL, '%s', '%s')", addonID.c_str(),version.c_str());
719 CLog::Log(LOGERROR, "%s failed on addon '%s' for version '%s'", __FUNCTION__, addonID.c_str(),version.c_str());
724 bool CAddonDatabase::IsAddonBlacklisted(const CStdString& addonID,
725 const CStdString& version)
727 CStdString where = PrepareSQL("addonID='%s' and version='%s'",addonID.c_str(),version.c_str());
728 return !GetSingleValue("blacklist","addonID",where).empty();
731 bool CAddonDatabase::RemoveAddonFromBlacklist(const CStdString& addonID,
732 const CStdString& version)
736 if (NULL == m_pDB.get()) return false;
737 if (NULL == m_pDS.get()) return false;
739 CStdString sql = PrepareSQL("delete from blacklist where addonID='%s' and version='%s'",addonID.c_str(),version.c_str());
745 CLog::Log(LOGERROR, "%s failed on addon '%s' for version '%s'", __FUNCTION__, addonID.c_str(),version.c_str());
750 bool CAddonDatabase::AddPackage(const CStdString& addonID,
751 const CStdString& packageFileName,
752 const CStdString& hash)
754 CStdString sql = PrepareSQL("insert into package(id, addonID, filename, hash)"
755 "values(NULL, '%s', '%s', '%s')",
756 addonID.c_str(), packageFileName.c_str(), hash.c_str());
757 return ExecuteQuery(sql);
760 bool CAddonDatabase::GetPackageHash(const CStdString& addonID,
761 const CStdString& packageFileName,
764 CStdString where = PrepareSQL("addonID='%s' and filename='%s'",
765 addonID.c_str(), packageFileName.c_str());
766 hash = GetSingleValue("package", "hash", where);
767 return !hash.empty();
770 bool CAddonDatabase::RemovePackage(const CStdString& packageFileName)
772 CStdString sql = PrepareSQL("delete from package where filename='%s'", packageFileName.c_str());
773 return ExecuteQuery(sql);