rdbms: allow callers to hint that native insertSelect() is safe
[lhc/web/wiklou.git] / includes / libs / rdbms / database / DatabaseMysqlBase.php
index 3085276..454e0c2 100644 (file)
@@ -512,7 +512,8 @@ abstract class DatabaseMysqlBase extends Database {
                $destTable, $srcTable, $varMap, $conds,
                $fname = __METHOD__, $insertOptions = [], $selectOptions = [], $selectJoinConds = []
        ) {
-               if ( $this->insertSelectIsSafe === null ) {
+               $isSafe = in_array( 'NO_AUTO_COLUMNS', $insertOptions, true );
+               if ( !$isSafe && $this->insertSelectIsSafe === null ) {
                        // In MySQL, an INSERT SELECT is only replication safe with row-based
                        // replication or if innodb_autoinc_lock_mode is 0. When those
                        // conditions aren't met, use non-native mode.
@@ -533,7 +534,7 @@ abstract class DatabaseMysqlBase extends Database {
                                (int)$row->innodb_autoinc_lock_mode === 0;
                }
 
-               if ( !$this->insertSelectIsSafe ) {
+               if ( !$isSafe && !$this->insertSelectIsSafe ) {
                        return $this->nonNativeInsertSelect(
                                $destTable,
                                $srcTable,
@@ -892,9 +893,15 @@ abstract class DatabaseMysqlBase extends Database {
                }
 
                // Call doQuery() directly, to avoid opening a transaction if DBO_TRX is set
-               if ( $pos->gtids ) {
+               if ( $pos->getGTIDs() ) {
+                       // Ignore GTIDs from domains exclusive to the master DB (presumably inactive)
+                       $rpos = $this->getReplicaPos();
+                       $gtidsWait = $rpos ? MySQLMasterPos::getCommonDomainGTIDs( $pos, $rpos ) : [];
+                       if ( !$gtidsWait ) {
+                               return -1; // $pos is from the wrong cluster?
+                       }
                        // Wait on the GTID set (MariaDB only)
-                       $gtidArg = $this->addQuotes( implode( ',', $pos->gtids ) );
+                       $gtidArg = $this->addQuotes( implode( ',', $gtidsWait ) );
                        $res = $this->doQuery( "SELECT MASTER_GTID_WAIT($gtidArg, $timeout)" );
                } else {
                        // Wait on the binlog coordinates
@@ -912,7 +919,7 @@ abstract class DatabaseMysqlBase extends Database {
                // Result can be NULL (error), -1 (timeout), or 0+ per the MySQL manual
                $status = ( $row[0] !== null ) ? intval( $row[0] ) : null;
                if ( $status === null ) {
-                       if ( !$pos->gtids ) {
+                       if ( !$pos->getGTIDs() ) {
                                // T126436: jobs programmed to wait on master positions might be referencing
                                // binlogs with an old master hostname; this makes MASTER_POS_WAIT() return null.
                                // Try to detect this case and treat the replica DB as having reached the given