bool CAddonDatabase::FindByAddonId(const std::string& addonId, ADDON::VECADDONS& result) { try { if (NULL == m_pDB.get()) return false; if (NULL == m_pDS.get()) return false; std::string sql = PrepareSQL( "SELECT addons.version, addons.name, addons.summary, addons.description, addons.metadata, addons.news," "repo.addonID AS repoID FROM addons " "JOIN addonlinkrepo ON addonlinkrepo.idAddon=addons.id " "JOIN repo ON repo.id=addonlinkrepo.idRepo " "WHERE " "repo.checksum IS NOT NULL AND repo.checksum != '' " "AND EXISTS (SELECT * FROM installed WHERE installed.addonID=repoID AND installed.enabled=1) " "AND addons.addonID='%s'", addonId.c_str()); VECADDONS addons; m_pDS->query(sql.c_str()); while (!m_pDS->eof()) { CAddonBuilder builder; builder.SetId(addonId); builder.SetVersion(AddonVersion(m_pDS->fv(0).get_asString())); builder.SetName(m_pDS->fv(1).get_asString()); builder.SetSummary(m_pDS->fv(2).get_asString()); builder.SetDescription(m_pDS->fv(3).get_asString()); DeserializeMetadata(m_pDS->fv(4).get_asString(), builder); builder.SetChangelog(m_pDS->fv(5).get_asString()); builder.SetOrigin(m_pDS->fv(6).get_asString()); auto addon = builder.Build(); if (addon) addons.push_back(std::move(addon)); else CLog::Log(LOGERROR, "CAddonDatabase: failed to build %s", addonId.c_str()); m_pDS->next(); } m_pDS->close(); result = std::move(addons); return true; } catch (...) { CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, addonId.c_str()); } return false; }
bool CAddonDatabase::GetRepositoryContent(const std::string& repoId, VECADDONS& addons) { try { if (NULL == m_pDB.get()) return false; if (NULL == m_pDS.get()) return false; auto start = XbmcThreads::SystemClockMillis(); std::string commonConstraint = PrepareSQL( "JOIN addonlinkrepo ON addon.id=addonlinkrepo.idAddon " "JOIN repo ON addonlinkrepo.idRepo=repo.id " "WHERE repo.checksum IS NOT NULL AND repo.checksum != ''"); if (!repoId.empty()) commonConstraint += PrepareSQL(" AND repo.addonId='%s'", repoId.c_str()); commonConstraint += PrepareSQL(" ORDER BY addon.addonID"); std::vector<CAddonBuilder> result; // Read basic info from the `addon` table { std::string sql = PrepareSQL("SELECT addon.*, broken.reason FROM addon " "LEFT JOIN broken ON broken.addonID=addon.addonID ") + commonConstraint; auto start = XbmcThreads::SystemClockMillis(); m_pDS->query(sql); CLog::Log(LOGDEBUG, "CAddonDatabase: query %s returned %d rows in %d ms", sql.c_str(), m_pDS->num_rows(), XbmcThreads::SystemClockMillis() - start); while (!m_pDS->eof()) { std::string addonId = m_pDS->fv(addon_addonID).get_asString(); AddonVersion version(m_pDS->fv(addon_version).get_asString()); if (!result.empty() && result.back().GetId() == addonId && result.back().GetVersion() >= version) { // We already have a version of this addon in our list which is newer. m_pDS->next(); continue; } CAddonBuilder builder; builder.SetId(addonId); builder.SetVersion(version); builder.SetType(TranslateType(m_pDS->fv(addon_type).get_asString())); builder.SetMinVersion(AddonVersion(m_pDS->fv(addon_minversion).get_asString())); builder.SetName(m_pDS->fv(addon_name).get_asString()); builder.SetSummary(m_pDS->fv(addon_summary).get_asString()); builder.SetDescription(m_pDS->fv(addon_description).get_asString()); builder.SetChangelog(m_pDS->fv(addon_changelog).get_asString()); builder.SetDisclaimer(m_pDS->fv(addon_disclaimer).get_asString()); builder.SetAuthor(m_pDS->fv(addon_author).get_asString()); builder.SetPath(m_pDS->fv(addon_path).get_asString()); builder.SetIcon(m_pDS->fv(addon_icon).get_asString()); builder.SetFanart(m_pDS->fv(addon_fanart).get_asString()); builder.SetBroken(m_pDS->fv(broken_reason).get_asString()); if (!result.empty() && result.back().GetId() == addonId) result.back() = std::move(builder); else result.push_back(std::move(builder)); m_pDS->next(); } } // Read extra info. { std::string sql = PrepareSQL( "SELECT addon.addonID as owner, addonextra.key, addonextra.value " "FROM addon JOIN addonextra ON addon.id=addonextra.id ") + commonConstraint; auto start = XbmcThreads::SystemClockMillis(); m_pDS->query(sql); CLog::Log(LOGDEBUG, "CAddonDatabase: query %s returned %d rows in %d ms", sql.c_str(), m_pDS->num_rows(), XbmcThreads::SystemClockMillis() - start); for (auto& builder : result) { //move cursor to current or next addon while (!m_pDS->eof() && m_pDS->fv(0).get_asString() < builder.GetId()) m_pDS->next(); InfoMap extraInfo; while (!m_pDS->eof() && m_pDS->fv(0).get_asString() == builder.GetId()) { extraInfo.emplace(m_pDS->fv(1).get_asString(), m_pDS->fv(2).get_asString()); m_pDS->next(); } builder.SetExtrainfo(std::move(extraInfo)); } } // Read dependency info. { std::string sql = PrepareSQL( "SELECT addon.addonID as owner, dependencies.addon, dependencies.version, dependencies.optional " "FROM addon JOIN dependencies ON addon.id=dependencies.id ") + commonConstraint; auto start = XbmcThreads::SystemClockMillis(); m_pDS->query(sql); CLog::Log(LOGDEBUG, "CAddonDatabase: query %s returned %d rows in %d ms", sql.c_str(), m_pDS->num_rows(), XbmcThreads::SystemClockMillis() - start); for (auto& builder : result) { //move cursor to the current or next addon while (!m_pDS->eof() && m_pDS->fv(0).get_asString() < builder.GetId()) m_pDS->next(); ADDONDEPS dependencies; while (!m_pDS->eof() && m_pDS->fv(0).get_asString() == builder.GetId()) { dependencies.emplace(m_pDS->fv(1).get_asString(), std::make_pair(AddonVersion(m_pDS->fv(2).get_asString()), m_pDS->fv(3).get_asBool())); m_pDS->next(); } builder.SetDependencies(std::move(dependencies)); } } m_pDS->close(); for (auto& builder : result) { auto addon = builder.Build(); if (addon) addons.push_back(std::move(addon)); } CLog::Log(LOGDEBUG, "CAddonDatabase::GetAddons took %i ms", XbmcThreads::SystemClockMillis() - start); return true; } catch (...) { CLog::Log(LOGERROR, "%s failed", __FUNCTION__); } return false; }
bool CAddonDatabase::GetAddon(int id, AddonPtr &addon) { try { if (NULL == m_pDB.get()) return false; if (NULL == m_pDS2.get()) return false; std::string sql = "SELECT addon.*," " broken.reason," " addonextra.key, addonextra.value," " dependencies.addon, dependencies.version, dependencies.optional" " FROM addon" " LEFT JOIN broken" " ON broken.addonID = addon.addonID" " LEFT JOIN addonextra" " ON addonextra.id = addon.id" " LEFT JOIN dependencies" " ON dependencies.id = addon.id"; sql += PrepareSQL(" WHERE addon.id=%i", id); m_pDS2->query(sql); if (!m_pDS2->eof()) { const dbiplus::query_data &data = m_pDS2->get_result_set().records; const dbiplus::sql_record* const record = data[0]; CAddonBuilder builder; builder.SetId(record->at(addon_addonID).get_asString()); builder.SetType(TranslateType(record->at(addon_type).get_asString())); builder.SetVersion(AddonVersion(record->at(addon_version).get_asString())); builder.SetMinVersion(AddonVersion(record->at(addon_minversion).get_asString())); builder.SetName(record->at(addon_name).get_asString()); builder.SetSummary(record->at(addon_summary).get_asString()); builder.SetDescription(record->at(addon_description).get_asString()); builder.SetChangelog(record->at(addon_changelog).get_asString()); builder.SetDisclaimer(record->at(addon_disclaimer).get_asString()); builder.SetAuthor(record->at(addon_author).get_asString()); builder.SetBroken(record->at(broken_reason).get_asString()); builder.SetPath(record->at(addon_path).get_asString()); builder.SetIcon(record->at(addon_icon).get_asString()); builder.SetFanart(record->at(addon_fanart).get_asString()); InfoMap extrainfo; ADDONDEPS dependencies; /* while this is a cartesion join and we'll typically get multiple rows, we rely on the fact that extrainfo and dependencies are maps, so insert() will insert the first instance only */ for (dbiplus::query_data::const_iterator i = data.begin(); i != data.end(); ++i) { const dbiplus::sql_record* const record = *i; if (!record->at(addonextra_key).get_asString().empty()) extrainfo.insert(std::make_pair(record->at(addonextra_key).get_asString(), record->at(addonextra_value).get_asString())); if (!m_pDS2->fv(dependencies_addon).get_asString().empty()) dependencies.insert(std::make_pair(record->at(dependencies_addon).get_asString(), std::make_pair(AddonVersion(record->at(dependencies_version).get_asString()), record->at(dependencies_optional).get_asBool()))); } builder.SetExtrainfo(std::move(extrainfo)); builder.SetDependencies(std::move(dependencies)); addon = builder.Build(); return NULL != addon.get(); } } catch (...) { CLog::Log(LOGERROR, "%s failed on addon %i", __FUNCTION__, id); } addon.reset(); return false; }