1<?php
2
3/**
4 * @file
5 * Install, update and uninstall functions for the node module.
6 */
7
8/**
9 * Implements hook_schema().
10 */
11function node_schema() {
12  $schema['node'] = array(
13    'description' => 'The base table for nodes.',
14    'fields' => array(
15      'nid' => array(
16        'description' => 'The primary identifier for a node.',
17        'type' => 'serial',
18        'unsigned' => TRUE,
19        'not null' => TRUE,
20      ),
21      // Defaults to NULL in order to avoid a brief period of potential
22      // deadlocks on the index.
23      'vid' => array(
24        'description' => 'The current {node_revision}.vid version identifier.',
25        'type' => 'int',
26        'unsigned' => TRUE,
27        'not null' => FALSE,
28        'default' => NULL,
29      ),
30      'type' => array(
31        'description' => 'The {node_type}.type of this node.',
32        'type' => 'varchar',
33        'length' => 32,
34        'not null' => TRUE,
35        'default' => '',
36      ),
37      'language' => array(
38        'description' => 'The {languages}.language of this node.',
39        'type' => 'varchar',
40        'length' => 12,
41        'not null' => TRUE,
42        'default' => '',
43      ),
44      'title' => array(
45        'description' => 'The title of this node, always treated as non-markup plain text.',
46        'type' => 'varchar',
47        'length' => 255,
48        'not null' => TRUE,
49        'default' => '',
50      ),
51      'uid' => array(
52        'description' => 'The {users}.uid that owns this node; initially, this is the user that created it.',
53        'type' => 'int',
54        'not null' => TRUE,
55        'default' => 0,
56      ),
57      'status' => array(
58        'description' => 'Boolean indicating whether the node is published (visible to non-administrators).',
59        'type' => 'int',
60        'not null' => TRUE,
61        'default' => 1,
62      ),
63      'created' => array(
64        'description' => 'The Unix timestamp when the node was created.',
65        'type' => 'int',
66        'not null' => TRUE,
67        'default' => 0,
68      ),
69      'changed' => array(
70        'description' => 'The Unix timestamp when the node was most recently saved.',
71        'type' => 'int',
72        'not null' => TRUE,
73        'default' => 0,
74      ),
75      'comment' => array(
76        'description' => 'Whether comments are allowed on this node: 0 = no, 1 = closed (read only), 2 = open (read/write).',
77        'type' => 'int',
78        'not null' => TRUE,
79        'default' => 0,
80      ),
81      'promote' => array(
82        'description' => 'Boolean indicating whether the node should be displayed on the front page.',
83        'type' => 'int',
84        'not null' => TRUE,
85        'default' => 0,
86      ),
87      'sticky' => array(
88        'description' => 'Boolean indicating whether the node should be displayed at the top of lists in which it appears.',
89        'type' => 'int',
90        'not null' => TRUE,
91        'default' => 0,
92      ),
93      'tnid' => array(
94        'description' => 'The translation set id for this node, which equals the node id of the source post in each set.',
95        'type' => 'int',
96        'unsigned' => TRUE,
97        'not null' => TRUE,
98        'default' => 0,
99      ),
100      'translate' => array(
101        'description' => 'A boolean indicating whether this translation page needs to be updated.',
102        'type' => 'int',
103        'not null' => TRUE,
104        'default' => 0,
105      ),
106    ),
107    'indexes' => array(
108      'node_changed'        => array('changed'),
109      'node_created'        => array('created'),
110      'node_frontpage'      => array('promote', 'status', 'sticky', 'created'),
111      'node_status_type'    => array('status', 'type', 'nid'),
112      'node_title_type'     => array('title', array('type', 4)),
113      'node_type'           => array(array('type', 4)),
114      'uid'                 => array('uid'),
115      'tnid'                => array('tnid'),
116      'translate'           => array('translate'),
117      'language'            => array('language'),
118    ),
119    'unique keys' => array(
120      'vid' => array('vid'),
121    ),
122    'foreign keys' => array(
123      'node_revision' => array(
124        'table' => 'node_revision',
125        'columns' => array('vid' => 'vid'),
126      ),
127      'node_author' => array(
128        'table' => 'users',
129        'columns' => array('uid' => 'uid'),
130      ),
131    ),
132    'primary key' => array('nid'),
133  );
134
135  $schema['node_access'] = array(
136    'description' => 'Identifies which realm/grant pairs a user must possess in order to view, update, or delete specific nodes.',
137    'fields' => array(
138      'nid' => array(
139        'description' => 'The {node}.nid this record affects.',
140        'type' => 'int',
141        'unsigned' => TRUE,
142        'not null' => TRUE,
143        'default' => 0,
144      ),
145      'gid' => array(
146        'description' => "The grant ID a user must possess in the specified realm to gain this row's privileges on the node.",
147        'type' => 'int',
148        'unsigned' => TRUE,
149        'not null' => TRUE,
150        'default' => 0,
151      ),
152      'realm' => array(
153        'description' => 'The realm in which the user must possess the grant ID. Each node access node can define one or more realms.',
154        'type' => 'varchar',
155        'length' => 255,
156        'not null' => TRUE,
157        'default' => '',
158      ),
159      'grant_view' => array(
160        'description' => 'Boolean indicating whether a user with the realm/grant pair can view this node.',
161        'type' => 'int',
162        'unsigned' => TRUE,
163        'not null' => TRUE,
164        'default' => 0,
165        'size' => 'tiny',
166      ),
167      'grant_update' => array(
168        'description' => 'Boolean indicating whether a user with the realm/grant pair can edit this node.',
169        'type' => 'int',
170        'unsigned' => TRUE,
171        'not null' => TRUE,
172        'default' => 0,
173        'size' => 'tiny',
174      ),
175      'grant_delete' => array(
176        'description' => 'Boolean indicating whether a user with the realm/grant pair can delete this node.',
177        'type' => 'int',
178        'unsigned' => TRUE,
179        'not null' => TRUE,
180        'default' => 0,
181        'size' => 'tiny',
182      ),
183    ),
184    'primary key' => array('nid', 'gid', 'realm'),
185    'foreign keys' => array(
186      'affected_node' => array(
187        'table' => 'node',
188        'columns' => array('nid' => 'nid'),
189      ),
190     ),
191  );
192
193  $schema['node_revision'] = array(
194    'description' => 'Stores information about each saved version of a {node}.',
195    'fields' => array(
196      'nid' => array(
197        'description' => 'The {node} this version belongs to.',
198        'type' => 'int',
199        'unsigned' => TRUE,
200        'not null' => TRUE,
201        'default' => 0,
202      ),
203      'vid' => array(
204        'description' => 'The primary identifier for this version.',
205        'type' => 'serial',
206        'unsigned' => TRUE,
207        'not null' => TRUE,
208      ),
209      'uid' => array(
210        'description' => 'The {users}.uid that created this version.',
211        'type' => 'int',
212        'not null' => TRUE,
213        'default' => 0,
214      ),
215      'title' => array(
216        'description' => 'The title of this version.',
217        'type' => 'varchar',
218        'length' => 255,
219        'not null' => TRUE,
220        'default' => '',
221      ),
222      'log' => array(
223        'description' => 'The log entry explaining the changes in this version.',
224        'type' => 'text',
225        'not null' => TRUE,
226        'size' => 'big',
227      ),
228      'timestamp' => array(
229        'description' => 'A Unix timestamp indicating when this version was created.',
230        'type' => 'int',
231        'not null' => TRUE,
232        'default' => 0,
233      ),
234      'status' => array(
235        'description' => 'Boolean indicating whether the node (at the time of this revision) is published (visible to non-administrators).',
236        'type' => 'int',
237        'not null' => TRUE,
238        'default' => 1,
239      ),
240      'comment' => array(
241        'description' => 'Whether comments are allowed on this node (at the time of this revision): 0 = no, 1 = closed (read only), 2 = open (read/write).',
242        'type' => 'int',
243        'not null' => TRUE,
244        'default' => 0,
245      ),
246      'promote' => array(
247        'description' => 'Boolean indicating whether the node (at the time of this revision) should be displayed on the front page.',
248        'type' => 'int',
249        'not null' => TRUE,
250        'default' => 0,
251      ),
252      'sticky' => array(
253        'description' => 'Boolean indicating whether the node (at the time of this revision) should be displayed at the top of lists in which it appears.',
254        'type' => 'int',
255        'not null' => TRUE,
256        'default' => 0,
257      ),
258    ),
259    'indexes' => array(
260      'nid' => array('nid'),
261      'uid' => array('uid'),
262    ),
263    'primary key' => array('vid'),
264    'foreign keys' => array(
265      'versioned_node' => array(
266        'table' => 'node',
267        'columns' => array('nid' => 'nid'),
268      ),
269      'version_author' => array(
270        'table' => 'users',
271        'columns' => array('uid' => 'uid'),
272      ),
273    ),
274  );
275
276  $schema['node_type'] = array(
277    'description' => 'Stores information about all defined {node} types.',
278    'fields' => array(
279      'type' => array(
280        'description' => 'The machine-readable name of this type.',
281        'type' => 'varchar',
282        'length' => 32,
283        'not null' => TRUE,
284      ),
285      'name' => array(
286        'description' => 'The human-readable name of this type.',
287        'type' => 'varchar',
288        'length' => 255,
289        'not null' => TRUE,
290        'default' => '',
291        'translatable' => TRUE,
292      ),
293      'base' => array(
294        'description' => 'The base string used to construct callbacks corresponding to this node type.',
295        'type' => 'varchar',
296        'length' => 255,
297        'not null' => TRUE,
298      ),
299      'module' => array(
300        'description' => 'The module defining this node type.',
301        'type' => 'varchar',
302        'length' => 255,
303        'not null' => TRUE,
304      ),
305      'description' => array(
306        'description' => 'A brief description of this type.',
307        'type' => 'text',
308        'not null' => TRUE,
309        'size' => 'medium',
310        'translatable' => TRUE,
311      ),
312      'help' => array(
313        'description' => 'Help information shown to the user when creating a {node} of this type.',
314        'type' => 'text',
315        'not null' => TRUE,
316        'size' => 'medium',
317        'translatable' => TRUE,
318      ),
319      'has_title' => array(
320        'description' => 'Boolean indicating whether this type uses the {node}.title field.',
321        'type' => 'int',
322        'unsigned' => TRUE,
323        'not null' => TRUE,
324        'size' => 'tiny',
325      ),
326      'title_label' => array(
327        'description' => 'The label displayed for the title field on the edit form.',
328        'type' => 'varchar',
329        'length' => 255,
330        'not null' => TRUE,
331        'default' => '',
332        'translatable' => TRUE,
333      ),
334      'custom' => array(
335        'description' => 'A boolean indicating whether this type is defined by a module (FALSE) or by a user via Add content type (TRUE).',
336        'type' => 'int',
337        'not null' => TRUE,
338        'default' => 0,
339        'size' => 'tiny',
340      ),
341      'modified' => array(
342        'description' => 'A boolean indicating whether this type has been modified by an administrator; currently not used in any way.',
343        'type' => 'int',
344        'not null' => TRUE,
345        'default' => 0,
346        'size' => 'tiny',
347      ),
348      'locked' => array(
349        'description' => 'A boolean indicating whether the administrator can change the machine name of this type.',
350        'type' => 'int',
351        'not null' => TRUE,
352        'default' => 0,
353        'size' => 'tiny',
354      ),
355      'disabled' => array(
356        'description' => 'A boolean indicating whether the node type is disabled.',
357        'type' => 'int',
358        'not null' => TRUE,
359        'default' => 0,
360        'size' => 'tiny'
361      ),
362      'orig_type' => array(
363        'description' => 'The original machine-readable name of this node type. This may be different from the current type name if the locked field is 0.',
364        'type' => 'varchar',
365        'length' => 255,
366        'not null' => TRUE,
367        'default' => '',
368      ),
369    ),
370    'primary key' => array('type'),
371  );
372
373  $schema['block_node_type'] = array(
374    'description' => 'Sets up display criteria for blocks based on content types',
375    'fields' => array(
376      'module' => array(
377        'type' => 'varchar',
378        'length' => 64,
379        'not null' => TRUE,
380        'description' => "The block's origin module, from {block}.module.",
381      ),
382      'delta' => array(
383        'type' => 'varchar',
384        'length' => 32,
385        'not null' => TRUE,
386        'description' => "The block's unique delta within module, from {block}.delta.",
387      ),
388      'type' => array(
389        'type' => 'varchar',
390        'length' => 32,
391        'not null' => TRUE,
392        'description' => "The machine-readable name of this type from {node_type}.type.",
393      ),
394    ),
395    'primary key' => array('module', 'delta', 'type'),
396    'indexes' => array(
397      'type' => array('type'),
398    ),
399  );
400
401  $schema['history'] = array(
402    'description' => 'A record of which {users} have read which {node}s.',
403    'fields' => array(
404      'uid' => array(
405        'description' => 'The {users}.uid that read the {node} nid.',
406        'type' => 'int',
407        'not null' => TRUE,
408        'default' => 0,
409      ),
410      'nid' => array(
411        'description' => 'The {node}.nid that was read.',
412        'type' => 'int',
413        'unsigned' => TRUE,
414        'not null' => TRUE,
415        'default' => 0,
416      ),
417      'timestamp' => array(
418        'description' => 'The Unix timestamp at which the read occurred.',
419        'type' => 'int',
420        'not null' => TRUE,
421        'default' => 0,
422      ),
423    ),
424    'primary key' => array('uid', 'nid'),
425    'indexes' => array(
426      'nid' => array('nid'),
427    ),
428  );
429
430  return $schema;
431}
432
433/**
434 * Implements hook_install().
435 */
436function node_install() {
437  // Populate the node access table.
438  db_insert('node_access')
439    ->fields(array(
440      'nid' => 0,
441      'gid' => 0,
442      'realm' => 'all',
443      'grant_view' => 1,
444      'grant_update' => 0,
445      'grant_delete' => 0,
446    ))
447    ->execute();
448}
449
450/**
451 * Implements hook_update_dependencies().
452 */
453function node_update_dependencies() {
454  // node_update_7006() migrates node data to fields and therefore must run
455  // after all Field modules have been enabled, which happens in
456  // system_update_7027(). It also needs to query the {filter_format} table to
457  // get a list of existing text formats, so it must run after
458  // filter_update_7000(), which creates that table.
459  $dependencies['node'][7006] = array(
460    'system' => 7027,
461    'filter' => 7000,
462  );
463
464  // node_update_7008() migrates role permissions and therefore must run after
465  // the {role} and {role_permission} tables are properly set up, which happens
466  // in user_update_7007().
467  $dependencies['node'][7008] = array(
468    'user' => 7007,
469  );
470
471  return $dependencies;
472}
473
474/**
475 * Utility function: fetch the node types directly from the database.
476 *
477 * This function is valid for a database schema version 7000.
478 *
479 * @ingroup update_api
480 */
481function _update_7000_node_get_types() {
482  $node_types = db_query('SELECT * FROM {node_type}')->fetchAllAssoc('type', PDO::FETCH_OBJ);
483
484  // Create default settings for orphan nodes.
485  $all_types = db_query('SELECT DISTINCT type FROM {node}')->fetchCol();
486  $extra_types = array_diff($all_types, array_keys($node_types));
487
488  foreach ($extra_types as $type) {
489    $type_object = new stdClass();
490    $type_object->type = $type;
491
492    // In Drupal 6, whether you have a body field or not is a flag in the node
493    // type table. If it's enabled, nodes may or may not have an empty string
494    // for the bodies. As we can't detect what this setting should be in
495    // Drupal 7 without access to the Drupal 6 node type settings, we assume
496    // the default, which is to enable the body field.
497    $type_object->has_body = 1;
498    $type_object->body_label = 'Body';
499    $node_types[$type_object->type] = $type_object;
500  }
501  return $node_types;
502}
503
504/**
505 * @addtogroup updates-6.x-to-7.x
506 * @{
507 */
508
509/**
510 * Upgrade the node type table and fix node type 'module' attribute to avoid name-space conflicts.
511 */
512function node_update_7000() {
513  // Rename the module column to base.
514  db_change_field('node_type', 'module', 'base', array('type' => 'varchar', 'length' => 255, 'not null' => TRUE));
515
516  db_add_field('node_type', 'module', array(
517    'description' => 'The module defining this node type.',
518    'type' => 'varchar',
519    'default' => '',
520    'length' => 255,
521    'not null' => TRUE,
522  ));
523
524  db_add_field('node_type', 'disabled', array(
525    'description' => 'A boolean indicating whether the node type is disabled.',
526    'type' => 'int',
527    'not null' => TRUE,
528    'default' => 0,
529    'size' => 'tiny'
530  ));
531
532  $modules = db_select('system', 's')
533    ->fields('s', array('name'))
534    ->condition('type', 'module');
535  db_update('node_type')
536    ->expression('module', 'base')
537    ->condition('base', $modules, 'IN')
538    ->execute();
539
540  db_update('node_type')
541    ->fields(array('base' => 'node_content'))
542    ->condition('base', 'node')
543    ->execute();
544}
545
546/**
547 * Rename {node_revisions} table to {node_revision}.
548 */
549function node_update_7001() {
550  db_rename_table('node_revisions', 'node_revision');
551}
552
553/**
554 * Extend the node_promote_status index to include all fields required for the node page query.
555 */
556function node_update_7002() {
557  db_drop_index('node', 'node_promote_status');
558  db_add_index('node', 'node_frontpage', array('promote', 'status', 'sticky', 'created'));
559}
560
561/**
562 * Remove the node_counter if the statistics module is uninstalled.
563 */
564function node_update_7003() {
565  if (drupal_get_installed_schema_version('statistics') == SCHEMA_UNINSTALLED) {
566    db_drop_table('node_counter');
567  }
568}
569
570/**
571 * Extend the existing default preview and teaser settings to all node types.
572 */
573function node_update_7004() {
574  // Get original settings and all types.
575  $original_length = variable_get('teaser_length', 600);
576  $original_preview = variable_get('node_preview', 0);
577
578  // Map old preview setting to new values order.
579  $original_preview ? $original_preview = 2 : $original_preview = 1;
580  node_type_cache_reset();
581
582  // Apply original settings to all types.
583  foreach (_update_7000_node_get_types() as $type => $type_object) {
584    variable_set('teaser_length_' . $type, $original_length);
585    variable_set('node_preview_' . $type, $original_preview);
586  }
587  // Delete old variable but leave 'teaser_length' for aggregator module upgrade.
588  variable_del('node_preview');
589}
590
591/**
592 * Add status/comment/promote and sticky columns to the {node_revision} table.
593 */
594function node_update_7005() {
595  foreach (array('status', 'comment', 'promote', 'sticky') as $column) {
596    db_add_field('node_revision', $column, array(
597      'type' => 'int',
598      'not null' => TRUE,
599      'default' => 0,
600    ));
601  }
602}
603
604/**
605 * Convert body and teaser from node properties to fields, and migrate status/comment/promote and sticky columns to the {node_revision} table.
606 */
607function node_update_7006(&$sandbox) {
608  $sandbox['#finished'] = 0;
609
610  // Get node type info for every invocation.
611  node_type_cache_reset();
612
613  if (!isset($sandbox['total'])) {
614    // Initial invocation.
615
616    // First, create the body field.
617    $body_field = array(
618      'field_name' => 'body',
619      'type' => 'text_with_summary',
620      'module' => 'text',
621      'cardinality' => 1,
622      'entity_types' => array('node'),
623      'translatable' => TRUE,
624    );
625    _update_7000_field_create_field($body_field);
626
627    $default_trim_length = variable_get('teaser_length', 600);
628
629    // Get node type info, specifically the body field settings.
630    $node_types = _update_7000_node_get_types();
631
632    // Add body field instances for existing node types.
633    foreach ($node_types as $node_type) {
634      if ($node_type->has_body) {
635        $trim_length = variable_get('teaser_length_' . $node_type->type, $default_trim_length);
636
637        $instance = array(
638          'entity_type' => 'node',
639          'bundle' => $node_type->type,
640          'label' => $node_type->body_label,
641          'description' => isset($node_type->description) ? $node_type->description : '',
642          'required' => (isset($node_type->min_word_count) && $node_type->min_word_count > 0) ? 1 : 0,
643          'widget' => array(
644            'type' => 'text_textarea_with_summary',
645            'settings' => array(
646              'rows' => 20,
647              'summary_rows' => 5,
648            ),
649            'weight' => -4,
650            'module' => 'text',
651          ),
652          'settings' => array('display_summary' => TRUE),
653          'display' => array(
654            'default' => array(
655              'label' => 'hidden',
656              'type' => 'text_default',
657            ),
658            'teaser' => array(
659              'label' => 'hidden',
660              'type' => 'text_summary_or_trimmed',
661              'trim_length' => $trim_length,
662            ),
663          ),
664        );
665        _update_7000_field_create_instance($body_field, $instance);
666        variable_del('teaser_length_' . $node_type->type);
667      }
668      // Leave 'teaser_length' variable for aggregator module upgrade.
669
670      $sandbox['node_types_info'][$node_type->type] = array(
671        'has_body' => $node_type->has_body,
672      );
673    }
674
675    // Used below when updating the stored text format of each node body.
676    $sandbox['existing_text_formats'] = db_query("SELECT format FROM {filter_format}")->fetchCol();
677
678    // Initialize state for future calls.
679    $sandbox['last'] = 0;
680    $sandbox['count'] = 0;
681
682    $query = db_select('node', 'n');
683    $query->join('node_revision', 'nr', 'n.nid = nr.nid');
684    $sandbox['total'] = $query->countQuery()->execute()->fetchField();
685
686    $sandbox['body_field_id'] = $body_field['id'];
687  }
688  else {
689    // Subsequent invocations.
690
691    $found = FALSE;
692    if ($sandbox['total']) {
693      // Operate on every revision of every node (whee!), in batches.
694      $batch_size = 200;
695      $query = db_select('node_revision', 'nr');
696      $query->innerJoin('node', 'n', 'n.nid = nr.nid');
697      $query
698        ->fields('nr', array('nid', 'vid', 'body', 'teaser', 'format'))
699        ->fields('n', array('type', 'status', 'comment', 'promote', 'sticky', 'language'))
700        ->condition('nr.vid', $sandbox['last'], '>')
701        ->orderBy('nr.vid', 'ASC')
702        ->range(0, $batch_size);
703      $revisions = $query->execute();
704
705      // Load each revision of each node, set up 'body'
706      // appropriately, and save the node's field data.  Note that
707      // node_load() will not return the body or teaser values from
708      // {node_revision} because those columns have been removed from the
709      // schema structure in memory (but not yet from the database),
710      // so we get the values from the explicit query of the table
711      // instead.
712      foreach ($revisions as $revision) {
713        $found = TRUE;
714
715        if ($sandbox['node_types_info'][$revision->type]['has_body']) {
716          $node = (object) array(
717            'nid' => $revision->nid,
718            'vid' => $revision->vid,
719            'type' => $revision->type,
720          );
721          // After node_update_7009() we will always have LANGUAGE_NONE as
722          // language neutral language code, but here we still have empty
723          // strings.
724          $langcode = empty($revision->language) ? LANGUAGE_NONE : $revision->language;
725          if (!empty($revision->teaser) && $revision->teaser != text_summary($revision->body)) {
726            $node->body[$langcode][0]['summary'] = $revision->teaser;
727          }
728          // Do this after text_summary() above.
729          $break = '<!--break-->';
730          if (substr($revision->body, 0, strlen($break)) == $break) {
731            $revision->body = substr($revision->body, strlen($break));
732          }
733          $node->body[$langcode][0]['value'] = $revision->body;
734          // Update the revision's text format for the changes to the Drupal 7
735          // filter system. This uses the same kind of logic that occurs, for
736          // example, in user_update_7010(), but we do this here rather than
737          // via a separate set of database queries, since we are already
738          // migrating the data.
739          if (empty($revision->body) && empty($revision->format)) {
740            $node->body[$langcode][0]['format'] = NULL;
741          }
742          elseif (!in_array($revision->format, $sandbox['existing_text_formats'])) {
743            $node->body[$langcode][0]['format'] = variable_get('filter_default_format', 1);
744          }
745          else {
746            $node->body[$langcode][0]['format'] = $revision->format;
747          }
748          // This is a core update and no contrib modules are enabled yet, so
749          // we can assume default field storage for a faster update.
750          _update_7000_field_sql_storage_write('node', $node->type, $node->nid, $node->vid, 'body', $node->body);
751        }
752
753        // Migrate the status columns to the {node_revision} table.
754        db_update('node_revision')
755          ->fields(array(
756            'status' => $revision->status,
757            'comment' => $revision->comment,
758            'promote' => $revision->promote,
759            'sticky' => $revision->sticky,
760          ))
761          ->condition('vid', $revision->vid)
762          ->execute();
763
764        $sandbox['last'] = $revision->vid;
765        $sandbox['count'] += 1;
766      }
767
768      $sandbox['#finished'] = min(0.99, $sandbox['count'] / $sandbox['total']);
769    }
770
771    if (!$found) {
772      // All nodes are processed.
773
774      // Remove the now-obsolete body info from node_revision.
775      db_drop_field('node_revision', 'body');
776      db_drop_field('node_revision', 'teaser');
777      db_drop_field('node_revision', 'format');
778
779      // Remove node_type properties related to the former 'body'.
780      db_drop_field('node_type', 'has_body');
781      db_drop_field('node_type', 'body_label');
782
783      // We're done.
784      $sandbox['#finished'] = 1;
785    }
786  }
787}
788
789/**
790 * Remove column min_word_count.
791 */
792function node_update_7007() {
793  db_drop_field('node_type', 'min_word_count');
794}
795
796/**
797 * Split the 'administer nodes' permission from 'access content overview'.
798 */
799function node_update_7008() {
800  $roles = user_roles(FALSE, 'administer nodes');
801  foreach ($roles as $rid => $role) {
802    _update_7000_user_role_grant_permissions($rid, array('access content overview'), 'node');
803  }
804}
805
806/**
807 * Convert node languages from the empty string to LANGUAGE_NONE.
808 */
809function node_update_7009() {
810  db_update('node')
811    ->fields(array('language' => LANGUAGE_NONE))
812    ->condition('language', '')
813    ->execute();
814}
815
816/**
817 * Add the {block_node_type} table.
818 */
819function node_update_7010() {
820  $schema['block_node_type'] = array(
821    'description' => 'Sets up display criteria for blocks based on content types',
822    'fields' => array(
823      'module' => array(
824        'type' => 'varchar',
825        'length' => 64,
826        'not null' => TRUE,
827        'description' => "The block's origin module, from {block}.module.",
828      ),
829      'delta' => array(
830        'type' => 'varchar',
831        'length' => 32,
832        'not null' => TRUE,
833        'description' => "The block's unique delta within module, from {block}.delta.",
834      ),
835      'type' => array(
836        'type' => 'varchar',
837        'length' => 32,
838        'not null' => TRUE,
839        'description' => "The machine-readable name of this type from {node_type}.type.",
840      ),
841    ),
842    'primary key' => array('module', 'delta', 'type'),
843    'indexes' => array(
844      'type' => array('type'),
845    ),
846  );
847
848  db_create_table('block_node_type', $schema['block_node_type']);
849}
850
851/**
852 * @} End of "addtogroup updates-6.x-to-7.x".
853 */
854
855/**
856 * @addtogroup updates-7.x-extra
857 * @{
858 */
859
860/**
861 * Update the database from Drupal 6 to match the schema.
862 */
863function node_update_7011() {
864  // Drop node moderation field.
865  db_drop_field('node', 'moderate');
866  db_drop_index('node', 'node_moderate');
867
868  // Change {node_revision}.status field to default to 1.
869  db_change_field('node_revision', 'status', 'status', array(
870    'type' => 'int',
871    'not null' => TRUE,
872    'default' => 1,
873  ));
874
875  // Change {node_type}.module field default.
876  db_change_field('node_type', 'module', 'module', array(
877    'type' => 'varchar',
878    'length' => 255,
879    'not null' => TRUE,
880  ));
881}
882
883/**
884 * Switches body fields to untranslatable while upgrading from D6 and makes them language neutral.
885 */
886function node_update_7012() {
887  // If we are upgrading from D6, then body fields should be set back to
888  // untranslatable, as D6 did not know about the idea of translating fields,
889  // but only nodes. If a D7 > D7 update is running we need to skip this update,
890  // as it is a valid use case to have translatable body fields in this context.
891  if (variable_get('update_d6', FALSE)) {
892    // Make node bodies untranslatable: field_update_field() cannot be used
893    // throughout the upgrade process and we do not have an update counterpart
894    // for _update_7000_field_create_field(). Hence we are forced to update the
895    // 'field_config' table directly. This is a safe operation since it is
896    // being performed while upgrading from D6. Perfoming the same operation
897    // during a D7 update is highly discouraged.
898    db_update('field_config')
899      ->fields(array('translatable' => 0))
900      ->condition('field_name', 'body')
901      ->execute();
902
903    // Switch field languages to LANGUAGE_NONE, since initially they were
904    // assigned the node language.
905    foreach (array('field_data_body', 'field_revision_body') as $table) {
906      db_update($table)
907        ->fields(array('language' => LANGUAGE_NONE))
908        ->execute();
909    }
910
911    node_type_cache_reset();
912  }
913}
914
915/**
916 * Change {node}.vid default value from 0 to NULL to avoid deadlock issues on MySQL.
917 */
918function node_update_7013() {
919  db_drop_unique_key('node', 'vid');
920  db_change_field('node', 'vid', 'vid', array(
921    'description' => 'The current {node_revision}.vid version identifier.',
922    'type' => 'int',
923    'unsigned' => TRUE,
924    'not null' => FALSE,
925    'default' => NULL,
926  ));
927  db_add_unique_key('node', 'vid', array('vid'));
928}
929
930/**
931 * Add an index on {node}.language.
932 */
933function node_update_7014() {
934  db_add_index('node', 'language', array('language'));
935}
936
937/**
938 * Enable node types that may have been erroneously disabled in Drupal 7.36.
939 */
940function node_update_7015() {
941  db_update('node_type')
942    ->fields(array('disabled' => 0))
943    ->condition('base', 'node_content')
944    ->execute();
945}
946
947/**
948 * Change {history}.nid to an unsigned int in order to match {node}.nid.
949 */
950function node_update_7016() {
951  db_drop_primary_key('history');
952  db_drop_index('history', 'nid');
953  db_change_field('history', 'nid', 'nid', array(
954    'description' => 'The {node}.nid that was read.',
955    'type' => 'int',
956    'unsigned' => TRUE,
957    'not null' => TRUE,
958    'default' => 0,
959  ));
960  db_add_primary_key('history', array('uid', 'nid'));
961  db_add_index('history', 'nid', array('nid'));
962}
963
964/**
965 * @} End of "addtogroup updates-7.x-extra".
966 */
967