Skip to content

Commit

Permalink
Merge 931f5a1 into 32c80b0
Browse files Browse the repository at this point in the history
  • Loading branch information
austinhyde committed Sep 12, 2015
2 parents 32c80b0 + 931f5a1 commit f053a54
Show file tree
Hide file tree
Showing 10 changed files with 134 additions and 33 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ vendor
*_composite.xml
clover.xml
coveralls-upload.json
phpunit.xml
2 changes: 2 additions & 0 deletions lib/DBSteward/dbsteward.dtd
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@
<!ATTLIST foreignKey foreignColumns CDATA #IMPLIED>
<!ATTLIST foreignKey constraintName CDATA #REQUIRED>
<!ATTLIST foreignKey indexName CDATA #IMPLIED>
<!ATTLIST foreignKey onUpdate CDATA #IMPLIED>
<!ATTLIST foreignKey onDelete CDATA #IMPLIED>

<!ELEMENT rows (row+)>
<!ATTLIST rows columns CDATA #REQUIRED>
Expand Down
26 changes: 14 additions & 12 deletions lib/DBSteward/sql_format/mysql5/mysql5.php
Original file line number Diff line number Diff line change
Expand Up @@ -552,18 +552,20 @@ public static function extract_schema($host, $port, $database, $user, $password)
}
elseif ( count($db_constraint->referenced_columns) > 1
&& count($db_constraint->referenced_columns) == count($db_constraint->columns) ) {
// compound index, define the FK as a constraint node
$node_constraint = $node_table->addChild('constraint');
$node_constraint['name'] = $db_constraint->constraint_name;
$node_constraint['type'] = 'FOREIGN KEY';
$node_constraint['foreignSchema'] = $db_constraint->referenced_table_schema;
$node_constraint['foreignTable'] = $db_constraint->referenced_table_name;

$node_constraint['definition'] = sprintf("(%s) REFERENCES %s (%s) ON DELETE %s ON UPDATE %s",
implode(', ', array_map('mysql5::get_quoted_column_name', $db_constraint->columns)),
mysql5::get_fully_qualified_table_name($db_constraint->referenced_table_schema,$db_constraint->referenced_table_name),
implode(', ', array_map('mysql5::get_quoted_column_name', $db_constraint->referenced_columns)),
$db_constraint->delete_rule, $db_constraint->update_rule);
$node_fkey = $node_table->addChild('foreignKey');
$node_fkey['columns'] = implode(', ', $db_constraint->columns);
$node_fkey['foreignSchema'] = $db_constraint->referenced_table_schema;
$node_fkey['foreignTable'] = $db_constraint->referenced_table_name;
$node_fkey['foreignColumns'] = implode(', ', $db_constraint->referenced_columns);
$node_fkey['constraintName'] = $db_constraint->constraint_name;

// RESTRICT is the default, leave it implicit if possible
if ( strcasecmp($db_constraint->delete_rule, 'restrict') !== 0 ) {
$node_fkey['onDelete'] = str_replace(' ', '_', $db_constraint->delete_rule);
}
if ( strcasecmp($db_constraint->update_rule, 'restrict') !== 0 ) {
$node_fkey['onUpdate'] = str_replace(' ', '_', $db_constraint->update_rule);
}
}
else {
var_dump($db_constraint);
Expand Down
17 changes: 17 additions & 0 deletions lib/DBSteward/sql_format/mysql5/mysql5_index.php
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,23 @@ public static function get_table_indexes($node_schema, $node_table) {
}
}

// Add explicit foreignKeys to the list
foreach ($node_table->foreignKey as $fkey) {
$cols = preg_split('/[\s,]+/', $fkey['columns'], -1, PREG_SPLIT_NO_EMPTY);

$fkey_index = new SimpleXMLElement('<index/>');
$fkey_index['name'] = (string)$fkey['indexName'] ?: (string)$fkey['constraintName'] ?: static::get_index_name(implode('_', $cols), $nodes);
$fkey_index['unique'] = 'false';
$fkey_index['using'] = 'btree';

foreach ($cols as $i => $col) {
$fkey_index->addChild('indexDimension', $col)
->addAttribute('name', $col . '_' . ($i + 1));
}

$nodes[] = $fkey_index;
}

