Browse Source

Merge pull request #6154 from cakephp/issue-6150

Describe foreign keys in a way that excludes procedures.
José Lorenzo Rodríguez 11 years ago
parent
commit
421b7ee8dd
1 changed files with 44 additions and 34 deletions
  1. 44 34
      src/Database/Schema/PostgresSchema.php

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

@@ -271,21 +271,35 @@ class PostgresSchema extends BaseSchema
      */
     public function describeForeignKeySql($tableName, $config)
     {
-        $sql = "SELECT
-			r.conname AS name,
-			r.confupdtype AS update_type,
-			r.confdeltype AS delete_type,
-			pg_catalog.pg_get_constraintdef(r.oid, true) AS definition
-			FROM pg_catalog.pg_constraint AS r
-			WHERE r.conrelid = (
-				SELECT c.oid
-				FROM pg_catalog.pg_class AS c,
-				pg_catalog.pg_namespace AS n
-				WHERE c.relname = ?
-				AND n.nspname = ?
-				AND n.oid = c.relnamespace
-			)
-			AND r.contype = 'f'";
+        $sql = "SELECT tc.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,
+            ccu.table_name AS references_table,
+            ccu.column_name AS references_field
+            FROM information_schema.table_constraints tc
+
+            LEFT JOIN information_schema.key_column_usage kcu
+            ON tc.constraint_catalog = kcu.constraint_catalog
+            AND tc.constraint_schema = kcu.constraint_schema
+            AND tc.constraint_name = kcu.constraint_name
+
+            LEFT JOIN information_schema.referential_constraints rc
+            ON tc.constraint_catalog = rc.constraint_catalog
+            AND tc.constraint_schema = rc.constraint_schema
+            AND tc.constraint_name = rc.constraint_name
+
+            LEFT JOIN information_schema.constraint_column_usage ccu
+            ON rc.unique_constraint_catalog = ccu.constraint_catalog
+            AND rc.unique_constraint_schema = ccu.constraint_schema
+            AND rc.unique_constraint_name = ccu.constraint_name
+
+            WHERE tc.table_name = ?
+            AND tc.table_schema = ?
+            AND tc.constraint_type = 'FOREIGN KEY'";
 
         $schema = empty($config['schema']) ? 'public' : $config['schema'];
         return [$sql, [$tableName, $schema]];
@@ -296,22 +310,18 @@ class PostgresSchema extends BaseSchema
      */
     public function convertForeignKeyDescription(Table $table, $row)
     {
-        preg_match('/REFERENCES ([^\)]+)\(([^\)]+)\)/', $row['definition'], $matches);
-        $tableName = $matches[1];
-        $column = $matches[2];
-
-        preg_match('/FOREIGN KEY \(([^\)]+)\) REFERENCES/', $row['definition'], $matches);
-        $columns = $this->_convertColumnList($matches[1]);
-
-        $data = [
-            'type' => Table::CONSTRAINT_FOREIGN,
-            'columns' => $columns,
-            'references' => [$tableName, $column],
-            'update' => $this->_convertOnClause($row['update_type']),
-            'delete' => $this->_convertOnClause($row['delete_type']),
-        ];
-        $name = $row['name'];
-        $table->addConstraint($name, $data);
+        $data = $table->constraint($row['name']);
+        if (empty($data)) {
+            $data = [
+                'type' => Table::CONSTRAINT_FOREIGN,
+                'columns' => [],
+                'references' => [$row['references_table'], $row['references_field']],
+                'update' => $this->_convertOnClause($row['on_update']),
+                'delete' => $this->_convertOnClause($row['on_delete']),
+            ];
+        }
+        $data['columns'][] = $row['column_name'];
+        $table->addConstraint($row['name'], $data);
     }
 
     /**
@@ -319,13 +329,13 @@ class PostgresSchema extends BaseSchema
      */
     protected function _convertOnClause($clause)
     {
-        if ($clause === 'r') {
+        if ($clause === 'RESTRICT') {
             return Table::ACTION_RESTRICT;
         }
-        if ($clause === 'a') {
+        if ($clause === 'NO ACTION') {
             return Table::ACTION_NO_ACTION;
         }
-        if ($clause === 'c') {
+        if ($clause === 'CASCADE') {
             return Table::ACTION_CASCADE;
         }
         return Table::ACTION_SET_NULL;