SQLAzureShardManager.php 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. <?php
  2. namespace Doctrine\DBAL\Sharding\SQLAzure;
  3. use Doctrine\DBAL\Connection;
  4. use Doctrine\DBAL\Sharding\ShardingException;
  5. use Doctrine\DBAL\Sharding\ShardManager;
  6. use Doctrine\DBAL\Types\Type;
  7. use Doctrine\Deprecations\Deprecation;
  8. use RuntimeException;
  9. use function sprintf;
  10. /**
  11. * Sharding using the SQL Azure Federations support.
  12. *
  13. * @deprecated
  14. */
  15. class SQLAzureShardManager implements ShardManager
  16. {
  17. /** @var string */
  18. private $federationName;
  19. /** @var bool */
  20. private $filteringEnabled;
  21. /** @var string */
  22. private $distributionKey;
  23. /** @var string */
  24. private $distributionType;
  25. /** @var Connection */
  26. private $conn;
  27. /** @var string|null */
  28. private $currentDistributionValue;
  29. /**
  30. * @throws ShardingException
  31. */
  32. public function __construct(Connection $conn)
  33. {
  34. Deprecation::trigger(
  35. 'doctrine/dbal',
  36. 'https://github.com/doctrine/dbal/issues/3595',
  37. 'Native Sharding support in DBAL is removed without replacement.'
  38. );
  39. $this->conn = $conn;
  40. $params = $conn->getParams();
  41. if (! isset($params['sharding']['federationName'])) {
  42. throw ShardingException::missingDefaultFederationName();
  43. }
  44. if (! isset($params['sharding']['distributionKey'])) {
  45. throw ShardingException::missingDefaultDistributionKey();
  46. }
  47. if (! isset($params['sharding']['distributionType'])) {
  48. throw ShardingException::missingDistributionType();
  49. }
  50. $this->federationName = $params['sharding']['federationName'];
  51. $this->distributionKey = $params['sharding']['distributionKey'];
  52. $this->distributionType = $params['sharding']['distributionType'];
  53. $this->filteringEnabled = (bool) ($params['sharding']['filteringEnabled'] ?? false);
  54. }
  55. /**
  56. * Gets the name of the federation.
  57. *
  58. * @return string
  59. */
  60. public function getFederationName()
  61. {
  62. return $this->federationName;
  63. }
  64. /**
  65. * Gets the distribution key.
  66. *
  67. * @return string
  68. */
  69. public function getDistributionKey()
  70. {
  71. return $this->distributionKey;
  72. }
  73. /**
  74. * Gets the Doctrine Type name used for the distribution.
  75. *
  76. * @return string
  77. */
  78. public function getDistributionType()
  79. {
  80. return $this->distributionType;
  81. }
  82. /**
  83. * Sets Enabled/Disable filtering on the fly.
  84. *
  85. * @param bool $flag
  86. *
  87. * @return void
  88. */
  89. public function setFilteringEnabled($flag)
  90. {
  91. $this->filteringEnabled = (bool) $flag;
  92. }
  93. /**
  94. * {@inheritDoc}
  95. */
  96. public function selectGlobal()
  97. {
  98. if ($this->conn->isTransactionActive()) {
  99. throw ShardingException::activeTransaction();
  100. }
  101. $sql = 'USE FEDERATION ROOT WITH RESET';
  102. $this->conn->exec($sql);
  103. $this->currentDistributionValue = null;
  104. }
  105. /**
  106. * {@inheritDoc}
  107. */
  108. public function selectShard($distributionValue)
  109. {
  110. if ($this->conn->isTransactionActive()) {
  111. throw ShardingException::activeTransaction();
  112. }
  113. $platform = $this->conn->getDatabasePlatform();
  114. $sql = sprintf(
  115. 'USE FEDERATION %s (%s = %s) WITH RESET, FILTERING = %s;',
  116. $platform->quoteIdentifier($this->federationName),
  117. $platform->quoteIdentifier($this->distributionKey),
  118. $this->conn->quote($distributionValue),
  119. ($this->filteringEnabled ? 'ON' : 'OFF')
  120. );
  121. $this->conn->exec($sql);
  122. $this->currentDistributionValue = $distributionValue;
  123. }
  124. /**
  125. * {@inheritDoc}
  126. */
  127. public function getCurrentDistributionValue()
  128. {
  129. return $this->currentDistributionValue;
  130. }
  131. /**
  132. * {@inheritDoc}
  133. */
  134. public function getShards()
  135. {
  136. $sql = 'SELECT member_id as id,
  137. distribution_name as distribution_key,
  138. CAST(range_low AS CHAR) AS rangeLow,
  139. CAST(range_high AS CHAR) AS rangeHigh
  140. FROM sys.federation_member_distributions d
  141. INNER JOIN sys.federations f ON f.federation_id = d.federation_id
  142. WHERE f.name = ' . $this->conn->quote($this->federationName);
  143. return $this->conn->fetchAllAssociative($sql);
  144. }
  145. /**
  146. * {@inheritDoc}
  147. */
  148. public function queryAll($sql, array $params = [], array $types = [])
  149. {
  150. $shards = $this->getShards();
  151. if (! $shards) {
  152. throw new RuntimeException('No shards found for ' . $this->federationName);
  153. }
  154. $result = [];
  155. $oldDistribution = $this->getCurrentDistributionValue();
  156. foreach ($shards as $shard) {
  157. $this->selectShard($shard['rangeLow']);
  158. foreach ($this->conn->fetchAllAssociative($sql, $params, $types) as $row) {
  159. $result[] = $row;
  160. }
  161. }
  162. if ($oldDistribution === null) {
  163. $this->selectGlobal();
  164. } else {
  165. $this->selectShard($oldDistribution);
  166. }
  167. return $result;
  168. }
  169. /**
  170. * Splits Federation at a given distribution value.
  171. *
  172. * @param mixed $splitDistributionValue
  173. *
  174. * @return void
  175. */
  176. public function splitFederation($splitDistributionValue)
  177. {
  178. $type = Type::getType($this->distributionType);
  179. $sql = 'ALTER FEDERATION ' . $this->getFederationName() . ' ' .
  180. 'SPLIT AT (' . $this->getDistributionKey() . ' = ' .
  181. $this->conn->quote($splitDistributionValue, $type->getBindingType()) . ')';
  182. $this->conn->exec($sql);
  183. }
  184. }