{"record":{"id":"8b496fca9f6d80e7","repo":"symfony/http-foundation","slug":"transactional-locks-are-currently-not-implemented-for-pdo","errorCode":null,"errorMessage":"Transactional locks are currently not implemented for PDO driver \"%s\".","messagePattern":"Transactional locks are currently not implemented for PDO driver \"(.+?)\"\\.","errorType":"exception","errorClass":"DomainException","httpStatus":null,"severity":"error","filePath":"Session/Storage/Handler/PdoSessionHandler.php","lineNumber":849,"sourceCode":"     * @throws \\DomainException When an unsupported PDO driver is used\n     */\n    private function getSelectSql(): string\n    {\n        if (self::LOCK_TRANSACTIONAL === $this->lockMode) {\n            $this->beginTransaction();\n\n            switch ($this->driver) {\n                case 'mysql':\n                case 'oci':\n                case 'pgsql':\n                    return \"SELECT $this->dataCol, $this->lifetimeCol FROM $this->table WHERE $this->idCol = :id FOR UPDATE\";\n                case 'sqlsrv':\n                    return \"SELECT $this->dataCol, $this->lifetimeCol FROM $this->table WITH (UPDLOCK, ROWLOCK) WHERE $this->idCol = :id\";\n                case 'sqlite':\n                    // we already locked when starting transaction\n                    break;\n                default:\n                    throw new \\DomainException(\\sprintf('Transactional locks are currently not implemented for PDO driver \"%s\".', $this->driver));\n            }\n        }\n\n        return \"SELECT $this->dataCol, $this->lifetimeCol FROM $this->table WHERE $this->idCol = :id\";\n    }\n\n    /**\n     * Returns an insert statement supported by the database for writing session data.\n     */\n    private function getInsertStatement(#[\\SensitiveParameter] string $sessionId, string $sessionData, int $maxlifetime): \\PDOStatement\n    {\n        switch ($this->driver) {\n            case 'oci':\n                $data = fopen('php://memory', 'r+');\n                fwrite($data, $sessionData);\n                rewind($data);\n                $sql = \"INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, EMPTY_BLOB(), :expiry, :time) RETURNING $this->dataCol into :data\";\n                break;","sourceCodeStart":831,"sourceCodeEnd":867,"githubUrl":"https://github.com/symfony/http-foundation/blob/5aea19cd678fa4140f6108406f1096de5e9ed6e4/Session/Storage/Handler/PdoSessionHandler.php#L831-L867","documentation":"This DomainException comes from PdoSessionHandler::getSelectSql() when lock_mode is LOCK_TRANSACTIONAL and the PDO driver is neither mysql, pgsql, oci, sqlsrv, nor sqlite. getSelectSql() builds the row-locking SELECT (FOR UPDATE / WITH (UPDLOCK, ROWLOCK)) per driver; an unrecognized driver has no known row-lock syntax, so the handler throws instead of silently reading without a lock. It is reached from doRead() during session_start().","triggerScenarios":"PdoSessionHandler on a PDO driver other than mysql/pgsql/oci/sqlsrv/sqlite (e.g. dblib for SQL Server, ibm, custom PDO subclass) with the default LOCK_TRANSACTIONAL lock mode (or lock_mode explicitly set to it), then opening a session.","commonSituations":"Connecting to SQL Server via pdo_dblib (FreeTDS) instead of pdo_sqlsrv, so ATTR_DRIVER_NAME reports 'dblib'; exotic PDO drivers; misconfigured DSNs that pick an unexpected driver; frameworks bundle config moved to a different database platform.","solutions":["Use a supported driver/DSN: switch pdo_dblib to pdo_sqlsrv ('sqlsrv:') for SQL Server, or use mysql/pgsql/oci/sqlite.","If row-level locking is genuinely unavailable, set 'lock_mode' => PdoSessionHandler::LOCK_NONE (accepting weaker concurrency guarantees).","Log/inspect (new PDO(...))->getAttribute(PDO::ATTR_DRIVER_NAME) to confirm which driver name the handler sees and align the DSN accordingly.","Subclass PdoSessionHandler and override getSelectSql()/doRead() to emit correct locking SQL for your driver."],"exampleFix":"// before (FreeTDS driver not supported)\n$pdo = new PDO('dblib:host=mssql;dbname=app', $user, $pass);\n\n// after\n$pdo = new PDO('sqlsrv:Server=mssql;Database=app', $user, $pass);","handlingStrategy":"validation","validationCode":"$driver = $pdo->getAttribute(PDO::ATTR_DRIVER_NAME);\n$supported = ['mysql', 'pgsql', 'oci', 'sqlsrv', 'sqlite'];\nif (!in_array($driver, $supported, true)) {\n    $options['lock_mode'] = PdoSessionHandler::LOCK_NONE; // or switch driver\n}","typeGuard":null,"tryCatchPattern":"try {\n    $session->start();\n} catch (\\DomainException $e) {\n    if (str_contains($e->getMessage(), 'Transactional locks are currently not implemented')) {\n        // fall back to a driver-appropriate handler (e.g. LOCK_NONE or native files)\n    } else {\n        throw $e;\n    }\n}","preventionTips":["Verify the actual PDO driver name at bootstrap; 'dblib' is NOT 'sqlsrv'","Use pdo_sqlsrv for SQL Server so the handler recognizes the driver","Compare PDO::ATTR_DRIVER_NAME against mysql/pgsql/oci/sqlsrv/sqlite before enabling the handler"],"tags":["sessions","pdo","database","configuration","locking"],"backgroundTag":"unsupported-operation","analyzedSha":"5aea19cd678fa4140f6108406f1096de5e9ed6e4","analyzedAt":"2026-09-13T01:52:22.855Z","contentChangedAt":"2026-09-13T01:52:22.855Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}