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 void CAddonDatabase::CreateTables()
49 CLog::Log(LOGINFO, "create addon table");
50 m_pDS->exec("CREATE TABLE addon (id integer primary key, type text,"
51 "name text, summary text, description text, stars integer,"
52 "path text, addonID text, icon text, version text, "
53 "changelog text, fanart text, author text, disclaimer text,"
54 "minversion text)\n");
56 CLog::Log(LOGINFO, "create addonextra table");
57 m_pDS->exec("CREATE TABLE addonextra (id integer, key text, value text)\n");
59 CLog::Log(LOGINFO, "create dependencies table");
60 m_pDS->exec("CREATE TABLE dependencies (id integer, addon text, version text, optional boolean)\n");
62 CLog::Log(LOGINFO, "create repo table");
63 m_pDS->exec("CREATE TABLE repo (id integer primary key, addonID text,"
64 "checksum text, lastcheck text)\n");
66 CLog::Log(LOGINFO, "create addonlinkrepo table");
67 m_pDS->exec("CREATE TABLE addonlinkrepo (idRepo integer, idAddon integer)\n");
69 CLog::Log(LOGINFO, "create disabled table");
70 m_pDS->exec("CREATE TABLE disabled (id integer primary key, addonID text)\n");
72 CLog::Log(LOGINFO, "create broken table");
73 m_pDS->exec("CREATE TABLE broken (id integer primary key, addonID text, reason text)\n");
75 CLog::Log(LOGINFO, "create blacklist table");
76 m_pDS->exec("CREATE TABLE blacklist (id integer primary key, addonID text, version text)\n");
78 CLog::Log(LOGINFO, "create package table");
79 m_pDS->exec("CREATE TABLE package (id integer primary key, addonID text, filename text, hash text)\n");
82 void CAddonDatabase::CreateAnalytics()
84 CLog::Log(LOGINFO, "%s creating indicies", __FUNCTION__);
85 m_pDS->exec("CREATE INDEX idxAddon ON addon(addonID)");
86 m_pDS->exec("CREATE INDEX idxAddonExtra ON addonextra(id)");
87 m_pDS->exec("CREATE INDEX idxDependencies ON dependencies(id)");
88 m_pDS->exec("CREATE UNIQUE INDEX ix_addonlinkrepo_1 ON addonlinkrepo ( idAddon, idRepo )\n");
89 m_pDS->exec("CREATE UNIQUE INDEX ix_addonlinkrepo_2 ON addonlinkrepo ( idRepo, idAddon )\n");
90 m_pDS->exec("CREATE UNIQUE INDEX idxDisabled ON disabled(addonID)");
91 m_pDS->exec("CREATE UNIQUE INDEX idxBroken ON broken(addonID)");
92 m_pDS->exec("CREATE UNIQUE INDEX idxBlack ON blacklist(addonID)");
93 m_pDS->exec("CREATE UNIQUE INDEX idxPackage ON package(filename)");
96 void CAddonDatabase::UpdateTables(int version)
100 m_pDS->exec("CREATE TABLE package (id integer primary key, addonID text, filename text, hash text)\n");
104 int CAddonDatabase::AddAddon(const AddonPtr& addon,
109 if (NULL == m_pDB.get()) return -1;
110 if (NULL == m_pDS.get()) return -1;
112 bool bDisablePVRAddon = addon->Type() == ADDON_PVRDLL && !HasAddon(addon->ID());
114 CStdString sql = PrepareSQL("insert into addon (id, type, name, summary,"
115 "description, stars, path, icon, changelog, "
116 "fanart, addonID, version, author, disclaimer, minversion)"
117 " values(NULL, '%s', '%s', '%s', '%s', %i,"
118 "'%s', '%s', '%s', '%s', '%s','%s','%s','%s','%s')",
119 TranslateType(addon->Type(),false).c_str(),
120 addon->Name().c_str(), addon->Summary().c_str(),
121 addon->Description().c_str(),addon->Stars(),
122 addon->Path().c_str(), addon->Props().icon.c_str(),
123 addon->ChangeLog().c_str(),addon->FanArt().c_str(),
124 addon->ID().c_str(), addon->Version().c_str(),
125 addon->Author().c_str(),addon->Disclaimer().c_str(),
126 addon->MinVersion().c_str());
127 m_pDS->exec(sql.c_str());
128 int idAddon = (int)m_pDS->lastinsertid();
130 sql = PrepareSQL("insert into addonlinkrepo (idRepo, idAddon) values (%i,%i)",idRepo,idAddon);
131 m_pDS->exec(sql.c_str());
133 const InfoMap &info = addon->ExtraInfo();
134 for (InfoMap::const_iterator i = info.begin(); i != info.end(); ++i)
136 sql = PrepareSQL("insert into addonextra(id, key, value) values (%i, '%s', '%s')", idAddon, i->first.c_str(), i->second.c_str());
137 m_pDS->exec(sql.c_str());
139 const ADDONDEPS &deps = addon->GetDeps();
140 for (ADDONDEPS::const_iterator i = deps.begin(); i != deps.end(); ++i)
142 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);
143 m_pDS->exec(sql.c_str());
145 // these need to be configured
146 if (bDisablePVRAddon)
147 DisableAddon(addon->ID(), true);
152 CLog::Log(LOGERROR, "%s failed on addon '%s'", __FUNCTION__, addon->Name().c_str());
157 AddonVersion CAddonDatabase::GetAddonVersion(const std::string &id)
159 AddonVersion maxversion("0.0.0");
162 if (NULL == m_pDB.get()) return maxversion;
163 if (NULL == m_pDS2.get()) return maxversion;
165 // there may be multiple addons with this id (eg from different repositories) in the database,
166 // so we want to retrieve the latest version. Order by version won't work as the database
167 // won't know that 1.10 > 1.2, so grab them all and order outside
168 CStdString sql = PrepareSQL("select version from addon where addonID='%s'",id.c_str());
169 m_pDS2->query(sql.c_str());
174 while (!m_pDS2->eof())
176 AddonVersion version(m_pDS2->fv(0).get_asString());
177 if (version > maxversion)
178 maxversion = version;
185 CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, id.c_str());
190 bool CAddonDatabase::GetAddon(const CStdString& id, AddonPtr& addon)
194 if (NULL == m_pDB.get()) return false;
195 if (NULL == m_pDS2.get()) return false;
197 // there may be multiple addons with this id (eg from different repositories) in the database,
198 // so we want to retrieve the latest version. Order by version won't work as the database
199 // won't know that 1.10 > 1.2, so grab them all and order outside
200 CStdString sql = PrepareSQL("select id,version from addon where addonID='%s'",id.c_str());
201 m_pDS2->query(sql.c_str());
206 AddonVersion maxversion("0.0.0");
208 while (!m_pDS2->eof())
210 AddonVersion version(m_pDS2->fv(1).get_asString());
211 if (version > maxversion)
213 maxid = m_pDS2->fv(0).get_asInt();
214 maxversion = version;
218 return GetAddon(maxid,addon);
222 CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, id.c_str());
228 bool CAddonDatabase::GetRepoForAddon(const CStdString& addonID, CStdString& repo)
232 if (NULL == m_pDB.get()) return false;
233 if (NULL == m_pDS2.get()) return false;
235 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());
236 m_pDS2->query(sql.c_str());
239 repo = m_pDS2->fv(0).get_asString();
246 CLog::Log(LOGERROR, "%s failed for addon %s", __FUNCTION__, addonID.c_str());
251 bool CAddonDatabase::GetAddon(int id, AddonPtr &addon)
255 if (NULL == m_pDB.get()) return false;
256 if (NULL == m_pDS2.get()) return false;
258 std::string sql = "SELECT addon.*,"
260 " addonextra.key, addonextra.value,"
261 " dependencies.addon, dependencies.version, dependencies.optional"
264 " ON broken.addonID = addon.addonID"
265 " LEFT JOIN addonextra"
266 " ON addonextra.id = addon.id"
267 " LEFT JOIN dependencies"
268 " ON dependencies.id = addon.id";
270 sql += PrepareSQL(" WHERE addon.id=%i", id);
272 m_pDS2->query(sql.c_str());
275 const dbiplus::query_data &data = m_pDS2->get_result_set().records;
276 const dbiplus::sql_record* const record = data[0];
277 AddonProps props(record->at(addon_addonID).get_asString(),
278 TranslateType(record->at(addon_type).get_asString()),
279 record->at(addon_version).get_asString(),
280 record->at(addon_minversion).get_asString());
281 props.name = record->at(addon_name).get_asString();
282 props.summary = record->at(addon_summary).get_asString();
283 props.description = record->at(addon_description).get_asString();
284 props.changelog = record->at(addon_changelog).get_asString();
285 props.path = record->at(addon_path).get_asString();
286 props.icon = record->at(addon_icon).get_asString();
287 props.fanart = record->at(addon_fanart).get_asString();
288 props.author = record->at(addon_author).get_asString();
289 props.disclaimer = record->at(addon_disclaimer).get_asString();
290 props.broken = record->at(broken_reason).get_asString();
292 /* while this is a cartesion join and we'll typically get multiple rows, we rely on the fact that
293 extrainfo and dependencies are maps, so insert() will insert the first instance only */
294 for (dbiplus::query_data::const_iterator i = data.begin(); i != data.end(); ++i)
296 const dbiplus::sql_record* const record = *i;
297 if (!record->at(addonextra_key).get_asString().empty())
298 props.extrainfo.insert(make_pair(record->at(addonextra_key).get_asString(), record->at(addonextra_value).get_asString()));
299 if (!m_pDS2->fv(dependencies_addon).get_asString().empty())
300 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())));
303 addon = CAddonMgr::AddonFromProps(props);
304 return NULL != addon.get();
309 CLog::Log(LOGERROR, "%s failed on addon %i", __FUNCTION__, id);
315 bool CAddonDatabase::GetAddons(VECADDONS& addons)
319 if (NULL == m_pDB.get()) return false;
320 if (NULL == m_pDS2.get()) return false;
322 CStdString sql = PrepareSQL("select distinct addonID from addon");
323 m_pDS->query(sql.c_str());
324 while (!m_pDS->eof())
327 if (GetAddon(m_pDS->fv(0).get_asString(),addon))
328 addons.push_back(addon);
336 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
341 void CAddonDatabase::DeleteRepository(const CStdString& id)
345 if (NULL == m_pDB.get()) return;
346 if (NULL == m_pDS.get()) return;
348 CStdString sql = PrepareSQL("select id from repo where addonID='%s'",id.c_str());
349 m_pDS->query(sql.c_str());
351 DeleteRepository(m_pDS->fv(0).get_asInt());
355 CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
359 void CAddonDatabase::DeleteRepository(int idRepo)
363 if (NULL == m_pDB.get()) return;
364 if (NULL == m_pDS.get()) return;
366 CStdString sql = PrepareSQL("delete from repo where id=%i",idRepo);
367 m_pDS->exec(sql.c_str());
368 sql = PrepareSQL("delete from addon where id in (select idAddon from addonlinkrepo where idRepo=%i)",idRepo);
369 m_pDS->exec(sql.c_str());
370 sql = PrepareSQL("delete from addonextra where id in (select idAddon from addonlinkrepo where idRepo=%i)",idRepo);
371 m_pDS->exec(sql.c_str());
372 sql = PrepareSQL("delete from dependencies where id in (select idAddon from addonlinkrepo where idRepo=%i)",idRepo);
373 m_pDS->exec(sql.c_str());
374 sql = PrepareSQL("delete from addonlinkrepo where idRepo=%i",idRepo);
375 m_pDS->exec(sql.c_str());
380 CLog::Log(LOGERROR, "%s failed on repo %i", __FUNCTION__, idRepo);
384 int CAddonDatabase::AddRepository(const CStdString& id, const VECADDONS& addons, const CStdString& checksum)
388 if (NULL == m_pDB.get()) return -1;
389 if (NULL == m_pDS.get()) return -1;
392 int idRepo = GetRepoChecksum(id,sql);
394 DeleteRepository(idRepo);
398 CDateTime time = CDateTime::GetCurrentDateTime();
399 sql = PrepareSQL("insert into repo (id,addonID,checksum,lastcheck) values (NULL,'%s','%s','%s')",id.c_str(),checksum.c_str(),time.GetAsDBDateTime().c_str());
400 m_pDS->exec(sql.c_str());
401 idRepo = (int)m_pDS->lastinsertid();
402 for (unsigned int i=0;i<addons.size();++i)
403 AddAddon(addons[i],idRepo);
410 CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
411 RollbackTransaction();
416 int CAddonDatabase::GetRepoChecksum(const std::string& id, std::string& checksum)
420 if (NULL == m_pDB.get()) return -1;
421 if (NULL == m_pDS.get()) return -1;
423 std::string strSQL = PrepareSQL("select * from repo where addonID='%s'",id.c_str());
424 m_pDS->query(strSQL.c_str());
427 checksum = m_pDS->fv("checksum").get_asString();
428 return m_pDS->fv("id").get_asInt();
433 CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
439 CDateTime CAddonDatabase::GetRepoTimestamp(const CStdString& id)
444 if (NULL == m_pDB.get()) return date;
445 if (NULL == m_pDS.get()) return date;
447 CStdString strSQL = PrepareSQL("select * from repo where addonID='%s'",id.c_str());
448 m_pDS->query(strSQL.c_str());
451 date.SetFromDBDateTime(m_pDS->fv("lastcheck").get_asString());
457 CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
462 bool CAddonDatabase::SetRepoTimestamp(const CStdString& id, const CStdString& time)
466 if (NULL == m_pDB.get()) return false;
467 if (NULL == m_pDS.get()) return false;
469 CStdString sql = PrepareSQL("update repo set lastcheck='%s' where addonID='%s'",time.c_str(),id.c_str());
470 m_pDS->exec(sql.c_str());
476 CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
481 bool CAddonDatabase::GetRepository(int id, VECADDONS& addons)
485 if (NULL == m_pDB.get()) return false;
486 if (NULL == m_pDS.get()) return false;
488 CStdString strSQL = PrepareSQL("select * from addonlinkrepo where idRepo=%i",id);
489 m_pDS->query(strSQL.c_str());
490 while (!m_pDS->eof())
493 if (GetAddon(m_pDS->fv("idAddon").get_asInt(),addon))
494 addons.push_back(addon);
501 CLog::Log(LOGERROR, "%s failed on repo %i", __FUNCTION__, id);
506 bool CAddonDatabase::GetRepository(const CStdString& id, VECADDONS& addons)
510 if (NULL == m_pDB.get()) return false;
511 if (NULL == m_pDS.get()) return false;
513 CStdString strSQL = PrepareSQL("select id from repo where addonID='%s'",id.c_str());
514 m_pDS->query(strSQL.c_str());
516 return GetRepository(m_pDS->fv(0).get_asInt(),addons);
520 CLog::Log(LOGERROR, "%s failed on repo %s", __FUNCTION__, id.c_str());
525 bool CAddonDatabase::Search(const CStdString& search, VECADDONS& addons)
529 if (NULL == m_pDB.get()) return false;
530 if (NULL == m_pDS.get()) return false;
533 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());
534 CLog::Log(LOGDEBUG, "%s query: %s", __FUNCTION__, strSQL.c_str());
536 if (!m_pDS->query(strSQL.c_str())) return false;
537 if (m_pDS->num_rows() == 0) return false;
539 while (!m_pDS->eof())
542 GetAddon(m_pDS->fv(0).get_asString(),addon);
543 if (addon->Type() >= ADDON_UNKNOWN+1 && addon->Type() < ADDON_SCRAPER_LIBRARY)
544 addons.push_back(addon);
552 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
557 void CAddonDatabase::SetPropertiesFromAddon(const AddonPtr& addon,
560 pItem->SetProperty("Addon.ID", addon->ID());
561 pItem->SetProperty("Addon.Type", TranslateType(addon->Type(),true));
562 pItem->SetProperty("Addon.intType", TranslateType(addon->Type()));
563 pItem->SetProperty("Addon.Name", addon->Name());
564 pItem->SetProperty("Addon.Version", addon->Version().c_str());
565 pItem->SetProperty("Addon.Summary", addon->Summary());
566 pItem->SetProperty("Addon.Description", addon->Description());
567 pItem->SetProperty("Addon.Creator", addon->Author());
568 pItem->SetProperty("Addon.Disclaimer", addon->Disclaimer());
569 pItem->SetProperty("Addon.Rating", addon->Stars());
570 CStdString starrating = StringUtils::Format("rating%d.png", addon->Stars());
571 pItem->SetProperty("Addon.StarRating",starrating);
572 pItem->SetProperty("Addon.Path", addon->Path());
573 if (addon->Props().broken == "DEPSNOTMET")
574 pItem->SetProperty("Addon.Broken", g_localizeStrings.Get(24044));
576 pItem->SetProperty("Addon.Broken", addon->Props().broken);
577 std::map<CStdString,CStdString>::iterator it =
578 addon->Props().extrainfo.find("language");
579 if (it != addon->Props().extrainfo.end())
580 pItem->SetProperty("Addon.Language", it->second);
583 bool CAddonDatabase::DisableAddon(const CStdString &addonID, bool disable /* = true */)
587 if (NULL == m_pDB.get()) return false;
588 if (NULL == m_pDS.get()) return false;
592 if (!IsAddonDisabled(addonID)) // Enabled
594 CStdString sql = PrepareSQL("insert into disabled(id, addonID) values(NULL, '%s')", addonID.c_str());
598 // If the addon is a service, stop it
599 if (CAddonMgr::Get().GetAddon(addonID, addon, ADDON_SERVICE, false) && addon)
601 boost::shared_ptr<CService> service = boost::dynamic_pointer_cast<CService>(addon);
605 // restart the pvr manager when disabling a pvr add-on with the pvr manager enabled
606 else if (CAddonMgr::Get().GetAddon(addonID, addon, ADDON_PVRDLL, false) && addon &&
607 PVR::CPVRManager::Get().IsStarted())
608 PVR::CPVRManager::Get().Start(true);
612 return false; // already disabled or failed query
616 bool disabled = IsAddonDisabled(addonID); //we need to know if service addon is running
617 CStdString sql = PrepareSQL("delete from disabled where addonID='%s'", addonID.c_str());
621 // If the addon is a service, start it
622 if (CAddonMgr::Get().GetAddon(addonID, addon, ADDON_SERVICE, false) && addon && disabled)
624 boost::shared_ptr<CService> service = boost::dynamic_pointer_cast<CService>(addon);
628 // (re)start the pvr manager when enabling a pvr add-on
629 else if (CAddonMgr::Get().GetAddon(addonID, addon, ADDON_PVRDLL, false) && addon)
630 PVR::CPVRManager::Get().Start(true);
636 CLog::Log(LOGERROR, "%s failed on addon '%s'", __FUNCTION__, addonID.c_str());
641 bool CAddonDatabase::BreakAddon(const CStdString &addonID, const CStdString& reason)
644 return ExecuteQuery(PrepareSQL("DELETE FROM broken WHERE addonID='%s'", addonID.c_str()));
646 return ExecuteQuery(PrepareSQL("REPLACE INTO broken(addonID, reason) VALUES('%s', '%s')",
647 addonID.c_str(), reason.c_str()));
650 bool CAddonDatabase::HasAddon(const CStdString &addonID)
652 CStdString strWhereClause = PrepareSQL("addonID = '%s'", addonID.c_str());
653 CStdString strHasAddon = GetSingleValue("addon", "id", strWhereClause);
655 return !strHasAddon.empty();
658 bool CAddonDatabase::IsAddonDisabled(const CStdString &addonID)
662 if (NULL == m_pDB.get()) return false;
663 if (NULL == m_pDS.get()) return false;
665 CStdString sql = PrepareSQL("select id from disabled where addonID='%s'", addonID.c_str());
666 m_pDS->query(sql.c_str());
667 bool ret = !m_pDS->eof(); // in the disabled table -> disabled
673 CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, addonID.c_str());
678 bool CAddonDatabase::IsSystemPVRAddonEnabled(const CStdString &addonID)
680 CStdString strWhereClause = PrepareSQL("addonID = '%s'", addonID.c_str());
681 CStdString strEnabled = GetSingleValue("pvrenabled", "id", strWhereClause);
683 return !strEnabled.empty();
686 CStdString CAddonDatabase::IsAddonBroken(const CStdString &addonID)
688 return GetSingleValue(PrepareSQL("SELECT reason FROM broken WHERE addonID='%s'", addonID.c_str()));
691 bool CAddonDatabase::HasDisabledAddons()
695 if (NULL == m_pDB.get()) return false;
696 if (NULL == m_pDS.get()) return false;
698 m_pDS->query("select count(id) from disabled");
699 bool ret = !m_pDS->eof() && m_pDS->fv(0).get_asInt() > 0; // have rows -> have disabled addons
705 CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
710 bool CAddonDatabase::BlacklistAddon(const CStdString& addonID,
711 const CStdString& version)
715 if (NULL == m_pDB.get()) return false;
716 if (NULL == m_pDS.get()) return false;
718 CStdString sql = PrepareSQL("insert into blacklist(id, addonID, version) values(NULL, '%s', '%s')", addonID.c_str(),version.c_str());
725 CLog::Log(LOGERROR, "%s failed on addon '%s' for version '%s'", __FUNCTION__, addonID.c_str(),version.c_str());
730 bool CAddonDatabase::IsAddonBlacklisted(const CStdString& addonID,
731 const CStdString& version)
733 CStdString where = PrepareSQL("addonID='%s' and version='%s'",addonID.c_str(),version.c_str());
734 return !GetSingleValue("blacklist","addonID",where).empty();
737 bool CAddonDatabase::RemoveAddonFromBlacklist(const CStdString& addonID,
738 const CStdString& version)
742 if (NULL == m_pDB.get()) return false;
743 if (NULL == m_pDS.get()) return false;
745 CStdString sql = PrepareSQL("delete from blacklist where addonID='%s' and version='%s'",addonID.c_str(),version.c_str());
751 CLog::Log(LOGERROR, "%s failed on addon '%s' for version '%s'", __FUNCTION__, addonID.c_str(),version.c_str());
756 bool CAddonDatabase::AddPackage(const CStdString& addonID,
757 const CStdString& packageFileName,
758 const CStdString& hash)
760 CStdString sql = PrepareSQL("insert into package(id, addonID, filename, hash)"
761 "values(NULL, '%s', '%s', '%s')",
762 addonID.c_str(), packageFileName.c_str(), hash.c_str());
763 return ExecuteQuery(sql);
766 bool CAddonDatabase::GetPackageHash(const CStdString& addonID,
767 const CStdString& packageFileName,
770 CStdString where = PrepareSQL("addonID='%s' and filename='%s'",
771 addonID.c_str(), packageFileName.c_str());
772 hash = GetSingleValue("package", "hash", where);
773 return !hash.empty();
776 bool CAddonDatabase::RemovePackage(const CStdString& packageFileName)
778 CStdString sql = PrepareSQL("delete from package where filename='%s'", packageFileName.c_str());
779 return ExecuteQuery(sql);