$names = array();
foreach ($nodes as $node) {
if (in_array((string)$node['name'], $names)) {
Expand Down
21 changes: 8 additions & 13 deletions lib/DBSteward/sql_format/pgsql8/pgsql8.php
Original file line number Diff line number Diff line change
Expand Up @@ -1905,19 +1905,14 @@ public static function extract_schema($host, $port, $database, $user, $password)
unset($node_column['type']);
}
elseif (count($local_cols) > 1) {
// separately on table
$node_constraint = $node_table->addChild('constraint');
$node_constraint['name'] = $fk_row['constraint_name'];
$node_constraint['type'] = 'FOREIGN KEY';
$node_constraint['definition'] = sprintf("(%s) REFERENCES %s (%s) ON UPDATE %s ON DELETE %s",
implode(', ', array_map('pgsql8::get_quoted_column_name', $local_cols)),
pgsql8::get_fully_qualified_table_name($fk_row['foreign_schema'],$fk_row['foreign_table']),
implode(', ', array_map('pgsql8::get_quoted_column_name', $foreign_cols)),
pgsql8_constraint::get_reference_option_sql($rules[$fk_row['update_rule']]),
pgsql8_constraint::get_reference_option_sql($rules[$fk_row['delete_rule']])
);
$node_constraint['foreignSchema'] = $fk_row['foreign_schema'];
$node_constraint['foreignTable'] = $fk_row['foreign_table'];
$node_fkey = $node_table->addChild('foreignKey');
$node_fkey['columns'] = implode(', ', $local_cols);
$node_fkey['foreignSchema'] = $fk_row['foreign_schema'];
$node_fkey['foreignTable'] = $fk_row['foreign_table'];
$node_fkey['foreignColumns'] = implode(', ', $foreign_cols);
$node_fkey['constraintName'] = $fk_row['constraint_name'];
$node_fkey['onUpdate'] = $rules[$fk_row['update_rule']];
$node_fkey['onDelete'] = $rules[$fk_row['delete_rule']];
}
}

