From: Tyler Anthony Romeo Date: Thu, 20 Jun 2013 19:20:37 +0000 (+0000) Subject: Changed FOR UPDATE handling in Postgresql X-Git-Tag: 1.31.0-rc.0~17271^2 X-Git-Url: https://git.cyclocoop.org/%7B%24www_url%7Dadmin/compta/banques/ajouter.php?a=commitdiff_plain;h=63d32eeb6f23b68ed783d6f6b5c6b39067b6316b;p=lhc%2Fweb%2Fwiklou.git Changed FOR UPDATE handling in Postgresql Postgresql cannot handle FOR UPDATE with outer joins, but it allows specifying which tables can be locked. This changes DatabasePostgresql to render proper FOR UPDATE statements that only include the main table and any tables in inner joins. Bug: 47055 Change-Id: I1ac587ac39f448b9e7f4befb44826b43044ad6f0 --- diff --git a/includes/db/DatabasePostgres.php b/includes/db/DatabasePostgres.php index cfa2074b78..edc8b2720c 100644 --- a/includes/db/DatabasePostgres.php +++ b/includes/db/DatabasePostgres.php @@ -772,6 +772,29 @@ __INDEXATTR__; return false; } + /** + * 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 * @@ -1473,9 +1496,12 @@ SQL; // : false ); //} - if ( isset( $noKeyOptions['FOR UPDATE'] ) ) { + if ( isset( $options['FOR UPDATE'] ) ) { + $postLimitTail .= ' FOR UPDATE OF ' . implode( ', ', $options['FOR UPDATE'] ); + } else if ( isset( $noKeyOptions['FOR UPDATE'] ) ) { $postLimitTail .= ' FOR UPDATE'; } + if ( isset( $noKeyOptions['DISTINCT'] ) || isset( $noKeyOptions['DISTINCTROW'] ) ) { $startOpts .= 'DISTINCT'; }