phalcon/cphalcon · error · Phalcon\Db\Exceptions\SqliteDropForeignKeyNotSupported

Dropping a foreign key constraint is not supported by SQLite

Error message

Dropping a foreign key constraint is not supported by SQLite

What it means

Phalcon\Db\Dialect\Sqlite::dropForeignKey() always throws SqliteDropForeignKeyNotSupported. SQLite enforces foreign keys but cannot drop them from an existing table; the constraint is part of the CREATE TABLE definition, so removing it requires a full table rebuild.

Source

Thrown at phalcon/Db/Dialect/Sqlite.zep:374

    {
        return "ALTER TABLE " . this->prepareTable(tableName, schemaName)
            . " DROP COLUMN \"" . columnName . "\"";
    }

    /**
     * SQLite cannot DROP a CHECK constraint from an existing table.
     */
    public function dropCheck( string tableName,  string schemaName,  string checkName) -> string
    {
        throw new SqliteDropCheckNotSupported();
    }

    /**
     * Generates SQL to delete a foreign key from a table
     */
    public function dropForeignKey( string tableName,  string schemaName,  string referenceName) -> string
    {
        throw new SqliteDropForeignKeyNotSupported();
    }

    /**
     * Generates SQL to delete an index from a table
     */
    public function dropIndex( string tableName,  string schemaName,  string indexName) -> string
    {
        if schemaName {
            return "DROP INDEX \"" . schemaName . "\".\"" . indexName . "\"";
        }

        return "DROP INDEX \"" . indexName . "\"";
    }

    /**
     * Generates SQL to delete primary key from a table
     */
    public function dropPrimaryKey( string tableName,  string schemaName) -> string

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Branch on $connection->getDialectType() and skip the call for 'sqlite'
  2. Rebuild the table without the FOREIGN KEY clause: CREATE TABLE new ..., INSERT INTO new SELECT * FROM old, DROP TABLE old, ALTER TABLE new RENAME TO old
  3. Model the constraint change as a new table version in a dialect-aware migration instead of an ALTER

Example fix

// before
$connection->dropForeignKey('posts', null, 'fk_posts_user');

// after
if ($connection->getDialectType() === 'sqlite') {
    // rebuild table without the FOREIGN KEY clause, then copy data and rename
} else {
    $connection->dropForeignKey('posts', null, 'fk_posts_user');
}
Defensive patterns

Strategy: try-catch

Validate before calling

if ($connection->getDialectType() !== 'sqlite') {
    $connection->dropForeignKey('posts', null, 'fk_posts_user');
}

Try / catch

try {
    $connection->dropForeignKey('posts', null, 'fk_posts_user');
} catch (\Phalcon\Db\Exceptions\SqliteDropForeignKeyNotSupported $e) {
    // SQLite: rebuild table without the FOREIGN KEY clause, copy data, rename
    $logger->info('Skipped dropForeignKey on SQLite', ['table' => 'posts']);
}

Prevention

When it happens

Trigger: Shared migration code calling $connection->dropForeignKey('posts', null, 'fk_posts_user') on a connection whose dialect is Sqlite; migration steps written for MySQL executed unchanged in SQLite-based test setups.

Common situations: Test suites on :memory: SQLite while production runs MySQL/PostgreSQL; refactoring tools that drop and re-add constraints; multi-tenant products supporting multiple database backends with one migration path.

Related errors


AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21). Data as JSON: /api/errors/37c4d035ddff187d. Report an issue: GitHub.