The upsert implmentation in Database.php is throwing exceptions when it doesn't need to be. For example, when adding a page to a category, the upsert does a "UPDATE category SET ... WHERE title = 'foo'" followed by an "INSERT INTO category (title) VALUES ('foo')", the latter of which fails because the row already exists. Hence, we should be checking affectedRows for the update and if a row was changed, skip the insert.
Cannot upload a file, so will have to inline the patch:
diff --git a/includes/db/Database.php b/includes/db/Database.php index 9df96f1..5c3ceac 100644 --- a/includes/db/Database.php +++ b/includes/db/Database.php @@ -2978,15 +2978,20 @@ abstract class DatabaseBase implements IDatabase { if ( $useTrx ) { $this->begin( $fname ); } + + $rows_updated = 0; try { # Update any existing conflicting row(s) if ( $where !== false ) { $ok = $this->update( $table, $set, $where, $fname ); + $rows_updated = $this->affectedRows(); } else { $ok = true; } - # Now insert any non-conflicting row(s) - $ok = $this->insert( $table, $rows, $fname, array( 'IGNORE' ) ) && $ok; + # Insert the row, but not if the update above changed something + if (! $rows_updated ) { + $ok = $this->insert( $table, $rows, $fname, array( 'IGNORE' ) ) && $ok; + } } catch ( Exception $e ) { if ( $useTrx ) { $this->rollback( $fname );