*/ protected array $_baseConfig = [ 'persistent' => true, 'host' => 'localhost', 'username' => 'root', 'password' => '', 'database' => 'cake', 'port' => '3306', 'flags' => [], 'encoding' => 'utf8mb4', 'timezone' => null, 'init' => [], ]; /** * String used to start a database identifier quoting to make it safe * * @var string */ protected string $_startQuote = '`'; /** * String used to end a database identifier quoting to make it safe * * @var string */ protected string $_endQuote = '`'; /** * Server type. * * If the underlying server is MariaDB, its value will get set to `'mariadb'` * after `version()` method is called. * * @var string */ protected string $serverType = self::SERVER_TYPE_MYSQL; /** * Mapping of feature to db server version for feature availability checks. * * @var array> */ protected array $featureVersions = [ 'mysql' => [ 'json' => '5.7.0', 'cte' => '8.0.0', 'window' => '8.0.0', 'intersect' => '8.0.31', 'intersect-all' => '8.0.31', 'check-constraints' => '8.0.16', ], 'mariadb' => [ 'json' => '10.2.7', 'cte' => '10.2.1', 'window' => '10.2.0', 'intersect' => '10.3.0', 'intersect-all' => '10.5.0', 'check-constraints' => '10.2.1', ], ]; /** * @inheritDoc */ public function connect(): void { if ($this->pdo !== null) { return; } $config = $this->_config; if ($config['timezone'] === 'UTC') { $config['timezone'] = '+0:00'; } if (!empty($config['timezone'])) { $config['init'][] = sprintf("SET time_zone = '%s'", $config['timezone']); } $config['flags'] += [ PDO::ATTR_PERSISTENT => $config['persistent'], $this->attrUseBufferedQueryId() => true, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, ]; if (!empty($config['ssl_key']) && !empty($config['ssl_cert'])) { $config['flags'][$this->attrSslKeyId()] = $config['ssl_key']; $config['flags'][$this->attrSslCertId()] = $config['ssl_cert']; } if (!empty($config['ssl_ca'])) { $config['flags'][$this->attrSslCaId()] = $config['ssl_ca']; } if (empty($config['unix_socket'])) { $dsn = "mysql:host={$config['host']};port={$config['port']};dbname={$config['database']}"; } else { $dsn = "mysql:unix_socket={$config['unix_socket']};dbname={$config['database']}"; } if (!empty($config['encoding'])) { $dsn .= ";charset={$config['encoding']}"; } $this->pdo = $this->createPdo($dsn, $config); if (!empty($config['init'])) { foreach ((array)$config['init'] as $command) { $this->pdo->exec($command); } } } /** * @inheritDoc */ public function run(Query $query): StatementInterface { $statement = $this->prepare($query); $query->getValueBinder()->attachTo($statement); if ($query instanceof SelectQuery) { try { $this->getPdo()->setAttribute($this->attrUseBufferedQueryId(), $query->isBufferedResultsEnabled()); $this->executeStatement($statement); } finally { $this->getPdo()->setAttribute($this->attrUseBufferedQueryId(), true); } } else { $this->executeStatement($statement); } return $statement; } /** * Returns whether php is able to use this driver for connecting to database * * @return bool true if it is valid to use this driver */ public function enabled(): bool { return in_array('mysql', PDO::getAvailableDrivers(), true); } /** * @inheritDoc */ public function schemaDialect(): SchemaDialect { return $this->_schemaDialect ?? ($this->_schemaDialect = new MysqlSchemaDialect($this)); } /** * @inheritDoc */ public function schema(): string { return $this->_config['database']; } /** * Get the SQL for disabling foreign keys. * * @return string */ public function disableForeignKeySQL(): string { return 'SET foreign_key_checks = 0'; } /** * @inheritDoc */ public function enableForeignKeySQL(): string { return 'SET foreign_key_checks = 1'; } /** * @inheritDoc */ public function supports(DriverFeatureEnum $feature): bool { $versionCompare = function () use ($feature) { return version_compare( $this->version(), $this->featureVersions[$this->serverType][$feature->value], '>=', ); }; return match ($feature) { DriverFeatureEnum::DISABLE_CONSTRAINT_WITHOUT_TRANSACTION, DriverFeatureEnum::SAVEPOINT => true, DriverFeatureEnum::TRUNCATE_WITH_CONSTRAINTS => false, DriverFeatureEnum::CTE, DriverFeatureEnum::JSON, DriverFeatureEnum::WINDOW => $versionCompare(), DriverFeatureEnum::INTERSECT => $versionCompare(), DriverFeatureEnum::INTERSECT_ALL => $versionCompare(), DriverFeatureEnum::CHECK_CONSTRAINTS => $versionCompare(), DriverFeatureEnum::SET_OPERATIONS_ORDER_BY => true, DriverFeatureEnum::OPTIMIZER_HINT_COMMENT => true, }; } /** * Returns true if the connected server is MariaDB. * * @return bool */ public function isMariadb(): bool { $this->version(); return $this->serverType === static::SERVER_TYPE_MARIADB; } /** * Returns connected server version. * * @return string */ public function version(): string { if ($this->_version === null) { $this->_version = (string)$this->getPdo()->getAttribute(PDO::ATTR_SERVER_VERSION); if (str_contains($this->_version, 'MariaDB')) { $this->serverType = static::SERVER_TYPE_MARIADB; preg_match('/^(?:5\.5\.5-)?(\d+\.\d+\.\d+.*-MariaDB[^:]*)/', $this->_version, $matches); $this->_version = $matches[1]; } } return $this->_version; } /** * Get PDO ATTR_SSL_KEY id. * * @return int */ private function attrSslKeyId(): int { return PHP_VERSION_ID < 80400 ? PDO::MYSQL_ATTR_SSL_KEY : PdoMysql::ATTR_SSL_KEY; } /** * Get PDO ATTR_SSL_CERT id. * * @return int */ private function attrSslCertId(): int { return PHP_VERSION_ID < 80400 ? PDO::MYSQL_ATTR_SSL_CERT : PdoMysql::ATTR_SSL_CERT; } /** * Get PDO ATTR_SSL_CA id. * * @return int */ private function attrSslCaId(): int { return PHP_VERSION_ID < 80400 ? PDO::MYSQL_ATTR_SSL_CA : PdoMysql::ATTR_SSL_CA; } /** * Get PDO ATTR_USE_BUFFERED_QUERY id. * * @return int */ private function attrUseBufferedQueryId(): int { return PHP_VERSION_ID < 80400 ? PDO::MYSQL_ATTR_USE_BUFFERED_QUERY : PdoMysql::ATTR_USE_BUFFERED_QUERY; } }