Page MenuHomePhabricator

Make upsert more upsert-able
Closed, DeclinedPublic

Description

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 );

Event Timeline

Greg_Sabino_Mullane raised the priority of this task from to Needs Triage.
Greg_Sabino_Mullane updated the task description. (Show Details)

Thanks for taking a look at the code!

You are very welcome to use developer access to submit this as a Git branch directly into Gerrit.

Putting your branch in Git makes it easier to review it. If you don't want to set up Git/Gerrit, you can also use the Gerrit Patch Uploader. Thanks again!

The second query happens unconditionally and that is intentional.

In what way did you observe the exception on the second query? It might be visible in debug logs, but should not be affecting end-users because it uses the IGNORE flag.

Krinkle changed the task status from Open to Stalled.Jul 23 2019, 4:27 PM

Unfortunately closing this Phabricator task as no further information has been provided.

@Greg_Sabino_Mullane: After you have provided the information asked for and if this still happens, please set the status of this task back to "Open" via the Add Action...Change Status dropdown. Thanks!