_connection) { return $this->_connection; } $this->_connect(); /** * Before MySQL 5.1.17, server-side prepared statements * do not use the query cache. * @see https://dev.mysql.com/doc/refman/5.1/en/query-cache-operation.html * * MySQL also does not support preparing certain DDL and SHOW * statements. * @see https://framework.zend.com/issues/browse/ZF-1398 */ $this->_connection->setAttribute(PDO::ATTR_EMULATE_PREPARES, true); return $this->_connection; } protected function _connect() // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore { if ($this->_connection) { return; } $sql = 'SET sql_mode = "' . Db::SQL_MODE . '"'; try { parent::_connect(); $this->_connection->exec($sql); } catch (Exception $e) { if ($this->isErrNo($e, \Piwik\Updater\Migration\Db::ERROR_CODE_MYSQL_SERVER_HAS_GONE_AWAY)) { // mysql may return a MySQL server has gone away error when trying to establish the connection. // in that case we want to retry establishing the connection once after a short sleep $this->_connection = null; // we need to unset, otherwise parent connect won't retry usleep(400 * 1000); parent::_connect(); $this->_connection->exec($sql); } else { throw $e; } } } /** * Reset the configuration variables in this adapter. */ public function resetConfig() { $this->_config = array(); } /** * Return default port. * * @deprecated Use Schema::getDefaultPortForSchema instead * @return int */ public static function getDefaultPort() { return 3306; } /** * Check MySQL version * * @throws Exception */ public function checkServerVersion() { $requiredVersion = Schema::getInstance()->getMinimumSupportedVersion(); $serverVersion = $this->getServerVersion(); if (version_compare($serverVersion, $requiredVersion) === -1) { throw new Exception(Piwik::translate('General_ExceptionDatabaseVersion', array('MySQL', $serverVersion, $requiredVersion))); } } /** * Returns the MySQL server version * * @return null|string */ public function getServerVersion() { // prioritizing SELECT @@VERSION in case the connection version string is incorrect (which can // occur on Azure) $versionInfo = $this->fetchAll('SELECT @@VERSION'); if (count($versionInfo)) { return $versionInfo[0]['@@VERSION']; } return parent::getServerVersion(); } /** * Check client version compatibility against database server * * @throws Exception */ public function checkClientVersion() { $serverVersion = $this->getServerVersion(); $clientVersion = $this->getClientVersion(); // incompatible change to DECIMAL implementation in 5.0.3 if ( version_compare($serverVersion, '5.0.3') >= 0 && version_compare($clientVersion, '5.0.3') < 0 ) { throw new Exception(Piwik::translate('General_ExceptionIncompatibleClientServerVersions', array('MySQL', $clientVersion, $serverVersion))); } } /** * Returns true if this adapter's required extensions are enabled * * @return bool */ public static function isEnabled() { return extension_loaded('PDO') && extension_loaded('pdo_mysql') && in_array('mysql', PDO::getAvailableDrivers()); } /** * Returns true if this adapter supports blobs as fields * * @return bool */ public function hasBlobDataType() { return true; } /** * Returns true if this adapter supports bulk loading * * @return bool */ public function hasBulkLoader() { return true; } /** * Test error number * * @param Exception $e * @param string|int $errno * @return bool */ public function isErrNo($e, $errno) { return self::isPdoErrorNumber($e, $errno); } /** * Test error number * * @param Exception $e * @param string|int $errno * @return bool */ public static function isPdoErrorNumber($e, $errno) { if (preg_match('/(?:\[|\s)([0-9]{4})(?:\]|\s)/', $e->getMessage(), $match)) { return $match[1] == $errno; } return false; } /** * Is the connection character set equal to utf8? * * @return bool */ public function isConnectionUTF8() { $charsetInfo = $this->fetchAll('SHOW VARIABLES LIKE ?', array('character_set_connection')); if (empty($charsetInfo)) { return false; } $charset = $charsetInfo[0]['Value']; return strpos($charset, 'utf8') === 0; } /** * Return number of affected rows in last query * * @param mixed $queryResult Result from query() * @return int */ public function rowCount($queryResult) { return $queryResult->rowCount(); } /** * Retrieve client version in PHP style * * @return string|null */ public function getClientVersion() { $this->_connect(); try { $version = $this->_connection->getAttribute(PDO::ATTR_CLIENT_VERSION); $matches = null; if (preg_match('/((?:[0-9]{1,2}\.){1,3}[0-9]{1,2})/', $version, $matches)) { return $matches[1]; } } catch (PDOException $e) { // In case of the driver doesn't support getting attributes } return null; } /** * Override _dsn() to ensure host and port to not be passed along * if unix_socket is set since setting both causes unexpected behaviour * @see https://php.net/manual/en/ref.pdo-mysql.connection.php */ protected function _dsn() // phpcs:ignore PSR2.Methods.MethodDeclaration.Underscore { if (!empty($this->_config['unix_socket'])) { unset($this->_config['host']); unset($this->_config['port']); } return parent::_dsn(); } }