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