Commit d833ee14 authored by romanb's avatar romanb

[2.0] Parser work. Drafted logic for multi-table deletes through DQL (for...

[2.0] Parser work. Drafted logic for multi-table deletes through DQL (for Class/Concrete Table Inheritance)
parent c7dbde9f
......@@ -63,6 +63,11 @@ abstract class AbstractEntityPersister
*/
protected $_em;
/**
* Queued inserts.
*
* @var array
*/
protected $_queuedInserts = array();
/**
......@@ -150,13 +155,21 @@ abstract class AbstractEntityPersister
/**
*
* @return Doctrine\ORM\ClassMetadata
* @return Doctrine\ORM\Mapping\ClassMetadata
*/
public function getClassMetadata()
{
return $this->_classMetadata;
}
/**
* Gets the table name to use for temporary identifier tables.
*/
public function getTemporaryIdTableName()
{
//...
}
/**
* Gets the name of the class in the entity hierarchy that owns the field with
* the given name. The owning class is the one that defines the field.
......
......@@ -22,7 +22,7 @@
namespace Doctrine\ORM\Persisters;
/**
* Persister for collections of basic elements / value objects.
* Persister for collections of basic elements / value types.
*
* @author robo
*/
......
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query\AST;
......
......@@ -48,9 +48,14 @@ class InExpression extends Node
$this->_not = $bool;
}
public function getNot()
public function isNot()
{
return $this->_not;
}
public function getPathExpression()
{
return $this->_pathExpression;
}
}
......@@ -10,6 +10,7 @@ namespace Doctrine\ORM\Query\AST;
* Description of JoinCollectionValuedPathExpression
*
* @author robo
* @todo Rename: JoinAssociationPathExpression
*/
class JoinPathExpression extends Node
{
......
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
namespace Doctrine\ORM\Query\AST;
/**
* NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL"
*
* @author robo
*/
class NullComparisonExpression extends Node
{
private $_expression;
private $_not;
public function __construct($expression)
{
$this->_expression = $expression;
}
public function getExpression()
{
return $this->_expression;
}
public function setNot($bool)
{
$this->_not = $bool;
}
public function isNot()
{
return $this->_not;
}
}
......@@ -16,7 +16,7 @@
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Query\AST;
......@@ -26,14 +26,14 @@ namespace Doctrine\ORM\Query\AST;
*
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @link http://www.doctrine-project.org
* @since 2.0
* @version $Revision$
*/
class SimpleStateFieldPathExpression extends Node
{
protected $_identificationVariable = null;
protected $_simpleStateField = null;
private $_identificationVariable = null;
private $_simpleStateField = null;
public function __construct($identificationVariable, $simpleStateField)
{
......
......@@ -7,11 +7,11 @@
namespace Doctrine\ORM\Query\AST;
/**
* Description of PathExpression
* StateFieldPathExpression ::= SimpleStateFieldPathExpression | SimpleStateFieldAssociationPathExpression
*
* @author robo
*/
class PathExpression extends Node
class StateFieldPathExpression extends Node
{
private $_parts;
// Information that is attached during semantical analysis.
......
......@@ -43,7 +43,16 @@ class MultiTableDeleteExecutor extends AbstractExecutor
*/
public function __construct(\Doctrine\ORM\Query\AST $AST)
{
// TODO: Inspect the AST, create the necessary SQL queries and store them
// 1. Create a INSERT ... SELECT statement where the SELECT statement
// selects the identifiers from the temporary ID table and uses the WhereClause of the $AST.
// 2. Create ID subselect statement used in DELETE .... WHERE ... IN (subselect)
// 3. Create and store DELETE statements
/*$subselect = 'SELECT id1, id2 FROM temptable';
foreach ($tableNames as $tableName) {
$this->_sqlStatements[] = 'DELETE FROM ' . $tableName . ' WHERE (id1, id2) IN (subselect)';
}*/
// in $this->_sqlStatements
}
......@@ -56,6 +65,8 @@ class MultiTableDeleteExecutor extends AbstractExecutor
*/
public function execute(\Doctrine\DBAL\Connection $conn, array $params)
{
// 1. Create temporary id table if necessary
//...
}
}
\ No newline at end of file
This diff is collapsed.
......@@ -154,7 +154,7 @@ class SqlWalker
public function walkSelectExpression($selectExpression)
{
$sql = '';
if ($selectExpression->getExpression() instanceof AST\PathExpression) {
if ($selectExpression->getExpression() instanceof AST\StateFieldPathExpression) {
$pathExpression = $selectExpression->getExpression();
if ($pathExpression->isSimpleStateFieldPathExpression()) {
$parts = $pathExpression->getParts();
......@@ -251,7 +251,7 @@ class SqlWalker
{
$sql = '';
$expr = $simpleSelectExpression->getExpression();
if ($expr instanceof AST\PathExpression) {
if ($expr instanceof AST\StateFieldPathExpression) {
//...
} else if ($expr instanceof AST\AggregateExpression) {
if ( ! $simpleSelectExpression->getFieldIdentificationVariable()) {
......@@ -351,6 +351,14 @@ class SqlWalker
else if ($simpleCond instanceof AST\LikeExpression) {
$sql .= $this->walkLikeExpression($simpleCond);
}
else if ($simpleCond instanceof AST\BetweenExpression) {
$sql .= $this->walkBetweenExpression($simpleCond);
}
else if ($simpleCond instanceof AST\InExpression) {
$sql .= $this->walkInExpression($simpleCond);
} else if ($simpleCond instanceof AST\NullComparisonExpression) {
$sql .= $this->walkNullComparisonExpression($simpleCond);
}
// else if ...
} else if ($primary->isConditionalExpression()) {
$sql .= '(' . implode(' OR ', array_map(array(&$this, 'walkConditionalTerm'),
......@@ -359,14 +367,60 @@ class SqlWalker
return $sql;
}
public function walkNullComparisonExpression($nullCompExpr)
{
$sql = '';
if ($nullCompExpr->getExpression() instanceof AST\InputParameter) {
$inputParam = $nullCompExpr->getExpression();
$sql .= ' ' . ($inputParam->isNamed() ? ':' . $inputParam->getName() : '?');
} else {
$sql .= $this->walkPathExpression($nullCompExpr->getExpression());
}
$sql .= ' IS' . ($nullCompExpr->isNot() ? ' NOT' : '') . ' NULL';
return $sql;
}
public function walkInExpression($inExpr)
{
$sql = $this->walkPathExpression($inExpr->getPathExpression());
if ($inExpr->isNot()) $sql .= ' NOT';
$sql .= ' IN (';
if ($inExpr->getSubselect()) {
$sql .= $this->walkSubselect($inExpr->getSubselect());
} else {
//$sql .= implode(', ', array_map(array($this, 'walkLiteral'), $inExpr->getLiterals()));
}
$sql .= ')';
return $sql;
}
public function walkBetweenExpression($betweenExpr)
{
$sql = $this->walkArithmeticExpression($betweenExpr->getBaseExpression());
if ($betweenExpr->getNot()) $sql .= ' NOT';
$sql .= ' BETWEEN ' . $this->walkArithmeticExpression($betweenExpr->getLeftBetweenExpression())
. ' AND ' . $this->walkArithmeticExpression($betweenExpr->getRightBetweenExpression());
return $sql;
}
public function walkLikeExpression($likeExpr)
{
$sql = '';
$stringExpr = $likeExpr->getStringExpression();
if ($stringExpr instanceof AST\PathExpression) {
if ($stringExpr instanceof AST\StateFieldPathExpression) {
$sql .= $this->walkPathExpression($stringExpr);
} //TODO else...
$sql .= ' LIKE ' . $likeExpr->getStringPattern();
if ($likeExpr->isNot()) $sql .= ' NOT';
$sql .= ' LIKE ';
if ($likeExpr->getStringPattern() instanceof AST\InputParameter) {
$inputParam = $likeExpr->getStringPattern();
$sql .= $inputParam->isNamed() ? ':' . $inputParam->getName() : '?';
} else {
$sql .= $likeExpr->getStringPattern();
}
if ($likeExpr->getEscapeChar()) {
$sql .= ' ESCAPE ' . $likeExpr->getEscapeChar();
}
return $sql;
}
......@@ -413,7 +467,7 @@ class SqlWalker
} else if (is_string($primary)) {
//TODO: quote string according to platform
$sql .= $primary;
} else if ($primary instanceof AST\PathExpression) {
} else if ($primary instanceof AST\StateFieldPathExpression) {
$sql .= $this->walkPathExpression($primary);
} else if ($primary instanceof AST\InputParameter) {
if ($primary->isNamed()) {
......@@ -456,9 +510,9 @@ class SqlWalker
$sqlTableAlias = $this->_dqlToSqlAliasMap[$dqlAlias];
$sql .= $sqlTableAlias . '.' . $class->getColumnName($fieldName);
} else if ($pathExpr->isSimpleStateFieldAssociationPathExpression()) {
\Doctrine\Common\DoctrineException::updateMe("Not yet implemented.");
throw \Doctrine\Common\DoctrineException::updateMe("Not yet implemented.");
} else {
\Doctrine\Common\DoctrineException::updateMe("Encountered invalid PathExpression during SQL construction.");
throw \Doctrine\Common\DoctrineException::updateMe("Encountered invalid PathExpression during SQL construction.");
}
return $sql;
}
......
......@@ -88,10 +88,10 @@ class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
'DELETE FROM cms_users c0 WHERE c0.id = ? OR (c0.username = ? OR c0.name = ?)'
);
/*$this->assertSqlGeneration(
'DELETE FROM Doctrine\Tests\Models\CMS\CmsUser WHERE id = ?1',
'DELETE FROM cms_users WHERE id = ?'
);*/
//$this->assertSqlGeneration(
// 'DELETE FROM Doctrine\Tests\Models\CMS\CmsUser WHERE id = ?1',
// 'DELETE FROM cms_users WHERE id = ?'
//);
}
public function testParserIsCaseAgnostic()
......@@ -163,7 +163,7 @@ class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
"DELETE FROM cms_users c0 WHERE c0.id <> ?"
);
}
/*
public function testWithExprAndBetween()
{
$this->assertSqlGeneration(
......@@ -181,60 +181,55 @@ class DeleteSqlGenerationTest extends \Doctrine\Tests\OrmTestCase
{
// "WHERE" Expression LikeExpression
$this->assertSqlGeneration(
'DELETE CmsUser u WHERE u.username NOT LIKE ?',
'DELETE FROM cms_user cu WHERE cu.username NOT LIKE ?'
'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username NOT LIKE ?1',
'DELETE FROM cms_users c0 WHERE c0.username NOT LIKE ?'
);
$this->assertSqlGeneration(
"DELETE CmsUser u WHERE u.username LIKE ? ESCAPE '\\'",
"DELETE FROM cms_user cu WHERE cu.username LIKE ? ESCAPE '\\'"
"DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.username LIKE ?1 ESCAPE '\\'",
"DELETE FROM cms_users c0 WHERE c0.username LIKE ? ESCAPE '\\'"
);
}
public function testWithExprAndIn()
public function testWithExprAndNull()
{
// "WHERE" Expression InExpression
// "WHERE" Expression NullComparisonExpression
$this->assertSqlGeneration(
'DELETE CmsUser u WHERE u.id IN ( ?, ?, ?, ? )',
'DELETE FROM cms_user cu WHERE cu.id IN (?, ?, ?, ?)'
'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name IS NULL',
'DELETE FROM cms_users c0 WHERE c0.name IS NULL'
);
$this->assertSqlGeneration(
'DELETE CmsUser u WHERE u.id NOT IN ( ?, ? )',
'DELETE FROM cms_user cu WHERE cu.id NOT IN (?, ?)'
'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name IS NOT NULL',
'DELETE FROM cms_users c0 WHERE c0.name IS NOT NULL'
);
}
public function testWithExprAndNull()
public function testWithPrimaryAsAtom()
{
// "WHERE" Expression NullComparisonExpression
$this->assertSqlGeneration(
'DELETE CmsUser u WHERE u.name IS NULL',
'DELETE FROM cms_user cu WHERE cu.name IS NULL'
'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE 1 = 1',
'DELETE FROM cms_users c0 WHERE 1 = 1'
);
$this->assertSqlGeneration(
'DELETE CmsUser u WHERE u.name IS NOT NULL',
'DELETE FROM cms_user cu WHERE cu.name IS NOT NULL'
'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE ?1 = 1',
'DELETE FROM cms_users c0 WHERE ? = 1'
);
}
// All previously defined tests used Primary as PathExpression. No need to check it again.
public function testWithPrimaryAsAtom()
/*
public function testWithExprAndIn()
{
// Atom = string | integer | float | boolean | input_parameter
// "WHERE" Expression InExpression
$this->assertSqlGeneration(
'DELETE CmsUser u WHERE 1 = 1',
'DELETE FROM cms_user cu WHERE 1 = 1'
'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id IN ( ?, ?, ?, ? )',
'DELETE FROM cms_users c0 WHERE c0.id IN (?, ?, ?, ?)'
);
$this->assertSqlGeneration(
'DELETE CmsUser u WHERE ? = 1',
'DELETE FROM cms_user cu WHERE ? = 1'
'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id NOT IN ( ?, ? )',
'DELETE FROM cms_users c0 WHERE c0.id NOT IN (?, ?)'
);
}
*/
......
......@@ -110,12 +110,12 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
public function testExistsExpressionSupportedInWherePart()
{
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE EXISTS (SELECT p.id FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.phonenumber = 1234)');
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE EXISTS (SELECT p.phonenumber FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.phonenumber = 1234)');
}
public function testNotExistsExpressionSupportedInWherePart()
{
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE NOT EXISTS (SELECT p.id FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.phonenumber = 1234)');
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE NOT EXISTS (SELECT p.phonenumber FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.phonenumber = 1234)');
}
public function testAggregateFunctionInHavingClause()
......@@ -239,14 +239,14 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
{
$this->assertValidDql("SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name LIKE 'z|%' ESCAPE '|'");
}
/*
public function testImplicitJoinInWhereOnSingleValuedAssociationPathExpression()
{
// This should be allowed because avatar is a single-value association.
// SQL: SELECT ... FROM forum_user fu INNER JOIN forum_avatar fa ON fu.avatar_id = fa.id WHERE fa.id = ?
$this->assertValidDql("SELECT u FROM Doctrine\Tests\Models\Forum\ForumUser u WHERE u.avatar.id = ?");
}
*/
public function testImplicitJoinInWhereOnCollectionValuedPathExpression()
{
// This should be forbidden, because articles is a collection
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment