Commit cd50fc38 authored by guilhermeblanco's avatar guilhermeblanco

[2.0] Implemented EmptyCollectionComparisonExpression. Need to write SQL transformation yet.

parent 462a27ee
......@@ -55,41 +55,42 @@ class Lexer
const T_DESC = 112;
const T_DISTINCT = 113;
const T_DOT = 114;
const T_ESCAPE = 115;
const T_EXISTS = 116;
const T_FROM = 117;
const T_GROUP = 118;
const T_HAVING = 119;
const T_IN = 120;
const T_INDEX = 121;
const T_INNER = 122;
const T_IS = 123;
const T_JOIN = 124;
const T_LEFT = 125;
const T_LIKE = 126;
const T_LIMIT = 127;
const T_MAX = 128;
const T_MIN = 129;
const T_MOD = 130;
const T_NOT = 131;
const T_NULL = 132;
const T_OFFSET = 133;
const T_ON = 134;
const T_OR = 135;
const T_ORDER = 136;
const T_OUTER = 137;
const T_SELECT = 138;
const T_SET = 139;
const T_SIZE = 140;
const T_SOME = 141;
const T_SUM = 142;
const T_UPDATE = 143;
const T_WHERE = 144;
const T_WITH = 145;
const T_TRUE = 146;
const T_FALSE = 147;
const T_MEMBER = 148;
const T_OF = 149;
const T_EMPTY = 115;
const T_ESCAPE = 116;
const T_EXISTS = 117;
const T_FROM = 118;
const T_GROUP = 119;
const T_HAVING = 120;
const T_IN = 121;
const T_INDEX = 122;
const T_INNER = 123;
const T_IS = 124;
const T_JOIN = 125;
const T_LEFT = 126;
const T_LIKE = 127;
const T_LIMIT = 128;
const T_MAX = 129;
const T_MIN = 130;
const T_MOD = 131;
const T_NOT = 132;
const T_NULL = 133;
const T_OFFSET = 134;
const T_ON = 135;
const T_OR = 136;
const T_ORDER = 137;
const T_OUTER = 138;
const T_SELECT = 139;
const T_SET = 140;
const T_SIZE = 141;
const T_SOME = 142;
const T_SUM = 143;
const T_UPDATE = 144;
const T_WHERE = 145;
const T_WITH = 146;
const T_TRUE = 147;
const T_FALSE = 148;
const T_MEMBER = 149;
const T_OF = 150;
private $_keywordsTable;
......@@ -354,6 +355,7 @@ class Lexer
self::T_DESC => "DESC",
self::T_DISTINCT => "DISTINCT",
self::T_DOT => ".",
self::T_EMPTY => "EMPTY",
self::T_ESCAPE => "ESCAPE",
self::T_EXISTS => "EXISTS",
self::T_FALSE => "FALSE",
......
......@@ -1639,7 +1639,7 @@ class Parser
* InExpression | NullComparisonExpression | ExistsExpression |
* EmptyCollectionComparisonExpression | CollectionMemberExpression
*
* @todo Posy 2.0 release. Missing EmptyCollectionComparisonExpression implementation
* @todo Post 2.0 release. Missing EmptyCollectionComparisonExpression implementation
*/
public function SimpleConditionalExpression()
{
......@@ -1669,9 +1669,18 @@ class Parser
if ($peek['type'] === Lexer::T_NOT) {
$peek = $this->_lexer->peek();
}
$this->_lexer->resetPeek();
$token = $peek;
// We need to go even further in case of IS (differenciate between NULL and EMPTY)
$lookahead = $this->_lexer->peek();
// Also peek beyond a NOT if there is one
if ($lookahead['type'] === Lexer::T_NOT) {
$lookahead = $this->_lexer->peek();
}
$this->_lexer->resetPeek();
}
if ($pathExprOrInputParam) {
......@@ -1689,7 +1698,11 @@ class Parser
return $this->InExpression();
case Lexer::T_IS:
return $this->NullComparisonExpression();
if ($lookahead['type'] == Lexer::T_NULL) {
return $this->NullComparisonExpression();
}
return $this->EmptyCollectionComparisonExpression();
case Lexer::T_MEMBER:
return $this->CollectionMemberExpression();
......@@ -1703,6 +1716,28 @@ class Parser
}
/**
* EmptyCollectionComparisonExpression ::= CollectionValuedPathExpression "IS" ["NOT"] "EMPTY"
*
* @return \Doctrine\ORM\Query\AST\EmptyCollectionComparisonExpression
*/
public function EmptyCollectionComparisonExpression()
{
$emptyColletionCompExpr = new AST\EmptyCollectionComparisonExpression(
$this->CollectionValuedPathExpression()
);
$this->match(Lexer::T_IS);
if ($this->_lexer->isNextToken(Lexer::T_NOT)) {
$this->match(Lexer::T_NOT);
$emptyColletionCompExpr->setNot(true);
}
$this->match(Lexer::T_EMPTY);
return $emptyColletionCompExpr;
}
/**
* CollectionMemberExpression ::= EntityExpression ["NOT"] "MEMBER" ["OF"] CollectionValuedPathExpression
*
......@@ -2122,9 +2157,6 @@ class Parser
/**
* ComparisonExpression ::= ArithmeticExpression ComparisonOperator ( QuantifiedExpression | ArithmeticExpression )
*
* @return AST\ComparisonExpression
* @todo Semantical checks whether $leftExpr $operator and $rightExpr are compatible.
*
* @return \Doctrine\ORM\Query\AST\ComparisonExpression
*/
public function ComparisonExpression()
......
......@@ -40,31 +40,42 @@ class SqlWalker implements TreeWalker
{
/** The ResultSetMapping. */
private $_rsm;
/** Counter for generating unique column aliases. */
private $_aliasCounter = 0;
/** Counter for generating unique table aliases. */
private $_tableAliasCounter = 0;
private $_scalarResultCounter = 1;
/** Counter for SQL parameter positions. */
private $_sqlParamIndex = 1;
/** The ParserResult. */
private $_parserResult;
/** The EntityManager. */
private $_em;
/** The Connection of the EntityManager. */
private $_conn;
/** The Query instance. */
private $_query;
private $_dqlToSqlAliasMap = array();
/** Map of all components/classes that appear in the DQL query. */
private $_queryComponents;
/** A list of classes that appear in non-scalar SelectExpressions. */
private $_selectedClasses = array();
/**
* The DQL alias of the root class of the currently traversed query.
* TODO: May need to be turned into a stack for usage in subqueries
*/
private $_currentRootAlias;
/**
* Flag that indicates whether to generate SQL table aliases in the SQL.
* These should only be generated for SELECT queries.
......@@ -123,6 +134,7 @@ class SqlWalker implements TreeWalker
{
$sql = $this->walkSelectClause($AST->getSelectClause());
$sql .= $this->walkFromClause($AST->getFromClause());
if ($whereClause = $AST->getWhereClause()) {
$sql .= $this->walkWhereClause($whereClause);
} else if ($discSql = $this->_generateDiscriminatorColumnConditionSql($this->_currentRootAlias)) {
......@@ -135,8 +147,8 @@ class SqlWalker implements TreeWalker
$q = $this->getQuery();
$sql = $this->getConnection()->getDatabasePlatform()->modifyLimitQuery(
$sql, $q->getMaxResults(), $q->getFirstResult()
);
$sql, $q->getMaxResults(), $q->getFirstResult()
);
return $sql;
}
......@@ -148,9 +160,9 @@ class SqlWalker implements TreeWalker
*/
public function walkSelectClause($selectClause)
{
$sql = 'SELECT ' . (($selectClause->isDistinct()) ? 'DISTINCT ' : '')
. implode(', ', array_map(array($this, 'walkSelectExpression'),
$selectClause->getSelectExpressions()));
$sql = 'SELECT ' . (($selectClause->isDistinct()) ? 'DISTINCT ' : '') . implode(
', ', array_map(array($this, 'walkSelectExpression'), $selectClause->getSelectExpressions())
);
foreach ($this->_selectedClasses as $dqlAlias => $class) {
if ($this->_queryComponents[$dqlAlias]['relation'] === null) {
......@@ -169,6 +181,7 @@ class SqlWalker implements TreeWalker
$discrColumn = $rootClass->discriminatorColumn;
$columnAlias = $this->getSqlColumnAlias($discrColumn['name']);
$sql .= ", $tblAlias." . $discrColumn['name'] . ' AS ' . $columnAlias;
$this->_rsm->setDiscriminatorColumn($dqlAlias, $columnAlias);
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $discrColumn['fieldName']);
}
......@@ -225,9 +238,9 @@ class SqlWalker implements TreeWalker
public function walkOrderByClause($orderByClause)
{
// OrderByClause ::= "ORDER" "BY" OrderByItem {"," OrderByItem}*
return ' ORDER BY '
. implode(', ', array_map(array($this, 'walkOrderByItem'),
$orderByClause->getOrderByItems()));
return ' ORDER BY ' . implode(
', ', array_map(array($this, 'walkOrderByItem'), $orderByClause->getOrderByItems())
);
}
/**
......@@ -244,6 +257,7 @@ class SqlWalker implements TreeWalker
$dqlAlias = $expr->getIdentificationVariable();
$qComp = $this->_queryComponents[$dqlAlias];
$columnName = $qComp['metadata']->getColumnName($parts[0]);
$sql = $this->getSqlTableAlias($qComp['metadata']->getTableName(), $dqlAlias) . '.' . $columnName;
$sql .= $orderByItem->isDesc() ? ' DESC' : ' ASC';
......@@ -258,8 +272,11 @@ class SqlWalker implements TreeWalker
*/
public function walkHavingClause($havingClause)
{
return ' HAVING ' . implode(' OR ', array_map(array($this, 'walkConditionalTerm'),
$havingClause->getConditionalExpression()->getConditionalTerms()));
$condExpr = $havingClause->getConditionalExpression();
return ' HAVING ' . implode(
' OR ', array_map(array($this, 'walkConditionalTerm'), $condExpr->getConditionalTerms())
);
}
/**
......@@ -272,6 +289,7 @@ class SqlWalker implements TreeWalker
{
$join = $joinVarDecl->getJoin();
$joinType = $join->getJoinType();
if ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER) {
$sql = ' LEFT JOIN ';
} else {
......@@ -304,6 +322,7 @@ class SqlWalker implements TreeWalker
} else {
$first = false;
}
if ($targetQComp['relation']->isOwningSide()) {
$sql .= "$sourceTableAlias.$sourceColumn = $targetTableAlias.$targetColumn";
} else {
......@@ -315,34 +334,34 @@ class SqlWalker implements TreeWalker
$joinTable = $assoc->getJoinTable();
$joinTableAlias = $this->getSqlTableAlias($joinTable['name']);
$sql .= $joinTable['name'] . ' ' . $joinTableAlias . ' ON ';
if ($targetQComp['relation']->isOwningSide) {
$sourceToRelationJoinColumns = $assoc->getSourceToRelationKeyColumns();
foreach ($sourceToRelationJoinColumns as $sourceColumn => $relationColumn) {
$sql .= "$sourceTableAlias.$sourceColumn = $joinTableAlias.$relationColumn";
}
} else {
$targetToRelationJoinColumns = $assoc->getTargetToRelationKeyColumns();
foreach ($targetToRelationJoinColumns as $targetColumn => $relationColumn) {
$sql .= "$sourceTableAlias.$targetColumn = $joinTableAlias.$relationColumn";
}
}
// Join target table
if ($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER) {
$sql .= ' LEFT JOIN ';
} else {
$sql .= ' INNER JOIN ';
}
$sql .= $targetTableName . ' ' . $targetTableAlias . ' ON ';
$sql .= (($joinType == AST\Join::JOIN_TYPE_LEFT || $joinType == AST\Join::JOIN_TYPE_LEFTOUTER)
? ' LEFT JOIN ' : ' INNER JOIN ') . $targetTableName . ' ' . $targetTableAlias . ' ON ';
if ($targetQComp['relation']->isOwningSide) {
$targetToRelationJoinColumns = $assoc->getTargetToRelationKeyColumns();
foreach ($targetToRelationJoinColumns as $targetColumn => $relationColumn) {
$sql .= "$targetTableAlias.$targetColumn = $joinTableAlias.$relationColumn";
}
} else {
$sourceToRelationJoinColumns = $assoc->getSourceToRelationKeyColumns();
foreach ($sourceToRelationJoinColumns as $sourceColumn => $relationColumn) {
$sql .= "$targetTableAlias.$sourceColumn = $joinTableAlias.$relationColumn";
}
......@@ -350,6 +369,7 @@ class SqlWalker implements TreeWalker
}
$discrSql = $this->_generateDiscriminatorColumnConditionSql($joinedDqlAlias);
if ($discrSql) {
$sql .= ' AND ' . $discrSql;
}
......@@ -389,8 +409,7 @@ class SqlWalker implements TreeWalker
$columnAlias = $this->getSqlColumnAlias($columnName);
$sql .= $sqlTableAlias . '.' . $columnName . ' AS ' . $columnAlias;
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName);
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName);
} else {
throw DoctrineException::updateMe("Encountered invalid PathExpression during SQL construction.");
}
......@@ -400,8 +419,10 @@ class SqlWalker implements TreeWalker
} else {
$resultAlias = $selectExpression->getFieldIdentificationVariable();
}
$columnAlias = 'sclr' . $this->_aliasCounter++;
$sql .= $this->walkAggregateExpression($expr) . ' AS ' . $columnAlias;
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
} else if ($expr instanceof AST\Subselect) {
$sql .= $this->walkSubselect($expr);
......@@ -411,12 +432,13 @@ class SqlWalker implements TreeWalker
} else {
$resultAlias = $selectExpression->getFieldIdentificationVariable();
}
$columnAlias = 'sclr' . $this->_aliasCounter++;
$sql .= $this->walkFunction($expr) . ' AS ' . $columnAlias;
$this->_rsm->addScalarResult($columnAlias, $resultAlias);
} else {
// IdentificationVariable
$dqlAlias = $expr;
$queryComp = $this->_queryComponents[$dqlAlias];
$class = $queryComp['metadata'];
......@@ -434,40 +456,52 @@ class SqlWalker implements TreeWalker
} else {
$tableName = $class->primaryTable['name'];
}
if ($beginning) $beginning = false; else $sql .= ', ';
$sqlTableAlias = $this->getSqlTableAlias($tableName, $dqlAlias);
$columnAlias = $this->getSqlColumnAlias($mapping['columnName']);
$sql .= $sqlTableAlias . '.' . $this->_conn->quoteIdentifier($mapping['columnName']) . ' AS ' . $columnAlias;
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName);
}
// Add any additional fields of subclasses (not inherited fields)
foreach ($class->subClasses as $subClassName) {
$subClass = $this->_em->getClassMetadata($subClassName);
foreach ($subClass->fieldMappings as $fieldName => $mapping) {
if (isset($mapping['inherited'])) {
continue;
}
if ($beginning) $beginning = false; else $sql .= ', ';
$sqlTableAlias = $this->getSqlTableAlias($subClass->primaryTable['name'], $dqlAlias);
$columnAlias = $this->getSqlColumnAlias($mapping['columnName']);
$sql .= $sqlTableAlias . '.' . $this->_conn->quoteIdentifier($mapping['columnName']) . ' AS ' . $columnAlias;
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName);
}
}
} else {
$fieldMappings = $class->fieldMappings;
foreach ($class->subClasses as $subclassName) {
$fieldMappings = array_merge(
$fieldMappings,
$this->_em->getClassMetadata($subclassName)->fieldMappings
);
}
$sqlTableAlias = $this->getSqlTableAlias($class->getTableName(), $dqlAlias);
foreach ($fieldMappings as $fieldName => $mapping) {
if ($beginning) $beginning = false; else $sql .= ', ';
$columnAlias = $this->getSqlColumnAlias($mapping['columnName']);
$sql .= $sqlTableAlias . '.' . $this->_conn->quoteIdentifier($mapping['columnName']) . ' AS ' . $columnAlias;
$this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName);
}
......@@ -475,13 +509,16 @@ class SqlWalker implements TreeWalker
//FIXME: Evaluate HINT_INCLUDE_META_COLUMNS
//FIXME: Needs to be done in the case of Class Table Inheritance, too
// (see upper block of the if/else)
if ( ! $this->_em->getConfiguration()->getAllowPartialObjects() &&
! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)) {
if (
! $this->_em->getConfiguration()->getAllowPartialObjects() &&
! $this->_query->getHint(Query::HINT_FORCE_PARTIAL_LOAD)
) {
foreach ($class->associationMappings as $assoc) {
if ($assoc->isOwningSide && $assoc->isOneToOne()) {
foreach ($assoc->targetToSourceKeyColumns as $srcColumn) {
$columnAlias = $this->getSqlColumnAlias($srcColumn);
$sql .= ', ' . $sqlTableAlias . '.' . $this->_conn->quoteIdentifier($srcColumn) . ' AS ' . $columnAlias;
$this->_rsm->addMetaResult($dqlAlias, $columnAlias, $srcColumn);
}
}
......@@ -503,9 +540,11 @@ class SqlWalker implements TreeWalker
public function walkQuantifiedExpression($qExpr)
{
$sql = '';
if ($qExpr->isAll()) $sql .= ' ALL';
else if ($qExpr->isAny()) $sql .= ' ANY';
else if ($qExpr->isSome()) $sql .= ' SOME';
return $sql .= '(' . $this->walkSubselect($qExpr->getSubselect()) . ')';
}
......@@ -519,12 +558,14 @@ class SqlWalker implements TreeWalker
{
$useAliasesBefore = $this->_useSqlTableAliases;
$this->_useSqlTableAliases = true;
$sql = $this->walkSimpleSelectClause($subselect->getSimpleSelectClause());
$sql .= $this->walkSubselectFromClause($subselect->getSubselectFromClause());
$sql .= $subselect->getWhereClause() ? $this->walkWhereClause($subselect->getWhereClause()) : '';
$sql .= $subselect->getGroupByClause() ? $this->walkGroupByClause($subselect->getGroupByClause()) : '';
$sql .= $subselect->getHavingClause() ? $this->walkHavingClause($subselect->getHavingClause()) : '';
$sql .= $subselect->getOrderByClause() ? $this->walkOrderByClause($subselect->getOrderByClause()) : '';
$this->_useSqlTableAliases = $useAliasesBefore;
return $sql;
......@@ -543,7 +584,7 @@ class SqlWalker implements TreeWalker
$firstIdentificationVarDecl = $identificationVarDecls[0];
$rangeDecl = $firstIdentificationVarDecl->getRangeVariableDeclaration();
$sql .= $rangeDecl->getClassMetadata()->getTableName() . ' '
. $this->getSqlTableAlias($rangeDecl->getClassMetadata()->getTableName(), $rangeDecl->getAliasIdentificationVariable());
. $this->getSqlTableAlias($rangeDecl->getClassMetadata()->getTableName(), $rangeDecl->getAliasIdentificationVariable());
foreach ($firstIdentificationVarDecl->getJoinVariableDeclarations() as $joinVarDecl) {
$sql .= $this->walkJoinVariableDeclaration($joinVarDecl);
......@@ -561,10 +602,13 @@ class SqlWalker implements TreeWalker
public function walkSimpleSelectClause($simpleSelectClause)
{
$sql = 'SELECT';
if ($simpleSelectClause->isDistinct()) {
$sql .= ' DISTINCT';
}
$sql .= $this->walkSimpleSelectExpression($simpleSelectClause->getSimpleSelectExpression());
return $sql;
}
......@@ -578,6 +622,7 @@ class SqlWalker implements TreeWalker
{
$sql = '';
$expr = $simpleSelectExpression->getExpression();
if ($expr instanceof AST\PathExpression) {
$sql .= ' ' . $this->walkPathExpression($expr);
//...
......@@ -587,6 +632,7 @@ class SqlWalker implements TreeWalker
} else {
$alias = $simpleSelectExpression->getFieldIdentificationVariable();
}
$sql .= $this->walkAggregateExpression($expr) . ' AS dctrn__' . $alias;
} else {
// IdentificationVariable
......@@ -596,6 +642,7 @@ class SqlWalker implements TreeWalker
$sql .= ' ' . $this->getSqlTableAlias($class->getTableName(), $expr) . '.';
$sql .= $class->getColumnName($class->identifier[0]);
}
return $sql;
}
......@@ -616,9 +663,12 @@ class SqlWalker implements TreeWalker
$columnName = $qComp['metadata']->getColumnName($fieldName);
$sql .= $aggExpression->getFunctionName() . '(';
if ($aggExpression->isDistinct()) $sql .= 'DISTINCT ';
$sql .= $this->getSqlTableAlias($qComp['metadata']->getTableName(), $dqlAlias) . '.' . $columnName;
$sql .= ')';
return $sql;
}
......@@ -630,9 +680,9 @@ class SqlWalker implements TreeWalker
*/
public function walkGroupByClause($groupByClause)
{
return ' GROUP BY '
. implode(', ', array_map(array($this, 'walkGroupByItem'),
$groupByClause->getGroupByItems()));
return ' GROUP BY ' . implode(
', ', array_map(array($this, 'walkGroupByItem'), $groupByClause->getGroupByItems())
);
}
/**
......@@ -648,6 +698,7 @@ class SqlWalker implements TreeWalker
$dqlAlias = $pathExpr->getIdentificationVariable();
$qComp = $this->_queryComponents[$dqlAlias];
$columnName = $qComp['metadata']->getColumnName($parts[0]);
return $this->getSqlTableAlias($qComp['metadata']->getTableName(), $dqlAlias) . '.' . $columnName;
}
......@@ -661,11 +712,13 @@ class SqlWalker implements TreeWalker
{
$this->_useSqlTableAliases = false; // TODO: Ask platform instead?
$sql = $this->walkUpdateClause($AST->getUpdateClause());
if ($whereClause = $AST->getWhereClause()) {
$sql .= $this->walkWhereClause($whereClause);
} else if ($discSql = $this->_generateDiscriminatorColumnConditionSql($this->_currentRootAlias)) {
$sql .= ' WHERE ' . $discSql;
}
return $sql;
}
......@@ -679,11 +732,13 @@ class SqlWalker implements TreeWalker
{
$this->_useSqlTableAliases = false; // TODO: Ask platform instead?
$sql = $this->walkDeleteClause($AST->getDeleteClause());
if ($whereClause = $AST->getWhereClause()) {
$sql .= $this->walkWhereClause($whereClause);
} else if ($discSql = $this->_generateDiscriminatorColumnConditionSql($this->_currentRootAlias)) {
$sql .= ' WHERE ' . $discSql;
}
return $sql;
}
......@@ -698,9 +753,11 @@ class SqlWalker implements TreeWalker
$sql = 'DELETE FROM ';
$class = $this->_em->getClassMetadata($deleteClause->getAbstractSchemaName());
$sql .= $class->getTableName();
if ($this->_useSqlTableAliases) {
$sql .= ' ' . $this->getSqlTableAlias($class->getTableName());
}
$this->_currentRootAlias = $deleteClause->getAliasIdentificationVariable();
return $sql;
......@@ -717,13 +774,16 @@ class SqlWalker implements TreeWalker
$sql = 'UPDATE ';
$class = $this->_em->getClassMetadata($updateClause->getAbstractSchemaName());
$sql .= $class->getTableName();
if ($this->_useSqlTableAliases) {
$sql .= ' ' . $this->getSqlTableAlias($class->getTableName());
}
$this->_currentRootAlias = $updateClause->getAliasIdentificationVariable();
$sql .= ' SET ' . implode(', ', array_map(array($this, 'walkUpdateItem'),
$updateClause->getUpdateItems()));
$sql .= ' SET ' . implode(
', ', array_map(array($this, 'walkUpdateItem'), $updateClause->getUpdateItems())
);
return $sql;
}
......@@ -746,6 +806,7 @@ class SqlWalker implements TreeWalker
if ($this->_useSqlTableAliases) {
$sql .= $this->getSqlTableAlias($qComp['metadata']->getTableName()) . '.';
}
$sql .= $qComp['metadata']->getColumnName($updateItem->getField()) . ' = ';
$newValue = $updateItem->getNewValue();
......@@ -776,12 +837,15 @@ class SqlWalker implements TreeWalker
$sql = ' WHERE ';
$condExpr = $whereClause->getConditionalExpression();
$sql .= implode(' OR ', array_map(array($this, 'walkConditionalTerm'),
$condExpr->getConditionalTerms()));
$sql .= implode(
' OR ', array_map(array($this, 'walkConditionalTerm'), $condExpr->getConditionalTerms())
);
$discrSql = $this->_generateDiscriminatorColumnConditionSql($this->_currentRootAlias);
if ($discrSql) {
if ($termsSql) $sql .= ' AND';
$sql .= ' ' . $discrSql;
}
......@@ -799,19 +863,25 @@ class SqlWalker implements TreeWalker
$sql = '';
if ($dqlAlias) {
$class = $this->_queryComponents[$dqlAlias]['metadata'];
if ($class->isInheritanceTypeSingleTable()) {
$conn = $this->_em->getConnection();
$values = array($conn->quote($class->discriminatorValue));
foreach ($class->subClasses as $subclassName) {
$values[] = $conn->quote($this->_em->getClassMetadata($subclassName)->discriminatorValue);
}
$discrColumn = $class->discriminatorColumn;
if ($this->_useSqlTableAliases) {
$sql .= $this->getSqlTableAlias($class->getTableName(), $dqlAlias) . '.';
}
$sql .= $discrColumn['name'] . ' IN (' . implode(', ', $values) . ')';
}
}
return $sql;
}
......@@ -823,8 +893,9 @@ class SqlWalker implements TreeWalker
*/
public function walkConditionalTerm($condTerm)
{
return implode(' AND ', array_map(array($this, 'walkConditionalFactor'),
$condTerm->getConditionalFactors()));
return implode(
' AND ', array_map(array($this, 'walkConditionalFactor'), $condTerm->getConditionalFactors())
);
}
/**
......@@ -836,14 +907,20 @@ class SqlWalker implements TreeWalker
public function walkConditionalFactor($factor)
{
$sql = '';
if ($factor->isNot()) $sql .= 'NOT ';
$primary = $factor->getConditionalPrimary();
if ($primary->isSimpleConditionalExpression()) {
$sql .= $primary->getSimpleConditionalExpression()->dispatch($this);
} else if ($primary->isConditionalExpression()) {
$sql .= '(' . implode(' OR ', array_map(array($this, 'walkConditionalTerm'),
$primary->getConditionalExpression()->getConditionalTerms())) . ')';
$condExpr = $primary->getConditionalExpression();
$sql .= '(' . implode(
' OR ', array_map(array($this, 'walkConditionalTerm'), $condExpr->getConditionalTerms())
) . ')';
}
return $sql;
}
......@@ -856,8 +933,11 @@ class SqlWalker implements TreeWalker
public function walkExistsExpression($existsExpr)
{
$sql = '';
if ($existsExpr->isNot()) $sql .= ' NOT';
$sql .= 'EXISTS (' . $this->walkSubselect($existsExpr->getSubselect()) . ')';
return $sql;
}
......@@ -881,7 +961,6 @@ class SqlWalker implements TreeWalker
if ($entityExpr instanceof AST\InputParameter) {
$dqlParamKey = $entityExpr->isNamed() ? $entityExpr->getName() : $entityExpr->getPosition();
$entity = $this->_query->getParameter($dqlParamKey);
} else {
throw DoctrineException::notImplemented();
}
......@@ -898,15 +977,19 @@ class SqlWalker implements TreeWalker
$owningAssoc = $targetClass->associationMappings[$assoc->mappedByFieldName];
$first = true;
foreach ($owningAssoc->targetToSourceKeyColumns as $targetColumn => $sourceColumn) {
if ($first) $first = false; else $sql .= ' AND ';
$sql .= $sourceTableAlias . '.' . $targetColumn . ' = ' . $targetTableAlias . '.' . $sourceColumn;
}
$sql .= ' AND ';
$first = true;
foreach ($targetClass->identifier as $idField) {
if ($first) $first = false; else $sql .= ' AND ';
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
$sql .= $targetTableAlias . '.' . $targetClass->columnNames[$idField] . ' = ?';
}
......@@ -919,15 +1002,17 @@ class SqlWalker implements TreeWalker
// join to target table
$sql .= $this->_conn->quoteIdentifier($joinTable['name'])
. ' ' . $joinTableAlias . ' INNER JOIN '
. $this->_conn->quoteIdentifier($targetClass->primaryTable['name'])
. ' ' . $targetTableAlias . ' ON ';
. ' ' . $joinTableAlias . ' INNER JOIN '
. $this->_conn->quoteIdentifier($targetClass->primaryTable['name'])
. ' ' . $targetTableAlias . ' ON ';
// join conditions
$joinColumns = $assoc->isOwningSide ? $joinTable['joinColumns'] : $joinTable['inverseJoinColumns'];
$first = true;
foreach ($joinColumns as $joinColumn) {
if ($first) $first = false; else $sql .= ' AND ';
$sql .= $joinTableAlias . '.' . $joinColumn['name'] . ' = ' . $sourceTableAlias . '.' . $joinColumn['referencedColumnName'];
}
......@@ -935,15 +1020,19 @@ class SqlWalker implements TreeWalker
$joinColumns = $assoc->isOwningSide ? $joinTable['inverseJoinColumns'] : $joinTable['joinColumns'];
$first = true;
foreach ($joinColumns as $joinColumn) {
if ($first) $first = false; else $sql .= ' AND ';
$sql .= $joinTableAlias . '.' . $joinColumn['name'] . ' = ' . $targetTableAlias . '.' . $joinColumn['referencedColumnName'];
}
$sql .= ' AND ';
$first = true;
foreach ($targetClass->identifier as $idField) {
if ($first) $first = false; else $sql .= ' AND ';
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
$sql .= $targetTableAlias . '.' . $targetClass->columnNames[$idField] . ' = ?';
}
......@@ -951,6 +1040,22 @@ class SqlWalker implements TreeWalker
return $sql . ')';
}
/**
* Walks down an EmptyCollectionComparisonExpression AST node, thereby generating the appropriate SQL.
*
* @param EmptyCollectionComparisonExpression
* @return string The SQL.
*
* @todo Finish this implementation. It is quite incomplete!
*/
public function walkEmptyCollectionComparisonExpression($emptyCollCompExpr)
{
$sql = $this->walkPathExpression($emptyCollCompExpr->getExpression());
$sql .= ' IS' . ($emptyCollCompExpr->isNot() ? ' NOT' : '') . ' EMPTY';
return $sql;
}
/**
* Walks down a NullComparisonExpression AST node, thereby generating the appropriate SQL.
......@@ -962,6 +1067,7 @@ class SqlWalker implements TreeWalker
{
$sql = '';
$innerExpr = $nullCompExpr->getExpression();
if ($innerExpr instanceof AST\InputParameter) {
$dqlParamKey = $innerExpr->isNamed() ? $innerExpr->getName() : $innerExpr->getPosition();
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
......@@ -969,7 +1075,9 @@ class SqlWalker implements TreeWalker
} else {
$sql .= $this->walkPathExpression($innerExpr);
}
$sql .= ' IS' . ($nullCompExpr->isNot() ? ' NOT' : '') . ' NULL';
return $sql;
}
......@@ -982,14 +1090,19 @@ class SqlWalker implements TreeWalker
public function walkInExpression($inExpr)
{
$sql = $this->walkPathExpression($inExpr->getPathExpression());
if ($inExpr->isNot()) $sql .= ' NOT';
$sql .= ' IN (';
if ($inExpr->getSubselect()) {
$sql .= $this->walkSubselect($inExpr->getSubselect());
} else {
$sql .= implode(', ', array_map(array($this, 'walkLiteral'), $inExpr->getLiterals()));
}
$sql .= ')';
return $sql;
}
......@@ -1004,10 +1117,11 @@ class SqlWalker implements TreeWalker
if ($literal instanceof AST\InputParameter) {
$dqlParamKey = $literal->isNamed() ? $literal->getName() : $literal->getPosition();
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
return '?';
} else {
return $literal; //TODO: quote() ?
}
return $literal; //TODO: quote() ?
}
/**
......@@ -1019,9 +1133,12 @@ class SqlWalker implements TreeWalker
public function walkBetweenExpression($betweenExpr)
{
$sql = $this->walkArithmeticExpression($betweenExpr->getBaseExpression());
if ($betweenExpr->getNot()) $sql .= ' NOT';
$sql .= ' BETWEEN ' . $this->walkArithmeticExpression($betweenExpr->getLeftBetweenExpression())
. ' AND ' . $this->walkArithmeticExpression($betweenExpr->getRightBetweenExpression());
. ' AND ' . $this->walkArithmeticExpression($betweenExpr->getRightBetweenExpression());
return $sql;
}
......@@ -1033,12 +1150,11 @@ class SqlWalker implements TreeWalker
*/
public function walkLikeExpression($likeExpr)
{
$sql = '';
$stringExpr = $likeExpr->getStringExpression();
$sql .= $stringExpr->dispatch($this);
$sql = $stringExpr->dispatch($this);
if ($likeExpr->isNot()) $sql .= ' NOT';
$sql .= ' LIKE ';
if ($likeExpr->getStringPattern() instanceof AST\InputParameter) {
......@@ -1049,9 +1165,11 @@ class SqlWalker implements TreeWalker
} else {
$sql .= $this->_conn->quote($likeExpr->getStringPattern());
}
if ($likeExpr->getEscapeChar()) {
$sql .= ' ESCAPE ' . $this->_conn->quote($likeExpr->getEscapeChar());
}
return $sql;
}
......@@ -1105,6 +1223,7 @@ class SqlWalker implements TreeWalker
{
$dqlParamKey = $inputParam->isNamed() ? $inputParam->getName() : $inputParam->getPosition();
$this->_parserResult->addParameterMapping($dqlParamKey, $this->_sqlParamIndex++);
return '?';
}
......@@ -1117,6 +1236,7 @@ class SqlWalker implements TreeWalker
public function walkArithmeticExpression($arithmeticExpr)
{
$sql = '';
if ($arithmeticExpr->isSimpleArithmeticExpression()) {
foreach ($arithmeticExpr->getSimpleArithmeticExpression()->getArithmeticTerms() as $term) {
$sql .= $this->walkArithmeticTerm($term);
......@@ -1124,6 +1244,7 @@ class SqlWalker implements TreeWalker
} else {
$sql .= $this->walkSubselect($arithmeticExpr->getSubselect());
}
return $sql;
}
......@@ -1137,8 +1258,9 @@ class SqlWalker implements TreeWalker
{
if (is_string($term)) return $term;
return implode(' ', array_map(array($this, 'walkArithmeticFactor'),
$term->getArithmeticFactors()));
return implode(
' ', array_map(array($this, 'walkArithmeticFactor'), $term->getArithmeticFactors())
);
}
/**
......@@ -1149,11 +1271,9 @@ class SqlWalker implements TreeWalker
*/
public function walkStringPrimary($stringPrimary)
{
if (is_string($stringPrimary)) {
return $this->_conn->quote($stringPrimary);
} else {
return $stringPrimary->dispatch($this);
}
return (is_string($stringPrimary))
? $this->_conn->quote($stringPrimary)
: $stringPrimary->dispatch($this);
}
/**
......@@ -1168,6 +1288,7 @@ class SqlWalker implements TreeWalker
$sql = '';
$primary = $factor->getArithmeticPrimary();
if (is_numeric($primary)) {
$sql .= $primary; //TODO: quote() ?
} else if (is_string($primary)) {
......@@ -1189,8 +1310,9 @@ class SqlWalker implements TreeWalker
*/
public function walkSimpleArithmeticExpression($simpleArithmeticExpr)
{
return implode(' ', array_map(array($this, 'walkArithmeticTerm'),
$simpleArithmeticExpr->getArithmeticTerms()));
return implode(
' ', array_map(array($this, 'walkArithmeticTerm'), $simpleArithmeticExpr->getArithmeticTerms())
);
}
/**
......@@ -1202,6 +1324,7 @@ class SqlWalker implements TreeWalker
public function walkPathExpression($pathExpr)
{
$sql = '';
if ($pathExpr->getType() == AST\PathExpression::TYPE_STATE_FIELD) {
$parts = $pathExpr->getParts();
$numParts = count($parts);
......@@ -1226,7 +1349,6 @@ class SqlWalker implements TreeWalker
} else {
$sql .= $this->_conn->quoteIdentifier($class->getColumnName($fieldName));
}
} else if ($pathExpr->isSimpleStateFieldAssociationPathExpression()) {
throw DoctrineException::updateMe("Not yet implemented.");
} else {
......@@ -1245,9 +1367,11 @@ class SqlWalker implements TreeWalker
public function getSqlTableAlias($tableName, $dqlAlias = '')
{
$tableName .= $dqlAlias;
if ( ! isset($this->_dqlToSqlAliasMap[$tableName])) {
$this->_dqlToSqlAliasMap[$tableName] = strtolower(substr($tableName, 0, 1)) . $this->_tableAliasCounter++ . '_';
}
return $this->_dqlToSqlAliasMap[$tableName];
}
......@@ -1295,8 +1419,10 @@ class SqlWalker implements TreeWalker
$tableAlias = $this->getSqlTableAlias($parentClass->primaryTable['name'], $dqlAlias);
$sql .= ' INNER JOIN ' . $parentClass->primaryTable['name'] . ' ' . $tableAlias . ' ON ';
$first = true;
foreach ($idColumns as $idColumn) {
if ($first) $first = false; else $sql .= ' AND ';
$sql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
}
}
......@@ -1307,8 +1433,10 @@ class SqlWalker implements TreeWalker
$tableAlias = $this->getSqlTableAlias($subClass->primaryTable['name'], $dqlAlias);
$sql .= ' LEFT JOIN ' . $subClass->primaryTable['name'] . ' ' . $tableAlias . ' ON ';
$first = true;
foreach ($idColumns as $idColumn) {
if ($first) $first = false; else $sql .= ' AND ';
$sql .= $baseTableAlias . '.' . $idColumn . ' = ' . $tableAlias . '.' . $idColumn;
}
}
......@@ -1330,6 +1458,7 @@ class SqlWalker implements TreeWalker
$primaryClass = $this->_em->getClassMetadata(
$AST->getDeleteClause()->getAbstractSchemaName()
);
if ($primaryClass->isInheritanceTypeJoined()) {
return new Exec\MultiTableDeleteExecutor($AST, $this);
} else {
......@@ -1339,6 +1468,7 @@ class SqlWalker implements TreeWalker
$primaryClass = $this->_em->getClassMetadata(
$AST->getUpdateClause()->getAbstractSchemaName()
);
if ($primaryClass->isInheritanceTypeJoined()) {
return new Exec\MultiTableUpdateExecutor($AST, $this);
} else {
......
......@@ -249,6 +249,14 @@ interface TreeWalker
* @return string The SQL.
*/
function walkCollectionMemberExpression($collMemberExpr);
/**
* Walks down an EmptyCollectionComparisonExpression AST node, thereby generating the appropriate SQL.
*
* @param EmptyCollectionComparisonExpression
* @return string The SQL.
*/
function walkEmptyCollectionComparisonExpression($emptyCollCompExpr);
/**
* Walks down a NullComparisonExpression AST node, thereby generating the appropriate SQL.
......
......@@ -247,6 +247,14 @@ abstract class TreeWalkerAdapter implements TreeWalker
*/
public function walkCollectionMemberExpression($collMemberExpr) {}
/**
* Walks down an EmptyCollectionComparisonExpression AST node, thereby generating the appropriate SQL.
*
* @param EmptyCollectionComparisonExpression
* @return string The SQL.
*/
public function walkEmptyCollectionComparisonExpression($emptyCollCompExpr) {}
/**
* Walks down a NullComparisonExpression AST node, thereby generating the appropriate SQL.
*
......
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