[2.0] Parser work.
This commit is contained in:
parent
bffd76d704
commit
b718cd1a63
53
lib/Doctrine/ORM/Query/AST/BetweenExpression.php
Normal file
53
lib/Doctrine/ORM/Query/AST/BetweenExpression.php
Normal file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* Description of BetweenExpression
|
||||
*
|
||||
* @author robo
|
||||
*/
|
||||
class BetweenExpression extends Node
|
||||
{
|
||||
private $_baseExpression;
|
||||
private $_leftBetweenExpression;
|
||||
private $_rightBetweenExpression;
|
||||
private $_not;
|
||||
|
||||
public function __construct($baseExpr, $leftExpr, $rightExpr)
|
||||
{
|
||||
$this->_baseExpression = $baseExpr;
|
||||
$this->_leftBetweenExpression = $leftExpr;
|
||||
$this->_rightBetweenExpression = $rightExpr;
|
||||
}
|
||||
|
||||
public function getBaseExpression()
|
||||
{
|
||||
return $this->_baseExpression;
|
||||
}
|
||||
|
||||
public function getLeftBetweenExpression()
|
||||
{
|
||||
return $this->_leftBetweenExpression;
|
||||
}
|
||||
|
||||
public function getRightBetweenExpression()
|
||||
{
|
||||
return $this->_rightBetweenExpression;
|
||||
}
|
||||
|
||||
public function setNot($bool)
|
||||
{
|
||||
$this->_not = $bool;
|
||||
}
|
||||
|
||||
public function getNot()
|
||||
{
|
||||
return $this->_not;
|
||||
}
|
||||
}
|
||||
|
37
lib/Doctrine/ORM/Query/AST/DeleteClause.php
Normal file
37
lib/Doctrine/ORM/Query/AST/DeleteClause.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName [["AS"] AliasIdentificationVariable]
|
||||
*/
|
||||
class DeleteClause extends Node
|
||||
{
|
||||
private $_abstractSchemaName;
|
||||
private $_aliasIdentificationVariable;
|
||||
|
||||
public function __construct($abstractSchemaName)
|
||||
{
|
||||
$this->_abstractSchemaName = $abstractSchemaName;
|
||||
}
|
||||
|
||||
public function getAbstractSchemaName()
|
||||
{
|
||||
return $this->_abstractSchemaName;
|
||||
}
|
||||
|
||||
public function getAliasIdentificationVariable()
|
||||
{
|
||||
return $this->_aliasIdentificationVariable;
|
||||
}
|
||||
|
||||
public function setAliasIdentificationVariable($alias)
|
||||
{
|
||||
$this->_aliasIdentificationVariable = $alias;
|
||||
}
|
||||
}
|
||||
|
@ -32,11 +32,10 @@ namespace Doctrine\ORM\Query\AST;
|
||||
*/
|
||||
class DeleteStatement extends Node
|
||||
{
|
||||
protected $_deleteClause;
|
||||
protected $_whereClause;
|
||||
private $_deleteClause;
|
||||
private $_whereClause;
|
||||
|
||||
/* Setters */
|
||||
public function setDeleteClause($deleteClause)
|
||||
public function __construct($deleteClause)
|
||||
{
|
||||
$this->_deleteClause = $deleteClause;
|
||||
}
|
||||
@ -46,7 +45,6 @@ class DeleteStatement extends Node
|
||||
$this->_whereClause = $whereClause;
|
||||
}
|
||||
|
||||
/* Getters */
|
||||
public function getDeleteClause()
|
||||
{
|
||||
return $this->_deleteClause;
|
||||
@ -56,14 +54,4 @@ class DeleteStatement extends Node
|
||||
{
|
||||
return $this->_whereClause;
|
||||
}
|
||||
|
||||
/* REMOVE ME LATER. COPIED METHODS FROM SPLIT OF PRODUCTION INTO "AST" AND "PARSER" */
|
||||
|
||||
public function buildSql()
|
||||
{
|
||||
// The 1=1 is needed to workaround the affected_rows in MySQL.
|
||||
// Simple "DELETE FROM table_name" gives 0 affected rows.
|
||||
return $this->_deleteClause->buildSql() . (($this->_whereClause !== null)
|
||||
? ' ' . $this->_whereClause->buildSql() : ' WHERE 1 = 1');
|
||||
}
|
||||
}
|
27
lib/Doctrine/ORM/Query/AST/HavingClause.php
Normal file
27
lib/Doctrine/ORM/Query/AST/HavingClause.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* Description of HavingClause
|
||||
*
|
||||
* @author robo
|
||||
*/
|
||||
class HavingClause extends Node
|
||||
{
|
||||
private $_conditionalExpression;
|
||||
|
||||
public function __construct($conditionalExpression)
|
||||
{
|
||||
$this->_conditionalExpression = $conditionalExpression;
|
||||
}
|
||||
|
||||
public function getConditionalExpression()
|
||||
{
|
||||
return $this->_conditionalExpression;
|
||||
}
|
||||
}
|
27
lib/Doctrine/ORM/Query/AST/OrderByClause.php
Normal file
27
lib/Doctrine/ORM/Query/AST/OrderByClause.php
Normal file
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}*
|
||||
*
|
||||
* @author robo
|
||||
*/
|
||||
class OrderByClause extends Node
|
||||
{
|
||||
private $_orderByItems = array();
|
||||
|
||||
public function __construct(array $orderByItems)
|
||||
{
|
||||
$this->_orderByItems = $orderByItems;
|
||||
}
|
||||
|
||||
public function getOrderByItems()
|
||||
{
|
||||
return $this->_orderByItems;
|
||||
}
|
||||
}
|
49
lib/Doctrine/ORM/Query/AST/OrderByItem.php
Normal file
49
lib/Doctrine/ORM/Query/AST/OrderByItem.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* OrderByItem ::= StateFieldPathExpression ["ASC" | "DESC"]
|
||||
*
|
||||
* @author robo
|
||||
*/
|
||||
class OrderByItem extends Node
|
||||
{
|
||||
private $_pathExpr;
|
||||
private $_asc;
|
||||
private $_desc;
|
||||
|
||||
public function __construct($pathExpr)
|
||||
{
|
||||
$this->_pathExpr = $pathExpr;
|
||||
}
|
||||
|
||||
public function getStateFieldPathExpression()
|
||||
{
|
||||
return $this->_pathExpr;
|
||||
}
|
||||
|
||||
public function setAsc($bool)
|
||||
{
|
||||
$this->_asc = $bool;
|
||||
}
|
||||
|
||||
public function isAsc()
|
||||
{
|
||||
return $this->_asc;
|
||||
}
|
||||
|
||||
public function setDesc($bool)
|
||||
{
|
||||
$this->_desc = $bool;
|
||||
}
|
||||
|
||||
public function isDesc()
|
||||
{
|
||||
return $this->_desc;
|
||||
}
|
||||
}
|
@ -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,7 +26,7 @@ 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$
|
||||
*/
|
||||
|
@ -22,7 +22,7 @@
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* SimpleSelectClause ::= "SELECT" [DISTINCT"] SimpleSelectExpression
|
||||
* SimpleSelectClause ::= "SELECT" ["DISTINCT"] SimpleSelectExpression
|
||||
*
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
|
58
lib/Doctrine/ORM/Query/AST/SimpleSelectExpression.php
Normal file
58
lib/Doctrine/ORM/Query/AST/SimpleSelectExpression.php
Normal file
@ -0,0 +1,58 @@
|
||||
<?php
|
||||
/*
|
||||
* $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;
|
||||
|
||||
/**
|
||||
* SimpleSelectExpression ::= StateFieldPathExpression | IdentificationVariable
|
||||
* | (AggregateExpression [["AS"] FieldAliasIdentificationVariable])
|
||||
*
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link http://www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class SimpleSelectExpression extends Node
|
||||
{
|
||||
private $_expression;
|
||||
private $_fieldIdentificationVariable;
|
||||
|
||||
public function __construct($expression)
|
||||
{
|
||||
$this->_expression = $expression;
|
||||
}
|
||||
|
||||
public function getExpression()
|
||||
{
|
||||
return $this->_expression;
|
||||
}
|
||||
|
||||
public function getFieldIdentificationVariable()
|
||||
{
|
||||
return $this->_fieldIdentificationVariable;
|
||||
}
|
||||
|
||||
public function setFieldIdentificationVariable($fieldAlias)
|
||||
{
|
||||
$this->_fieldIdentificationVariable = $fieldAlias;
|
||||
}
|
||||
}
|
@ -40,7 +40,7 @@ class SubselectFromClause extends Node
|
||||
}
|
||||
|
||||
/* Getters */
|
||||
public function geSubselectIdentificationVariableDeclarations()
|
||||
public function getSubselectIdentificationVariableDeclarations()
|
||||
{
|
||||
return $this->_identificationVariableDeclarations;
|
||||
}
|
||||
|
44
lib/Doctrine/ORM/Query/AST/UpdateClause.php
Normal file
44
lib/Doctrine/ORM/Query/AST/UpdateClause.php
Normal file
@ -0,0 +1,44 @@
|
||||
<?php
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* UpdateClause ::= "UPDATE" AbstractSchemaName [["AS"] AliasIdentificationVariable] "SET" UpdateItem {"," UpdateItem}*
|
||||
*/
|
||||
class UpdateClause extends Node
|
||||
{
|
||||
private $_abstractSchemaName;
|
||||
private $_aliasIdentificationVariable;
|
||||
private $_updateItems = array();
|
||||
|
||||
public function __construct($abstractSchemaName, array $updateItems)
|
||||
{
|
||||
$this->_abstractSchemaName = $abstractSchemaName;
|
||||
$this->_updateItems = $updateItems;
|
||||
}
|
||||
|
||||
public function getAbstractSchemaName()
|
||||
{
|
||||
return $this->_abstractSchemaName;
|
||||
}
|
||||
|
||||
public function getAliasIdentificationVariable()
|
||||
{
|
||||
return $this->_aliasIdentificationVariable;
|
||||
}
|
||||
|
||||
public function setAliasIdentificationVariable($alias)
|
||||
{
|
||||
$this->_aliasIdentificationVariable = $alias;
|
||||
}
|
||||
|
||||
public function getUpdateItems()
|
||||
{
|
||||
return $this->_updateItems;
|
||||
}
|
||||
}
|
||||
|
46
lib/Doctrine/ORM/Query/AST/UpdateItem.php
Normal file
46
lib/Doctrine/ORM/Query/AST/UpdateItem.php
Normal file
@ -0,0 +1,46 @@
|
||||
<?php
|
||||
/*
|
||||
* To change this template, choose Tools | Templates
|
||||
* and open the template in the editor.
|
||||
*/
|
||||
|
||||
namespace Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* UpdateItem ::= [IdentificationVariable "."] {StateField | SingleValuedAssociationField} "=" NewValue
|
||||
*
|
||||
* @author robo
|
||||
*/
|
||||
class UpdateItem extends Node
|
||||
{
|
||||
private $_identificationVariable;
|
||||
private $_field;
|
||||
private $_newValue;
|
||||
|
||||
public function __construct($field, $newValue)
|
||||
{
|
||||
$this->_field = $field;
|
||||
$this->_newValue = $newValue;
|
||||
}
|
||||
|
||||
public function setIdentificationVariable($identVar)
|
||||
{
|
||||
$this->_identificationVariable = $identVar;
|
||||
}
|
||||
|
||||
public function getIdentificationVariable()
|
||||
{
|
||||
return $this->_identificationVariable;
|
||||
}
|
||||
|
||||
public function getField()
|
||||
{
|
||||
return $this->_field;
|
||||
}
|
||||
|
||||
public function getNewValue()
|
||||
{
|
||||
return $this->_newValue;
|
||||
}
|
||||
}
|
||||
|
@ -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,17 +26,16 @@ 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 UpdateStatement extends Node
|
||||
{
|
||||
protected $_updateClause;
|
||||
protected $_whereClause;
|
||||
private $_updateClause;
|
||||
private $_whereClause;
|
||||
|
||||
/* Setters */
|
||||
public function setUpdateClause($updateClause)
|
||||
public function __construct($updateClause)
|
||||
{
|
||||
$this->_updateClause = $updateClause;
|
||||
}
|
||||
@ -46,7 +45,6 @@ class UpdateStatement extends Node
|
||||
$this->_whereClause = $whereClause;
|
||||
}
|
||||
|
||||
/* Getters */
|
||||
public function getUpdateClause()
|
||||
{
|
||||
return $this->_updateClause;
|
||||
@ -56,13 +54,4 @@ class UpdateStatement extends Node
|
||||
{
|
||||
return $this->_whereClause;
|
||||
}
|
||||
|
||||
/* REMOVE ME LATER. COPIED METHODS FROM SPLIT OF PRODUCTION INTO "AST" AND "PARSER" */
|
||||
public function buildSql()
|
||||
{
|
||||
// The 1=1 is needed to workaround the affected_rows in MySQL.
|
||||
// Simple "UPDATE table_name SET column_name = value" gives 0 affected rows.
|
||||
return $this->_updateClause->buildSql() . (($this->_whereClause !== null)
|
||||
? ' ' . $this->_whereClause->buildSql() : ' WHERE 1 = 1');
|
||||
}
|
||||
}
|
@ -17,7 +17,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;
|
||||
@ -26,7 +26,7 @@ namespace Doctrine\ORM\Query;
|
||||
* Doctrine_ORM_Query_AbstractResult
|
||||
*
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.com
|
||||
* @link www.doctrine-project.com
|
||||
* @since 2.0
|
||||
* @version $Revision: 1393 $
|
||||
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
|
||||
|
@ -79,7 +79,7 @@ abstract class AbstractExecutor implements \Serializable
|
||||
}
|
||||
} else ...
|
||||
*/
|
||||
return new SingleTableDeleteUpdateExecutor($AST);
|
||||
return new SingleTableDeleteUpdateExecutor($AST, $sqlWalker);
|
||||
} else {
|
||||
return new SingleSelectExecutor($AST, $sqlWalker);
|
||||
}
|
||||
|
@ -16,11 +16,13 @@
|
||||
*
|
||||
* 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\Exec;
|
||||
|
||||
use Doctrine\ORM\Query\AST;
|
||||
|
||||
/**
|
||||
* Executor that executes the SQL statements for DQL DELETE/UPDATE statements on classes
|
||||
* that are mapped to a single table.
|
||||
@ -28,16 +30,20 @@ namespace Doctrine\ORM\Query\Exec;
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @version $Revision$
|
||||
* @link www.phpdoctrine.org
|
||||
* @link www.doctrine-project.org
|
||||
* @since 2.0
|
||||
* @todo This is exactly the same as SingleSelectExecutor. Unify in SingleStatementExecutor.
|
||||
*/
|
||||
class SingleTableDeleteUpdateExecutor extends AbstractExecutor
|
||||
{
|
||||
public function __construct(\Doctrine\ORM\Query\AST\Node $AST)
|
||||
public function __construct(AST\Node $AST, $sqlWalker)
|
||||
{
|
||||
parent::__construct($AST);
|
||||
$this->_sqlStatements = $AST->buildSql();
|
||||
parent::__construct($AST, $sqlWalker);
|
||||
if ($AST instanceof AST\UpdateStatement) {
|
||||
$this->_sqlStatements = $sqlWalker->walkUpdateStatement($AST);
|
||||
} else if ($AST instanceof AST\DeleteStatement) {
|
||||
$this->_sqlStatements = $sqlWalker->walkDeleteStatement($AST);
|
||||
}
|
||||
}
|
||||
|
||||
public function execute(\Doctrine\DBAL\Connection $conn, array $params)
|
||||
|
@ -326,16 +326,10 @@ class Parser
|
||||
switch ($this->_lexer->lookahead['type']) {
|
||||
case Lexer::T_SELECT:
|
||||
return $this->_SelectStatement();
|
||||
break;
|
||||
|
||||
case Lexer::T_UPDATE:
|
||||
return $this->_UpdateStatement();
|
||||
break;
|
||||
|
||||
case Lexer::T_DELETE:
|
||||
return $this->_DeleteStatement();
|
||||
break;
|
||||
|
||||
default:
|
||||
$this->syntaxError('SELECT, UPDATE or DELETE');
|
||||
break;
|
||||
@ -430,7 +424,97 @@ class Parser
|
||||
*/
|
||||
private function _UpdateStatement()
|
||||
{
|
||||
//TODO
|
||||
$updateStatement = new AST\UpdateStatement($this->_UpdateClause());
|
||||
$updateStatement->setWhereClause(
|
||||
$this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->_WhereClause() : null
|
||||
);
|
||||
return $updateStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* UpdateClause ::= "UPDATE" AbstractSchemaName [["AS"] AliasIdentificationVariable] "SET" UpdateItem {"," UpdateItem}*
|
||||
*/
|
||||
private function _UpdateClause()
|
||||
{
|
||||
$this->match(Lexer::T_UPDATE);
|
||||
$abstractSchemaName = $this->_AbstractSchemaName();
|
||||
$aliasIdentificationVariable = null;
|
||||
if ($this->_lexer->isNextToken(Lexer::T_AS)) {
|
||||
$this->match(Lexer::T_AS);
|
||||
}
|
||||
if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
$aliasIdentificationVariable = $this->_lexer->token['value'];
|
||||
}
|
||||
$this->match(Lexer::T_SET);
|
||||
$updateItems = array();
|
||||
$updateItems[] = $this->_UpdateItem();
|
||||
while ($this->_lexer->isNextToken(',')) {
|
||||
$this->match(',');
|
||||
$updateItems[] = $this->_UpdateItem();
|
||||
}
|
||||
|
||||
if ($aliasIdentificationVariable) {
|
||||
$classMetadata = $this->_em->getClassMetadata($abstractSchemaName);
|
||||
// Building queryComponent
|
||||
$queryComponent = array(
|
||||
'metadata' => $classMetadata,
|
||||
'parent' => null,
|
||||
'relation' => null,
|
||||
'map' => null,
|
||||
'scalar' => null,
|
||||
);
|
||||
$this->_parserResult->setQueryComponent($aliasIdentificationVariable, $queryComponent);
|
||||
}
|
||||
|
||||
$updateClause = new AST\UpdateClause($abstractSchemaName, $updateItems);
|
||||
$updateClause->setAliasIdentificationVariable($aliasIdentificationVariable);
|
||||
|
||||
return $updateClause;
|
||||
}
|
||||
|
||||
/**
|
||||
* UpdateItem ::= [IdentificationVariable "."] {StateField | SingleValuedAssociationField} "=" NewValue
|
||||
*/
|
||||
private function _UpdateItem()
|
||||
{
|
||||
$peek = $this->_lexer->glimpse();
|
||||
$identVariable = null;
|
||||
if ($peek['value'] == '.') {
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
$identVariable = $this->_lexer->token['value'];
|
||||
$this->match('.');
|
||||
}
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
$field = $this->_lexer->token['value'];
|
||||
$this->match('=');
|
||||
$newValue = $this->_NewValue();
|
||||
|
||||
$updateItem = new AST\UpdateItem($field, $newValue);
|
||||
$updateItem->setIdentificationVariable($identVariable);
|
||||
|
||||
return $updateItem;
|
||||
}
|
||||
|
||||
/**
|
||||
* NewValue ::= SimpleArithmeticExpression | StringPrimary | DatetimePrimary | BooleanPrimary |
|
||||
* EnumPrimary | SimpleEntityExpression | "NULL"
|
||||
*/
|
||||
private function _NewValue()
|
||||
{
|
||||
if ($this->_lexer->isNextToken(Lexer::T_NULL)) {
|
||||
$this->match(Lexer::T_NULL);
|
||||
return null;
|
||||
} else if ($this->_lexer->isNextToken(Lexer::T_INPUT_PARAMETER)) {
|
||||
$this->match(Lexer::T_INPUT_PARAMETER);
|
||||
return new AST\InputParameter($this->_lexer->token['value']);
|
||||
} else if ($this->_lexer->isNextToken(Lexer::T_STRING)) {
|
||||
//TODO: Can be StringPrimary or EnumPrimary
|
||||
return $this->_StringPrimary();
|
||||
} else {
|
||||
$this->syntaxError('Not yet implemented.');
|
||||
//echo "UH OH ...";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -438,7 +522,42 @@ class Parser
|
||||
*/
|
||||
private function _DeleteStatement()
|
||||
{
|
||||
//TODO
|
||||
$deleteStatement = new AST\DeleteStatement($this->_DeleteClause());
|
||||
$deleteStatement->setWhereClause(
|
||||
$this->_lexer->isNextToken(Lexer::T_WHERE) ? $this->_WhereClause() : null
|
||||
);
|
||||
return $deleteStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
* DeleteClause ::= "DELETE" ["FROM"] AbstractSchemaName [["AS"] AliasIdentificationVariable]
|
||||
*/
|
||||
private function _DeleteClause()
|
||||
{
|
||||
$this->match(Lexer::T_DELETE);
|
||||
if ($this->_lexer->isNextToken(Lexer::T_FROM)) {
|
||||
$this->match(Lexer::T_FROM);
|
||||
}
|
||||
$deleteClause = new AST\DeleteClause($this->_AbstractSchemaName());
|
||||
if ($this->_lexer->isNextToken(Lexer::T_AS)) {
|
||||
$this->match(Lexer::T_AS);
|
||||
}
|
||||
if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
$deleteClause->setAliasIdentificationVariable($this->_lexer->token['value']);
|
||||
|
||||
$classMetadata = $this->_em->getClassMetadata($deleteClause->getAbstractSchemaName());
|
||||
// Building queryComponent
|
||||
$queryComponent = array(
|
||||
'metadata' => $classMetadata,
|
||||
'parent' => null,
|
||||
'relation' => null,
|
||||
'map' => null,
|
||||
'scalar' => null,
|
||||
);
|
||||
$this->_parserResult->setQueryComponent($this->_lexer->token['value'], $queryComponent);
|
||||
}
|
||||
return $deleteClause;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -496,17 +615,23 @@ class Parser
|
||||
if ($peek['value'] != '.' && $this->_lexer->lookahead['type'] === Lexer::T_IDENTIFIER) {
|
||||
$expression = $this->_IdentificationVariable();
|
||||
} else if (($isFunction = $this->_isFunction()) !== false || $this->_isSubselect()) {
|
||||
$expression = $isFunction ? $this->_AggregateExpression() : $this->_Subselect();
|
||||
if ($isFunction) {
|
||||
$expression = $this->_AggregateExpression();
|
||||
} else {
|
||||
$this->match('(');
|
||||
$expression = $this->_Subselect();
|
||||
$this->match(')');
|
||||
}
|
||||
if ($this->_lexer->isNextToken(Lexer::T_AS)) {
|
||||
$this->match(Lexer::T_AS);
|
||||
$fieldIdentificationVariable = $this->_FieldAliasIdentificationVariable();
|
||||
} else if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
|
||||
$fieldIdentificationVariable = $this->_FieldAliasIdentificationVariable();
|
||||
}
|
||||
if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
$fieldIdentificationVariable = $this->_lexer->token['value'];
|
||||
}
|
||||
} else {
|
||||
$expression = $this->_PathExpressionInSelect();
|
||||
}
|
||||
|
||||
return new AST\SelectExpression($expression, $fieldIdentificationVariable);
|
||||
}
|
||||
|
||||
@ -835,14 +960,23 @@ class Parser
|
||||
// For now we only support a PathExpression here...
|
||||
$pathExp = $this->_PathExpression();
|
||||
$this->match(')');
|
||||
} else if ($this->_lexer->isNextToken(Lexer::T_AVG)) {
|
||||
} else {
|
||||
if ($this->_lexer->isNextToken(Lexer::T_AVG)) {
|
||||
$this->match(Lexer::T_AVG);
|
||||
$functionName = $this->_lexer->token['value'];
|
||||
$this->match('(');
|
||||
//...
|
||||
} else if ($this->_lexer->isNextToken(Lexer::T_MAX)) {
|
||||
$this->match(Lexer::T_MAX);
|
||||
} else if ($this->_lexer->isNextToken(Lexer::T_MIN)) {
|
||||
$this->match(Lexer::T_MIN);
|
||||
} else if ($this->_lexer->isNextToken(Lexer::T_SUM)) {
|
||||
$this->match(Lexer::T_SUM);
|
||||
} else {
|
||||
$this->syntaxError('One of: MAX, MIN, AVG, SUM, COUNT');
|
||||
}
|
||||
$functionName = $this->_lexer->token['value'];
|
||||
$this->match('(');
|
||||
$pathExp = $this->_StateFieldPathExpression();
|
||||
$this->match(')');
|
||||
}
|
||||
return new AST\AggregateExpression($functionName, $pathExp, $isDistinct);
|
||||
}
|
||||
|
||||
@ -863,6 +997,49 @@ class Parser
|
||||
return new AST\GroupByClause($groupByItems);
|
||||
}
|
||||
|
||||
/**
|
||||
* HavingClause ::= "HAVING" ConditionalExpression
|
||||
*/
|
||||
private function _HavingClause()
|
||||
{
|
||||
$this->match(Lexer::T_HAVING);
|
||||
return new AST\HavingClause($this->_ConditionalExpression());
|
||||
}
|
||||
|
||||
/**
|
||||
* OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}*
|
||||
*/
|
||||
private function _OrderByClause()
|
||||
{
|
||||
$this->match(Lexer::T_ORDER);
|
||||
$this->match(Lexer::T_BY);
|
||||
$orderByItems = array();
|
||||
$orderByItems[] = $this->_OrderByItem();
|
||||
while ($this->_lexer->isNextToken(',')) {
|
||||
$this->match(',');
|
||||
$orderByItems[] = $this->_OrderByItem();
|
||||
}
|
||||
return new AST\OrderByClause($orderByItems);
|
||||
}
|
||||
|
||||
/**
|
||||
* OrderByItem ::= StateFieldPathExpression ["ASC" | "DESC"]
|
||||
*/
|
||||
private function _OrderByItem()
|
||||
{
|
||||
$item = new AST\OrderByItem($this->_StateFieldPathExpression());
|
||||
if ($this->_lexer->isNextToken(Lexer::T_ASC)) {
|
||||
$this->match(Lexer::T_ASC);
|
||||
$item->setAsc(true);
|
||||
} else if ($this->_lexer->isNextToken(Lexer::T_DESC)) {
|
||||
$this->match(Lexer::T_DESC);
|
||||
$item->setDesc(true);
|
||||
} else {
|
||||
$item->setDesc(true);
|
||||
}
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* WhereClause ::= "WHERE" ConditionalExpression
|
||||
*/
|
||||
@ -1000,9 +1177,9 @@ class Parser
|
||||
default:
|
||||
$this->syntaxError();
|
||||
}
|
||||
} else if ($token['value'] == '(') {
|
||||
return $this->_ComparisonExpression();
|
||||
} else {
|
||||
return $this->_ComparisonExpression();
|
||||
/*} else {
|
||||
switch ($token['type']) {
|
||||
case Lexer::T_INTEGER:
|
||||
// IF it turns out its a ComparisonExpression, then it MUST be ArithmeticExpression
|
||||
@ -1012,7 +1189,7 @@ class Parser
|
||||
break;
|
||||
default:
|
||||
$this->syntaxError();
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
@ -1226,7 +1403,7 @@ class Parser
|
||||
}
|
||||
|
||||
/**
|
||||
* SimpleSelectExpression ::= SingleValuedPathExpression | IdentificationVariable | AggregateExpression
|
||||
* SimpleSelectExpression ::= StateFieldPathExpression | IdentificationVariable | (AggregateExpression [["AS"] FieldAliasIdentificationVariable])
|
||||
*/
|
||||
private function _SimpleSelectExpression()
|
||||
{
|
||||
@ -1234,13 +1411,21 @@ class Parser
|
||||
// SingleValuedPathExpression | IdentificationVariable
|
||||
$peek = $this->_lexer->glimpse();
|
||||
if ($peek['value'] == '.') {
|
||||
return $this->_PathExpressionInSelect();
|
||||
return new AST\SimpleSelectExpression($this->_PathExpressionInSelect());
|
||||
} else {
|
||||
$this->match($this->_lexer->lookahead['value']);
|
||||
return $this->_lexer->token['value'];
|
||||
return new AST\SimpleSelectExpression($this->_lexer->token['value']);
|
||||
}
|
||||
} else {
|
||||
return $this->_AggregateExpression();
|
||||
$expr = new AST\SimpleSelectExpression($this->_AggregateExpression());
|
||||
if ($this->_lexer->isNextToken(Lexer::T_AS)) {
|
||||
$this->match(Lexer::T_AS);
|
||||
}
|
||||
if ($this->_lexer->isNextToken(Lexer::T_IDENTIFIER)) {
|
||||
$this->match(Lexer::T_IDENTIFIER);
|
||||
$expr->setFieldIdentificationVariable($this->_lexer->token['value']);
|
||||
}
|
||||
return $expr;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1263,6 +1448,28 @@ class Parser
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* BetweenExpression ::= ArithmeticExpression ["NOT"] "BETWEEN" ArithmeticExpression "AND" ArithmeticExpression
|
||||
*/
|
||||
private function _BetweenExpression()
|
||||
{
|
||||
$not = false;
|
||||
$arithExpr1 = $this->_ArithmeticExpression();
|
||||
if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
|
||||
$this->match(Lexer::T_NOT);
|
||||
$not = true;
|
||||
}
|
||||
$this->match(Lexer::T_BETWEEN);
|
||||
$arithExpr2 = $this->_ArithmeticExpression();
|
||||
$this->match(Lexer::T_AND);
|
||||
$arithExpr3 = $this->_ArithmeticExpression();
|
||||
|
||||
$betweenExpr = new AST\BetweenExpression($arithExpr1, $arithExpr2, $arithExpr3);
|
||||
$betweenExpr->setNot($not);
|
||||
|
||||
return $betweenExpr;
|
||||
}
|
||||
|
||||
/**
|
||||
* ArithmeticPrimary ::= StateFieldPathExpression | Literal | "(" SimpleArithmeticExpression ")" | Function | AggregateExpression
|
||||
*/
|
||||
@ -1274,13 +1481,11 @@ class Parser
|
||||
$this->match(')');
|
||||
return $expr;
|
||||
}
|
||||
|
||||
switch ($this->_lexer->lookahead['type']) {
|
||||
case Lexer::T_IDENTIFIER:
|
||||
$peek = $this->_lexer->glimpse();
|
||||
if ($peek['value'] == '(') {
|
||||
if ($this->_isAggregateFunction($peek['type'])) {
|
||||
return $this->_AggregateExpression();
|
||||
}
|
||||
return $this->_FunctionsReturningStrings();
|
||||
}
|
||||
return $this->_StateFieldPathExpression();
|
||||
@ -1293,8 +1498,16 @@ class Parser
|
||||
$this->match($this->_lexer->lookahead['value']);
|
||||
return $this->_lexer->token['value'];
|
||||
default:
|
||||
$peek = $this->_lexer->glimpse();
|
||||
if ($peek['value'] == '(') {
|
||||
if ($this->_isAggregateFunction($this->_lexer->lookahead['type'])) {
|
||||
return $this->_AggregateExpression();
|
||||
}
|
||||
return $this->_FunctionsReturningStrings();
|
||||
} else {
|
||||
$this->syntaxError();
|
||||
}
|
||||
}
|
||||
throw \Doctrine\Common\DoctrineException::updateMe("Not yet implemented.");
|
||||
//TODO...
|
||||
}
|
||||
@ -1402,9 +1615,8 @@ class Parser
|
||||
$escapeChar = null;
|
||||
if ($this->_lexer->lookahead['type'] === Lexer::T_ESCAPE) {
|
||||
$this->match(Lexer::T_ESCAPE);
|
||||
var_dump($this->_lexer->lookahead);
|
||||
//$this->match(Lexer::T_)
|
||||
//$escapeChar =
|
||||
$this->match(Lexer::T_STRING);
|
||||
$escapeChar = $this->_lexer->token['value'];
|
||||
}
|
||||
return new AST\LikeExpression($stringExpr, $stringPattern, $isNot, $escapeChar);
|
||||
}
|
||||
@ -1438,9 +1650,11 @@ class Parser
|
||||
$this->syntaxError("'.' or '('");
|
||||
}
|
||||
} else if ($this->_lexer->lookahead['type'] === Lexer::T_STRING) {
|
||||
//TODO...
|
||||
$this->match(Lexer::T_STRING);
|
||||
return $this->_lexer->token['value'];
|
||||
} else if ($this->_lexer->lookahead['type'] === Lexer::T_INPUT_PARAMETER) {
|
||||
//TODO...
|
||||
$this->match(Lexer::T_INPUT_PARAMETER);
|
||||
return new AST\InputParameter($this->_lexer->token['value']);
|
||||
} else {
|
||||
$this->syntaxError('StateFieldPathExpression | string | InputParameter | FunctionsReturningStrings | AggregateExpression');
|
||||
}
|
||||
|
@ -181,27 +181,16 @@ class SqlWalker
|
||||
}
|
||||
else if ($selectExpression->getExpression() instanceof AST\AggregateExpression) {
|
||||
$aggExpr = $selectExpression->getExpression();
|
||||
|
||||
if ( ! $selectExpression->getFieldIdentificationVariable()) {
|
||||
$alias = $this->_scalarAliasCounter++;
|
||||
} else {
|
||||
$alias = $selectExpression->getFieldIdentificationVariable();
|
||||
}
|
||||
|
||||
$parts = $aggExpr->getPathExpression()->getParts();
|
||||
$dqlAlias = $parts[0];
|
||||
$fieldName = $parts[1];
|
||||
|
||||
$qComp = $this->_parserResult->getQueryComponent($dqlAlias);
|
||||
$columnName = $qComp['metadata']->getColumnName($fieldName);
|
||||
|
||||
$sql .= $aggExpr->getFunctionName() . '(';
|
||||
if ($aggExpr->isDistinct()) $sql .= 'DISTINCT ';
|
||||
$sql .= $this->_dqlToSqlAliasMap[$dqlAlias] . '.' . $columnName;
|
||||
$sql .= ') AS dctrn__' . $alias;
|
||||
$sql .= $this->walkAggregateExpression($aggExpr) . ' AS dctrn__' . $alias;
|
||||
}
|
||||
//TODO: else if Subselect
|
||||
else {
|
||||
else if ($selectExpression->getExpression() instanceof AST\Subselect) {
|
||||
$sql .= $this->walkSubselect($selectExpression->getExpression());
|
||||
} else {
|
||||
$dqlAlias = $selectExpression->getExpression();
|
||||
$queryComp = $this->_parserResult->getQueryComponent($dqlAlias);
|
||||
$class = $queryComp['metadata'];
|
||||
@ -221,6 +210,80 @@ class SqlWalker
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public function walkSubselect($subselect)
|
||||
{
|
||||
$sql = $this->walkSimpleSelectClause($subselect->getSimpleSelectClause());
|
||||
$sql .= $this->walkSubselectFromClause($subselect->getSubselectFromClause());
|
||||
$sql .= $subselect->getWhereClause() ? $this->walkWhereClause($subselect->getWhereClause()) : '';
|
||||
$sql .= $subselect->getGroupByClause() ? $this->walkGroupByClause($subselect->getGroupByClause()) : '';
|
||||
|
||||
//... more clauses
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public function walkSubselectFromClause($subselectFromClause)
|
||||
{
|
||||
$sql = ' FROM ';
|
||||
$identificationVarDecls = $subselectFromClause->getSubselectIdentificationVariableDeclarations();
|
||||
$firstIdentificationVarDecl = $identificationVarDecls[0];
|
||||
$rangeDecl = $firstIdentificationVarDecl->getRangeVariableDeclaration();
|
||||
$sql .= $rangeDecl->getClassMetadata()->getTableName() . ' '
|
||||
. $this->_dqlToSqlAliasMap[$rangeDecl->getAliasIdentificationVariable()];
|
||||
|
||||
foreach ($firstIdentificationVarDecl->getJoinVariableDeclarations() as $joinVarDecl) {
|
||||
$sql .= $this->walkJoinVariableDeclaration($joinVarDecl);
|
||||
}
|
||||
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public function walkSimpleSelectClause($simpleSelectClause)
|
||||
{
|
||||
$sql = 'SELECT';
|
||||
if ($simpleSelectClause->isDistinct()) {
|
||||
$sql .= ' DISTINCT';
|
||||
}
|
||||
$sql .= $this->walkSimpleSelectExpression($simpleSelectClause->getSimpleSelectExpression());
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public function walkSimpleSelectExpression($simpleSelectExpression)
|
||||
{
|
||||
$sql = '';
|
||||
$expr = $simpleSelectExpression->getExpression();
|
||||
if ($expr instanceof AST\PathExpression) {
|
||||
//...
|
||||
} else if ($expr instanceof AST\AggregateExpression) {
|
||||
if ( ! $simpleSelectExpression->getFieldIdentificationVariable()) {
|
||||
$alias = $this->_scalarAliasCounter++;
|
||||
} else {
|
||||
$alias = $simpleSelectExpression->getFieldIdentificationVariable();
|
||||
}
|
||||
$sql .= $this->walkAggregateExpression($expr) . ' AS dctrn__' . $alias;
|
||||
} else {
|
||||
// $expr is IdentificationVariable
|
||||
//...
|
||||
}
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public function walkAggregateExpression($aggExpression)
|
||||
{
|
||||
$sql = '';
|
||||
$parts = $aggExpression->getPathExpression()->getParts();
|
||||
$dqlAlias = $parts[0];
|
||||
$fieldName = $parts[1];
|
||||
|
||||
$qComp = $this->_parserResult->getQueryComponent($dqlAlias);
|
||||
$columnName = $qComp['metadata']->getColumnName($fieldName);
|
||||
|
||||
$sql .= $aggExpression->getFunctionName() . '(';
|
||||
if ($aggExpression->isDistinct()) $sql .= 'DISTINCT ';
|
||||
$sql .= $this->_dqlToSqlAliasMap[$dqlAlias] . '.' . $columnName;
|
||||
$sql .= ')';
|
||||
return $sql;
|
||||
}
|
||||
|
||||
public function walkGroupByClause($groupByClause)
|
||||
{
|
||||
return ' GROUP BY '
|
||||
|
@ -112,111 +112,41 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
|
||||
{
|
||||
$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)');
|
||||
}
|
||||
/*
|
||||
|
||||
public function testNotExistsExpressionSupportedInWherePart()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.* FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE NOT EXISTS (SELECT p.user_id FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.user_id = u.id)');
|
||||
}
|
||||
|
||||
public function testLiteralValueAsInOperatorOperandIsSupported()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE 1 IN (1, 2)');
|
||||
}
|
||||
|
||||
public function testUpdateWorksWithOneColumn()
|
||||
{
|
||||
$this->assertValidDql("UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = 'someone'");
|
||||
}
|
||||
|
||||
public function testUpdateWorksWithMultipleColumns()
|
||||
{
|
||||
$this->assertValidDql("UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = 'someone', u.username = 'some'");
|
||||
}
|
||||
|
||||
public function testUpdateSupportsConditions()
|
||||
{
|
||||
$this->assertValidDql("UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = 'someone' WHERE u.id = 5");
|
||||
}
|
||||
|
||||
public function testDeleteAll()
|
||||
{
|
||||
$this->assertValidDql('DELETE FROM Doctrine\Tests\Models\CMS\CmsUser');
|
||||
}
|
||||
|
||||
public function testDeleteWithCondition()
|
||||
{
|
||||
$this->assertValidDql('DELETE FROM Doctrine\Tests\Models\CMS\CmsUser WHERE id = 3');
|
||||
}
|
||||
|
||||
public function testAdditionExpression()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.*, (u.id + u.id) addition FROM Doctrine\Tests\Models\CMS\CmsUser u');
|
||||
}
|
||||
|
||||
public function testSubtractionExpression()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.*, (u.id - u.id) subtraction FROM Doctrine\Tests\Models\CMS\CmsUser u');
|
||||
}
|
||||
|
||||
public function testDivisionExpression()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.*, (u.id/u.id) division FROM Doctrine\Tests\Models\CMS\CmsUser u');
|
||||
}
|
||||
|
||||
public function testMultiplicationExpression()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.*, (u.id * u.id) multiplication FROM Doctrine\Tests\Models\CMS\CmsUser u');
|
||||
}
|
||||
|
||||
public function testNegationExpression()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.*, -u.id negation FROM Doctrine\Tests\Models\CMS\CmsUser u');
|
||||
}
|
||||
|
||||
public function testExpressionWithPrecedingPlusSign()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.*, +u.id FROM CmsUser u');
|
||||
$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)');
|
||||
}
|
||||
|
||||
public function testAggregateFunctionInHavingClause()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.phonenumbers p HAVING COUNT(p.phonenumber) > 2');
|
||||
$this->assertValidDql("SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.phonenumbers p HAVING MAX(u.name) = 'zYne'");
|
||||
}
|
||||
|
||||
public function testMultipleAggregateFunctionsInHavingClause()
|
||||
{
|
||||
$this->assertValidDql("SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.phonenumbers p HAVING MAX(u.name) = 'zYne'");
|
||||
$this->assertValidDql("SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.phonenumbers p HAVING MAX(u.name) = 'romanb'");
|
||||
}
|
||||
|
||||
public function testLeftJoin()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.*, p.* FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.phonenumbers p');
|
||||
$this->assertValidDql('SELECT u, p FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.phonenumbers p');
|
||||
}
|
||||
|
||||
public function testJoin()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.* FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.phonenumbers');
|
||||
$this->assertValidDql('SELECT u,p FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.phonenumbers p');
|
||||
}
|
||||
|
||||
public function testInnerJoin()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.*, u.phonenumbers.* FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.phonenumbers');
|
||||
$this->assertValidDql('SELECT u, p FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.phonenumbers p');
|
||||
}
|
||||
|
||||
public function testMultipleLeftJoin()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.articles.*, u.phonenumbers.* FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles LEFT JOIN u.phonenumbers');
|
||||
$this->assertValidDql('SELECT u, a, p FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a LEFT JOIN u.phonenumbers p');
|
||||
}
|
||||
|
||||
public function testMultipleInnerJoin()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles INNER JOIN u.phonenumbers');
|
||||
}
|
||||
|
||||
public function testMultipleInnerJoin2()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles, u.phonenumbers');
|
||||
$this->assertValidDql('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles a INNER JOIN u.phonenumbers p');
|
||||
}
|
||||
|
||||
public function testMixingOfJoins()
|
||||
@ -224,11 +154,6 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
|
||||
$this->assertValidDql('SELECT u.name, a.topic, p.phonenumber FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles a LEFT JOIN u.phonenumbers p');
|
||||
}
|
||||
|
||||
public function testMixingOfJoins2()
|
||||
{
|
||||
$this->assertInvalidDql('SELECT u.name, u.articles.topic, c.text FROM Doctrine\Tests\Models\CMS\CmsUser u INNER JOIN u.articles.comments c');
|
||||
}
|
||||
|
||||
public function testOrderBySingleColumn()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.name');
|
||||
@ -249,31 +174,134 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
|
||||
$this->assertValidDql('SELECT u.name, u.username FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY u.username DESC, u.name DESC');
|
||||
}
|
||||
|
||||
public function testOrderByWithFunctionExpression()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.name FROM Doctrine\Tests\Models\CMS\CmsUser u ORDER BY COALESCE(u.id, u.name) DESC');
|
||||
}*/
|
||||
/*
|
||||
public function testSubselectInInExpression()
|
||||
{
|
||||
$this->assertValidDql("SELECT * FROM CmsUser u WHERE u.id NOT IN (SELECT u2.id FROM CmsUser u2 WHERE u2.name = 'zYne')");
|
||||
$this->assertValidDql("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id NOT IN (SELECT u2.id FROM Doctrine\Tests\Models\CMS\CmsUser u2 WHERE u2.name = 'zYne')");
|
||||
}
|
||||
|
||||
public function testSubselectInSelectPart()
|
||||
{
|
||||
// Semantical error: Unknown query component u (probably in subselect)
|
||||
$this->assertValidDql("SELECT u.name, (SELECT COUNT(p.phonenumber) FROM CmsPhonenumber p WHERE p.user_id = u.id) pcount FROM CmsUser u WHERE u.name = 'zYne' LIMIT 1");
|
||||
$this->assertValidDql("SELECT u.name, (SELECT COUNT(p.phonenumber) FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p WHERE p.phonenumber = 1234) pcount FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name = 'jon'");
|
||||
}
|
||||
*//*
|
||||
|
||||
public function testPositionalInputParameter()
|
||||
{
|
||||
$this->assertValidDql('SELECT * FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?');
|
||||
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = ?');
|
||||
}
|
||||
|
||||
public function testNamedInputParameter()
|
||||
{
|
||||
$this->assertValidDql('SELECT * FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :id');
|
||||
}*/
|
||||
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = :id');
|
||||
}
|
||||
|
||||
public function testJoinConditionsSupported()
|
||||
{
|
||||
$this->assertValidDql("SELECT u.name, p FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.phonenumbers p ON p.phonenumber = '123 123'");
|
||||
}
|
||||
|
||||
public function testIndexByClauseWithOneComponent()
|
||||
{
|
||||
$this->assertValidDql('SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u INDEX BY u.id');
|
||||
}
|
||||
|
||||
public function testIndexBySupportsJoins()
|
||||
{
|
||||
$this->assertValidDql('SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles a INDEX BY a.id'); // INDEX BY is now referring to articles
|
||||
}
|
||||
|
||||
public function testIndexBySupportsJoins2()
|
||||
{
|
||||
$this->assertValidDql('SELECT u, p FROM Doctrine\Tests\Models\CMS\CmsUser u INDEX BY u.id LEFT JOIN u.phonenumbers p INDEX BY p.phonenumber');
|
||||
}
|
||||
|
||||
public function testBetweenExpressionSupported()
|
||||
{
|
||||
$this->assertValidDql("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name BETWEEN 'jepso' AND 'zYne'");
|
||||
}
|
||||
|
||||
public function testNotBetweenExpressionSupported()
|
||||
{
|
||||
$this->assertValidDql("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name NOT BETWEEN 'jepso' AND 'zYne'");
|
||||
}
|
||||
|
||||
public function testLikeExpression()
|
||||
{
|
||||
$this->assertValidDql("SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name LIKE 'z%'");
|
||||
}
|
||||
|
||||
public function testNotLikeExpression()
|
||||
{
|
||||
$this->assertValidDql("SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name NOT LIKE 'z%'");
|
||||
}
|
||||
|
||||
public function testLikeExpressionWithCustomEscapeCharacter()
|
||||
{
|
||||
$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
|
||||
$this->assertInvalidDql("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.articles.title = ?");
|
||||
}
|
||||
|
||||
public function testInvalidSyntaxIsRejected()
|
||||
{
|
||||
$this->assertInvalidDql("FOOBAR CmsUser");
|
||||
//$this->assertInvalidDql("DELETE FROM Doctrine\Tests\Models\CMS\CmsUser.articles");
|
||||
//$this->assertInvalidDql("DELETE FROM Doctrine\Tests\Models\CMS\CmsUser cu WHERE cu.articles.id > ?");
|
||||
$this->assertInvalidDql("SELECT u FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.articles.comments");
|
||||
|
||||
// Currently UNDEFINED OFFSET error
|
||||
$this->assertInvalidDql("SELECT c FROM CmsUser.articles.comments c");
|
||||
}
|
||||
|
||||
public function testUpdateWorksWithOneField()
|
||||
{
|
||||
$this->assertValidDql("UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = 'someone'");
|
||||
}
|
||||
|
||||
public function testUpdateWorksWithMultipleFields()
|
||||
{
|
||||
$this->assertValidDql("UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = 'someone', u.username = 'some'");
|
||||
}
|
||||
|
||||
public function testUpdateSupportsConditions()
|
||||
{
|
||||
$this->assertValidDql("UPDATE Doctrine\Tests\Models\CMS\CmsUser u SET u.name = 'someone' WHERE u.id = 5");
|
||||
}
|
||||
|
||||
public function testDeleteAll()
|
||||
{
|
||||
$this->assertValidDql('DELETE FROM Doctrine\Tests\Models\CMS\CmsUser');
|
||||
}
|
||||
|
||||
public function testDeleteWithCondition()
|
||||
{
|
||||
$this->assertValidDql('DELETE FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.id = 3');
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: Hydration can't deal with this currently but it should be allowed.
|
||||
* Also, generated SQL looks like: "... FROM cms_user, cms_article ..." which
|
||||
* may not work on all dbms.
|
||||
*
|
||||
* The main use case for this generalized style of join is when a join condition
|
||||
* does not involve a foreign key relationship that is mapped to an entity relationship.
|
||||
*/
|
||||
public function testImplicitJoinWithCartesianProductAndConditionInWhere()
|
||||
{
|
||||
$this->assertValidDql("SELECT u, a FROM Doctrine\Tests\Models\CMS\CmsUser u, Doctrine\Tests\Models\CMS\CmsArticle a WHERE u.name = a.topic");
|
||||
}
|
||||
|
||||
/*
|
||||
public function testCustomJoinsAndWithKeywordSupported()
|
||||
{
|
||||
@ -281,37 +309,6 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
|
||||
$this->assertValidDql('SELECT c.*, c2.*, d.* FROM Record_Country c INNER JOIN c.City c2 WITH c2.id = 2 WHERE c.id = 1');
|
||||
}
|
||||
*/
|
||||
/*
|
||||
public function testJoinConditionsSupported()
|
||||
{
|
||||
$this->assertValidDql("SELECT u.name, p.* FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.phonenumbers p ON p.phonenumber = '123 123'");
|
||||
}
|
||||
|
||||
public function testIndexByClauseWithOneComponent()
|
||||
{
|
||||
$this->assertValidDql('SELECT * FROM Doctrine\Tests\Models\CMS\CmsUser u INDEX BY id');
|
||||
}
|
||||
|
||||
public function testIndexBySupportsJoins()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.*, u.articles.* FROM Doctrine\Tests\Models\CMS\CmsUser u LEFT JOIN u.articles INDEX BY id'); // INDEX BY is now referring to articles
|
||||
}
|
||||
|
||||
public function testIndexBySupportsJoins2()
|
||||
{
|
||||
$this->assertValidDql('SELECT u.*, p.* FROM Doctrine\Tests\Models\CMS\CmsUser u INDEX BY id LEFT JOIN u.phonenumbers p INDEX BY phonenumber');
|
||||
}
|
||||
|
||||
public function testBetweenExpressionSupported()
|
||||
{
|
||||
$this->assertValidDql("SELECT * FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name BETWEEN 'jepso' AND 'zYne'");
|
||||
}
|
||||
|
||||
public function testNotBetweenExpressionSupported()
|
||||
{
|
||||
$this->assertValidDql("SELECT * FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name NOT BETWEEN 'jepso' AND 'zYne'");
|
||||
}
|
||||
*/
|
||||
/* public function testAllExpressionWithCorrelatedSubquery()
|
||||
{
|
||||
// We need existant classes here, otherwise semantical will always fail
|
||||
@ -329,62 +326,5 @@ class LanguageRecognitionTest extends \Doctrine\Tests\OrmTestCase
|
||||
// We need existant classes here, otherwise semantical will always fail
|
||||
$this->assertValidDql('SELECT * FROM Employee e WHERE e.salary > SOME (SELECT m.salary FROM Manager m WHERE m.department = e.department)');
|
||||
}
|
||||
*//*
|
||||
public function testLikeExpression()
|
||||
{
|
||||
$this->assertValidDql("SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name LIKE 'z%'");
|
||||
}
|
||||
|
||||
public function testNotLikeExpression()
|
||||
{
|
||||
$this->assertValidDql("SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name NOT LIKE 'z%'");
|
||||
}
|
||||
|
||||
public function testLikeExpressionWithCustomEscapeCharacter()
|
||||
{
|
||||
$this->assertValidDql("SELECT u.id FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.name LIKE 'z|%' ESCAPE '|'");
|
||||
}
|
||||
*/
|
||||
/**
|
||||
* TODO: Hydration can't deal with this currently but it should be allowed.
|
||||
* Also, generated SQL looks like: "... FROM cms_user, cms_article ..." which
|
||||
* may not work on all dbms.
|
||||
*
|
||||
* The main use case for this generalized style of join is when a join condition
|
||||
* does not involve a foreign key relationship that is mapped to an entity relationship.
|
||||
*/
|
||||
/* public function testImplicitJoinWithCartesianProductAndConditionInWhere()
|
||||
{
|
||||
$this->assertValidDql("SELECT u.*, a.* FROM Doctrine\Tests\Models\CMS\CmsUser u, CmsArticle a WHERE u.name = a.topic");
|
||||
}
|
||||
|
||||
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 ForumUser u WHERE u.avatar.id = ?");
|
||||
}
|
||||
|
||||
public function testImplicitJoinInWhereOnCollectionValuedPathExpression()
|
||||
{
|
||||
// This should be forbidden, because articles is a collection
|
||||
$this->assertInvalidDql("SELECT u.* FROM Doctrine\Tests\Models\CMS\CmsUser u WHERE u.articles.title = ?");
|
||||
}
|
||||
|
||||
public function testInvalidSyntaxIsRejected()
|
||||
{
|
||||
$this->assertInvalidDql("FOOBAR CmsUser");
|
||||
$this->assertInvalidDql("DELETE FROM Doctrine\Tests\Models\CMS\CmsUser.articles");
|
||||
$this->assertInvalidDql("DELETE FROM Doctrine\Tests\Models\CMS\CmsUser cu WHERE cu.articles.id > ?");
|
||||
$this->assertInvalidDql("SELECT user FROM Doctrine\Tests\Models\CMS\CmsUser user");
|
||||
|
||||
// Error message here is: Relation 'comments' does not exist in component 'CmsUser'
|
||||
// This means it is intepreted as:
|
||||
// SELECT u.* FROM CmsUser u JOIN u.articles JOIN u.comments
|
||||
// This seems wrong. "JOIN u.articles.comments" should not be allowed.
|
||||
$this->assertInvalidDql("SELECT u.* FROM Doctrine\Tests\Models\CMS\CmsUser u JOIN u.articles.comments");
|
||||
|
||||
// Currently UNDEFINED OFFSET error
|
||||
//$this->assertInvalidDql("SELECT * FROM CmsUser.articles.comments");
|
||||
}*/
|
||||
}
|
Loading…
Reference in New Issue
Block a user