}
protected function open( $server, $user, $password, $dbName, $schema, $tablePrefix ) {
- # Close/unset connection handle
$this->close();
+ if ( $schema !== null ) {
+ throw new DBExpectedError( $this, __CLASS__ . ": domain schemas are not supported." );
+ }
+
$this->server = $server;
$this->user = $user;
$this->password = $password;
$error = $error ?: $this->lastError();
$this->connLogger->error(
"Error connecting to {db_server}: {error}",
- $this->getLogContext( [
- 'method' => __METHOD__,
- 'error' => $error,
- ] )
+ $this->getLogContext( [ 'method' => __METHOD__, 'error' => $error ] )
);
$this->connLogger->debug( "DB connection error\n" .
"Server: $server, User: $user, Password: " .
substr( $password, 0, 3 ) . "..., error: " . $error . "\n" );
-
throw new DBConnectionError( $this, $error );
}
- if ( strlen( $dbName ) ) {
- $this->selectDomain( new DatabaseDomain( $dbName, null, $tablePrefix ) );
- } else {
- $this->currentDomain = new DatabaseDomain( null, null, $tablePrefix );
- }
-
- // Tell the server what we're communicating with
- if ( !$this->connectInitCharset() ) {
- $error = $this->lastError();
- $this->queryLogger->error(
- "Error setting character set: {error}",
- $this->getLogContext( [
- 'method' => __METHOD__,
- 'error' => $this->lastError(),
- ] )
+ try {
+ $this->currentDomain = new DatabaseDomain(
+ strlen( $dbName ) ? $dbName : null,
+ null,
+ $tablePrefix
);
- throw new DBConnectionError( $this, "Error setting character set: $error" );
- }
- // Abstract over any insane MySQL defaults
- $set = [ 'group_concat_max_len = 262144' ];
- // Set SQL mode, default is turning them all off, can be overridden or skipped with null
- if ( is_string( $this->sqlMode ) ) {
- $set[] = 'sql_mode = ' . $this->addQuotes( $this->sqlMode );
- }
- // Set any custom settings defined by site config
- // (e.g. https://dev.mysql.com/doc/refman/4.1/en/innodb-parameters.html)
- foreach ( $this->sessionVars as $var => $val ) {
- // Escape strings but not numbers to avoid MySQL complaining
- if ( !is_int( $val ) && !is_float( $val ) ) {
- $val = $this->addQuotes( $val );
+ // Abstract over any insane MySQL defaults
+ $set = [ 'group_concat_max_len = 262144' ];
+ // Set SQL mode, default is turning them all off, can be overridden or skipped with null
+ if ( is_string( $this->sqlMode ) ) {
+ $set[] = 'sql_mode = ' . $this->addQuotes( $this->sqlMode );
+ }
+ // Set any custom settings defined by site config
+ // (e.g. https://dev.mysql.com/doc/refman/4.1/en/innodb-parameters.html)
+ foreach ( $this->connectionVariables as $var => $val ) {
+ // Escape strings but not numbers to avoid MySQL complaining
+ if ( !is_int( $val ) && !is_float( $val ) ) {
+ $val = $this->addQuotes( $val );
+ }
+ $set[] = $this->addIdentifierQuotes( $var ) . ' = ' . $val;
}
- $set[] = $this->addIdentifierQuotes( $var ) . ' = ' . $val;
- }
- if ( $set ) {
- // Use doQuery() to avoid opening implicit transactions (DBO_TRX)
- $success = $this->doQuery( 'SET ' . implode( ', ', $set ) );
- if ( !$success ) {
- $error = $this->lastError();
- $this->queryLogger->error(
- 'Error setting MySQL variables on server {db_server}: {error}',
- $this->getLogContext( [
- 'method' => __METHOD__,
- 'error' => $error,
- ] )
+ if ( $set ) {
+ $this->query(
+ 'SET ' . implode( ', ', $set ),
+ __METHOD__,
+ self::QUERY_IGNORE_DBO_TRX | self::QUERY_NO_RETRY
);
- throw new DBConnectionError( $this, "Error setting MySQL variables: $error" );
}
+ } catch ( Exception $e ) {
+ // Connection was not fully initialized and is not safe for use
+ $this->conn = false;
}
- $this->opened = true;
-
return true;
}
- /**
- * Set the character set information right after connection
- * @return bool
- */
- protected function connectInitCharset() {
- if ( $this->utf8Mode ) {
- // Tell the server we're communicating with it in UTF-8.
- // This may engage various charset conversions.
- return $this->mysqlSetCharset( 'utf8' );
- } else {
- return $this->mysqlSetCharset( 'binary' );
- }
- }
-
protected function doSelectDomain( DatabaseDomain $domain ) {
if ( $domain->getSchema() !== null ) {
throw new DBExpectedError( $this, __CLASS__ . ": domain schemas are not supported." );
if ( $database !== $this->getDBname() ) {
$sql = 'USE ' . $this->addIdentifierQuotes( $database );
- $ret = $this->doQuery( $sql );
- if ( $ret === false ) {
- $error = $this->lastError();
- $errno = $this->lastErrno();
- $this->reportQueryError( $error, $errno, $sql, __METHOD__ );
+ list( $res, $err, $errno ) =
+ $this->executeQuery( $sql, __METHOD__, self::QUERY_IGNORE_DBO_TRX );
+
+ if ( $res === false ) {
+ $this->reportQueryError( $err, $errno, $sql, __METHOD__ );
+ return false; // unreachable
}
}
abstract protected function mysqlConnect( $realServer, $dbName );
/**
- * Set the character set of the MySQL link
- *
- * @param string $charset
- * @return bool
- */
- abstract protected function mysqlSetCharset( $charset );
-
- /**
- * @param ResultWrapper|resource $res
+ * @param IResultWrapper|resource $res
* @throws DBUnexpectedError
*/
public function freeResult( $res ) {
abstract protected function mysqlFreeResult( $res );
/**
- * @param ResultWrapper|resource $res
+ * @param IResultWrapper|resource $res
* @return stdClass|bool
* @throws DBUnexpectedError
*/
* Fetch a result row as an associative and numeric array
*
* @param resource $res Raw result
- * @return array
+ * @return array|false
*/
abstract protected function mysqlFetchArray( $res );
/**
* @throws DBUnexpectedError
- * @param ResultWrapper|resource $res
+ * @param IResultWrapper|resource $res
* @return int
*/
function numRows( $res ) {
abstract protected function mysqlNumRows( $res );
/**
- * @param ResultWrapper|resource $res
+ * @param IResultWrapper|resource $res
* @return int
*/
public function numFields( $res ) {
abstract protected function mysqlNumFields( $res );
/**
- * @param ResultWrapper|resource $res
+ * @param IResultWrapper|resource $res
* @param int $n
* @return string
*/
/**
* Get the name of the specified field in a result
*
- * @param ResultWrapper|resource $res
+ * @param IResultWrapper|resource $res
* @param int $n
* @return string
*/
/**
* mysql_field_type() wrapper
- * @param ResultWrapper|resource $res
+ * @param IResultWrapper|resource $res
* @param int $n
* @return string
*/
/**
* Get the type of the specified field in a result
*
- * @param ResultWrapper|resource $res
+ * @param IResultWrapper|resource $res
* @param int $n
* @return string
*/
abstract protected function mysqlFieldType( $res, $n );
/**
- * @param ResultWrapper|resource $res
+ * @param IResultWrapper|resource $res
* @param int $row
* @return bool
*/
/**
* Move internal result pointer
*
- * @param ResultWrapper|resource $res
+ * @param IResultWrapper|resource $res
* @param int $row
* @return bool
*/
return strlen( $name ) && $name[0] == '`' && substr( $name, -1, 1 ) == '`';
}
- public function getLag() {
+ protected function doGetLag() {
if ( $this->getLagDetectionMethod() === 'pt-heartbeat' ) {
return $this->getLagFromPtHeartbeat();
} else {
$gtidArg = $this->addQuotes( implode( ',', $gtidsWait ) );
if ( strpos( $gtidArg, ':' ) !== false ) {
// MySQL GTIDs, e.g "source_id:transaction_id"
- $res = $this->doQuery( "SELECT WAIT_FOR_EXECUTED_GTID_SET($gtidArg, $timeout)" );
+ $sql = "SELECT WAIT_FOR_EXECUTED_GTID_SET($gtidArg, $timeout)";
} else {
// MariaDB GTIDs, e.g."domain:server:sequence"
- $res = $this->doQuery( "SELECT MASTER_GTID_WAIT($gtidArg, $timeout)" );
+ $sql = "SELECT MASTER_GTID_WAIT($gtidArg, $timeout)";
}
} else {
// Wait on the binlog coordinates
$encFile = $this->addQuotes( $pos->getLogFile() );
$encPos = intval( $pos->getLogPosition()[$pos::CORD_EVENT] );
- $res = $this->doQuery( "SELECT MASTER_POS_WAIT($encFile, $encPos, $timeout)" );
+ $sql = "SELECT MASTER_POS_WAIT($encFile, $encPos, $timeout)";
}
+ list( $res, $err ) = $this->executeQuery( $sql, __METHOD__, self::QUERY_IGNORE_DBO_TRX );
$row = $res ? $this->fetchRow( $res ) : false;
if ( !$row ) {
- throw new DBExpectedError( $this, "Replication wait failed: {$this->lastError()}" );
+ throw new DBExpectedError( $this, "Replication wait failed: {$err}" );
}
// Result can be NULL (error), -1 (timeout), or 0+ per the MySQL manual
/**
* @param string $tableName
* @param string $fName
- * @return bool|ResultWrapper
+ * @return bool|IResultWrapper
*/
public function dropTable( $tableName, $fName = __METHOD__ ) {
if ( !$this->tableExists( $tableName, $fName ) ) {