+ // Sanity check that the SQL query is appropriate in the current context and is
+ // allowed for an outside caller (e.g. does not break transaction/session tracking).
+ $this->assertQueryIsCurrentlyAllowed( $sql, $fname );
+
+ // Send the query to the server and fetch any corresponding errors
+ list( $ret, $err, $errno, $unignorable ) = $this->executeQuery( $sql, $fname, $flags );
+ if ( $ret === false ) {
+ $ignoreErrors = $this->hasFlags( $flags, self::QUERY_SILENCE_ERRORS );
+ // Throw an error unless both the ignore flag was set and a rollback is not needed
+ $this->reportQueryError( $err, $errno, $sql, $fname, $ignoreErrors && !$unignorable );
+ }
+
+ return $this->resultObject( $ret );
+ }
+
+ /**
+ * Execute a query, retrying it if there is a recoverable connection loss
+ *
+ * This is similar to query() except:
+ * - It does not prevent all non-ROLLBACK queries if there is a corrupted transaction
+ * - It does not disallow raw queries that are supposed to use dedicated IDatabase methods
+ * - It does not throw exceptions for common error cases
+ *
+ * This is meant for internal use with Database subclasses.
+ *
+ * @param string $sql Original SQL query
+ * @param string $fname Name of the calling function
+ * @param int $flags Bitfield of class QUERY_* constants
+ * @return array An n-tuple of:
+ * - mixed|bool: An object, resource, or true on success; false on failure
+ * - string: The result of calling lastError()
+ * - int: The result of calling lastErrno()
+ * - bool: Whether a rollback is needed to allow future non-rollback queries
+ * @throws DBUnexpectedError
+ */
+ final protected function executeQuery( $sql, $fname, $flags ) {
+ $this->assertHasConnectionHandle();