Browse Source

Generated SQL should not contain multi-column primary keys

While totally valid in databases, the Schema system is not designed to
handle multi-column primary keys in a sane way. In MySQL this results in
two auto_increment columns, and in postgres this results in two serial
columns.

Fixes #3069
mark_story 13 years ago
parent
commit
27e2132a13

+ 14 - 1
lib/Cake/Model/Datasource/DboSource.php

@@ -2953,11 +2953,24 @@ class DboSource extends DataSource {
 				$primary = null;
 				$table = $this->fullTableName($curTable);
 
+				$primaryCount = 0;
+				foreach ($columns as $col) {
+					if (isset($col['key']) && $col['key'] === 'primary') {
+						$primaryCount++;
+					}
+				}
+
 				foreach ($columns as $name => $col) {
 					if (is_string($col)) {
 						$col = array('type' => $col);
 					}
-					if (isset($col['key']) && $col['key'] === 'primary') {
+					$isPrimary = isset($col['key']) && $col['key'] === 'primary';
+					// Multi-column primary keys are not supported.
+					if ($isPrimary && $primaryCount > 1) {
+						unset($col['key']);
+						$isPrimary = false;
+					}
+					if ($isPrimary) {
 						$primary = $name;
 					}
 					if ($name !== 'indexes' && $name !== 'tableParameters') {

+ 39 - 0
lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php

@@ -839,6 +839,45 @@ class MysqlTest extends CakeTestCase {
 	}
 
 /**
+ * Test that two columns with key => primary doesn't create invalid sql.
+ *
+ * @return void
+ */
+	public function testTwoColumnsWithPrimaryKey() {
+		$schema = new CakeSchema(array(
+			'connection' => 'test',
+			'roles_users' => array(
+				'role_id' => array(
+					'type' => 'integer',
+					'null' => false,
+					'default' => null,
+					'key' => 'primary'
+				),
+				'user_id' => array(
+					'type' => 'integer',
+					'null' => false,
+					'default' => null,
+					'key' => 'primary'
+				),
+				'indexes' => array(
+					'user_role_index' => array(
+						'column' => array('role_id', 'user_id'),
+						'unique' => 1
+					),
+					'user_index' => array(
+						'column' => 'user_id',
+						'unique' => 0
+					)
+				),
+			)
+		));
+
+		$result = $this->Dbo->createSchema($schema);
+		$this->assertContains('`role_id` int(11) NOT NULL,', $result);
+		$this->assertContains('`user_id` int(11) NOT NULL,', $result);
+	}
+
+/**
  * Tests that listSources method sends the correct query and parses the result accordingly
  * @return void
  */