summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrion Vibber <brion@pobox.com>2010-10-19 12:08:59 -0700
committerBrion Vibber <brion@pobox.com>2010-10-19 12:08:59 -0700
commit7751d455de464f29988de6c5a3128f9ca8357403 (patch)
tree3c3c419de682eb09fc8bff5fa80004dc40ca3b0f
parentb635c75639f5119d89a7f228155466a80d7ba185 (diff)
Initial foreign key setup support
-rw-r--r--db/core.php4
-rw-r--r--lib/schema.php89
2 files changed, 82 insertions, 11 deletions
diff --git a/db/core.php b/db/core.php
index 9be793ffb..ebf873504 100644
--- a/db/core.php
+++ b/db/core.php
@@ -511,8 +511,8 @@ $schema['foreign_link'] = array(
$schema['foreign_subscription'] = array(
'fields' => array(
'service' => array('type' => 'int', 'not null' => true, 'description' => 'service where relationship happens'),
- 'subscriber' => array('type' => 'int', 'not null' => true, 'description' => 'subscriber on foreign service'),
- 'subscribed' => array('type' => 'int', 'not null' => true, 'description' => 'subscribed user'),
+ 'subscriber' => array('type' => 'int', 'size' => 'big', 'not null' => true, 'description' => 'subscriber on foreign service'),
+ 'subscribed' => array('type' => 'int', 'size' => 'big', 'not null' => true, 'description' => 'subscribed user'),
'created' => array('type' => 'datetime', 'not null' => true, 'description' => 'date this record was created'),
),
'primary key' => array('service', 'subscriber', 'subscribed'),
diff --git a/lib/schema.php b/lib/schema.php
index 6e9643b67..c32e6b523 100644
--- a/lib/schema.php
+++ b/lib/schema.php
@@ -149,7 +149,7 @@ class Schema
$this->appendColumnDef($sql, $col, $colDef);
}
- // Primary and unique keys are constraints, so go within
+ // Primary, unique, and foreign keys are constraints, so go within
// the CREATE TABLE statement normally.
if (!empty($def['primary key'])) {
$this->appendPrimaryKeyDef($sql, $def['primary key']);
@@ -161,6 +161,12 @@ class Schema
}
}
+ if (!empty($def['foreign keys'])) {
+ foreach ($def['foreign keys'] as $keyName => $keyDef) {
+ $this->appendForeignKeyDef($sql, $keyName, $keyDef);
+ }
+ }
+
// Multi-value indexes are advisory and for best portability
// should be created as separate statements.
$statements = array();
@@ -225,7 +231,7 @@ class Schema
}
/**
- * Append an SQL fragment with a constraint definition for a primary
+ * Append an SQL fragment with a constraint definition for a unique
* key in a CREATE TABLE statement.
*
* @param array $sql
@@ -238,6 +244,27 @@ class Schema
}
/**
+ * Append an SQL fragment with a constraint definition for a foreign
+ * key in a CREATE TABLE statement.
+ *
+ * @param array $sql
+ * @param string $name
+ * @param array $def
+ */
+ function appendForeignKeyDef(array &$sql, $name, array $def)
+ {
+ list($refTable, $map) = $def;
+ $srcCols = array_keys($map);
+ $refCols = array_values($map);
+ $sql[] = "CONSTRAINT $name FOREIGN KEY " .
+ $this->buildIndexList($srcCols) .
+ " REFERENCES " .
+ $this->quoteIdentifier($refTable) .
+ " " .
+ $this->buildIndexList($refCols);
+ }
+
+ /**
* Append an SQL statement with an index definition for an advisory
* index over one or more columns on a table.
*
@@ -251,6 +278,19 @@ class Schema
$statements[] = "CREATE INDEX $name ON $table " . $this->buildIndexList($def);
}
+ /**
+ * Append an SQL statement to drop an index from a table.
+ *
+ * @param array $statements
+ * @param string $table
+ * @param string $name
+ * @param array $def
+ */
+ function appendDropIndex(array &$statements, $table, $name)
+ {
+ $statements[] = "DROP INDEX $name ON " . $this->quoteIdentifier($table);
+ }
+
function buildIndexList(array $def)
{
// @fixme
@@ -485,19 +525,30 @@ class Schema
return $this->buildCreateTable($tableName, $def);
}
- //$old = $this->filterDef($old);
+ // Filter the DB-independent table definition to match the current
+ // database engine's features and limitations.
$def = $this->filterDef($def);
- // @fixme check if not present
+ $statements = array();
$fields = $this->diffArrays($old, $def, 'fields', array($this, 'columnsEqual'));
$uniques = $this->diffArrays($old, $def, 'unique keys');
$indexes = $this->diffArrays($old, $def, 'indexes');
+ $foreign = $this->diffArrays($old, $def, 'foreign keys');
+
+ // Drop any obsolete or modified indexes ahead...
+ foreach ($indexes['del'] + $indexes['mod'] as $indexName) {
+ $this->appendDropIndex($statements, $tableName, $indexName);
+ }
// For efficiency, we want this all in one
// query, instead of using our methods.
$phrase = array();
+ foreach ($foreign['del'] + $foreign['mod'] as $keyName) {
+ $this->appendAlterDropForeign($phrase, $keyName);
+ }
+
foreach ($uniques['del'] + $uniques['mod'] as $keyName) {
$this->appendAlterDropUnique($phrase, $keyName);
}
@@ -521,16 +572,23 @@ class Schema
$this->appendAlterAddUnique($phrase, $keyName, $def['unique keys'][$keyName]);
}
+ foreach ($foreign['mod'] + $foreign['add'] as $keyName) {
+ $this->appendAlterAddForeign($phrase, $keyName, $def['foreign keys'][$keyName]);
+ }
+
$this->appendAlterExtras($phrase, $tableName);
- if (count($phrase) == 0) {
- // nothing to do
- return array();
+ if (count($phrase) > 0) {
+ $sql = 'ALTER TABLE ' . $tableName . ' ' . implode(",\n", $phrase);
+ $statements[] = $sql;
}
- $sql = 'ALTER TABLE ' . $tableName . ' ' . implode(",\n", $phrase);
+ // Now create any indexes...
+ foreach ($indexes['mod'] + $indexes['add'] as $indexName) {
+ $this->appendCreateIndex($statements, $tableName, $indexName, $def['indexes'][$indexName]);
+ }
- return array($sql);
+ return $statements;
}
function diffArrays($oldDef, $newDef, $section, $compareCallback=null)
@@ -621,11 +679,24 @@ class Schema
$phrase[] = implode(' ', $sql);
}
+ function appendAlterAddForeign(array &$phrase, $keyName, array $def)
+ {
+ $sql = array();
+ $sql[] = 'ADD';
+ $this->appendForeignKeyDef($sql, $keyName, $def);
+ $phrase[] = implode(' ', $sql);
+ }
+
function appendAlterDropUnique(array &$phrase, $keyName)
{
$phrase[] = 'DROP CONSTRAINT ' . $keyName;
}
+ function appendAlterDropForeign(array &$phrase, $keyName)
+ {
+ $phrase[] = 'DROP FOREIGN KEY ' . $keyName;
+ }
+
function appendAlterExtras(array &$phrase, $tableName)
{
// no-op