Browse Source

primary/replica in a definitely non-breaking way (#18106)

tags/2.0.36
Brandon Kelly 4 years ago committed by GitHub
parent
commit
eb956e9c6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      framework/CHANGELOG.md
  2. 4
      framework/db/Command.php
  3. 186
      framework/db/Connection.php
  4. 32
      framework/db/ConnectionDeprecationsTrait.php
  5. 2
      framework/db/Migration.php
  6. 6
      framework/db/Schema.php
  7. 10
      framework/db/cubrid/Schema.php
  8. 2
      framework/db/mysql/QueryBuilder.php
  9. 2
      framework/db/mysql/Schema.php
  10. 2
      framework/db/oci/QueryBuilder.php
  11. 4
      framework/db/oci/Schema.php
  12. 2
      framework/db/pgsql/QueryBuilder.php
  13. 2
      framework/db/sqlite/QueryBuilder.php
  14. 4
      framework/mutex/MysqlMutex.php
  15. 4
      framework/mutex/OracleMutex.php
  16. 4
      framework/mutex/PgsqlMutex.php
  17. 29
      framework/validators/ExistValidator.php
  18. 24
      framework/validators/ForceMasterDbTrait.php
  19. 25
      framework/validators/UniqueValidator.php
  20. 2
      framework/web/DbSession.php
  21. 20
      tests/framework/db/ConnectionTest.php
  22. 4
      tests/framework/db/SchemaTest.php
  23. 2
      tests/framework/db/cubrid/QueryBuilderTest.php
  24. 2
      tests/framework/db/mysql/QueryBuilderTest.php
  25. 32
      tests/framework/db/sqlite/ConnectionTest.php
  26. 2
      tests/framework/validators/ExistValidatorTest.php
  27. 2
      tests/framework/validators/UniqueValidatorTest.php

16
framework/CHANGELOG.md

@ -18,19 +18,19 @@ Yii Framework 2 Change Log
- Bug #18096: Fix InlineValidator with anonymous inline function not working well from EachValidator (trombipeti)
- Enh #18083: Add `Controller::$request` and `$response` (brandonkelly)
- Enh #18102: Use “primary”/“replica” terminology instead of “master”/“slave” (brandonkelly)
- Added `yii\db\Connection::$enableReplicas` and deprecated `$enableSlaves` via magic methods.
- Added `yii\db\Connection::$replicas` and deprecated `$slaves` via magic methods.
- Added `yii\db\Connection::$replicaConfig` and deprecated `$slaveConfig` via magic methods.
- Added `yii\db\Connection::$primaries` and deprecated `$masters` via magic methods.
- Added `yii\db\Connection::$primaryConfig` and deprecated `$masterConfig` via magic methods.
- Added `yii\db\Connection::$shufflePrimaries` and deprecated `$shuffleMasters` via magic methods.
- Added `yii\db\Connection::$enableReplicas` via magic methods and deprecated `$enableSlaves`.
- Added `yii\db\Connection::$replicas` via magic methods and deprecated `$slaves`.
- Added `yii\db\Connection::$replicaConfig` via magic methods and deprecated `$slaveConfig`.
- Added `yii\db\Connection::$primaries` via magic methods and deprecated `$masters`.
- Added `yii\db\Connection::$primaryConfig` via magic methods and deprecated `$masterConfig`.
- Added `yii\db\Connection::$shufflePrimaries` via magic methods and deprecated `$shuffleMasters`.
- Added `yii\db\Connection::getReplicaPdo()` and deprecated `getSlavePdo()`.
- Added `yii\db\Connection::getPrimaryPdo()` and deprecated `getMasterPdo()`.
- Added `yii\db\Connection::getReplica()` and deprecated `getSlave()`.
- Added `yii\db\Connection::getPrimary()` and deprecated `getMaster()`.
- Added `yii\db\Connection::usePrimary()` and deprecated `useMaster()`.
- Added `yii\validators\ExistValidator::$forcePrimaryDb` and deprecated `$forceMasterDb` via magic methods.
- Added `yii\validators\UniqueValidator::$forcePrimaryDb` and deprecated `$forceMasterDb` via magic methods.
- Added `yii\validators\ExistValidator::$forcePrimaryDb` via magic methods and deprecated `$forceMasterDb`.
- Added `yii\validators\UniqueValidator::$forcePrimaryDb` via magic methods and deprecated `$forceMasterDb`.
- Bug #18101: Fix behavior of OUTPUT INSERTED.* for SQL Server query: "insert default values"; correct MSSQL unit tests; turn off profiling echo message in migration test (darkdef)
- Bug #18105: Fix for old trigger in RBAC migration with/without prefixTable (darkdef)

4
framework/db/Command.php

@ -252,9 +252,9 @@ class Command extends Component
$forRead = false;
}
if ($forRead || $forRead === null && $this->db->getSchema()->isReadQuery($sql)) {
$pdo = $this->db->getReplicaPdo();
$pdo = $this->db->getSlavePdo();
} else {
$pdo = $this->db->getPrimaryPdo();
$pdo = $this->db->getMasterPdo();
}
try {

186
framework/db/Connection.php

@ -114,6 +114,43 @@ use yii\caching\CacheInterface;
* @property bool $isActive Whether the DB connection is established. This property is read-only.
* @property string $lastInsertID The row ID of the last row inserted, or the last value retrieved from the
* sequence object. This property is read-only.
* @property bool $enableReplicas whether to enable read/write splitting by using [[replicas]] to read data.
* Note that if [[replicas]] is empty, read/write splitting will NOT be enabled no matter what value this property takes.
* @property array $replicas list of replica connection configurations. Each configuration is used to create a replica DB connection.
* When [[enableReplicas]] is true, one of these configurations will be chosen and used to create a DB connection
* for performing read queries only.
* @property array $replicaConfig the configuration that should be merged with every replica configuration listed in [[replicas]].
* For example,
*
* ```php
* [
* 'username' => 'replica',
* 'password' => 'replica',
* 'attributes' => [
* // use a smaller connection timeout
* PDO::ATTR_TIMEOUT => 10,
* ],
* ]
* ```
* @property array $primaries list of primary connection configurations. Each configuration is used to create a primary DB connection.
* When [[open()]] is called, one of these configurations will be chosen and used to create a DB connection
* which will be used by this object.
* Note that when this property is not empty, the connection setting (e.g. `dsn`, `username`) of this object will
* be ignored.
* @property array $primaryConfig the configuration that should be merged with every primary configuration listed in [[primaries]].
* For example,
*
* ```php
* [
* 'username' => 'primary',
* 'password' => 'primary',
* 'attributes' => [
* // use a smaller connection timeout
* PDO::ATTR_TIMEOUT => 10,
* ],
* ]
* ```
* @property bool $shufflePrimaries whether to shuffle [[primaries]] before getting one.
* @property-read Connection|null $primary The currently active primary connection. `null` is returned if no primary
* connection is available. This property is read-only.
* @property-read PDO $primaryPdo The PDO instance for the currently active primary connection. This property is
@ -128,7 +165,6 @@ use yii\caching\CacheInterface;
* is read-only.
* @property Transaction|null $transaction The currently active transaction. Null if no active transaction.
* This property is read-only.
* @mixin ConnectionDeprecationsTrait
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
@ -344,53 +380,57 @@ class Connection extends Component
/**
* @var bool whether to enable read/write splitting by using [[replicas]] to read data.
* Note that if [[replicas]] is empty, read/write splitting will NOT be enabled no matter what value this property takes.
* @since 2.0.36
* @deprecated since 2.0.36. Use [[enableReplicas]] instead.
*/
public $enableReplicas = true;
public $enableSlaves = true;
/**
* Returns the value of [[enableReplicas]].
* @return bool
* @deprecated since 2.0.36. Use [[enableReplicas]] instead.
* @since 2.0.36
* @internal
*/
public function getEnableSlaves()
public function getEnableReplicas()
{
return $this->enableReplicas;
return $this->enableSlaves;
}
/**
* Sets the value of [[enableReplicas]].
* @param bool $value
* @deprecated since 2.0.36. Use [[enableReplicas]] instead.
* @since 2.0.36
* @internal
*/
public function setEnableSlaves($value)
public function setEnableReplicas($value)
{
$this->enableReplicas = $value;
$this->enableSlaves = $value;
}
/**
* @var array list of replica connection configurations. Each configuration is used to create a replica DB connection.
* When [[enableReplicas]] is true, one of these configurations will be chosen and used to create a DB connection
* for performing read queries only.
* @see enableReplicas
* @see replicaConfig
* @since 2.0.36
* @see enableSlaves
* @see slaveConfig
* @deprecated since 2.0.36. Use [[replicas]] instead.
*/
public $replicas = [];
public $slaves = [];
/**
* Returns the value of [[replicas]].
* @return array
* @deprecated since 2.0.36. Use [[replicas]] instead.
* @since 2.0.36
* @internal
*/
public function getSlaves()
public function getReplicas()
{
return $this->replicas;
return $this->slaves;
}
/**
* Sets the value of [[replicas]].
* @param array $value
* @deprecated since 2.0.36. Use [[replicas]] instead.
* @since 2.0.36
* @internal
*/
public function setSlaves($value)
public function setReplicas($value)
{
$this->replicas = $value;
$this->slaves = $value;
}
/**
* @var array the configuration that should be merged with every replica configuration listed in [[replicas]].
@ -407,26 +447,28 @@ class Connection extends Component
* ]
* ```
*
* @since 2.0.36
* @deprecated since 2.0.36. Use [[replicaConfig]] instead.
*/
public $replicaConfig = [];
public $slaveConfig = [];
/**
* Returns the value of [[replicaConfig]].
* @return array
* @deprecated since 2.0.36. Use [[replicaConfig]] instead.
* @since 2.0.36
* @internal
*/
public function getSlaveConfig()
public function getReplicaConfig()
{
return $this->replicaConfig;
return $this->slaveConfig;
}
/**
* Sets the value of [[replicaConfig]].
* @param array $value
* @deprecated since 2.0.36. Use [[replicaConfig]] instead.
* @since 2.0.36
* @internal
*/
public function setSlaveConfig($value)
public function setReplicaConfig($value)
{
$this->replicaConfig = $value;
$this->slaveConfig = $value;
}
/**
* @var array list of primary connection configurations. Each configuration is used to create a primary DB connection.
@ -434,28 +476,30 @@ class Connection extends Component
* which will be used by this object.
* Note that when this property is not empty, the connection setting (e.g. `dsn`, `username`) of this object will
* be ignored.
* @see primaryConfig
* @see shufflePrimaries
* @since 2.0.36
* @see masterConfig
* @see shuffleMasters
* @deprecated since 2.0.36. Use [[primaries]] instead.
*/
public $primaries = [];
public $masters = [];
/**
* Returns the value of [[primaries]].
* @return array
* @deprecated since 2.0.36. Use [[primaries]] instead.
* @since 2.0.36
* @internal
*/
public function getMasters()
public function getPrimaries()
{
return $this->primaries;
return $this->masters;
}
/**
* Sets the value of [[primaries]].
* @param array $value
* @deprecated since 2.0.36. Use [[primaries]] instead.
* @since 2.0.36
* @internal
*/
public function setMasters($value)
public function setPrimaries($value)
{
$this->primaries = $value;
$this->masters = $value;
}
/**
* @var array the configuration that should be merged with every primary configuration listed in [[primaries]].
@ -472,51 +516,55 @@ class Connection extends Component
* ]
* ```
*
* @since 2.0.36
* @deprecated since 2.0.36. Use [[primaryConfig]] instead.
*/
public $primaryConfig = [];
public $masterConfig = [];
/**
* Returns the value of [[primaryConfig]].
* @return array
* @deprecated since 2.0.36. Use [[primaryConfig]] instead.
* @since 2.0.36
* @internal
*/
public function getMasterConfig()
public function getPrimaryConfig()
{
return $this->primaryConfig;
return $this->masterConfig;
}
/**
* Sets the value of [[primaryConfig]].
* @param array $value
* @deprecated since 2.0.36. Use [[primaryConfig]] instead.
* @since 2.0.36
* @internal
*/
public function setMasterConfig($value)
public function setPrimaryConfig($value)
{
$this->primaryConfig = $value;
$this->masterConfig = $value;
}
/**
* @var bool whether to shuffle [[primaries]] before getting one.
* @since 2.0.11
* @see primaries
* @since 2.0.36
* @see masters
* @deprecated since 2.0.36. Use [[shufflePrimaries]] instead.
*/
public $shufflePrimaries = true;
public $shuffleMasters = true;
/**
* Returns the value of [[shufflePrimaries]].
* @return bool
* @deprecated since 2.0.36. Use [[shufflePrimaries]] instead.
* @since 2.0.36
* @internal
*/
public function getShuffleMasters()
public function getShufflePrimaries()
{
return $this->shufflePrimaries;
return $this->shuffleMasters;
}
/**
* Sets the value of [[shufflePrimaries]].
* @param bool $value
* @deprecated since 2.0.36. Use [[shufflePrimaries]] instead.
* @since 2.0.36
* @internal
*/
public function setShuffleMasters($value)
public function setShufflePrimaries($value)
{
$this->shufflePrimaries = $value;
$this->shuffleMasters = $value;
}
/**
* @var bool whether to enable logging of database queries. Defaults to true.
@ -714,8 +762,8 @@ class Connection extends Component
return;
}
if (!empty($this->primaries)) {
$db = $this->getPrimary();
if (!empty($this->masters)) {
$db = $this->getMaster();
if ($db !== null) {
$this->pdo = $db->pdo;
return;
@ -1087,7 +1135,7 @@ class Connection extends Component
if (($pos = strpos($this->dsn, ':')) !== false) {
$this->_driverName = strtolower(substr($this->dsn, 0, $pos));
} else {
$this->_driverName = strtolower($this->getReplicaPdo()->getAttribute(PDO::ATTR_DRIVER_NAME));
$this->_driverName = strtolower($this->getSlavePdo()->getAttribute(PDO::ATTR_DRIVER_NAME));
}
}
@ -1124,9 +1172,9 @@ class Connection extends Component
*/
public function getReplicaPdo($fallbackToPrimary = true)
{
$db = $this->getReplica(false);
$db = $this->getSlave(false);
if ($db === null) {
return $fallbackToPrimary ? $this->getPrimaryPdo() : null;
return $fallbackToPrimary ? $this->getMasterPdo() : null;
}
return $db->pdo;
@ -1181,12 +1229,12 @@ class Connection extends Component
*/
public function getReplica($fallbackToPrimary = true)
{
if (!$this->enableReplicas) {
if (!$this->enableSlaves) {
return $fallbackToPrimary ? $this : null;
}
if ($this->_replica === false) {
$this->_replica = $this->openFromPool($this->replicas, $this->replicaConfig);
$this->_replica = $this->openFromPool($this->slaves, $this->slaveConfig);
}
return $this->_replica === null && $fallbackToPrimary ? $this : $this->_replica;
@ -1218,9 +1266,9 @@ class Connection extends Component
public function getPrimary()
{
if ($this->_primary === false) {
$this->_primary = $this->shufflePrimaries
? $this->openFromPool($this->primaries, $this->primaryConfig)
: $this->openFromPoolSequentially($this->primaries, $this->primaryConfig);
$this->_primary = $this->shuffleMasters
? $this->openFromPool($this->masters, $this->masterConfig)
: $this->openFromPoolSequentially($this->masters, $this->masterConfig);
}
return $this->_primary;
@ -1259,19 +1307,19 @@ class Connection extends Component
*/
public function usePrimary(callable $callback)
{
if ($this->enableReplicas) {
$this->enableReplicas = false;
if ($this->enableSlaves) {
$this->enableSlaves = false;
try {
$result = call_user_func($callback, $this);
} catch (\Exception $e) {
$this->enableReplicas = true;
$this->enableSlaves = true;
throw $e;
} catch (\Throwable $e) {
$this->enableReplicas = true;
$this->enableSlaves = true;
throw $e;
}
// TODO: use "finally" keyword when miminum required PHP version is >= 5.5
$this->enableReplicas = true;
$this->enableSlaves = true;
} else {
$result = call_user_func($callback, $this);
}

32
framework/db/ConnectionDeprecationsTrait.php

@ -19,38 +19,6 @@ use PDO;
trait ConnectionDeprecationsTrait
{
/**
* @var bool whether to enable read/write splitting by using [[Connection::$replicas]] to read data.
* @deprecated since 2.0.36. Use [[Connection::$enableReplicas]] instead.
*/
public $enableSlaves;
/**
* @var array list of replica connection configurations. Each configuration is used to create a replica DB connection.
* @deprecated since 2.0.36. Use [[Connection::$replicas]] instead.
*/
public $slaves;
/**
* @var array the configuration that should be merged with every replica configuration listed in
* [[Connection::$replicas]].
* @deprecated since 2.0.36. Use [[Connection::$replicaConfig]] instead.
*/
public $slaveConfig;
/**
* @var array list of primary connection configurations. Each configuration is used to create a primary DB connection.
* @deprecated since 2.0.36. Use [[Connection::$primaries]] instead.
*/
public $masters;
/**
* @var array the configuration that should be merged with every primary configuration listed in
* [[Connection::$primaries]].
* @deprecated since 2.0.36. Use [[Connection::$primaryConfig]] instead.
*/
public $masterConfig;
/**
* @var bool whether to shuffle [[Connection::$primaries]] before getting one.
* @deprecated since 2.0.36. Use [[Connection::$shufflePrimaries]] instead.
*/
public $shuffleMasters;
/**
* @var Connection|null The currently active primary connection. `null` is returned if no primary connection is
* available. This property is read-only.
* @deprecated since 2.0.36. Use [[Connection::$primary]] instead.

2
framework/db/Migration.php

@ -89,7 +89,7 @@ class Migration extends Component implements MigrationInterface
parent::init();
$this->db = Instance::ensure($this->db, Connection::className());
$this->db->getSchema()->refresh();
$this->db->enableReplicas = false;
$this->db->enableSlaves = false;
}
/**

6
framework/db/Schema.php

@ -459,7 +459,7 @@ abstract class Schema extends BaseObject
return $str;
}
if (($value = $this->db->getReplicaPdo()->quote($str)) !== false) {
if (($value = $this->db->getSlavePdo()->quote($str)) !== false) {
return $value;
}
@ -696,7 +696,7 @@ abstract class Schema extends BaseObject
public function getServerVersion()
{
if ($this->_serverVersion === null) {
$this->_serverVersion = $this->db->getReplicaPdo()->getAttribute(\PDO::ATTR_SERVER_VERSION);
$this->_serverVersion = $this->db->getSlavePdo()->getAttribute(\PDO::ATTR_SERVER_VERSION);
}
return $this->_serverVersion;
}
@ -810,7 +810,7 @@ abstract class Schema extends BaseObject
*/
protected function normalizePdoRowKeyCase(array $row, $multiple)
{
if ($this->db->getReplicaPdo()->getAttribute(\PDO::ATTR_CASE) !== \PDO::CASE_UPPER) {
if ($this->db->getSlavePdo()->getAttribute(\PDO::ATTR_CASE) !== \PDO::CASE_UPPER) {
return $row;
}

10
framework/db/cubrid/Schema.php

@ -91,7 +91,7 @@ class Schema extends \yii\db\Schema implements ConstraintFinderInterface
*/
protected function findTableNames($schema = '')
{
$pdo = $this->db->getReplicaPdo();
$pdo = $this->db->getSlavePdo();
$tables = $pdo->cubrid_schema(\PDO::CUBRID_SCH_TABLE);
$tableNames = [];
foreach ($tables as $table) {
@ -109,7 +109,7 @@ class Schema extends \yii\db\Schema implements ConstraintFinderInterface
*/
protected function loadTableSchema($name)
{
$pdo = $this->db->getReplicaPdo();
$pdo = $this->db->getSlavePdo();
$tableInfo = $pdo->cubrid_schema(\PDO::CUBRID_SCH_TABLE, $name);
@ -158,7 +158,7 @@ class Schema extends \yii\db\Schema implements ConstraintFinderInterface
*/
protected function loadTablePrimaryKey($tableName)
{
$primaryKey = $this->db->getReplicaPdo()->cubrid_schema(\PDO::CUBRID_SCH_PRIMARY_KEY, $tableName);
$primaryKey = $this->db->getSlavePdo()->cubrid_schema(\PDO::CUBRID_SCH_PRIMARY_KEY, $tableName);
if (empty($primaryKey)) {
return null;
}
@ -182,7 +182,7 @@ class Schema extends \yii\db\Schema implements ConstraintFinderInterface
3 => 'SET NULL',
];
$foreignKeys = $this->db->getReplicaPdo()->cubrid_schema(\PDO::CUBRID_SCH_IMPORTED_KEYS, $tableName);
$foreignKeys = $this->db->getSlavePdo()->cubrid_schema(\PDO::CUBRID_SCH_IMPORTED_KEYS, $tableName);
$foreignKeys = ArrayHelper::index($foreignKeys, null, 'FK_NAME');
ArrayHelper::multisort($foreignKeys, 'KEY_SEQ', SORT_ASC, SORT_NUMERIC);
$result = [];
@ -385,7 +385,7 @@ class Schema extends \yii\db\Schema implements ConstraintFinderInterface
*/
private function loadTableConstraints($tableName, $returnType)
{
$constraints = $this->db->getReplicaPdo()->cubrid_schema(\PDO::CUBRID_SCH_CONSTRAINT, $tableName);
$constraints = $this->db->getSlavePdo()->cubrid_schema(\PDO::CUBRID_SCH_CONSTRAINT, $tableName);
$constraints = ArrayHelper::index($constraints, null, ['TYPE', 'NAME']);
ArrayHelper::multisort($constraints, 'KEY_ORDER', SORT_ASC, SORT_NUMERIC);
$result = [

2
framework/db/mysql/QueryBuilder.php

@ -403,7 +403,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
}
$version = $cache ? $cache->get($key) : null;
if (!$version) {
$version = $this->db->getReplicaPdo()->getAttribute(\PDO::ATTR_SERVER_VERSION);
$version = $this->db->getSlavePdo()->getAttribute(\PDO::ATTR_SERVER_VERSION);
if ($cache) {
$cache->set($key, $version, $this->db->schemaCacheDuration);
}

2
framework/db/mysql/Schema.php

@ -475,7 +475,7 @@ SQL;
protected function isOldMysql()
{
if ($this->_oldMysql === null) {
$version = $this->db->getReplicaPdo()->getAttribute(\PDO::ATTR_SERVER_VERSION);
$version = $this->db->getSlavePdo()->getAttribute(\PDO::ATTR_SERVER_VERSION);
$this->_oldMysql = version_compare($version, '5.1', '<=');
}

2
framework/db/oci/QueryBuilder.php

@ -155,7 +155,7 @@ EOD;
throw new InvalidArgumentException("Can't reset sequence for composite primary key in table: $table");
}
// use primary connection to get the biggest PK value
$value = $this->db->usePrimary(function (Connection $db) use ($tableSchema) {
$value = $this->db->useMaster(function (Connection $db) use ($tableSchema) {
return $db->createCommand(
'SELECT MAX("' . $tableSchema->primaryKey[0] . '") FROM "'. $tableSchema->name . '"'
)->queryScalar();

4
framework/db/oci/Schema.php

@ -57,7 +57,7 @@ class Schema extends \yii\db\Schema implements ConstraintFinderInterface
if ($this->defaultSchema === null) {
$username = $this->db->username;
if (empty($username)) {
$username = isset($this->db->primaries[0]['username']) ? $this->db->primaries[0]['username'] : '';
$username = isset($this->db->masters[0]['username']) ? $this->db->masters[0]['username'] : '';
}
$this->defaultSchema = strtoupper($username);
}
@ -384,7 +384,7 @@ SQL;
if ($this->db->isActive) {
// get the last insert id from the primary connection
$sequenceName = $this->quoteSimpleTableName($sequenceName);
return $this->db->usePrimary(function (Connection $db) use ($sequenceName) {
return $this->db->useMaster(function (Connection $db) use ($sequenceName) {
return $db->createCommand("SELECT {$sequenceName}.CURRVAL FROM DUAL")->queryScalar();
});
} else {

2
framework/db/pgsql/QueryBuilder.php

@ -221,7 +221,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
}
// enable to have ability to alter several tables
$this->db->getPrimaryPdo()->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true);
$this->db->getMasterPdo()->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true);
return $command;
}

2
framework/db/sqlite/QueryBuilder.php

@ -206,7 +206,7 @@ class QueryBuilder extends \yii\db\QueryBuilder
$tableName = $db->quoteTableName($tableName);
if ($value === null) {
$key = $this->db->quoteColumnName(reset($table->primaryKey));
$value = $this->db->usePrimary(function (Connection $db) use ($key, $tableName) {
$value = $this->db->useMaster(function (Connection $db) use ($key, $tableName) {
return $db->createCommand("SELECT MAX($key) FROM $tableName")->queryScalar();
});
} else {

4
framework/mutex/MysqlMutex.php

@ -56,7 +56,7 @@ class MysqlMutex extends DbMutex
*/
protected function acquireLock($name, $timeout = 0)
{
return $this->db->usePrimary(function ($db) use ($name, $timeout) {
return $this->db->useMaster(function ($db) use ($name, $timeout) {
/** @var \yii\db\Connection $db */
return (bool) $db->createCommand(
'SELECT GET_LOCK(:name, :timeout)',
@ -73,7 +73,7 @@ class MysqlMutex extends DbMutex
*/
protected function releaseLock($name)
{
return $this->db->usePrimary(function ($db) use ($name) {
return $this->db->useMaster(function ($db) use ($name) {
/** @var \yii\db\Connection $db */
return (bool) $db->createCommand(
'SELECT RELEASE_LOCK(:name)',

4
framework/mutex/OracleMutex.php

@ -88,7 +88,7 @@ class OracleMutex extends DbMutex
$timeout = abs((int) $timeout);
// inside pl/sql scopes pdo binding not working correctly :(
$this->db->usePrimary(function ($db) use ($name, $timeout, $releaseOnCommit, &$lockStatus) {
$this->db->useMaster(function ($db) use ($name, $timeout, $releaseOnCommit, &$lockStatus) {
/** @var \yii\db\Connection $db */
$db->createCommand(
'DECLARE
@ -115,7 +115,7 @@ END;',
protected function releaseLock($name)
{
$releaseStatus = null;
$this->db->usePrimary(function ($db) use ($name, &$releaseStatus) {
$this->db->useMaster(function ($db) use ($name, &$releaseStatus) {
/** @var \yii\db\Connection $db */
$db->createCommand(
'DECLARE

4
framework/mutex/PgsqlMutex.php

@ -73,7 +73,7 @@ class PgsqlMutex extends DbMutex
list($key1, $key2) = $this->getKeysFromName($name);
return $this->retryAcquire($timeout, function () use ($key1, $key2) {
return $this->db->usePrimary(function ($db) use ($key1, $key2) {
return $this->db->useMaster(function ($db) use ($key1, $key2) {
/** @var \yii\db\Connection $db */
return (bool) $db->createCommand(
'SELECT pg_try_advisory_lock(:key1, :key2)',
@ -92,7 +92,7 @@ class PgsqlMutex extends DbMutex
protected function releaseLock($name)
{
list($key1, $key2) = $this->getKeysFromName($name);
return $this->db->usePrimary(function ($db) use ($key1, $key2) {
return $this->db->useMaster(function ($db) use ($key1, $key2) {
/** @var \yii\db\Connection $db */
return (bool) $db->createCommand(
'SELECT pg_advisory_unlock(:key1, :key2)',

29
framework/validators/ExistValidator.php

@ -44,7 +44,7 @@ use yii\db\QueryInterface;
* ['type_id', 'exist', 'targetRelation' => 'type'],
* ```
*
* @mixin ForceMasterDbTrait
* @property bool $forcePrimaryDb whether this validator is forced to always use the primary DB connection
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
@ -89,26 +89,29 @@ class ExistValidator extends Validator
public $targetAttributeJunction = 'and';
/**
* @var bool whether this validator is forced to always use the primary DB connection
* @since 2.0.36
* @since 2.0.14
* @deprecated since 2.0.36. Use [[forcePrimaryDb]] instead.
*/
public $forcePrimaryDb = true;
public $forceMasterDb = true;
/**
* Returns the value of [[forcePrimaryDb]].
* @return bool
* @deprecated since 2.0.36. Use [[forcePrimaryDb]] instead.
* @since 2.0.36
* @internal
*/
public function getForceMasterDb()
public function getForcePrimaryDb()
{
return $this->forcePrimaryDb;
return $this->forceMasterDb;
}
/**
* Sets the value of [[forcePrimaryDb]].
* @param bool $value
* @deprecated since 2.0.36. Use [[forcePrimaryDb]] instead.
* @since 2.0.36
* @internal
*/
public function setForceMasterDb($value)
public function setForcePrimaryDb($value)
{
$this->forcePrimaryDb = $value;
$this->forceMasterDb = $value;
}
@ -152,8 +155,8 @@ class ExistValidator extends Validator
$relationQuery->andWhere($this->filter);
}
if ($this->forcePrimaryDb && method_exists($model::getDb(), 'usePrimary')) {
$model::getDb()->usePrimary(function() use ($relationQuery, &$exists) {
if ($this->forceMasterDb && method_exists($model::getDb(), 'useMaster')) {
$model::getDb()->useMaster(function() use ($relationQuery, &$exists) {
$exists = $relationQuery->exists();
});
} else {
@ -280,8 +283,8 @@ class ExistValidator extends Validator
$db = $targetClass::getDb();
$exists = false;
if ($this->forcePrimaryDb && method_exists($db, 'usePrimary')) {
$db->usePrimary(function ($db) use ($query, $value, &$exists) {
if ($this->forceMasterDb && method_exists($db, 'useMaster')) {
$db->useMaster(function ($db) use ($query, $value, &$exists) {
$exists = $this->queryValueExists($query, $value);
});
} else {

24
framework/validators/ForceMasterDbTrait.php

@ -1,24 +0,0 @@
<?php
/**
* @link http://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license http://www.yiiframework.com/license/
*/
namespace yii\validators;
/**
* @internal This trait is only used to denote deprecated magic properties of [[ExistValidator]] for IDEs via a
* `@mixin` tag. It is never actually loaded at runtime.
*
* @author Brandon Kelly <brandon@craftcms.com>
* @since 2.0.36
*/
trait ForceMasterDbTrait
{
/**
* @var bool whether this validator is forced to always use primary DB connection
* @deprecated since 2.0.36. Use [[ExistValidator::$forcePrimaryDb]] instead.
*/
public $forceMasterDb = true;
}

25
framework/validators/UniqueValidator.php

@ -37,7 +37,7 @@ use yii\helpers\Inflector;
* ['a1', 'unique', 'targetAttribute' => ['a2', 'a1' => 'a3']]
* ```
*
* @mixin ForceMasterDbTrait
* @property bool $forcePrimaryDb whether this validator is forced to always use the primary DB connection
*
* @author Qiang Xue <qiang.xue@gmail.com>
* @since 2.0
@ -94,26 +94,29 @@ class UniqueValidator extends Validator
public $targetAttributeJunction = 'and';
/**
* @var bool whether this validator is forced to always use the primary DB connection
* @since 2.0.26
* @since 2.0.14
* @deprecated since 2.0.36. Use [[forcePrimaryDb]] instead.
*/
public $forcePrimaryDb = true;
public $forceMasterDb = true;
/**
* Returns the value of [[forcePrimaryDb]].
* @return bool
* @deprecated since 2.0.36. Use [[forcePrimaryDb]] instead.
* @since 2.0.36
* @internal
*/
public function getForceMasterDb()
public function getForcePrimaryDb()
{
return $this->forcePrimaryDb;
return $this->forceMasterDb;
}
/**
* Sets the value of [[forcePrimaryDb]].
* @param bool $value
* @deprecated since 2.0.36. Use [[forcePrimaryDb]] instead.
* @since 2.0.36
* @internal
*/
public function setForceMasterDb($value)
public function setForcePrimaryDb($value)
{
$this->forcePrimaryDb = $value;
$this->forceMasterDb = $value;
}
@ -162,8 +165,8 @@ class UniqueValidator extends Validator
$modelExists = false;
if ($this->forcePrimaryDb && method_exists($db, 'usePrimary')) {
$db->usePrimary(function () use ($targetClass, $conditions, $model, &$modelExists) {
if ($this->forceMasterDb && method_exists($db, 'useMaster')) {
$db->useMaster(function () use ($targetClass, $conditions, $model, &$modelExists) {
$modelExists = $this->modelExists($targetClass, $conditions, $model);
});
} else {

2
framework/web/DbSession.php

@ -114,7 +114,7 @@ class DbSession extends MultiFieldSession
return;
}
$row = $this->db->usePrimary(function() use ($oldID) {
$row = $this->db->useMaster(function() use ($oldID) {
return (new Query())->from($this->sessionTable)
->where(['id' => $oldID])
->createCommand($this->db)

20
tests/framework/db/ConnectionTest.php

@ -416,19 +416,19 @@ abstract class ConnectionTest extends DatabaseTestCase
public function testGetPdoAfterClose()
{
$connection = $this->getConnection();
$connection->replicas[] = [
$connection->slaves[] = [
'dsn' => $connection->dsn,
'username' => $connection->username,
'password' => $connection->password,
];
$this->assertNotNull($connection->getReplicaPdo(false));
$this->assertNotNull($connection->getSlavePdo(false));
$connection->close();
$primaryPdo = $connection->getPrimaryPdo();
$primaryPdo = $connection->getMasterPdo();
$this->assertNotFalse($primaryPdo);
$this->assertNotNull($primaryPdo);
$replicaPdo = $connection->getReplicaPdo(false);
$replicaPdo = $connection->getSlavePdo(false);
$this->assertNotFalse($replicaPdo);
$this->assertNotNull($replicaPdo);
$this->assertNotSame($primaryPdo, $replicaPdo);
@ -440,12 +440,12 @@ abstract class ConnectionTest extends DatabaseTestCase
Yii::$app->set('cache', $cache);
$connection = $this->getConnection(true, false);
$connection->primaries[] = [
$connection->masters[] = [
'dsn' => $connection->dsn,
'username' => $connection->username,
'password' => $connection->password,
];
$connection->shufflePrimaries = false;
$connection->shuffleMasters = false;
$cacheKey = ['yii\db\Connection::openFromPoolSequentially', $connection->dsn];
@ -455,7 +455,7 @@ abstract class ConnectionTest extends DatabaseTestCase
$connection->close();
$cacheKey = ['yii\db\Connection::openFromPoolSequentially', 'host:invalid'];
$connection->primaries[0]['dsn'] = 'host:invalid';
$connection->masters[0]['dsn'] = 'host:invalid';
try {
$connection->open();
} catch (InvalidConfigException $e) {
@ -470,12 +470,12 @@ abstract class ConnectionTest extends DatabaseTestCase
Yii::$app->set('cache', $cache);
$connection = $this->getConnection(true, false);
$connection->primaries[] = [
$connection->masters[] = [
'dsn' => $connection->dsn,
'username' => $connection->username,
'password' => $connection->password,
];
$connection->shufflePrimaries = false;
$connection->shuffleMasters = false;
$connection->serverStatusCache = false;
$cacheKey = ['yii\db\Connection::openFromPoolSequentially', $connection->dsn];
@ -486,7 +486,7 @@ abstract class ConnectionTest extends DatabaseTestCase
$connection->close();
$cacheKey = ['yii\db\Connection::openFromPoolSequentially', 'host:invalid'];
$connection->primaries[0]['dsn'] = 'host:invalid';
$connection->masters[0]['dsn'] = 'host:invalid';
try {
$connection->open();
} catch (InvalidConfigException $e) {

4
tests/framework/db/SchemaTest.php

@ -757,7 +757,7 @@ abstract class SchemaTest extends DatabaseTestCase
}
$connection = $this->getConnection(false);
$connection->getReplicaPdo()->setAttribute(PDO::ATTR_CASE, PDO::CASE_UPPER);
$connection->getSlavePdo()->setAttribute(PDO::ATTR_CASE, PDO::CASE_UPPER);
$constraints = $connection->getSchema()->{'getTable' . ucfirst($type)}($tableName, true);
$this->assertMetadataEquals($expected, $constraints);
}
@ -775,7 +775,7 @@ abstract class SchemaTest extends DatabaseTestCase
}
$connection = $this->getConnection(false);
$connection->getReplicaPdo()->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
$connection->getSlavePdo()->setAttribute(PDO::ATTR_CASE, PDO::CASE_LOWER);
$constraints = $connection->getSchema()->{'getTable' . ucfirst($type)}($tableName, true);
$this->assertMetadataEquals($expected, $constraints);
}

2
tests/framework/db/cubrid/QueryBuilderTest.php

@ -57,7 +57,7 @@ class QueryBuilderTest extends \yiiunit\framework\db\QueryBuilderTest
public function testCommentColumn()
{
$version = $this->getQueryBuilder(false)->db->getReplicaPdo()->getAttribute(\PDO::ATTR_SERVER_VERSION);
$version = $this->getQueryBuilder(false)->db->getSlavePdo()->getAttribute(\PDO::ATTR_SERVER_VERSION);
if (version_compare($version, '10.0', '<')) {
$this->markTestSkipped('Comments on columns are supported starting with CUBRID 10.0.');
return;

2
tests/framework/db/mysql/QueryBuilderTest.php

@ -126,7 +126,7 @@ class QueryBuilderTest extends \yiiunit\framework\db\QueryBuilderTest
/**
* @link https://github.com/yiisoft/yii2/issues/14367
*/
$mysqlVersion = $this->getDb()->getReplicaPdo()->getAttribute(\PDO::ATTR_SERVER_VERSION);
$mysqlVersion = $this->getDb()->getSlavePdo()->getAttribute(\PDO::ATTR_SERVER_VERSION);
$supportsFractionalSeconds = version_compare($mysqlVersion,'5.6.4', '>=');
if ($supportsFractionalSeconds) {
$expectedValues = [

32
tests/framework/db/sqlite/ConnectionTest.php

@ -58,8 +58,8 @@ class ConnectionTest extends \yiiunit\framework\db\ConnectionTest
$db = $this->preparePrimaryReplica($primaryCount, $replicaCount);
$this->assertInstanceOf(Connection::className(), $db->getReplica());
$this->assertTrue($db->getReplica()->isActive);
$this->assertInstanceOf(Connection::className(), $db->getSlave());
$this->assertTrue($db->getSlave()->isActive);
$this->assertFalse($db->isActive);
// test SELECT uses replica
@ -70,13 +70,13 @@ class ConnectionTest extends \yiiunit\framework\db\ConnectionTest
$db->createCommand("UPDATE profile SET description='test' WHERE id=1")->execute();
$this->assertTrue($db->isActive);
if ($primaryCount > 0) {
$this->assertInstanceOf(Connection::className(), $db->getPrimary());
$this->assertTrue($db->getPrimary()->isActive);
$this->assertInstanceOf(Connection::className(), $db->getMaster());
$this->assertTrue($db->getMaster()->isActive);
} else {
$this->assertNull($db->getPrimary());
$this->assertNull($db->getMaster());
}
$this->assertNotEquals('test', $db->createCommand('SELECT description FROM profile WHERE id=1')->queryScalar());
$result = $db->usePrimary(function (Connection $db) {
$result = $db->useMaster(function (Connection $db) {
return $db->createCommand('SELECT description FROM profile WHERE id=1')->queryScalar();
});
$this->assertEquals('test', $result);
@ -96,7 +96,7 @@ class ConnectionTest extends \yiiunit\framework\db\ConnectionTest
$customer = Customer::findOne(1);
$this->assertInstanceOf(Customer::className(), $customer);
$this->assertEquals('user1', $customer->name);
$result = $db->usePrimary(function () {
$result = $db->useMaster(function () {
return Customer::findOne(1)->name;
});
$this->assertEquals('test', $result);
@ -115,10 +115,10 @@ class ConnectionTest extends \yiiunit\framework\db\ConnectionTest
for ($i = $nodesCount * $retryPerNode; $i-- > 0;) {
$db = $this->preparePrimaryReplica($primariesCount, $replicasCount);
$db->shufflePrimaries = true;
$db->shuffleMasters = true;
$hit_replicas[$db->getReplica()->dsn] = true;
$hit_primaries[$db->getPrimary()->dsn] = true;
$hit_replicas[$db->getSlave()->dsn] = true;
$hit_primaries[$db->getMaster()->dsn] = true;
if (\count($hit_replicas) === $replicasCount && \count($hit_primaries) === $primariesCount) {
break;
}
@ -140,10 +140,10 @@ class ConnectionTest extends \yiiunit\framework\db\ConnectionTest
for ($i = $nodesCount * $retryPerNode; $i-- > 0;) {
$db = $this->preparePrimaryReplica($primariesCount, $replicasCount);
$db->shufflePrimaries = false;
$db->shuffleMasters = false;
$hit_replicas[$db->getReplica()->dsn] = true;
$hit_primaries[$db->getPrimary()->dsn] = true;
$hit_replicas[$db->getSlave()->dsn] = true;
$hit_primaries[$db->getMaster()->dsn] = true;
if (\count($hit_replicas) === $replicasCount) {
break;
}
@ -157,16 +157,16 @@ class ConnectionTest extends \yiiunit\framework\db\ConnectionTest
public function testRestorePrimaryAfterException()
{
$db = $this->preparePrimaryReplica(1, 1);
$this->assertTrue($db->enableReplicas);
$this->assertTrue($db->enableSlaves);
try {
$db->usePrimary(function (Connection $db) {
$db->useMaster(function (Connection $db) {
throw new \Exception('fail');
});
$this->fail('Exception was caught somewhere');
} catch (\Exception $e) {
// ok
}
$this->assertTrue($db->enableReplicas);
$this->assertTrue($db->enableSlaves);
}
/**

2
tests/framework/validators/ExistValidatorTest.php

@ -242,7 +242,7 @@ abstract class ExistValidatorTest extends DatabaseTestCase
ActiveRecord::$db = $connection;
$model = null;
$connection->usePrimary(function() use (&$model) {
$connection->useMaster(function() use (&$model) {
$model = ValidatorTestMainModel::findOne(2);
});

2
tests/framework/validators/UniqueValidatorTest.php

@ -470,7 +470,7 @@ abstract class UniqueValidatorTest extends DatabaseTestCase
ActiveRecord::$db = $connection;
$model = null;
$connection->usePrimary(function() use (&$model) {
$connection->useMaster(function() use (&$model) {
$model = WithCustomer::find()->one();
});

Loading…
Cancel
Save