diff --git a/lib/Doctrine.php b/lib/Doctrine.php index c7ee312b8..32facca6f 100644 --- a/lib/Doctrine.php +++ b/lib/Doctrine.php @@ -388,7 +388,7 @@ final class Doctrine */ public static function getPath() { - if (! self::$path) { + if ( ! self::$path) { self::$path = dirname(__FILE__); } return self::$path; diff --git a/lib/Doctrine/Configurable.php b/lib/Doctrine/Configurable.php index 9673c2d17..5228dba22 100644 --- a/lib/Doctrine/Configurable.php +++ b/lib/Doctrine/Configurable.php @@ -62,6 +62,16 @@ abstract class Doctrine_Configurable extends Doctrine_Object */ public function setAttribute($attribute,$value) { + if (is_string($attribute)) { + $upper = strtoupper($attribute); + + $const = 'Doctrine::ATTR_' . $attribute; + if (defined($const)) { + $this->_state = constant($const); + } else { + throw new Doctrine_Exception('Unknown attribute ' . $attribute); + } + } switch ($attribute) { case Doctrine::ATTR_FETCHMODE: if ($value < 0) { diff --git a/lib/Doctrine/Hydrate.php b/lib/Doctrine/Hydrate.php index 9616717d1..ffb272ba3 100644 --- a/lib/Doctrine/Hydrate.php +++ b/lib/Doctrine/Hydrate.php @@ -881,11 +881,13 @@ class Doctrine_Hydrate extends Doctrine_Object implements Serializable foreach ($maps as $map) { $b = array(); foreach ($map as $field => $value) { + $identifier = $this->_conn->quoteIdentifier($tableAlias . $field); + if ($index > 0) { - $b[] = '(' . $tableAlias . $field . ' = ' . $value - . ' OR ' . $tableAlias . $field . ' IS NULL)'; + $b[] = '(' . $identifier . ' = ' . $value + . ' OR ' . $identifier . ' IS NULL)'; } else { - $b[] = $tableAlias . $field . ' = ' . $value; + $b[] = $identifier . ' = ' . $value; } } diff --git a/lib/Doctrine/Query.php b/lib/Doctrine/Query.php index 532f815f1..af5aab3bd 100644 --- a/lib/Doctrine/Query.php +++ b/lib/Doctrine/Query.php @@ -368,7 +368,9 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable foreach ($fields as $name) { $name = $table->getColumnName($name); - $this->parts['select'][] = $tableAlias . '.' .$name . ' AS ' . $tableAlias . '__' . $name; + $this->parts['select'][] = $this->_conn->quoteIdentifier($tableAlias . '.' . $name) + . ' AS ' + . $this->_conn->quoteIdentifier($tableAlias . '__' . $name); } $this->neededTables[] = $tableAlias; @@ -520,7 +522,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable $sqlAlias = $tableAlias . '__' . count($this->aggregateMap); - $this->parts['select'][] = '(' . $sql . ') AS ' . $sqlAlias; + $this->parts['select'][] = '(' . $sql . ') AS ' . $this->_conn->quoteIdentifier($sqlAlias); $this->aggregateMap[$alias] = $sqlAlias; $this->_aliasMap[$componentAlias]['agg'][] = $alias; @@ -568,7 +570,9 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable $tableAliases[$tableAlias] = true; // build sql expression - $expression = str_replace($component, $tableAlias . '.' . $field, $expression); + + $identifier = $this->_conn->quoteIdentifier($tableAlias . '.' . $field); + $expression = str_replace($component, $identifier, $expression); } } @@ -578,7 +582,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable } $index = count($this->aggregateMap); - $sqlAlias = $tableAlias . '__' . $index; + $sqlAlias = $this->_conn->quoteIdentifier($tableAlias . '__' . $index); $this->parts['select'][] = $expression . ' AS ' . $sqlAlias; @@ -804,7 +808,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable // only append the subquery if it actually contains something if ($subquery !== '') { - array_unshift($this->parts['where'], $field. ' IN (' . $subquery . ')'); + array_unshift($this->parts['where'], $this->_conn->quoteIdentifier($field) . ' IN (' . $subquery . ')'); } $modifyLimit = false; @@ -853,7 +857,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable $primaryKey = $alias . '.' . $table->getIdentifier(); // initialize the base of the subquery - $subquery = 'SELECT DISTINCT ' . $primaryKey; + $subquery = 'SELECT DISTINCT ' . $this->_conn->quoteIdentifier($primaryKey); $driverName = $this->_conn->getAttribute(Doctrine::ATTR_DRIVER_NAME); @@ -917,14 +921,16 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable $subquery = $this->_conn->modifyLimitQuery($subquery, $this->parts['limit'], $this->parts['offset']); $parts = Doctrine_Tokenizer::quoteExplode($subquery, ' ', "'", "'"); - //print_r($parts); + foreach ($parts as $k => $part) { - if (strpos($part, "'") !== false) { + if (strpos($part, ' ') !== false) { continue; } + + $part = trim($part, "\"'`"); if ($this->hasTableAlias($part)) { - $parts[$k] = $this->generateNewTableAlias($part); + $parts[$k] = $this->_conn->quoteIdentifier($this->generateNewTableAlias($part)); continue; } @@ -1153,8 +1159,13 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable $localAlias = $this->getTableAlias($parent, $table->getTableName()); $foreignAlias = $this->getTableAlias($componentAlias, $relation->getTable()->getTableName()); - $localSql = $this->_conn->quoteIdentifier($table->getTableName()) . ' ' . $localAlias; - $foreignSql = $this->_conn->quoteIdentifier($relation->getTable()->getTableName()) . ' ' . $foreignAlias; + $localSql = $this->_conn->quoteIdentifier($table->getTableName()) + . ' ' + . $this->_conn->quoteIdentifier($localAlias); + + $foreignSql = $this->_conn->quoteIdentifier($relation->getTable()->getTableName()) + . ' ' + . $this->_conn->quoteIdentifier($foreignAlias); $map = $relation->getTable()->inheritanceMap; @@ -1192,22 +1203,29 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable if ($relation->isEqual()) { $queryPart .= '('; } - $queryPart .= $foreignAlias . '.' - . $relation->getTable()->getIdentifier() . ' = ' - . $assocAlias . '.' . $relation->getForeign(); + $queryPart .= $this->_conn->quoteIdentifier($foreignAlias . '.' . $relation->getTable()->getIdentifier()) + . ' = ' + . $this->_conn->quoteIdentifier($assocAlias . '.' . $relation->getForeign()); if ($relation->isEqual()) { - $queryPart .= ' OR ' . $foreignAlias . '.' . $table->getIdentifier() - . ' = ' . $assocAlias . '.' . $relation->getLocal() - . ') AND ' . $foreignAlias . '.' . $table->getIdentifier() - . ' != ' . $localAlias . '.' . $table->getIdentifier(); + $queryPart .= ' OR ' + . $this->_conn->quoteIdentifier($foreignAlias . '.' . $table->getIdentifier()) + . ' = ' + . $this->_conn->quoteIdentifier($assocAlias . '.' . $relation->getLocal()) + . ') AND ' + . $this->_conn->quoteIdentifier($foreignAlias . '.' . $table->getIdentifier()) + . ' != ' + . $this->_conn->quoteIdentifier($localAlias . '.' . $table->getIdentifier()); } } else { $queryPart = $join . $foreignSql - . ' ON ' . $localAlias . '.' - . $relation->getLocal() . ' = ' . $foreignAlias . '.' . $relation->getForeign(); + . ' ON ' + . $this->_conn->quoteIdentifier($localAlias . '.' . $relation->getLocal()) + . ' = ' + . $this->_conn->quoteIdentifier($foreignAlias . '.' . $relation->getForeign()); + } $this->parts['from'][$componentAlias] = $queryPart; if ( ! empty($joinCondition)) { @@ -1262,7 +1280,7 @@ class Doctrine_Query extends Doctrine_Query_Abstract implements Countable $queryPart = $this->_conn->quoteIdentifier($tableName); if ($this->type === self::SELECT) { - $queryPart .= ' ' . $tableAlias; + $queryPart .= ' ' . $this->_conn->quoteIdentifier($tableAlias); } $this->parts['from'][] = $queryPart; diff --git a/lib/Doctrine/Query/Where.php b/lib/Doctrine/Query/Where.php index 56ba4e8a7..85fc52541 100644 --- a/lib/Doctrine/Query/Where.php +++ b/lib/Doctrine/Query/Where.php @@ -42,6 +42,7 @@ class Doctrine_Query_Where extends Doctrine_Query_Condition public function load($where) { $where = trim($where); + $conn = $this->query->getConnection(); $e = Doctrine_Tokenizer::sqlExplode($where); @@ -107,9 +108,9 @@ class Doctrine_Query_Where extends Doctrine_Query_Condition } $where = array(); foreach ($values as $value) { - $where[] = $alias . '.' . $relation->getLocal() - . ' IN (SELECT '.$relation->getForeign() - . ' FROM ' . $relation->getTable()->getTableName() + $where[] = $conn->quoteIdentifier($alias . '.' . $relation->getLocal()) + . ' IN (SELECT ' . $conn->quoteIdentifier($relation->getForeign()) + . ' FROM ' . $conn->quoteIdentifier($relation->getTable()->getTableName()) . ' WHERE ' . $field . $operator . $value . ')'; } $where = implode(' AND ', $where); @@ -126,7 +127,7 @@ class Doctrine_Query_Where extends Doctrine_Query_Condition $field = $table->getColumnName($field); // check if value is enumerated value $enumIndex = $table->enumIndex($field, trim($value, "'")); - + if (substr($value, 0, 1) == '(') { // trim brackets $trimmed = Doctrine_Tokenizer::bracketTrim($value); @@ -180,7 +181,7 @@ class Doctrine_Query_Where extends Doctrine_Query_Condition default: if ($this->query->getType() === Doctrine_Query::SELECT) { - $fieldname = $alias ? $alias . '.' . $field : $field; + $fieldname = $alias ? $conn->quoteIdentifier($alias . '.' . $field) : $field; } else { $fieldname = $field; } diff --git a/lib/Doctrine/Record.php b/lib/Doctrine/Record.php index 6e95df9d7..99a46f790 100644 --- a/lib/Doctrine/Record.php +++ b/lib/Doctrine/Record.php @@ -578,17 +578,12 @@ abstract class Doctrine_Record extends Doctrine_Record_Abstract implements Count } } elseif (is_string($state)) { $upper = strtoupper($state); - switch ($upper) { - case 'DIRTY': - case 'CLEAN': - case 'TDIRTY': - case 'TCLEAN': - case 'PROXY': - case 'DELETED': - $this->_state = constant('Doctrine_Record::STATE_' . $upper); - break; - default: - $err = true; + + $const = 'Doctrine_Record::STATE_' . $upper; + if (defined($const)) { + $this->_state = constant($const); + } else { + $err = true; } } diff --git a/tests/Query/IdentifierQuotingTestCase.php b/tests/Query/IdentifierQuotingTestCase.php index 3207031df..e65a2217a 100644 --- a/tests/Query/IdentifierQuotingTestCase.php +++ b/tests/Query/IdentifierQuotingTestCase.php @@ -33,34 +33,53 @@ * @since 1.0 * @version $Revision$ */ -class Doctrine_Query_IdentifierQuoting_TestCase extends Doctrine_UnitTestCase { - public function prepareTables() { } - public function prepareData() { } - public function testQuerySupportsIdentifierQuoting() { +class Doctrine_Query_IdentifierQuoting_TestCase extends Doctrine_UnitTestCase +{ + public function prepareTables() + { } + + public function prepareData() + { } + + public function testQuerySupportsIdentifierQuoting() + { $this->conn->setAttribute(Doctrine::ATTR_QUOTE_IDENTIFIER, true); $q = new Doctrine_Query(); - + $q->parseQuery('SELECT MAX(u.id), MIN(u.name) FROM User u'); - $this->assertEqual($q->getQuery(), 'SELECT MAX(e.id) AS e__0, MIN(e.name) AS e__1 FROM "entity" e WHERE (e.type = 0)'); + $this->assertEqual($q->getQuery(), 'SELECT MAX("e.id") AS "e__0", MIN("e.name") AS "e__1" FROM "entity" "e" WHERE ("e.type" = 0)'); } - public function testQuerySupportsIdentifierQuotingWithJoins() { + + public function testQuerySupportsIdentifierQuotingInWherePart() + { + $q = new Doctrine_Query(); + + $q->parseQuery('SELECT u.name FROM User u WHERE u.id = 3'); + + $this->assertEqual($q->getQuery(), 'SELECT "e.id" AS "e__id", "e.name" AS "e__name" FROM "entity" "e" WHERE "e.id" = 3 AND ("e.type" = 0)'); + } + + public function testQuerySupportsIdentifierQuotingWithJoins() + { $q = new Doctrine_Query(); $q->parseQuery('SELECT u.name FROM User u LEFT JOIN u.Phonenumber p'); - $this->assertEqual($q->getQuery(), 'SELECT e.id AS e__id, e.name AS e__name FROM "entity" e LEFT JOIN "phonenumber" p ON e.id = p.entity_id WHERE (e.type = 0)'); + $this->assertEqual($q->getQuery(), 'SELECT "e.id" AS "e__id", "e.name" AS "e__name" FROM "entity" "e" LEFT JOIN "phonenumber" "p" ON "e.id" = "p.entity_id" WHERE ("e.type" = 0)'); + } - - public function testLimitSubqueryAlgorithmSupportsIdentifierQuoting() { + + public function testLimitSubqueryAlgorithmSupportsIdentifierQuoting() + { $q = new Doctrine_Query(); - - $q->parseQuery('SELECT u.name FROM User u INNER JOIN u.Phonenumber p')->limit(5); - - $this->assertEqual($q->getQuery(), 'SELECT e.id AS e__id, e.name AS e__name FROM "entity" e INNER JOIN "phonenumber" p ON e.id = p.entity_id WHERE e.id IN (SELECT DISTINCT e2.id FROM "entity" e2 INNER JOIN "phonenumber" p2 ON e2.id = p2.entity_id WHERE (e2.type = 0) LIMIT 5) AND (e.type = 0)'); - + + $q->parseQuery('SELECT u.name FROM User u INNER JOIN u.Phonenumber p')->limit(5); + + $this->assertEqual($q->getQuery(), 'SELECT "e.id" AS "e__id", "e.name" AS "e__name" FROM "entity" "e" INNER JOIN "phonenumber" "p" ON "e.id" = "p.entity_id" WHERE "e.id" IN (SELECT DISTINCT "e2.id" FROM "entity" "e2" INNER JOIN "phonenumber" "p2" ON "e2.id" = "p2.entity_id" WHERE ("e2.type" = 0) LIMIT 5) AND ("e.type" = 0)'); + $this->conn->setAttribute(Doctrine::ATTR_QUOTE_IDENTIFIER, false); } }