The txindex was moved to its own database in #13033. As part of that change, data migration functionality was added, allowing the txindex to be maintained across upgrade without having to rebuild the entire index from scratch:

https://github.com/bitcoin/bitcoin/blob/5cf28d5203a6203355283ea59f071af6a468d239/src/index/txindex.cpp#L75-L90

13033 was included in v0.17, released in October 2018 and EOL in August 2020. Anyone who hasn't upgraded at this point is running unsupported code, and shouldn't have expectations around upgrading their node without having to rebuild the index. We should simplify the code by removing the `MigrateData()` functionality.
*
      * While this is more complicated than marking everything which descends
      * from an invalid block as invalid at the time we discover it to be
      * invalid, doing so would require walking all of m_block_index to find all
      * descendants. Since this case should be very rare, keeping track of all
      * BLOCK_FAILED_VALID blocks in a set should be just fine and work just as
      * well.
      *
      * Because we already walk m_block_index in height-order at startup, we go
      * ahead and mark descendants of invalid blocks as FAILED_CHILD at that time,
      * instead of putting things in this set.
      */
    std::set<CBlockIndex*> m_failed_blocks;
    /**
     * All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions.
     * Pruned nodes may have entries where B is missing data.
     */
    std::multimap<CBlockIndex*, CBlockIndex*> m_blocks_unlinked;
    std::unique_ptr<CBlockTreeDB> m_block_tree_db GUARDED_BY(::cs_main);
    bool LoadBlockIndexDB(std::set<CBlockIndex*, CBlockIndexWorkComparator>& setBlockIndexCandidates) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
    /**
     * Load the blocktree off disk and into memory. Populate certain metadata
     * per index entry (nStatus, nChainWork, nTimeMax, etc.) as well as peripheral
     * collections like setDirtyBlockIndex.
     *
     * @param[out] block_index_candidates  Fill this set with any valid blocks for
     *                                     which we've downloaded all transactions.
     */
    bool LoadBlockIndex(
        const Consensus::Params& consensus_params,