Commit 3f60b8b5 authored by romanb's avatar romanb

More DQL parser work. First basic WHERE conditions. Changed scanner according...

More DQL parser work. First basic WHERE conditions. Changed scanner according to new positional parameter syntax (?<number>)
parent 663a7415
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* ArithmeticExpression ::= SimpleArithmeticExpression | "(" Subselect ")"
*
* @author robo
*/
class Doctrine_ORM_Query_AST_ArithmeticExpression extends Doctrine_ORM_Query_AST
{
private $_simpleArithmeticExpression;
private $_subselect;
public function setSimpleArithmeticExpression($simpleArithmeticExpr)
{
if ($this->_subselect) throw new Doctrine_Exception;
$this->_simpleArithmeticExpression = $simpleArithmeticExpr;
}
public function setSubselect($subselect)
{
if ($this->_simpleArithmeticExpression) throw new Doctrine_Exception;
$this->_subselect = $subselect;
}
public function getSimpleArithmeticExpression()
{
return $this->_simpleArithmeticExpression;
}
public function getSubselect()
{
return $this->_subselect;
}
public function isSimpleArithmeticExpression()
{
return (bool)$this->_simpleArithmeticExpression;
}
public function isSubselect()
{
return (bool)$this->_subselect;
}
}
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* ArithmeticFactor ::= [("+" | "-")] ArithmeticPrimary
*
* @author robo
*/
class Doctrine_ORM_Query_AST_ArithmeticFactor extends Doctrine_ORM_Query_AST
{
private $_arithmeticPrimary;
private $_pSigned;
private $_nSigned;
public function __construct($arithmeticPrimary, $pSigned = false, $nSigned = false)
{
$this->_arithmeticPrimary = $arithmeticPrimary;
$this->_pSigned = $pSigned;
$this->_nSigned = $nSigned;
}
public function getArithmeticPrimary()
{
return $this->_arithmeticPrimary;
}
public function isPositiveSigned()
{
return $this->_pSigned;
}
public function isNegativeSigned()
{
return $this->_nSigned;
}
}
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* ArithmeticTerm ::= ArithmeticFactor {("*" | "/") ArithmeticFactor}*
*
* @author robo
*/
class Doctrine_ORM_Query_AST_ArithmeticTerm extends Doctrine_ORM_Query_AST
{
private $_factors;
public function __construct(array $arithmeticFactors)
{
$this->_factors = $arithmeticFactors;
}
public function getArithmeticFactors()
{
return $this->_factors;
}
}
......@@ -5,12 +5,41 @@
*/
/**
* Description of ComparisonExpression
* ComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression ) |
* StringExpression ComparisonOperator (StringExpression | QuantifiedExpression) |
* BooleanExpression ("=" | "<>" | "!=") (BooleanExpression | QuantifiedExpression) |
* EnumExpression ("=" | "<>" | "!=") (EnumExpression | QuantifiedExpression) |
* DatetimeExpression ComparisonOperator (DatetimeExpression | QuantifiedExpression) |
* EntityExpression ("=" | "<>") (EntityExpression | QuantifiedExpression)
*
* @author robo
*/
class Doctrine_ORM_Query_AST_ComparisonExpression extends Doctrine_ORM_Query_AST
{
private $_leftExpr;
private $_rightExpr;
private $_operator;
public function __construct($leftExpr, $operator, $rightExpr)
{
$this->_leftExpr = $leftExpr;
$this->_rightExpr = $rightExpr;
$this->_operator = $operator;
}
public function getLeftExpression()
{
return $this->_leftExpr;
}
public function getRightExpression()
{
return $this->_rightExpr;
}
public function getOperator()
{
return $this->_operator;
}
}
<?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>.
*/
/**
* ComparisonOperator = "=" | "<" | "<=" | "<>" | ">" | ">=" | "!="
*
* @package Doctrine
* @subpackage Query
* @author Guilherme Blanco <guilhermeblanco@hotmail.com>
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link http://www.phpdoctrine.org
* @since 2.0
* @version $Revision$
*/
class Doctrine_ORM_Query_AST_ComparisonOperator extends Doctrine_ORM_Query_AST
{
}
......@@ -20,7 +20,7 @@ class Doctrine_ORM_Query_AST_ConditionalExpression extends Doctrine_ORM_Query_AS
public function getConditionalTerms()
{
return $this->_conditionalTerm;
return $this->_conditionalTerms;
}
}
......@@ -33,5 +33,15 @@ class Doctrine_ORM_Query_AST_ConditionalPrimary extends Doctrine_ORM_Query_AST
{
return $this->_conditionalExpression;
}
public function isSimpleConditionalExpression()
{
return (bool)$this->_simpleConditionalExpression;
}
public function isConditionalExpression()
{
return (bool)$this->_conditionalExpression;
}
}
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* Description of InputParameter
*
* @author robo
*/
class Doctrine_ORM_Query_AST_InputParameter extends Doctrine_ORM_Query_AST
{
private $_isNamed;
private $_position;
private $_name;
public function __construct($value)
{
$param = substr($value, 1);
$this->_isNamed = ! is_numeric($param);
if ($this->_isNamed) {
$this->_name = $param;
} else {
$this->_position = $param;
}
}
public function isNamed()
{
return $this->_isNamed;
}
public function isPositional()
{
return ! $this->_isNamed;
}
public function getName()
{
return $this->_name;
}
public function getPosition()
{
return $this->_position;
}
}
......@@ -17,6 +17,7 @@ class Doctrine_ORM_Query_AST_PathExpression
private $_isSimpleStateFieldAssociationPathExpression = false;
private $_embeddedClassFields = array();
private $_singleValuedAssociationFields = array();
private $_collectionValuedAssociationFields = array();
public function __construct(array $parts)
{
......@@ -61,6 +62,11 @@ class Doctrine_ORM_Query_AST_PathExpression
return isset($this->_singleValuedAssociationFields[$part]);
}
public function isPartCollectionValuedAssociationField($part)
{
return isset($this->_collectionValuedAssociationFields[$part]);
}
/* Setters to attach semantical information during semantical analysis. */
public function setIsSimpleStateFieldPathExpression($bool)
......@@ -82,5 +88,10 @@ class Doctrine_ORM_Query_AST_PathExpression
{
$this->_singleValuedAssociationFields[$part] = true;
}
public function setIsCollectionValuedAssociationPart($part)
{
$this->_collectionValuedAssociationFields[$part] = true;
}
}
<?php
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
/**
* SimpleArithmeticExpression ::= ArithmeticTerm {("+" | "-") ArithmeticTerm}*
*
* @author robo
*/
class Doctrine_ORM_Query_AST_SimpleArithmeticExpression extends Doctrine_ORM_Query_AST
{
private $_terms;
public function __construct(array $arithmeticTerms)
{
$this->_terms = $arithmeticTerms;
}
public function getArithmeticTerms()
{
return $this->_terms;
}
}
<?php
/**
* SimpleConditionalExpression ::= ExistsExpression |
* (SimpleStateFieldPathExpression (ComparisonExpression | BetweenExpression | LikeExpression |
* InExpression | NullComparisonExpression)) |
* (CollectionValuedPathExpression EmptyCollectionComparisonExpression) |
* (EntityExpression CollectionMemberExpression)
*
* @author robo
*/
class Doctrine_ORM_Query_AST_SimpleConditionalExpression extends Doctrine_ORM_Query_AST
{
}
This diff is collapsed.
......@@ -91,7 +91,7 @@ class Doctrine_ORM_Query_Scanner
'[a-z_][a-z0-9_]*',
'(?:[0-9]+(?:[,\.][0-9]+)*)(?:e[+-]?[0-9]+)?',
"'(?:[^']|'')*'",
'\?|:[a-z]+'
'\?[0-9]+|:[a-z]+'
);
$regex = '/(' . implode(')|(', $patterns) . ')|\s+|(.)/i';
}
......
......@@ -44,7 +44,9 @@ class Doctrine_ORM_Query_SqlWalker
{
$sql = $this->walkSelectClause($AST->getSelectClause());
$sql .= $this->walkFromClause($AST->getFromClause());
$sql .= $AST->getWhereClause() ? $this->walkWhereClause($AST->getWhereClause()) : '';
$sql .= $AST->getGroupByClause() ? $this->walkGroupByClause($AST->getGroupByClause()) : '';
//... more clauses
return $sql;
}
......@@ -223,6 +225,122 @@ class Doctrine_ORM_Query_SqlWalker
}
public function walkWhereClause($whereClause)
{
$sql = ' WHERE ';
$condExpr = $whereClause->getConditionalExpression();
foreach ($condExpr->getConditionalTerms() as $term) {
$sql .= $this->walkConditionalTerm($term);
}
return $sql;
}
public function walkConditionalTerm($condTerm)
{
$sql = '';
foreach ($condTerm->getConditionalFactors() as $factor) {
$sql .= $this->walkConditionalFactor($factor);
}
return $sql;
}
public function walkConditionalFactor($factor)
{
$sql = '';
if ($factor->isNot()) $sql .= ' NOT ';
$primary = $factor->getConditionalPrimary();
if ($primary->isSimpleConditionalExpression()) {
$simpleCond = $primary->getSimpleConditionalExpression();
if ($simpleCond instanceof Doctrine_ORM_Query_AST_ComparisonExpression) {
$sql .= $this->walkComparisonExpression($simpleCond);
}
// else if ...
}
return $sql;
}
public function walkComparisonExpression($compExpr)
{
$sql = '';
if ($compExpr->getLeftExpression() instanceof Doctrine_ORM_Query_AST_ArithmeticExpression) {
$sql .= $this->walkArithmeticExpression($compExpr->getLeftExpression());
} // else...
$sql .= ' ' . $compExpr->getOperator() . ' ';
if ($compExpr->getRightExpression() instanceof Doctrine_ORM_Query_AST_ArithmeticExpression) {
$sql .= $this->walkArithmeticExpression($compExpr->getRightExpression());
}
return $sql;
}
public function walkArithmeticExpression($arithmeticExpr)
{
$sql = '';
if ($arithmeticExpr->isSimpleArithmeticExpression()) {
foreach ($arithmeticExpr->getSimpleArithmeticExpression()->getArithmeticTerms() as $term) {
$sql .= $this->walkArithmeticTerm($term);
}
} else {
$sql .= $this->walkSubselect($arithmeticExpr->getSubselect());
}
return $sql;
}
public function walkArithmeticTerm($term)
{
$sql = '';
foreach ($term->getArithmeticFactors() as $factor) {
$sql .= $this->walkArithmeticFactor($factor);
}
return $sql;
}
public function walkArithmeticFactor($factor)
{
$sql = '';
$primary = $factor->getArithmeticPrimary();
if ($primary instanceof Doctrine_ORM_Query_AST_PathExpression) {
$sql .= $this->walkPathExpression($primary);
} else if ($primary instanceof Doctrine_ORM_Query_AST_InputParameter) {
if ($primary->isNamed()) {
$sql .= ':' . $primary->getName();
} else {
$sql .= '?';
}
}
// else...
return $sql;
}
public function walkPathExpression($pathExpr)
{
$sql = '';
if ($pathExpr->isSimpleStateFieldPathExpression()) {
$parts = $pathExpr->getParts();
$numParts = count($parts);
$dqlAlias = $parts[0];
$fieldName = $parts[$numParts-1];
$qComp = $this->_parserResult->getQueryComponent($dqlAlias);
$class = $qComp['metadata'];
if ($numParts > 2) {
for ($i = 1; $i < $numParts-1; ++$i) {
//TODO
}
}
$sqlTableAlias = $this->_dqlToSqlAliasMap[$dqlAlias];
$sql .= $sqlTableAlias . '.' . $class->getColumnName($fieldName);
} else if ($pathExpr->isSimpleStateFieldAssociationPathExpression()) {
throw new Doctrine_Exception("Not yet implemented.");
} else {
throw new Doctrine_ORM_Query_Exception("Encountered invalid PathExpression during SQL construction.");
}
return $sql;
}
/**
* Generates an SQL table alias from given table name and associates
* it with given component alias
......
......@@ -88,58 +88,11 @@ final class Doctrine_ORM_Query_Token
const T_FALSE = 147;
protected $_keywordsTable = array();
protected $_keywordsTable;
public function __construct()
{
$this->addKeyword(self::T_ALL, "ALL");
$this->addKeyword(self::T_AND, "AND");
$this->addKeyword(self::T_ANY, "ANY");
$this->addKeyword(self::T_AS, "AS");
$this->addKeyword(self::T_ASC, "ASC");
$this->addKeyword(self::T_AVG, "AVG");
$this->addKeyword(self::T_BETWEEN, "BETWEEN");
$this->addKeyword(self::T_BY, "BY");
$this->addKeyword(self::T_COMMA, ",");
$this->addKeyword(self::T_COUNT, "COUNT");
$this->addKeyword(self::T_DELETE, "DELETE");
$this->addKeyword(self::T_DESC, "DESC");
$this->addKeyword(self::T_DISTINCT, "DISTINCT");
$this->addKeyword(self::T_DOT, ".");
$this->addKeyword(self::T_ESCAPE, "ESPACE");
$this->addKeyword(self::T_EXISTS, "EXISTS");
$this->addKeyword(self::T_FALSE, "FALSE");
$this->addKeyword(self::T_FROM, "FROM");
$this->addKeyword(self::T_GROUP, "GROUP");
$this->addKeyword(self::T_HAVING, "HAVING");
$this->addKeyword(self::T_IN, "IN");
$this->addKeyword(self::T_INDEX, "INDEX");
$this->addKeyword(self::T_INNER, "INNER");
$this->addKeyword(self::T_IS, "IS");
$this->addKeyword(self::T_JOIN, "JOIN");
$this->addKeyword(self::T_LEFT, "LEFT");
$this->addKeyword(self::T_LIKE, "LIKE");
$this->addKeyword(self::T_LIMIT, "LIMIT");
$this->addKeyword(self::T_MAX, "MAX");
$this->addKeyword(self::T_MIN, "MIN");
$this->addKeyword(self::T_MOD, "MOD");
$this->addKeyword(self::T_NOT, "NOT");
$this->addKeyword(self::T_NULL, "NULL");
$this->addKeyword(self::T_OFFSET, "OFFSET");
$this->addKeyword(self::T_ON, "ON");
$this->addKeyword(self::T_OR, "OR");
$this->addKeyword(self::T_ORDER, "ORDER");
$this->addKeyword(self::T_OUTER, "OUTER");
$this->addKeyword(self::T_SELECT, "SELECT");
$this->addKeyword(self::T_SET, "SET");
$this->addKeyword(self::T_SIZE, "SIZE");
$this->addKeyword(self::T_SOME, "SOME");
$this->addKeyword(self::T_SUM, "SUM");
$this->addKeyword(self::T_TRUE, "TRUE");
$this->addKeyword(self::T_UPDATE, "UPDATE");
$this->addKeyword(self::T_WHERE, "WHERE");
$this->addKeyword(self::T_WITH, "WITH");
}
......@@ -151,6 +104,55 @@ final class Doctrine_ORM_Query_Token
public function getLiteral($token)
{
if ( ! $this->_keywordsTable) {
$this->addKeyword(self::T_ALL, "ALL");
$this->addKeyword(self::T_AND, "AND");
$this->addKeyword(self::T_ANY, "ANY");
$this->addKeyword(self::T_AS, "AS");
$this->addKeyword(self::T_ASC, "ASC");
$this->addKeyword(self::T_AVG, "AVG");
$this->addKeyword(self::T_BETWEEN, "BETWEEN");
$this->addKeyword(self::T_BY, "BY");
$this->addKeyword(self::T_COMMA, ",");
$this->addKeyword(self::T_COUNT, "COUNT");
$this->addKeyword(self::T_DELETE, "DELETE");
$this->addKeyword(self::T_DESC, "DESC");
$this->addKeyword(self::T_DISTINCT, "DISTINCT");
$this->addKeyword(self::T_DOT, ".");
$this->addKeyword(self::T_ESCAPE, "ESPACE");
$this->addKeyword(self::T_EXISTS, "EXISTS");
$this->addKeyword(self::T_FALSE, "FALSE");
$this->addKeyword(self::T_FROM, "FROM");
$this->addKeyword(self::T_GROUP, "GROUP");
$this->addKeyword(self::T_HAVING, "HAVING");
$this->addKeyword(self::T_IN, "IN");
$this->addKeyword(self::T_INDEX, "INDEX");
$this->addKeyword(self::T_INNER, "INNER");
$this->addKeyword(self::T_IS, "IS");
$this->addKeyword(self::T_JOIN, "JOIN");
$this->addKeyword(self::T_LEFT, "LEFT");
$this->addKeyword(self::T_LIKE, "LIKE");
$this->addKeyword(self::T_LIMIT, "LIMIT");
$this->addKeyword(self::T_MAX, "MAX");
$this->addKeyword(self::T_MIN, "MIN");
$this->addKeyword(self::T_MOD, "MOD");
$this->addKeyword(self::T_NOT, "NOT");
$this->addKeyword(self::T_NULL, "NULL");
$this->addKeyword(self::T_OFFSET, "OFFSET");
$this->addKeyword(self::T_ON, "ON");
$this->addKeyword(self::T_OR, "OR");
$this->addKeyword(self::T_ORDER, "ORDER");
$this->addKeyword(self::T_OUTER, "OUTER");
$this->addKeyword(self::T_SELECT, "SELECT");
$this->addKeyword(self::T_SET, "SET");
$this->addKeyword(self::T_SIZE, "SIZE");
$this->addKeyword(self::T_SOME, "SOME");
$this->addKeyword(self::T_SUM, "SUM");
$this->addKeyword(self::T_TRUE, "TRUE");
$this->addKeyword(self::T_UPDATE, "UPDATE");
$this->addKeyword(self::T_WHERE, "WHERE");
$this->addKeyword(self::T_WITH, "WITH");
}
return isset($this->_keywordsTable[$token])
? $this->_keywordsTable[$token]
: (is_string($token) ? $token : '');
......
......@@ -50,6 +50,7 @@ class Orm_Query_SelectSqlGenerationTest extends Doctrine_OrmTestCase
parent::assertEquals($sqlToBeConfirmed, $query->getSql());
$query->free();
} catch (Doctrine_Exception $e) {
echo $e->getMessage();
echo $e->getTraceAsString(); die();
$this->fail($e->getMessage());
}
......@@ -112,7 +113,7 @@ class Orm_Query_SelectSqlGenerationTest extends Doctrine_OrmTestCase
public function testWhereClauseInSelect()
{
$this->assertSqlGeneration(
'select u from ForumUser u where u.id = ?',
'select u from ForumUser u where u.id = ?1',
'SELECT fu.id AS fu__id, fu.username AS fu__username FROM ForumUser fu WHERE fu.id = ?'
);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment