phalcon/cphalcon · error · SqliteAlterCheckNotSupported
Adding a CHECK constraint to an existing table is not suppor
Error message
Adding a CHECK constraint to an existing table is not supported by SQLite
What it means
The SQLite dialect's addCheck() always throws SqliteAlterCheckNotSupported. SQLite has no ALTER TABLE ... ADD CONSTRAINT CHECK statement: CHECK constraints must be part of the original CREATE TABLE statement. Phalcon surfaces this engine limitation as an exception instead of emitting SQL SQLite would reject.
Source
Thrown at phalcon/Db/Dialect/Sqlite.zep:93
let sql .= " NOT NULL";
} else {
let sql .= " NULL";
}
if !column->isGenerated() && column->isAutoincrement() {
let sql .= " PRIMARY KEY AUTOINCREMENT";
}
return sql;
}
/**
* SQLite cannot ALTER an existing table to add a CHECK constraint;
* the constraint must be declared at CREATE TABLE time.
*/
public function addCheck( string tableName, string schemaName, <CheckInterface> check) -> string
{
throw new SqliteAlterCheckNotSupported();
}
/**
* Generates SQL to add an index to a table
*/
public function addForeignKey( string tableName, string schemaName, <ReferenceInterface> reference) -> string
{
throw new SqliteAlterForeignKeyNotSupported();
}
/**
* Generates SQL to add an index to a table
*/
public function addIndex( string tableName, string schemaName, <IndexInterface> index) -> string
{
var indexType;
string sql;
View on GitHub (pinned to b7419de9cd)
Solutions
- Declare the CHECK in createTable() using a Phalcon\Db\Check constraint in the definition array, so it lands in the CREATE TABLE statement
- If the constraint must be added later, use SQLite's 12-step procedure: create a new table with the constraint, copy data, drop the old table, rename
- Skip addCheck() on SQLite via dialect check: if (!($adapter->getDialect() instanceof Sqlite)) { $adapter->addCheck(...); }
Example fix
// before
$connection->addCheck('robots', null, new Check('chk_price', ['price > 0']));
// after — declare at CREATE TABLE time on SQLite
$connection->createTable('robots', null, [
'columns' => [new Column('price', ['type' => Column::TYPE_DECIMAL, 'size' => 10, 'scale' => 2])],
'checks' => [new Check('chk_price', ['price > 0'])],
]); Defensive patterns
Strategy: type-guard
Validate before calling
if ($adapter->getDialect() instanceof \Phalcon\Db\Dialect\Sqlite) {
// fold the CHECK into CREATE TABLE instead of addCheck()
$definition['checks'] = $definition['checks'] ?? [];
$definition['checks'][] = $check;
} else {
$adapter->addCheck($table, $schema, $check);
} Type guard
function supportsAddCheck(\Phalcon\Db\Adapter\AdapterInterface $adapter): bool
{
return !($adapter->getDialect() instanceof \Phalcon\Db\Dialect\Sqlite);
} Try / catch
try {
$adapter->addCheck($table, $schema, $check);
} catch (\Phalcon\Db\Exceptions\SqliteAlterCheckNotSupported $e) {
// rebuild the table with the CHECK declared inline
rebuildSqliteTableWithChecks($adapter, $table, [$check]);
} Prevention
- Declare all CHECK constraints in createTable() when targeting SQLite
- Gate ALTER-based migration steps on the dialect type
- Run migrations against SQLite in CI to catch unsupported ALTERs early
When it happens
Trigger: Calling $sqliteAdapter->addCheck('robots', null, $check) or any migration/DDL pipeline that invokes addCheck() on an SQLite connection; running cross-database migration code written for MySQL/PostgreSQL against SQLite tests.
Common situations: Test suites running migrations on SQLite while production runs MySQL/Postgres; shared migration files that add CHECK constraints after table creation; CI pipelines switching the adapter to SQLite for speed.
Related errors
- Adding a foreign key constraint to an existing table is not
- Adding a primary key after table has been created is not sup
- Dropping a CHECK constraint is not supported by SQLite
- The table must contain at least one column
- The index 'columns' is required in the definition array
AI-assisted analysis of phalcon/cphalcon@b7419de9cd (2026-08-21).
Data as JSON: /api/errors/f7a6eb94582a9bb3.
Report an issue: GitHub.