Fix various PostgreSQL failures
[lhc/web/wiklou.git] / includes / libs / rdbms / database / DatabasePostgres.php
index 57acd01..fcfd937 100644 (file)
@@ -256,7 +256,10 @@ class DatabasePostgres extends Database {
                }
                /* Transaction stays in the ERROR state until rolled back */
                if ( $this->mTrxLevel ) {
-                       $this->rollback( __METHOD__ );
+                       // Throw away the transaction state, then raise the error as normal.
+                       // Note that if this connection is managed by LBFactory, it's already expected
+                       // that the other transactions LBFactory manages will be rolled back.
+                       $this->rollback( __METHOD__, self::FLUSHING_INTERNAL );
                }
                parent::reportQueryError( $error, $errno, $sql, $fname, false );
        }
@@ -518,6 +521,10 @@ __INDEXATTR__;
        public function selectSQLText(
                $table, $vars, $conds = '', $fname = __METHOD__, $options = [], $join_conds = []
        ) {
+               if ( is_string( $options ) ) {
+                       $options = [ $options ];
+               }
+
                // 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
@@ -529,12 +536,28 @@ __INDEXATTR__;
                        $forUpdateKey = array_search( 'FOR UPDATE', $options, true );
                        if ( $forUpdateKey !== false && $join_conds ) {
                                unset( $options[$forUpdateKey] );
+                               $options['FOR UPDATE'] = [];
+
+                               // All tables not in $join_conds are good
+                               foreach ( $table as $alias => $name ) {
+                                       if ( is_numeric( $alias ) ) {
+                                               $alias = $name;
+                                       }
+                                       if ( !isset( $join_conds[$alias] ) ) {
+                                               $options['FOR UPDATE'][] = $alias;
+                                       }
+                               }
 
                                foreach ( $join_conds as $table_cond => $join_cond ) {
                                        if ( 0 === preg_match( '/^(?:LEFT|RIGHT|FULL)(?: OUTER)? JOIN$/i', $join_cond[0] ) ) {
                                                $options['FOR UPDATE'][] = $table_cond;
                                        }
                                }
+
+                               // Quote alias names so $this->tableName() won't mangle them
+                               $options['FOR UPDATE'] = array_map( function ( $name ) use ( $table ) {
+                                       return isset( $table[$name] ) ? $this->addIdentifierQuotes( $name ) : $name;
+                               }, $options['FOR UPDATE'] );
                        }
 
                        if ( isset( $options['ORDER BY'] ) && $options['ORDER BY'] == 'NULL' ) {
@@ -1367,6 +1390,13 @@ SQL;
                return false;
        }
 
+       public function serverIsReadOnly() {
+               $res = $this->query( "SHOW default_transaction_read_only", __METHOD__ );
+               $row = $this->fetchObject( $res );
+
+               return $row ? ( strtolower( $row->default_transaction_read_only ) === 'on' ) : false;
+       }
+
        /**
         * @param string $lockName
         * @return string Integer