Skip to content

Commit

Permalink
Describe foreign keys in a way that excludes procedures.
Browse files Browse the repository at this point in the history
Use information_schema to exclude procedure based foreign keys in schema
reflection. We have no way of managing or re-using procedure based
constraints so we should just exclude them from our reflections.

Refs #6150
  • Loading branch information
markstory committed Mar 24, 2015
1 parent 09eb238 commit f03fd3b
Showing 1 changed file with 44 additions and 34 deletions.
78 changes: 44 additions & 34 deletions src/Database/Schema/PostgresSchema.php
Expand Up @@ -271,21 +271,35 @@ protected function _convertColumnList($columns)
*/
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]];
Expand All @@ -296,36 +310,32 @@ public function describeForeignKeySql($tableName, $config)
*/
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);
}

/**
* {@inheritDoc}
*/
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;
Expand Down

0 comments on commit f03fd3b

Please sign in to comment.