{"record":{"id":"e568fac48ce2b6bc","repo":"yiisoft/yii2","slug":"yii-db-sqlite-querybuilder-dropforeignkey-is-not","errorCode":null,"errorMessage":"yii\\db\\sqlite\\QueryBuilder::dropForeignKey is not supported by SQLite.","messagePattern":"yii\\\\db\\\\sqlite\\\\QueryBuilder::dropForeignKey is not supported by SQLite\\.","errorType":"exception","errorClass":"yii\\base\\NotSupportedException","httpStatus":null,"severity":"error","filePath":"framework/db/sqlite/QueryBuilder.php","lineNumber":311,"sourceCode":"     * @param string|null $update the ON UPDATE option. Most DBMS support these options: RESTRICT, CASCADE, NO ACTION, SET DEFAULT, SET NULL\n     * @return string the SQL statement for adding a foreign key constraint to an existing table.\n     * @throws NotSupportedException this is not supported by SQLite\n     */\n    public function addForeignKey($name, $table, $columns, $refTable, $refColumns, $delete = null, $update = null)\n    {\n        throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');\n    }\n\n    /**\n     * Builds a SQL statement for dropping a foreign key constraint.\n     * @param string $name the name of the foreign key constraint to be dropped. The name will be properly quoted by the method.\n     * @param string $table the table whose foreign is to be dropped. The name will be properly quoted by the method.\n     * @return string the SQL statement for dropping a foreign key constraint.\n     * @throws NotSupportedException this is not supported by SQLite\n     */\n    public function dropForeignKey($name, $table)\n    {\n        throw new NotSupportedException(__METHOD__ . ' is not supported by SQLite.');\n    }\n\n    /**\n     * Builds a SQL statement for renaming a DB table.\n     *\n     * @param string $table the table to be renamed. The name will be properly quoted by the method.\n     * @param string $newName the new table name. The name will be properly quoted by the method.\n     * @return string the SQL statement for renaming a DB table.\n     */\n    public function renameTable($table, $newName)\n    {\n        return 'ALTER TABLE ' . $this->db->quoteTableName($table) . ' RENAME TO ' . $this->db->quoteTableName($newName);\n    }\n\n    /**\n     * Builds a SQL statement for changing the definition of a column.\n     * @param string $table the table whose column is to be changed. The table name will be properly quoted by the method.\n     * @param string $column the name of the column to be changed. The name will be properly quoted by the method.","sourceCodeStart":293,"sourceCodeEnd":329,"githubUrl":"https://github.com/yiisoft/yii2/blob/66f00d18a29b520f85e8e8f1e32d1e7e7b556cac/framework/db/sqlite/QueryBuilder.php#L293-L329","documentation":"yii\\db\\sqlite\\QueryBuilder::dropForeignKey() unconditionally throws NotSupportedException because SQLite's ALTER TABLE has no DROP CONSTRAINT/DROP FOREIGN KEY form - foreign keys are part of the CREATE TABLE definition. Any migration that drops an FK while running on SQLite hits this.","triggerScenarios":"Executing $this->dropForeignKey('fk_name', 'tbl') in a migration, or calling $db->createCommand()->dropForeignKey(...), when the connection's driver is sqlite - e.g., an in-memory or file test database.","commonSituations":"Test suites configured with sqlite for speed while migrations were written for MySQL/PostgreSQL; CI pipelines running the whole migration chain on sqlite; down() migrations dropping FKs.","solutions":["Guard the migration per driver: skip dropForeignKey() when $this->db->driverName === 'sqlite'.","Apply SQLite's only real path: recreate the table without the FK and copy the data.","Catch NotSupportedException in cross-DB migration runners and mark the step skipped.","Design migrations to keep FK changes at CREATE TABLE time for sqlite deployments."],"exampleFix":"// before\n$this->dropForeignKey('fk_order_user', 'order');\n\n// after\nif ($this->db->driverName !== 'sqlite') {\n    $this->dropForeignKey('fk_order_user', 'order');\n} else {\n    // SQLite: rebuild table without the FK, copy data, swap names\n    $this->execute('CREATE TABLE order_new ... ; INSERT INTO order_new SELECT * FROM \"order\"; DROP TABLE \"order\"; ALTER TABLE order_new RENAME TO \"order\";');\n}","handlingStrategy":"try-catch","validationCode":"if ($db->driverName !== 'sqlite') {\n    $db->createCommand()->dropForeignKey($name, $table)->execute();\n} else {\n    // SQLite: rebuild table without FK, or skip in tests\n}","typeGuard":null,"tryCatchPattern":"try {\n    $db->createCommand()->dropForeignKey($name, $table)->execute();\n} catch (\\yii\\db\\NotSupportedException $e) {\n    // SQLite cannot drop FK constraints; rebuild the table or skip\n}","preventionTips":["Branch migrations on $this->db->driverName when touching constraints.","Keep a sqlite-specific migration path (recreate-and-copy) in shared tooling.","Run the full migration chain against sqlite in CI to catch unsupported steps early."],"tags":["yii2","php","sqlite","database","foreign-key","migration","not-supported"],"backgroundTag":"unsupported-driver-operation","analyzedSha":"66f00d18a29b520f85e8e8f1e32d1e7e7b556cac","analyzedAt":"2026-08-17T05:17:23.470Z","schemaVersion":2},"datasetVersion":"2026-08-17T09:17:11.063Z"}