1 | <?php |
---|
2 | /* |
---|
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. |
---|
14 | * |
---|
15 | * This software consists of voluntary contributions made by many individuals |
---|
16 | * and is licensed under the LGPL. For more information, see |
---|
17 | * <http://www.doctrine-project.org>. |
---|
18 | */ |
---|
19 | |
---|
20 | namespace Doctrine\ORM\Query\Exec; |
---|
21 | |
---|
22 | use Doctrine\DBAL\Connection, |
---|
23 | Doctrine\ORM\Query\AST; |
---|
24 | |
---|
25 | /** |
---|
26 | * Executes the SQL statements for bulk DQL DELETE statements on classes in |
---|
27 | * Class Table Inheritance (JOINED). |
---|
28 | * |
---|
29 | * @author Roman Borschel <roman@code-factory.org> |
---|
30 | * @license http://www.opensource.org/licenses/lgpl-license.php LGPL |
---|
31 | * @link http://www.doctrine-project.org |
---|
32 | * @since 2.0 |
---|
33 | */ |
---|
34 | class MultiTableDeleteExecutor extends AbstractSqlExecutor |
---|
35 | { |
---|
36 | private $_createTempTableSql; |
---|
37 | private $_dropTempTableSql; |
---|
38 | private $_insertSql; |
---|
39 | |
---|
40 | /** |
---|
41 | * Initializes a new <tt>MultiTableDeleteExecutor</tt>. |
---|
42 | * |
---|
43 | * @param Node $AST The root AST node of the DQL query. |
---|
44 | * @param SqlWalker $sqlWalker The walker used for SQL generation from the AST. |
---|
45 | * @internal Any SQL construction and preparation takes place in the constructor for |
---|
46 | * best performance. With a query cache the executor will be cached. |
---|
47 | */ |
---|
48 | public function __construct(AST\Node $AST, $sqlWalker) |
---|
49 | { |
---|
50 | $em = $sqlWalker->getEntityManager(); |
---|
51 | $conn = $em->getConnection(); |
---|
52 | $platform = $conn->getDatabasePlatform(); |
---|
53 | |
---|
54 | $primaryClass = $em->getClassMetadata($AST->deleteClause->abstractSchemaName); |
---|
55 | $primaryDqlAlias = $AST->deleteClause->aliasIdentificationVariable; |
---|
56 | $rootClass = $em->getClassMetadata($primaryClass->rootEntityName); |
---|
57 | |
---|
58 | $tempTable = $platform->getTemporaryTableName($rootClass->getTemporaryIdTableName()); |
---|
59 | $idColumnNames = $rootClass->getIdentifierColumnNames(); |
---|
60 | $idColumnList = implode(', ', $idColumnNames); |
---|
61 | |
---|
62 | // 1. Create an INSERT INTO temptable ... SELECT identifiers WHERE $AST->getWhereClause() |
---|
63 | $sqlWalker->setSQLTableAlias($primaryClass->getTableName(), 't0', $primaryDqlAlias); |
---|
64 | |
---|
65 | $this->_insertSql = 'INSERT INTO ' . $tempTable . ' (' . $idColumnList . ')' |
---|
66 | . ' SELECT t0.' . implode(', t0.', $idColumnNames); |
---|
67 | |
---|
68 | $rangeDecl = new AST\RangeVariableDeclaration($primaryClass->name, $primaryDqlAlias); |
---|
69 | $fromClause = new AST\FromClause(array(new AST\IdentificationVariableDeclaration($rangeDecl, null, array()))); |
---|
70 | $this->_insertSql .= $sqlWalker->walkFromClause($fromClause); |
---|
71 | |
---|
72 | // Append WHERE clause, if there is one. |
---|
73 | if ($AST->whereClause) { |
---|
74 | $this->_insertSql .= $sqlWalker->walkWhereClause($AST->whereClause); |
---|
75 | } |
---|
76 | |
---|
77 | // 2. Create ID subselect statement used in DELETE ... WHERE ... IN (subselect) |
---|
78 | $idSubselect = 'SELECT ' . $idColumnList . ' FROM ' . $tempTable; |
---|
79 | |
---|
80 | // 3. Create and store DELETE statements |
---|
81 | $classNames = array_merge($primaryClass->parentClasses, array($primaryClass->name), $primaryClass->subClasses); |
---|
82 | foreach (array_reverse($classNames) as $className) { |
---|
83 | $tableName = $em->getClassMetadata($className)->getQuotedTableName($platform); |
---|
84 | $this->_sqlStatements[] = 'DELETE FROM ' . $tableName |
---|
85 | . ' WHERE (' . $idColumnList . ') IN (' . $idSubselect . ')'; |
---|
86 | } |
---|
87 | |
---|
88 | // 4. Store DDL for temporary identifier table. |
---|
89 | $columnDefinitions = array(); |
---|
90 | foreach ($idColumnNames as $idColumnName) { |
---|
91 | $columnDefinitions[$idColumnName] = array( |
---|
92 | 'notnull' => true, |
---|
93 | 'type' => \Doctrine\DBAL\Types\Type::getType($rootClass->getTypeOfColumn($idColumnName)) |
---|
94 | ); |
---|
95 | } |
---|
96 | $this->_createTempTableSql = $platform->getCreateTemporaryTableSnippetSQL() . ' ' . $tempTable . ' (' |
---|
97 | . $platform->getColumnDeclarationListSQL($columnDefinitions) . ')'; |
---|
98 | $this->_dropTempTableSql = $platform->getDropTemporaryTableSQL($tempTable); |
---|
99 | } |
---|
100 | |
---|
101 | /** |
---|
102 | * {@inheritDoc} |
---|
103 | */ |
---|
104 | public function execute(Connection $conn, array $params, array $types) |
---|
105 | { |
---|
106 | $numDeleted = 0; |
---|
107 | |
---|
108 | // Create temporary id table |
---|
109 | $conn->executeUpdate($this->_createTempTableSql); |
---|
110 | |
---|
111 | // Insert identifiers |
---|
112 | $numDeleted = $conn->executeUpdate($this->_insertSql, $params, $types); |
---|
113 | |
---|
114 | // Execute DELETE statements |
---|
115 | foreach ($this->_sqlStatements as $sql) { |
---|
116 | $conn->executeUpdate($sql); |
---|
117 | } |
---|
118 | |
---|
119 | // Drop temporary table |
---|
120 | $conn->executeUpdate($this->_dropTempTableSql); |
---|
121 | |
---|
122 | return $numDeleted; |
---|
123 | } |
---|
124 | } |
---|