[2.0] Parser work. Drafted logic for multi-table deletes through DQL (for Class/Concrete Table Inheritance)
This commit is contained in:
parent
c7dbde9f89
commit
d833ee1464
@ -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
|
||||
*/
|
||||
|
@ -1,7 +1,22 @@
|
||||
<?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
|
||||
{
|
||||
|
39
lib/Doctrine/ORM/Query/AST/NullComparisonExpression.php
Normal file
39
lib/Doctrine/ORM/Query/AST/NullComparisonExpression.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?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
|
||||
|
||||
//...
|
||||
}
|
||||
}
|
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
@ -53,7 +52,7 @@ class Parser
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_pendingPathExpressionsInSelect = array();
|
||||
private $_deferredPathExpressionStacks = array();
|
||||
|
||||
/**
|
||||
* A scanner object.
|
||||
@ -127,7 +126,6 @@ class Parser
|
||||
}
|
||||
|
||||
if ( ! $isMatch) {
|
||||
// No definition for value checking.
|
||||
$this->syntaxError($this->_lexer->getLiteral($token));
|
||||
}
|
||||
|
||||
@ -159,7 +157,6 @@ class Parser
|
||||
|
||||
$this->_lexer->token = null;
|
||||
$this->_lexer->lookahead = null;
|
||||
|
||||
//$this->_errorDistance = self::MIN_ERROR_DISTANCE;
|
||||
}
|
||||
|
||||
@ -340,9 +337,10 @@ class Parser
|
||||
*/
|
||||
private function _SelectStatement()
|
||||
{
|
||||
$this->_beginDeferredPathExpressionStack();
|
||||
$selectClause = $this->_SelectClause();
|
||||
$fromClause = $this->_FromClause();
|
||||
$this->_processPendingPathExpressionsInSelect();
|
||||
$this->_processDeferredPathExpressionStack();
|
||||
|
||||
$whereClause = $this->_lexer->isNextToken(Lexer::T_WHERE) ?
|
||||
$this->_WhereClause() : null;
|
||||
@ -361,16 +359,25 @@ class Parser
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private function _beginDeferredPathExpressionStack()
|
||||
{
|
||||
$this->_deferredPathExpressionStacks[] = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes pending path expressions that were encountered while parsing
|
||||
* select expressions. These will be validated to make sure they are indeed
|
||||
* valid <tt>StateFieldPathExpression</tt>s and additional information
|
||||
* is attached to their AST nodes.
|
||||
*/
|
||||
private function _processPendingPathExpressionsInSelect()
|
||||
private function _processDeferredPathExpressionStack()
|
||||
{
|
||||
$exprStack = array_pop($this->_deferredPathExpressionStacks);
|
||||
$qComps = $this->_parserResult->getQueryComponents();
|
||||
foreach ($this->_pendingPathExpressionsInSelect as $expr) {
|
||||
foreach ($exprStack as $expr) {
|
||||
$parts = $expr->getParts();
|
||||
$numParts = count($parts);
|
||||
$dqlAlias = $parts[0];
|
||||
@ -511,7 +518,7 @@ class Parser
|
||||
//TODO: Can be StringPrimary or EnumPrimary
|
||||
return $this->_StringPrimary();
|
||||
} else {
|
||||
$this->syntaxError('Not yet implemented.');
|
||||
$this->syntaxError('Not yet implemented-1.');
|
||||
//echo "UH OH ...";
|
||||
}
|
||||
}
|
||||
@ -629,7 +636,7 @@ class Parser
|
||||
$fieldIdentificationVariable = $this->_lexer->token['value'];
|
||||
}
|
||||
} else {
|
||||
$expression = $this->_PathExpressionInSelect();
|
||||
$expression = $this->_StateFieldPathExpression();
|
||||
}
|
||||
return new AST\SelectExpression($expression, $fieldIdentificationVariable);
|
||||
}
|
||||
@ -714,7 +721,7 @@ class Parser
|
||||
/**
|
||||
* Special rule that acceps all kinds of path expressions.
|
||||
*/
|
||||
private function _PathExpression()
|
||||
/*private function _StateFieldPathExpression()
|
||||
{
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
$parts = array($this->_lexer->token['value']);
|
||||
@ -723,21 +730,28 @@ class Parser
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
$parts[] = $this->_lexer->token['value'];
|
||||
}
|
||||
$pathExpression = new AST\PathExpression($parts);
|
||||
$pathExpression = new AST\StateFieldPathExpression($parts);
|
||||
return $pathExpression;
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* Special rule that acceps all kinds of path expressions. and defers their
|
||||
* semantical checking until the FROM part has been parsed completely (joins inclusive).
|
||||
* Mainly used for path expressions in the SelectExpressions.
|
||||
*/
|
||||
private function _PathExpressionInSelect()
|
||||
/*private function _PathExpressionInSelect()
|
||||
{
|
||||
$expr = $this->_PathExpression();
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
$parts = array($this->_lexer->token['value']);
|
||||
while ($this->_lexer->isNextToken('.')) {
|
||||
$this->match('.');
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
$parts[] = $this->_lexer->token['value'];
|
||||
}
|
||||
$expr = new AST\StateFieldPathExpression($parts);
|
||||
$this->_pendingPathExpressionsInSelect[] = $expr;
|
||||
return $expr;
|
||||
}
|
||||
}*/
|
||||
|
||||
/**
|
||||
* JoinVariableDeclaration ::= Join [IndexBy]
|
||||
@ -818,14 +832,6 @@ class Parser
|
||||
return $join;
|
||||
}
|
||||
|
||||
/*private function _JoinAssociationPathExpression() {
|
||||
if ($this->_isSingleValuedPathExpression()) {
|
||||
return $this->_JoinSingleValuedAssociationPathExpression();
|
||||
} else {
|
||||
return $this->_JoinCollectionValuedPathExpression();
|
||||
}
|
||||
}*/
|
||||
|
||||
/*private function _isSingleValuedPathExpression()
|
||||
{
|
||||
$parserResult = $this->_parserResult;
|
||||
@ -894,6 +900,21 @@ class Parser
|
||||
*/
|
||||
private function _StateFieldPathExpression()
|
||||
{
|
||||
if ( ! empty($this->_deferredPathExpressionStacks)) {
|
||||
$exprStack = array_pop($this->_deferredPathExpressionStacks);
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
$parts = array($this->_lexer->token['value']);
|
||||
while ($this->_lexer->isNextToken('.')) {
|
||||
$this->match('.');
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
$parts[] = $this->_lexer->token['value'];
|
||||
}
|
||||
$expr = new AST\StateFieldPathExpression($parts);
|
||||
$exprStack[] = $expr;
|
||||
array_push($this->_deferredPathExpressionStacks, $exprStack);
|
||||
return $expr; // EARLY EXIT!
|
||||
}
|
||||
|
||||
$parts = array();
|
||||
$stateFieldSeen = false;
|
||||
$assocSeen = false;
|
||||
@ -928,7 +949,7 @@ class Parser
|
||||
$parts[] = $part;
|
||||
}
|
||||
|
||||
$pathExpr = new AST\PathExpression($parts);
|
||||
$pathExpr = new AST\StateFieldPathExpression($parts);
|
||||
|
||||
if ($assocSeen) {
|
||||
$pathExpr->setIsSimpleStateFieldAssociationPathExpression(true);
|
||||
@ -939,6 +960,28 @@ class Parser
|
||||
return $pathExpr;
|
||||
}
|
||||
|
||||
/**
|
||||
* NullComparisonExpression ::= (SingleValuedPathExpression | InputParameter) "IS" ["NOT"] "NULL"
|
||||
*/
|
||||
private function _NullComparisonExpression()
|
||||
{
|
||||
if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
|
||||
$this->match(Lexer::T_INPUT_PARAMETER);
|
||||
$expr = new AST\InputParameter($this->_lexer->token['value']);
|
||||
} else {
|
||||
//TODO: Support SingleValuedAssociationPathExpression
|
||||
$expr = $this->_StateFieldPathExpression();
|
||||
}
|
||||
$nullCompExpr = new AST\NullComparisonExpression($expr);
|
||||
$this->match(Lexer::T_IS);
|
||||
if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
|
||||
$this->match(Lexer::T_NOT);
|
||||
$nullCompExpr->setNot(true);
|
||||
}
|
||||
$this->match(Lexer::T_NULL);
|
||||
return $nullCompExpr;
|
||||
}
|
||||
|
||||
/**
|
||||
* AggregateExpression ::=
|
||||
* ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] StateFieldPathExpression ")" |
|
||||
@ -957,7 +1000,7 @@ class Parser
|
||||
$isDistinct = true;
|
||||
}
|
||||
// For now we only support a PathExpression here...
|
||||
$pathExp = $this->_PathExpression();
|
||||
$pathExp = $this->_StateFieldPathExpression();
|
||||
$this->match(')');
|
||||
} else {
|
||||
if ($this->_lexer->isNextToken(Lexer::T_AVG)) {
|
||||
@ -988,10 +1031,10 @@ class Parser
|
||||
$this->match(Lexer::T_GROUP);
|
||||
$this->match(Lexer::T_BY);
|
||||
$groupByItems = array();
|
||||
$groupByItems[] = $this->_PathExpression();
|
||||
$groupByItems[] = $this->_StateFieldPathExpression();
|
||||
while ($this->_lexer->isNextToken(',')) {
|
||||
$this->match(',');
|
||||
$groupByItems[] = $this->_PathExpression();
|
||||
$groupByItems[] = $this->_StateFieldPathExpression();
|
||||
}
|
||||
return new AST\GroupByClause($groupByItems);
|
||||
}
|
||||
@ -1286,7 +1329,7 @@ class Parser
|
||||
*/
|
||||
private function _InExpression()
|
||||
{
|
||||
$inExpression = new AST\InExpression($this->_PathExpression());
|
||||
$inExpression = new AST\InExpression($this->_StateFieldPathExpression());
|
||||
if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
|
||||
$this->match(Lexer::T_NOT);
|
||||
$inExpression->setNot(true);
|
||||
@ -1331,7 +1374,9 @@ class Parser
|
||||
*/
|
||||
private function _Subselect()
|
||||
{
|
||||
$this->_beginDeferredPathExpressionStack();
|
||||
$subselect = new AST\Subselect($this->_SimpleSelectClause(), $this->_SubselectFromClause());
|
||||
$this->_processDeferredPathExpressionStack();
|
||||
|
||||
$subselect->setWhereClause(
|
||||
$this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->_WhereClause() : null
|
||||
@ -1410,7 +1455,7 @@ class Parser
|
||||
// SingleValuedPathExpression | IdentificationVariable
|
||||
$peek = $this->_lexer->glimpse();
|
||||
if ($peek['value'] == '.') {
|
||||
return new AST\SimpleSelectExpression($this->_PathExpressionInSelect());
|
||||
return new AST\SimpleSelectExpression($this->_StateFieldPathExpression());
|
||||
} else {
|
||||
$this->match($this->_lexer->lookahead['value']);
|
||||
return new AST\SimpleSelectExpression($this->_lexer->token['value']);
|
||||
@ -1507,7 +1552,7 @@ class Parser
|
||||
$this->syntaxError();
|
||||
}
|
||||
}
|
||||
throw \Doctrine\Common\DoctrineException::updateMe("Not yet implemented.");
|
||||
throw \Doctrine\Common\DoctrineException::updateMe("Not yet implemented2.");
|
||||
//TODO...
|
||||
}
|
||||
|
||||
@ -1598,7 +1643,7 @@ class Parser
|
||||
}
|
||||
|
||||
/**
|
||||
* LikeExpression ::= StringExpression ["NOT"] "LIKE" string ["ESCAPE" char]
|
||||
* LikeExpression ::= StringExpression ["NOT"] "LIKE" (string | input_parameter) ["ESCAPE" char]
|
||||
*/
|
||||
private function _LikeExpression()
|
||||
{
|
||||
@ -1609,8 +1654,13 @@ class Parser
|
||||
$isNot = true;
|
||||
}
|
||||
$this->match(Lexer::T_LIKE);
|
||||
$this->match(Lexer::T_STRING);
|
||||
$stringPattern = $this->_lexer->token['value'];
|
||||
if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
|
||||
$this->match(Lexer::T_INPUT_PARAMETER);
|
||||
$stringPattern = new AST\InputParameter($this->_lexer->token['value']);
|
||||
} else {
|
||||
$this->match(Lexer::T_STRING);
|
||||
$stringPattern = $this->_lexer->token['value'];
|
||||
}
|
||||
$escapeChar = null;
|
||||
if ($this->_lexer->lookahead['type'] === Lexer::T_ESCAPE) {
|
||||
$this->match(Lexer::T_ESCAPE);
|
||||
|
@ -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()
|
||||
{
|
||||
// "WHERE" Expression InExpression
|
||||
$this->assertSqlGeneration(
|
||||
'DELETE CmsUser u WHERE u.id IN ( ?, ?, ?, ? )',
|
||||
'DELETE FROM cms_user cu WHERE cu.id IN (?, ?, ?, ?)'
|
||||
);
|
||||
|
||||
$this->assertSqlGeneration(
|
||||
'DELETE CmsUser u WHERE u.id NOT IN ( ?, ? )',
|
||||
'DELETE FROM cms_user cu WHERE cu.id NOT IN (?, ?)'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function testWithExprAndNull()
|
||||
{
|
||||
// "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 u.name IS NULL',
|
||||
'DELETE FROM cms_users c0 WHERE c0.name IS NULL'
|
||||
);
|
||||
|
||||
$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 u.name IS NOT NULL',
|
||||
'DELETE FROM cms_users c0 WHERE c0.name IS NOT NULL'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// All previously defined tests used Primary as PathExpression. No need to check it again.
|
||||
|
||||
public function testWithPrimaryAsAtom()
|
||||
{
|
||||
// Atom = string | integer | float | boolean | input_parameter
|
||||
$this->assertSqlGeneration(
|
||||
'DELETE CmsUser u WHERE 1 = 1',
|
||||
'DELETE FROM cms_user cu WHERE 1 = 1'
|
||||
'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE 1 = 1',
|
||||
'DELETE FROM cms_users c0 WHERE 1 = 1'
|
||||
);
|
||||
|
||||
$this->assertSqlGeneration(
|
||||
'DELETE CmsUser u WHERE ? = 1',
|
||||
'DELETE FROM cms_user cu WHERE ? = 1'
|
||||
'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE ?1 = 1',
|
||||
'DELETE FROM cms_users c0 WHERE ? = 1'
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
public function testWithExprAndIn()
|
||||
{
|
||||
// "WHERE" Expression InExpression
|
||||
$this->assertSqlGeneration(
|
||||
'DELETE Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id IN ( ?, ?, ?, ? )',
|
||||
'DELETE FROM cms_users c0 WHERE c0.id IN (?, ?, ?, ?)'
|
||||
);
|
||||
|
||||
$this->assertSqlGeneration(
|
||||
'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
|
||||
|
Loading…
Reference in New Issue
Block a user