forked from rebillar/site-accueil-insa
95 lines
3 KiB
PHP
95 lines
3 KiB
PHP
<?php
|
|
/**
|
|
* Matomo - free/libre analytics platform
|
|
*
|
|
* @link https://matomo.org
|
|
* @license http://www.gnu.org/licenses/gpl-3.0.html GPL v3 or later
|
|
*
|
|
*/
|
|
|
|
namespace Piwik\Db;
|
|
|
|
use Piwik\Db;
|
|
use Piwik\Option;
|
|
|
|
class TransactionLevel
|
|
{
|
|
const TEST_OPTION_NAME = 'TransactionLevel.testOption';
|
|
|
|
private $statusBackup;
|
|
|
|
/**
|
|
* @var \Piwik\Tracker\Db|\Piwik\Db\AdapterInterface|\Piwik\Db $db
|
|
*/
|
|
private $db;
|
|
|
|
/**
|
|
* @param \Piwik\Tracker\Db|\Piwik\Db\AdapterInterface|\Piwik\Db $db
|
|
*/
|
|
public function __construct($db)
|
|
{
|
|
$this->db = $db;
|
|
}
|
|
|
|
public function canLikelySetTransactionLevel()
|
|
{
|
|
$dbSettings = new Db\Settings();
|
|
|
|
return strtolower($dbSettings->getEngine()) === 'innodb';
|
|
}
|
|
|
|
public function setUncommitted()
|
|
{
|
|
if ($this->db->supportsUncommitted === false) {
|
|
// we know "Uncommitted" transaction level is not supported, we don't need to do anything as it won't work to set the status
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
$backup = $this->db->fetchOne('SELECT @@TX_ISOLATION');
|
|
} catch (\Exception $e) {
|
|
try {
|
|
$backup = $this->db->fetchOne('SELECT @@transaction_isolation');
|
|
} catch (\Exception $e) {
|
|
$this->db->supportsUncommitted = false;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
try {
|
|
$this->db->query('SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED');
|
|
$this->statusBackup = $backup;
|
|
|
|
if ($this->db->supportsUncommitted === null) {
|
|
// the first time we need to check if the transaction level actually works by
|
|
// trying to set something w/ the new transaction isolation level
|
|
Option::set(self::TEST_OPTION_NAME, '1');
|
|
}
|
|
|
|
$this->db->supportsUncommitted = true;
|
|
} catch (\Exception $e) {
|
|
// setting the transaction level status did not work
|
|
// catch eg 1665 Cannot execute statement: impossible to write to binary log since BINLOG_FORMAT = STATEMENT and at least one table uses a storage engine limited to row-based logging. InnoDB is limited to row-logging when transaction isolation level is READ COMMITTED or READ UNCOMMITTED
|
|
$this->db->supportsUncommitted = false;
|
|
$this->restorePreviousStatus();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public function restorePreviousStatus()
|
|
{
|
|
if ($this->statusBackup) {
|
|
$value = strtoupper($this->statusBackup);
|
|
$this->statusBackup = null;
|
|
|
|
$value = str_replace('-', ' ', $value);
|
|
if (in_array($value, array('REPEATABLE READ', 'READ COMMITTED', 'SERIALIZABLE'))) {
|
|
$this->db->query('SET SESSION TRANSACTION ISOLATION LEVEL '.$value);
|
|
} elseif ($value !== 'READ UNCOMMITTED') {
|
|
$this->db->query('SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ');
|
|
}
|
|
}
|
|
}
|
|
}
|