/** * Attepts to find a column on a foreign table. * Walks up table inheritance chains. * If the foreign column is itself a foreign key, resolves the type of that column before returning. */ private static function resolve_foreign_column($db_doc, $local_schema, $local_table, $local_colname, $foreign_schema, $foreign_table, $foreign_colname, $visited = array()) { // walk up the foreign table inheritance chain to find the foreign column definition $fschema = $foreign_schema; $ftable = $foreign_table; do { $foreign_column = dbx::get_table_column($ftable, $foreign_colname); if ($ftable['inheritsSchema']) { $fschema = dbx::get_schema($db_doc, (string) $ftable['inheritsSchema']); } if ($ftable['inheritsTable']) { $ftable = dbx::get_table($fschema, (string) $ftable['inheritsTable']); } else { $ftable = null; } } while (!$foreign_column && !!$fschema && !!$ftable); if (!$foreign_column) { // column wasn't found in any referenced tables throw new Exception("Local column {$local_schema['name']}.{$local_table['name']}.{$local_colname} references unknown column {$foreign_schema['name']}.{$foreign_table['name']}.{$foreign_colname}"); } // column type is missing, and resolved foreign is also a foreign key? // recurse and find the cascading foreign key if (empty($foreign_column['type']) && !empty($foreign_column['foreignTable'])) { // make sure we don't visit the same column twice $foreign_col = format::get_fully_qualified_column_name($foreign_schema['name'], $foreign_table['name'], $foreign_column['name']); if (in_array($foreign_col, $visited)) { $local = format::get_fully_qualified_column_name($local_schema['name'], $local_table['name'], $local_colname); throw new Exception("Foreign key cyclic dependency detected! Local column {$local} pointing to foreign column {$foreign_col}"); } $visited[] = $foreign_col; $nested_fkey = self::foreign_key_lookup($db_doc, $foreign_schema, $foreign_table, $foreign_column, $visited); // make a separate clone of the column element because we are specifying the type only for foreign key type referencing $foreign_column = new SimpleXMLElement($foreign_column->asXML()); $foreign_column['type'] = (string) $nested_fkey['column']['type']; } return $foreign_column; }