updates to the lexer of the new dql parser
This commit is contained in:
parent
3fcf1fb818
commit
ec4ea31da8
@ -56,6 +56,20 @@ abstract class Doctrine_Query_Production
|
|||||||
return ($la['type'] === $token || $la['value'] === $token);
|
return ($la['type'] === $token || $la['value'] === $token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function _isFunction()
|
||||||
|
{
|
||||||
|
$la = $this->_parser->lookahead;
|
||||||
|
$next = $this->_parser->getScanner()->peek();
|
||||||
|
return ($la['type'] === Doctrine_Query_Token::T_IDENTIFIER && $next['value'] === '(');
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function _isSubselect()
|
||||||
|
{
|
||||||
|
$la = $this->_parser->lookahead;
|
||||||
|
$next = $this->_parser->getScanner()->peek();
|
||||||
|
return ($la['value'] === '(' && $next['type'] === Doctrine_Query_Token::T_SELECT);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Executes a production with specified name and parameters.
|
* Executes a production with specified name and parameters.
|
||||||
*
|
*
|
||||||
|
@ -32,19 +32,11 @@
|
|||||||
*/
|
*/
|
||||||
class Doctrine_Query_Production_ComparisonExpression extends Doctrine_Query_Production
|
class Doctrine_Query_Production_ComparisonExpression extends Doctrine_Query_Production
|
||||||
{
|
{
|
||||||
private function _isSubquery()
|
|
||||||
{
|
|
||||||
$lookahead = $this->_parser->lookahead;
|
|
||||||
$next = $this->_parser->getScanner()->peek();
|
|
||||||
|
|
||||||
return $lookahead['value'] === '(' && $next['type'] === Doctrine_Query_Token::T_SELECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute(array $params = array())
|
public function execute(array $params = array())
|
||||||
{
|
{
|
||||||
$this->ComparisonOperator();
|
$this->ComparisonOperator();
|
||||||
|
|
||||||
if ($this->_isSubquery()) {
|
if ($this->_isSubselect()) {
|
||||||
$this->_parser->match('(');
|
$this->_parser->match('(');
|
||||||
$this->Subselect();
|
$this->Subselect();
|
||||||
$this->_parser->match(')');
|
$this->_parser->match(')');
|
||||||
|
@ -32,9 +32,52 @@
|
|||||||
*/
|
*/
|
||||||
class Doctrine_Query_Production_ConditionalPrimary extends Doctrine_Query_Production
|
class Doctrine_Query_Production_ConditionalPrimary extends Doctrine_Query_Production
|
||||||
{
|
{
|
||||||
|
private function _isConditionalExpression()
|
||||||
|
{
|
||||||
|
$token = $this->_parser->lookahead;
|
||||||
|
$parenthesis = 0;
|
||||||
|
|
||||||
|
if ($token['value'] === '(') {
|
||||||
|
$parenthesis++;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ($parenthesis > 0) {
|
||||||
|
$token = $this->_parser->getScanner()->peek();
|
||||||
|
|
||||||
|
if ($token['value'] === '(') {
|
||||||
|
$parenthesis++;
|
||||||
|
} elseif ($token['value'] === ')') {
|
||||||
|
$parenthesis--;
|
||||||
|
} else {
|
||||||
|
switch ($token['type']) {
|
||||||
|
case Doctrine_Query_Token::T_NOT:
|
||||||
|
case Doctrine_Query_Token::T_AND:
|
||||||
|
case Doctrine_Query_Token::T_OR:
|
||||||
|
case Doctrine_Query_Token::T_BETWEEN:
|
||||||
|
case Doctrine_Query_Token::T_LIKE:
|
||||||
|
case Doctrine_Query_Token::T_IN:
|
||||||
|
case Doctrine_Query_Token::T_IS:
|
||||||
|
case Doctrine_Query_Token::T_EXISTS:
|
||||||
|
return true;
|
||||||
|
|
||||||
|
case Doctrine_Query_Token::T_NONE:
|
||||||
|
switch ($token['value']) {
|
||||||
|
case '=':
|
||||||
|
case '<':
|
||||||
|
case '>':
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public function execute(array $params = array())
|
public function execute(array $params = array())
|
||||||
{
|
{
|
||||||
if ($this->_isNextToken('(')) {
|
if ($this->_isConditionalExpression()) {
|
||||||
$this->_parser->match('(');
|
$this->_parser->match('(');
|
||||||
$this->ConditionalExpression();
|
$this->ConditionalExpression();
|
||||||
$this->_parser->match(')');
|
$this->_parser->match(')');
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DeleteStatement = DeleteClause [WhereClause] [OrderByClause] [LimitClause]
|
* DeleteStatement = DeleteClause [WhereClause] [OrderByClause] [LimitClause] [OffsetClause]
|
||||||
*
|
*
|
||||||
* @package Doctrine
|
* @package Doctrine
|
||||||
* @subpackage Query
|
* @subpackage Query
|
||||||
@ -47,5 +47,9 @@ class Doctrine_Query_Production_DeleteStatement extends Doctrine_Query_Productio
|
|||||||
if ($this->_isNextToken(Doctrine_Query_Token::T_LIMIT)) {
|
if ($this->_isNextToken(Doctrine_Query_Token::T_LIMIT)) {
|
||||||
$this->LimitClause();
|
$this->LimitClause();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($this->_isNextToken(Doctrine_Query_Token::T_OFFSET)) {
|
||||||
|
$this->OffsetClause();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ExistsExpression = ["NOT"] "EXISTS" "(" Subselect ")"
|
* ExistsExpression = "EXISTS" "(" Subselect ")"
|
||||||
*
|
*
|
||||||
* @package Doctrine
|
* @package Doctrine
|
||||||
* @subpackage Query
|
* @subpackage Query
|
||||||
@ -34,10 +34,6 @@ class Doctrine_Query_Production_ExistsExpression extends Doctrine_Query_Producti
|
|||||||
{
|
{
|
||||||
public function execute(array $params = array())
|
public function execute(array $params = array())
|
||||||
{
|
{
|
||||||
if ($this->_isNextToken(Doctrine_Query_Token::T_NOT)) {
|
|
||||||
$this->_parser->match(Doctrine_Query_Token::T_NOT);
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->_parser->match(Doctrine_Query_Token::T_EXISTS);
|
$this->_parser->match(Doctrine_Query_Token::T_EXISTS);
|
||||||
|
|
||||||
$this->_parser->match('(');
|
$this->_parser->match('(');
|
||||||
|
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Join = ["LEFT" ["OUTER"] | "INNER"] "JOIN" PathExpression "AS" identifier
|
* Join = ["LEFT" | "INNER"] "JOIN" RangeVariableDeclaration [("ON" | "WITH") ConditionalExpression] [IndexBy]
|
||||||
*
|
*
|
||||||
* @package Doctrine
|
* @package Doctrine
|
||||||
* @subpackage Query
|
* @subpackage Query
|
||||||
@ -36,11 +36,6 @@ class Doctrine_Query_Production_Join extends Doctrine_Query_Production
|
|||||||
{
|
{
|
||||||
if ($this->_isNextToken(Doctrine_Query_Token::T_LEFT)) {
|
if ($this->_isNextToken(Doctrine_Query_Token::T_LEFT)) {
|
||||||
$this->_parser->match(Doctrine_Query_Token::T_LEFT);
|
$this->_parser->match(Doctrine_Query_Token::T_LEFT);
|
||||||
|
|
||||||
if ($this->_isNextToken(Doctrine_Query_Token::T_OUTER)) {
|
|
||||||
$this->_parser->match(Doctrine_Query_Token::T_OUTER);
|
|
||||||
}
|
|
||||||
|
|
||||||
} elseif ($this->_isNextToken(Doctrine_Query_Token::T_INNER)) {
|
} elseif ($this->_isNextToken(Doctrine_Query_Token::T_INNER)) {
|
||||||
$this->_parser->match(Doctrine_Query_Token::T_INNER);
|
$this->_parser->match(Doctrine_Query_Token::T_INNER);
|
||||||
}
|
}
|
||||||
@ -49,7 +44,16 @@ class Doctrine_Query_Production_Join extends Doctrine_Query_Production
|
|||||||
|
|
||||||
$this->RangeVariableDeclaration();
|
$this->RangeVariableDeclaration();
|
||||||
|
|
||||||
$this->_parser->match(Doctrine_Query_Token::T_AS);
|
if ($this->_isNextToken(Doctrine_Query_Token::T_ON)) {
|
||||||
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
|
$this->_parser->match(Doctrine_Query_Token::T_ON);
|
||||||
|
$this->ConditionalExpression();
|
||||||
|
} elseif ($this->_isNextToken(Doctrine_Query_Token::T_WITH)) {
|
||||||
|
$this->_parser->match(Doctrine_Query_Token::T_WITH);
|
||||||
|
$this->ConditionalExpression();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($this->_isNextToken(Doctrine_Query_Token::T_INDEX)) {
|
||||||
|
$this->IndexBy();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
40
draft/Doctrine/Query/Production/LimitClause.php
Normal file
40
draft/Doctrine/Query/Production/LimitClause.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?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.phpdoctrine.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* LimitClause = "LIMIT" Expression
|
||||||
|
*
|
||||||
|
* @package Doctrine
|
||||||
|
* @subpackage Query
|
||||||
|
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||||
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||||
|
* @link http://www.phpdoctrine.org
|
||||||
|
* @since 1.0
|
||||||
|
* @version $Revision$
|
||||||
|
*/
|
||||||
|
class Doctrine_Query_Production_LimitClause extends Doctrine_Query_Production
|
||||||
|
{
|
||||||
|
public function execute(array $params = array())
|
||||||
|
{
|
||||||
|
$this->_parser->match(Doctrine_Query_Token::T_LIMIT);
|
||||||
|
$this->Expression();
|
||||||
|
}
|
||||||
|
}
|
40
draft/Doctrine/Query/Production/OffsetClause.php
Normal file
40
draft/Doctrine/Query/Production/OffsetClause.php
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<?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.phpdoctrine.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OffsetClause = "OFFSET" Expression
|
||||||
|
*
|
||||||
|
* @package Doctrine
|
||||||
|
* @subpackage Query
|
||||||
|
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||||
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||||
|
* @link http://www.phpdoctrine.org
|
||||||
|
* @since 1.0
|
||||||
|
* @version $Revision$
|
||||||
|
*/
|
||||||
|
class Doctrine_Query_Production_OffsetClause extends Doctrine_Query_Production
|
||||||
|
{
|
||||||
|
public function execute(array $params = array())
|
||||||
|
{
|
||||||
|
$this->_parser->match(Doctrine_Query_Token::T_OFFSET);
|
||||||
|
$this->Expression();
|
||||||
|
}
|
||||||
|
}
|
@ -20,7 +20,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OrderByItem = PathExpression ["ASC" | "DESC"]
|
* OrderByItem = Expression ["ASC" | "DESC"]
|
||||||
*
|
*
|
||||||
* @package Doctrine
|
* @package Doctrine
|
||||||
* @subpackage Query
|
* @subpackage Query
|
||||||
@ -34,7 +34,7 @@ class Doctrine_Query_Production_OrderByItem extends Doctrine_Query_Production
|
|||||||
{
|
{
|
||||||
public function execute(array $params = array())
|
public function execute(array $params = array())
|
||||||
{
|
{
|
||||||
$this->PathExpression();
|
$this->Expression();
|
||||||
|
|
||||||
if ($this->_isNextToken(Doctrine_Query_Token::T_ASC)) {
|
if ($this->_isNextToken(Doctrine_Query_Token::T_ASC)) {
|
||||||
$this->_parser->match(Doctrine_Query_Token::T_ASC);
|
$this->_parser->match(Doctrine_Query_Token::T_ASC);
|
||||||
|
@ -37,9 +37,7 @@ class Doctrine_Query_Production_Primary extends Doctrine_Query_Production
|
|||||||
{
|
{
|
||||||
switch ($this->_parser->lookahead['type']) {
|
switch ($this->_parser->lookahead['type']) {
|
||||||
case Doctrine_Query_Token::T_IDENTIFIER:
|
case Doctrine_Query_Token::T_IDENTIFIER:
|
||||||
$nextToken = $this->_parser->getScanner()->peek();
|
if ($this->_isFunction()) {
|
||||||
|
|
||||||
if ($nextToken['value'] === '(') {
|
|
||||||
$this->Function();
|
$this->Function();
|
||||||
} else {
|
} else {
|
||||||
$this->PathExpression();
|
$this->PathExpression();
|
||||||
|
@ -45,19 +45,11 @@ class Doctrine_Query_Production_SelectExpression extends Doctrine_Query_Producti
|
|||||||
return $token['value'] === '*';
|
return $token['value'] === '*';
|
||||||
}
|
}
|
||||||
|
|
||||||
private function _isSubquery()
|
|
||||||
{
|
|
||||||
$lookahead = $this->_parser->lookahead;
|
|
||||||
$next = $this->_parser->getScanner()->peek();
|
|
||||||
|
|
||||||
return $lookahead['value'] === '(' && $next['type'] === Doctrine_Query_Token::T_SELECT;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute(array $params = array())
|
public function execute(array $params = array())
|
||||||
{
|
{
|
||||||
if ($this->_isPathExpressionEndingWithAsterisk()) {
|
if ($this->_isPathExpressionEndingWithAsterisk()) {
|
||||||
$this->PathExpressionEndingWithAsterisk();
|
$this->PathExpressionEndingWithAsterisk();
|
||||||
} elseif ($this->_isSubquery()) {
|
} elseif ($this->_isSubselect()) {
|
||||||
$this->_parser->match('(');
|
$this->_parser->match('(');
|
||||||
$this->Subselect();
|
$this->Subselect();
|
||||||
$this->_parser->match(')');
|
$this->_parser->match(')');
|
||||||
|
@ -38,10 +38,10 @@ class Doctrine_Query_Production_UpdateClause extends Doctrine_Query_Production
|
|||||||
$this->RangeVariableDeclaration();
|
$this->RangeVariableDeclaration();
|
||||||
$this->_parser->match(Doctrine_Query_Token::T_SET);
|
$this->_parser->match(Doctrine_Query_Token::T_SET);
|
||||||
|
|
||||||
$this->RangeVariableDeclaration();
|
$this->UpdateItem();
|
||||||
while ($this->_isNextToken(',')) {
|
while ($this->_isNextToken(',')) {
|
||||||
$this->_parser->match(',');
|
$this->_parser->match(',');
|
||||||
$this->RangeVariableDeclaration();
|
$this->UpdateItem();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
47
draft/Doctrine/Query/Production/UpdateItem.php
Normal file
47
draft/Doctrine/Query/Production/UpdateItem.php
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
<?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.phpdoctrine.org>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UpdateItem = PathExpression "=" (Expression | "NULL")
|
||||||
|
*
|
||||||
|
* @package Doctrine
|
||||||
|
* @subpackage Query
|
||||||
|
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||||
|
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||||
|
* @link http://www.phpdoctrine.org
|
||||||
|
* @since 1.0
|
||||||
|
* @version $Revision$
|
||||||
|
*/
|
||||||
|
class Doctrine_Query_Production_UpdateItem extends Doctrine_Query_Production
|
||||||
|
{
|
||||||
|
public function execute(array $params = array())
|
||||||
|
{
|
||||||
|
$this->PathExpression();
|
||||||
|
|
||||||
|
$this->_parser->match('=');
|
||||||
|
|
||||||
|
if ($this->_isNextToken(Doctrine_Query_Token::T_NULL)) {
|
||||||
|
$this->_parser->match(Doctrine_Query_Token::T_NULL);
|
||||||
|
} else {
|
||||||
|
$this->Expression();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -47,7 +47,7 @@ final class Doctrine_Query_Token
|
|||||||
const T_BETWEEN = 107;
|
const T_BETWEEN = 107;
|
||||||
const T_BY = 108;
|
const T_BY = 108;
|
||||||
const T_COUNT = 109;
|
const T_COUNT = 109;
|
||||||
const T_DELETE = 100;
|
const T_DELETE = 110;
|
||||||
const T_DESC = 111;
|
const T_DESC = 111;
|
||||||
const T_DISTINCT = 112;
|
const T_DISTINCT = 112;
|
||||||
const T_ESCAPE = 113;
|
const T_ESCAPE = 113;
|
||||||
@ -56,27 +56,30 @@ final class Doctrine_Query_Token
|
|||||||
const T_GROUP = 116;
|
const T_GROUP = 116;
|
||||||
const T_HAVING = 117;
|
const T_HAVING = 117;
|
||||||
const T_IN = 118;
|
const T_IN = 118;
|
||||||
const T_INNER = 119;
|
const T_INDEX = 119;
|
||||||
const T_IS = 120;
|
const T_INNER = 120;
|
||||||
const T_JOIN = 121;
|
const T_IS = 121;
|
||||||
const T_LEFT = 122;
|
const T_JOIN = 122;
|
||||||
const T_LIKE = 123;
|
const T_LEFT = 123;
|
||||||
const T_LIMIT = 124;
|
const T_LIKE = 124;
|
||||||
const T_MAX = 125;
|
const T_LIMIT = 125;
|
||||||
const T_MIN = 126;
|
const T_MAX = 126;
|
||||||
const T_NOT = 127;
|
const T_MIN = 127;
|
||||||
const T_NULL = 128;
|
const T_MOD = 128;
|
||||||
const T_OFFSET = 129;
|
const T_NOT = 129;
|
||||||
const T_OR = 130;
|
const T_NULL = 130;
|
||||||
const T_ORDER = 131;
|
const T_OFFSET = 131;
|
||||||
const T_SELECT = 132;
|
const T_ON = 132;
|
||||||
const T_SET = 133;
|
const T_OR = 133;
|
||||||
const T_SOME = 134;
|
const T_ORDER = 134;
|
||||||
const T_SUM = 135;
|
const T_SELECT = 135;
|
||||||
const T_UPDATE = 136;
|
const T_SET = 136;
|
||||||
const T_WHERE = 137;
|
const T_SIZE = 137;
|
||||||
const T_MOD = 142;
|
const T_SOME = 138;
|
||||||
const T_SIZE = 143;
|
const T_SUM = 139;
|
||||||
|
const T_UPDATE = 140;
|
||||||
|
const T_WHERE = 141;
|
||||||
|
const T_WITH = 142;
|
||||||
|
|
||||||
private function __construct() {}
|
private function __construct() {}
|
||||||
}
|
}
|
||||||
|
@ -13,9 +13,9 @@
|
|||||||
|
|
||||||
QueryLanguage = SelectStatement | UpdateStatement | DeleteStatement
|
QueryLanguage = SelectStatement | UpdateStatement | DeleteStatement
|
||||||
|
|
||||||
SelectStatement = [SelectClause] FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] [LimitClause]
|
SelectStatement = [SelectClause] FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] [LimitClause] [OffsetClause]
|
||||||
UpdateStatement = UpdateClause [WhereClause] [OrderByClause] [LimitClause]
|
UpdateStatement = UpdateClause [WhereClause] [OrderByClause] [LimitClause] [OffsetClause]
|
||||||
DeleteStatement = DeleteClause [WhereClause] [OrderByClause] [LimitClause]
|
DeleteStatement = DeleteClause [WhereClause] [OrderByClause] [LimitClause] [OffsetClause]
|
||||||
|
|
||||||
Subselect = SimpleSelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] [LimitClause] [OffsetClause]
|
Subselect = SimpleSelectClause FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] [LimitClause] [OffsetClause]
|
||||||
SelectClause = "SELECT" ["ALL" | "DISTINCT"] SelectExpression {"," SelectExpression}
|
SelectClause = "SELECT" ["ALL" | "DISTINCT"] SelectExpression {"," SelectExpression}
|
||||||
@ -26,7 +26,8 @@ FromClause = "FROM" IdentificationVariableDeclaration {"," IdentificationVa
|
|||||||
HavingClause = "HAVING" ConditionalExpression
|
HavingClause = "HAVING" ConditionalExpression
|
||||||
GroupByClause = "GROUP" "BY" GroupByItem {"," GroupByItem}
|
GroupByClause = "GROUP" "BY" GroupByItem {"," GroupByItem}
|
||||||
OrderByClause = "ORDER" "BY" OrderByItem {"," OrderByItem}
|
OrderByClause = "ORDER" "BY" OrderByItem {"," OrderByItem}
|
||||||
LimitClause = "LIMIT" Expression ["OFFSET" Expression]
|
LimitClause = "LIMIT" Expression
|
||||||
|
OffsetClause = "OFFSET" Expression
|
||||||
UpdateClause = "UPDATE" RangeVariableDeclaration "SET" UpdateItem {"," UpdateItem}
|
UpdateClause = "UPDATE" RangeVariableDeclaration "SET" UpdateItem {"," UpdateItem}
|
||||||
|
|
||||||
OrderByItem = Expression ["ASC" | "DESC"]
|
OrderByItem = Expression ["ASC" | "DESC"]
|
||||||
@ -67,6 +68,6 @@ ComparisonExpression = ComparisonOperator ( QuantifiedExpression | Expressio
|
|||||||
InExpression = ["NOT"] "IN" "(" (Atom {"," Atom} | Subselect) ")"
|
InExpression = ["NOT"] "IN" "(" (Atom {"," Atom} | Subselect) ")"
|
||||||
LikeExpression = ["NOT"] "LIKE" Expression ["ESCAPE" string_literal]
|
LikeExpression = ["NOT"] "LIKE" Expression ["ESCAPE" string_literal]
|
||||||
NullComparisonExpression = "IS" ["NOT"] "NULL"
|
NullComparisonExpression = "IS" ["NOT"] "NULL"
|
||||||
ExistsExpression = ["NOT"] "EXISTS" "(" Subselect ")"
|
ExistsExpression = "EXISTS" "(" Subselect ")"
|
||||||
|
|
||||||
Function = identifier "(" [Expression {"," Expression}] ")"
|
Function = identifier "(" [Expression {"," Expression}] ")"
|
||||||
|
@ -25,6 +25,11 @@ class Doctrine_Query_LanguageRecognition_TestCase extends Doctrine_UnitTestCase
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testEmptyQueryString()
|
||||||
|
{
|
||||||
|
$this->assertInvalidDql('');
|
||||||
|
}
|
||||||
|
|
||||||
public function testPlainFromClauseWithoutAlias()
|
public function testPlainFromClauseWithoutAlias()
|
||||||
{
|
{
|
||||||
$this->assertValidDql('FROM User');
|
$this->assertValidDql('FROM User');
|
||||||
@ -99,4 +104,180 @@ class Doctrine_Query_LanguageRecognition_TestCase extends Doctrine_UnitTestCase
|
|||||||
{
|
{
|
||||||
$this->assertValidDql('SELECT u.id FROM User u WHERE 1 IN (1, 2)');
|
$this->assertValidDql('SELECT u.id FROM User u WHERE 1 IN (1, 2)');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testUpdateWorksWithOneColumn()
|
||||||
|
{
|
||||||
|
$this->assertValidDql("UPDATE User u SET u.name = 'someone'");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUpdateWorksWithMultipleColumns()
|
||||||
|
{
|
||||||
|
$this->assertValidDql("UPDATE User u SET u.name = 'someone', u.email_id = 5");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testUpdateSupportsConditions()
|
||||||
|
{
|
||||||
|
$this->assertValidDql("UPDATE User u SET u.name = 'someone' WHERE u.id = 5");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDeleteAll()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('DELETE FROM Entity');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDeleteWithCondition()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('DELETE FROM Entity WHERE id = 3');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDeleteWithLimit()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('DELETE FROM Entity LIMIT 20');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDeleteWithLimitAndOffset()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('DELETE FROM Entity LIMIT 10 OFFSET 20');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAdditionExpression()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('SELECT u.*, (u.id + u.id) addition FROM User u');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSubtractionExpression()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('SELECT u.*, (u.id - u.id) subtraction FROM User u');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testDivisionExpression()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('SELECT u.*, (u.id/u.id) division FROM User u');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMultiplicationExpression()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('SELECT u.*, (u.id * u.id) multiplication FROM User u');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNegationExpression()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('SELECT u.*, -u.id negation FROM User u');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testExpressionWithPrecedingPlusSign()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('SELECT u.*, +u.id FROM User u');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAggregateFunctionInHavingClause()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('SELECT u.name FROM User u LEFT JOIN u.Phonenumber p HAVING COUNT(p.id) > 2');
|
||||||
|
$this->assertValidDql("SELECT u.name FROM User u LEFT JOIN u.Phonenumber p HAVING MAX(u.name) = 'zYne'");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMultipleAggregateFunctionsInHavingClause()
|
||||||
|
{
|
||||||
|
$this->assertValidDql("SELECT u.name FROM User u LEFT JOIN u.Phonenumber p HAVING MAX(u.name) = 'zYne'");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testLeftJoin()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('FROM User u LEFT JOIN u.Group');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testJoin()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('FROM User u JOIN u.Group');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInnerJoin()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('FROM User u INNER JOIN u.Group');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMultipleLeftJoin()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('FROM User u LEFT JOIN u.Group LEFT JOIN u.Phonenumber');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMultipleInnerJoin()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('SELECT u.name FROM User u INNER JOIN u.Group INNER JOIN u.Phonenumber');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMultipleInnerJoin2()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('SELECT u.name FROM User u INNER JOIN u.Group, u.Phonenumber');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMixingOfJoins()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('SELECT u.name, g.name, p.phonenumber FROM User u INNER JOIN u.Group g LEFT JOIN u.Phonenumber p');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testMixingOfJoins2()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('SELECT u.name, g.name, p.phonenumber FROM User u INNER JOIN u.Group.Phonenumber p');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOrderBySingleColumn()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('SELECT u.name FROM User u ORDER BY u.name');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOrderBySingleColumnAscending()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('SELECT u.name FROM User u ORDER BY u.name ASC');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOrderBySingleColumnDescending()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('SELECT u.name FROM User u ORDER BY u.name DESC');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOrderByMultipleColumns()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('SELECT u.firstname, u.lastname FROM User u ORDER BY u.lastname DESC, u.firstname DESC');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testOrderByWithFunctionExpression()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('SELECT u.name FROM User u ORDER BY COALESCE(u.id, u.name) DESC');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSubselectInInExpression()
|
||||||
|
{
|
||||||
|
$this->assertValidDql("FROM User u WHERE u.id NOT IN (SELECT u2.id FROM User u2 WHERE u2.name = 'zYne')");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testSubselectInSelectPart()
|
||||||
|
{
|
||||||
|
$this->assertValidDql("SELECT u.name, (SELECT COUNT(p.id) FROM Phonenumber p WHERE p.entity_id = u.id) pcount FROM User u WHERE u.name = 'zYne' LIMIT 1");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testInputParameter()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('FROM User WHERE u.id = ?');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testNamedInputParameter()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('FROM User WHERE u.id = :id');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testCustomJoinsAndWithKeywordSupported()
|
||||||
|
{
|
||||||
|
$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.id FROM User u LEFT JOIN u.Phonenumber p ON p.phonenumber = '123 123'");
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIndexByClauseWithOneComponent()
|
||||||
|
{
|
||||||
|
$this->assertValidDql('FROM Record_City c INDEX BY c.name');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -91,6 +91,24 @@ class Doctrine_Query_Scanner_TestCase extends Doctrine_UnitTestCase
|
|||||||
$this->assertEqual("'abc''defg'''", $token['value']);
|
$this->assertEqual("'abc''defg'''", $token['value']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testScannerRecognizesInputParameter()
|
||||||
|
{
|
||||||
|
$scanner = new Doctrine_Query_Scanner('?');
|
||||||
|
|
||||||
|
$token = $scanner->next();
|
||||||
|
$this->assertEqual(Doctrine_Query_Token::T_INPUT_PARAMETER, $token['type']);
|
||||||
|
$this->assertEqual('?', $token['value']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testScannerRecognizesNamedInputParameter()
|
||||||
|
{
|
||||||
|
$scanner = new Doctrine_Query_Scanner(':name');
|
||||||
|
|
||||||
|
$token = $scanner->next();
|
||||||
|
$this->assertEqual(Doctrine_Query_Token::T_INPUT_PARAMETER, $token['type']);
|
||||||
|
$this->assertEqual(':name', $token['value']);
|
||||||
|
}
|
||||||
|
|
||||||
public function testScannerTokenizesASimpleQueryCorrectly()
|
public function testScannerTokenizesASimpleQueryCorrectly()
|
||||||
{
|
{
|
||||||
$dql = "SELECT u.* FROM User u WHERE u.name = 'Jack O''Neil'";
|
$dql = "SELECT u.* FROM User u WHERE u.name = 'Jack O''Neil'";
|
||||||
|
Loading…
Reference in New Issue
Block a user