From ea64588a814b09565b82c428845f7a096814c327 Mon Sep 17 00:00:00 2001 From: Mark Story Date: Mon, 15 Mar 2010 22:55:14 -0400 Subject: [PATCH] Adding tests from 'Stephen Cuppert' to test incorrectly generate DELETE queries for habtm join tables that do not have a primary key when using PostgreSQL. Updating DboSource::_matchRecords() to only query the table if the supplied conditions are actually multi-table conditions. Fixes #459 --- cake/libs/model/datasources/dbo_source.php | 16 ++++++ .../cases/libs/model/model_delete.test.php | 55 +++++++++++++++++++ 2 files changed, 71 insertions(+) diff --git a/cake/libs/model/datasources/dbo_source.php b/cake/libs/model/datasources/dbo_source.php index 9f087946d..5982e137d 100644 --- a/cake/libs/model/datasources/dbo_source.php +++ b/cake/libs/model/datasources/dbo_source.php @@ -1477,6 +1477,22 @@ class DboSource extends DataSource { } elseif ($conditions === null) { $conditions = $this->conditions($this->defaultConditions($model, $conditions, false), true, true, $model); } else { + $noJoin = true; + foreach ($conditions as $field => $value) { + $originalField = $field; + if (strpos($field, '.') !== false) { + list($alias, $field) = explode('.', $field); + } + if (!$model->hasField($field)) { + $noJoin = false; + break; + } + $conditions[$field] = $value; + unset($conditions[$originalField]); + } + if ($noJoin === true) { + return $this->conditions($conditions); + } $idList = $model->find('all', array( 'fields' => "{$model->alias}.{$model->primaryKey}", 'conditions' => $conditions diff --git a/cake/tests/cases/libs/model/model_delete.test.php b/cake/tests/cases/libs/model/model_delete.test.php index e2d4874f8..d299cc905 100644 --- a/cake/tests/cases/libs/model/model_delete.test.php +++ b/cake/tests/cases/libs/model/model_delete.test.php @@ -580,6 +580,61 @@ class ModelDeleteTest extends BaseModelTest { $exists = $Model->findById(1); $this->assertTrue(is_array($exists)); } +/** + * test for a habtm deletion error that occurs in postgres but should not. + * And should not occur in any dbo. + * + * @return void + */ + function testDeleteHabtmPostgresFailure() { + $this->loadFixtures('Article', 'Tag', 'ArticlesTag'); + + $Article =& ClassRegistry::init('Article'); + $Article->hasAndBelongsToMany['Tag']['unique'] = true; + + $Tag =& ClassRegistry::init('Tag'); + $Tag->bindModel(array('hasAndBelongsToMany' => array( + 'Article' => array( + 'className' => 'Article', + 'unique' => true + ) + )), true); + + // Article 1 should have Tag.1 and Tag.2 + $before = $Article->find("all", array( + "conditions" => array("Article.id" => 1), + )); + $this->assertEqual(count($before[0]['Tag']), 2, 'Tag count for Article.id = 1 is incorrect, should be 2 %s'); + + // From now on, Tag #1 is only associated with Post #1 + $submitted_data = array( + "Tag" => array("id" => 1, 'tag' => 'tag1'), + "Article" => array( + "Article" => array(1) + ) + ); + $Tag->save($submitted_data); + + // One more submission (The other way around) to make sure the reverse save looks good. + $submitted_data = array( + "Article" => array("id" => 2, 'title' => 'second article'), + "Tag" => array( + "Tag" => array(2, 3) + ) + ); + // ERROR: + // Postgresql: DELETE FROM "articles_tags" WHERE tag_id IN ('1', '3') + // MySQL: DELETE `ArticlesTag` FROM `articles_tags` AS `ArticlesTag` WHERE `ArticlesTag`.`article_id` = 2 AND `ArticlesTag`.`tag_id` IN (1, 3) + $Article->save($submitted_data); + + // Want to make sure Article #1 has Tag #1 and Tag #2 still. + $after = $Article->find("all", array( + "conditions" => array("Article.id" => 1), + )); + + // Removing Article #2 from Tag #1 is all that should have happened. + $this->assertEqual(count($before[0]["Tag"]), count($after[0]["Tag"])); + } } ?> \ No newline at end of file