Merge "rdbms: change "profiler" argument in Database::factory so it works again"
[lhc/web/wiklou.git] / includes / libs / rdbms / database / Database.php
index 3475b09..13bf8f0 100644 (file)
@@ -260,7 +260,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
        /** @var int[] Prior flags member variable values */
        private $priorFlags = [];
 
-       /** @var mixed Class name or object With profileIn/profileOut methods */
+       /** @var callable|null */
        protected $profiler;
        /** @var TransactionProfiler */
        protected $trxProfiler;
@@ -308,7 +308,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
 
                $this->srvCache = $params['srvCache'] ?? new HashBagOStuff();
 
-               $this->profiler = $params['profiler'];
+               $this->profiler = is_callable( $params['profiler'] ) ? $params['profiler'] : null;
                $this->trxProfiler = $params['trxProfiler'];
                $this->connLogger = $params['connLogger'];
                $this->queryLogger = $params['queryLogger'];
@@ -408,9 +408,10 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
         *      used to adjust lock timeouts or encoding modes and the like.
         *   - connLogger: Optional PSR-3 logger interface instance.
         *   - queryLogger: Optional PSR-3 logger interface instance.
-        *   - profiler: Optional class name or object with profileIn()/profileOut() methods.
-        *      These will be called in query(), using a simplified version of the SQL that also
-        *      includes the agent as a SQL comment.
+        *   - profiler : Optional callback that takes a section name argument and returns
+        *      a ScopedCallback instance that ends the profile section in its destructor.
+        *      These will be called in query(), using a simplified version of the SQL that
+        *      also includes the agent as a SQL comment.
         *   - trxProfiler: Optional TransactionProfiler instance.
         *   - errorLogger: Optional callback that takes an Exception and logs it.
         *   - deprecationLogger: Optional callback that takes a string and logs it.
@@ -1236,7 +1237,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                                        # option is ROLLBACK, since the snapshots would have been released.
                                        $this->trxStatus = self::STATUS_TRX_ERROR;
                                        $this->trxStatusCause =
-                                               $this->makeQueryException( $lastError, $lastErrno, $sql, $fname );
+                                               $this->getQueryExceptionAndLog( $lastError, $lastErrno, $sql, $fname );
                                        $tempIgnore = false; // cannot recover
                                        $this->trxStatusIgnoredCause = null;
                                }
@@ -1272,19 +1273,13 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                $queryProf .= $this->trxShortId ? " [TRX#{$this->trxShortId}]" : "";
 
                $startTime = microtime( true );
-               if ( $this->profiler ) {
-                       $this->profiler->profileIn( $queryProf );
-               }
+               $ps = $this->profiler ? ( $this->profiler )( $queryProf ) : null;
                $this->affectedRowCount = null;
                $ret = $this->doQuery( $commentedSql );
                $this->affectedRowCount = $this->affectedRows();
-               if ( $this->profiler ) {
-                       $this->profiler->profileOut( $queryProf );
-               }
+               unset( $ps ); // profile out (if set)
                $queryRuntime = max( microtime( true ) - $startTime, 0.0 );
 
-               unset( $queryProfSection ); // profile out (if set)
-
                if ( $ret !== false ) {
                        $this->lastPing = $startTime;
                        if ( $isWrite && $this->trxLevel ) {
@@ -1489,7 +1484,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                if ( $tempIgnore ) {
                        $this->queryLogger->debug( "SQL ERROR (ignored): $error\n" );
                } else {
-                       $exception = $this->makeQueryException( $error, $errno, $sql, $fname );
+                       $exception = $this->getQueryExceptionAndLog( $error, $errno, $sql, $fname );
 
                        throw $exception;
                }
@@ -1502,7 +1497,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
         * @param string $fname
         * @return DBError
         */
-       private function makeQueryException( $error, $errno, $sql, $fname ) {
+       private function getQueryExceptionAndLog( $error, $errno, $sql, $fname ) {
                $sql1line = mb_substr( str_replace( "\n", "\\n", $sql ), 0, 5 * 1024 );
                $this->queryLogger->error(
                        "{fname}\t{db_server}\t{errno}\t{error}\t{sql1line}",
@@ -1512,6 +1507,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                                'error' => $error,
                                'sql1line' => $sql1line,
                                'fname' => $fname,
+                               'trace' => ( new RuntimeException() )->getTraceAsString()
                        ] )
                );
                $this->queryLogger->debug( "SQL ERROR: " . $error . "\n" );
@@ -2682,15 +2678,6 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                }
        }
 
-       /**
-        * Quotes an identifier using `backticks` or "double quotes" depending on the database type.
-        * MySQL uses `backticks` while basically everything else uses double quotes.
-        * Since MySQL is the odd one out here the double quotes are our generic
-        * and we implement backticks in DatabaseMysqlBase.
-        *
-        * @param string $s
-        * @return string
-        */
        public function addIdentifierQuotes( $s ) {
                return '"' . str_replace( '"', '""', $s ) . '"';
        }
@@ -2791,6 +2778,7 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                        return;
                }
 
+               $uniqueIndexes = (array)$uniqueIndexes;
                // Single row case
                if ( !is_array( reset( $rows ) ) ) {
                        $rows = [ $rows ];
@@ -2870,13 +2858,14 @@ abstract class Database implements IDatabase, IMaintainableDatabase, LoggerAware
                $this->query( $sql, $fname );
        }
 
-       public function upsert( $table, array $rows, array $uniqueIndexes, array $set,
+       public function upsert( $table, array $rows, $uniqueIndexes, array $set,
                $fname = __METHOD__
        ) {
                if ( $rows === [] ) {
                        return true; // nothing to do
                }
 
+               $uniqueIndexes = (array)$uniqueIndexes;
                if ( !is_array( reset( $rows ) ) ) {
                        $rows = [ $rows ];
                }