Index: modules/system/system.install =================================================================== RCS file: /cvs/drupal/drupal/modules/system/system.install,v retrieving revision 1.416 diff -u -r1.416 system.install --- modules/system/system.install 7 Nov 2009 13:35:21 -0000 1.416 +++ modules/system/system.install 9 Nov 2009 00:45:19 -0000 @@ -2635,27 +2635,7 @@ * Migrate upload module files to the new {file} table. */ function system_update_7035() { - if (!db_table_exists('upload')) { - return; - } - - // The old {files} tables still exists. We migrate core data from upload - // module, but any contrib module using it will need to do its own update. - $result = db_query('SELECT fid, uid, filename, filepath AS uri, filemime, filesize, status, timestamp FROM {files} f INNER JOIN {upload} u ON u.fid = f.fid', array(), array('fetch' => PDO::FETCH_ASSOC)); - - // We will convert filepaths to uri using the default schmeme - // and stripping off the existing file directory path. - $basename = variable_get('file_directory_path', conf_path() . '/files'); - $scheme = variable_get('file_default_scheme', 'public') . '://'; - $fids = array(); - // TODO: does this function need to run in batch mode, or should we use a multi-insert? - foreach ($result as $file) { - $file['uri'] = $scheme . str_replace($basename, '', $file['uri']); - $file['uri'] = file_stream_wrapper_uri_normalize($file['uri']); - db_insert('file')->fields($file)->execute(); - $fids[] = $file['fid']; - } - // TODO: delete the found fids from {files}? + // Update merged into system_update_7046(). } /** @@ -2784,6 +2764,215 @@ } /** + * Migrate upload.module to file.module. + */ +function system_update_7046(&$sandbox) { + if (!db_table_exists('upload')) { + return; + } + + if (!isset($sandbox['progress'])) { + // Initialize batch update information. + $sandbox['progress'] = 0; + $sandbox['last_vid_processed'] = -1; + $sandbox['max'] = db_query("SELECT COUNT(DISTINCT u.vid) FROM {upload} u")->fetchField(); + + // Check which node types have upload.module attachments enabled. + $context['types'] = array(); + foreach (node_type_get_types() as $node_type => $node_info) { + if (variable_get('upload_' . $node_type, 1)) { + $context['types'][$node_type] = $node_type; + } + variable_del('upload_' . $node_type); + } + // The {upload} table will be deleted when this update is complete so we + // want to be careful to migrate all the data, even for node types that + // may have had attachments disabled after files were uploaded. Look for + // any other node types referenced by the upload records and add those to + // the list. The admin can always remove the field later. + $query = db_select('node', 'n')->distinct(TRUE); + $query->innerJoin('upload', 'u', 'n.vid = u.vid'); + $results = $query->fields('n', array('type'))->execute(); + foreach ($results as $row) { + if (!isset($context['types'][$row->type])) { + drupal_set_message('The content type ' . $row->type . ' had uploads disabled but contained uploaded file data. Uploads have been re-enabled to migrate the existing data. You may delete the "File attachments" field in the ' . $row->type . ' type if this data is not necessary.'); + $context['types'][$row->type] = $row->type; + } + } + + // Create a single "field_upload" field on all the content types that have + // uploads enabled, then add an instance to each enabled type. + if (count($context['types']) > 0) { + drupal_install_modules(array('file')); + module_load_include('inc', 'field', 'field.crud'); + + $field = array( + 'field_name' => 'field_upload', + 'type' => 'file', + 'locked' => FALSE, + 'cardinality' => '-1', + 'translatable' => FALSE, + 'settings' => array( + 'display_field' => 1, + 'display_default' => variable_get('upload_list_default', 1), + 'uri_scheme' => variable_get('file_default_scheme', 'public'), + 'default_file' => 0, + ), + ); + + $upload_size = variable_get('upload_uploadsize_default', 1); + $instance = array( + 'field_name' => 'field_upload', + 'object_type' => 'node', + 'bundle' => NULL, + 'label' => 'File attachments', + 'widget_type' => 'file_generic', + 'required' => 0, + 'description' => '', + 'widget' => array( + 'weight' => '1', + 'settings' => array( + 'progress_indicator' => 'throbber', + ), + 'type' => 'file_generic', + ), + 'settings' => array( + 'max_filesize' => $upload_size ? ($upload_size . ' MB') : '', + 'file_extensions' => variable_get('upload_extensions_default', 'jpg jpeg gif png txt doc xls pdf ppt pps odt ods odp'), + 'file_directory' => '', + 'description_field' => 1, + ), + 'display' => array( + 'full' => array( + 'label' => 'above', + 'type' => 'file_table', + 'settings' => array(), + 'weight' => 0, + 'module' => 'file', + ), + 'teaser' => array( + 'label' => 'hidden', + 'type' => 'hidden', + 'settings' => array(), + 'weight' => 0, + 'module' => NULL, + ), + 'rss' => array( + 'label' => 'hidden', + 'type' => 'file_table', + 'settings' => array(), + 'weight' => 0, + 'module' => 'file', + ), + ), + ); + + try { + // Create the field. + $sandbox['upload_field'] = field_create_field($field); + + // Create the instances. + foreach ($context['types'] as $bundle) { + $instance['bundle'] = $bundle; + field_create_instance($instance); + } + } + catch (FieldException $e) { + // TODO: How do we report errors without $ret now? + $sandbox['#abort'] = array('success' => FALSE, 'query' => $e->getMessage()); + return; + } + } + else { + $sandbox['#finished'] = 1; + return; + } + } + + // Migrate a batch of files from the upload table to the appropriate field. + $limit = 500; + $query = db_select('upload', 'u'); + $query->innerJoin('node_revision', 'nr', 'u.vid = nr.vid'); + $query->innerJoin('node', 'n', 'n.nid = nr.nid'); + $query + ->fields('u', array('fid', 'vid', 'list', 'description')) + ->fields('n', array('nid', 'type')) + ->distinct(TRUE) + ->condition('u.vid', $sandbox['last_vid_processed'], '>') + ->orderBy('u.vid') + ->orderBy('u.weight') + ->range(0, $limit); + $result = $query->execute(); + foreach ($result as $record) { + // Note that we still reference the old files table here, since upload will + // not know about the new FID in the new file table. + $file = db_select('files', 'f') + ->fields('f', array('fid', 'uid', 'filename', 'filepath', 'filemime', 'filesize', 'status', 'timestamp')) + ->condition('f.fid', $record->fid) + ->execute() + ->fetch(PDO::FETCH_ASSOC); + if (!$file) { + continue; + } + + $file['description'] = $record->description; + $file['display'] = $record->list; + + $node_revisions[$record->vid]['nid'] = $record->nid; + $node_revisions[$record->vid]['vid'] = $record->vid; + $node_revisions[$record->vid]['type'] = $record->type; + $node_revisions[$record->vid]['field_upload'][FIELD_LANGUAGE_NONE][] = $file; + } + + // To make sure we process an entire revision all at once, toss the last node + // revision (which might be partial) unless it's the last one. + if ((count($node_revisions) > 1) && (count($result) == $limit)) { + array_pop($node_revisions); + } + else { + $finished = TRUE; + } + + $basename = variable_get('file_directory_path', conf_path() . '/files'); + $scheme = variable_get('file_default_scheme', 'public') . '://'; + foreach ($node_revisions as $vid => $revision) { + // We will convert filepaths to uri using the default scheme + // and stripping off the existing file directory path. + $fids = array(); + foreach ($revision['field_upload'][FIELD_LANGUAGE_NONE] as $delta => $file) { + // Insert into the file table. + $file['uri'] = $scheme . str_replace($basename, '', $file['filepath']); + $file['uri'] = file_stream_wrapper_uri_normalize($file['uri']); + unset($file['filepath']); + drupal_write_record('file', $file); + + // Update the node field with the file URI. + $revision['field_upload'][FIELD_LANGUAGE_NONE][$delta] = $file; + } + + // Insert the revision's files into the field_upload table. + $node = (object) $revision; + field_sql_storage_field_storage_write('node', $node, FIELD_STORAGE_INSERT, array($sandbox['upload_field']['id'])); + + // Update our progress information for the batch update. + $sandbox['progress']++; + $sandbox['last_vid_processed'] = $vid; + } + + // Indicate our current progress to the batch update system. If there's no + // max value then there's nothing to update and we're finished. + if (empty($sandbox['max']) || isset($finished)) { + db_delete('system', array('type' => 'module', 'name' => 'upload')); + db_drop_table('upload'); + $sandbox['#finished'] = 1; + return t('Upload module has been migrated to file module.'); + } + else { + $sandbox['#finished'] = $sandbox['progress'] / $sandbox['max']; + } +} + +/** * @} End of "defgroup updates-6.x-to-7.x" * The next series of updates should start at 8000. */