Merge "Postgres installation fixes"
[lhc/web/wiklou.git] / includes / libs / rdbms / database / Database.php
index fc55671..d22ecd0 100644 (file)
@@ -25,6 +25,7 @@
  */
 use Psr\Log\LoggerAwareInterface;
 use Psr\Log\LoggerInterface;
+use Wikimedia\ScopedCallback;
 
 /**
  * Relational database abstraction object
@@ -50,8 +51,8 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
 
        /** @var string SQL query */
        protected $mLastQuery = '';
-       /** @var bool */
-       protected $mDoneWrites = false;
+       /** @var float|bool UNIX timestamp of last write query */
+       protected $mLastWriteTime = false;
        /** @var string|bool */
        protected $mPHPError = false;
        /** @var string */
@@ -78,7 +79,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        /** @var callback Error logging callback */
        protected $errorLogger;
 
-       /** @var resource Database connection */
+       /** @var resource|null Database connection */
        protected $mConn = null;
        /** @var bool */
        protected $mOpened = false;
@@ -382,7 +383,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        }
                        if ( !isset( $p['errorLogger'] ) ) {
                                $p['errorLogger'] = function ( Exception $e ) {
-                                       trigger_error( get_class( $e ) . ': ' . $e->getMessage(), E_WARNING );
+                                       trigger_error( get_class( $e ) . ': ' . $e->getMessage(), E_USER_WARNING );
                                };
                        }
 
@@ -511,11 +512,11 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        }
 
        public function doneWrites() {
-               return (bool)$this->mDoneWrites;
+               return (bool)$this->mLastWriteTime;
        }
 
        public function lastDoneWrites() {
-               return $this->mDoneWrites ?: false;
+               return $this->mLastWriteTime ?: false;
        }
 
        public function writesPending() {
@@ -608,6 +609,11 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                return !!( $this->mFlags & $flag );
        }
 
+       /**
+        * @param string $name Class field name
+        * @return mixed
+        * @deprecated Since 1.28
+        */
        public function getProperty( $name ) {
                return $this->$name;
        }
@@ -773,8 +779,11 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
         * @return bool
         */
        protected function isTransactableQuery( $sql ) {
-               $verb = $this->getQueryVerb( $sql );
-               return !in_array( $verb, [ 'BEGIN', 'COMMIT', 'ROLLBACK', 'SHOW', 'SET' ], true );
+               return !in_array(
+                       $this->getQueryVerb( $sql ),
+                       [ 'BEGIN', 'COMMIT', 'ROLLBACK', 'SHOW', 'SET', 'CREATE', 'ALTER' ],
+                       true
+               );
        }
 
        /**
@@ -820,7 +829,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                                throw new DBReadOnlyError( $this, "Database is read-only: $reason" );
                        }
                        # Set a flag indicating that writes have been done
-                       $this->mDoneWrites = microtime( true );
+                       $this->mLastWriteTime = microtime( true );
                }
 
                // Add trace comment to the begin of the sql string, right after the operator.
@@ -2751,7 +2760,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                $writeTime = $this->pendingWriteQueryDuration( self::ESTIMATE_DB_APPLY );
                $this->doCommit( $fname );
                if ( $this->mTrxDoneWrites ) {
-                       $this->mDoneWrites = microtime( true );
+                       $this->mLastWriteTime = microtime( true );
                        $this->trxProfiler->transactionWritingOut(
                                $this->mServer, $this->mDBname, $this->mTrxShortId, $writeTime );
                }
@@ -2828,7 +2837,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        $fnames = implode( ', ', $this->pendingWriteAndCallbackCallers() );
                        throw new DBUnexpectedError(
                                $this,
-                               "$fname: Cannot COMMIT to clear snapshot because writes are pending ($fnames)."
+                               "$fname: Cannot flush snapshot because writes are pending ($fnames)."
                        );
                }
 
@@ -3249,7 +3258,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        $fnames = implode( ', ', $this->pendingWriteAndCallbackCallers() );
                        throw new DBUnexpectedError(
                                $this,
-                               "$fname: Cannot COMMIT to clear snapshot because writes are pending ($fnames)."
+                               "$fname: Cannot flush pre-lock snapshot because writes are pending ($fnames)."
                        );
                }
 
@@ -3368,6 +3377,28 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                return true;
        }
 
+       /**
+        * Get the underlying binding handle, mConn
+        *
+        * Makes sure that mConn is set (disconnects and ping() failure can unset it).
+        * This catches broken callers than catch and ignore disconnection exceptions.
+        * Unlike checking isOpen(), this is safe to call inside of open().
+        *
+        * @return resource|object
+        * @throws DBUnexpectedError
+        * @since 1.26
+        */
+       protected function getBindingHandle() {
+               if ( !$this->mConn ) {
+                       throw new DBUnexpectedError(
+                               $this,
+                               'DB connection was already closed or the connection dropped.'
+                       );
+               }
+
+               return $this->mConn;
+       }
+
        /**
         * @since 1.19
         * @return string
@@ -3422,8 +3453,11 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                }
 
                if ( $this->mConn ) {
-                       // Avoid connection leaks for sanity
+                       // Avoid connection leaks for sanity. Normally, resources close at script completion.
+                       // The connection might already be closed in zend/hhvm by now, so suppress warnings.
+                       \MediaWiki\suppressWarnings();
                        $this->closeConnection();
+                       \MediaWiki\restoreWarnings();
                        $this->mConn = false;
                        $this->mOpened = false;
                }