From 0b6c23d04fe99ab1a4b10ed773fbfa4047747fe6 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 26 Mar 2017 22:22:51 -0400 Subject: [PATCH] Update schema reflection for postgres. Use the schema reflection query from 3.x to provide access to the serial column attributes. These attributes give a more reliable way to access primary key data than comparing the primary key of the model. The old approach failed when schema was generated and concrete model's were missing. Refs #10356 --- .../Model/Datasource/Database/Postgres.php | 50 +++++++++++++------ lib/Cake/Test/Case/Model/CakeSchemaTest.php | 9 ++-- 2 files changed, 39 insertions(+), 20 deletions(-) diff --git a/lib/Cake/Model/Datasource/Database/Postgres.php b/lib/Cake/Model/Datasource/Database/Postgres.php index 8673fbc5c..173c67c67 100644 --- a/lib/Cake/Model/Datasource/Database/Postgres.php +++ b/lib/Cake/Model/Datasource/Database/Postgres.php @@ -198,14 +198,26 @@ class Postgres extends DboSource { $fields = parent::describe($table); $this->_sequenceMap[$table] = array(); $cols = null; + $hasPrimary = false; if ($fields === null) { $cols = $this->_execute( - "SELECT DISTINCT table_schema AS schema, column_name AS name, data_type AS type, is_nullable AS null, - column_default AS default, ordinal_position AS position, character_maximum_length AS char_length, - character_octet_length AS oct_length FROM information_schema.columns - WHERE table_name = ? AND table_schema = ? ORDER BY position", - array($table, $this->config['schema']) + 'SELECT DISTINCT table_schema AS schema, + column_name AS name, + data_type AS type, + is_nullable AS null, + column_default AS default, + ordinal_position AS position, + character_maximum_length AS char_length, + character_octet_length AS oct_length, + pg_get_serial_sequence(attr.attrelid::regclass::text, attr.attname) IS NOT NULL AS has_serial + FROM information_schema.columns c + INNER JOIN pg_catalog.pg_namespace ns ON (ns.nspname = table_schema) + INNER JOIN pg_catalog.pg_class cl ON (cl.relnamespace = ns.oid AND cl.relname = table_name) + LEFT JOIN pg_catalog.pg_attribute attr ON (cl.oid = attr.attrelid AND column_name = attr.attname) + WHERE table_name = ? AND table_schema = ? AND table_catalog = ? + ORDER BY ordinal_position', + array($table, $this->config['schema'], $this->config['database']) ); // @codingStandardsIgnoreStart @@ -238,17 +250,25 @@ class Postgres extends DboSource { "$1", preg_replace('/::.*/', '', $c->default) ), - 'length' => $length + 'length' => $length, ); - if ($model instanceof Model) { - if ($c->name === $model->primaryKey) { - $fields[$c->name]['key'] = 'primary'; - if ( - $fields[$c->name]['type'] !== 'string' && - $fields[$c->name]['type'] !== 'uuid' - ) { - $fields[$c->name]['length'] = 11; - } + + // Serial columns are primary integer keys + if ($c->has_serial) { + $fields[$c->name]['key'] = 'primary'; + $fields[$c->name]['length'] = 11; + $hasPrimary = true; + } + if ($hasPrimary === false && + $model instanceof Model && + $c->name === $model->primaryKey + ) { + $fields[$c->name]['key'] = 'primary'; + if ( + $fields[$c->name]['type'] !== 'string' && + $fields[$c->name]['type'] !== 'uuid' + ) { + $fields[$c->name]['length'] = 11; } } if ( diff --git a/lib/Cake/Test/Case/Model/CakeSchemaTest.php b/lib/Cake/Test/Case/Model/CakeSchemaTest.php index 7d27fc681..b2e887313 100644 --- a/lib/Cake/Test/Case/Model/CakeSchemaTest.php +++ b/lib/Cake/Test/Case/Model/CakeSchemaTest.php @@ -688,7 +688,6 @@ class CakeSchemaTest extends CakeTestCase { * @return void */ public function testSchemaReadWithNonConventionalPrimaryKey() { - $this->skipIf($this->db instanceof Postgres, 'Cannot test on Postgres'); $db = ConnectionManager::getDataSource('test'); $fixture = new NonConventionalPrimaryKeyFixture(); $fixture->create($db); @@ -700,14 +699,14 @@ class CakeSchemaTest extends CakeTestCase { )); $fixture->drop($db); - $hasTable = isset($read['tables']['non_conventional']); - $this->assertTrue($hasTable, 'non_conventional table should appear'); + $this->assertArrayHasKey('non_conventional', $read['tables']); $versionIdHasKey = isset($read['tables']['non_conventional']['version_id']['key']); $this->assertTrue($versionIdHasKey, 'version_id key should be set'); $versionIdKeyIsPrimary = $read['tables']['non_conventional']['version_id']['key'] === 'primary'; $this->assertTrue($versionIdKeyIsPrimary, 'version_id key should be primary'); - $idHasNoKey = !isset($read['tables']['non_conventional']['id']['key']); - $this->assertTrue($idHasNoKey, 'id key should not be set'); + + $idHasKey = isset($read['tables']['non_conventional']['id']['key']); + $this->assertFalse($idHasKey, 'id key should not be set'); } /**