Index: modules/field/field.crud.inc =================================================================== RCS file: /cvs/drupal/drupal/modules/field/field.crud.inc,v retrieving revision 1.70 diff -u -p -r1.70 field.crud.inc --- modules/field/field.crud.inc 24 Sep 2010 02:10:06 -0000 1.70 +++ modules/field/field.crud.inc 26 Sep 2010 19:59:44 -0000 @@ -79,6 +79,11 @@ * 'columns' setting are allowed. Note that field types can specify * default indexes, which can be modified or added to when * creating a field. + * - foreign keys: (optional) An associative array of relations, using the same + * structure as the 'foreign keys' definition of hook_schema(). Note, however, + * that the field data is not necessarily stored in SQL. Also, the possible + * usage is limited, as you cannot specify another field as related, only + * existing SQL tables, such as filter formats. * - settings (array) * A sub-array of key/value pairs of field-type-specific settings. Each * field type module defines and documents its own field settings. @@ -319,9 +324,11 @@ function field_create_field($field) { // Collect storage information. module_load_install($field['module']); $schema = (array) module_invoke($field['module'], 'field_schema', $field); - $schema += array('columns' => array(), 'indexes' => array()); + $schema += array('columns' => array(), 'indexes' => array(), 'foreign keys' => array()); // 'columns' are hardcoded in the field type. $field['columns'] = $schema['columns']; + // 'foreign keys' are hardcoded in the field type. + $field['foreign keys'] = $schema['foreign keys']; // 'indexes' can be both hardcoded in the field type, and specified in the // incoming $field definition. $field += array( Index: modules/field/modules/field_sql_storage/field_sql_storage.module =================================================================== RCS file: /cvs/drupal/drupal/modules/field/modules/field_sql_storage/field_sql_storage.module,v retrieving revision 1.52 diff -u -p -r1.52 field_sql_storage.module --- modules/field/modules/field_sql_storage/field_sql_storage.module 5 Sep 2010 20:00:45 -0000 1.52 +++ modules/field/modules/field_sql_storage/field_sql_storage.module 26 Sep 2010 19:54:14 -0000 @@ -188,20 +188,31 @@ function _field_sql_storage_schema($fiel ), ); + $field += array('columns' => array(), 'indexes' => array(), 'foreign keys' => array()); // Add field columns. - foreach ((array) $field['columns'] as $column_name => $attributes) { + foreach ($field['columns'] as $column_name => $attributes) { $real_name = _field_sql_storage_columnname($field['field_name'], $column_name); $current['fields'][$real_name] = $attributes; } // Add indexes. - foreach ((array) $field['indexes'] as $index_name => $columns) { + foreach ($field['indexes'] as $index_name => $columns) { $real_name = _field_sql_storage_indexname($field['field_name'], $index_name); foreach ($columns as $column_name) { $current['indexes'][$real_name][] = _field_sql_storage_columnname($field['field_name'], $column_name); } } + // Add foreign keys. + foreach ($field['foreign keys'] as $specifier => $specification) { + $real_name = _field_sql_storage_indexname($field['field_name'], $specifier); + $current['foreign keys'][$real_name]['table'] = $specification['table']; + foreach ($specification['columns'] as $column => $referenced) { + $sql_storage_column = _field_sql_storage_columnname($field['field_name'], $column_name); + $current['foreign keys'][$real_name]['columns'][$sql_storage_column] = $referenced; + } + } + // Construct the revision table. The primary key includes // revision_id but not entity_id so that multiple revision loads can // use the IN operator. Index: modules/field/modules/field_sql_storage/field_sql_storage.test =================================================================== RCS file: /cvs/drupal/drupal/modules/field/modules/field_sql_storage/field_sql_storage.test,v retrieving revision 1.21 diff -u -p -r1.21 field_sql_storage.test --- modules/field/modules/field_sql_storage/field_sql_storage.test 5 Aug 2010 23:53:37 -0000 1.21 +++ modules/field/modules/field_sql_storage/field_sql_storage.test 26 Sep 2010 19:54:14 -0000 @@ -392,4 +392,26 @@ class FieldSqlStorageTestCase extends Dr $this->assertEqual($details[FIELD_LOAD_REVISION][$revision][$column_name], $storage_column_name, t('Column name %value matches the definition in %bin.', array('%value' => $column_name, '%bin' => $revision))); } } + + /** + * Test foreign key support. + */ + function testFieldSqlStorageForeignKeys() { + // Create a decimal field. + $field_name = 'testfield'; + $field = array('field_name' => $field_name, 'type' => 'text'); + $field = field_create_field($field); + // Retrieve the field and instance with field_info and verify the foreign + // keys are in place. + $field = field_info_field($field_name); + $this->assertEqual($field['foreign keys']['text_format']['table'], 'filter_format', t('Foreign key table name preserved through CRUD')); + $this->assertEqual($field['foreign keys']['text_format']['columns']['format'], 'format', t('Foreign key column name preserved through CRUD')); + // Now grab the SQL schema and verify that too. + $schema = drupal_get_schema(_field_sql_storage_tablename($field)); + $this->assertEqual(count($schema['foreign keys']), 1, t("There is 1 foreign key in the schema")); + $foreign_key = reset($schema['foreign keys']); + $filter_column = _field_sql_storage_columnname($field['field_name'], 'format'); + $this->assertEqual($foreign_key['table'], 'filter_format', t('Foreign key table name preserved in the schema')); + $this->assertEqual($foreign_key['columns'][$filter_column], 'format', t('Foreign key column name preserved in the schema')); + } } Index: modules/field/modules/text/text.install =================================================================== RCS file: /cvs/drupal/drupal/modules/field/modules/text/text.install,v retrieving revision 1.1 diff -u -p -r1.1 text.install --- modules/field/modules/text/text.install 4 Sep 2010 15:40:51 -0000 1.1 +++ modules/field/modules/text/text.install 26 Sep 2010 20:01:16 -0000 @@ -20,6 +20,7 @@ function text_field_schema($field) { ), ); break; + case 'text_long': $columns = array( 'value' => array( @@ -29,6 +30,7 @@ function text_field_schema($field) { ), ); break; + case 'text_with_summary': $columns = array( 'value' => array( @@ -56,5 +58,11 @@ function text_field_schema($field) { 'indexes' => array( 'format' => array('format'), ), + 'foreign keys' => array( + 'format' => array( + 'table' => 'filter_format', + 'columns' => array('format' => 'format'), + ), + ), ); } Index: modules/file/file.install =================================================================== RCS file: /cvs/drupal/drupal/modules/file/file.install,v retrieving revision 1.3 diff -u -p -r1.3 file.install --- modules/file/file.install 4 Sep 2010 15:40:51 -0000 1.3 +++ modules/file/file.install 26 Sep 2010 19:54:14 -0000 @@ -35,6 +35,12 @@ function file_field_schema($field) { 'indexes' => array( 'fid' => array('fid'), ), + 'foreign keys' => array( + 'fid' => array( + 'table' => 'file', + 'columns' => array('fid' => 'fid'), + ), + ), ); } Index: modules/system/system.api.php =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.api.php,v retrieving revision 1.194 diff -u -p -r1.194 system.api.php --- modules/system/system.api.php 24 Sep 2010 00:37:44 -0000 1.194 +++ modules/system/system.api.php 26 Sep 2010 19:54:14 -0000 @@ -2633,9 +2633,11 @@ function hook_requirements($phase) { * details on schema definition structures. * * @return - * A schema definition structure array. For each element of the - * array, the key is a table name and the value is a table structure - * definition. + * A schema definition structure array. For each element of the + * array, the key is a table name and the value is a table structure + * definition. + * + * @ingroup schemaapi */ function hook_schema() { $schema['node'] = array(