From 6f356799115b1edf17309f826345da82b16ce7f2 Mon Sep 17 00:00:00 2001 From: Jan Sorgalla Date: Sat, 19 Nov 2011 00:35:29 +0100 Subject: [PATCH 1/4] Initial implementation of Doctrine\DBAL\Types\Type::convertToDatabaseValueSQL() and Doctrine\DBAL\Types\Type::convertToPHPValueSQL() integration --- .../AbstractEntityInheritancePersister.php | 5 + .../ORM/Persisters/BasicEntityPersister.php | 43 +++++++- lib/Doctrine/ORM/Query/SqlWalker.php | 82 ++++++++++++-- .../DbalTypes/NegativeToPositiveType.php | 34 ++++++ .../Tests/DbalTypes/UpperCaseStringType.php | 29 +++++ tests/Doctrine/Tests/Mocks/ConnectionMock.php | 14 +++ .../Models/CustomType/CustomTypeChild.php | 21 ++++ .../Models/CustomType/CustomTypeParent.php | 68 ++++++++++++ .../Models/CustomType/CustomTypeUpperCase.php | 21 ++++ .../Tests/ORM/Functional/TypeValueSqlTest.php | 104 ++++++++++++++++++ .../BasicEntityPersisterTypeValueSqlTest.php | 73 ++++++++++++ .../ORM/Query/SelectSqlGenerationTest.php | 43 ++++++++ .../ORM/Query/UpdateSqlGenerationTest.php | 24 ++++ .../Doctrine/Tests/OrmFunctionalTestCase.php | 12 ++ 14 files changed, 559 insertions(+), 14 deletions(-) create mode 100644 tests/Doctrine/Tests/DbalTypes/NegativeToPositiveType.php create mode 100644 tests/Doctrine/Tests/DbalTypes/UpperCaseStringType.php create mode 100644 tests/Doctrine/Tests/Models/CustomType/CustomTypeChild.php create mode 100644 tests/Doctrine/Tests/Models/CustomType/CustomTypeParent.php create mode 100644 tests/Doctrine/Tests/Models/CustomType/CustomTypeUpperCase.php create mode 100644 tests/Doctrine/Tests/ORM/Functional/TypeValueSqlTest.php create mode 100644 tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php diff --git a/lib/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php b/lib/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php index 84540a337..4f45f0877 100644 --- a/lib/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php +++ b/lib/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php @@ -65,6 +65,11 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister $columnAlias = $this->getSQLColumnAlias($columnName); $this->_rsm->addFieldResult($alias, $columnAlias, $field, $class->name); + if (!$class->isIdentifier($field)) { + $type = Type::getType($class->getTypeOfField($field)); + $sql = $type->convertToPHPValueSQL($sql, $this->_platform); + } + return $sql . ' AS ' . $columnAlias; } diff --git a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php index 4deece2e9..41fb01a75 100644 --- a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php @@ -338,10 +338,19 @@ class BasicEntityPersister $set = $params = $types = array(); foreach ($updateData as $columnName => $value) { - $set[] = (isset($this->_class->fieldNames[$columnName])) - ? $this->_class->getQuotedColumnName($this->_class->fieldNames[$columnName], $this->_platform) . ' = ?' - : $columnName . ' = ?'; + $column = $columnName; + $placeholder = '?'; + + if (isset($this->_class->fieldNames[$columnName])) { + $column = $this->_class->getQuotedColumnName($this->_class->fieldNames[$columnName], $this->_platform); + if (!$this->_class->isIdentifier($this->_class->fieldNames[$columnName])) { + $type = Type::getType($this->_columnTypes[$columnName]); + $placeholder = $type->convertToDatabaseValueSQL('?', $this->_platform); + } + } + + $set[] = $column . ' = ' . $placeholder; $params[] = $value; $types[] = $this->_columnTypes[$columnName]; } @@ -1117,7 +1126,18 @@ class BasicEntityPersister ); } else { $columns = array_unique($columns); - $values = array_fill(0, count($columns), '?'); + + $values = array(); + foreach ($columns AS $column) { + $placeholder = '?'; + + if (isset($this->_columnTypes[$column])) { + $type = Type::getType($this->_columnTypes[$column]); + $placeholder = $type->convertToDatabaseValueSQL('?', $this->_platform); + } + + $values[] = $placeholder; + } $insertSql = 'INSERT INTO ' . $this->_class->getQuotedTableName($this->_platform) . ' (' . implode(', ', $columns) . ') VALUES (' . implode(', ', $values) . ')'; @@ -1156,6 +1176,7 @@ class BasicEntityPersister } } else if ($this->_class->generatorType != ClassMetadata::GENERATOR_TYPE_IDENTITY || $this->_class->identifier[0] != $name) { $columns[] = $this->_class->getQuotedColumnName($name, $this->_platform); + $this->_columnTypes[$name] = $this->_class->fieldMappings[$name]['type']; } } @@ -1177,6 +1198,11 @@ class BasicEntityPersister $columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]); $this->_rsm->addFieldResult($alias, $columnAlias, $field); + + if (!$class->isIdentifier($field)) { + $type = Type::getType($class->getTypeOfField($field)); + $sql = $type->convertToPHPValueSQL($sql, $this->_platform); + } return $sql . ' AS ' . $columnAlias; } @@ -1259,6 +1285,8 @@ class BasicEntityPersister foreach ($criteria as $field => $value) { $conditionSql .= $conditionSql ? ' AND ' : ''; + + $placeholder = '?'; if (isset($this->_class->columnNames[$field])) { $className = (isset($this->_class->fieldMappings[$field]['inherited'])) @@ -1266,6 +1294,11 @@ class BasicEntityPersister : $this->_class->name; $conditionSql .= $this->_getSQLTableAlias($className) . '.' . $this->_class->getQuotedColumnName($field, $this->_platform); + + if (!$this->_class->isIdentifier($field)) { + $type = Type::getType($this->_class->getTypeOfField($field)); + $placeholder = $type->convertToDatabaseValueSQL($placeholder, $this->_platform); + } } else if (isset($this->_class->associationMappings[$field])) { if ( ! $this->_class->associationMappings[$field]['isOwningSide']) { throw ORMException::invalidFindByInverseAssociation($this->_class->name, $field); @@ -1286,7 +1319,7 @@ class BasicEntityPersister throw ORMException::unrecognizedField($field); } - $conditionSql .= (is_array($value)) ? ' IN (?)' : (($value === null) ? ' IS NULL' : ' = ?'); + $conditionSql .= (is_array($value)) ? ' IN (?)' : (($value === null) ? ' IS NULL' : ' = ' . $placeholder); } return $conditionSql; } diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index 624f14b89..382796631 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -20,6 +20,7 @@ namespace Doctrine\ORM\Query; use Doctrine\DBAL\LockMode, + Doctrine\DBAL\Types\Type, Doctrine\ORM\Mapping\ClassMetadata, Doctrine\ORM\Query, Doctrine\ORM\Query\QueryException, @@ -96,6 +97,17 @@ class SqlWalker implements TreeWalker * These should only be generated for SELECT queries, not for UPDATE/DELETE. */ private $_useSqlTableAliases = true; + + /** + * Flag that indicates whether to pass columns through Type::convertToPHPValueSQL(). + * These should only be done for SELECT queries, not for UPDATE. + */ + private $_useDbalTypeValueSql = true; + + /** + * Holds the current columns type. + */ + private $_currentColumnType; /** * The database platform abstraction. @@ -409,6 +421,7 @@ class SqlWalker implements TreeWalker public function walkUpdateStatement(AST\UpdateStatement $AST) { $this->_useSqlTableAliases = false; + $this->_useDbalTypeValueSql = false; return $this->walkUpdateClause($AST->updateClause) . $this->walkWhereClause($AST->whereClause); } @@ -464,11 +477,20 @@ class SqlWalker implements TreeWalker $dqlAlias = $pathExpr->identificationVariable; $class = $this->_queryComponents[$dqlAlias]['metadata']; + $column = ''; + if ($this->_useSqlTableAliases) { - $sql .= $this->walkIdentificationVariable($dqlAlias, $fieldName) . '.'; + $column .= $this->walkIdentificationVariable($dqlAlias, $fieldName) . '.'; } - $sql .= $class->getQuotedColumnName($fieldName, $this->_platform); + $column .= $class->getQuotedColumnName($fieldName, $this->_platform); + + if ($this->_useDbalTypeValueSql && !$class->isIdentifier($fieldName)) { + $type = Type::getType($class->getTypeOfField($fieldName)); + $column = $type->convertToPHPValueSQL($column, $this->_conn->getDatabasePlatform()); + } + + $sql .= $column; break; case AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION: @@ -1002,9 +1024,16 @@ class SqlWalker implements TreeWalker $sqlTableAlias = $this->getSQLTableAlias($tableName, $dqlAlias); $columnName = $class->getQuotedColumnName($fieldName, $this->_platform); - $columnAlias = $this->getSQLColumnAlias($columnName); + $columnAlias = $this->getSQLColumnAlias($columnName); - $sql .= $sqlTableAlias . '.' . $columnName . ' AS ' . $columnAlias; + $col = $sqlTableAlias . '.' . $columnName; + + if (!$class->isIdentifier($fieldName)) { + $type = Type::getType($class->getTypeOfField($fieldName)); + $col = $type->convertToPHPValueSQL($col, $this->_conn->getDatabasePlatform()); + } + + $sql .= $col . ' AS ' . $columnAlias; if ( ! $hidden) { $this->_rsm->addScalarResult($columnAlias, $resultAlias); @@ -1086,7 +1115,14 @@ class SqlWalker implements TreeWalker $columnAlias = $this->getSQLColumnAlias($mapping['columnName']); $quotedColumnName = $class->getQuotedColumnName($fieldName, $this->_platform); - $sqlParts[] = $sqlTableAlias . '.' . $quotedColumnName . ' AS '. $columnAlias; + $col = $sqlTableAlias . '.' . $quotedColumnName; + + if (!$class->isIdentifier($fieldName)) { + $type = Type::getType($class->getTypeOfField($fieldName)); + $col = $type->convertToPHPValueSQL($col, $this->_platform); + } + + $sqlParts[] = $col . ' AS '. $columnAlias; $this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $class->name); } @@ -1108,7 +1144,14 @@ class SqlWalker implements TreeWalker $columnAlias = $this->getSQLColumnAlias($mapping['columnName']); $quotedColumnName = $subClass->getQuotedColumnName($fieldName, $this->_platform); - $sqlParts[] = $sqlTableAlias . '.' . $quotedColumnName . ' AS ' . $columnAlias; + $col = $sqlTableAlias . '.' . $quotedColumnName; + + if (!$subClass->isIdentifier($fieldName)) { + $type = Type::getType($subClass->getTypeOfField($fieldName)); + $col = $type->convertToPHPValueSQL($col, $this->_platform); + } + + $sqlParts[] = $col . ' AS ' . $columnAlias; $this->_rsm->addFieldResult($dqlAlias, $columnAlias, $fieldName, $subClassName); } @@ -1386,7 +1429,18 @@ class SqlWalker implements TreeWalker switch (true) { case ($newValue instanceof AST\Node): + $currentColumnTypeBefore = $this->_currentColumnType; + $this->_currentColumnType = null; + + if ($updateItem->pathExpression->type == AST\PathExpression::TYPE_STATE_FIELD) { + $class = $this->_queryComponents[$updateItem->pathExpression->identificationVariable]['metadata']; + if (!$class->isIdentifier($updateItem->pathExpression->field)) { + $this->_currentColumnType = $class->getTypeOfField($updateItem->pathExpression->field); + } + } + $sql .= $newValue->dispatch($this); + $this->_currentColumnType = $currentColumnTypeBefore; break; case ($newValue === null): @@ -1759,20 +1813,30 @@ class SqlWalker implements TreeWalker { switch ($literal->type) { case AST\Literal::STRING: - return $this->_conn->quote($literal->value); + $value = $this->_conn->quote($literal->value); + break; case AST\Literal::BOOLEAN: $bool = strtolower($literal->value) == 'true' ? true : false; $boolVal = $this->_conn->getDatabasePlatform()->convertBooleans($bool); - return $boolVal; + $value = $boolVal; + break; case AST\Literal::NUMERIC: - return $literal->value; + $value = $literal->value; + break; default: throw QueryException::invalidLiteral($literal); } + + if ($this->_currentColumnType !== null) { + $type = Type::getType($this->_currentColumnType); + $value = $type->convertToDatabaseValueSQL($value, $this->_conn->getDatabasePlatform()); + } + + return $value; } /** diff --git a/tests/Doctrine/Tests/DbalTypes/NegativeToPositiveType.php b/tests/Doctrine/Tests/DbalTypes/NegativeToPositiveType.php new file mode 100644 index 000000000..e477ecd3c --- /dev/null +++ b/tests/Doctrine/Tests/DbalTypes/NegativeToPositiveType.php @@ -0,0 +1,34 @@ +getIntegerTypeDeclarationSQL($fieldDeclaration); + } + + public function canRequireSQLConversion() + { + return true; + } + + public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform) + { + return 'ABS(' . $sqlExpr . ')'; + } + + public function convertToPHPValueSQL($sqlExpr, $platform) + { + return '((' . $sqlExpr . ') * -1)'; + } +} diff --git a/tests/Doctrine/Tests/DbalTypes/UpperCaseStringType.php b/tests/Doctrine/Tests/DbalTypes/UpperCaseStringType.php new file mode 100644 index 000000000..47e8c790d --- /dev/null +++ b/tests/Doctrine/Tests/DbalTypes/UpperCaseStringType.php @@ -0,0 +1,29 @@ +_inserts[$tableName][] = $data; } + /** + * @override + */ + public function executeUpdate($query, array $params = array(), array $types = array()) + { + $this->_executeUpdates[] = array('query' => $query, 'params' => $params, 'types' => $types); + } + /** * @override */ @@ -84,6 +93,11 @@ class ConnectionMock extends \Doctrine\DBAL\Connection return $this->_inserts; } + public function getExecuteUpdates() + { + return $this->_executeUpdates; + } + public function reset() { $this->_inserts = array(); diff --git a/tests/Doctrine/Tests/Models/CustomType/CustomTypeChild.php b/tests/Doctrine/Tests/Models/CustomType/CustomTypeChild.php new file mode 100644 index 000000000..799ad5016 --- /dev/null +++ b/tests/Doctrine/Tests/Models/CustomType/CustomTypeChild.php @@ -0,0 +1,21 @@ +friendsWithMe = new \Doctrine\Common\Collections\ArrayCollection(); + $this->myFriends = new \Doctrine\Common\Collections\ArrayCollection(); + } + + public function addMyFriend(CustomTypeParent $friend) + { + $this->getMyFriends()->add($friend); + $friend->addFriendWithMe($this); + } + + public function getMyFriends() + { + return $this->myFriends; + } + + public function addFriendWithMe(CustomTypeParent $friend) + { + $this->getFriendsWithMe()->add($friend); + } + + public function getFriendsWithMe() + { + return $this->friendsWithMe; + } +} diff --git a/tests/Doctrine/Tests/Models/CustomType/CustomTypeUpperCase.php b/tests/Doctrine/Tests/Models/CustomType/CustomTypeUpperCase.php new file mode 100644 index 000000000..26e0ec115 --- /dev/null +++ b/tests/Doctrine/Tests/Models/CustomType/CustomTypeUpperCase.php @@ -0,0 +1,21 @@ +useModelSet('customtype'); + parent::setUp(); + } + + public function testUpperCaseStringType() + { + $entity = new CustomTypeUpperCase(); + $entity->lowerCaseString = 'foo'; + + $this->_em->persist($entity); + $this->_em->flush(); + + $id = $entity->id; + + $this->_em->clear(); + + $entity = $this->_em->find('\Doctrine\Tests\Models\CustomType\CustomTypeUpperCase', $id); + + $this->assertEquals('foo', $entity->lowerCaseString, 'Entity holds lowercase string'); + $this->assertEquals('FOO', $this->_em->getConnection()->fetchColumn("select lowerCaseString from customtype_uppercases where id=".$entity->id.""), 'Database holds uppercase string'); + } + + public function testTypeValueSqlWithAssociations() + { + $parent = new CustomTypeParent(); + $parent->customInteger = -1; + $parent->child = new CustomTypeChild(); + + $friend1 = new CustomTypeParent(); + $friend2 = new CustomTypeParent(); + + $parent->addMyFriend($friend1); + $parent->addMyFriend($friend2); + + $this->_em->persist($parent); + $this->_em->persist($friend1); + $this->_em->persist($friend2); + $this->_em->flush(); + + $parentId = $parent->id; + + $this->_em->clear(); + + $entity = $this->_em->find('Doctrine\Tests\Models\CustomType\CustomTypeParent', $parentId); + + $this->assertTrue($entity->customInteger < 0, 'Fetched customInteger negative'); + $this->assertEquals(1, $this->_em->getConnection()->fetchColumn("select customInteger from customtype_parents where id=".$entity->id.""), 'Database has stored customInteger positive'); + + $this->assertNotNull($parent->child, 'Child attached'); + $this->assertCount(2, $entity->getMyFriends(), '2 friends attached'); + } + + public function testSelectDQL() + { + $parent = new CustomTypeParent(); + $parent->customInteger = -1; + $parent->child = new CustomTypeChild(); + + $this->_em->persist($parent); + $this->_em->flush(); + + $parentId = $parent->id; + + $this->_em->clear(); + + $query = $this->_em->createQuery("SELECT p, p.customInteger, c from Doctrine\Tests\Models\CustomType\CustomTypeParent p JOIN p.child c where p.id = " . $parentId . " AND p.customInteger = -1"); + + $result = $query->getResult(); + + $this->assertEquals(1, count($result)); + $this->assertInstanceOf('Doctrine\Tests\Models\CustomType\CustomTypeParent', $result[0][0]); + + $this->assertEquals(-1, $result[0]['customInteger']); + + $this->assertEquals('foo', $result[0][0]->child->lowerCaseString); + } +} diff --git a/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php b/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php new file mode 100644 index 000000000..e608e6ba8 --- /dev/null +++ b/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php @@ -0,0 +1,73 @@ +_em = $this->_getTestEntityManager(); + + $this->_persister = new BasicEntityPersister($this->_em, $this->_em->getClassMetadata("Doctrine\Tests\Models\CustomType\CustomTypeParent")); + + if (DBALType::hasType('negative_to_positive')) { + DBALType::overrideType('negative_to_positive', '\Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } else { + DBALType::addType('negative_to_positive', '\Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } + } + + public function testGetInsertSQLUsesTypeValuesSQL() + { + $method = new \ReflectionMethod($this->_persister, '_getInsertSQL'); + $method->setAccessible(true); + + $sql = $method->invoke($this->_persister); + + $this->assertEquals('INSERT INTO customtype_parents (customInteger, child_id) VALUES (ABS(?), ?)', $sql); + } + + public function testUpdateUsesTypeValuesSQL() + { + $child = new CustomTypeChild(); + + $parent = new CustomTypeParent(); + $parent->customInteger = 1; + $parent->child = $child; + + $this->_em->getUnitOfWork()->registerManaged($parent, array('id' => 1), array('customInteger' => 0, 'child' => null)); + $this->_em->getUnitOfWork()->registerManaged($child, array('id' => 1), array()); + + $this->_em->getUnitOfWork()->propertyChanged($parent, 'customInteger', 0, 1); + $this->_em->getUnitOfWork()->propertyChanged($parent, 'child', null, $child); + + $this->_persister->update($parent); + + $executeUpdates = $this->_em->getConnection()->getExecuteUpdates(); + + $this->assertEquals('UPDATE customtype_parents SET customInteger = ABS(?), child_id = ? WHERE id = ?', $executeUpdates[0]['query']); + } + + public function testGetSelectConditionSQLUsesTypeValuesSQL() + { + $method = new \ReflectionMethod($this->_persister, '_getSelectConditionSQL'); + $method->setAccessible(true); + + $sql = $method->invoke($this->_persister, array('customInteger' => 1, 'child' => 1)); + + $this->assertEquals('t0.customInteger = ABS(?) AND t0.child_id = ?', $sql); + } +} diff --git a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php index 7ddfe77b8..028406068 100644 --- a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php @@ -2,6 +2,7 @@ namespace Doctrine\Tests\ORM\Query; +use Doctrine\DBAL\Types\Type as DBALType; use Doctrine\ORM\Query; require_once __DIR__ . '/../../TestInit.php'; @@ -1333,6 +1334,48 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase 'SELECT c0_.id AS id0, c0_.name AS name1 FROM cms_employees c0_ GROUP BY c0_.id, c0_.name, c0_.spouse_id' ); } + + public function testCustomTypeValueSql() + { + if (DBALType::hasType('negative_to_positive')) { + DBALType::overrideType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } else { + DBALType::addType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } + + $this->assertSqlGeneration( + 'SELECT p.customInteger FROM Doctrine\Tests\Models\CustomType\CustomTypeParent p WHERE p.id = 1', + 'SELECT ((c0_.customInteger) * -1) AS customInteger0 FROM customtype_parents c0_ WHERE c0_.id = 1' + ); + } + + public function testCustomTypeValueSqlIgnoresIdentifierColumn() + { + if (DBALType::hasType('negative_to_positive')) { + DBALType::overrideType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } else { + DBALType::addType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } + + $this->assertSqlGeneration( + 'SELECT p.id FROM Doctrine\Tests\Models\CustomType\CustomTypeParent p WHERE p.id = 1', + 'SELECT c0_.id AS id0 FROM customtype_parents c0_ WHERE c0_.id = 1' + ); + } + + public function testCustomTypeValueSqlForAllFields() + { + if (DBALType::hasType('negative_to_positive')) { + DBALType::overrideType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } else { + DBALType::addType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } + + $this->assertSqlGeneration( + 'SELECT p FROM Doctrine\Tests\Models\CustomType\CustomTypeParent p', + 'SELECT c0_.id AS id0, ((c0_.customInteger) * -1) AS customInteger1 FROM customtype_parents c0_' + ); + } } diff --git a/tests/Doctrine/Tests/ORM/Query/UpdateSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/UpdateSqlGenerationTest.php index a8a59ff63..34658c95a 100644 --- a/tests/Doctrine/Tests/ORM/Query/UpdateSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/UpdateSqlGenerationTest.php @@ -21,6 +21,8 @@ namespace Doctrine\Tests\ORM\Query; +use Doctrine\DBAL\Types\Type as DBALType; + require_once __DIR__ . '/../../TestInit.php'; /** @@ -42,6 +44,12 @@ class UpdateSqlGenerationTest extends \Doctrine\Tests\OrmTestCase private $_em; protected function setUp() { + if (DBALType::hasType('negative_to_positive')) { + DBALType::overrideType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } else { + DBALType::addType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } + $this->_em = $this->_getTestEntityManager(); } @@ -186,4 +194,20 @@ class UpdateSqlGenerationTest extends \Doctrine\Tests\OrmTestCase "UPDATE cms_users SET status = 'inactive' WHERE (SELECT COUNT(*) FROM cms_users_groups c0_ WHERE c0_.user_id = cms_users.id) = 10" ); } + + public function testCustomTypeValueSql() + { + $this->assertSqlGeneration( + 'UPDATE Doctrine\Tests\Models\CustomType\CustomTypeParent p SET p.customInteger = 1 WHERE p.id = 1', + 'UPDATE customtype_parents SET customInteger = ABS(1) WHERE id = 1' + ); + } + + public function testCustomTypeValueSqlIgnoresIdentifierColumns() + { + $this->assertSqlGeneration( + 'UPDATE Doctrine\Tests\Models\CustomType\CustomTypeParent p SET p.id = 2 WHERE p.id = 1', + 'UPDATE customtype_parents SET id = 2 WHERE id = 1' + ); + } } diff --git a/tests/Doctrine/Tests/OrmFunctionalTestCase.php b/tests/Doctrine/Tests/OrmFunctionalTestCase.php index 0900e4e99..e0b9d7bee 100644 --- a/tests/Doctrine/Tests/OrmFunctionalTestCase.php +++ b/tests/Doctrine/Tests/OrmFunctionalTestCase.php @@ -112,6 +112,11 @@ abstract class OrmFunctionalTestCase extends OrmTestCase 'Doctrine\Tests\Models\Legacy\LegacyArticle', 'Doctrine\Tests\Models\Legacy\LegacyCar', ), + 'customtype' => array( + 'Doctrine\Tests\Models\CustomType\CustomTypeChild', + 'Doctrine\Tests\Models\CustomType\CustomTypeParent', + 'Doctrine\Tests\Models\CustomType\CustomTypeUpperCase', + ), ); protected function useModelSet($setName) @@ -219,6 +224,13 @@ abstract class OrmFunctionalTestCase extends OrmTestCase $conn->executeUpdate('DELETE FROM legacy_users'); } + if (isset($this->_usedModelSets['customtype'])) { + $conn->executeUpdate('DELETE FROM customtype_parent_friends'); + $conn->executeUpdate('DELETE FROM customtype_parents'); + $conn->executeUpdate('DELETE FROM customtype_children'); + $conn->executeUpdate('DELETE FROM customtype_uppercases'); + } + $this->_em->clear(); } From 841d12e9b6efebc08a76687c94e963376d223444 Mon Sep 17 00:00:00 2001 From: Jan Sorgalla Date: Sun, 20 Nov 2011 19:50:51 +0100 Subject: [PATCH 2/4] Move check for conversion SQL to ClassMetadataInfo --- lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php | 11 ++++++++++- lib/Doctrine/ORM/Mapping/MappingException.php | 5 +++++ .../AbstractEntityInheritancePersister.php | 4 ++-- .../ORM/Persisters/BasicEntityPersister.php | 11 ++++++----- lib/Doctrine/ORM/Query/SqlWalker.php | 10 +++++----- .../Tests/Models/CustomType/CustomTypeChild.php | 2 +- .../Tests/Models/CustomType/CustomTypeParent.php | 2 +- .../BasicEntityPersisterTypeValueSqlTest.php | 16 +++++++++++----- 8 files changed, 41 insertions(+), 20 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index b8c4ef2f1..c15b2d066 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -20,6 +20,7 @@ namespace Doctrine\ORM\Mapping; use Doctrine\Common\Persistence\Mapping\ClassMetadata; +use Doctrine\DBAL\Types\Type; use ReflectionClass; /** @@ -735,7 +736,7 @@ class ClassMetadataInfo implements ClassMetadata // Complete id mapping if (isset($mapping['id']) && $mapping['id'] === true) { if ($this->versionField == $mapping['fieldName']) { - throw MappingException::cannotVersionIdField($this->name, $mapping['fieldName']); + throw MappingException::cannotVersionIdField($this->name, $mapping['fieldName'], $mapping['type']); } if ( ! in_array($mapping['fieldName'], $this->identifier)) { @@ -746,6 +747,14 @@ class ClassMetadataInfo implements ClassMetadata $this->isIdentifierComposite = true; } } + + if (Type::hasType($mapping['type']) && Type::getType($mapping['type'])->canRequireSQLConversion()) { + if (isset($mapping['id']) && $mapping['id'] === true) { + throw MappingException::sqlConversionNotAllowedForIdentifiers($this->name, $mapping['fieldName']); + } + + $mapping['requireSQLConversion'] = true; + } } /** diff --git a/lib/Doctrine/ORM/Mapping/MappingException.php b/lib/Doctrine/ORM/Mapping/MappingException.php index e32e34c16..9c23d6f1a 100644 --- a/lib/Doctrine/ORM/Mapping/MappingException.php +++ b/lib/Doctrine/ORM/Mapping/MappingException.php @@ -226,6 +226,11 @@ class MappingException extends \Doctrine\ORM\ORMException return new self("Setting Id field '$fieldName' as versionale in entity class '$className' is not supported."); } + public static function sqlConversionNotAllowedForIdentifiers($className, $fieldName, $type) + { + return new self("It is not possible to set id field '$fieldName' to type '$type' in entity class '$className'. The type '$type' requires conversion SQL which is not allowed for identifiers."); + } + /** * @param string $className * @param string $columnName diff --git a/lib/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php b/lib/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php index 4f45f0877..e3bb9a943 100644 --- a/lib/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php +++ b/lib/Doctrine/ORM/Persisters/AbstractEntityInheritancePersister.php @@ -65,10 +65,10 @@ abstract class AbstractEntityInheritancePersister extends BasicEntityPersister $columnAlias = $this->getSQLColumnAlias($columnName); $this->_rsm->addFieldResult($alias, $columnAlias, $field, $class->name); - if (!$class->isIdentifier($field)) { + if (isset($class->fieldMappings[$field]['requireSQLConversion'])) { $type = Type::getType($class->getTypeOfField($field)); $sql = $type->convertToPHPValueSQL($sql, $this->_platform); - } + } return $sql . ' AS ' . $columnAlias; } diff --git a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php index 41fb01a75..16dace847 100644 --- a/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php +++ b/lib/Doctrine/ORM/Persisters/BasicEntityPersister.php @@ -344,7 +344,7 @@ class BasicEntityPersister if (isset($this->_class->fieldNames[$columnName])) { $column = $this->_class->getQuotedColumnName($this->_class->fieldNames[$columnName], $this->_platform); - if (!$this->_class->isIdentifier($this->_class->fieldNames[$columnName])) { + if (isset($this->_class->fieldMappings[$this->_class->fieldNames[$columnName]]['requireSQLConversion'])) { $type = Type::getType($this->_columnTypes[$columnName]); $placeholder = $type->convertToDatabaseValueSQL('?', $this->_platform); } @@ -1131,7 +1131,8 @@ class BasicEntityPersister foreach ($columns AS $column) { $placeholder = '?'; - if (isset($this->_columnTypes[$column])) { + if (isset($this->_columnTypes[$column]) && + isset($this->_class->fieldMappings[$this->_class->fieldNames[$column]]['requireSQLConversion'])) { $type = Type::getType($this->_columnTypes[$column]); $placeholder = $type->convertToDatabaseValueSQL('?', $this->_platform); } @@ -1198,8 +1199,8 @@ class BasicEntityPersister $columnAlias = $this->getSQLColumnAlias($class->columnNames[$field]); $this->_rsm->addFieldResult($alias, $columnAlias, $field); - - if (!$class->isIdentifier($field)) { + + if (isset($class->fieldMappings[$field]['requireSQLConversion'])) { $type = Type::getType($class->getTypeOfField($field)); $sql = $type->convertToPHPValueSQL($sql, $this->_platform); } @@ -1295,7 +1296,7 @@ class BasicEntityPersister $conditionSql .= $this->_getSQLTableAlias($className) . '.' . $this->_class->getQuotedColumnName($field, $this->_platform); - if (!$this->_class->isIdentifier($field)) { + if (isset($this->_class->fieldMappings[$field]['requireSQLConversion'])) { $type = Type::getType($this->_class->getTypeOfField($field)); $placeholder = $type->convertToDatabaseValueSQL($placeholder, $this->_platform); } diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index 382796631..ccf6f2ca8 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -485,7 +485,7 @@ class SqlWalker implements TreeWalker $column .= $class->getQuotedColumnName($fieldName, $this->_platform); - if ($this->_useDbalTypeValueSql && !$class->isIdentifier($fieldName)) { + if ($this->_useDbalTypeValueSql && isset($class->fieldMappings[$fieldName]['requireSQLConversion'])) { $type = Type::getType($class->getTypeOfField($fieldName)); $column = $type->convertToPHPValueSQL($column, $this->_conn->getDatabasePlatform()); } @@ -1028,7 +1028,7 @@ class SqlWalker implements TreeWalker $col = $sqlTableAlias . '.' . $columnName; - if (!$class->isIdentifier($fieldName)) { + if (isset($class->fieldMappings[$fieldName]['requireSQLConversion'])) { $type = Type::getType($class->getTypeOfField($fieldName)); $col = $type->convertToPHPValueSQL($col, $this->_conn->getDatabasePlatform()); } @@ -1117,7 +1117,7 @@ class SqlWalker implements TreeWalker $col = $sqlTableAlias . '.' . $quotedColumnName; - if (!$class->isIdentifier($fieldName)) { + if (isset($class->fieldMappings[$fieldName]['requireSQLConversion'])) { $type = Type::getType($class->getTypeOfField($fieldName)); $col = $type->convertToPHPValueSQL($col, $this->_platform); } @@ -1146,7 +1146,7 @@ class SqlWalker implements TreeWalker $col = $sqlTableAlias . '.' . $quotedColumnName; - if (!$subClass->isIdentifier($fieldName)) { + if (isset($subClass->fieldMappings[$fieldName]['requireSQLConversion'])) { $type = Type::getType($subClass->getTypeOfField($fieldName)); $col = $type->convertToPHPValueSQL($col, $this->_platform); } @@ -1434,7 +1434,7 @@ class SqlWalker implements TreeWalker if ($updateItem->pathExpression->type == AST\PathExpression::TYPE_STATE_FIELD) { $class = $this->_queryComponents[$updateItem->pathExpression->identificationVariable]['metadata']; - if (!$class->isIdentifier($updateItem->pathExpression->field)) { + if (isset($class->fieldMappings[$updateItem->pathExpression->field]['requireSQLConversion'])) { $this->_currentColumnType = $class->getTypeOfField($updateItem->pathExpression->field); } } diff --git a/tests/Doctrine/Tests/Models/CustomType/CustomTypeChild.php b/tests/Doctrine/Tests/Models/CustomType/CustomTypeChild.php index 799ad5016..e178ab51c 100644 --- a/tests/Doctrine/Tests/Models/CustomType/CustomTypeChild.php +++ b/tests/Doctrine/Tests/Models/CustomType/CustomTypeChild.php @@ -9,7 +9,7 @@ namespace Doctrine\Tests\Models\CustomType; class CustomTypeChild { /** - * @Id @Column(type="negative_to_positive") + * @Id @Column(type="integer") * @GeneratedValue(strategy="AUTO") */ public $id; diff --git a/tests/Doctrine/Tests/Models/CustomType/CustomTypeParent.php b/tests/Doctrine/Tests/Models/CustomType/CustomTypeParent.php index 0ade61c91..1cc3126e4 100644 --- a/tests/Doctrine/Tests/Models/CustomType/CustomTypeParent.php +++ b/tests/Doctrine/Tests/Models/CustomType/CustomTypeParent.php @@ -9,7 +9,7 @@ namespace Doctrine\Tests\Models\CustomType; class CustomTypeParent { /** - * @Id @Column(type="negative_to_positive") + * @Id @Column(type="integer") * @GeneratedValue(strategy="AUTO") */ public $id; diff --git a/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php b/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php index e608e6ba8..04c47893d 100644 --- a/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php +++ b/tests/Doctrine/Tests/ORM/Persisters/BasicEntityPersisterTypeValueSqlTest.php @@ -18,16 +18,22 @@ class BasicEntityPersisterTypeValueSqlTest extends \Doctrine\Tests\OrmTestCase protected function setUp() { parent::setUp(); - - $this->_em = $this->_getTestEntityManager(); - - $this->_persister = new BasicEntityPersister($this->_em, $this->_em->getClassMetadata("Doctrine\Tests\Models\CustomType\CustomTypeParent")); - + if (DBALType::hasType('negative_to_positive')) { DBALType::overrideType('negative_to_positive', '\Doctrine\Tests\DbalTypes\NegativeToPositiveType'); } else { DBALType::addType('negative_to_positive', '\Doctrine\Tests\DbalTypes\NegativeToPositiveType'); } + + if (DBALType::hasType('upper_case_string')) { + DBALType::overrideType('upper_case_string', '\Doctrine\Tests\DbalTypes\UpperCaseStringType'); + } else { + DBALType::addType('upper_case_string', '\Doctrine\Tests\DbalTypes\UpperCaseStringType'); + } + + $this->_em = $this->_getTestEntityManager(); + + $this->_persister = new BasicEntityPersister($this->_em, $this->_em->getClassMetadata("Doctrine\Tests\Models\CustomType\CustomTypeParent")); } public function testGetInsertSQLUsesTypeValuesSQL() From 4042bc53ce9c98124d24a652b1ef5c5a311296b9 Mon Sep 17 00:00:00 2001 From: Jan Sorgalla Date: Sun, 20 Nov 2011 19:57:04 +0100 Subject: [PATCH 3/4] Fix argument on wrong method call --- lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php index c15b2d066..80349fc3c 100644 --- a/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php +++ b/lib/Doctrine/ORM/Mapping/ClassMetadataInfo.php @@ -736,7 +736,7 @@ class ClassMetadataInfo implements ClassMetadata // Complete id mapping if (isset($mapping['id']) && $mapping['id'] === true) { if ($this->versionField == $mapping['fieldName']) { - throw MappingException::cannotVersionIdField($this->name, $mapping['fieldName'], $mapping['type']); + throw MappingException::cannotVersionIdField($this->name, $mapping['fieldName']); } if ( ! in_array($mapping['fieldName'], $this->identifier)) { @@ -750,7 +750,7 @@ class ClassMetadataInfo implements ClassMetadata if (Type::hasType($mapping['type']) && Type::getType($mapping['type'])->canRequireSQLConversion()) { if (isset($mapping['id']) && $mapping['id'] === true) { - throw MappingException::sqlConversionNotAllowedForIdentifiers($this->name, $mapping['fieldName']); + throw MappingException::sqlConversionNotAllowedForIdentifiers($this->name, $mapping['fieldName'], $mapping['type']); } $mapping['requireSQLConversion'] = true; From 16aa558292d8513c27add2dd7ed0574b3d6820db Mon Sep 17 00:00:00 2001 From: jsor Date: Mon, 21 Nov 2011 15:08:36 +0100 Subject: [PATCH 4/4] Remove sql conversion from where clauses and update statements --- lib/Doctrine/ORM/Query/SqlWalker.php | 52 ++----------------- .../DbalTypes/NegativeToPositiveType.php | 2 +- .../Tests/ORM/Functional/TypeValueSqlTest.php | 5 +- .../ORM/Query/SelectSqlGenerationTest.php | 18 ++++++- .../ORM/Query/UpdateSqlGenerationTest.php | 12 +---- 5 files changed, 27 insertions(+), 62 deletions(-) diff --git a/lib/Doctrine/ORM/Query/SqlWalker.php b/lib/Doctrine/ORM/Query/SqlWalker.php index ccf6f2ca8..3b58dfba2 100644 --- a/lib/Doctrine/ORM/Query/SqlWalker.php +++ b/lib/Doctrine/ORM/Query/SqlWalker.php @@ -97,17 +97,6 @@ class SqlWalker implements TreeWalker * These should only be generated for SELECT queries, not for UPDATE/DELETE. */ private $_useSqlTableAliases = true; - - /** - * Flag that indicates whether to pass columns through Type::convertToPHPValueSQL(). - * These should only be done for SELECT queries, not for UPDATE. - */ - private $_useDbalTypeValueSql = true; - - /** - * Holds the current columns type. - */ - private $_currentColumnType; /** * The database platform abstraction. @@ -421,7 +410,6 @@ class SqlWalker implements TreeWalker public function walkUpdateStatement(AST\UpdateStatement $AST) { $this->_useSqlTableAliases = false; - $this->_useDbalTypeValueSql = false; return $this->walkUpdateClause($AST->updateClause) . $this->walkWhereClause($AST->whereClause); } @@ -477,20 +465,11 @@ class SqlWalker implements TreeWalker $dqlAlias = $pathExpr->identificationVariable; $class = $this->_queryComponents[$dqlAlias]['metadata']; - $column = ''; - if ($this->_useSqlTableAliases) { - $column .= $this->walkIdentificationVariable($dqlAlias, $fieldName) . '.'; + $sql .= $this->walkIdentificationVariable($dqlAlias, $fieldName) . '.'; } - $column .= $class->getQuotedColumnName($fieldName, $this->_platform); - - if ($this->_useDbalTypeValueSql && isset($class->fieldMappings[$fieldName]['requireSQLConversion'])) { - $type = Type::getType($class->getTypeOfField($fieldName)); - $column = $type->convertToPHPValueSQL($column, $this->_conn->getDatabasePlatform()); - } - - $sql .= $column; + $sql .= $class->getQuotedColumnName($fieldName, $this->_platform); break; case AST\PathExpression::TYPE_SINGLE_VALUED_ASSOCIATION: @@ -1429,18 +1408,7 @@ class SqlWalker implements TreeWalker switch (true) { case ($newValue instanceof AST\Node): - $currentColumnTypeBefore = $this->_currentColumnType; - $this->_currentColumnType = null; - - if ($updateItem->pathExpression->type == AST\PathExpression::TYPE_STATE_FIELD) { - $class = $this->_queryComponents[$updateItem->pathExpression->identificationVariable]['metadata']; - if (isset($class->fieldMappings[$updateItem->pathExpression->field]['requireSQLConversion'])) { - $this->_currentColumnType = $class->getTypeOfField($updateItem->pathExpression->field); - } - } - $sql .= $newValue->dispatch($this); - $this->_currentColumnType = $currentColumnTypeBefore; break; case ($newValue === null): @@ -1813,30 +1781,20 @@ class SqlWalker implements TreeWalker { switch ($literal->type) { case AST\Literal::STRING: - $value = $this->_conn->quote($literal->value); - break; + return $this->_conn->quote($literal->value); case AST\Literal::BOOLEAN: $bool = strtolower($literal->value) == 'true' ? true : false; $boolVal = $this->_conn->getDatabasePlatform()->convertBooleans($bool); - $value = $boolVal; - break; + return $boolVal; case AST\Literal::NUMERIC: - $value = $literal->value; - break; + return $literal->value; default: throw QueryException::invalidLiteral($literal); } - - if ($this->_currentColumnType !== null) { - $type = Type::getType($this->_currentColumnType); - $value = $type->convertToDatabaseValueSQL($value, $this->_conn->getDatabasePlatform()); - } - - return $value; } /** diff --git a/tests/Doctrine/Tests/DbalTypes/NegativeToPositiveType.php b/tests/Doctrine/Tests/DbalTypes/NegativeToPositiveType.php index e477ecd3c..ae704f8bd 100644 --- a/tests/Doctrine/Tests/DbalTypes/NegativeToPositiveType.php +++ b/tests/Doctrine/Tests/DbalTypes/NegativeToPositiveType.php @@ -29,6 +29,6 @@ class NegativeToPositiveType extends Type public function convertToPHPValueSQL($sqlExpr, $platform) { - return '((' . $sqlExpr . ') * -1)'; + return '-(' . $sqlExpr . ')'; } } diff --git a/tests/Doctrine/Tests/ORM/Functional/TypeValueSqlTest.php b/tests/Doctrine/Tests/ORM/Functional/TypeValueSqlTest.php index 6102812d7..5a05d76d2 100644 --- a/tests/Doctrine/Tests/ORM/Functional/TypeValueSqlTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/TypeValueSqlTest.php @@ -46,7 +46,7 @@ class TypeValueSqlTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals('foo', $entity->lowerCaseString, 'Entity holds lowercase string'); $this->assertEquals('FOO', $this->_em->getConnection()->fetchColumn("select lowerCaseString from customtype_uppercases where id=".$entity->id.""), 'Database holds uppercase string'); } - + public function testTypeValueSqlWithAssociations() { $parent = new CustomTypeParent(); @@ -90,12 +90,13 @@ class TypeValueSqlTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->_em->clear(); - $query = $this->_em->createQuery("SELECT p, p.customInteger, c from Doctrine\Tests\Models\CustomType\CustomTypeParent p JOIN p.child c where p.id = " . $parentId . " AND p.customInteger = -1"); + $query = $this->_em->createQuery("SELECT p, p.customInteger, c from Doctrine\Tests\Models\CustomType\CustomTypeParent p JOIN p.child c where p.id = " . $parentId); $result = $query->getResult(); $this->assertEquals(1, count($result)); $this->assertInstanceOf('Doctrine\Tests\Models\CustomType\CustomTypeParent', $result[0][0]); + $this->assertEquals(-1, $result[0][0]->customInteger); $this->assertEquals(-1, $result[0]['customInteger']); diff --git a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php index 028406068..ceb1a3729 100644 --- a/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/SelectSqlGenerationTest.php @@ -1345,7 +1345,7 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase $this->assertSqlGeneration( 'SELECT p.customInteger FROM Doctrine\Tests\Models\CustomType\CustomTypeParent p WHERE p.id = 1', - 'SELECT ((c0_.customInteger) * -1) AS customInteger0 FROM customtype_parents c0_ WHERE c0_.id = 1' + 'SELECT -(c0_.customInteger) AS customInteger0 FROM customtype_parents c0_ WHERE c0_.id = 1' ); } @@ -1373,7 +1373,21 @@ class SelectSqlGenerationTest extends \Doctrine\Tests\OrmTestCase $this->assertSqlGeneration( 'SELECT p FROM Doctrine\Tests\Models\CustomType\CustomTypeParent p', - 'SELECT c0_.id AS id0, ((c0_.customInteger) * -1) AS customInteger1 FROM customtype_parents c0_' + 'SELECT c0_.id AS id0, -(c0_.customInteger) AS customInteger1 FROM customtype_parents c0_' + ); + } + + public function testCustomTypeValueSqlForPartialObject() + { + if (DBALType::hasType('negative_to_positive')) { + DBALType::overrideType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } else { + DBALType::addType('negative_to_positive', 'Doctrine\Tests\DbalTypes\NegativeToPositiveType'); + } + + $this->assertSqlGeneration( + 'SELECT partial p.{id, customInteger} FROM Doctrine\Tests\Models\CustomType\CustomTypeParent p', + 'SELECT c0_.id AS id0, -(c0_.customInteger) AS customInteger1 FROM customtype_parents c0_' ); } } diff --git a/tests/Doctrine/Tests/ORM/Query/UpdateSqlGenerationTest.php b/tests/Doctrine/Tests/ORM/Query/UpdateSqlGenerationTest.php index 34658c95a..a65efe079 100644 --- a/tests/Doctrine/Tests/ORM/Query/UpdateSqlGenerationTest.php +++ b/tests/Doctrine/Tests/ORM/Query/UpdateSqlGenerationTest.php @@ -195,19 +195,11 @@ class UpdateSqlGenerationTest extends \Doctrine\Tests\OrmTestCase ); } - public function testCustomTypeValueSql() + public function testCustomTypeValueSqlCompletelyIgnoredInUpdateStatements() { $this->assertSqlGeneration( 'UPDATE Doctrine\Tests\Models\CustomType\CustomTypeParent p SET p.customInteger = 1 WHERE p.id = 1', - 'UPDATE customtype_parents SET customInteger = ABS(1) WHERE id = 1' - ); - } - - public function testCustomTypeValueSqlIgnoresIdentifierColumns() - { - $this->assertSqlGeneration( - 'UPDATE Doctrine\Tests\Models\CustomType\CustomTypeParent p SET p.id = 2 WHERE p.id = 1', - 'UPDATE customtype_parents SET id = 2 WHERE id = 1' + 'UPDATE customtype_parents SET customInteger = 1 WHERE id = 1' ); } }