Commit cc09204a authored by Benjamin Eberlei's avatar Benjamin Eberlei

Merge branch 'DBAL-172' into 2.1.x

parents 7df036a6 fa092140
...@@ -24,10 +24,10 @@ use Doctrine\DBAL\Query\Expression\CompositeExpression, ...@@ -24,10 +24,10 @@ use Doctrine\DBAL\Query\Expression\CompositeExpression,
/** /**
* QueryBuilder class is responsible to dynamically create SQL queries. * QueryBuilder class is responsible to dynamically create SQL queries.
* *
* Important: Verify that every feature you use will work with your database vendor. * Important: Verify that every feature you use will work with your database vendor.
* SQL Query Builder does not attempt to validate the generated SQL at all. * SQL Query Builder does not attempt to validate the generated SQL at all.
* *
* The query builder does no validation whatsoever if certain features even work with the * The query builder does no validation whatsoever if certain features even work with the
* underlying database vendor. Limit queries and joins are NOT applied to UPDATE and DELETE statements * underlying database vendor. Limit queries and joins are NOT applied to UPDATE and DELETE statements
* even if some vendors such as MySQL support it. * even if some vendors such as MySQL support it.
...@@ -102,10 +102,10 @@ class QueryBuilder ...@@ -102,10 +102,10 @@ class QueryBuilder
* @var integer The maximum number of results to retrieve. * @var integer The maximum number of results to retrieve.
*/ */
private $maxResults = null; private $maxResults = null;
/** /**
* The counter of bound parameters used with {@see bindValue) * The counter of bound parameters used with {@see bindValue)
* *
* @var int * @var int
*/ */
private $boundCounter = 0; private $boundCounter = 0;
...@@ -170,14 +170,14 @@ class QueryBuilder ...@@ -170,14 +170,14 @@ class QueryBuilder
{ {
return $this->state; return $this->state;
} }
/** /**
* Execute this query using the bound parameters and their types. * Execute this query using the bound parameters and their types.
* *
* Uses {@see Connection::executeQuery} for select statements and {@see Connection::executeUpdate} * Uses {@see Connection::executeQuery} for select statements and {@see Connection::executeUpdate}
* for insert, update and delete statements. * for insert, update and delete statements.
* *
* @return mixed * @return mixed
*/ */
public function execute() public function execute()
{ {
...@@ -390,7 +390,7 @@ class QueryBuilder ...@@ -390,7 +390,7 @@ class QueryBuilder
} }
$this->sqlParts[$sqlPartName] = $sqlPart; $this->sqlParts[$sqlPartName] = $sqlPart;
return $this; return $this;
} }
...@@ -604,7 +604,7 @@ class QueryBuilder ...@@ -604,7 +604,7 @@ class QueryBuilder
) )
), true); ), true);
} }
/** /**
* Creates and adds a right join to the query. * Creates and adds a right join to the query.
* *
...@@ -939,69 +939,76 @@ class QueryBuilder ...@@ -939,69 +939,76 @@ class QueryBuilder
return $this; return $this;
} }
/** /**
* Converts this instance into a SELECT string in SQL. * Converts this instance into a SELECT string in SQL.
* *
* @return string * @return string
*/ */
private function getSQLForSelect() private function getSQLForSelect()
{ {
$query = 'SELECT ' . implode(', ', $this->sqlParts['select']) . ' FROM '; $query = 'SELECT ' . implode(', ', $this->sqlParts['select']) . ' FROM ';
$fromClauses = array(); $fromClauses = array();
// Loop through all FROM clauses // Loop through all FROM clauses
foreach ($this->sqlParts['from'] as $from) { foreach ($this->sqlParts['from'] as $from) {
$fromClause = $from['table'] . ' ' . $from['alias']; $fromClause = $from['table'] . ' ' . $from['alias'];
if (isset($this->sqlParts['join'][$from['alias']])) { if (isset($this->sqlParts['join'][$from['alias']])) {
foreach ($this->sqlParts['join'][$from['alias']] as $join) { foreach ($this->sqlParts['join'][$from['alias']] as $join) {
$fromClause .= ' ' . strtoupper($join['joinType']) $fromClause .= ' ' . strtoupper($join['joinType'])
. ' JOIN ' . $join['joinTable'] . ' ' . $join['joinAlias'] . ' JOIN ' . $join['joinTable'] . ' ' . $join['joinAlias']
. ' ON ' . ((string) $join['joinCondition']); . ' ON ' . ((string) $join['joinCondition']);
} }
} }
$fromClauses[] = $fromClause; $fromClauses[$from['alias']] = $fromClause;
} }
$query .= implode(', ', $fromClauses) // loop through all JOIN clasues for validation purpose
foreach ($this->sqlParts['join'] as $fromAlias => $joins) {
if ( ! isset($fromClauses[$fromAlias]) ) {
throw QueryException::unknownFromAlias($fromAlias, array_keys($fromClauses));
}
}
$query .= implode(', ', $fromClauses)
. ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : '') . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : '')
. ($this->sqlParts['groupBy'] ? ' GROUP BY ' . implode(', ', $this->sqlParts['groupBy']) : '') . ($this->sqlParts['groupBy'] ? ' GROUP BY ' . implode(', ', $this->sqlParts['groupBy']) : '')
. ($this->sqlParts['having'] !== null ? ' HAVING ' . ((string) $this->sqlParts['having']) : '') . ($this->sqlParts['having'] !== null ? ' HAVING ' . ((string) $this->sqlParts['having']) : '')
. ($this->sqlParts['orderBy'] ? ' ORDER BY ' . implode(', ', $this->sqlParts['orderBy']) : ''); . ($this->sqlParts['orderBy'] ? ' ORDER BY ' . implode(', ', $this->sqlParts['orderBy']) : '');
return ($this->maxResults === null && $this->firstResult == null) return ($this->maxResults === null && $this->firstResult == null)
? $query ? $query
: $this->connection->getDatabasePlatform()->modifyLimitQuery($query, $this->maxResults, $this->firstResult); : $this->connection->getDatabasePlatform()->modifyLimitQuery($query, $this->maxResults, $this->firstResult);
} }
/** /**
* Converts this instance into an UPDATE string in SQL. * Converts this instance into an UPDATE string in SQL.
* *
* @return string * @return string
*/ */
private function getSQLForUpdate() private function getSQLForUpdate()
{ {
$table = $this->sqlParts['from']['table'] . ($this->sqlParts['from']['alias'] ? ' ' . $this->sqlParts['from']['alias'] : ''); $table = $this->sqlParts['from']['table'] . ($this->sqlParts['from']['alias'] ? ' ' . $this->sqlParts['from']['alias'] : '');
$query = 'UPDATE ' . $table $query = 'UPDATE ' . $table
. ' SET ' . implode(", ", $this->sqlParts['set']) . ' SET ' . implode(", ", $this->sqlParts['set'])
. ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : ''); . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : '');
return $query; return $query;
} }
/** /**
* Converts this instance into a DELETE string in SQL. * Converts this instance into a DELETE string in SQL.
* *
* @return string * @return string
*/ */
private function getSQLForDelete() private function getSQLForDelete()
{ {
$table = $this->sqlParts['from']['table'] . ($this->sqlParts['from']['alias'] ? ' ' . $this->sqlParts['from']['alias'] : ''); $table = $this->sqlParts['from']['table'] . ($this->sqlParts['from']['alias'] ? ' ' . $this->sqlParts['from']['alias'] : '');
$query = 'DELETE FROM ' . $table . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : ''); $query = 'DELETE FROM ' . $table . ($this->sqlParts['where'] !== null ? ' WHERE ' . ((string) $this->sqlParts['where']) : '');
return $query; return $query;
} }
...@@ -1015,7 +1022,7 @@ class QueryBuilder ...@@ -1015,7 +1022,7 @@ class QueryBuilder
{ {
return $this->getSQL(); return $this->getSQL();
} }
/** /**
* Create a new named parameter and bind the value $value to it. * Create a new named parameter and bind the value $value to it.
* *
...@@ -1053,15 +1060,15 @@ class QueryBuilder ...@@ -1053,15 +1060,15 @@ class QueryBuilder
return $placeHolder; return $placeHolder;
} }
/** /**
* Create a new positional parameter and bind the given value to it. * Create a new positional parameter and bind the given value to it.
* *
* Attention: If you are using positional parameters with the query builder you have * Attention: If you are using positional parameters with the query builder you have
* to be very careful to bind all parameters in the order they appear in the SQL * to be very careful to bind all parameters in the order they appear in the SQL
* statement , otherwise they get bound in the wrong order which can lead to serious * statement , otherwise they get bound in the wrong order which can lead to serious
* bugs in your code. * bugs in your code.
* *
* Example: * Example:
* <code> * <code>
* $qb = $conn->createQueryBuilder(); * $qb = $conn->createQueryBuilder();
...@@ -1070,7 +1077,7 @@ class QueryBuilder ...@@ -1070,7 +1077,7 @@ class QueryBuilder
* ->where('u.username = ' . $qb->createPositionalParameter('Foo', PDO::PARAM_STR)) * ->where('u.username = ' . $qb->createPositionalParameter('Foo', PDO::PARAM_STR))
* ->orWhere('u.username = ' . $qb->createPositionalParameter('Bar', PDO::PARAM_STR)) * ->orWhere('u.username = ' . $qb->createPositionalParameter('Bar', PDO::PARAM_STR))
* </code> * </code>
* *
* @param mixed $value * @param mixed $value
* @param mixed $type * @param mixed $type
* @return string * @return string
......
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\DBAL\Query;
use Doctrine\DBAL\DBALException;
/**
* Driver interface.
* Interface that all DBAL drivers must implement.
*
* @since 2.1.4
*/
class QueryException extends DBALException
{
static public function unknownFromAlias($alias, $registeredAliases)
{
return new self("The given alias '" . $alias . "' is not part of " .
"any FROM clause table. The currently registered FROM-clause " .
"aliases are: " . implode(", ", $registeredAliases) . ". Join clauses " .
"are bound to from clauses to provide support for mixing of multiple " .
"from and join clauses.");
}
}
\ No newline at end of file
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