Repository: yiisoft/yii (language: php)

Issue:
PHP 8 - "There is no active transaction" when transaction is autocommitted
This is related to https://github.com/yiisoft/yii2/issues/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



Discussion / hints:
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:
```php
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

```php
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?  

Fix patch:
diff --git a/CHANGELOG b/CHANGELOG
index 13a5f4c880..0b83ccdfe3 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -4,7 +4,7 @@
 Version 1.1.24 under development
 --------------------------------
 
-- no changes yet.
+- Bug #4339: "There is no active transaction" when transaction is autocommitted (twisted1919)
 
 Version 1.1.23 December 2, 2020
 -------------------------------
diff --git a/framework/db/CDbTransaction.php b/framework/db/CDbTransaction.php
index 15234e4519..136d85e016 100644
--- a/framework/db/CDbTransaction.php
+++ b/framework/db/CDbTransaction.php
@@ -61,7 +61,8 @@ public function commit()
 		if($this->_active && $this->_connection->getActive())
 		{
 			Yii::trace('Committing transaction','system.db.CDbTransaction');
-			$this->_connection->getPdoInstance()->commit();
+			if($this->_connection->getPdoInstance()->inTransaction())
+				$this->_connection->getPdoInstance()->commit();
 			$this->_active=false;
 		}
 		else
@@ -77,7 +78,8 @@ public function rollback()
 		if($this->_active && $this->_connection->getActive())
 		{
 			Yii::trace('Rolling back transaction','system.db.CDbTransaction');
-			$this->_connection->getPdoInstance()->rollBack();
+			if($this->_connection->getPdoInstance()->inTransaction())
+				$this->_connection->getPdoInstance()->rollBack();
 			$this->_active=false;
 		}
 		else


Test patch: