Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1378 from markstory/3.0-postgres-fk
3.0 postgres foreign keys
- Loading branch information
Showing
11 changed files
with
274 additions
and
242 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
<?php | ||
/** | ||
* PHP Version 5.4 | ||
* | ||
* CakePHP(tm) : Rapid Development Framework (http://cakephp.org) | ||
* Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) | ||
* | ||
* Licensed under The MIT License | ||
* For full copyright and license information, please see the LICENSE.txt | ||
* Redistributions of files must retain the above copyright notice. | ||
* | ||
* @copyright Copyright (c) Cake Software Foundation, Inc. (http://cakefoundation.org) | ||
* @link http://cakephp.org CakePHP(tm) Project | ||
* @since CakePHP(tm) v 3.0.0 | ||
* @license MIT License (http://www.opensource.org/licenses/mit-license.php) | ||
*/ | ||
namespace Cake\Database\Schema; | ||
|
||
/** | ||
* Base class for schema implementations. | ||
* | ||
* This class contains methods that are common across | ||
* the various SQL dialects. | ||
*/ | ||
class BaseSchema { | ||
|
||
/** | ||
* Generate an ON clause for a foreign key. | ||
* | ||
* @param string|null $on The on clause | ||
* @return string | ||
*/ | ||
protected function _foreignOnClause($on) { | ||
if ($on === Table::ACTION_SET_NULL) { | ||
return 'SET NULL'; | ||
} | ||
if ($on === Table::ACTION_CASCADE) { | ||
return 'CASCADE'; | ||
} | ||
if ($on === Table::ACTION_RESTRICT) { | ||
return 'RESTRICT'; | ||
} | ||
if ($on === Table::ACTION_NO_ACTION) { | ||
return 'NO ACTION'; | ||
} | ||
} | ||
|
||
/** | ||
* Convert string on clauses to the abstract ones. | ||
* | ||
* @param string $clause | ||
* @return string|null | ||
*/ | ||
protected function _convertOnClause($clause) { | ||
if ($clause === 'CASCADE' || $clause === 'RESTRICT') { | ||
return strtolower($clause); | ||
} | ||
if ($clause === 'NO ACTION') { | ||
return Table::ACTION_NO_ACTION; | ||
} | ||
return Table::ACTION_SET_NULL; | ||
} | ||
|
||
/** | ||
* Generate the SQL to drop a table. | ||
* | ||
* @param Cake\Database\Schema\Table $table Table instance | ||
* @return array SQL statements to drop DROP a table. | ||
*/ | ||
public function dropTableSql(Table $table) { | ||
$sql = sprintf( | ||
'DROP TABLE %s', | ||
$this->_driver->quoteIdentifier($table->name()) | ||
); | ||
return [$sql]; | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -22,7 +22,7 @@ | |
/** | ||
* Schema management/reflection features for Postgres. | ||
*/ | ||
class PostgresSchema { | ||
class PostgresSchema extends BaseSchema { | ||
|
||
/** | ||
* The driver instance being used. | ||
|
@@ -187,11 +187,13 @@ public function describeIndexSql($table, $config) { | |
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 | ||
FROM pg_catalog.pg_class AS c, | ||
pg_catalog.pg_class AS c2, | ||
pg_catalog.pg_index AS 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 | ||
LEFT JOIN pg_catalog.pg_namespace AS n ON n.oid = c.relnamespace | ||
WHERE c.relname = ? | ||
AND pg_catalog.pg_table_is_visible(c.oid) | ||
AND n.nspname = ? | ||
|
@@ -244,8 +246,24 @@ public function convertIndexDescription(Table $table, $row) { | |
* | ||
* @return array List of sql, params | ||
*/ | ||
public function describeForeignKeySql($table) { | ||
return ['', []]; | ||
public function describeForeignKeySql($table, $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'"; | ||
$schema = empty($config['schema']) ? 'public' : $config['schema']; | ||
return [$sql, [$table, $schema]]; | ||
} | ||
|
||
/** | ||
|
@@ -256,6 +274,41 @@ public function describeForeignKeySql($table) { | |
* @return void | ||
*/ | ||
public function convertForeignKey(Table $table, $row) { | ||
preg_match('/REFERENCES ([^\)]+)\(([^\)]+)\)/', $row['definition'], $matches); | ||
$tableName = $matches[1]; | ||
$column = $matches[2]; | ||
|
||
preg_match('/FOREIGN KEY \(([^\)]+)\) REFERENCES/', $row['definition'], $matches); | ||
$columns = explode(',', $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); | ||
} | ||
|
||
/** | ||
* Convert Postgres on clauses to the abstract ones. | ||
* | ||
* @param string $clause | ||
* @return string|null | ||
*/ | ||
protected function _convertOnClause($clause) { | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
markstory
Member
|
||
if ($clause === 'r') { | ||
return Table::ACTION_RESTRICT; | ||
} | ||
if ($clause === 'a') { | ||
return Table::ACTION_NO_ACTION; | ||
} | ||
if ($clause === 'c') { | ||
return Table::ACTION_CASCADE; | ||
} | ||
return Table::ACTION_SET_NULL; | ||
} | ||
|
||
/** | ||
|
@@ -363,16 +416,37 @@ public function constraintSql(Table $table, $name) { | |
$data = $table->constraint($name); | ||
$out = 'CONSTRAINT ' . $this->_driver->quoteIdentifier($name); | ||
if ($data['type'] === Table::CONSTRAINT_PRIMARY) { | ||
$out = 'PRIMARY KEY '; | ||
$out = 'PRIMARY KEY'; | ||
} | ||
if ($data['type'] === Table::CONSTRAINT_UNIQUE) { | ||
$out .= ' UNIQUE '; | ||
$out .= ' UNIQUE'; | ||
} | ||
return $this->_keySql($out, $data); | ||
} | ||
|
||
/** | ||
* Helper method for generating key SQL snippets. | ||
* | ||
* @param string $prefix The key prefix | ||
* @param array $data Key data. | ||
* @return string | ||
*/ | ||
protected function _keySql($prefix, $data) { | ||
$columns = array_map( | ||
[$this->_driver, 'quoteIdentifier'], | ||
$data['columns'] | ||
); | ||
return $out . '(' . implode(', ', $columns) . ')'; | ||
if ($data['type'] === Table::CONSTRAINT_FOREIGN) { | ||
return $prefix . sprintf( | ||
' FOREIGN KEY (%s) REFERENCES %s (%s) ON UPDATE %s ON DELETE %s', | ||
implode(', ', $columns), | ||
$this->_driver->quoteIdentifier($data['references'][0]), | ||
$this->_driver->quoteIdentifier($data['references'][1]), | ||
$this->_foreignOnClause($data['update']), | ||
$this->_foreignOnClause($data['delete']) | ||
); | ||
} | ||
return $prefix . ' (' . implode(', ', $columns) . ')'; | ||
} | ||
|
||
/** | ||
|
@@ -406,16 +480,6 @@ public function createTableSql(Table $table, $columns, $constraints, $indexes) { | |
return $out; | ||
} | ||
|
||
/** | ||
* Generate the SQL to drop a table. | ||
* | ||
* @param Cake\Database\Schema\Table $table Table instance | ||
* @return array SQL statements to drop DROP a table. | ||
*/ | ||
public function dropTableSql(Table $table) { | ||
return [sprintf('DROP TABLE "%s"', $table->name())]; | ||
} | ||
|
||
/** | ||
* Generate the SQL to truncate a table. | ||
* | ||
|
Oops, something went wrong.
May be personal preference, but would a simple
switch
be cleaner (and, slightly, faster)?