#898558: Clean-up the node upgrade path.

From: Damien Tournoud <damien@commerceguys.com>


---
 field/field.install |   53 ++++++++++++++++++++++++++++++++++++++
 node/node.install   |   71 +++++++++++++++++++++++++++++++++------------------
 2 files changed, 99 insertions(+), 25 deletions(-)

diff --git modules/field/field.install modules/field/field.install
index 6630849..e290a16 100644
--- modules/field/field.install
+++ modules/field/field.install
@@ -264,3 +264,56 @@ function _update_field_create_instance($field, &$instance) {
     ->fields($record)
     ->execute();
 }
+
+/**
+ * Utility function: write field data directly to the SQL storage.
+ */
+function _update_field_sql_storage_write($entity_type, $bundle, $entity_id, $revision_id, $field_name, $data) {
+  $etid = _field_sql_storage_etid($entity_type);
+  $table_name = "field_data_{$field_name}";
+  $revision_name = "field_revision_{$field_name}";
+
+  db_delete($table_name)
+    ->condition('etid', $etid)
+    ->condition('entity_id', $entity_id)
+    ->execute();
+  db_delete($revision_name)
+    ->condition('etid', $etid)
+    ->condition('entity_id', $entity_id)
+    ->condition('revision_id', $revision_id)
+    ->execute();
+
+  $columns = array();
+  foreach ($data as $langcode => $items) {
+    foreach ($items as $delta => $item) {
+      $record = array(
+        'etid' => $etid,
+        'entity_id' => $entity_id,
+        'revision_id' => $revision_id,
+        'bundle' => $bundle,
+        'delta' => $delta,
+        'language' => $langcode,
+      );
+      foreach ($item as $column => $value) {
+        $record[_field_sql_storage_columnname($field_name, $column)] = $value;
+      }
+
+      $records[] = $record;
+      // Record the columns used.
+      $columns += $record;
+    }
+  }
+
+  if ($columns) {
+    $query = db_insert($table_name)->fields(array_keys($columns));
+    $revision_query = db_insert($revision_name)->fields(array_keys($columns));
+    foreach ($records as $record) {
+      $query->values($record);
+      if ($revision_id) {
+        $revision_query->values($record);
+      }
+    }
+    $query->execute();
+    $revision_query->execute();
+  }
+}
diff --git modules/node/node.install modules/node/node.install
index bae6f87..9cc3620 100644
--- modules/node/node.install
+++ modules/node/node.install
@@ -478,10 +478,9 @@ function node_update_7004() {
   // Map old preview setting to new values order.
   $original_preview ? $original_preview = 2 : $original_preview = 1;
   drupal_static_reset('_node_types_build');
-  $type_list = node_type_get_types();
 
   // Apply original settings to all types.
-  foreach ($type_list as $type => $entity) {
+  foreach (_update_node_get_types() as $type) {
     variable_set('teaser_length_' . $type, $original_length);
     variable_set('node_preview_' . $type, $original_preview);
   }
@@ -510,36 +509,60 @@ function node_update_7006(&$sandbox) {
 
   // Get node type info for every invocation.
   drupal_static_reset('_node_types_build');
-  $node_types = node_type_get_types();
 
   if (!isset($sandbox['total'])) {
     // Initial invocation.
 
+    // First, create the body field.
+    $body_field = array(
+      'field_name' => 'body',
+      'type' => 'text_with_summary',
+      'module' => 'text',
+      'cardinality' => 1,
+      'entity_types' => array('node'),
+      'translatable' => TRUE,
+    );
+    _update_field_create_field($body_field);
+
+    $default_trim_length = variable_get('teaser_length', 600);
+
     // Get node type info, specifically the body field settings.
     $result = db_select('node_type', 'node_type')
       ->fields('node_type')
       ->execute();
 
-    $default_trim_length = variable_get('teaser_length', 600);
     // Add body field instances for existing node types.
     foreach ($result as $node_type) {
       if ($node_type->has_body) {
-        $instance = node_add_body_field($node_type, $node_type->body_label);
-        // Update newly created instance to convert teaser_length variable
-        // into formatter settings.
         $trim_length = variable_get('teaser_length_' . $node_type->type, $default_trim_length);
-        $instance_changed = FALSE;
-        foreach ($instance['display'] as $view_mode => $view_mode_info) {
-          if ($view_mode_info['type'] == 'text_trimmed' || $view_mode_info['type'] == 'text_summary_or_trimmed') {
-            if (!isset($view_mode_info['settings']['trim_length'])) {
-              $instance['display'][$view_mode]['settings']['trim_length'] = $trim_length;
-              $instance_changed = TRUE;
-            }
-          }
-        }
-        if ($instance_changed) {
-          field_update_instance($instance);
-        }
+
+        $instance = array(
+          'entity_type' => 'node',
+          'bundle' => $node_type->type,
+          'label' => $node_type->body_label,
+          'widget' => array(
+            'type' => 'text_textarea_with_summary',
+            'settings' => array(
+              'rows' => 20,
+              'summary_rows' => 5,
+            ),
+            'weight' => -4,
+            'module' => 'text',
+          ),
+          'settings' => array('display_summary' => TRUE),
+          'display' => array(
+            'default' => array(
+              'label' => 'hidden',
+              'type' => 'text_default',
+            ),
+            'teaser' => array(
+              'label' => 'hidden',
+              'type' => 'text_summary_or_trimmed',
+              'trim_length' => $trim_length,
+            ),
+          ),
+        );
+        _update_field_create_instance($body_field, $instance);
         variable_del('teaser_length_' . $node_type->type);
       }
       // Leave 'teaser_length' variable for aggregator module upgrade.
@@ -556,14 +579,12 @@ function node_update_7006(&$sandbox) {
     $query = db_select('node', 'n');
     $query->join('node_revision', 'nr', 'n.vid = nr.vid');
     $sandbox['total'] = $query->countQuery()->execute()->fetchField();
+
+    $sandbox['body_field_id'] = $body_field['id'];
   }
   else {
     // Subsequent invocations.
 
-    // Grab the body field ID for field_sql_storage_field_storage_write().
-    $body_field = field_info_field('body');
-    $body_field_id = $body_field['id'];
-
     $found = FALSE;
     if ($sandbox['total']) {
       // Operate on every revision of every node (whee!), in batches.
@@ -614,7 +635,7 @@ function node_update_7006(&$sandbox) {
           $node->body[$langcode][0]['format'] = !empty($revision->format) ? $revision->format : variable_get('filter_default_format', 1);
           // This is a core update and no contrib modules are enabled yet, so
           // we can assume default field storage for a faster update.
-          field_sql_storage_field_storage_write('node', $node, FIELD_STORAGE_INSERT, array($body_field_id));
+          _update_field_sql_storage_write('node', $node->type, $node->nid, $node->vid, 'body', $node->body);
         }
 
         // Migrate the status columns to the {node_revision} table.
@@ -666,7 +687,7 @@ function node_update_7007() {
 function node_update_7008() {
   $roles = user_roles(FALSE, 'administer nodes');
   foreach ($roles as $rid => $role) {
-    user_role_grant_permissions($rid, array('access content overview'));
+    _update_user_role_grant_permissions($rid, array('access content overview'), 'node');
   }
 }
 
