yiisoft/yii

PHP 8 - "There is no active transaction" when transaction is autocommitted

twisted1919 opened this issue · 1 comments

This is related to yiisoft/yii2#18406

As of PHP 8, PDO::commit() and rollBack() will throw a There is no active transaction PDOException if the transaction had been autocommitted, as MySQL will do whenever a schema change is made. Previously they would fail silently.

What steps will reproduce the problem?

  1. Connect to a MySQL database
  2. Call Yii::app()->db->beginTransaction()
  3. Make a schema change, such as add a new column to a table (the transaction will be autocommitted in the process)
  4. Call Yii::app()->db->commit()

What is the expected result?

PHP would move along to the next line of code, regardless of whether the app is running on PHP 5, 7, or 8.

What do you get instead?

A PDOException is thrown with the message There is no active transaction when running PHP 8.

Additional info

Q A
Yii version 1.1.24-dev
PHP version 8.0.0
Operating system Centos 7

I am not sure if this is a good fix or not, but what we did was to modify a bit the CDbTransaction class and basically wrap PDO's commit and rollback method calls in an additional if which makes sure we're still inside a transaction, like:

public function commit()
	{
		if($this->_active && $this->_connection->getActive())
		{
			Yii::trace('Committing transaction','system.db.CDbTransaction');
			if ($this->_connection->getPdoInstance()->inTransaction()) {
				$this->_connection->getPdoInstance()->commit();	
			}
			$this->_active=false;
		}
		else
			throw new CDbException(Yii::t('yii','CDbTransaction is inactive and cannot perform commit or roll back operations.'));
	}

and

public function rollback()
	{
		if($this->_active && $this->_connection->getActive())
		{
			Yii::trace('Rolling back transaction','system.db.CDbTransaction');
			if ($this->_connection->getPdoInstance()->inTransaction()) {
				$this->_connection->getPdoInstance()->rollBack();
			}
			$this->_active=false;
		}
		else
			throw new CDbException(Yii::t('yii','CDbTransaction is inactive and cannot perform commit or roll back operations.'));
	}

Does this seem correct to you?