diff options
| author | polo <ordipolo@gmx.fr> | 2024-08-13 23:45:21 +0200 |
|---|---|---|
| committer | polo <ordipolo@gmx.fr> | 2024-08-13 23:45:21 +0200 |
| commit | bf6655a534a6775d30cafa67bd801276bda1d98d (patch) | |
| tree | c6381e3f6c81c33eab72508f410b165ba05f7e9c /vendor/symfony/cache/Adapter/PdoAdapter.php | |
| parent | 94d67a4b51f8e62e7d518cce26a526ae1ec48278 (diff) | |
| download | AppliGestionPHP-bf6655a534a6775d30cafa67bd801276bda1d98d.tar.gz AppliGestionPHP-bf6655a534a6775d30cafa67bd801276bda1d98d.tar.bz2 AppliGestionPHP-bf6655a534a6775d30cafa67bd801276bda1d98d.zip | |
VERSION 0.2 doctrine ORM et entités
Diffstat (limited to 'vendor/symfony/cache/Adapter/PdoAdapter.php')
| -rw-r--r-- | vendor/symfony/cache/Adapter/PdoAdapter.php | 398 |
1 files changed, 398 insertions, 0 deletions
diff --git a/vendor/symfony/cache/Adapter/PdoAdapter.php b/vendor/symfony/cache/Adapter/PdoAdapter.php new file mode 100644 index 0000000..b18428d --- /dev/null +++ b/vendor/symfony/cache/Adapter/PdoAdapter.php | |||
| @@ -0,0 +1,398 @@ | |||
| 1 | <?php | ||
| 2 | |||
| 3 | /* | ||
| 4 | * This file is part of the Symfony package. | ||
| 5 | * | ||
| 6 | * (c) Fabien Potencier <fabien@symfony.com> | ||
| 7 | * | ||
| 8 | * For the full copyright and license information, please view the LICENSE | ||
| 9 | * file that was distributed with this source code. | ||
| 10 | */ | ||
| 11 | |||
| 12 | namespace Symfony\Component\Cache\Adapter; | ||
| 13 | |||
| 14 | use Symfony\Component\Cache\Exception\InvalidArgumentException; | ||
| 15 | use Symfony\Component\Cache\Marshaller\DefaultMarshaller; | ||
| 16 | use Symfony\Component\Cache\Marshaller\MarshallerInterface; | ||
| 17 | use Symfony\Component\Cache\PruneableInterface; | ||
| 18 | |||
| 19 | class PdoAdapter extends AbstractAdapter implements PruneableInterface | ||
| 20 | { | ||
| 21 | private const MAX_KEY_LENGTH = 255; | ||
| 22 | |||
| 23 | private MarshallerInterface $marshaller; | ||
| 24 | private \PDO $conn; | ||
| 25 | private string $dsn; | ||
| 26 | private string $driver; | ||
| 27 | private string $serverVersion; | ||
| 28 | private string $table = 'cache_items'; | ||
| 29 | private string $idCol = 'item_id'; | ||
| 30 | private string $dataCol = 'item_data'; | ||
| 31 | private string $lifetimeCol = 'item_lifetime'; | ||
| 32 | private string $timeCol = 'item_time'; | ||
| 33 | private ?string $username = null; | ||
| 34 | private ?string $password = null; | ||
| 35 | private array $connectionOptions = []; | ||
| 36 | private string $namespace; | ||
| 37 | |||
| 38 | /** | ||
| 39 | * You can either pass an existing database connection as PDO instance or | ||
| 40 | * a DSN string that will be used to lazy-connect to the database when the | ||
| 41 | * cache is actually used. | ||
| 42 | * | ||
| 43 | * List of available options: | ||
| 44 | * * db_table: The name of the table [default: cache_items] | ||
| 45 | * * db_id_col: The column where to store the cache id [default: item_id] | ||
| 46 | * * db_data_col: The column where to store the cache data [default: item_data] | ||
| 47 | * * db_lifetime_col: The column where to store the lifetime [default: item_lifetime] | ||
| 48 | * * db_time_col: The column where to store the timestamp [default: item_time] | ||
| 49 | * * db_username: The username when lazy-connect [default: ''] | ||
| 50 | * * db_password: The password when lazy-connect [default: ''] | ||
| 51 | * * db_connection_options: An array of driver-specific connection options [default: []] | ||
| 52 | * | ||
| 53 | * @throws InvalidArgumentException When first argument is not PDO nor Connection nor string | ||
| 54 | * @throws InvalidArgumentException When PDO error mode is not PDO::ERRMODE_EXCEPTION | ||
| 55 | * @throws InvalidArgumentException When namespace contains invalid characters | ||
| 56 | */ | ||
| 57 | public function __construct(#[\SensitiveParameter] \PDO|string $connOrDsn, string $namespace = '', int $defaultLifetime = 0, array $options = [], ?MarshallerInterface $marshaller = null) | ||
| 58 | { | ||
| 59 | if (\is_string($connOrDsn) && str_contains($connOrDsn, '://')) { | ||
| 60 | throw new InvalidArgumentException(sprintf('Usage of Doctrine DBAL URL with "%s" is not supported. Use a PDO DSN or "%s" instead.', __CLASS__, DoctrineDbalAdapter::class)); | ||
| 61 | } | ||
| 62 | |||
| 63 | if (isset($namespace[0]) && preg_match('#[^-+.A-Za-z0-9]#', $namespace, $match)) { | ||
| 64 | throw new InvalidArgumentException(sprintf('Namespace contains "%s" but only characters in [-+.A-Za-z0-9] are allowed.', $match[0])); | ||
| 65 | } | ||
| 66 | |||
| 67 | if ($connOrDsn instanceof \PDO) { | ||
| 68 | if (\PDO::ERRMODE_EXCEPTION !== $connOrDsn->getAttribute(\PDO::ATTR_ERRMODE)) { | ||
| 69 | throw new InvalidArgumentException(sprintf('"%s" requires PDO error mode attribute be set to throw Exceptions (i.e. $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION)).', __CLASS__)); | ||
| 70 | } | ||
| 71 | |||
| 72 | $this->conn = $connOrDsn; | ||
| 73 | } else { | ||
| 74 | $this->dsn = $connOrDsn; | ||
| 75 | } | ||
| 76 | |||
| 77 | $this->maxIdLength = self::MAX_KEY_LENGTH; | ||
| 78 | $this->table = $options['db_table'] ?? $this->table; | ||
| 79 | $this->idCol = $options['db_id_col'] ?? $this->idCol; | ||
| 80 | $this->dataCol = $options['db_data_col'] ?? $this->dataCol; | ||
| 81 | $this->lifetimeCol = $options['db_lifetime_col'] ?? $this->lifetimeCol; | ||
| 82 | $this->timeCol = $options['db_time_col'] ?? $this->timeCol; | ||
| 83 | $this->username = $options['db_username'] ?? $this->username; | ||
| 84 | $this->password = $options['db_password'] ?? $this->password; | ||
| 85 | $this->connectionOptions = $options['db_connection_options'] ?? $this->connectionOptions; | ||
| 86 | $this->namespace = $namespace; | ||
| 87 | $this->marshaller = $marshaller ?? new DefaultMarshaller(); | ||
| 88 | |||
| 89 | parent::__construct($namespace, $defaultLifetime); | ||
| 90 | } | ||
| 91 | |||
| 92 | public static function createConnection(#[\SensitiveParameter] string $dsn, array $options = []): \PDO|string | ||
| 93 | { | ||
| 94 | if ($options['lazy'] ?? true) { | ||
| 95 | return $dsn; | ||
| 96 | } | ||
| 97 | |||
| 98 | $pdo = new \PDO($dsn); | ||
| 99 | $pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); | ||
| 100 | |||
| 101 | return $pdo; | ||
| 102 | } | ||
| 103 | |||
| 104 | /** | ||
| 105 | * Creates the table to store cache items which can be called once for setup. | ||
| 106 | * | ||
| 107 | * Cache ID are saved in a column of maximum length 255. Cache data is | ||
| 108 | * saved in a BLOB. | ||
| 109 | * | ||
| 110 | * @throws \PDOException When the table already exists | ||
| 111 | * @throws \DomainException When an unsupported PDO driver is used | ||
| 112 | */ | ||
| 113 | public function createTable(): void | ||
| 114 | { | ||
| 115 | $sql = match ($driver = $this->getDriver()) { | ||
| 116 | // We use varbinary for the ID column because it prevents unwanted conversions: | ||
| 117 | // - character set conversions between server and client | ||
| 118 | // - trailing space removal | ||
| 119 | // - case-insensitivity | ||
| 120 | // - language processing like é == e | ||
| 121 | 'mysql' => "CREATE TABLE $this->table ($this->idCol VARBINARY(255) NOT NULL PRIMARY KEY, $this->dataCol MEDIUMBLOB NOT NULL, $this->lifetimeCol INTEGER UNSIGNED, $this->timeCol INTEGER UNSIGNED NOT NULL) COLLATE utf8mb4_bin, ENGINE = InnoDB", | ||
| 122 | 'sqlite' => "CREATE TABLE $this->table ($this->idCol TEXT NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)", | ||
| 123 | 'pgsql' => "CREATE TABLE $this->table ($this->idCol VARCHAR(255) NOT NULL PRIMARY KEY, $this->dataCol BYTEA NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)", | ||
| 124 | 'oci' => "CREATE TABLE $this->table ($this->idCol VARCHAR2(255) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)", | ||
| 125 | 'sqlsrv' => "CREATE TABLE $this->table ($this->idCol VARCHAR(255) NOT NULL PRIMARY KEY, $this->dataCol VARBINARY(MAX) NOT NULL, $this->lifetimeCol INTEGER, $this->timeCol INTEGER NOT NULL)", | ||
| 126 | default => throw new \DomainException(sprintf('Creating the cache table is currently not implemented for PDO driver "%s".', $driver)), | ||
| 127 | }; | ||
| 128 | |||
| 129 | $this->getConnection()->exec($sql); | ||
| 130 | } | ||
| 131 | |||
| 132 | public function prune(): bool | ||
| 133 | { | ||
| 134 | $deleteSql = "DELETE FROM $this->table WHERE $this->lifetimeCol + $this->timeCol <= :time"; | ||
| 135 | |||
| 136 | if ('' !== $this->namespace) { | ||
| 137 | $deleteSql .= " AND $this->idCol LIKE :namespace"; | ||
| 138 | } | ||
| 139 | |||
| 140 | $connection = $this->getConnection(); | ||
| 141 | |||
| 142 | try { | ||
| 143 | $delete = $connection->prepare($deleteSql); | ||
| 144 | } catch (\PDOException) { | ||
| 145 | return true; | ||
| 146 | } | ||
| 147 | $delete->bindValue(':time', time(), \PDO::PARAM_INT); | ||
| 148 | |||
| 149 | if ('' !== $this->namespace) { | ||
| 150 | $delete->bindValue(':namespace', sprintf('%s%%', $this->namespace), \PDO::PARAM_STR); | ||
| 151 | } | ||
| 152 | try { | ||
| 153 | return $delete->execute(); | ||
| 154 | } catch (\PDOException) { | ||
| 155 | return true; | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | protected function doFetch(array $ids): iterable | ||
| 160 | { | ||
| 161 | $connection = $this->getConnection(); | ||
| 162 | |||
| 163 | $now = time(); | ||
| 164 | $expired = []; | ||
| 165 | |||
| 166 | $sql = str_pad('', (\count($ids) << 1) - 1, '?,'); | ||
| 167 | $sql = "SELECT $this->idCol, CASE WHEN $this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > ? THEN $this->dataCol ELSE NULL END FROM $this->table WHERE $this->idCol IN ($sql)"; | ||
| 168 | $stmt = $connection->prepare($sql); | ||
| 169 | $stmt->bindValue($i = 1, $now, \PDO::PARAM_INT); | ||
| 170 | foreach ($ids as $id) { | ||
| 171 | $stmt->bindValue(++$i, $id); | ||
| 172 | } | ||
| 173 | $result = $stmt->execute(); | ||
| 174 | |||
| 175 | if (\is_object($result)) { | ||
| 176 | $result = $result->iterateNumeric(); | ||
| 177 | } else { | ||
| 178 | $stmt->setFetchMode(\PDO::FETCH_NUM); | ||
| 179 | $result = $stmt; | ||
| 180 | } | ||
| 181 | |||
| 182 | foreach ($result as $row) { | ||
| 183 | if (null === $row[1]) { | ||
| 184 | $expired[] = $row[0]; | ||
| 185 | } else { | ||
| 186 | yield $row[0] => $this->marshaller->unmarshall(\is_resource($row[1]) ? stream_get_contents($row[1]) : $row[1]); | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | if ($expired) { | ||
| 191 | $sql = str_pad('', (\count($expired) << 1) - 1, '?,'); | ||
| 192 | $sql = "DELETE FROM $this->table WHERE $this->lifetimeCol + $this->timeCol <= ? AND $this->idCol IN ($sql)"; | ||
| 193 | $stmt = $connection->prepare($sql); | ||
| 194 | $stmt->bindValue($i = 1, $now, \PDO::PARAM_INT); | ||
| 195 | foreach ($expired as $id) { | ||
| 196 | $stmt->bindValue(++$i, $id); | ||
| 197 | } | ||
| 198 | $stmt->execute(); | ||
| 199 | } | ||
| 200 | } | ||
| 201 | |||
| 202 | protected function doHave(string $id): bool | ||
| 203 | { | ||
| 204 | $connection = $this->getConnection(); | ||
| 205 | |||
| 206 | $sql = "SELECT 1 FROM $this->table WHERE $this->idCol = :id AND ($this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > :time)"; | ||
| 207 | $stmt = $connection->prepare($sql); | ||
| 208 | |||
| 209 | $stmt->bindValue(':id', $id); | ||
| 210 | $stmt->bindValue(':time', time(), \PDO::PARAM_INT); | ||
| 211 | $stmt->execute(); | ||
| 212 | |||
| 213 | return (bool) $stmt->fetchColumn(); | ||
| 214 | } | ||
| 215 | |||
| 216 | protected function doClear(string $namespace): bool | ||
| 217 | { | ||
| 218 | $conn = $this->getConnection(); | ||
| 219 | |||
| 220 | if ('' === $namespace) { | ||
| 221 | if ('sqlite' === $this->getDriver()) { | ||
| 222 | $sql = "DELETE FROM $this->table"; | ||
| 223 | } else { | ||
| 224 | $sql = "TRUNCATE TABLE $this->table"; | ||
| 225 | } | ||
| 226 | } else { | ||
| 227 | $sql = "DELETE FROM $this->table WHERE $this->idCol LIKE '$namespace%'"; | ||
| 228 | } | ||
| 229 | |||
| 230 | try { | ||
| 231 | $conn->exec($sql); | ||
| 232 | } catch (\PDOException) { | ||
| 233 | } | ||
| 234 | |||
| 235 | return true; | ||
| 236 | } | ||
| 237 | |||
| 238 | protected function doDelete(array $ids): bool | ||
| 239 | { | ||
| 240 | $sql = str_pad('', (\count($ids) << 1) - 1, '?,'); | ||
| 241 | $sql = "DELETE FROM $this->table WHERE $this->idCol IN ($sql)"; | ||
| 242 | try { | ||
| 243 | $stmt = $this->getConnection()->prepare($sql); | ||
| 244 | $stmt->execute(array_values($ids)); | ||
| 245 | } catch (\PDOException) { | ||
| 246 | } | ||
| 247 | |||
| 248 | return true; | ||
| 249 | } | ||
| 250 | |||
| 251 | protected function doSave(array $values, int $lifetime): array|bool | ||
| 252 | { | ||
| 253 | if (!$values = $this->marshaller->marshall($values, $failed)) { | ||
| 254 | return $failed; | ||
| 255 | } | ||
| 256 | |||
| 257 | $conn = $this->getConnection(); | ||
| 258 | |||
| 259 | $driver = $this->getDriver(); | ||
| 260 | $insertSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)"; | ||
| 261 | |||
| 262 | switch (true) { | ||
| 263 | case 'mysql' === $driver: | ||
| 264 | $sql = $insertSql." ON DUPLICATE KEY UPDATE $this->dataCol = VALUES($this->dataCol), $this->lifetimeCol = VALUES($this->lifetimeCol), $this->timeCol = VALUES($this->timeCol)"; | ||
| 265 | break; | ||
| 266 | case 'oci' === $driver: | ||
| 267 | // DUAL is Oracle specific dummy table | ||
| 268 | $sql = "MERGE INTO $this->table USING DUAL ON ($this->idCol = ?) ". | ||
| 269 | "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?) ". | ||
| 270 | "WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?"; | ||
| 271 | break; | ||
| 272 | case 'sqlsrv' === $driver && version_compare($this->getServerVersion(), '10', '>='): | ||
| 273 | // MERGE is only available since SQL Server 2008 and must be terminated by semicolon | ||
| 274 | // It also requires HOLDLOCK according to http://weblogs.sqlteam.com/dang/archive/2009/01/31/UPSERT-Race-Condition-With-MERGE.aspx | ||
| 275 | $sql = "MERGE INTO $this->table WITH (HOLDLOCK) USING (SELECT 1 AS dummy) AS src ON ($this->idCol = ?) ". | ||
| 276 | "WHEN NOT MATCHED THEN INSERT ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (?, ?, ?, ?) ". | ||
| 277 | "WHEN MATCHED THEN UPDATE SET $this->dataCol = ?, $this->lifetimeCol = ?, $this->timeCol = ?;"; | ||
| 278 | break; | ||
| 279 | case 'sqlite' === $driver: | ||
| 280 | $sql = 'INSERT OR REPLACE'.substr($insertSql, 6); | ||
| 281 | break; | ||
| 282 | case 'pgsql' === $driver && version_compare($this->getServerVersion(), '9.5', '>='): | ||
| 283 | $sql = $insertSql." ON CONFLICT ($this->idCol) DO UPDATE SET ($this->dataCol, $this->lifetimeCol, $this->timeCol) = (EXCLUDED.$this->dataCol, EXCLUDED.$this->lifetimeCol, EXCLUDED.$this->timeCol)"; | ||
| 284 | break; | ||
| 285 | default: | ||
| 286 | $driver = null; | ||
| 287 | $sql = "UPDATE $this->table SET $this->dataCol = :data, $this->lifetimeCol = :lifetime, $this->timeCol = :time WHERE $this->idCol = :id"; | ||
| 288 | break; | ||
| 289 | } | ||
| 290 | |||
| 291 | $now = time(); | ||
| 292 | $lifetime = $lifetime ?: null; | ||
| 293 | try { | ||
| 294 | $stmt = $conn->prepare($sql); | ||
| 295 | } catch (\PDOException $e) { | ||
| 296 | if ($this->isTableMissing($e) && (!$conn->inTransaction() || \in_array($driver, ['pgsql', 'sqlite', 'sqlsrv'], true))) { | ||
| 297 | $this->createTable(); | ||
| 298 | } | ||
| 299 | $stmt = $conn->prepare($sql); | ||
| 300 | } | ||
| 301 | |||
| 302 | // $id and $data are defined later in the loop. Binding is done by reference, values are read on execution. | ||
| 303 | if ('sqlsrv' === $driver || 'oci' === $driver) { | ||
| 304 | $stmt->bindParam(1, $id); | ||
| 305 | $stmt->bindParam(2, $id); | ||
| 306 | $stmt->bindParam(3, $data, \PDO::PARAM_LOB); | ||
| 307 | $stmt->bindValue(4, $lifetime, \PDO::PARAM_INT); | ||
| 308 | $stmt->bindValue(5, $now, \PDO::PARAM_INT); | ||
| 309 | $stmt->bindParam(6, $data, \PDO::PARAM_LOB); | ||
| 310 | $stmt->bindValue(7, $lifetime, \PDO::PARAM_INT); | ||
| 311 | $stmt->bindValue(8, $now, \PDO::PARAM_INT); | ||
| 312 | } else { | ||
| 313 | $stmt->bindParam(':id', $id); | ||
| 314 | $stmt->bindParam(':data', $data, \PDO::PARAM_LOB); | ||
| 315 | $stmt->bindValue(':lifetime', $lifetime, \PDO::PARAM_INT); | ||
| 316 | $stmt->bindValue(':time', $now, \PDO::PARAM_INT); | ||
| 317 | } | ||
| 318 | if (null === $driver) { | ||
| 319 | $insertStmt = $conn->prepare($insertSql); | ||
| 320 | |||
| 321 | $insertStmt->bindParam(':id', $id); | ||
| 322 | $insertStmt->bindParam(':data', $data, \PDO::PARAM_LOB); | ||
| 323 | $insertStmt->bindValue(':lifetime', $lifetime, \PDO::PARAM_INT); | ||
| 324 | $insertStmt->bindValue(':time', $now, \PDO::PARAM_INT); | ||
| 325 | } | ||
| 326 | |||
| 327 | foreach ($values as $id => $data) { | ||
| 328 | try { | ||
| 329 | $stmt->execute(); | ||
| 330 | } catch (\PDOException $e) { | ||
| 331 | if ($this->isTableMissing($e) && (!$conn->inTransaction() || \in_array($driver, ['pgsql', 'sqlite', 'sqlsrv'], true))) { | ||
| 332 | $this->createTable(); | ||
| 333 | } | ||
| 334 | $stmt->execute(); | ||
| 335 | } | ||
| 336 | if (null === $driver && !$stmt->rowCount()) { | ||
| 337 | try { | ||
| 338 | $insertStmt->execute(); | ||
| 339 | } catch (\PDOException) { | ||
| 340 | // A concurrent write won, let it be | ||
| 341 | } | ||
| 342 | } | ||
| 343 | } | ||
| 344 | |||
| 345 | return $failed; | ||
| 346 | } | ||
| 347 | |||
| 348 | /** | ||
| 349 | * @internal | ||
| 350 | */ | ||
| 351 | protected function getId(mixed $key): string | ||
| 352 | { | ||
| 353 | if ('pgsql' !== $this->getDriver()) { | ||
| 354 | return parent::getId($key); | ||
| 355 | } | ||
| 356 | |||
| 357 | if (str_contains($key, "\0") || str_contains($key, '%') || !preg_match('//u', $key)) { | ||
| 358 | $key = rawurlencode($key); | ||
| 359 | } | ||
| 360 | |||
| 361 | return parent::getId($key); | ||
| 362 | } | ||
| 363 | |||
| 364 | private function getConnection(): \PDO | ||
| 365 | { | ||
| 366 | if (!isset($this->conn)) { | ||
| 367 | $this->conn = new \PDO($this->dsn, $this->username, $this->password, $this->connectionOptions); | ||
| 368 | $this->conn->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION); | ||
| 369 | } | ||
| 370 | |||
| 371 | return $this->conn; | ||
| 372 | } | ||
| 373 | |||
| 374 | private function getDriver(): string | ||
| 375 | { | ||
| 376 | return $this->driver ??= $this->getConnection()->getAttribute(\PDO::ATTR_DRIVER_NAME); | ||
| 377 | } | ||
| 378 | |||
| 379 | private function getServerVersion(): string | ||
| 380 | { | ||
| 381 | return $this->serverVersion ??= $this->getConnection()->getAttribute(\PDO::ATTR_SERVER_VERSION); | ||
| 382 | } | ||
| 383 | |||
| 384 | private function isTableMissing(\PDOException $exception): bool | ||
| 385 | { | ||
| 386 | $driver = $this->getDriver(); | ||
| 387 | [$sqlState, $code] = $exception->errorInfo ?? [null, $exception->getCode()]; | ||
| 388 | |||
| 389 | return match ($driver) { | ||
| 390 | 'pgsql' => '42P01' === $sqlState, | ||
| 391 | 'sqlite' => str_contains($exception->getMessage(), 'no such table:'), | ||
| 392 | 'oci' => 942 === $code, | ||
| 393 | 'sqlsrv' => 208 === $code, | ||
| 394 | 'mysql' => 1146 === $code, | ||
| 395 | default => false, | ||
| 396 | }; | ||
| 397 | } | ||
| 398 | } | ||
