Repository: xbmc/xbmc
File: xbmc/video/VideoDatabase.cpp (C++)

Code before:
                                         int idEpisode /* = -1 */)
{
  const auto filePath = details.GetPath();

  try
  {
    BeginTransaction();
    if (idEpisode < 0)
      idEpisode = GetEpisodeId(filePath);

    if (idEpisode > 0)
      DeleteEpisode(idEpisode, true); // true to keep the table entry
    else
    {
      // only add a new episode if we don't already have a valid idEpisode
      // (DeleteEpisode is called with bKeepId == true so the episode won't
      // be removed from the episode table)
      idEpisode = AddNewEpisode(idShow, details);
      if (idEpisode < 0)
      {
        RollbackTransaction();
        return -1;
      }
    }

    // update dateadded if it's set
    if (details.m_dateAdded.IsValid())
      UpdateFileDateAdded(details);

    AddCast(idEpisode, "episode", details.m_cast);
    AddActorLinksToItem(idEpisode, MediaTypeEpisode, "director", details.m_director);
    AddActorLinksToItem(idEpisode, MediaTypeEpisode, "writer", details.m_writingCredits);

    // add ratings
    details.m_iIdRating = AddRatings(idEpisode, MediaTypeEpisode, details.m_ratings, details.GetDefaultRating());

    // add unique ids
    details.m_iIdUniqueID = AddUniqueIDs(idEpisode, MediaTypeEpisode, details);

    if (details.HasStreamDetails())
      SetStreamDetailsForFileId(details.m_streamDetails, GetAndFillFileId(details));

    // ensure we have this season already added
    int idSeason = AddSeason(idShow, details.m_iSeason);

    SetArtForItem(idEpisode, MediaTypeEpisode, artwork);

    if (details.m_iEpisode != -1 && details.m_iSeason != -1)
    { // query DB for any episodes matching idShow, Season and Episode
      std::string strSQL = PrepareSQL("SELECT files.playCount, files.lastPlayed "
                                      "FROM episode INNER JOIN files ON files.idFile=episode.idFile "

Review comment (bug):
Sorry for noticing this late and after a fixup commit was just merged.
This line is wrong, it will update all versions/extra of the movie and break them. videoversion.idFile is the only link between a parent movie and its additional versions/extras.
This also breaks version artwork, which uses idFile as key in the art table.
What is the need to change the idFile?
While this function may do the correct thing for a standalone/parent movie, it won't work if you try to apply this to an additional version or an extra.

Code after:
  {
    BeginTransaction();
    std::string sql = PrepareSQL("UPDATE episode SET c18='%s', idFile=%i WHERE idEpisode=%i",
                                 fileAndPath.c_str(), idFile, idEpisode);
    m_pDS->exec(sql);
    CommitTransaction();

    return true;
  }
  catch (...)
  {
    CLog::Log(LOGERROR, "{} ({}) failed", __FUNCTION__, idEpisode);
  }
  RollbackTransaction();
  return false;
}

bool CVideoDatabase::SetFileForMovie(const std::string& fileAndPath, int idMovie, int idFile)
{
  try
  {
    BeginTransaction();
    std::string sql = PrepareSQL("UPDATE movie SET c22='%s', idFile=%i WHERE idMovie=%i",
                                 fileAndPath.c_str(), idFile, idMovie);
    m_pDS->exec(sql);
    sql = PrepareSQL("UPDATE videoversion SET idFile=%i WHERE idMedia=%i AND media_type='movie'",
                     idFile, idMovie);
    m_pDS->exec(sql);
    CommitTransaction();

    return true;
  }
  catch (...)
  {
    CLog::Log(LOGERROR, "{} ({}) failed", __FUNCTION__, idMovie);
  }
  RollbackTransaction();
  return false;
}

int CVideoDatabase::SetDetailsForEpisode(CVideoInfoTag& details,
                                         const std::map<std::string, std::string>& artwork,
                                         int idShow,
                                         int idEpisode /* = -1 */)
{
  const auto filePath = details.GetPath();

  try
  {
    BeginTransaction();
    if (idEpisode < 0)