Merge "Changed FOR UPDATE handling in Postgresql"
authorjenkins-bot <jenkins-bot@gerrit.wikimedia.org>
Mon, 13 Jan 2014 03:15:46 +0000 (03:15 +0000)
committerGerrit Code Review <gerrit@wikimedia.org>
Mon, 13 Jan 2014 03:15:46 +0000 (03:15 +0000)
1  2 
includes/db/DatabasePostgres.php

@@@ -815,10 -765,36 +815,33 @@@ __INDEXATTR__
                if ( !$res ) {
                        return null;
                }
 -              foreach ( $res as $row ) {
 -                      return true;
 -              }
  
 -              return false;
 +              return $res->numRows() > 0;
        }
  
+       /**
+        * Change the FOR UPDATE option as necessary based on the join conditions. Then pass
+        * to the parent function to get the actual SQL text.
+        *
+        * In Postgres when using FOR UPDATE, only the main table and tables that are inner joined
+        * can be locked. That means tables in an outer join cannot be FOR UPDATE locked. Trying to do
+        * so causes a DB error. This wrapper checks which tables can be locked and adjusts it accordingly.
+        */
+       function selectSQLText( $table, $vars, $conds = '', $fname = __METHOD__, $options = array(), $join_conds = array() ) {
+               $forUpdateKey = array_search( 'FOR UPDATE', $options );
+               if ( $forUpdateKey !== false && $join_conds ) {
+                       unset( $options[$forUpdateKey] );
+                       foreach ( $join_conds as $table => $join_cond ) {
+                               if ( 0 === preg_match( '/^(?:LEFT|RIGHT|FULL)(?: OUTER)? JOIN$/i', $join_cond[0] ) ) {
+                                       $options['FOR UPDATE'][] = $table;
+                               }
+                       }
+               }
+               return parent::selectSQLText( $table, $vars, $conds, $fname, $options, $join_conds );
+       }
        /**
         * INSERT wrapper, inserts an array into a table
         *