From be529eb875290d74a551d349faa61230de48c956 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 2 Jun 2013 16:20:14 -0400 Subject: [PATCH] Implement index/constraint reflection for postgres. Implement index reflection for postgres. --- lib/Cake/Database/Schema/PostgresSchema.php | 57 ++++++++++++++++--- .../Database/Schema/PostgresSchemaTest.php | 45 ++++++++++++++- 2 files changed, 90 insertions(+), 12 deletions(-) diff --git a/lib/Cake/Database/Schema/PostgresSchema.php b/lib/Cake/Database/Schema/PostgresSchema.php index d4d03eac06d..47144f20e47 100644 --- a/lib/Cake/Database/Schema/PostgresSchema.php +++ b/lib/Cake/Database/Schema/PostgresSchema.php @@ -168,13 +168,9 @@ public function convertFieldDescription(Table $table, $row, $fieldParams = []) { $field += [ 'null' => $row['null'] === 'YES' ? true : false, 'default' => $row['default'], + 'comment' => $row['comment'] ]; $field['length'] = $row['char_length'] ?: $field['length']; - foreach ($fieldParams as $key => $metadata) { - if (!empty($row[$metadata['column']])) { - $field[$key] = $row[$metadata['column']]; - } - } $table->addColumn($row['name'], $field); if (!empty($row['pk'])) { $table->addConstraint('primary', [ @@ -188,11 +184,34 @@ public function convertFieldDescription(Table $table, $row, $fieldParams = []) { * Get the SQL to describe the indexes in a table. * * @param string $table The table name to get information on. + * @param array $config The configuration containing the schema name. * @return array An array of (sql, params) to execute. */ - public function describeIndexSql($table) { - $sql = ''; - return [$sql, []]; + public function describeIndexSql($table, $config) { + $sql = "SELECT + c2.relname, + i.indisprimary, + i.indisunique, + i.indisvalid, + pg_catalog.pg_get_indexdef(i.indexrelid, 0, true) AS statement + FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i + WHERE c.oid = ( + SELECT c.oid + FROM pg_catalog.pg_class c + LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace + WHERE c.relname = ? + AND pg_catalog.pg_table_is_visible(c.oid) + AND n.nspname = ? + ) + AND c.oid = i.indrelid + AND i.indexrelid = c2.oid + ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname"; + + $schema = 'public'; + if (!empty($config['schema'])) { + $schema = $config['schema']; + } + return [$sql, [$table, $schema]]; } /** @@ -204,6 +223,27 @@ public function describeIndexSql($table) { * @return void */ public function convertIndexDescription(Table $table, $row) { + $type = Table::INDEX_INDEX; + $name = $row['relname']; + if ($row['indisprimary']) { + $name = $type = Table::CONSTRAINT_PRIMARY; + } + if ($row['indisunique'] && $type === Table::INDEX_INDEX) { + $type = Table::CONSTRAINT_UNIQUE; + } + preg_match('/\(([^\)]+)\)/', $row['statement'], $matches); + $columns = explode(', ', $matches[1]); + if ($type === Table::CONSTRAINT_PRIMARY || $type === Table::CONSTRAINT_UNIQUE) { + $table->addConstraint($name, [ + 'type' => $type, + 'columns' => $columns + ]); + } else { + $table->addIndex($name, [ + 'type' => $type, + 'columns' => $columns + ]); + } } @@ -373,7 +413,6 @@ public function dropTableSql(Table $table) { */ public function truncateTableSql(Table $table) { $name = $this->_driver->quoteIdentifier($table->name()); - return [ sprintf("TRUNCATE %s RESTART IDENTITY", $name) ]; diff --git a/lib/Cake/Test/TestCase/Database/Schema/PostgresSchemaTest.php b/lib/Cake/Test/TestCase/Database/Schema/PostgresSchemaTest.php index d074d5a47f3..c497b0073bb 100644 --- a/lib/Cake/Test/TestCase/Database/Schema/PostgresSchemaTest.php +++ b/lib/Cake/Test/TestCase/Database/Schema/PostgresSchemaTest.php @@ -67,11 +67,13 @@ protected function _createTables($connection) { author_id INTEGER NOT NULL, published BOOLEAN DEFAULT false, views SMALLINT DEFAULT 0, -created TIMESTAMP +created TIMESTAMP, +CONSTRAINT "content_idx" UNIQUE ("title", "body") ) SQL; $connection->execute($table); $connection->execute('COMMENT ON COLUMN "articles"."title" IS \'a title\''); + $connection->execute('CREATE INDEX "author_idx" ON "articles" ("author_id")'); } /** @@ -282,7 +284,7 @@ public function testDescribeTable() { 'length' => null, 'precision' => null, 'fixed' => null, - 'collate' => null, + 'comment' => null, ], ]; $this->assertEquals(['id'], $result->primaryKey()); @@ -291,6 +293,43 @@ public function testDescribeTable() { } } +/** + * Test describing a table with indexes + * + * @return void + */ + public function testDescribeTableIndexes() { + $connection = new Connection(Configure::read('Datasource.test')); + $this->_createTables($connection); + + $schema = new SchemaCollection($connection); + $result = $schema->describe('articles'); + $this->assertInstanceOf('Cake\Database\Schema\Table', $result); + $expected = [ + 'primary' => [ + 'type' => 'primary', + 'columns' => ['id'], + 'length' => [] + ], + 'content_idx' => [ + 'type' => 'unique', + 'columns' => ['title', 'body'], + 'length' => [] + ] + ]; + $this->assertCount(2, $result->constraints()); + $this->assertEquals($expected['primary'], $result->constraint('primary')); + $this->assertEquals($expected['content_idx'], $result->constraint('content_idx')); + + $this->assertCount(1, $result->indexes()); + $expected = [ + 'type' => 'index', + 'columns' => ['author_id'], + 'length' => [] + ]; + $this->assertEquals($expected, $result->index('author_idx')); + } + /** * Column provider for creating column sql * @@ -473,7 +512,7 @@ public static function constraintSqlProvider() { } /** - * Test the indexSql method. + * Test the constraintSql method. * * @dataProvider constraintSqlProvider */