Merge "Move section ID fallbacks into headers themselves"
[lhc/web/wiklou.git] / includes / libs / rdbms / database / DatabasePostgres.php
index 2fe275b..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' ) {
@@ -681,14 +704,13 @@ __INDEXATTR__;
         * @param string $fname
         * @param array $insertOptions
         * @param array $selectOptions
+        * @param array $selectJoinConds
         * @return bool
         */
        public function nativeInsertSelect(
                $destTable, $srcTable, $varMap, $conds, $fname = __METHOD__,
-               $insertOptions = [], $selectOptions = []
+               $insertOptions = [], $selectOptions = [], $selectJoinConds = []
        ) {
-               $destTable = $this->tableName( $destTable );
-
                if ( !is_array( $insertOptions ) ) {
                        $insertOptions = [ $insertOptions ];
                }
@@ -705,28 +727,9 @@ __INDEXATTR__;
                        $savepoint->savepoint();
                }
 
-               if ( !is_array( $selectOptions ) ) {
-                       $selectOptions = [ $selectOptions ];
-               }
-               list( $startOpts, $useIndex, $tailOpts, $ignoreIndex ) =
-                       $this->makeSelectOptions( $selectOptions );
-               if ( is_array( $srcTable ) ) {
-                       $srcTable = implode( ',', array_map( [ $this, 'tableName' ], $srcTable ) );
-               } else {
-                       $srcTable = $this->tableName( $srcTable );
-               }
-
-               $sql = "INSERT INTO $destTable (" . implode( ',', array_keys( $varMap ) ) . ')' .
-                       " SELECT $startOpts " . implode( ',', $varMap ) .
-                       " FROM $srcTable $useIndex $ignoreIndex ";
-
-               if ( $conds != '*' ) {
-                       $sql .= ' WHERE ' . $this->makeList( $conds, LIST_AND );
-               }
-
-               $sql .= " $tailOpts";
+               $res = parent::nativeInsertSelect( $destTable, $srcTable, $varMap, $conds, $fname,
+                       $insertOptions, $selectOptions, $selectJoinConds );
 
-               $res = (bool)$this->query( $sql, $fname, $savepoint );
                if ( $savepoint ) {
                        $bar = pg_result_error( $this->mLastResult );
                        if ( $bar != false ) {
@@ -1059,6 +1062,7 @@ __INDEXATTR__;
                if ( $schema === false ) {
                        $schema = $this->getCoreSchema();
                }
+               $table = $this->realTableName( $table, 'raw' );
                $etable = $this->addQuotes( $table );
                $eschema = $this->addQuotes( $schema );
                $sql = "SELECT 1 FROM pg_catalog.pg_class c, pg_catalog.pg_namespace n "
@@ -1386,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