3 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
15 * This software consists of voluntary contributions made by many individuals
16 * and is licensed under the MIT license. For more information, see
17 * <http://www.doctrine-project.org>.
20 namespace Doctrine\DBAL\Sharding\SQLAzure;
22 use Doctrine\DBAL\Sharding\ShardManager;
23 use Doctrine\DBAL\Sharding\ShardingException;
24 use Doctrine\DBAL\Connection;
25 use Doctrine\DBAL\Types\Type;
28 * Sharding using the SQL Azure Federations support.
30 * @author Benjamin Eberlei <kontakt@beberlei.de>
32 class SQLAzureShardManager implements ShardManager
37 private $federationName;
42 private $filteringEnabled;
47 private $distributionKey;
52 private $distributionType;
62 private $currentDistributionValue;
65 * @param Connection $conn
67 public function __construct(Connection $conn)
70 $params = $conn->getParams();
72 if ( ! isset($params['sharding']['federationName'])) {
73 throw ShardingException::missingDefaultFederationName();
76 if ( ! isset($params['sharding']['distributionKey'])) {
77 throw ShardingException::missingDefaultDistributionKey();
80 if ( ! isset($params['sharding']['distributionType'])) {
81 throw ShardingException::missingDistributionType();
84 $this->federationName = $params['sharding']['federationName'];
85 $this->distributionKey = $params['sharding']['distributionKey'];
86 $this->distributionType = $params['sharding']['distributionType'];
87 $this->filteringEnabled = (isset($params['sharding']['filteringEnabled'])) ? (bool)$params['sharding']['filteringEnabled'] : false;
91 * Get name of the federation
95 public function getFederationName()
97 return $this->federationName;
101 * Get the distribution key
105 public function getDistributionKey()
107 return $this->distributionKey;
111 * Get the Doctrine Type name used for the distribution
115 public function getDistributionType()
117 return $this->distributionType;
121 * Enabled/Disable filtering on the fly.
126 public function setFilteringEnabled($flag)
128 $this->filteringEnabled = (bool)$flag;
134 public function selectGlobal()
136 if ($this->conn->isTransactionActive()) {
137 throw ShardingException::activeTransaction();
140 $sql = "USE FEDERATION ROOT WITH RESET";
141 $this->conn->exec($sql);
142 $this->currentDistributionValue = null;
148 public function selectShard($distributionValue)
150 if ($this->conn->isTransactionActive()) {
151 throw ShardingException::activeTransaction();
154 if ($distributionValue === null || is_bool($distributionValue) || !is_scalar($distributionValue)) {
155 throw ShardingException::noShardDistributionValue();
158 $platform = $this->conn->getDatabasePlatform();
160 "USE FEDERATION %s (%s = %s) WITH RESET, FILTERING = %s;",
161 $platform->quoteIdentifier($this->federationName),
162 $platform->quoteIdentifier($this->distributionKey),
163 $this->conn->quote($distributionValue),
164 ($this->filteringEnabled ? 'ON' : 'OFF')
167 $this->conn->exec($sql);
168 $this->currentDistributionValue = $distributionValue;
174 public function getCurrentDistributionValue()
176 return $this->currentDistributionValue;
182 public function getShards()
184 $sql = "SELECT member_id as id,
185 distribution_name as distribution_key,
186 CAST(range_low AS CHAR) AS rangeLow,
187 CAST(range_high AS CHAR) AS rangeHigh
188 FROM sys.federation_member_distributions d
189 INNER JOIN sys.federations f ON f.federation_id = d.federation_id
190 WHERE f.name = " . $this->conn->quote($this->federationName);
191 return $this->conn->fetchAll($sql);
197 public function queryAll($sql, array $params = array(), array $types = array())
199 $shards = $this->getShards();
201 throw new \RuntimeException("No shards found for " . $this->federationName);
205 $oldDistribution = $this->getCurrentDistributionValue();
207 foreach ($shards as $shard) {
208 $this->selectShard($shard['rangeLow']);
209 foreach ($this->conn->fetchAll($sql, $params, $types) as $row) {
214 if ($oldDistribution === null) {
215 $this->selectGlobal();
217 $this->selectShard($oldDistribution);
224 * Split Federation at a given distribution value.
226 * @param mixed $splitDistributionValue
228 public function splitFederation($splitDistributionValue)
230 $type = Type::getType($this->distributionType);
232 $sql = "ALTER FEDERATION " . $this->getFederationName() . " " .
233 "SPLIT AT (" . $this->getDistributionKey() . " = " .
234 $this->conn->quote($splitDistributionValue, $type->getBindingType()) . ")";
235 $this->conn->exec($sql);