Commit 0ad6aee3 authored by romanb's avatar romanb

Merged DQL parser branch to trunk.

parent f8017c9c
......@@ -303,7 +303,8 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
*/
public function getDbh()
{
$this->connect();
//$this->connect();
return $this->dbh;
}
......@@ -319,8 +320,8 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
return false;
}
$event = new Doctrine_Event($this, Doctrine_Event::CONN_CONNECT);
$this->getListener()->preConnect($event);
//$event = new Doctrine_Event($this, Doctrine_Event::CONN_CONNECT);
//$this->getListener()->preConnect($event);
$e = explode(':', $this->options['dsn']);
if (extension_loaded('pdo')) {
......@@ -346,7 +347,7 @@ abstract class Doctrine_Connection extends Doctrine_Configurable implements Coun
$this->isConnected = true;
$this->getListener()->postConnect($event);
//$this->getListener()->postConnect($event);
return true;
}
......
......@@ -36,7 +36,7 @@ class Doctrine_Connection_Mock extends Doctrine_Connection_Common
/**
* @var string $driverName the name of this connection driver
*/
protected $driverName = 'Mock';
protected $driverName = 'MySql';
/**
* the constructor
......
......@@ -106,7 +106,7 @@ class Doctrine_Connection_Pgsql extends Doctrine_Connection_Common
{
if (is_array($item)) {
foreach ($item as $key => $value) {
if (is_bool($value)) {
if (is_bool($value) || is_numeric($item)) {
$item[$key] = ($value) ? 'true' : 'false';
}
}
......
......@@ -168,8 +168,6 @@ class Doctrine_Formatter extends Doctrine_Connection_Module
case 'gzip':
case 'blob':
case 'clob':
$this->conn->connect();
return $this->conn->getDbh()->quote($input);
}
}
......
......@@ -33,10 +33,9 @@
* @author Roman Borschel <roman@code-factory.org>
*/
class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
{
{
/**
* hydrateResultSet
* parses the data returned by statement object
*
* This is method defines the core of Doctrine's object population algorithm.
*
......@@ -46,7 +45,6 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
* @todo: Detailed documentation. Refactor (too long & nesting level).
*
* @param mixed $stmt
* @param array $tableAliases Array that maps table aliases (SQL alias => DQL alias)
* @param array $aliasMap Array that maps DQL aliases to their components
* (DQL alias => array(
* 'table' => Table object,
......@@ -71,7 +69,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
if ($hydrationMode == Doctrine::HYDRATE_NONE) {
return $stmt->fetchAll(PDO::FETCH_NUM);
}
$this->_tableAliases = $parserResult->getTableToClassAliasMap();
$this->_queryComponents = $parserResult->getQueryComponents();
......@@ -87,24 +85,29 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
// Used variables during hydration
reset($this->_queryComponents);
$rootAlias = key($this->_queryComponents);
$rootComponentName = $this->_queryComponents[$rootAlias]['table']->getComponentName();
// if only one component is involved we can make our lives easier
$isSimpleQuery = count($this->_queryComponents) <= 1;
// Holds hydration listeners that get called during hydration
$listeners = array();
// Lookup map to quickly discover/lookup existing records in the result
// It's the identifier "memory"
$identifierMap = array();
// Holds for each component the last previously seen element in the result set
$prev = array();
// holds the values of the identifier/primary key fields of components,
// Holds the values of the identifier/primary key fields of components,
// separated by a pipe '|' and grouped by component alias (r, u, i, ... whatever)
// the $idTemplate is a prepared template. $id is set to a fresh template when
// starting to process a row.
$id = array();
$idTemplate = array();
// Holds the resulting hydrated data structure
$result = $driver->getElementCollection($rootComponentName);
......@@ -122,9 +125,10 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
$prev[$dqlAlias] = array();
$idTemplate[$dqlAlias] = '';
}
// Process result set
$cache = array();
while ($data = $stmt->fetch(Doctrine::FETCH_ASSOC)) {
$id = $idTemplate; // initialize the id-memory
$nonemptyComponents = array();
......@@ -138,16 +142,16 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
// just event stuff
$event->set('data', $rowData[$rootAlias]);
$listeners[$componentName]->preHydrate($event);
//--
// Check for an existing element
$index = false;
if ($isSimpleQuery || ! isset($identifierMap[$rootAlias][$id[$rootAlias]])) {
$element = $driver->getElement($rowData[$rootAlias], $componentName);
// just event stuff
$event->set('data', $element);
$listeners[$componentName]->postHydrate($event);
//--
......@@ -158,6 +162,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
} else if ( ! isset($element[$field])) {
throw new Doctrine_Hydrator_Exception("Couldn't hydrate. Found a non-existent key.");
}
$result[$element[$field]] = $element;
} else {
$result[] = $element;
......@@ -170,10 +175,8 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
$this->_setLastElement($prev, $result, $index, $rootAlias, false);
unset($rowData[$rootAlias]);
// end hydrate data of the root component for the current row
// End hydrate data of the root component for the current row
// $prev[$rootAlias] now points to the last element in $result.
// now hydrate the rest of the data found in the current row, that belongs to other
// (related) components.
......@@ -184,6 +187,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
// just event stuff
$event->set('data', $data);
$listeners[$componentName]->preHydrate($event);
//--
......@@ -219,6 +223,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
} else if ( ! isset($element[$field])) {
throw Doctrine_Hydrator_Exception::nonExistantFieldUsedAsIndex($field);
}
$prev[$parent][$relationAlias][$element[$field]] = $element;
} else {
$prev[$parent][$relationAlias][] = $element;
......@@ -236,6 +241,7 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
} else {
// 1-1 relation
$oneToOne = true;
if ( ! isset($nonemptyComponents[$dqlAlias])) {
$prev[$parent][$relationAlias] = $driver->getNullPointer();
} else if ( ! isset($prev[$parent][$relationAlias])) {
......@@ -251,14 +257,13 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
}
$stmt->closeCursor();
$driver->flush();
// re-enable lazy loading
// Re-enable lazy loading
foreach ($this->_queryComponents as $dqlAlias => $data) {
$data['table']->setAttribute(Doctrine::ATTR_LOAD_REFERENCES, true);
}
//$e = microtime(true);
//echo 'Hydration took: ' . ($e - $s) . ' for '.count($result).' records<br />';
......@@ -284,14 +289,14 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
if ($coll === $this->_nullObject) {
return false;
}
if ($index !== false) {
// Link element at $index to previous element for the component
// identified by the DQL alias $alias
$prev[$dqlAlias] =& $coll[$index];
return;
}
if (is_array($coll) && $coll) {
if ($oneToOne) {
$prev[$dqlAlias] =& $coll;
......@@ -307,19 +312,22 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
unset($prev[$dqlAlias]);
}
}
/**
* _gatherRowData
*
* Puts the fields of a data row into a new array, grouped by the component
* they belong to. The column names in the result set are mapped to their
* they belong to. The column names in the result set are mapped to their
* field names during this procedure.
*
* @return array An array with all the fields (name => value) of the data row,
* @return array An array with all the fields (name => value) of the data row,
* grouped by their component (alias).
*/
protected function _gatherRowData(&$data, &$cache, &$id, &$nonemptyComponents)
{
$rowData = array();
foreach ($data as $key => $value) {
// Parse each column name only once. Cache the results.
if ( ! isset($cache[$key])) {
......@@ -374,13 +382,16 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
$nonemptyComponents[$dqlAlias] = true;
}
}
return $rowData;
}
/**
/**
* _getCustomIndexField
*
* Gets the custom field used for indexing for the specified component alias.
*
*
* @return string The field name of the field used for indexing or NULL
* if the component does not use any custom field indices.
*/
......@@ -388,5 +399,5 @@ class Doctrine_Hydrator extends Doctrine_Hydrator_Abstract
{
return isset($this->_queryComponents[$alias]['map']) ? $this->_queryComponents[$alias]['map'] : null;
}
}
......@@ -33,22 +33,23 @@
abstract class Doctrine_Hydrator_Abstract
{
/**
* @var array $_aliasMap two dimensional array containing the map for query aliases
* Main keys are component aliases
* @var array $_queryComponents
*
* table table object associated with given alias
* Two dimensional array containing the map for query aliases. Main keys are component aliases.
*
* relation the relation object owned by the parent
*
* parent the alias of the parent
*
* agg the aggregates of this component
*
* map the name of the column / aggregate value this
* component is mapped to a collection
* table Table object associated with given alias.
* relation Relation object owned by the parent.
* parent Alias of the parent.
* agg Aggregates of this component.
* map Name of the column / aggregate value this component is mapped to a collection.
*/
protected $_queryComponents = array();
/**
* @var array Table alias map. Keys are SQL aliases and values DQL aliases.
*/
protected $_tableAliasMap = array();
/**
* The current hydration mode.
*/
......@@ -58,6 +59,7 @@ abstract class Doctrine_Hydrator_Abstract
protected $_em;
/**
* constructor
*
......@@ -69,96 +71,88 @@ abstract class Doctrine_Hydrator_Abstract
$this->_nullObject = Doctrine_Null::$INSTANCE;
}
/**
* Sets the fetchmode.
* setHydrationMode
*
* Defines the hydration process mode.
*
* @param integer $fetchmode One of the Doctrine::HYDRATE_* constants.
* @param integer $hydrationMode Doctrine processing mode to be used during hydration process.
* One of the Doctrine::HYDRATE_* constants.
*/
public function setHydrationMode($hydrationMode)
{
$this->_hydrationMode = $hydrationMode;
}
/**
* setAliasMap
* sets the whole component alias map
* setQueryComponents
*
* Defines the mapping components.
*
* @param array $map alias map
* @return Doctrine_Hydrate this object
* @param array $queryComponents Query components.
*/
public function setQueryComponents(array $queryComponents)
{
$this->_queryComponents = $queryComponents;
}
/**
* getAliasMap
* returns the component alias map
* getQueryComponents
*
* Gets the mapping components.
*
* @return array component alias map
* @return array Query components.
*/
public function getQueryComponents()
{
return $this->_queryComponents;
}
/**
* hasAliasDeclaration
* whether or not this object has a declaration for given component alias
* setTableAliasMap
*
* @param string $componentAlias the component alias the retrieve the declaration from
* @return boolean
*/
public function hasAliasDeclaration($componentAlias)
{
return isset($this->_queryComponents[$componentAlias]);
}
/**
* getAliasDeclaration
* get the declaration for given component alias
* Defines the table aliases.
*
* @param string $componentAlias the component alias the retrieve the declaration from
* @return array the alias declaration
* @deprecated
* @param array $tableAliasMap Table aliases.
*/
public function getAliasDeclaration($componentAlias)
public function setTableAliasMap(array $tableAliasMap)
{
return $this->getQueryComponent($componentAlias);
$this->_tableAliasMap = $tableAliasMap;
}
/**
* getQueryComponent
* get the declaration for given component alias
* getTableAliasMap
*
* Returns all table aliases.
*
* @param string $componentAlias the component alias the retrieve the declaration from
* @return array the alias declaration
* @return array Table aliases as an array.
*/
public function getQueryComponent($componentAlias)
public function getTableAliasMap()
{
if ( ! isset($this->_queryComponents[$componentAlias])) {
throw new Doctrine_Query_Exception('Unknown component alias ' . $componentAlias);
}
return $this->_queryComponents[$componentAlias];
return $this->_tableAliasMap;
}
/**
* parseData
* parses the data returned by statement object
* hydrateResultSet
*
* Processes data returned by statement object.
*
* This is method defines the core of Doctrine object population algorithm
* hence this method strives to be as fast as possible
* hence this method strives to be as fast as possible.
*
* The key idea is the loop over the rowset only once doing all the needed operations
* within this massive loop.
*
* @todo: Can we refactor this function so that it is not so long and
* nested?
*
* @param mixed $stmt
* @return array
* @param mixed $stmt PDOStatement
* @param integer $hydrationMode Doctrine processing mode to be used during hydration process.
* One of the Doctrine::HYDRATE_* constants.
* @return mixed Doctrine_Collection|array
*/
abstract public function hydrateResultSet($parserResult);
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.phpdoctrine.org>.
*/
Doctrine::autoload('Doctrine_Query_Part');
/**
* Doctrine_Query_JoinCondition
*
* @package Doctrine
* @subpackage Query
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
* @link www.phpdoctrine.org
* @since 1.0
* @version $Revision$
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
*/
class Doctrine_Query_JoinCondition extends Doctrine_Query_Condition
{
public function load($condition)
{
$condition = trim($condition);
$e = $this->_tokenizer->sqlExplode($condition);
if (count($e) > 2) {
$a = explode('.', $e[0]);
$field = array_pop($a);
$reference = implode('.', $a);
$operator = $e[1];
$value = $e[2];
$conn = $this->query->getConnection();
$alias = $this->query->getTableAlias($reference);
$map = $this->query->getAliasDeclaration($reference);
$table = $map['table'];
// check if value is enumerated value
$enumIndex = $table->enumIndex($field, trim($value, "'"));
if (false !== $enumIndex && $conn->getAttribute(Doctrine::ATTR_USE_NATIVE_ENUM)) {
$enumIndex = $conn->quote($enumIndex, 'text');
}
if (substr($value, 0, 1) == '(') {
// trim brackets
$trimmed = $this->_tokenizer->bracketTrim($value);
if (substr($trimmed, 0, 4) == 'FROM' || substr($trimmed, 0, 6) == 'SELECT') {
// subquery found
$q = $this->query->createSubquery();
$value = '(' . $q->parseQuery($trimmed)->getQuery() . ')';
} elseif (substr($trimmed, 0, 4) == 'SQL:') {
$value = '(' . substr($trimmed, 4) . ')';
} else {
// simple in expression found
$e = $this->_tokenizer->sqlExplode($trimmed, ',');
$value = array();
foreach ($e as $part) {
$index = $table->enumIndex($field, trim($part, "'"));
if (false !== $index && $conn->getAttribute(Doctrine::ATTR_USE_NATIVE_ENUM)) {
$index = $conn->quote($index, 'text');
}
if ($index !== false) {
$value[] = $index;
} else {
$value[] = $this->parseLiteralValue($part);
}
}
$value = '(' . implode(', ', $value) . ')';
}
} else {
if ($enumIndex !== false) {
$value = $enumIndex;
} else {
$value = $this->parseLiteralValue($value);
}
}
switch ($operator) {
case '<':
case '>':
case '=':
case '!=':
if ($enumIndex !== false) {
$value = $enumIndex;
}
default:
$condition = $alias . '.' . $field . ' '
. $operator . ' ' . $value;
}
}
return $condition;
}
}
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
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