Browse Source

Merge pull request #8437 from cakephp/issue-8160

Optimize postgres index/constraint reflection
José Lorenzo Rodríguez 10 years ago
parent
commit
7480ec3ef1

+ 34 - 59
src/Database/Schema/PostgresSchema.php

@@ -191,33 +191,26 @@ class PostgresSchema extends BaseSchema
      */
     public function describeIndexSql($tableName, $config)
     {
-        $sql = 'SELECT
-            c2.relname,
-            a.attname,
-            i.indisprimary,
-            i.indisunique
-        FROM pg_catalog.pg_class AS c,
-            pg_catalog.pg_class AS c2,
-            pg_catalog.pg_index AS i,
-            pg_catalog.pg_attribute AS a
-        WHERE c.oid  = (
-            SELECT c.oid
-            FROM pg_catalog.pg_class c
-            LEFT JOIN pg_catalog.pg_namespace AS n ON n.oid = c.relnamespace
-            WHERE c.relname = ?
-                AND n.nspname = ?
-        )
-        AND c.oid = i.indrelid
-        AND c.oid = a.attrelid
+        $sql = "SELECT
+        c2.relname,
+        a.attname,
+        i.indisprimary,
+        i.indisunique
+        FROM pg_catalog.pg_namespace n
+        INNER JOIN pg_catalog.pg_class c ON (n.oid = c.relnamespace)
+        INNER JOIN pg_catalog.pg_index i ON (c.oid = i.indrelid)
+        INNER JOIN pg_catalog.pg_class c2 ON (c2.oid = i.indexrelid)
+        INNER JOIN pg_catalog.pg_attribute a ON (a.attrelid = c.oid AND i.indrelid::regclass = a.attrelid::regclass)
+        WHERE n.nspname = ?
         AND a.attnum = ANY(i.indkey)
-        AND i.indexrelid = c2.oid
-        ORDER BY i.indisprimary DESC, i.indisunique DESC, c2.relname, a.attnum';
+        AND c.relname = ?
+        ORDER BY i.indisprimary DESC, i.indisunique DESC, c.relname, a.attnum";
 
         $schema = 'public';
         if (!empty($config['schema'])) {
             $schema = $config['schema'];
         }
-        return [$sql, [$tableName, $schema]];
+        return [$sql, [$schema, $tableName]];
     }
 
     /**
@@ -276,43 +269,25 @@ class PostgresSchema extends BaseSchema
     public function describeForeignKeySql($tableName, $config)
     {
         $sql = "SELECT
-            rc.constraint_name AS name,
-            tc.constraint_type AS type,
-            kcu.column_name,
-            rc.match_option AS match_type,
-            rc.update_rule AS on_update,
-            rc.delete_rule AS on_delete,
-
-            kc.table_name AS references_table,
-            kc.column_name AS references_field
-
-            FROM information_schema.referential_constraints rc
-
-            JOIN information_schema.table_constraints tc
-                ON tc.constraint_name = rc.constraint_name
-                AND tc.constraint_schema = rc.constraint_schema
-                AND tc.constraint_name = rc.constraint_name
-                AND tc.table_schema = rc.constraint_schema
-
-            JOIN information_schema.key_column_usage kcu
-                ON kcu.constraint_name = rc.constraint_name
-                AND kcu.constraint_schema = rc.constraint_schema
-                AND kcu.constraint_name = rc.constraint_name
-                AND kcu.constraint_schema = rc.constraint_schema
-
-            JOIN information_schema.key_column_usage kc
-                ON kc.ordinal_position = kcu.position_in_unique_constraint
-                AND kc.constraint_name = rc.unique_constraint_name
-                AND kc.constraint_schema = rc.constraint_schema
-
-            WHERE kcu.table_name = ?
-              AND rc.constraint_schema = ?
-              AND tc.constraint_type = 'FOREIGN KEY'
-
-            ORDER BY rc.constraint_name, kcu.ordinal_position";
+        c.conname AS name,
+        c.contype AS type,
+        a.attname AS column_name,
+        c.confmatchtype AS match_type,
+        c.confupdtype AS on_update,
+        c.confdeltype AS on_delete,
+        c.confrelid::regclass AS references_table,
+        ab.attname AS references_field
+        FROM pg_catalog.pg_namespace n
+        INNER JOIN pg_catalog.pg_class cl ON (n.oid = cl.relnamespace)
+        INNER JOIN pg_catalog.pg_constraint c ON (n.oid = c.connamespace)
+        INNER JOIN pg_catalog.pg_attribute a ON (a.attrelid = cl.oid AND c.conrelid = a.attrelid AND a.attnum = ANY(c.conkey))
+        INNER JOIN pg_catalog.pg_attribute ab ON (a.attrelid = cl.oid AND c.confrelid = ab.attrelid AND ab.attnum = ANY(c.confkey))
+        WHERE n.nspname = ?
+        AND c.conrelid = ?::regclass
+        ORDER BY name, a.attnum, ab.attnum DESC";
 
         $schema = empty($config['schema']) ? 'public' : $config['schema'];
-        return [$sql, [$tableName, $schema]];
+        return [$sql, [$schema, $tableName]];
     }
 
     /**
@@ -335,13 +310,13 @@ class PostgresSchema extends BaseSchema
      */
     protected function _convertOnClause($clause)
     {
-        if ($clause === 'RESTRICT') {
+        if ($clause === 'r') {
             return Table::ACTION_RESTRICT;
         }
-        if ($clause === 'NO ACTION') {
+        if ($clause === 'a') {
             return Table::ACTION_NO_ACTION;
         }
-        if ($clause === 'CASCADE') {
+        if ($clause === 'c') {
             return Table::ACTION_CASCADE;
         }
         return Table::ACTION_SET_NULL;

+ 4 - 4
src/Database/Schema/Table.php

@@ -566,15 +566,15 @@ class Table
             $attrs = $this->_checkForeignKey($attrs);
 
             if (isset($this->_constraints[$name])) {
-                $this->_constraints[$name]['columns'] = array_merge(
+                $this->_constraints[$name]['columns'] = array_unique(array_merge(
                     $this->_constraints[$name]['columns'],
                     $attrs['columns']
-                );
+                ));
 
-                $this->_constraints[$name]['references'][1] = array_merge(
+                $this->_constraints[$name]['references'][1] = array_unique(array_merge(
                     (array)$this->_constraints[$name]['references'][1],
                     [$attrs['references'][1]]
-                );
+                ));
                 return $this;
             }
         } else {

+ 0 - 1
tests/TestCase/Database/Schema/TableTest.php

@@ -527,7 +527,6 @@ class TableTest extends TestCase
             'delete' => 'cascade',
             'length' => []
         ];
-
         $this->assertEquals($expected, $compositeConstraint);
 
         $expectedSubstring = 'CONSTRAINT <product_category_fk> FOREIGN KEY \(<product_category>, <product_id>\)' .