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

Savepoints are not supported by this database adapter

Error message

Savepoints are not supported by this database adapter

What it means

createSavepoint() first asks the adapter's dialect supportsSavePoints(); if the dialect reports no savepoint support, SavepointsNotSupported is thrown before any SQL is sent. All bundled dialects (Mysql, Postgresql, Sqlite) inherit the base Phalcon\Db\Dialect::supportsSavepoints() which returns true, so in practice this fires when a custom dialectClass overrides supportsSavePoints() to false or a hand-written DialectInterface implementation returns false/null.

Source

Thrown at phalcon/Db/Adapter/AbstractAdapter.zep:308

            this->dialect->addPrimaryKey(
                tableName,
                schemaName,
                index
            )
        );
    }

    /**
     * Creates a new savepoint
     */
    public function createSavepoint( string name) -> bool
    {
        var dialect;

        let dialect = this->dialect;

        if unlikely !dialect->supportsSavePoints() {
            throw new SavepointsNotSupported();
        }

        return this->{"execute"}(
            dialect->createSavepoint(name)
        );
    }

    /**
     * Creates a table
     */
    public function createTable( string tableName,  string schemaName,  array definition) -> bool
    {
        var columns;

        if unlikely !fetch columns, definition["columns"] {
            throw new TableMustHaveColumn();
        }

View on GitHub (pinned to b7419de9cd)

Solutions

  1. Check $connection->getDialect()->supportsSavePoints() before calling createSavepoint()
  2. If the database does support SAVEPOINT, fix the custom dialect: extend Phalcon\Db\Dialect (inherits true) or override supportsSavePoints() to return true
  3. Avoid nested transactions: do not call setNestedTransactionsWithSavepoints(true) and keep transaction level at 1

Example fix

// before
$connection->createSavepoint('LEVEL_1');

// after
if ($connection->getDialect()->supportsSavePoints()) {
    $connection->createSavepoint('LEVEL_1');
} else {
    // fall back to flat transactions: commit/rollback at level 1 only
}
Defensive patterns

Strategy: validation

Validate before calling

if (!$connection->getDialect()->supportsSavePoints()) {
    // run without savepoints: keep the transaction flat instead of creating one
    return;
}
$connection->createSavepoint($name);

Try / catch

use Phalcon\Db\Exceptions\SavepointsNotSupported;

try {
    $connection->createSavepoint($name);
} catch (SavepointsNotSupported $e) {
    // degrade gracefully: continue in a flat, non-nested transaction
    $logger->warning('Savepoints unavailable, nesting disabled: ' . $e->getMessage());
}

Prevention

When it happens

Trigger: Direct call $connection->createSavepoint('my_savepoint') while the configured dialect reports no savepoint support; or enabling nested transactions with savepoints ($connection->setNestedTransactionsWithSavepoints(true)) and then calling begin() repeatedly so the second nesting level issues createSavepoint().

Common situations: Custom dialect for a database/proxy layer that genuinely lacks SAVEPOINT; test doubles whose supportsSavePoints() returns false by default (PHPUnit mocks return null/false); a hand-implemented DialectInterface that forgot the support methods; adapters for platforms without nested-transaction support.

Related errors


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