Expand Down
12 changes: 11 additions & 1 deletion lib/DBSteward/sql_format/sql99/sql99_constraint.php
Original file line number Diff line number Diff line change
Expand Up @@ -259,14 +259,24 @@ public static function get_table_constraints($db_doc, $node_schema, $node_table,
$local_cols = preg_split('/[\s,]+/', $node_fkey['columns'], -1, PREG_SPLIT_NO_EMPTY);
$quoted_cols = implode(', ', array_map('format::get_quoted_column_name', $local_cols));

$constraints[] = array(
$constraint = array(
'name' => (string)$node_fkey['constraintName'],
'schema_name' => (string)$node_schema['name'],
'table_name' => (string)$node_table['name'],
'type' => 'FOREIGN KEY',
'definition' => "($quoted_cols) REFERENCES {$foreign['references']}",
'foreign_key_data' => $foreign
);
if (isset($node_fkey['onDelete'])) {
$constraint['foreignOnDelete'] = (string)$node_fkey['onDelete'];
}
if (isset($node_fkey['onUpdate'])) {
$constraint['foreignOnUpdate'] = (string)$node_fkey['onUpdate'];
}
if (isset($node_fkey['indexName'])) {
$constraint['foreignIndexName'] = (string)$node_fkey['foreignIndexName'];
}
$constraints[] = $constraint;
}

// look for constraints in columns: foreign key and unique
Expand Down
6 changes: 3 additions & 3 deletions phpunit.xml.dist
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
backupGlobals="false"
bootstrap="tests/bootstrap.php">
<php>
<const name="PGSQL8_DBHOST" value="db-pgsql8.dev.pitbpa0"/>
<const name="PGSQL8_DBHOST" value="localhost"/>
<const name="PGSQL8_DBPORT" value="5432"/>
<const name="PGSQL8_DBNAME" value="dbsteward_phpunit"/>
<const name="PGSQL8_DBUSER" value="deployment"/>
Expand All @@ -12,7 +12,7 @@
<const name="PGSQL8_DBUSER_MANAGEMENT" value="deployment"/>
<const name="PGSQL8_DBPASS_MANAGEMENT" value="password1"/>

<const name="MSSQL10_DBHOST" value="db-mssql10.dev.pitbpa0"/>
<const name="MSSQL10_DBHOST" value="localhost"/>
<const name="MSSQL10_DBPORT" value="1433"/>
<const name="MSSQL10_DBNAME" value="dbsteward_phpunit"/>
<const name="MSSQL10_DBUSER" value="deployment"/>
Expand All @@ -21,7 +21,7 @@
<const name="MSSQL10_DBUSER_MANAGEMENT" value="deployment"/>
<const name="MSSQL10_DBPASS_MANAGEMENT" value="password1"/>

<const name="MYSQL5_DBHOST" value="db-mysql5.dev.pitbpa0"/>
<const name="MYSQL5_DBHOST" value="localhost"/>
<const name="MYSQL5_DBPORT" value="3306"/>
<const name="MYSQL5_DBNAME" value="dbsteward_phpunit"/>
<const name="MYSQL5_DBUSER" value="deployment"/>
Expand Down
37 changes: 37 additions & 0 deletions tests/mysql5/Mysql5ExtractCompoundForeignKeyTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php
/**
* DBSteward unit test for mysql5 foreign key extraction
*
* @package DBSteward
* @license http://www.opensource.org/licenses/bsd-license.php Simplified BSD License
*/

require_once __DIR__ . '/Mysql5ExtractionTest.php';

/**
* @group mysql5
*/
class Mysql5ExtractCompoundForeignKeyTest extends Mysql5ExtractionTest {

public function testCompoundFKeyExtraction() {
$sql = <<<SQL
CREATE TABLE t1 (c1 int, c2 int);
CREATE TABLE t2 (c1 int, c2 int);
CREATE INDEX t2_fkey_idx ON t2 (c1, c2);
ALTER TABLE t1 ADD FOREIGN KEY (c1, c2) REFERENCES t2 (c1, c2) ON UPDATE RESTRICT ON DELETE SET NULL;
SQL;

$expected = <<<XML
<foreignKey
columns="c1, c2"
foreignSchema="Mysql5ExtractionTest"
foreignTable="t2"
foreignColumns="c1, c2"
constraintName="t1_ibfk_1"
onDelete="SET_NULL"/>
XML;

$schema = $this->extract($sql);
$this->assertEquals(simplexml_load_string($expected), $schema->table[0]->foreignKey);
}
}
28 changes: 27 additions & 1 deletion tests/mysql5/Mysql5IndexSQLTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -282,5 +282,31 @@ public function testForeignKeyOnPrimaryKeyDoesntCreateIndex() {

$this->assertEquals(array(), $indexes, "There should be no indexes created when the fkey is on the pkey");
}

public function testCompoundForeignKeyCreatesIndex() {
$xml = <<<XML
<schema name="public" owner="ROLE_OWNER">
<table name="table1" owner="ROLE_OWNER" primaryKey="col1">
<column name="col1" type="int"/>
<column name="col2" type="int"/>
<column name="col3" type="int"/>
<foreignKey columns="col2, col3" foreignTable="table2" />
</table>
<table name="table2" owner="ROLE_OWNER" primaryKey="col2">
<column name="col2" type="int"/>
<column name="col3" type="int"/>
</table>
</schema>
XML;

$schema = simplexml_load_string($xml);
$table = $schema->table;

$indexes = mysql5_index::get_table_indexes($schema, $table);
$expected = array(
simplexml_load_string('<index name="col2_col3" unique="false" using="btree"><indexDimension name="col2_1">col2</indexDimension><indexDimension name="col3_2">col3</indexDimension></index>')
);

$this->assertEquals($expected, $indexes, "There should be a compound index for the explicit foreignKey element");
}
}
?>
17 changes: 14 additions & 3 deletions tests/pgsql8/ExtractionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -230,12 +230,23 @@ public function testCompositeForeignKeyReferentialConstraints() {
ON DELETE SET NULL
);
SQL;
$schema = $this->extract($sql);

$schemaname = __CLASS__;
$expected = <<<XML
<foreignKey
columns="foo, bar"
foreignSchema="$schemaname"
foreignTable="dummy"
foreignColumns="foo, bar"
constraintName="test_foo_fkey"
onUpdate="NO_ACTION"
onDelete="SET_NULL"/>
XML;

$schema = $this->extract($sql);
foreach ($schema->table as $table) {
if ((string)$table['name'] == 'test') {
$this->assertEquals("(foo, bar) REFERENCES $schemaname.dummy (foo, bar) ON UPDATE NO ACTION ON DELETE SET NULL",
(string)$table->constraint['definition']);
$this->assertEquals(simplexml_load_string($expected), $table->foreignKey);
return;
}
}
Expand Down

0 comments on commit f053a54

Please sign in to comment.